From a09730e110f489c6399c1c9b0f5085dd9174c15f Mon Sep 17 00:00:00 2001
From: David Beal
Date: Thu, 31 Oct 2019 15:49:38 +0100
Subject: [PATCH 1/6] ADD module mrp_unbuild_tracked_raw_material
---
mrp_unbuild_tracked_raw_material/README.rst | 5 +
mrp_unbuild_tracked_raw_material/__init__.py | 1 +
.../__manifest__.py | 19 +++
.../models/__init__.py | 2 +
.../models/product.py | 14 +++
.../models/unbuild.py | 117 ++++++++++++++++++
.../readme/CONFIGURE.rst | 1 +
.../readme/CONTRIBUTORS.rst | 3 +
.../readme/DESCRIPTION.rst | 17 +++
.../readme/ROADMAP.rst | 3 +
.../readme/USAGE.rst | 6 +
.../tests/__init__.py | 1 +
.../tests/test_unbuild.py | 71 +++++++++++
.../views/product_view.xml | 16 +++
14 files changed, 276 insertions(+)
create mode 100644 mrp_unbuild_tracked_raw_material/README.rst
create mode 100644 mrp_unbuild_tracked_raw_material/__init__.py
create mode 100644 mrp_unbuild_tracked_raw_material/__manifest__.py
create mode 100644 mrp_unbuild_tracked_raw_material/models/__init__.py
create mode 100644 mrp_unbuild_tracked_raw_material/models/product.py
create mode 100644 mrp_unbuild_tracked_raw_material/models/unbuild.py
create mode 100644 mrp_unbuild_tracked_raw_material/readme/CONFIGURE.rst
create mode 100644 mrp_unbuild_tracked_raw_material/readme/CONTRIBUTORS.rst
create mode 100644 mrp_unbuild_tracked_raw_material/readme/DESCRIPTION.rst
create mode 100644 mrp_unbuild_tracked_raw_material/readme/ROADMAP.rst
create mode 100644 mrp_unbuild_tracked_raw_material/readme/USAGE.rst
create mode 100644 mrp_unbuild_tracked_raw_material/tests/__init__.py
create mode 100644 mrp_unbuild_tracked_raw_material/tests/test_unbuild.py
create mode 100644 mrp_unbuild_tracked_raw_material/views/product_view.xml
diff --git a/mrp_unbuild_tracked_raw_material/README.rst b/mrp_unbuild_tracked_raw_material/README.rst
new file mode 100644
index 000000000..ee0cc78b9
--- /dev/null
+++ b/mrp_unbuild_tracked_raw_material/README.rst
@@ -0,0 +1,5 @@
+.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ !! This file is generated by oca-gen-addon-readme !!
+ !! changes will be overwritten. !!
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
diff --git a/mrp_unbuild_tracked_raw_material/__init__.py b/mrp_unbuild_tracked_raw_material/__init__.py
new file mode 100644
index 000000000..0650744f6
--- /dev/null
+++ b/mrp_unbuild_tracked_raw_material/__init__.py
@@ -0,0 +1 @@
+from . import models
diff --git a/mrp_unbuild_tracked_raw_material/__manifest__.py b/mrp_unbuild_tracked_raw_material/__manifest__.py
new file mode 100644
index 000000000..930bb35c3
--- /dev/null
+++ b/mrp_unbuild_tracked_raw_material/__manifest__.py
@@ -0,0 +1,19 @@
+# Copyright (C) 2019 Akretion (http://www.akretion.com). All Rights Reserved
+# @author David BEAL
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+{
+ "name": "Mrp Unbuild Tracked Raw Material",
+ "summary": "Allow to unbuild tracked purchased products",
+ "author": "Akretion, Odoo Community Association (OCA)",
+ "website": "https://github.com/OCA/manufacture",
+ "category": "Manufacturing",
+ "version": "12.0.1.0.0",
+ "license": "AGPL-3",
+ "depends": ["mrp"],
+ "maintainers": ["bealdav"],
+ "data": [
+ "views/product_view.xml",
+ ],
+ "installable": True,
+}
diff --git a/mrp_unbuild_tracked_raw_material/models/__init__.py b/mrp_unbuild_tracked_raw_material/models/__init__.py
new file mode 100644
index 000000000..7adb5e1e2
--- /dev/null
+++ b/mrp_unbuild_tracked_raw_material/models/__init__.py
@@ -0,0 +1,2 @@
+from . import product
+from . import unbuild
diff --git a/mrp_unbuild_tracked_raw_material/models/product.py b/mrp_unbuild_tracked_raw_material/models/product.py
new file mode 100644
index 000000000..6d8f102cd
--- /dev/null
+++ b/mrp_unbuild_tracked_raw_material/models/product.py
@@ -0,0 +1,14 @@
+# Copyright (C) 2019 Akretion (http://www.akretion.com). All Rights Reserved
+# @author David BEAL
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from odoo import fields, models
+
+
+class ProductTemplate(models.Model):
+ _inherit = "product.template"
+
+ allow_unbuild_purchased = fields.Boolean(
+ help="If checked, unbuild orders doesn't assume a previous "
+ "manufacturing order have built this product.\n"
+ "In this case it's a purchased product and you want unbuild it")
diff --git a/mrp_unbuild_tracked_raw_material/models/unbuild.py b/mrp_unbuild_tracked_raw_material/models/unbuild.py
new file mode 100644
index 000000000..65116232f
--- /dev/null
+++ b/mrp_unbuild_tracked_raw_material/models/unbuild.py
@@ -0,0 +1,117 @@
+# Copyright (C) 2019 Akretion (http://www.akretion.com). All Rights Reserved
+# @author David BEAL
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+import logging
+from datetime import datetime
+from odoo import _, models
+from odoo.exceptions import UserError
+from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT as DT_FORMAT
+
+logger = logging.getLogger(__name__)
+
+MESSAGE = "Some of your components are tracked, you have to specify " \
+ "a manufacturing order in order to retrieve " \
+ "the correct components."
+ALTER_MESSAGE = "Alternatively, you may unbuild '%s' tracked product " \
+ "if you set it as '%s'.\n" \
+ "In this case lots'll be automatically created for you."
+
+
+class MrpUnbuild(models.Model):
+ _inherit = "mrp.unbuild"
+
+ def action_unbuild(self):
+ """ We need to catch raise behavior when tracked products
+ are unbuild without an original manufacturing order and
+ go on with another workflow with
+ _bypass_tracked_product_without_mo()
+ """
+ try:
+ res = super().action_unbuild()
+ except UserError as err:
+ # Unbuild is impossible because of MESSAGE
+ # original condition of this raise is :
+ # any(produce_move.has_tracking != 'none'
+ # and not self.mo_id for produce_move in produce_moves)
+ if hasattr(err, 'name') and err.name == _(MESSAGE):
+ if self.product_id.allow_unbuild_purchased:
+ # In this case it becomes possible to unbuild
+ return self._bypass_tracked_product_without_mo()
+ # Here other option to resolve unbuild conditions
+ new_message = _(ALTER_MESSAGE) % (
+ self.product_id.name, _("Unbuild Purchased"))
+ # We teach user the 2 conditions that make unbuild possible
+ raise UserError(_("%s \n\n%s") % (err.name, new_message))
+ # Here is the Odoo native raise
+ raise err
+ return res
+
+ def _bypass_tracked_product_without_mo(self):
+ # These moves are already generated with call to
+ # super().action_unbuild(). We catch them
+ consume_move = self.env["stock.move"].search(
+ [("consume_unbuild_id", "=", self.id)])
+ produce_moves = self.env["stock.move"].search(
+ [("unbuild_id", "=", self.id)])
+
+ # Comes from
+ # https://github.com/OCA/ocb/blob/12.0/addons/mrp/models/...
+ # mrp_unbuild.py#L117
+ if consume_move.has_tracking != 'none':
+ self.env['stock.move.line'].create({
+ 'move_id': consume_move.id,
+ 'lot_id': self.lot_id.id,
+ 'qty_done': consume_move.product_uom_qty,
+ 'product_id': consume_move.product_id.id,
+ 'product_uom_id': consume_move.product_uom.id,
+ 'location_id': consume_move.location_id.id,
+ 'location_dest_id': consume_move.location_dest_id.id,
+ })
+ else:
+ consume_move.quantity_done = consume_move.product_uom_qty
+ consume_move._action_done()
+
+ # Comment from odoo original module:
+ # TODO: Will fail if user do more than one unbuild with lot
+ # on the same MO. Need to check what other unbuild has aready took
+ for produce_move in produce_moves:
+ if produce_move.has_tracking != 'none':
+ if produce_move.product_id.tracking == "serial":
+ # TODO
+ raise UserError(_(
+ "Unbuild of component of tracked as serial "
+ "is not supported for now: contact maintainers of "
+ "'mrp_unbuild_tracked_raw_material' module "
+ "if you want this feature"))
+ lot = self.env['stock.production.lot'].create(
+ self._prepare_lots_for_purchased_unbuild(
+ produce_move.product_id))
+ self.env['stock.move.line'].create({
+ 'move_id': produce_move.id,
+ 'lot_id': lot.id,
+ 'qty_done': produce_move.product_uom_qty,
+ 'product_id': produce_move.product_id.id,
+ 'product_uom_id': produce_move.product_uom.id,
+ 'location_id': produce_move.location_id.id,
+ 'location_dest_id': produce_move.location_dest_id.id,
+ })
+ else:
+ produce_move.quantity_done = produce_move.product_uom_qty
+ # comes from native code
+ produce_moves._action_done()
+ produced_move_line_ids = produce_moves.mapped(
+ 'move_line_ids').filtered(lambda ml: ml.qty_done > 0)
+ consume_move.move_line_ids.write(
+ {'produce_line_ids': [(6, 0, produced_move_line_ids.ids)]})
+ self.message_post(
+ body=_("Product has been unbuilt without previous "
+ "manufacturing order"))
+ return self.write({'state': 'done'})
+
+ def _prepare_lots_for_purchased_unbuild(self, product):
+ # Customize your data lot with your own code
+ return {
+ "name": datetime.now().strftime(DT_FORMAT),
+ "product_id": product.id,
+ }
diff --git a/mrp_unbuild_tracked_raw_material/readme/CONFIGURE.rst b/mrp_unbuild_tracked_raw_material/readme/CONFIGURE.rst
new file mode 100644
index 000000000..573718713
--- /dev/null
+++ b/mrp_unbuild_tracked_raw_material/readme/CONFIGURE.rst
@@ -0,0 +1 @@
+Customize method `_prepare_lots_for_purchased_unbuild()` to define your own data lot
diff --git a/mrp_unbuild_tracked_raw_material/readme/CONTRIBUTORS.rst b/mrp_unbuild_tracked_raw_material/readme/CONTRIBUTORS.rst
new file mode 100644
index 000000000..55e5f2ff8
--- /dev/null
+++ b/mrp_unbuild_tracked_raw_material/readme/CONTRIBUTORS.rst
@@ -0,0 +1,3 @@
+Akretion:
+
+ * David Béal
diff --git a/mrp_unbuild_tracked_raw_material/readme/DESCRIPTION.rst b/mrp_unbuild_tracked_raw_material/readme/DESCRIPTION.rst
new file mode 100644
index 000000000..3b73611b1
--- /dev/null
+++ b/mrp_unbuild_tracked_raw_material/readme/DESCRIPTION.rst
@@ -0,0 +1,17 @@
+Odoo has a limitation on tracked product's components
+which are not manufactured in the ERP.
+
+When you try to do it, you get this warning:
+
+Some of your components are tracked, you have to specify a manufacturing order in order to retrieve the correct components.
+
+Unfortunately, it doesn't cover all the use cases.
+
+Example:
+You receive eggs and you want to unbuild them in 2 parts:
+
+ - yellow part
+ - white part
+
+Each of the parts are tracked and not linked to a previous manufacturing order
+because, you don't build the eggs yourself, you subcontract it to a chicken.
diff --git a/mrp_unbuild_tracked_raw_material/readme/ROADMAP.rst b/mrp_unbuild_tracked_raw_material/readme/ROADMAP.rst
new file mode 100644
index 000000000..14e25ae53
--- /dev/null
+++ b/mrp_unbuild_tracked_raw_material/readme/ROADMAP.rst
@@ -0,0 +1,3 @@
+This module doesn't take account product `allow_unbuild_purchased` checked
+which use `serial` tracking
+
diff --git a/mrp_unbuild_tracked_raw_material/readme/USAGE.rst b/mrp_unbuild_tracked_raw_material/readme/USAGE.rst
new file mode 100644
index 000000000..bbb3ed384
--- /dev/null
+++ b/mrp_unbuild_tracked_raw_material/readme/USAGE.rst
@@ -0,0 +1,6 @@
+# Check 'Allow Unbuild Purchased' field in Inventory tab on product form
+for any product with a bom you didn't manufactured but you want unbuild.
+
+# Go to Manufacturing > Operations > Unbuild Orders
+
+# Encode an unbuild order with the product used in first step
diff --git a/mrp_unbuild_tracked_raw_material/tests/__init__.py b/mrp_unbuild_tracked_raw_material/tests/__init__.py
new file mode 100644
index 000000000..96a4196aa
--- /dev/null
+++ b/mrp_unbuild_tracked_raw_material/tests/__init__.py
@@ -0,0 +1 @@
+from . import test_unbuild
diff --git a/mrp_unbuild_tracked_raw_material/tests/test_unbuild.py b/mrp_unbuild_tracked_raw_material/tests/test_unbuild.py
new file mode 100644
index 000000000..2fd15850d
--- /dev/null
+++ b/mrp_unbuild_tracked_raw_material/tests/test_unbuild.py
@@ -0,0 +1,71 @@
+# Copyright (C) 2019 Akretion (http://www.akretion.com). All Rights Reserved
+# @author David BEAL
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+# from odoo.tests.common import TransactionCase
+from odoo.addons.mrp.tests.common import TestMrpCommon
+from datetime import datetime
+
+
+class TestUnbuildUnmanufacturedProduct(TestMrpCommon):
+
+ def setUp(self, *args, **kwargs):
+ self.loc = self.env.ref("stock.stock_location_stock")
+ super().setUp(*args, **kwargs)
+
+ def create_data(self):
+ prd_to_build = self.env["product.product"].create({
+ "name": "To unbuild",
+ "type": "product",
+ "allow_unbuild_purchased": True,
+ "tracking": "lot",
+ })
+ prd_to_use1 = self.env["product.product"].create({
+ "name": "component 1",
+ "type": "product",
+ "tracking": "lot",
+ })
+ prd_to_use2 = self.env["product.product"].create({
+ "name": "component 2",
+ "type": "product",
+ "tracking": "none",
+ })
+ bom = self.env["mrp.bom"].create({
+ "product_id": prd_to_build.id,
+ "product_tmpl_id": prd_to_build.product_tmpl_id.id,
+ "product_uom_id": self.uom_unit.id,
+ "product_qty": 1.0,
+ "type": "normal",
+ "bom_line_ids": [
+ (0, 0, {"product_id": prd_to_use2.id,
+ "product_qty": 1}),
+ (0, 0, {"product_id": prd_to_use1.id,
+ "product_qty": 2})
+ ]})
+ return (bom, prd_to_build, prd_to_use1, prd_to_use2)
+
+ def test_unbuild(self):
+ """ """
+ bom, prd_to_build, prd_to_use1, prd_to_use2 = self.create_data()
+ lot = self.env['stock.production.lot'].create(
+ {"name": "%s" % datetime.now(),
+ "product_id": prd_to_build.id})
+ self.env["stock.quant"]._update_available_quantity(
+ prd_to_build, self.loc, 10, lot_id=lot)
+ unbuild = self.env["mrp.unbuild"].create({
+ "product_id": prd_to_build.id,
+ "bom_id": bom.id,
+ "product_qty": 1.0,
+ "lot_id": lot.id,
+ "product_uom_id": self.uom_unit.id,
+ })
+ unbuild.action_validate()
+ self._check_qty(9, prd_to_build)
+ self._check_qty(2, prd_to_use1)
+ self._check_qty(1, prd_to_use2)
+
+ def _check_qty(self, qty, product):
+ self.assertEqual(self.env["stock.quant"]._get_available_quantity(
+ product, self.loc), qty,
+ "You should have the %s product '%s' in stock" % (
+ qty, product.name))
diff --git a/mrp_unbuild_tracked_raw_material/views/product_view.xml b/mrp_unbuild_tracked_raw_material/views/product_view.xml
new file mode 100644
index 000000000..ec4fb0ad5
--- /dev/null
+++ b/mrp_unbuild_tracked_raw_material/views/product_view.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+ product.template
+
+
+
+
+
+
+
+
+
From 9923257ee54b3ce977f7891ba505f8787957b543 Mon Sep 17 00:00:00 2001
From: oca-travis
Date: Tue, 5 Nov 2019 16:32:31 +0000
Subject: [PATCH 2/6] [UPD] Update mrp_unbuild_tracked_raw_material.pot
---
.../i18n/mrp_unbuild_tracked_raw_material.pot | 64 +++++++++++++++++++
1 file changed, 64 insertions(+)
create mode 100644 mrp_unbuild_tracked_raw_material/i18n/mrp_unbuild_tracked_raw_material.pot
diff --git a/mrp_unbuild_tracked_raw_material/i18n/mrp_unbuild_tracked_raw_material.pot b/mrp_unbuild_tracked_raw_material/i18n/mrp_unbuild_tracked_raw_material.pot
new file mode 100644
index 000000000..6a3cda1ff
--- /dev/null
+++ b/mrp_unbuild_tracked_raw_material/i18n/mrp_unbuild_tracked_raw_material.pot
@@ -0,0 +1,64 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * mrp_unbuild_tracked_raw_material
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 12.0\n"
+"Report-Msgid-Bugs-To: \n"
+"Last-Translator: <>\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: mrp_unbuild_tracked_raw_material
+#: code:addons/mrp_unbuild_tracked_raw_material/models/unbuild.py:45
+#, python-format
+msgid "%s \n"
+"\n"
+"%s"
+msgstr ""
+
+#. module: mrp_unbuild_tracked_raw_material
+#: model:ir.model.fields,field_description:mrp_unbuild_tracked_raw_material.field_product_product__allow_unbuild_purchased
+#: model:ir.model.fields,field_description:mrp_unbuild_tracked_raw_material.field_product_template__allow_unbuild_purchased
+msgid "Allow Unbuild Purchased"
+msgstr ""
+
+#. module: mrp_unbuild_tracked_raw_material
+#: model:ir.model.fields,help:mrp_unbuild_tracked_raw_material.field_product_product__allow_unbuild_purchased
+#: model:ir.model.fields,help:mrp_unbuild_tracked_raw_material.field_product_template__allow_unbuild_purchased
+msgid "If checked, unbuild orders doesn't assume a previous manufacturing order have built this product.\n"
+"In this case it's a purchased product and you want unbuild it"
+msgstr ""
+
+#. module: mrp_unbuild_tracked_raw_material
+#: model:ir.model,name:mrp_unbuild_tracked_raw_material.model_product_template
+msgid "Product Template"
+msgstr ""
+
+#. module: mrp_unbuild_tracked_raw_material
+#: code:addons/mrp_unbuild_tracked_raw_material/models/unbuild.py:108
+#, python-format
+msgid "Product has been unbuilt without previous manufacturing order"
+msgstr ""
+
+#. module: mrp_unbuild_tracked_raw_material
+#: model:ir.model,name:mrp_unbuild_tracked_raw_material.model_mrp_unbuild
+msgid "Unbuild Order"
+msgstr ""
+
+#. module: mrp_unbuild_tracked_raw_material
+#: code:addons/mrp_unbuild_tracked_raw_material/models/unbuild.py:43
+#, python-format
+msgid "Unbuild Purchased"
+msgstr ""
+
+#. module: mrp_unbuild_tracked_raw_material
+#: code:addons/mrp_unbuild_tracked_raw_material/models/unbuild.py:82
+#, python-format
+msgid "Unbuild of component of tracked as serial is not supported for now: contact maintainers of 'mrp_unbuild_tracked_raw_material' module if you want this feature"
+msgstr ""
+
From b3003090a118a214cd26056707c074ab9f3e6fee Mon Sep 17 00:00:00 2001
From: OCA-git-bot
Date: Tue, 5 Nov 2019 16:59:04 +0000
Subject: [PATCH 3/6] [UPD] README.rst
---
mrp_unbuild_tracked_raw_material/README.rst | 116 +++++
.../static/description/index.html | 457 ++++++++++++++++++
2 files changed, 573 insertions(+)
create mode 100644 mrp_unbuild_tracked_raw_material/static/description/index.html
diff --git a/mrp_unbuild_tracked_raw_material/README.rst b/mrp_unbuild_tracked_raw_material/README.rst
index ee0cc78b9..3179e7963 100644
--- a/mrp_unbuild_tracked_raw_material/README.rst
+++ b/mrp_unbuild_tracked_raw_material/README.rst
@@ -1,5 +1,121 @@
+================================
+Mrp Unbuild Tracked Raw Material
+================================
+
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
+ :target: https://odoo-community.org/page/development-status
+ :alt: Beta
+.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
+ :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
+ :alt: License: AGPL-3
+.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fmanufacture-lightgray.png?logo=github
+ :target: https://github.com/OCA/manufacture/tree/12.0/mrp_unbuild_tracked_raw_material
+ :alt: OCA/manufacture
+.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
+ :target: https://translation.odoo-community.org/projects/manufacture-12-0/manufacture-12-0-mrp_unbuild_tracked_raw_material
+ :alt: Translate me on Weblate
+.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
+ :target: https://runbot.odoo-community.org/runbot/129/12.0
+ :alt: Try me on Runbot
+
+|badge1| |badge2| |badge3| |badge4| |badge5|
+
+Odoo has a limitation on tracked product's components
+which are not manufactured in the ERP.
+
+When you try to do it, you get this warning:
+
+Some of your components are tracked, you have to specify a manufacturing order in order to retrieve the correct components.
+
+Unfortunately, it doesn't cover all the use cases.
+
+Example:
+You receive eggs and you want to unbuild them in 2 parts:
+
+ - yellow part
+ - white part
+
+Each of the parts are tracked and not linked to a previous manufacturing order
+because, you don't build the eggs yourself, you subcontract it to a chicken.
+
+**Table of contents**
+
+.. contents::
+ :local:
+
+Configuration
+=============
+
+Customize method `_prepare_lots_for_purchased_unbuild()` to define your own data lot
+
+Usage
+=====
+
+# Check 'Allow Unbuild Purchased' field in Inventory tab on product form
+for any product with a bom you didn't manufactured but you want unbuild.
+
+# Go to Manufacturing > Operations > Unbuild Orders
+
+# Encode an unbuild order with the product used in first step
+
+Known issues / Roadmap
+======================
+
+This module doesn't take account product `allow_unbuild_purchased` checked
+which use `serial` tracking
+
+
+Bug Tracker
+===========
+
+Bugs are tracked on `GitHub Issues `_.
+In case of trouble, please check there if your issue has already been reported.
+If you spotted it first, help us smashing it by providing a detailed and welcomed
+`feedback `_.
+
+Do not contact contributors directly about support or help with technical issues.
+
+Credits
+=======
+
+Authors
+~~~~~~~
+
+* Akretion
+
+Contributors
+~~~~~~~~~~~~
+
+Akretion:
+
+ * David Béal
+
+Maintainers
+~~~~~~~~~~~
+
+This module is maintained by the OCA.
+
+.. image:: https://odoo-community.org/logo.png
+ :alt: Odoo Community Association
+ :target: https://odoo-community.org
+
+OCA, or the Odoo Community Association, is a nonprofit organization whose
+mission is to support the collaborative development of Odoo features and
+promote its widespread use.
+
+.. |maintainer-bealdav| image:: https://github.com/bealdav.png?size=40px
+ :target: https://github.com/bealdav
+ :alt: bealdav
+
+Current `maintainer `__:
+
+|maintainer-bealdav|
+
+This module is part of the `OCA/manufacture `_ project on GitHub.
+
+You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
diff --git a/mrp_unbuild_tracked_raw_material/static/description/index.html b/mrp_unbuild_tracked_raw_material/static/description/index.html
new file mode 100644
index 000000000..d4e7cf461
--- /dev/null
+++ b/mrp_unbuild_tracked_raw_material/static/description/index.html
@@ -0,0 +1,457 @@
+
+
+
+
+
+
+Mrp Unbuild Tracked Raw Material
+
+
+
+
+
Mrp Unbuild Tracked Raw Material
+
+
+

+
Odoo has a limitation on tracked product’s components
+which are not manufactured in the ERP.
+
When you try to do it, you get this warning:
+
Some of your components are tracked, you have to specify a manufacturing order in order to retrieve the correct components.
+
Unfortunately, it doesn’t cover all the use cases.
+
Example:
+You receive eggs and you want to unbuild them in 2 parts:
+
+
+- yellow part
+- white part
+
+
+
Each of the parts are tracked and not linked to a previous manufacturing order
+because, you don’t build the eggs yourself, you subcontract it to a chicken.
+
Table of contents
+
+
+
+
Customize method _prepare_lots_for_purchased_unbuild() to define your own data lot
+
+
+
+
# Check ‘Allow Unbuild Purchased’ field in Inventory tab on product form
+for any product with a bom you didn’t manufactured but you want unbuild.
+
# Go to Manufacturing > Operations > Unbuild Orders
+
# Encode an unbuild order with the product used in first step
+
+
+
+
This module doesn’t take account product allow_unbuild_purchased checked
+which use serial tracking
+
+
+
+
Bugs are tracked on GitHub Issues.
+In case of trouble, please check there if your issue has already been reported.
+If you spotted it first, help us smashing it by providing a detailed and welcomed
+feedback.
+
Do not contact contributors directly about support or help with technical issues.
+
+
+
+
+
+
+
+
This module is maintained by the OCA.
+

+
OCA, or the Odoo Community Association, is a nonprofit organization whose
+mission is to support the collaborative development of Odoo features and
+promote its widespread use.
+
Current maintainer:
+

+
This module is part of the OCA/manufacture project on GitHub.
+
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
+
+
+
+
+
From 93df824ce4bd47c57ce003d1a75984b129a3aa6e Mon Sep 17 00:00:00 2001
From: OCA-git-bot
Date: Tue, 5 Nov 2019 16:59:04 +0000
Subject: [PATCH 4/6] [ADD] icon.png
---
.../static/description/icon.png | Bin 0 -> 9455 bytes
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 mrp_unbuild_tracked_raw_material/static/description/icon.png
diff --git a/mrp_unbuild_tracked_raw_material/static/description/icon.png b/mrp_unbuild_tracked_raw_material/static/description/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d
GIT binary patch
literal 9455
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
z
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
Xviia!U7SGha1wx#SCgwmn*{w2TRX*I
literal 0
HcmV?d00001
From c39007743c78fb775e7e50bb2971ff9053f642ff Mon Sep 17 00:00:00 2001
From: ps-tubtim
Date: Thu, 12 Mar 2020 13:54:55 +0700
Subject: [PATCH 5/6] [IMP] mrp_unbuild_tracked_raw_material,: black, isort
---
.../__manifest__.py | 6 +-
.../models/product.py | 5 +-
.../models/unbuild.py | 111 ++++++++++--------
.../readme/DESCRIPTION.rst | 2 +-
.../readme/ROADMAP.rst | 1 -
.../readme/USAGE.rst | 2 +-
.../tests/test_unbuild.py | 93 ++++++++-------
7 files changed, 117 insertions(+), 103 deletions(-)
diff --git a/mrp_unbuild_tracked_raw_material/__manifest__.py b/mrp_unbuild_tracked_raw_material/__manifest__.py
index 930bb35c3..10895f517 100644
--- a/mrp_unbuild_tracked_raw_material/__manifest__.py
+++ b/mrp_unbuild_tracked_raw_material/__manifest__.py
@@ -8,12 +8,10 @@
"author": "Akretion, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/manufacture",
"category": "Manufacturing",
- "version": "12.0.1.0.0",
+ "version": "13.0.1.0.0",
"license": "AGPL-3",
"depends": ["mrp"],
"maintainers": ["bealdav"],
- "data": [
- "views/product_view.xml",
- ],
+ "data": ["views/product_view.xml"],
"installable": True,
}
diff --git a/mrp_unbuild_tracked_raw_material/models/product.py b/mrp_unbuild_tracked_raw_material/models/product.py
index 6d8f102cd..f6238f996 100644
--- a/mrp_unbuild_tracked_raw_material/models/product.py
+++ b/mrp_unbuild_tracked_raw_material/models/product.py
@@ -10,5 +10,6 @@ class ProductTemplate(models.Model):
allow_unbuild_purchased = fields.Boolean(
help="If checked, unbuild orders doesn't assume a previous "
- "manufacturing order have built this product.\n"
- "In this case it's a purchased product and you want unbuild it")
+ "manufacturing order have built this product.\n"
+ "In this case it's a purchased product and you want unbuild it"
+ )
diff --git a/mrp_unbuild_tracked_raw_material/models/unbuild.py b/mrp_unbuild_tracked_raw_material/models/unbuild.py
index 65116232f..4bce46332 100644
--- a/mrp_unbuild_tracked_raw_material/models/unbuild.py
+++ b/mrp_unbuild_tracked_raw_material/models/unbuild.py
@@ -4,18 +4,23 @@
import logging
from datetime import datetime
+
from odoo import _, models
from odoo.exceptions import UserError
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT as DT_FORMAT
logger = logging.getLogger(__name__)
-MESSAGE = "Some of your components are tracked, you have to specify " \
- "a manufacturing order in order to retrieve " \
- "the correct components."
-ALTER_MESSAGE = "Alternatively, you may unbuild '%s' tracked product " \
- "if you set it as '%s'.\n" \
- "In this case lots'll be automatically created for you."
+MESSAGE = (
+ "Some of your components are tracked, you have to specify "
+ "a manufacturing order in order to retrieve "
+ "the correct components."
+)
+ALTER_MESSAGE = (
+ "Alternatively, you may unbuild '%s' tracked product "
+ "if you set it as '%s'.\n"
+ "In this case lots'll be automatically created for you."
+)
class MrpUnbuild(models.Model):
@@ -34,13 +39,15 @@ class MrpUnbuild(models.Model):
# original condition of this raise is :
# any(produce_move.has_tracking != 'none'
# and not self.mo_id for produce_move in produce_moves)
- if hasattr(err, 'name') and err.name == _(MESSAGE):
+ if hasattr(err, "name") and err.name == _(MESSAGE):
if self.product_id.allow_unbuild_purchased:
# In this case it becomes possible to unbuild
return self._bypass_tracked_product_without_mo()
# Here other option to resolve unbuild conditions
new_message = _(ALTER_MESSAGE) % (
- self.product_id.name, _("Unbuild Purchased"))
+ self.product_id.name,
+ _("Unbuild Purchased"),
+ )
# We teach user the 2 conditions that make unbuild possible
raise UserError(_("%s \n\n%s") % (err.name, new_message))
# Here is the Odoo native raise
@@ -51,23 +58,25 @@ class MrpUnbuild(models.Model):
# These moves are already generated with call to
# super().action_unbuild(). We catch them
consume_move = self.env["stock.move"].search(
- [("consume_unbuild_id", "=", self.id)])
- produce_moves = self.env["stock.move"].search(
- [("unbuild_id", "=", self.id)])
+ [("consume_unbuild_id", "=", self.id)]
+ )
+ produce_moves = self.env["stock.move"].search([("unbuild_id", "=", self.id)])
# Comes from
# https://github.com/OCA/ocb/blob/12.0/addons/mrp/models/...
# mrp_unbuild.py#L117
- if consume_move.has_tracking != 'none':
- self.env['stock.move.line'].create({
- 'move_id': consume_move.id,
- 'lot_id': self.lot_id.id,
- 'qty_done': consume_move.product_uom_qty,
- 'product_id': consume_move.product_id.id,
- 'product_uom_id': consume_move.product_uom.id,
- 'location_id': consume_move.location_id.id,
- 'location_dest_id': consume_move.location_dest_id.id,
- })
+ if consume_move.has_tracking != "none":
+ self.env["stock.move.line"].create(
+ {
+ "move_id": consume_move.id,
+ "lot_id": self.lot_id.id,
+ "qty_done": consume_move.product_uom_qty,
+ "product_id": consume_move.product_id.id,
+ "product_uom_id": consume_move.product_uom.id,
+ "location_id": consume_move.location_id.id,
+ "location_dest_id": consume_move.location_dest_id.id,
+ }
+ )
else:
consume_move.quantity_done = consume_move.product_uom_qty
consume_move._action_done()
@@ -76,42 +85,46 @@ class MrpUnbuild(models.Model):
# TODO: Will fail if user do more than one unbuild with lot
# on the same MO. Need to check what other unbuild has aready took
for produce_move in produce_moves:
- if produce_move.has_tracking != 'none':
+ if produce_move.has_tracking != "none":
if produce_move.product_id.tracking == "serial":
# TODO
- raise UserError(_(
- "Unbuild of component of tracked as serial "
- "is not supported for now: contact maintainers of "
- "'mrp_unbuild_tracked_raw_material' module "
- "if you want this feature"))
- lot = self.env['stock.production.lot'].create(
- self._prepare_lots_for_purchased_unbuild(
- produce_move.product_id))
- self.env['stock.move.line'].create({
- 'move_id': produce_move.id,
- 'lot_id': lot.id,
- 'qty_done': produce_move.product_uom_qty,
- 'product_id': produce_move.product_id.id,
- 'product_uom_id': produce_move.product_uom.id,
- 'location_id': produce_move.location_id.id,
- 'location_dest_id': produce_move.location_dest_id.id,
- })
+ raise UserError(
+ _(
+ "Unbuild of component of tracked as serial "
+ "is not supported for now: contact maintainers of "
+ "'mrp_unbuild_tracked_raw_material' module "
+ "if you want this feature"
+ )
+ )
+ lot = self.env["stock.production.lot"].create(
+ self._prepare_lots_for_purchased_unbuild(produce_move.product_id)
+ )
+ self.env["stock.move.line"].create(
+ {
+ "move_id": produce_move.id,
+ "lot_id": lot.id,
+ "qty_done": produce_move.product_uom_qty,
+ "product_id": produce_move.product_id.id,
+ "product_uom_id": produce_move.product_uom.id,
+ "location_id": produce_move.location_id.id,
+ "location_dest_id": produce_move.location_dest_id.id,
+ }
+ )
else:
produce_move.quantity_done = produce_move.product_uom_qty
# comes from native code
produce_moves._action_done()
- produced_move_line_ids = produce_moves.mapped(
- 'move_line_ids').filtered(lambda ml: ml.qty_done > 0)
+ produced_move_line_ids = produce_moves.mapped("move_line_ids").filtered(
+ lambda ml: ml.qty_done > 0
+ )
consume_move.move_line_ids.write(
- {'produce_line_ids': [(6, 0, produced_move_line_ids.ids)]})
+ {"produce_line_ids": [(6, 0, produced_move_line_ids.ids)]}
+ )
self.message_post(
- body=_("Product has been unbuilt without previous "
- "manufacturing order"))
- return self.write({'state': 'done'})
+ body=_("Product has been unbuilt without previous " "manufacturing order")
+ )
+ return self.write({"state": "done"})
def _prepare_lots_for_purchased_unbuild(self, product):
# Customize your data lot with your own code
- return {
- "name": datetime.now().strftime(DT_FORMAT),
- "product_id": product.id,
- }
+ return {"name": datetime.now().strftime(DT_FORMAT), "product_id": product.id}
diff --git a/mrp_unbuild_tracked_raw_material/readme/DESCRIPTION.rst b/mrp_unbuild_tracked_raw_material/readme/DESCRIPTION.rst
index 3b73611b1..f340cd97a 100644
--- a/mrp_unbuild_tracked_raw_material/readme/DESCRIPTION.rst
+++ b/mrp_unbuild_tracked_raw_material/readme/DESCRIPTION.rst
@@ -3,7 +3,7 @@ which are not manufactured in the ERP.
When you try to do it, you get this warning:
-Some of your components are tracked, you have to specify a manufacturing order in order to retrieve the correct components.
+Some of your components are tracked, you have to specify a manufacturing order in order to retrieve the correct components.
Unfortunately, it doesn't cover all the use cases.
diff --git a/mrp_unbuild_tracked_raw_material/readme/ROADMAP.rst b/mrp_unbuild_tracked_raw_material/readme/ROADMAP.rst
index 14e25ae53..00031023f 100644
--- a/mrp_unbuild_tracked_raw_material/readme/ROADMAP.rst
+++ b/mrp_unbuild_tracked_raw_material/readme/ROADMAP.rst
@@ -1,3 +1,2 @@
This module doesn't take account product `allow_unbuild_purchased` checked
which use `serial` tracking
-
diff --git a/mrp_unbuild_tracked_raw_material/readme/USAGE.rst b/mrp_unbuild_tracked_raw_material/readme/USAGE.rst
index bbb3ed384..015ace3d8 100644
--- a/mrp_unbuild_tracked_raw_material/readme/USAGE.rst
+++ b/mrp_unbuild_tracked_raw_material/readme/USAGE.rst
@@ -1,4 +1,4 @@
-# Check 'Allow Unbuild Purchased' field in Inventory tab on product form
+# Check 'Allow Unbuild Purchased' field in Inventory tab on product form
for any product with a bom you didn't manufactured but you want unbuild.
# Go to Manufacturing > Operations > Unbuild Orders
diff --git a/mrp_unbuild_tracked_raw_material/tests/test_unbuild.py b/mrp_unbuild_tracked_raw_material/tests/test_unbuild.py
index 2fd15850d..fdbb3f2d6 100644
--- a/mrp_unbuild_tracked_raw_material/tests/test_unbuild.py
+++ b/mrp_unbuild_tracked_raw_material/tests/test_unbuild.py
@@ -2,70 +2,73 @@
# @author David BEAL
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+from datetime import datetime
+
# from odoo.tests.common import TransactionCase
from odoo.addons.mrp.tests.common import TestMrpCommon
-from datetime import datetime
class TestUnbuildUnmanufacturedProduct(TestMrpCommon):
-
def setUp(self, *args, **kwargs):
self.loc = self.env.ref("stock.stock_location_stock")
super().setUp(*args, **kwargs)
def create_data(self):
- prd_to_build = self.env["product.product"].create({
- "name": "To unbuild",
- "type": "product",
- "allow_unbuild_purchased": True,
- "tracking": "lot",
- })
- prd_to_use1 = self.env["product.product"].create({
- "name": "component 1",
- "type": "product",
- "tracking": "lot",
- })
- prd_to_use2 = self.env["product.product"].create({
- "name": "component 2",
- "type": "product",
- "tracking": "none",
- })
- bom = self.env["mrp.bom"].create({
- "product_id": prd_to_build.id,
- "product_tmpl_id": prd_to_build.product_tmpl_id.id,
- "product_uom_id": self.uom_unit.id,
- "product_qty": 1.0,
- "type": "normal",
- "bom_line_ids": [
- (0, 0, {"product_id": prd_to_use2.id,
- "product_qty": 1}),
- (0, 0, {"product_id": prd_to_use1.id,
- "product_qty": 2})
- ]})
+ prd_to_build = self.env["product.product"].create(
+ {
+ "name": "To unbuild",
+ "type": "product",
+ "allow_unbuild_purchased": True,
+ "tracking": "lot",
+ }
+ )
+ prd_to_use1 = self.env["product.product"].create(
+ {"name": "component 1", "type": "product", "tracking": "lot"}
+ )
+ prd_to_use2 = self.env["product.product"].create(
+ {"name": "component 2", "type": "product", "tracking": "none"}
+ )
+ bom = self.env["mrp.bom"].create(
+ {
+ "product_id": prd_to_build.id,
+ "product_tmpl_id": prd_to_build.product_tmpl_id.id,
+ "product_uom_id": self.uom_unit.id,
+ "product_qty": 1.0,
+ "type": "normal",
+ "bom_line_ids": [
+ (0, 0, {"product_id": prd_to_use2.id, "product_qty": 1}),
+ (0, 0, {"product_id": prd_to_use1.id, "product_qty": 2}),
+ ],
+ }
+ )
return (bom, prd_to_build, prd_to_use1, prd_to_use2)
def test_unbuild(self):
""" """
bom, prd_to_build, prd_to_use1, prd_to_use2 = self.create_data()
- lot = self.env['stock.production.lot'].create(
- {"name": "%s" % datetime.now(),
- "product_id": prd_to_build.id})
+ lot = self.env["stock.production.lot"].create(
+ {"name": "%s" % datetime.now(), "product_id": prd_to_build.id}
+ )
self.env["stock.quant"]._update_available_quantity(
- prd_to_build, self.loc, 10, lot_id=lot)
- unbuild = self.env["mrp.unbuild"].create({
- "product_id": prd_to_build.id,
- "bom_id": bom.id,
- "product_qty": 1.0,
- "lot_id": lot.id,
- "product_uom_id": self.uom_unit.id,
- })
+ prd_to_build, self.loc, 10, lot_id=lot
+ )
+ unbuild = self.env["mrp.unbuild"].create(
+ {
+ "product_id": prd_to_build.id,
+ "bom_id": bom.id,
+ "product_qty": 1.0,
+ "lot_id": lot.id,
+ "product_uom_id": self.uom_unit.id,
+ }
+ )
unbuild.action_validate()
self._check_qty(9, prd_to_build)
self._check_qty(2, prd_to_use1)
self._check_qty(1, prd_to_use2)
def _check_qty(self, qty, product):
- self.assertEqual(self.env["stock.quant"]._get_available_quantity(
- product, self.loc), qty,
- "You should have the %s product '%s' in stock" % (
- qty, product.name))
+ self.assertEqual(
+ self.env["stock.quant"]._get_available_quantity(product, self.loc),
+ qty,
+ "You should have the {} product '{}' in stock".format(qty, product.name),
+ )
From 46e42bb0078bd70c8fef5eca383884d4a7808354 Mon Sep 17 00:00:00 2001
From: ps-tubtim
Date: Mon, 16 Mar 2020 14:47:44 +0700
Subject: [PATCH 6/6] [MIG] mrp_unbuild_tracked_raw_material: Migration to 13.0
---
mrp_unbuild_tracked_raw_material/README.rst | 17 ++++----
.../models/unbuild.py | 42 ++++++++++---------
.../readme/CONTRIBUTORS.rst | 2 +
.../static/description/index.html | 9 ++--
.../tests/test_unbuild.py | 14 +++++--
.../views/product_view.xml | 13 +++---
.../addons/mrp_unbuild_tracked_raw_material | 1 +
.../mrp_unbuild_tracked_raw_material/setup.py | 6 +++
8 files changed, 64 insertions(+), 40 deletions(-)
create mode 120000 setup/mrp_unbuild_tracked_raw_material/odoo/addons/mrp_unbuild_tracked_raw_material
create mode 100644 setup/mrp_unbuild_tracked_raw_material/setup.py
diff --git a/mrp_unbuild_tracked_raw_material/README.rst b/mrp_unbuild_tracked_raw_material/README.rst
index 3179e7963..86af614f3 100644
--- a/mrp_unbuild_tracked_raw_material/README.rst
+++ b/mrp_unbuild_tracked_raw_material/README.rst
@@ -14,13 +14,13 @@ Mrp Unbuild Tracked Raw Material
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fmanufacture-lightgray.png?logo=github
- :target: https://github.com/OCA/manufacture/tree/12.0/mrp_unbuild_tracked_raw_material
+ :target: https://github.com/OCA/manufacture/tree/13.0/mrp_unbuild_tracked_raw_material
:alt: OCA/manufacture
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
- :target: https://translation.odoo-community.org/projects/manufacture-12-0/manufacture-12-0-mrp_unbuild_tracked_raw_material
+ :target: https://translation.odoo-community.org/projects/manufacture-13-0/manufacture-13-0-mrp_unbuild_tracked_raw_material
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
- :target: https://runbot.odoo-community.org/runbot/129/12.0
+ :target: https://runbot.odoo-community.org/runbot/129/13.0
:alt: Try me on Runbot
|badge1| |badge2| |badge3| |badge4| |badge5|
@@ -30,7 +30,7 @@ which are not manufactured in the ERP.
When you try to do it, you get this warning:
-Some of your components are tracked, you have to specify a manufacturing order in order to retrieve the correct components.
+Some of your components are tracked, you have to specify a manufacturing order in order to retrieve the correct components.
Unfortunately, it doesn't cover all the use cases.
@@ -56,7 +56,7 @@ Customize method `_prepare_lots_for_purchased_unbuild()` to define your own data
Usage
=====
-# Check 'Allow Unbuild Purchased' field in Inventory tab on product form
+# Check 'Allow Unbuild Purchased' field in Inventory tab on product form
for any product with a bom you didn't manufactured but you want unbuild.
# Go to Manufacturing > Operations > Unbuild Orders
@@ -69,14 +69,13 @@ Known issues / Roadmap
This module doesn't take account product `allow_unbuild_purchased` checked
which use `serial` tracking
-
Bug Tracker
===========
Bugs are tracked on `GitHub Issues `_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
-`feedback `_.
+`feedback `_.
Do not contact contributors directly about support or help with technical issues.
@@ -95,6 +94,8 @@ Akretion:
* David Béal
+* Pimolnat Suntian
+
Maintainers
~~~~~~~~~~~
@@ -116,6 +117,6 @@ Current `maintainer `__:
|maintainer-bealdav|
-This module is part of the `OCA/manufacture `_ project on GitHub.
+This module is part of the `OCA/manufacture `_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
diff --git a/mrp_unbuild_tracked_raw_material/models/unbuild.py b/mrp_unbuild_tracked_raw_material/models/unbuild.py
index 4bce46332..78665ce54 100644
--- a/mrp_unbuild_tracked_raw_material/models/unbuild.py
+++ b/mrp_unbuild_tracked_raw_material/models/unbuild.py
@@ -13,8 +13,7 @@ logger = logging.getLogger(__name__)
MESSAGE = (
"Some of your components are tracked, you have to specify "
- "a manufacturing order in order to retrieve "
- "the correct components."
+ "a manufacturing order in order to retrieve the correct components."
)
ALTER_MESSAGE = (
"Alternatively, you may unbuild '%s' tracked product "
@@ -65,21 +64,22 @@ class MrpUnbuild(models.Model):
# Comes from
# https://github.com/OCA/ocb/blob/12.0/addons/mrp/models/...
# mrp_unbuild.py#L117
- if consume_move.has_tracking != "none":
- self.env["stock.move.line"].create(
- {
- "move_id": consume_move.id,
- "lot_id": self.lot_id.id,
- "qty_done": consume_move.product_uom_qty,
- "product_id": consume_move.product_id.id,
- "product_uom_id": consume_move.product_uom.id,
- "location_id": consume_move.location_id.id,
- "location_dest_id": consume_move.location_dest_id.id,
- }
- )
- else:
- consume_move.quantity_done = consume_move.product_uom_qty
- consume_move._action_done()
+ if consume_move:
+ if consume_move.has_tracking != "none":
+ self.env["stock.move.line"].create(
+ {
+ "move_id": consume_move.id,
+ "lot_id": self.lot_id.id,
+ "qty_done": consume_move.product_uom_qty,
+ "product_id": consume_move.product_id.id,
+ "product_uom_id": consume_move.product_uom.id,
+ "location_id": consume_move.location_id.id,
+ "location_dest_id": consume_move.location_dest_id.id,
+ }
+ )
+ else:
+ consume_move.quantity_done = consume_move.product_uom_qty
+ consume_move._action_done()
# Comment from odoo original module:
# TODO: Will fail if user do more than one unbuild with lot
@@ -121,10 +121,14 @@ class MrpUnbuild(models.Model):
{"produce_line_ids": [(6, 0, produced_move_line_ids.ids)]}
)
self.message_post(
- body=_("Product has been unbuilt without previous " "manufacturing order")
+ body=_("Product has been unbuilt without previous manufacturing order")
)
return self.write({"state": "done"})
def _prepare_lots_for_purchased_unbuild(self, product):
# Customize your data lot with your own code
- return {"name": datetime.now().strftime(DT_FORMAT), "product_id": product.id}
+ return {
+ "name": datetime.now().strftime(DT_FORMAT),
+ "product_id": product.id,
+ "company_id": self.env.company.id,
+ }
diff --git a/mrp_unbuild_tracked_raw_material/readme/CONTRIBUTORS.rst b/mrp_unbuild_tracked_raw_material/readme/CONTRIBUTORS.rst
index 55e5f2ff8..e8d004e6d 100644
--- a/mrp_unbuild_tracked_raw_material/readme/CONTRIBUTORS.rst
+++ b/mrp_unbuild_tracked_raw_material/readme/CONTRIBUTORS.rst
@@ -1,3 +1,5 @@
Akretion:
* David Béal
+
+* Pimolnat Suntian
diff --git a/mrp_unbuild_tracked_raw_material/static/description/index.html b/mrp_unbuild_tracked_raw_material/static/description/index.html
index d4e7cf461..eed2a8197 100644
--- a/mrp_unbuild_tracked_raw_material/static/description/index.html
+++ b/mrp_unbuild_tracked_raw_material/static/description/index.html
@@ -367,7 +367,7 @@ ul.auto-toc {
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
-

+

Odoo has a limitation on tracked product’s components
which are not manufactured in the ERP.
When you try to do it, you get this warning:
@@ -419,7 +419,7 @@ which use serial tracking
Bugs are tracked on GitHub Issues.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
-feedback.
+feedback.
Do not contact contributors directly about support or help with technical issues.
@@ -438,6 +438,9 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
David Béal <david.beal@akretion.com>
+
@@ -448,7 +451,7 @@ mission is to support the collaborative development of Odoo features and
promote its widespread use.
Current maintainer:

-
This module is part of the OCA/manufacture project on GitHub.
+
This module is part of the OCA/manufacture project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
diff --git a/mrp_unbuild_tracked_raw_material/tests/test_unbuild.py b/mrp_unbuild_tracked_raw_material/tests/test_unbuild.py
index fdbb3f2d6..6edf404f0 100644
--- a/mrp_unbuild_tracked_raw_material/tests/test_unbuild.py
+++ b/mrp_unbuild_tracked_raw_material/tests/test_unbuild.py
@@ -10,6 +10,7 @@ from odoo.addons.mrp.tests.common import TestMrpCommon
class TestUnbuildUnmanufacturedProduct(TestMrpCommon):
def setUp(self, *args, **kwargs):
+ self.company = self.env.ref("base.main_company")
self.loc = self.env.ref("stock.stock_location_stock")
super().setUp(*args, **kwargs)
@@ -44,10 +45,13 @@ class TestUnbuildUnmanufacturedProduct(TestMrpCommon):
return (bom, prd_to_build, prd_to_use1, prd_to_use2)
def test_unbuild(self):
- """ """
bom, prd_to_build, prd_to_use1, prd_to_use2 = self.create_data()
lot = self.env["stock.production.lot"].create(
- {"name": "%s" % datetime.now(), "product_id": prd_to_build.id}
+ {
+ "name": "%s" % datetime.now(),
+ "product_id": prd_to_build.id,
+ "company_id": self.company.id,
+ }
)
self.env["stock.quant"]._update_available_quantity(
prd_to_build, self.loc, 10, lot_id=lot
@@ -59,6 +63,8 @@ class TestUnbuildUnmanufacturedProduct(TestMrpCommon):
"product_qty": 1.0,
"lot_id": lot.id,
"product_uom_id": self.uom_unit.id,
+ "location_id": self.loc.id,
+ "location_dest_id": self.loc.id,
}
)
unbuild.action_validate()
@@ -68,7 +74,9 @@ class TestUnbuildUnmanufacturedProduct(TestMrpCommon):
def _check_qty(self, qty, product):
self.assertEqual(
- self.env["stock.quant"]._get_available_quantity(product, self.loc),
+ self.env["stock.quant"]._get_available_quantity(
+ product, self.loc, allow_negative=True
+ ),
qty,
"You should have the {} product '{}' in stock".format(qty, product.name),
)
diff --git a/mrp_unbuild_tracked_raw_material/views/product_view.xml b/mrp_unbuild_tracked_raw_material/views/product_view.xml
index ec4fb0ad5..c8a554806 100644
--- a/mrp_unbuild_tracked_raw_material/views/product_view.xml
+++ b/mrp_unbuild_tracked_raw_material/views/product_view.xml
@@ -1,16 +1,15 @@
-
-
+
-
product.template
-
+
-
+
-
diff --git a/setup/mrp_unbuild_tracked_raw_material/odoo/addons/mrp_unbuild_tracked_raw_material b/setup/mrp_unbuild_tracked_raw_material/odoo/addons/mrp_unbuild_tracked_raw_material
new file mode 120000
index 000000000..9bf782814
--- /dev/null
+++ b/setup/mrp_unbuild_tracked_raw_material/odoo/addons/mrp_unbuild_tracked_raw_material
@@ -0,0 +1 @@
+../../../../mrp_unbuild_tracked_raw_material
\ No newline at end of file
diff --git a/setup/mrp_unbuild_tracked_raw_material/setup.py b/setup/mrp_unbuild_tracked_raw_material/setup.py
new file mode 100644
index 000000000..28c57bb64
--- /dev/null
+++ b/setup/mrp_unbuild_tracked_raw_material/setup.py
@@ -0,0 +1,6 @@
+import setuptools
+
+setuptools.setup(
+ setup_requires=['setuptools-odoo'],
+ odoo_addon=True,
+)