Slink/sos_sales/report/sos_billing_target_report.py

105 lines
3.9 KiB
Python
Executable File

from odoo import models, api
from collections import defaultdict
from datetime import datetime, timedelta, date
# Constants
PRODUCTION_LEAD_DAYS = {
'BHMS 1.2V': 60,
'BHMS 2V': 30,
'BHMS 12V': 30,
'BHMS 48V': 30,
'BMS-LV 100A': 30,
'BMS-LV 40A': 30,
'MC 250W': 45,
'HeartTarang': 30,
}
MONTH_NAMES = [
'April', 'May', 'June', 'July', 'August', 'September',
'October', 'November', 'December', 'January', 'February', 'March'
]
class ReportBillingTarget(models.AbstractModel):
_name = 'report.sos_sales.report_billing_target'
_description = 'Billing Target Report'
def get_month_start_dates(self, fy_start_year):
dates = {}
for i, name in enumerate(MONTH_NAMES):
month = i + 4 if i < 9 else i - 8
year = fy_start_year if i < 9 else fy_start_year + 1
dates[name] = datetime(year, month, 1)
return dates
@api.model
def _get_report_values(self, docids, data=None):
fy_start_year = 2024 # Change to dynamic year if needed
month_start_dates = self.get_month_start_dates(fy_start_year)
today = date.today()
fy_year = today.year if today.month >= 4 else today.year - 1
current_fy = f"FY {fy_year}-{fy_year + 1}"
result = defaultdict(lambda: defaultdict(lambda: defaultdict(float)))
records = self.env['sos_sales_plan_target'].search([
('financial_year', '=', current_fy)
])
for rec in records:
exec_name = rec.sales_executive.name
for line in rec.line_ids:
product = line.product
if not product:
continue
lead_days = PRODUCTION_LEAD_DAYS.get(product, 0)
for month in MONTH_NAMES:
short = month.lower()[:3]
value = getattr(line, f"{short}_value", 0.0)
if value:
source_start = month_start_dates[month]
next_month = source_start.replace(day=28) + timedelta(days=4)
last_day_of_month = next_month.replace(day=1) - timedelta(days=1)
billed_date = last_day_of_month + timedelta(days=lead_days)
# Match billed_date to one of the financial year months
for name, start_date in month_start_dates.items():
if start_date.month == billed_date.month and start_date.year == billed_date.year:
billed_month = name
break
else:
billed_month = None
if billed_month in MONTH_NAMES:
result[exec_name][billed_month][product] += value
# Step 2: Filter products and compute totals
filtered_products_by_exec = defaultdict(set)
display_totals = defaultdict(lambda: defaultdict(float))
for exec_name, month_data in result.items():
for month, prod_data in month_data.items():
for product, val in prod_data.items():
if val > 0:
filtered_products_by_exec[exec_name].add(product)
display_totals[exec_name][month] += val
overall_monthly_totals = defaultdict(float)
for exec_name, month_totals in display_totals.items():
for month, value in month_totals.items():
overall_monthly_totals[month] += value
grand_total = sum(overall_monthly_totals.values())
return {
'doc_ids': docids,
'doc_model': 'sos_sales_plan_target',
'billing_data': result,
'month_names': MONTH_NAMES,
'filtered_products_by_exec': filtered_products_by_exec,
'monthly_totals': display_totals,
'overall_monthly_totals': overall_monthly_totals,
'grand_total': grand_total,
}