from odoo import models, fields, api from datetime import date from odoo.exceptions import ValidationError from collections import defaultdict class sos_sales_plan_target(models.Model): _name = 'sos_sales_plan_target' _description = 'Sosaley Sales Target' _rec_name='financial_year' financial_year = fields.Char(string="Financial Year", default=lambda self: self._get_financial_year()) line_ids = fields.One2many('sos_sales_plan_target_lines', 'ref_id', string="Sales Target Lines",copy=True) sales_executive = fields.Many2one( 'res.users', string='Sales Executive', default=lambda self: self.env.user, readonly=True ) total_april_value = fields.Float(string="April Target", compute="_compute_monthly_totals", store=True) total_may_value = fields.Float(string="May Target", compute="_compute_monthly_totals", store=True) total_june_value = fields.Float(string="June Target", compute="_compute_monthly_totals", store=True) total_july_value = fields.Float(string="July Target", compute="_compute_monthly_totals", store=True) total_august_value = fields.Float(string="August Target", compute="_compute_monthly_totals", store=True) total_september_value = fields.Float(string="September Target", compute="_compute_monthly_totals", store=True) total_october_value = fields.Float(string="October Target", compute="_compute_monthly_totals", store=True) total_november_value = fields.Float(string="November Target", compute="_compute_monthly_totals", store=True) total_december_value = fields.Float(string="December Target", compute="_compute_monthly_totals", store=True) total_january_value = fields.Float(string="January Target", compute="_compute_monthly_totals", store=True) total_february_value = fields.Float(string="February Target", compute="_compute_monthly_totals", store=True) total_march_value = fields.Float(string="March Target", compute="_compute_monthly_totals", store=True) total_annual_value = fields.Float(string="Annual Target", compute="_compute_total_annual_value", store=True) total_q1_value = fields.Float(string="Q1 Target", compute="_compute_q1_value", store=True) total_q2_value = fields.Float(string="Q2 Target", compute="_compute_q2_value", store=True) total_q3_value = fields.Float(string="Q3 Target", compute="_compute_q3_value", store=True) total_q4_value = fields.Float(string="Q4 Target", compute="_compute_q4_value", store=True) product_summary = fields.Html(string="Product-wise Summary", compute="_compute_product_summary") def _compute_product_summary(self): for rec in self: totals = defaultdict(float) for line in rec.line_ids: total = sum([ line.apr_value, line.may_value, line.jun_value, line.jul_value, line.aug_value, line.sep_value, line.oct_value, line.nov_value, line.dec_value, line.jan_value, line.feb_value, line.mar_value ]) totals[line.product] += total rows = "".join(f"{prod}₹ {amt:.2f}" for prod, amt in totals.items()) rec.product_summary = f""" {rows}
Product Wise Target (Rupees In Lakhs)
ProductTotal
""" def action_report_sales_plan_btn(self): try: action = self.env.ref("sos_sales.action_report_sales_plan").with_context(landscape=True).report_action(self) return action except ValueError as e: print(f"Failed to find report action: {e}") @api.model def create(self, vals): month_map = { 'total_april_value': 'apr_value', 'total_may_value': 'may_value', 'total_june_value': 'jun_value', 'total_july_value': 'jul_value', 'total_august_value': 'aug_value', 'total_september_value': 'sep_value', 'total_october_value': 'oct_value', 'total_november_value': 'nov_value', 'total_december_value': 'dec_value', 'total_january_value': 'jan_value', 'total_february_value': 'feb_value', 'total_march_value': 'mar_value', } monthly_totals = {key: 0.0 for key in month_map} line_items = vals.get('line_ids', []) for command in line_items: if isinstance(command, (list, tuple)) and command[0] == 0: # create command line_vals = command[2] for field_name, month_key in month_map.items(): monthly_totals[field_name] += line_vals.get(month_key, 0.0) # Assign calculated values into vals vals.update(monthly_totals) # Also calculate total_annual_value from monthly values total = sum(monthly_totals.values()) vals['total_annual_value'] = total sales_achievement_records = self.env['sos_sales_achievement_report'].search([ ('financial_year', '=', vals['financial_year']), ('sales_person', '=', self.env.user.id) ], limit=1) if sales_achievement_records: sales_achievement_records.write({ 'overall_target':total, 'planned_target_april':vals['total_april_value'], 'planned_target_may':vals['total_may_value'], 'planned_target_june':vals['total_june_value'], 'planned_target_july':vals['total_july_value'], 'planned_target_august':vals['total_august_value'], 'planned_target_september':vals['total_september_value'], 'planned_target_october':vals['total_october_value'], 'planned_target_november':vals['total_november_value'], 'planned_target_december':vals['total_december_value'], 'planned_target_january':vals['total_january_value'], 'planned_target_february':vals['total_february_value'], 'planned_target_march':vals['total_march_value'] }) else: self.env['sos_sales_achievement_report'].create({ 'financial_year': vals['financial_year'], 'sales_person': self.env.user.id, 'overall_target':vals['total_annual_value'], 'planned_target_april':vals['total_april_value'], 'planned_target_may':vals['total_may_value'], 'planned_target_june':vals['total_june_value'], 'planned_target_july':vals['total_july_value'], 'planned_target_august':vals['total_august_value'], 'planned_target_september':vals['total_september_value'], 'planned_target_october':vals['total_october_value'], 'planned_target_november':vals['total_november_value'], 'planned_target_december':vals['total_december_value'], 'planned_target_january':vals['total_january_value'], 'planned_target_february':vals['total_february_value'], 'planned_target_march':vals['total_march_value'] }) return super(sos_sales_plan_target, self).create(vals) def write(self, vals): res = super(sos_sales_plan_target, self).write(vals) # Perform the write first for rec in self: achievement = self.env['sos_sales_achievement_report'].search([ ('financial_year', '=', rec.financial_year), ('sales_person', '=', rec.sales_executive.id) ], limit=1) vals_to_write = { 'overall_target': rec.total_annual_value, 'planned_target_april': rec.total_april_value, 'planned_target_may': rec.total_may_value, 'planned_target_june': rec.total_june_value, 'planned_target_july': rec.total_july_value, 'planned_target_august': rec.total_august_value, 'planned_target_september': rec.total_september_value, 'planned_target_october': rec.total_october_value, 'planned_target_november': rec.total_november_value, 'planned_target_december': rec.total_december_value, 'planned_target_january': rec.total_january_value, 'planned_target_february': rec.total_february_value, 'planned_target_march': rec.total_march_value, } if achievement: achievement.write(vals_to_write) else: vals_to_write.update({ 'financial_year': rec.financial_year, 'sales_person': rec.sales_executive.id, }) self.env['sos_sales_achievement_report'].create(vals_to_write) return res @api.constrains('financial_year', 'sales_executive') def check_unique_values(self): for record in self: existing_records = self.search([ ('sales_executive', '=', record.sales_executive.id), ('financial_year', '=', record.financial_year), ('id', '!=', record.id) # Exclude self ]) print(existing_records) if existing_records: raise ValidationError("Target of the financial year must be unique.") @api.depends('line_ids.apr_value', 'line_ids.may_value', 'line_ids.jun_value', 'line_ids.jul_value', 'line_ids.aug_value', 'line_ids.sep_value', 'line_ids.oct_value', 'line_ids.nov_value', 'line_ids.dec_value', 'line_ids.jan_value', 'line_ids.feb_value', 'line_ids.mar_value') def _compute_total_annual_value(self): for rec in self: rec.total_annual_value = sum( line.apr_value + line.may_value + line.jun_value + line.jul_value + line.aug_value + line.sep_value + line.oct_value + line.nov_value + line.dec_value + line.jan_value + line.feb_value + line.mar_value for line in rec.line_ids ) @api.depends('line_ids.apr_value', 'line_ids.may_value', 'line_ids.jun_value') def _compute_q1_value(self): for rec in self: rec.total_q1_value = sum( line.apr_value + line.may_value + line.jun_value for line in rec.line_ids ) @api.depends('line_ids.jul_value', 'line_ids.aug_value', 'line_ids.sep_value') def _compute_q2_value(self): for rec in self: rec.total_q2_value = sum( line.jul_value + line.aug_value + line.sep_value for line in rec.line_ids ) @api.depends('line_ids.oct_value', 'line_ids.nov_value', 'line_ids.dec_value') def _compute_q3_value(self): for rec in self: rec.total_q3_value = sum( line.oct_value + line.nov_value + line.dec_value for line in rec.line_ids ) @api.depends('line_ids.jan_value', 'line_ids.feb_value', 'line_ids.mar_value') def _compute_q4_value(self): for rec in self: rec.total_q4_value = sum( line.jan_value + line.feb_value + line.mar_value for line in rec.line_ids ) @api.depends( 'line_ids.apr_value', 'line_ids.may_value', 'line_ids.jun_value', 'line_ids.jul_value', 'line_ids.aug_value', 'line_ids.sep_value', 'line_ids.oct_value', 'line_ids.nov_value', 'line_ids.dec_value', 'line_ids.jan_value', 'line_ids.feb_value', 'line_ids.mar_value' ) def _compute_monthly_totals(self): for rec in self: rec.total_april_value = sum(line.apr_value for line in rec.line_ids) rec.total_may_value = sum(line.may_value for line in rec.line_ids) rec.total_june_value = sum(line.jun_value for line in rec.line_ids) rec.total_july_value = sum(line.jul_value for line in rec.line_ids) rec.total_august_value = sum(line.aug_value for line in rec.line_ids) rec.total_september_value = sum(line.sep_value for line in rec.line_ids) rec.total_october_value = sum(line.oct_value for line in rec.line_ids) rec.total_november_value = sum(line.nov_value for line in rec.line_ids) rec.total_december_value = sum(line.dec_value for line in rec.line_ids) rec.total_january_value = sum(line.jan_value for line in rec.line_ids) rec.total_february_value = sum(line.feb_value for line in rec.line_ids) rec.total_march_value = sum(line.mar_value for line in rec.line_ids) def _get_financial_year(self): current_date = date.today() start_year = current_date.year if current_date.month >= 4 else current_date.year - 1 end_year = start_year + 1 return f"FY {start_year}-{end_year}" class sos_sales_plan_target_Line(models.Model): _name = 'sos_sales_plan_target_lines' _description = 'Sosaley Sales Target Lines' ref_id = fields.Many2one('sos_sales_plan_target', string="Sales Target") region = fields.Char(string="Region / Vertical") customer_name = fields.Many2one('sos_customers',string="Customer Name",domain=lambda self: [('responsible', '=', self.env.uid)]) product = fields.Selection( [ ('BHMS 1.2V', 'BHMS 1.2V'), ('BHMS 2V', 'BHMS 2V'), ('BHMS 12V', 'BHMS 12V'), ('BHMS 48V', 'BHMS 48V'), ('BMS-HV', 'BMS-HV'), ('BMS-LV 100A', 'BMS-LV 100A'), ('BMS-LV 40A', 'BMS-LV 40A'), ('SBMS 55A', 'SBMS 55A'), ('MC 250W', 'MC 250W'), ('HeartTarang', 'HeartTarang') ], string="Products") location = fields.Char(string="Location") date_billed = fields.Date(string="Date (Billed)") apr_qty = fields.Integer(string="April Qty") apr_value = fields.Float(string="April Value", digits=(12, 2)) may_qty = fields.Integer(string="May Qty") may_value = fields.Float(string="May Value", digits=(12, 2)) jun_qty = fields.Integer(string="June Qty") jun_value = fields.Float(string="June Value", digits=(12, 2)) jul_qty = fields.Integer(string="July Qty") jul_value = fields.Float(string="July Value", digits=(12, 2)) aug_qty = fields.Integer(string="August Qty") aug_value = fields.Float(string="August Value", digits=(12, 2)) sep_qty = fields.Integer(string="September Qty") sep_value = fields.Float(string="September Value", digits=(12, 2)) oct_qty = fields.Integer(string="October Qty") oct_value = fields.Float(string="October Value", digits=(12, 2)) nov_qty = fields.Integer(string="November Qty") nov_value = fields.Float(string="November Value", digits=(12, 2)) dec_qty = fields.Integer(string="December Qty") dec_value = fields.Float(string="December Value", digits=(12, 2)) jan_qty = fields.Integer(string="January Qty") jan_value = fields.Float(string="January Value", digits=(12, 2)) feb_qty = fields.Integer(string="February Qty") feb_value = fields.Float(string="February Value", digits=(12, 2)) mar_qty = fields.Integer(string="March Qty") mar_value = fields.Float(string="March Value", digits=(12, 2)) @api.onchange('customer_name') def _onchange_customer_name(self): if self.customer_name: self.location = self.customer_name.customer_city or ''