[IMP] stock_secondary_unit: Use secondary units directly in pickings

[IMP] stock_secondary_unit: Use product_secondary_unit mixin model from product-attribute repository.
This commit is contained in:
sergio-teruel
2020-12-19 08:01:10 +01:00
committed by Jesús Alan Ramos Rodríguez
parent 8d8638fe22
commit 392e95308a
3 changed files with 145 additions and 29 deletions

View File

@@ -4,31 +4,45 @@ from odoo import api, fields, models
from odoo.tools.float_utils import float_round
class StockSecondaryUnitMixin(models.AbstractModel):
_name = "stock.secondary.unit.mixin"
_description = "Stock Secondary Unit Mixin"
secondary_uom_id = fields.Many2one(
comodel_name="product.secondary.unit", string="Second unit"
)
secondary_uom_qty = fields.Float(
string="Secondary Qty", digits="Product Unit of Measure"
)
class StockMove(models.Model):
_inherit = ["stock.move", "stock.secondary.unit.mixin"]
_inherit = ["stock.move", "product.secondary.unit.mixin"]
_name = "stock.move"
_secondary_unit_fields = {
"qty_field": "product_uom_qty",
"uom_field": "product_uom",
}
product_uom_qty = fields.Float(
store=True, readonly=False, compute="_compute_product_uom_qty", copy=True
)
@api.depends("secondary_uom_qty", "secondary_uom_id")
def _compute_product_uom_qty(self):
self._compute_helper_target_field_qty()
@api.onchange("product_uom")
def onchange_product_uom_for_secondary(self):
self._onchange_helper_product_uom_for_secondary()
def _merge_moves_fields(self):
res = super()._merge_moves_fields()
res["secondary_uom_qty"] = self[-1:].secondary_uom_qty
res["secondary_uom_qty"] = sum(self.mapped("secondary_uom_qty"))
return res
@api.model
def _prepare_merge_moves_distinct_fields(self):
"""Don't merge moves with distinct secondary units"""
distinct_fields = super()._prepare_merge_moves_distinct_fields()
distinct_fields += ["secondary_uom_id"]
return distinct_fields
class StockMoveLine(models.Model):
_inherit = ["stock.move.line", "stock.secondary.unit.mixin"]
_inherit = ["stock.move.line", "product.secondary.unit.mixin"]
_name = "stock.move.line"
_secondary_unit_fields = {"qty_field": "qty_done", "uom_field": "product_uom_id"}
qty_done = fields.Float(store=True, readonly=False, compute="_compute_qty_done")
@api.model
def create(self, vals):
@@ -45,3 +59,7 @@ class StockMoveLine(models.Model):
{"secondary_uom_qty": qty, "secondary_uom_id": move.secondary_uom_id.id}
)
return super().create(vals)
@api.depends("secondary_uom_id", "secondary_uom_qty")
def _compute_qty_done(self):
self._compute_helper_target_field_qty()

View File

@@ -1,17 +1,24 @@
# Copyright 2018 Tecnativa - Sergio Teruel
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo.tests import SavepointCase
from odoo.tests import Form, SavepointCase, tagged
@tagged("-at_install", "post_install")
class TestProductSecondaryUnit(SavepointCase):
at_install = False
post_install = True
@classmethod
def setUpClass(cls):
super().setUpClass()
# Active multiple units of measure security group for user
cls.env.user.groups_id = [(4, cls.env.ref("uom.group_uom").id)]
cls.StockPicking = cls.env["stock.picking"]
cls.warehouse = cls.env.ref("stock.warehouse0")
cls.location_supplier = cls.env.ref("stock.stock_location_suppliers")
cls.location_stock = cls.env.ref("stock.stock_location_stock")
cls.picking_type_in = cls.env.ref("stock.picking_type_in")
cls.picking_type_out = cls.env.ref("stock.picking_type_out")
cls.product_uom_kg = cls.env.ref("uom.product_uom_kgm")
cls.product_uom_ton = cls.env.ref("uom.product_uom_ton")
cls.product_uom_unit = cls.env.ref("uom.product_uom_unit")
ProductAttribute = cls.env["product.attribute"]
ProductAttributeValue = cls.env["product.attribute.value"]
@@ -34,7 +41,7 @@ class TestProductSecondaryUnit(SavepointCase):
0,
{
"code": "A",
"name": "unit-700",
"name": "unit-500",
"uom_id": cls.product_uom_unit.id,
"factor": 0.5,
},
@@ -49,6 +56,16 @@ class TestProductSecondaryUnit(SavepointCase):
"factor": 0.9,
},
),
(
0,
0,
{
"code": "C",
"name": "box 10",
"uom_id": cls.product_uom_unit.id,
"factor": 10,
},
),
],
"attribute_line_ids": [
(
@@ -97,22 +114,19 @@ class TestProductSecondaryUnit(SavepointCase):
def test_03_stock_picking_secondary_unit(self):
StockPicking = self.env["stock.picking"]
product1 = self.product_template.product_variant_ids[0]
location = self.env.ref("stock.stock_location_suppliers")
location_dest = self.env.ref("stock.stock_location_stock")
picking_type = self.env.ref("stock.picking_type_in")
move_vals = {
"product_id": product1.id,
"name": product1.display_name,
"secondary_uom_id": product1.secondary_uom_ids[0].id,
"product_uom": product1.uom_id.id,
"product_uom_qty": 10.0,
"location_id": location.id,
"location_dest_id": location_dest.id,
"location_id": self.location_supplier.id,
"location_dest_id": self.location_stock.id,
}
do_vals = {
"location_id": location.id,
"location_dest_id": location_dest.id,
"picking_type_id": picking_type.id,
"location_id": self.location_supplier.id,
"location_dest_id": self.location_stock.id,
"picking_type_id": self.picking_type_in.id,
"move_ids_without_package": [
(0, None, move_vals),
(0, None, move_vals),
@@ -130,3 +144,83 @@ class TestProductSecondaryUnit(SavepointCase):
)
self.assertEquals(uom_qty, 20.0)
self.assertEquals(secondary_uom_qty, 40.0)
def test_picking_secondary_unit(self):
product = self.product_template.product_variant_ids[0]
with Form(
self.StockPicking.with_context(
planned_picking=True, default_picking_type_id=self.picking_type_out.id,
)
) as picking_form:
with picking_form.move_ids_without_package.new() as move:
move.product_id = product
move.secondary_uom_qty = 1
move.secondary_uom_id = product.secondary_uom_ids[0]
self.assertEqual(move.product_uom_qty, 0.5)
move.secondary_uom_qty = 2
self.assertEqual(move.product_uom_qty, 1)
move.secondary_uom_id = product.secondary_uom_ids[1]
self.assertEqual(move.product_uom_qty, 1.8)
move.product_uom_qty = 5
self.assertAlmostEqual(move.secondary_uom_qty, 5.56, 2)
# Change uom from stock move line
move.secondary_uom_qty = 1
move.secondary_uom_id = product.secondary_uom_ids[2]
self.assertEqual(move.product_uom_qty, 10)
move.product_uom = self.product_uom_ton
self.assertAlmostEqual(move.secondary_uom_qty, 1000, 2)
picking = picking_form.save()
picking.action_confirm()
with Form(picking) as picking_form:
# Test detail operations
with picking_form.move_line_ids_without_package.new() as move:
move.product_id = product
move.secondary_uom_qty = 1
move.secondary_uom_id = product.secondary_uom_ids[0]
self.assertEqual(move.qty_done, 0.5)
move.secondary_uom_qty = 2
self.assertEqual(move.qty_done, 1)
move.secondary_uom_id = product.secondary_uom_ids[1]
self.assertEqual(move.qty_done, 1.8)
move.qty_done = 5
self.assertAlmostEqual(move.secondary_uom_qty, 5.56, 2)
def test_secondary_unit_merge_move_diff_uom(self):
product = self.product_template.product_variant_ids[0]
with Form(
self.StockPicking.with_context(
planned_picking=True, default_picking_type_id=self.picking_type_out.id,
)
) as picking_form:
with picking_form.move_ids_without_package.new() as move:
move.product_id = product
move.secondary_uom_qty = 1
move.secondary_uom_id = product.secondary_uom_ids[0]
with picking_form.move_ids_without_package.new() as move:
move.product_id = product
move.secondary_uom_qty = 1
move.secondary_uom_id = product.secondary_uom_ids[1]
picking = picking_form.save()
picking.action_confirm()
self.assertEquals(len(picking.move_lines), 2)
def test_secondary_unit_merge_move_same_uom(self):
product = self.product_template.product_variant_ids[0]
with Form(
self.StockPicking.with_context(
planned_picking=True, default_picking_type_id=self.picking_type_out.id,
)
) as picking_form:
with picking_form.move_ids_without_package.new() as move:
move.product_id = product
move.secondary_uom_qty = 1
move.secondary_uom_id = product.secondary_uom_ids[0]
with picking_form.move_ids_without_package.new() as move:
move.product_id = product
move.secondary_uom_qty = 1
move.secondary_uom_id = product.secondary_uom_ids[0]
picking = picking_form.save()
picking.action_confirm()
self.assertEquals(len(picking.move_lines), 1)
self.assertEquals(picking.move_lines.secondary_uom_qty, 2)

View File

@@ -12,11 +12,15 @@
expr="//field[@name='move_ids_without_package']/tree/field[@name='product_uom_qty']"
position="before"
>
<field name="secondary_uom_qty" />
<field
name="secondary_uom_qty"
attrs="{'column_invisible': [('parent.immediate_transfer', '=', True)], 'readonly': ['|', ('is_initial_demand_editable', '=', False), '&amp;', '&amp;', ('show_operations', '=', True), ('is_locked', '=', True), ('is_initial_demand_editable', '=', False)]}"
/>
<field
name="secondary_uom_id"
domain="[('product_tmpl_id.product_variant_ids', 'in', [product_id])]"
options="{'no_create': True}"
attrs="{'column_invisible': [('parent.immediate_transfer', '=', True)], 'readonly': ['|', ('is_initial_demand_editable', '=', False), '&amp;', '&amp;', ('show_operations', '=', True), ('is_locked', '=', True), ('is_initial_demand_editable', '=', False)]}"
/>
</xpath>
</field>