# Copyright 2013 Julius Network Solutions # Copyright 2015 Clear Corp # Copyright 2016 OpenSynergy Indonesia # Copyright 2017 ForgeFlow S.L. # Copyright 2018 Hibou Corp. # Copyright 2023 Quartile Limited # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from odoo import api, fields, models class StockMove(models.Model): _name = "stock.move" _inherit = ["stock.move", "analytic.mixin"] analytic_distribution = fields.Json( inverse="_inverse_analytic_distribution", ) def _inverse_analytic_distribution(self): """If analytic distribution is set on move, write it on all move lines""" for move in self: move.move_line_ids.write( {"analytic_distribution": move.analytic_distribution} ) def _prepare_account_move_line( self, qty, cost, credit_account_id, debit_account_id, svl_id, description ): self.ensure_one() res = super(StockMove, self)._prepare_account_move_line( qty, cost, credit_account_id, debit_account_id, svl_id, description ) if not self.analytic_distribution: return res accounts = self.product_id.product_tmpl_id.get_product_accounts() account_valuation_id = ( accounts.get("stock_valuation") and accounts["stock_valuation"].id ) for line in res: if line[2]["account_id"] != account_valuation_id: # Add analytic account in debit line line[2].update({"analytic_distribution": self.analytic_distribution}) return res def _prepare_procurement_values(self): """ Allows to transmit analytic account from moves to new moves through procurement. """ res = super()._prepare_procurement_values() if self.analytic_distribution: res.update( { "analytic_distribution": self.analytic_distribution, } ) return res def _prepare_move_line_vals(self, quantity=None, reserved_quant=None): """ We fill in the analytic account when creating the move line from the move """ res = super()._prepare_move_line_vals( quantity=quantity, reserved_quant=reserved_quant ) if self.analytic_distribution: res.update({"analytic_distribution": self.analytic_distribution}) return res def _need_validate_distribution(self): """Return moves are made outside the scope of the validation for now, since there could be cases where the necessity cannot be judged solely by the operation type. """ self.ensure_one() if self._is_in() and self._is_returned(valued_type="in"): return False elif self._is_out() and self._is_returned(valued_type="out"): return False elif self.company_id.anglo_saxon_accounting and self._is_dropshipped_returned(): return False return True def _action_done(self, cancel_backorder=False): for move in self: move.move_line_ids.analytic_distribution = move.analytic_distribution if not move._need_validate_distribution(): continue move._validate_distribution( **{ "product": move.product_id.id, "picking_type": move.picking_type_id.id, "business_domain": "stock_move", "company_id": move.company_id.id, } ) return super()._action_done(cancel_backorder=cancel_backorder) class StockMoveLine(models.Model): _name = "stock.move.line" _inherit = ["stock.move.line", "analytic.mixin"] @api.model def _prepare_stock_move_vals(self): """ In the case move lines are created manually, we should fill in the new move created here with the analytic account if filled in. """ res = super()._prepare_stock_move_vals() if self.analytic_distribution: res.update({"analytic_distribution": self.analytic_distribution}) return res def write(self, vals): if "analytic_distribution" in vals: self.move_id.analytic_distribution = vals["analytic_distribution"] return super().write(vals)