From 4b64d5eee684cf2fdd664856e311e14199a68a24 Mon Sep 17 00:00:00 2001 From: Saran440 Date: Thu, 25 Jul 2024 17:58:23 +0700 Subject: [PATCH] [FIX] split line carry commit budget --- budget_control/models/analytic_account.py | 45 ++----- budget_control/models/base_budget_move.py | 15 ++- .../models/budget_commit_forward.py | 125 +++++++++--------- .../views/budget_commit_forward_view.xml | 12 +- .../wizards/budget_commit_forward_info.py | 44 +++--- .../budget_commit_forward_info_view.xml | 14 +- 6 files changed, 122 insertions(+), 133 deletions(-) diff --git a/budget_control/models/analytic_account.py b/budget_control/models/analytic_account.py index 334b495d..d23e14c1 100644 --- a/budget_control/models/analytic_account.py +++ b/budget_control/models/analytic_account.py @@ -192,44 +192,17 @@ def _auto_create_next_analytic(self, next_date_range): next_analytic.write(val_update) return next_analytic - @api.model - def _get_analytic_date(self, analytic_account, order): - """ - Finds the minimum or maximum date of an analytic account. - - :param analytic_account: Analytic account record - :param order: The order to search for the earliest or latest date - :return: The earliest or latest date found, or None if no records - """ - - # Access the analytic line model - AnalyticAccount = self.env["account.analytic.account"] - - # Construct the domain to search for the specific analytic account - domain = [('id', 'in', [analytic_id for analytic_id, _ in analytic_account.items()])] - # Perform the search - result = AnalyticAccount.search(domain, order=order, limit=1) - - # Return the date if a record is found, else None - return result - - @api.model - def next_year_analytic(self, analytic_distribution, auto_create=True): + def next_year_analytic(self, auto_create=True): """Find next analytic from analytic date_to + 1, if bm_date_to = False, this is an open end analytic, always return False""" - next_analytic_distribution = {} - for analytic_id, aa_percent in analytic_distribution.items(): - analytic = self.browse(int(analytic_id)) - # Use same analytic - if not analytic.bm_date_to: - next_analytic_distribution[str(analytic_id)] = aa_percent - continue - next_date_range = analytic.bm_date_to + relativedelta(days=1) - next_analytic = analytic._find_next_analytic(next_date_range) - if not next_analytic and auto_create: - next_analytic = analytic._auto_create_next_analytic(next_date_range) - next_analytic_distribution[str(next_analytic.id)] = aa_percent - return next_analytic_distribution + self.ensure_one() + if not self.bm_date_to: + return False + next_date_range = self.bm_date_to + relativedelta(days=1) + next_analytic = self._find_next_analytic(next_date_range) + if not next_analytic and auto_create: + next_analytic = self._auto_create_next_analytic(next_date_range) + return next_analytic def _check_budget_control_status(self, budget_period_id=False): """Warning for budget_control on budget_period, but not in controlled""" diff --git a/budget_control/models/base_budget_move.py b/budget_control/models/base_budget_move.py index 457943f1..2935717d 100644 --- a/budget_control/models/base_budget_move.py +++ b/budget_control/models/base_budget_move.py @@ -472,9 +472,17 @@ def commit_budget(self, reverse=False, **vals): to_commit = self.env.context.get("force_commit") or self._valid_commit_state() if self.can_commit and to_commit: budget_commit_vals = [] - analytic_account = self._convert_analytics( - analytic_distribution=vals.get("analytic_distribution", False) - ) + # Specific analytic account + if vals.get("analytic_account_id", False): + analytic_account = vals["analytic_account_id"] + else: + analytic_account = self._convert_analytics( + analytic_distribution=vals.get("analytic_distribution", False) + ) + # Delete analytic_distribution from vals + if vals.get("analytic_distribution"): + del vals["analytic_distribution"] + for analytic in analytic_account: # Set amount_currency budget_vals = self._init_docline_budget_vals(vals, analytic.id) @@ -483,6 +491,7 @@ def commit_budget(self, reverse=False, **vals): # Case force use_amount_commit, this should overwrite tax compute if self.env.context.get("use_amount_commit"): budget_vals["amount_currency"] = self.amount_commit + # Case forward_commit if self.env.context.get("fwd_amount_commit"): budget_vals["amount_currency"] = self.env.context.get( "fwd_amount_commit" diff --git a/budget_control/models/budget_commit_forward.py b/budget_control/models/budget_commit_forward.py index 9c6cee73..5b295c3a 100644 --- a/budget_control/models/budget_commit_forward.py +++ b/budget_control/models/budget_commit_forward.py @@ -63,7 +63,7 @@ def _compute_missing_analytic(self): for rec in self: rec.missing_analytic = any( rec.forward_line_ids.filtered_domain( - [("to_analytic_distribution", "=", False)] + [("to_analytic_account_id", "=", False)] ) ) @@ -98,30 +98,28 @@ def _prepare_vals_forward(self, docs, res_model): analytic_account = ( doc.fwd_analytic_distribution or doc[doc._budget_analytic_field] ) - # Get analytic min date - analytic_min_date = AnalyticAccount._get_analytic_date(analytic_account, "bm_date_to asc") - method_type = False - to_analytic_account_id = False - if analytic_min_date.bm_date_to and analytic_min_date.bm_date_to < self.to_date_commit: - method_type = "new" - - # to_analytic_account_id = analytic.next_year_analytic( - # auto_create=False - # ) - value_dict.append( - { - "forward_id": self.id, - "analytic_distribution": analytic_account, - "method_type": method_type, - "res_model": res_model, - "res_id": doc.id, - "document_id": "{},{}".format(doc._name, doc.id), - "document_number": self._get_document_number(doc), - "to_analytic_distribution": {}, - "amount_commit": doc.amount_commit, - "date_commit": doc.fwd_date_commit or doc.date_commit, - } - ) + for analytic_id, aa_percent in analytic_account.items(): + method_type = False + analytic = AnalyticAccount.browse(int(analytic_id)) + if ( + analytic.bm_date_to + and analytic.bm_date_to < self.to_date_commit + ): + method_type = "new" + value_dict.append( + { + "forward_id": self.id, + "analytic_account_id": analytic_id, + "analytic_percent": aa_percent / 100, + "method_type": method_type, + "res_model": res_model, + "res_id": doc.id, + "document_id": "{},{}".format(doc._name, doc.id), + "document_number": self._get_document_number(doc), + "amount_commit": doc.amount_commit * aa_percent / 100, + "date_commit": doc.fwd_date_commit or doc.date_commit, + } + ) return value_dict def action_review_budget_commit(self): @@ -140,13 +138,12 @@ def get_budget_commit_forward(self, res_model): Line.create(vals) def create_missing_analytic(self): - AnalyticAccount = self.env["account.analytic.account"] for rec in self: for line in rec.forward_line_ids.filtered_domain( - [("to_analytic_distribution", "=", False)] + [("to_analytic_account_id", "=", False)] ): - line.to_analytic_distribution = ( - AnalyticAccount.next_year_analytic(line.analytic_distribution) + line.to_analytic_account_id = ( + line.analytic_account_id.next_year_analytic() ) def preview_budget_commit_forward_info(self): @@ -184,13 +181,13 @@ def _get_forward_initial_commit(self, domain): self.ensure_one() forwards = self.env["budget.commit.forward.line"].read_group( domain, - ["to_analytic_distribution", "amount_commit"], - ["to_analytic_distribution"], - orderby="to_analytic_distribution", - ) + ["to_analytic_account_id", "amount_commit"], + ["to_analytic_account_id"], + orderby="to_analytic_account_id", + ) res = [ { - "analytic_distribution": f["to_analytic_distribution"], + "analytic_account_id": f["to_analytic_account_id"][0], "initial_commit": f["amount_commit"], } for f in forwards @@ -200,7 +197,7 @@ def _get_forward_initial_commit(self, domain): def _do_forward_commit(self, reverse=False): """Create carry forward budget move to all related documents""" self = self.sudo() - _analytic_field = "analytic_distribution" if reverse else "to_analytic_distribution" + _analytic_field = "analytic_account_id" if reverse else "to_analytic_account_id" for rec in self: group_document = {} # Group by document @@ -210,11 +207,10 @@ def _do_forward_commit(self, reverse=False): else: group_document[line.document_id] = [line] for doc, fwd_line in group_document.items(): + # Convert to json fwd_analytic_distribution = {} for line in fwd_line: - fwd_analytic_distribution[ - str(line[_analytic_field].id) - ] = line.analytic_percent + fwd_analytic_distribution[str(line[_analytic_field].id)] = line.analytic_percent * 100 doc.write( { "fwd_analytic_distribution": fwd_analytic_distribution, @@ -234,12 +230,12 @@ def _do_update_initial_commit(self, reverse=False): """Update all Analytic Account's initial commit value related to budget period""" self.ensure_one() # Reset initial when cancel document only - Analytic = self.env["account.analytic.account"] + AnalyticAccount = self.env["account.analytic.account"] domain = [("forward_id", "=", self.id)] if reverse: forward_vals = self._get_forward_initial_commit(domain) for val in forward_vals: - analytic = Analytic.browse(val["analytic_account_id"]) + analytic = AnalyticAccount.browse(val["analytic_account_id"]) analytic.initial_commit -= val["initial_commit"] return forward_duplicate = self.env["budget.commit.forward"].search( @@ -252,7 +248,7 @@ def _do_update_initial_commit(self, reverse=False): domain.append(("forward_id.state", "in", ["review", "done"])) forward_vals = self._get_forward_initial_commit(domain) for val in forward_vals: - analytic = Analytic.browse(val["analytic_account_id"]) + analytic = AnalyticAccount.browse(val["analytic_account_id"]) # Check first forward commit in the year, it should overwrite initial commit if not forward_duplicate: analytic.initial_commit = val["initial_commit"] @@ -296,7 +292,6 @@ def action_draft(self): class BudgetCommitForwardLine(models.Model): _name = "budget.commit.forward.line" - _inherit = "analytic.mixin" _description = "Budget Commit Forward Line" forward_id = fields.Many2one( @@ -307,6 +302,15 @@ class BudgetCommitForwardLine(models.Model): readonly=True, ondelete="cascade", ) + analytic_account_id = fields.Many2one( + comodel_name="account.analytic.account", + index=True, + required=True, + readonly=True, + ) + analytic_percent = fields.Float( + readonly=True, + ) method_type = fields.Selection( selection=[ ("new", "New"), @@ -316,13 +320,13 @@ class BudgetCommitForwardLine(models.Model): help="New: if the analytic has ended, 'To Analytic Account' is required\n" "Extended: if the analytic has ended, but want to extend to next period date end", ) - to_analytic_distribution = fields.Json( - string="To Analytic", - compute="_compute_to_analytic_distribution", + to_analytic_account_id = fields.Many2one( + comodel_name="account.analytic.account", + string="Forward to Analytic", + compute="_compute_to_analytic_account_id", store=True, ) bm_date_to = fields.Date( - string="Date To", compute="_compute_bm_date_to", ) res_model = fields.Selection( @@ -362,40 +366,33 @@ class BudgetCommitForwardLine(models.Model): readonly=True, ) - @api.depends("analytic_distribution") + @api.depends("analytic_account_id") def _compute_bm_date_to(self): - AnalyticAccount = self.env["account.analytic.account"] for rec in self: - analytic_min_date = AnalyticAccount._get_analytic_date(rec.analytic_distribution, "bm_date_to asc") - rec.bm_date_to = analytic_min_date.bm_date_to + rec.bm_date_to = rec.analytic_account_id.bm_date_to @api.depends("method_type") - def _compute_to_analytic_distribution(self): - AnalyticAccount = self.env["account.analytic.account"] + def _compute_to_analytic_account_id(self): for rec in self: - if not rec.analytic_distribution: - continue - analytic_min_date = AnalyticAccount._get_analytic_date(rec.analytic_distribution, "bm_date_to asc") - # Case analytic has no end date, always use same analytic - if not analytic_min_date.bm_date_to: - rec.to_analytic_distribution = rec.analytic_distribution + if not rec.analytic_account_id.bm_date_to: + rec.to_analytic_account_id = rec.analytic_account_id rec.method_type = False continue # Case analytic has extended end date that cover new commit date, use same analytic if ( - analytic_min_date.bm_date_to - and analytic_min_date.bm_date_to >= rec.forward_id.to_date_commit + rec.analytic_account_id.bm_date_to + and rec.analytic_account_id.bm_date_to >= rec.forward_id.to_date_commit ): - rec.to_analytic_distribution = rec.analytic_distribution + rec.to_analytic_account_id = rec.analytic_account_id rec.method_type = "extend" continue # Case want to extend analytic to end of next budget period if rec.method_type == "extend": - rec.to_analytic_distribution = rec.analytic_distribution + rec.to_analytic_account_id = rec.analytic_account_id continue # Case want to use next analytic, if exists if rec.method_type == "new": - rec.to_analytic_distribution = AnalyticAccount.next_year_analytic( - rec.analytic_distribution, auto_create=False + rec.to_analytic_account_id = rec.analytic_account_id.next_year_analytic( + auto_create=False ) diff --git a/budget_control/views/budget_commit_forward_view.xml b/budget_control/views/budget_commit_forward_view.xml index 84227764..789423de 100644 --- a/budget_control/views/budget_commit_forward_view.xml +++ b/budget_control/views/budget_commit_forward_view.xml @@ -22,7 +22,8 @@ - + + - + @@ -46,10 +50,10 @@ - + - + diff --git a/budget_control/wizards/budget_commit_forward_info.py b/budget_control/wizards/budget_commit_forward_info.py index 2f5a894c..a85fe593 100644 --- a/budget_control/wizards/budget_commit_forward_info.py +++ b/budget_control/wizards/budget_commit_forward_info.py @@ -1,7 +1,7 @@ # Copyright 2021 Ecosoft - (http://ecosoft.co.th) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import fields, models +from odoo import fields, models, api class BudgetCommitForwardInfo(models.TransientModel): @@ -32,7 +32,6 @@ def action_budget_commit_forward(self): class BudgetCommitForwardInfoLine(models.TransientModel): _name = "budget.commit.forward.info.line" - _inherit = "analytic.mixin" _description = "Budget Commitment Forward Info Line" forward_info_id = fields.Many2one( @@ -42,30 +41,37 @@ class BudgetCommitForwardInfoLine(models.TransientModel): readonly=True, ondelete="cascade", ) - # analytic_plan = fields.Many2one( - # comodel_name="account.analytic.plan", - # related="analytic_account_id.plan_id", - # readonly=True, - # ) - # initial_available = fields.Monetary( - # string="Initial Available", - # related="analytic_account_id.initial_available", - # readonly=True, - # ) + analytic_account_id = fields.Many2one( + string="Forward to Analytic", + comodel_name="account.analytic.account", + readonly=True, + ) + analytic_plan = fields.Many2one( + comodel_name="account.analytic.plan", + string="Analytic Group", + related="analytic_account_id.plan_id", + readonly=True, + ) + initial_available = fields.Monetary( + string="Initial Available", + related="analytic_account_id.initial_available", + readonly=True, + ) initial_commit = fields.Monetary( string="Initial Commitment", readonly=True, ) - # amount_balance = fields.Monetary( - # string="Available", - # compute="_compute_amount_balance", - # ) + amount_balance = fields.Monetary( + string="Available", + compute="_compute_amount_balance", + ) currency_id = fields.Many2one( comodel_name="res.currency", related="forward_info_id.currency_id", readonly=True, ) - # def _compute_amount_balance(self): - # for rec in self: - # rec.amount_balance = rec.initial_available - rec.initial_commit + @api.depends("initial_available", "initial_commit") + def _compute_amount_balance(self): + for rec in self: + rec.amount_balance = rec.initial_available - rec.initial_commit diff --git a/budget_control/wizards/budget_commit_forward_info_view.xml b/budget_control/wizards/budget_commit_forward_info_view.xml index b5df1f12..4ac06000 100644 --- a/budget_control/wizards/budget_commit_forward_info_view.xml +++ b/budget_control/wizards/budget_commit_forward_info_view.xml @@ -11,30 +11,30 @@ - - - + /> - + />