[IMP] mrp_unbuild_tracked_raw_material,: black, isort

This commit is contained in:
ps-tubtim
2020-03-12 13:54:55 +07:00
parent 93df824ce4
commit c39007743c
7 changed files with 117 additions and 103 deletions

View File

@@ -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,
}

View File

@@ -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"
)

View File

@@ -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}

View File

@@ -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.

View File

@@ -1,3 +1,2 @@
This module doesn't take account product `allow_unbuild_purchased` checked
which use `serial` tracking

View File

@@ -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

View File

@@ -2,70 +2,73 @@
# @author David BEAL <david.beal@akretion.com>
# 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),
)