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, }