diff --git a/mrp_analytic_cost_material/README.rst b/mrp_analytic_cost/README.rst similarity index 100% rename from mrp_analytic_cost_material/README.rst rename to mrp_analytic_cost/README.rst diff --git a/mrp_analytic_cost_material/__init__.py b/mrp_analytic_cost/__init__.py similarity index 100% rename from mrp_analytic_cost_material/__init__.py rename to mrp_analytic_cost/__init__.py diff --git a/mrp_analytic_cost_material/__manifest__.py b/mrp_analytic_cost/__manifest__.py similarity index 61% rename from mrp_analytic_cost_material/__manifest__.py rename to mrp_analytic_cost/__manifest__.py index c8fa68292..76840a95e 100644 --- a/mrp_analytic_cost_material/__manifest__.py +++ b/mrp_analytic_cost/__manifest__.py @@ -3,15 +3,18 @@ { "name": "Manufacturing Materials Analytic Costs", - "summary": "Track raw material costs as Analytic Items during the \ - manufacturing process", + "summary": "Track manufacturing costs in real time, using Analytic Items", "version": "14.0.1.0.1", "category": "Manufacturing", "author": "Open Source Integrators, Odoo Community Association (OCA)", "website": "https://github.com/OCA/manufacture", "license": "AGPL-3", - "depends": ["mrp_analytic"], - "data": ["views/account_analytic_line_view.xml", "views/mrp_production_views.xml"], + "depends": ["mrp_analytic", "analytic_activity_based_cost"], + "data": [ + "views/account_analytic_line_view.xml", + "views/mrp_production_views.xml", + "views/mrp_workcenter_view.xml", + ], "maintainer": "dreispt", "development_status": "Alpha", "installable": True, diff --git a/mrp_analytic_cost_material/i18n/hu.po b/mrp_analytic_cost/i18n/hu.po similarity index 100% rename from mrp_analytic_cost_material/i18n/hu.po rename to mrp_analytic_cost/i18n/hu.po diff --git a/mrp_analytic_cost_material/i18n/mrp_analytic_cost_material.pot b/mrp_analytic_cost/i18n/mrp_analytic_cost_material.pot similarity index 100% rename from mrp_analytic_cost_material/i18n/mrp_analytic_cost_material.pot rename to mrp_analytic_cost/i18n/mrp_analytic_cost_material.pot diff --git a/mrp_analytic_cost_material/models/__init__.py b/mrp_analytic_cost/models/__init__.py similarity index 87% rename from mrp_analytic_cost_material/models/__init__.py rename to mrp_analytic_cost/models/__init__.py index 9d34c7c3d..fbd410b7f 100644 --- a/mrp_analytic_cost_material/models/__init__.py +++ b/mrp_analytic_cost/models/__init__.py @@ -3,4 +3,5 @@ from . import account_analytic_line from . import mrp_production +from . import mrp_workorder from . import stock_move diff --git a/mrp_analytic_cost_material/models/account_analytic_line.py b/mrp_analytic_cost/models/account_analytic_line.py similarity index 82% rename from mrp_analytic_cost_material/models/account_analytic_line.py rename to mrp_analytic_cost/models/account_analytic_line.py index 0044ff010..dc2c90b4f 100644 --- a/mrp_analytic_cost_material/models/account_analytic_line.py +++ b/mrp_analytic_cost/models/account_analytic_line.py @@ -7,11 +7,15 @@ from odoo import fields, models class AccountAnalyticLine(models.Model): _inherit = "account.analytic.line" - stock_move_id = fields.Many2one( - "stock.move", - string="Related Stock Move", - ) manufacturing_order_id = fields.Many2one( "mrp.production", string="Related Manufacturing Order", ) + stock_move_id = fields.Many2one( + "stock.move", + string="Related Stock Move", + ) + workorder_id = fields.Many2one( + "mrp.workorder", + string="Work Order", + ) diff --git a/mrp_analytic_cost_material/models/mrp_production.py b/mrp_analytic_cost/models/mrp_production.py similarity index 100% rename from mrp_analytic_cost_material/models/mrp_production.py rename to mrp_analytic_cost/models/mrp_production.py diff --git a/mrp_analytic_cost/models/mrp_workorder.py b/mrp_analytic_cost/models/mrp_workorder.py new file mode 100644 index 000000000..31f462185 --- /dev/null +++ b/mrp_analytic_cost/models/mrp_workorder.py @@ -0,0 +1,78 @@ +# Copyright (C) 2020 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class MRPWorkcenter(models.Model): + _inherit = "mrp.workcenter" + + @api.depends("analytic_product_id.standard_price") + def _compute_onchange_costs_hour(self): + """ + When using Cost Type Product, set the corresponding standard cost + and the work center hourly cost + """ + for wc in self: + standard_cost = wc.analytic_product_id.standard_price + if standard_cost: + wc.costs_hour = standard_cost + + analytic_product_id = fields.Many2one( + "product.product", string="Cost Type", domain="[('is_cost_type', '=', True)]" + ) + costs_hour = fields.Float( + compute="_compute_onchange_costs_hour", store=True, readonly=False + ) + + +class MRPWorkorder(models.Model): + _inherit = "mrp.workorder" + + def _prepare_mrp_workorder_analytic_item(self): + self.ensure_one() + return { + "name": "{} / {}".format(self.production_id.name, self.name), + "account_id": self.production_id.analytic_account_id.id, + "date": fields.Date.today(), + "company_id": self.company_id.id, + "manufacturing_order_id": self.production_id.id, + "product_id": self.workcenter_id.analytic_product_id.id, + "unit_amount": self.duration / 60, # convert minutes to hours + "workorder_id": self.id, + } + + def generate_mrp_work_analytic_line(self): + """Generate Analytic Lines""" + AnalyticLine = self.env["account.analytic.line"].sudo() + workorders = self.filtered("workcenter_id.analytic_product_id").filtered( + "production_id.analytic_account_id" + ) + existing_items = workorders and AnalyticLine.search( + [("workorder_id", "in", self.ids)] + ) + for workorder in workorders: + line_vals = self._prepare_mrp_workorder_analytic_item() + analytic_lines = existing_items.filtered( + lambda x: x.workorder_id == workorder + ) + if analytic_lines: + for analytic_line in analytic_lines: + analytic_line.write(line_vals) + analytic_line.on_change_unit_amount() + else: + analytic_line = AnalyticLine.create(line_vals) + analytic_line.on_change_unit_amount() + + @api.model + def create(self, vals): + res = super().create(vals) + if vals.get("duration"): + res.generate_mrp_work_analytic_line() + return res + + def write(self, vals): + res = super().write(vals) + if vals.get("duration"): + self.generate_mrp_work_analytic_line() + return res diff --git a/mrp_analytic_cost_material/models/stock_move.py b/mrp_analytic_cost/models/stock_move.py similarity index 92% rename from mrp_analytic_cost_material/models/stock_move.py rename to mrp_analytic_cost/models/stock_move.py index d984bc73f..9eeec95e5 100644 --- a/mrp_analytic_cost_material/models/stock_move.py +++ b/mrp_analytic_cost/models/stock_move.py @@ -48,6 +48,14 @@ class StockMove(models.Model): self.generate_mrp_raw_analytic_line() return res + @api.model + def create(self, vals): + qty_done = vals.get("qty_done") + res = super().create(vals) + if qty_done: + res.generate_mrp_raw_analytic_line() + return res + class StockMoveLine(models.Model): _inherit = "stock.move.line" diff --git a/mrp_analytic_cost/readme/CONFIGURATION.rst b/mrp_analytic_cost/readme/CONFIGURATION.rst new file mode 100644 index 000000000..e0eb7f85e --- /dev/null +++ b/mrp_analytic_cost/readme/CONFIGURATION.rst @@ -0,0 +1,3 @@ +* Create a Product for each cost type needed. Set the standard cost to use for each of them. + It is also recommended to properly organize them in Product Categories. +* On each Work Center, select the Cost Type Products to use for the operrations generated Analytic Items. diff --git a/mrp_analytic_cost_material/readme/CONTRIBUTORS.rst b/mrp_analytic_cost/readme/CONTRIBUTORS.rst similarity index 100% rename from mrp_analytic_cost_material/readme/CONTRIBUTORS.rst rename to mrp_analytic_cost/readme/CONTRIBUTORS.rst diff --git a/mrp_analytic_cost/readme/DESCRIPTION.rst b/mrp_analytic_cost/readme/DESCRIPTION.rst new file mode 100644 index 000000000..59e9259d5 --- /dev/null +++ b/mrp_analytic_cost/readme/DESCRIPTION.rst @@ -0,0 +1,12 @@ +Out of the box, manufacturing costs are only generated +when a Manufacturing Order is closed. + +There are cases where the manufacturing costs need to be tracked in real time. +This is especially important for manufacturing scenarios with a long cycle time, +spanning for multiple months. + +This feature allows to track costs while the manufacturing is in progress, +both for raw materials used and work order operations. + +Costs incurred are stored as Analytic Items, and can then be analyzed. +No journal entries are generated. diff --git a/mrp_analytic_cost_material/readme/USAGE.rst b/mrp_analytic_cost/readme/USAGE.rst similarity index 64% rename from mrp_analytic_cost_material/readme/USAGE.rst rename to mrp_analytic_cost/readme/USAGE.rst index 9fd13862b..c9de1984d 100644 --- a/mrp_analytic_cost_material/readme/USAGE.rst +++ b/mrp_analytic_cost/readme/USAGE.rst @@ -1,7 +1,10 @@ To use: * On the Manufacturing Order, set the Analytic Account to use. This may correspond to a Project. -* On Manufacturing Orders, when a stock reservation is triggered, Analytic Items are automatically generated . +* On Manufacturing Orders, Analytic Items are automatically generated when: + + * Raw materials are consumed, or + * Time is spent on work order Operations, with a Work Center with a Cost Type product set. To analyze costs: diff --git a/mrp_analytic_cost_material/static/description/icon.png b/mrp_analytic_cost/static/description/icon.png similarity index 100% rename from mrp_analytic_cost_material/static/description/icon.png rename to mrp_analytic_cost/static/description/icon.png diff --git a/mrp_analytic_cost_material/static/description/index.html b/mrp_analytic_cost/static/description/index.html similarity index 100% rename from mrp_analytic_cost_material/static/description/index.html rename to mrp_analytic_cost/static/description/index.html diff --git a/mrp_analytic_cost_material/views/account_analytic_line_view.xml b/mrp_analytic_cost/views/account_analytic_line_view.xml similarity index 100% rename from mrp_analytic_cost_material/views/account_analytic_line_view.xml rename to mrp_analytic_cost/views/account_analytic_line_view.xml diff --git a/mrp_analytic_cost_material/views/mrp_production_views.xml b/mrp_analytic_cost/views/mrp_production_views.xml similarity index 100% rename from mrp_analytic_cost_material/views/mrp_production_views.xml rename to mrp_analytic_cost/views/mrp_production_views.xml diff --git a/mrp_analytic_cost/views/mrp_workcenter_view.xml b/mrp_analytic_cost/views/mrp_workcenter_view.xml new file mode 100644 index 000000000..2e9ef87bc --- /dev/null +++ b/mrp_analytic_cost/views/mrp_workcenter_view.xml @@ -0,0 +1,20 @@ + + + + mrp.workcenter.form.custom + mrp.workcenter + + + + + + + + {"readonly": [("analytic_product_id", "!=", False)]} + + + + + diff --git a/mrp_analytic_cost_material/readme/DESCRIPTION.rst b/mrp_analytic_cost_material/readme/DESCRIPTION.rst deleted file mode 100644 index 29b809945..000000000 --- a/mrp_analytic_cost_material/readme/DESCRIPTION.rst +++ /dev/null @@ -1,4 +0,0 @@ -Manufacturing costs are only generated when a Manufacturing Order is closed. - -This feature allows to track costs while the manufacturing is in progress. -This is done for raw materials used, by generating Analytic Items when the stock is reserved. diff --git a/setup/mrp_analytic_cost/odoo/addons/mrp_analytic_cost b/setup/mrp_analytic_cost/odoo/addons/mrp_analytic_cost new file mode 120000 index 000000000..3ac271197 --- /dev/null +++ b/setup/mrp_analytic_cost/odoo/addons/mrp_analytic_cost @@ -0,0 +1 @@ +../../../../mrp_analytic_cost \ No newline at end of file diff --git a/setup/mrp_analytic_cost_material/setup.py b/setup/mrp_analytic_cost/setup.py similarity index 100% rename from setup/mrp_analytic_cost_material/setup.py rename to setup/mrp_analytic_cost/setup.py diff --git a/setup/mrp_analytic_cost_material/odoo/addons/mrp_analytic_cost_material b/setup/mrp_analytic_cost_material/odoo/addons/mrp_analytic_cost_material deleted file mode 120000 index 27645af9d..000000000 --- a/setup/mrp_analytic_cost_material/odoo/addons/mrp_analytic_cost_material +++ /dev/null @@ -1 +0,0 @@ -../../../../mrp_analytic_cost_material \ No newline at end of file