diff --git a/addons/analytic/models/analytic_mixin.py b/addons/analytic/models/analytic_mixin.py index 33f3dc4c7f2..1cf4154bcb0 100644 --- a/addons/analytic/models/analytic_mixin.py +++ b/addons/analytic/models/analytic_mixin.py @@ -29,7 +29,7 @@ class AnalyticMixin(models.AbstractModel): FROM information_schema.tables WHERE table_name=%s ''' self.env.cr.execute(query, [self._table]) - if self.env.cr.dictfetchone(): + if self.env.cr.dictfetchone() and self._fields['analytic_distribution'].store: query = f""" CREATE INDEX IF NOT EXISTS {self._table}_analytic_distribution_gin_index ON {self._table} USING gin(analytic_distribution); diff --git a/addons/mrp_account/models/analytic_account.py b/addons/mrp_account/models/analytic_account.py index 1cf3e213eed..1d87481aa5d 100644 --- a/addons/mrp_account/models/analytic_account.py +++ b/addons/mrp_account/models/analytic_account.py @@ -8,11 +8,11 @@ class AccountAnalyticAccount(models.Model): _inherit = 'account.analytic.account' _description = 'Analytic Account' - production_ids = fields.One2many('mrp.production', 'analytic_account_id', string='Manufacturing Orders') + production_ids = fields.Many2many('mrp.production') production_count = fields.Integer("Manufacturing Orders Count", compute='_compute_production_count') - bom_ids = fields.One2many('mrp.bom', 'analytic_account_id', string='Bills of Materials') + bom_ids = fields.Many2many('mrp.bom') bom_count = fields.Integer("BoM Count", compute='_compute_bom_count') - workcenter_ids = fields.One2many('mrp.workcenter', 'costs_hour_account_id', string='Workcenters') + workcenter_ids = fields.Many2many('mrp.workcenter') workorder_count = fields.Integer("Work Order Count", compute='_compute_workorder_count') @api.depends('production_ids') @@ -77,3 +77,14 @@ class AccountAnalyticLine(models.Model): _inherit = 'account.analytic.line' category = fields.Selection(selection_add=[('manufacturing_order', 'Manufacturing Order')]) + +class AccountAnalyticApplicability(models.Model): + _inherit = 'account.analytic.applicability' + _description = "Analytic Plan's Applicabilities" + + business_domain = fields.Selection( + selection_add=[ + ('manufacturing_order', 'Manufacturing Order'), + ], + ondelete={'manufacturing_order': 'cascade'}, + ) diff --git a/addons/mrp_account/models/mrp_bom.py b/addons/mrp_account/models/mrp_bom.py index 8ab3aba569c..7f23d2d1774 100644 --- a/addons/mrp_account/models/mrp_bom.py +++ b/addons/mrp_account/models/mrp_bom.py @@ -1,10 +1,48 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +import json + +from odoo import models, api, fields -from odoo import fields, models class MrpBom(models.Model): - _inherit = 'mrp.bom' + _name = 'mrp.bom' + _inherit = ['mrp.bom', 'analytic.mixin'] - analytic_account_id = fields.Many2one('account.analytic.account', 'Analytic Account', company_dependent=True, copy=True, - help="Analytic account in which cost and revenue entries will take place for financial management of the manufacturing order.") + # Company dependent JSON fields are not yet supported + analytic_distribution_text = fields.Text(company_dependent=True) + analytic_distribution = fields.Json(inverse="_inverse_analytic_distribution", store=False, precompute=False) + analytic_account_ids = fields.Many2many('account.analytic.account', compute="_compute_analytic_account_ids", copy=True) + + @api.depends_context('company') + @api.depends('analytic_distribution_text') + def _compute_analytic_distribution(self): + for record in self: + record.analytic_distribution = json.loads(record.analytic_distribution_text or '{}') + + def _inverse_analytic_distribution(self): + for record in self: + record.analytic_distribution_text = json.dumps(record.analytic_distribution) + + @api.depends('analytic_distribution') + def _compute_analytic_account_ids(self): + for record in self: + record.analytic_account_ids = list(map(int, record.analytic_distribution.keys())) if record.analytic_distribution else [] + + @api.onchange('product_id') + def _onchange_analytic_distribution(self): + for record in self: + if record.product_id: + record.analytic_distribution = record.env['account.analytic.distribution.model']._get_distribution({ + "product_id": record.product_id.id, + "product_categ_id": record.product_id.categ_id.id, + "company_id": record.company_id.id, + }) + + @api.constrains('analytic_distribution') + def _check_analytic(self): + for record in self: + record.with_context({'validate_analytic': True})._validate_distribution(**{ + 'product': record.product_id.id, + 'company_id': record.company_id.id, + }) diff --git a/addons/mrp_account/models/mrp_production.py b/addons/mrp_account/models/mrp_production.py index 10ee676c9ca..3ebb7d484e4 100644 --- a/addons/mrp_account/models/mrp_production.py +++ b/addons/mrp_account/models/mrp_production.py @@ -1,53 +1,60 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. - from ast import literal_eval from odoo import api, fields, models, _ -from odoo.tools import float_is_zero, float_round +from odoo.tools import float_round class MrpProduction(models.Model): - _inherit = 'mrp.production' + _name = 'mrp.production' + _inherit = ['mrp.production', 'analytic.mixin'] extra_cost = fields.Float(copy=False, string='Extra Unit Cost') show_valuation = fields.Boolean(compute='_compute_show_valuation') - analytic_account_id = fields.Many2one( - 'account.analytic.account', 'Analytic Account', copy=True, - help="Analytic account in which cost and revenue entries will take\ - place for financial management of the manufacturing order.", - compute='_compute_analytic_account_id', store=True, readonly=False) + analytic_account_ids = fields.Many2many('account.analytic.account', compute='_compute_analytic_account_ids', store=True) def _compute_show_valuation(self): for order in self: order.show_valuation = any(m.state == 'done' for m in order.move_finished_ids) - @api.depends('bom_id') - def _compute_analytic_account_id(self): - if self.bom_id.analytic_account_id: - self.analytic_account_id = self.bom_id.analytic_account_id + @api.depends('bom_id', 'product_id') + def _compute_analytic_distribution(self): + for record in self: + if record.bom_id.analytic_distribution: + record.analytic_distribution = record.bom_id.analytic_distribution + else: + record.analytic_distribution = record.env['account.analytic.distribution.model']._get_distribution({ + "product_id": record.product_id.id, + "product_categ_id": record.product_id.categ_id.id, + "company_id": record.company_id.id, + }) + + @api.depends('analytic_distribution') + def _compute_analytic_account_ids(self): + for record in self: + record.analytic_account_ids = list( + map(int, record.analytic_distribution.keys())) if record.analytic_distribution else [] + + @api.constrains('analytic_distribution') + def _check_analytic(self): + for record in self: + params = {'business_domain': 'manufacturing_order', 'company_id': record.company_id.id} + if record.product_id: + params['product'] = record.product_id.id + record.with_context({'validate_analytic': True})._validate_distribution(**params) def write(self, vals): - origin_analytic_account = {production: production.analytic_account_id for production in self} res = super().write(vals) for production in self: if vals.get('name'): - production.move_raw_ids.analytic_account_line_id.ref = production.display_name + production.move_raw_ids.analytic_account_line_ids.ref = production.display_name for workorder in production.workorder_ids: - workorder.mo_analytic_account_line_id.ref = production.display_name - workorder.mo_analytic_account_line_id.name = _("[WC] %s", workorder.display_name) - if 'analytic_account_id' in vals and production.state != 'draft': - if vals['analytic_account_id'] and origin_analytic_account[production]: - # Link the account analytic lines to the new AA - production.move_raw_ids.analytic_account_line_id.write({'account_id': vals['analytic_account_id']}) - production.workorder_ids.mo_analytic_account_line_id.write({'account_id': vals['analytic_account_id']}) - elif vals['analytic_account_id'] and not origin_analytic_account[production]: - # Create the account analytic lines if no AA is set in the MO - production.move_raw_ids._account_analytic_entry_move() - production.workorder_ids._create_or_update_analytic_entry() - else: - production.move_raw_ids.analytic_account_line_id.unlink() - production.workorder_ids.mo_analytic_account_line_id.unlink() + workorder.mo_analytic_account_line_ids.ref = production.display_name + workorder.mo_analytic_account_line_ids.name = _("[WC] %s", workorder.display_name) + if 'analytic_distribution' in vals and production.state != 'draft': + production.move_raw_ids._account_analytic_entry_move() + production.workorder_ids._create_or_update_analytic_entry() return res def action_view_stock_valuation_layers(self): @@ -60,15 +67,14 @@ class MrpProduction(models.Model): context['search_default_group_by_product_id'] = False return dict(action, domain=domain, context=context) - def action_view_analytic_account(self): + def action_view_analytic_accounts(self): self.ensure_one() return { "type": "ir.actions.act_window", "res_model": "account.analytic.account", - 'res_id': self.analytic_account_id.id, - "context": {"create": False}, - "name": _("Analytic Account"), - 'view_mode': 'form', + 'domain': [('id', 'in', self.analytic_account_ids.ids)], + "name": _("Analytic Accounts"), + 'view_mode': 'tree,form', } def _cal_price(self, consumed_moves): diff --git a/addons/mrp_account/models/mrp_workcenter.py b/addons/mrp_account/models/mrp_workcenter.py index 3cddf595e66..6f56856beaa 100644 --- a/addons/mrp_account/models/mrp_workcenter.py +++ b/addons/mrp_account/models/mrp_workcenter.py @@ -1,12 +1,23 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo import fields, models +from odoo import api, models, fields class MrpWorkcenter(models.Model): - _inherit = 'mrp.workcenter' + _name = 'mrp.workcenter' + _inherit = ['mrp.workcenter', 'analytic.mixin'] - costs_hour_account_id = fields.Many2one( - 'account.analytic.account', string='Analytic Account', - help="Posts analytical accounting entries in real time for both component and operational costs.") + costs_hour_account_ids = fields.Many2many('account.analytic.account', compute="_compute_costs_hour_account_ids", store=True) + + @api.depends('analytic_distribution') + def _compute_costs_hour_account_ids(self): + for record in self: + record.costs_hour_account_ids = list(map(int, record.analytic_distribution.keys())) if record.analytic_distribution else [] + + @api.constrains('analytic_distribution') + def _check_analytic(self): + for record in self: + record.with_context({'validate_analytic': True})._validate_distribution(**{ + 'company_id': record.company_id.id, + }) diff --git a/addons/mrp_account/models/mrp_workorder.py b/addons/mrp_account/models/mrp_workorder.py index 89c7e8a2fab..9cd2f7e285c 100644 --- a/addons/mrp_account/models/mrp_workorder.py +++ b/addons/mrp_account/models/mrp_workorder.py @@ -2,14 +2,13 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo import fields, models, _ -from odoo.tools import float_is_zero class MrpWorkorder(models.Model): _inherit = 'mrp.workorder' - mo_analytic_account_line_id = fields.Many2one('account.analytic.line', copy=False) - wc_analytic_account_line_id = fields.Many2one('account.analytic.line', copy=False) + mo_analytic_account_line_ids = fields.Many2many('account.analytic.line', 'mrp_workorder_mo_analytic_rel', copy=False) + wc_analytic_account_line_ids = fields.Many2many('account.analytic.line', 'mrp_workorder_wc_analytic_rel', copy=False) def _compute_duration(self): res = super()._compute_duration() @@ -22,15 +21,15 @@ class MrpWorkorder(models.Model): return res def action_cancel(self): - (self.mo_analytic_account_line_id | self.wc_analytic_account_line_id).unlink() + (self.mo_analytic_account_line_ids | self.wc_analytic_account_line_ids).unlink() return super().action_cancel() - def _prepare_analytic_line_values(self, account, unit_amount, amount): + def _prepare_analytic_line_values(self, account, amount, unit_amount): self.ensure_one() return { 'name': _("[WC] %s", self.display_name), 'amount': amount, - 'account_id': account.id, + 'account_id': account, 'unit_amount': unit_amount, 'product_id': self.product_id.id, 'product_uom_id': self.env.ref('uom.product_uom_hour').id, @@ -40,43 +39,18 @@ class MrpWorkorder(models.Model): } def _create_or_update_analytic_entry(self): - wo_to_link_mo_analytic_line = self.env['mrp.workorder'] - wo_to_link_wc_analytic_line = self.env['mrp.workorder'] - mo_analytic_line_vals_list = [] - wc_analytic_line_vals_list = [] - for wo in self.filtered(lambda wo: wo.production_id.analytic_account_id or wo.workcenter_id.costs_hour_account_id): + for wo in self.filtered(lambda wo: wo.id and (wo.production_id.analytic_distribution or wo.workcenter_id.analytic_distribution or wo.wc_analytic_account_line_ids or wo.mo_analytic_account_line_ids)): hours = wo.duration / 60.0 value = -hours * wo.workcenter_id.costs_hour - mo_account = wo.production_id.analytic_account_id - wc_account = wo.workcenter_id.costs_hour_account_id - if mo_account: - mo_currency = mo_account.currency_id or wo.company_id.currency_id - is_zero = float_is_zero(value, precision_rounding=mo_currency.rounding) - if wo.mo_analytic_account_line_id: - wo.mo_analytic_account_line_id.write({ - 'unit_amount': hours, - 'amount': value if not is_zero else 0, - }) - elif not is_zero: - wo_to_link_mo_analytic_line += wo - mo_analytic_line_vals_list.append(wo._prepare_analytic_line_values(mo_account, hours, value)) - if wc_account and wc_account != mo_account: - is_zero = float_is_zero(value, precision_rounding=wc_account.currency_id.rounding) - if wo.wc_analytic_account_line_id: - wo.wc_analytic_account_line_id.write({ - 'unit_amount': hours, - 'amount': value if not is_zero else 0, - }) - elif not is_zero: - wo_to_link_wc_analytic_line += wo - wc_analytic_line_vals_list.append(wo._prepare_analytic_line_values(wc_account, hours, value)) - analytic_lines = self.env['account.analytic.line'].sudo().create(mo_analytic_line_vals_list + wc_analytic_line_vals_list) - mo_analytic_lines, wc_analytic_lines = analytic_lines[:len(wo_to_link_mo_analytic_line)], analytic_lines[len(wo_to_link_mo_analytic_line):] - for wo, analytic_line in zip(wo_to_link_mo_analytic_line, mo_analytic_lines): - wo.mo_analytic_account_line_id = analytic_line - for wo, analytic_line in zip(wo_to_link_wc_analytic_line, wc_analytic_lines): - wo.wc_analytic_account_line_id = analytic_line + + mo_analytic_line_vals = self.env['account.analytic.account']._perform_analytic_distribution(wo.production_id.analytic_distribution, value, hours, wo.mo_analytic_account_line_ids, wo) + if mo_analytic_line_vals: + wo.mo_analytic_account_line_ids += self.env['account.analytic.line'].sudo().create(mo_analytic_line_vals) + + wc_analytic_line_vals = self.env['account.analytic.account']._perform_analytic_distribution(wo.workcenter_id.analytic_distribution, value, hours, wo.wc_analytic_account_line_ids, wo) + if wc_analytic_line_vals: + wo.wc_analytic_account_line_ids += self.env['account.analytic.line'].sudo().create(wc_analytic_line_vals) def unlink(self): - (self.mo_analytic_account_line_id | self.wc_analytic_account_line_id).unlink() + (self.mo_analytic_account_line_ids | self.wc_analytic_account_line_ids).unlink() return super().unlink() diff --git a/addons/mrp_account/models/stock_move.py b/addons/mrp_account/models/stock_move.py index e13ff82be58..4b22c852fa6 100644 --- a/addons/mrp_account/models/stock_move.py +++ b/addons/mrp_account/models/stock_move.py @@ -12,19 +12,19 @@ class StockMove(models.Model): res += self.filtered(lambda m: m.bom_line_id.bom_id.product_tmpl_id.id == product.product_tmpl_id.id) return res - def _generate_analytic_lines_data(self, unit_amount, amount): - vals = super()._generate_analytic_lines_data(unit_amount, amount) - if self.raw_material_production_id.analytic_account_id: + def _generate_analytic_lines_data(self, unit_amount, amount, distribution, account, distribution_on_each_plan): + vals = super()._generate_analytic_lines_data(unit_amount, amount, distribution, account, distribution_on_each_plan) + if self._get_analytic_distribution(): vals['name'] = _('[Raw] %s', self.product_id.display_name) vals['ref'] = self.raw_material_production_id.display_name vals['category'] = 'manufacturing_order' return vals - def _get_analytic_account(self): - account = self.raw_material_production_id.analytic_account_id - if account: - return account - return super()._get_analytic_account() + def _get_analytic_distribution(self): + distribution = self.raw_material_production_id.analytic_distribution + if distribution: + return distribution + return super()._get_analytic_distribution() def _ignore_automatic_valuation(self): return bool(self.raw_material_production_id) diff --git a/addons/mrp_account/models/stock_rule.py b/addons/mrp_account/models/stock_rule.py index f10a8bc17f6..5c1624eccdf 100644 --- a/addons/mrp_account/models/stock_rule.py +++ b/addons/mrp_account/models/stock_rule.py @@ -9,6 +9,6 @@ class StockRule(models.Model): def _prepare_mo_vals(self, product_id, product_qty, product_uom, location_id, name, origin, company_id, values, bom): res = super()._prepare_mo_vals(product_id, product_qty, product_uom, location_id, name, origin, company_id, values, bom) - if not bom.analytic_account_id and values.get('analytic_account_id'): - res['analytic_account_id'] = values.get('analytic_account_id').id + if not bom.analytic_distribution and values.get('analytic_distribution'): + res['analytic_distribution'] = values.get('analytic_distribution') return res diff --git a/addons/mrp_account/tests/test_analytic_account.py b/addons/mrp_account/tests/test_analytic_account.py index ee25eb56ac1..8c9488eacb9 100644 --- a/addons/mrp_account/tests/test_analytic_account.py +++ b/addons/mrp_account/tests/test_analytic_account.py @@ -64,32 +64,30 @@ class TestAnalyticAccount(TestMrpAnalyticAccount): mo_form.product_id = self.product mo_form.bom_id = self.bom mo_form.product_qty = 10.0 - mo_form.analytic_account_id = self.analytic_account + mo_form.analytic_distribution = {str(self.analytic_account.id): 100.0} mo = mo_form.save() mo.action_confirm() self.assertEqual(mo.state, 'confirmed') - self.assertEqual(len(mo.move_raw_ids.analytic_account_line_id), 0) + self.assertEqual(len(mo.move_raw_ids.analytic_account_line_ids), 0) # increase qty_producing to 5.0 mo_form = Form(mo) mo_form.qty_producing = 5.0 mo_form.save() self.assertEqual(mo.state, 'progress') - self.assertEqual(mo.move_raw_ids.analytic_account_line_id.amount, -50.0) + self.assertEqual(mo.move_raw_ids.analytic_account_line_ids.amount, -50.0) # increase qty_producing to 10.0 mo_form = Form(mo) mo_form.qty_producing = 10.0 mo_form.save() - # Hack to bypass test doing strange things - mo._set_qty_producing() mo.workorder_ids.button_finish() self.assertEqual(mo.state, 'to_close') - self.assertEqual(mo.move_raw_ids.analytic_account_line_id.amount, -100.0) + self.assertEqual(mo.move_raw_ids.analytic_account_line_ids.amount, -100.0) # mark as done mo.button_mark_done() self.assertEqual(mo.state, 'done') - self.assertEqual(mo.move_raw_ids.analytic_account_line_id.amount, -100.0) + self.assertEqual(mo.move_raw_ids.analytic_account_line_ids.amount, -100.0) def test_mo_analytic_backorder(self): """Test the analytic lines are correctly posted when backorder. @@ -99,65 +97,23 @@ class TestAnalyticAccount(TestMrpAnalyticAccount): mo_form.product_id = self.product mo_form.bom_id = self.bom mo_form.product_qty = 10.0 - mo_form.analytic_account_id = self.analytic_account + mo_form.analytic_distribution = {str(self.analytic_account.id): 100.0} mo = mo_form.save() mo.action_confirm() self.assertEqual(mo.state, 'confirmed') - self.assertEqual(len(mo.move_raw_ids.analytic_account_line_id), 0) + self.assertEqual(len(mo.move_raw_ids.analytic_account_line_ids), 0) # increase qty_producing to 5.0 mo_form = Form(mo) mo_form.qty_producing = 5.0 mo_form.save() self.assertEqual(mo.state, 'progress') - self.assertEqual(mo.move_raw_ids.analytic_account_line_id.amount, -50.0) + self.assertEqual(mo.move_raw_ids.analytic_account_line_ids.amount, -50.0) backorder_wizard_dict = mo.button_mark_done() Form(self.env[(backorder_wizard_dict.get('res_model'))].with_context(backorder_wizard_dict['context'])).save().action_backorder() self.assertEqual(mo.state, 'done') - self.assertEqual(mo.move_raw_ids.analytic_account_line_id.amount, -50.0) - - def test_workcenter_same_analytic_account(self): - """Test when workcenter and MO are using the same analytic account, no - duplicated lines will be post. - """ - # Required for `workorder_ids` to be visible in the view - self.env.user.groups_id += self.env.ref('mrp.group_mrp_routings') - # set wc analytic account to be the same of the one on the bom - self.workcenter.costs_hour_account_id = self.analytic_account - - # create a mo - mo_form = Form(self.env['mrp.production']) - mo_form.product_id = self.product - mo_form.bom_id = self.bom - mo_form.product_qty = 10.0 - mo_form.analytic_account_id = self.analytic_account - mo = mo_form.save() - mo.action_confirm() - self.assertEqual(len(mo.workorder_ids.wc_analytic_account_line_id), 0) - - # change duration to 60 - mo_form = Form(mo) - with mo_form.workorder_ids.edit(0) as line_edit: - line_edit.duration = 60.0 - mo_form.save() - self.assertEqual(mo.workorder_ids.mo_analytic_account_line_id.amount, -10.0) - self.assertEqual(len(mo.workorder_ids.wc_analytic_account_line_id), 0) - - # change duration to 120 - with mo_form.workorder_ids.edit(0) as line_edit: - line_edit.duration = 120.0 - mo_form.save() - self.assertEqual(mo.workorder_ids.mo_analytic_account_line_id.amount, -20.0) - self.assertEqual(len(mo.workorder_ids.wc_analytic_account_line_id), 0) - - # mark as done - mo_form.qty_producing = 10.0 - mo_form.save() - mo.button_mark_done() - self.assertEqual(mo.state, 'done') - self.assertEqual(mo.workorder_ids.mo_analytic_account_line_id.amount, -20.0) - self.assertEqual(len(mo.workorder_ids.wc_analytic_account_line_id), 0) + self.assertEqual(mo.move_raw_ids.analytic_account_line_ids.amount, -50.0) def test_workcenter_different_analytic_account(self): """Test when workcenter and MO are using the same analytic account, no @@ -168,46 +124,46 @@ class TestAnalyticAccount(TestMrpAnalyticAccount): # set wc analytic account to be different from the one on the bom analytic_plan = self.env['account.analytic.plan'].create({'name': 'Plan Test', 'company_id': False}) wc_analytic_account = self.env['account.analytic.account'].create({'name': 'wc_analytic_account', 'plan_id': analytic_plan.id}) - self.workcenter.costs_hour_account_id = wc_analytic_account + self.workcenter.analytic_distribution = {str(wc_analytic_account.id): 100.0} # create a mo mo_form = Form(self.env['mrp.production']) mo_form.product_id = self.product mo_form.bom_id = self.bom mo_form.product_qty = 10.0 - mo_form.analytic_account_id = self.analytic_account + mo_form.analytic_distribution = {str(self.analytic_account.id): 100.0} mo = mo_form.save() mo.action_confirm() - self.assertEqual(len(mo.workorder_ids.wc_analytic_account_line_id), 0) + self.assertEqual(len(mo.workorder_ids.wc_analytic_account_line_ids), 0) # change duration to 60 mo_form = Form(mo) with mo_form.workorder_ids.edit(0) as line_edit: line_edit.duration = 60.0 mo_form.save() - self.assertEqual(mo.workorder_ids.mo_analytic_account_line_id.amount, -10.0) - self.assertEqual(mo.workorder_ids.mo_analytic_account_line_id.account_id, self.analytic_account) - self.assertEqual(mo.workorder_ids.wc_analytic_account_line_id.amount, -10.0) - self.assertEqual(mo.workorder_ids.wc_analytic_account_line_id.account_id, wc_analytic_account) + self.assertEqual(mo.workorder_ids.mo_analytic_account_line_ids.amount, -10.0) + self.assertEqual(mo.workorder_ids.mo_analytic_account_line_ids.account_id, self.analytic_account) + self.assertEqual(mo.workorder_ids.wc_analytic_account_line_ids.amount, -10.0) + self.assertEqual(mo.workorder_ids.wc_analytic_account_line_ids.account_id, wc_analytic_account) # change duration to 120 with mo_form.workorder_ids.edit(0) as line_edit: line_edit.duration = 120.0 mo_form.save() - self.assertEqual(mo.workorder_ids.mo_analytic_account_line_id.amount, -20.0) - self.assertEqual(mo.workorder_ids.mo_analytic_account_line_id.account_id, self.analytic_account) - self.assertEqual(mo.workorder_ids.wc_analytic_account_line_id.amount, -20.0) - self.assertEqual(mo.workorder_ids.wc_analytic_account_line_id.account_id, wc_analytic_account) + self.assertEqual(mo.workorder_ids.mo_analytic_account_line_ids.amount, -20.0) + self.assertEqual(mo.workorder_ids.mo_analytic_account_line_ids.account_id, self.analytic_account) + self.assertEqual(mo.workorder_ids.wc_analytic_account_line_ids.amount, -20.0) + self.assertEqual(mo.workorder_ids.wc_analytic_account_line_ids.account_id, wc_analytic_account) # mark as done mo_form.qty_producing = 10.0 mo_form.save() mo.button_mark_done() self.assertEqual(mo.state, 'done') - self.assertEqual(mo.workorder_ids.mo_analytic_account_line_id.amount, -20.0) - self.assertEqual(mo.workorder_ids.mo_analytic_account_line_id.account_id, self.analytic_account) - self.assertEqual(mo.workorder_ids.wc_analytic_account_line_id.amount, -20.0) - self.assertEqual(mo.workorder_ids.wc_analytic_account_line_id.account_id, wc_analytic_account) + self.assertEqual(mo.workorder_ids.mo_analytic_account_line_ids.amount, -20.0) + self.assertEqual(mo.workorder_ids.mo_analytic_account_line_ids.account_id, self.analytic_account) + self.assertEqual(mo.workorder_ids.wc_analytic_account_line_ids.amount, -20.0) + self.assertEqual(mo.workorder_ids.wc_analytic_account_line_ids.account_id, wc_analytic_account) def test_changing_mo_analytic_account(self): """ Check if the MO account analytic lines are correctly updated @@ -220,46 +176,46 @@ class TestAnalyticAccount(TestMrpAnalyticAccount): mo_form.product_id = self.product mo_form.bom_id = self.bom mo_form.product_qty = 1 - mo_form.analytic_account_id = self.analytic_account + mo_form.analytic_distribution = {str(self.analytic_account.id): 100.0} mo = mo_form.save() mo.action_confirm() self.assertEqual(mo.state, 'confirmed') - self.assertEqual(len(mo.move_raw_ids.analytic_account_line_id), 0) - self.assertEqual(len(mo.workorder_ids.mo_analytic_account_line_id), 0) + self.assertEqual(len(mo.move_raw_ids.analytic_account_line_ids), 0) + self.assertEqual(len(mo.workorder_ids.mo_analytic_account_line_ids), 0) # Change duration to 60 mo_form = Form(mo) with mo_form.workorder_ids.edit(0) as line_edit: line_edit.duration = 60.0 mo_form.save() - self.assertEqual(mo.workorder_ids.mo_analytic_account_line_id.account_id, self.analytic_account) + self.assertEqual(mo.workorder_ids.mo_analytic_account_line_ids.account_id, self.analytic_account) # Mark as done mo.button_mark_done() self.assertEqual(mo.state, 'done') - self.assertEqual(len(mo.move_raw_ids.analytic_account_line_id), 1) + self.assertEqual(len(mo.move_raw_ids.analytic_account_line_ids), 1) # Create a new analytic account analytic_plan = self.env['account.analytic.plan'].create({'name': 'Plan Test', 'company_id': False}) new_analytic_account = self.env['account.analytic.account'].create({'name': 'test_analytic_account_2', 'plan_id': analytic_plan.id}) # Change the MO analytic account - mo.analytic_account_id = new_analytic_account - self.assertEqual(mo.move_raw_ids.analytic_account_line_id.account_id.id, new_analytic_account.id) - self.assertEqual(mo.workorder_ids.mo_analytic_account_line_id.account_id.id, new_analytic_account.id) + mo.analytic_distribution = {str(new_analytic_account.id): 100.0} + self.assertEqual(mo.move_raw_ids.analytic_account_line_ids.account_id.id, new_analytic_account.id) + self.assertEqual(mo.workorder_ids.mo_analytic_account_line_ids.account_id.id, new_analytic_account.id) #Get the MO analytic account lines - mo_analytic_account_raw_lines = mo.move_raw_ids.analytic_account_line_id - mo_analytic_account_wc_lines = mo.workorder_ids.mo_analytic_account_line_id - mo.analytic_account_id = False + mo_analytic_account_raw_lines = mo.move_raw_ids.analytic_account_line_ids + mo_analytic_account_wc_lines = mo.move_raw_ids.analytic_account_line_ids + mo.analytic_distribution = {} # Check that the MO analytic account lines are deleted - self.assertEqual(len(mo.move_raw_ids.analytic_account_line_id), 0) - self.assertEqual(len(mo.workorder_ids.mo_analytic_account_line_id), 0) + self.assertEqual(len(mo.move_raw_ids.analytic_account_line_ids), 0) + self.assertEqual(len(mo.workorder_ids.mo_analytic_account_line_ids), 0) self.assertFalse(mo_analytic_account_raw_lines.exists()) self.assertFalse(mo_analytic_account_wc_lines.exists()) # Check that the AA lines are recreated correctly if we delete the AA, save the MO, and assign a new one - mo.analytic_account_id = self.analytic_account - self.assertEqual(len(mo.move_raw_ids.analytic_account_line_id), 1) - self.assertEqual(len(mo.workorder_ids.mo_analytic_account_line_id), 1) + mo.analytic_distribution = {str(self.analytic_account.id): 100.0} + self.assertEqual(len(mo.move_raw_ids.analytic_account_line_ids), 1) + self.assertEqual(len(mo.workorder_ids.mo_analytic_account_line_ids), 1) def test_add_remove_wo_analytic_no_company(self): """Test the addition and removal of work orders to a MO linked to @@ -275,7 +231,7 @@ class TestAnalyticAccount(TestMrpAnalyticAccount): # Create a mo linked to an analytic account with no associated company mo_no_company = self.env['mrp.production'].create({ 'product_id': self.product.id, - 'analytic_account_id': analytic_account_no_company.id, + 'analytic_distribution': {str(analytic_account_no_company.id): 100.0}, 'product_uom_id': self.bom.product_uom_id.id, }) @@ -289,7 +245,7 @@ class TestAnalyticAccount(TestMrpAnalyticAccount): }) mo_no_c_form.save() self.assertTrue(mo_no_company.workorder_ids) - self.assertEqual(wo.production_id.analytic_account_id, analytic_account_no_company) + self.assertEqual(wo.production_id.analytic_account_ids, analytic_account_no_company) self.assertEqual(len(analytic_account_no_company.line_ids), 1) mo_no_company.workorder_ids.unlink() self.assertEqual(len(analytic_account_no_company.line_ids), 0) diff --git a/addons/mrp_account/views/mrp_bom_views.xml b/addons/mrp_account/views/mrp_bom_views.xml index 5e42b78483e..24ef39867d8 100644 --- a/addons/mrp_account/views/mrp_bom_views.xml +++ b/addons/mrp_account/views/mrp_bom_views.xml @@ -6,7 +6,9 @@ - + diff --git a/addons/mrp_account/views/mrp_production_views.xml b/addons/mrp_account/views/mrp_production_views.xml index 4b68de29983..381c88e2678 100644 --- a/addons/mrp_account/views/mrp_production_views.xml +++ b/addons/mrp_account/views/mrp_production_views.xml @@ -5,7 +5,10 @@ - + @@ -29,9 +32,9 @@