[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 Rocío Vega
parent 61c0303d7b
commit 221170515a
7 changed files with 223 additions and 92 deletions

View File

@@ -3,7 +3,7 @@
{
"name": "Stock Secondary Unit",
"summary": "Get product quantities in a secondary unit",
"version": "13.0.1.1.1",
"version": "13.0.2.0.0",
"development_status": "Production/Stable",
"category": "stock",
"website": "https://github.com/OCA/stock-logistics-warehouse",

View File

@@ -24,19 +24,26 @@ msgstr ""
#. module: stock_secondary_unit
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_product_secondary_unit__display_name
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_secondary_unit_mixin__display_name
msgid "Display Name"
msgstr "Mostrar Nombre"
#. module: stock_secondary_unit
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_move_line__qty_done
msgid "Done"
msgstr ""
#. module: stock_secondary_unit
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_product_secondary_unit__id
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_secondary_unit_mixin__id
msgid "ID"
msgstr "ID"
#. module: stock_secondary_unit
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_move__product_uom_qty
msgid "Initial Demand"
msgstr ""
#. module: stock_secondary_unit
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_product_secondary_unit____last_update
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_secondary_unit_mixin____last_update
msgid "Last Modified on"
msgstr "Última modificación en"
@@ -62,28 +69,12 @@ msgstr "Plantilla de producto"
msgid "Quantity On Hand (2Unit)"
msgstr "Cantidad a mano (2Ud.)"
#. module: stock_secondary_unit
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_move__secondary_uom_id
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_move_line__secondary_uom_id
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_secondary_unit_mixin__secondary_uom_id
#, fuzzy
msgid "Second unit"
msgstr "Unidad Secundaria"
#. module: stock_secondary_unit
#: model:ir.model.fields,field_description:stock_secondary_unit.field_product_product__stock_secondary_uom_id
#: model:ir.model.fields,field_description:stock_secondary_unit.field_product_template__stock_secondary_uom_id
msgid "Second unit for inventory"
msgstr "Segunda unidad de medida para inventario"
#. module: stock_secondary_unit
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_move__secondary_uom_qty
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_move_line__secondary_uom_qty
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_secondary_unit_mixin__secondary_uom_qty
#, fuzzy
msgid "Secondary Qty"
msgstr "Unidad Secundaria"
#. module: stock_secondary_unit
#: model_terms:ir.ui.view,arch_db:stock_secondary_unit.view_template_property_form
msgid "Secondary unit"
@@ -101,10 +92,27 @@ msgid "Stock Product Secondary Unit"
msgstr "Unidad Secundaria"
#. module: stock_secondary_unit
#: model:ir.model,name:stock_secondary_unit.model_stock_secondary_unit_mixin
#: model:ir.model.fields,help:stock_secondary_unit.field_stock_move__product_uom_qty
msgid ""
"This is the quantity of products from an inventory point of view. For moves "
"in the state 'done', this is the quantity of products that were actually "
"moved. For other moves, this is the quantity of product that is planned to "
"be moved. Lowering this quantity does not generate a backorder. Changing "
"this quantity on assigned moves affects the product reservation, and should "
"be done with care."
msgstr ""
#, fuzzy
msgid "Stock Secondary Unit Mixin"
msgstr "Unidad Secundaria"
#~ msgid "Second unit"
#~ msgstr "Unidad Secundaria"
#, fuzzy
#~ msgid "Secondary Qty"
#~ msgstr "Unidad Secundaria"
#, fuzzy
#~ msgid "Stock Secondary Unit Mixin"
#~ msgstr "Unidad Secundaria"
#~ msgid "On Hand (2unit)"
#~ msgstr "A mano (2Ud.)"

View File

@@ -20,19 +20,26 @@ msgstr ""
#. module: stock_secondary_unit
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_product_secondary_unit__display_name
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_secondary_unit_mixin__display_name
msgid "Display Name"
msgstr ""
#. module: stock_secondary_unit
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_move_line__qty_done
msgid "Done"
msgstr ""
#. module: stock_secondary_unit
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_product_secondary_unit__id
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_secondary_unit_mixin__id
msgid "ID"
msgstr ""
#. module: stock_secondary_unit
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_move__product_uom_qty
msgid "Initial Demand"
msgstr ""
#. module: stock_secondary_unit
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_product_secondary_unit____last_update
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_secondary_unit_mixin____last_update
msgid "Last Modified on"
msgstr ""
@@ -58,26 +65,12 @@ msgstr ""
msgid "Quantity On Hand (2Unit)"
msgstr ""
#. module: stock_secondary_unit
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_move__secondary_uom_id
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_move_line__secondary_uom_id
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_secondary_unit_mixin__secondary_uom_id
msgid "Second unit"
msgstr ""
#. module: stock_secondary_unit
#: model:ir.model.fields,field_description:stock_secondary_unit.field_product_product__stock_secondary_uom_id
#: model:ir.model.fields,field_description:stock_secondary_unit.field_product_template__stock_secondary_uom_id
msgid "Second unit for inventory"
msgstr ""
#. module: stock_secondary_unit
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_move__secondary_uom_qty
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_move_line__secondary_uom_qty
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_secondary_unit_mixin__secondary_uom_qty
msgid "Secondary Qty"
msgstr ""
#. module: stock_secondary_unit
#: model_terms:ir.ui.view,arch_db:stock_secondary_unit.view_template_property_form
msgid "Secondary unit"
@@ -94,6 +87,12 @@ msgid "Stock Product Secondary Unit"
msgstr ""
#. module: stock_secondary_unit
#: model:ir.model,name:stock_secondary_unit.model_stock_secondary_unit_mixin
msgid "Stock Secondary Unit Mixin"
#: model:ir.model.fields,help:stock_secondary_unit.field_stock_move__product_uom_qty
msgid ""
"This is the quantity of products from an inventory point of view. For moves "
"in the state 'done', this is the quantity of products that were actually "
"moved. For other moves, this is the quantity of product that is planned to "
"be moved. Lowering this quantity does not generate a backorder. Changing "
"this quantity on assigned moves affects the product reservation, and should "
"be done with care."
msgstr ""

View File

@@ -23,19 +23,26 @@ msgstr "<strong> 辅助单位数量</strong>"
#. module: stock_secondary_unit
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_product_secondary_unit__display_name
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_secondary_unit_mixin__display_name
msgid "Display Name"
msgstr "显示名称"
#. module: stock_secondary_unit
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_move_line__qty_done
msgid "Done"
msgstr ""
#. module: stock_secondary_unit
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_product_secondary_unit__id
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_secondary_unit_mixin__id
msgid "ID"
msgstr "ID"
#. module: stock_secondary_unit
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_move__product_uom_qty
msgid "Initial Demand"
msgstr ""
#. module: stock_secondary_unit
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_product_secondary_unit____last_update
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_secondary_unit_mixin____last_update
msgid "Last Modified on"
msgstr "最后修改时间"
@@ -61,26 +68,12 @@ msgstr "产品模板"
msgid "Quantity On Hand (2Unit)"
msgstr "在手数量(辅助单位)"
#. module: stock_secondary_unit
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_move__secondary_uom_id
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_move_line__secondary_uom_id
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_secondary_unit_mixin__secondary_uom_id
msgid "Second unit"
msgstr "辅助单位"
#. module: stock_secondary_unit
#: model:ir.model.fields,field_description:stock_secondary_unit.field_product_product__stock_secondary_uom_id
#: model:ir.model.fields,field_description:stock_secondary_unit.field_product_template__stock_secondary_uom_id
msgid "Second unit for inventory"
msgstr "库存辅助单位"
#. module: stock_secondary_unit
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_move__secondary_uom_qty
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_move_line__secondary_uom_qty
#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_secondary_unit_mixin__secondary_uom_qty
msgid "Secondary Qty"
msgstr "辅助单位数量"
#. module: stock_secondary_unit
#: model_terms:ir.ui.view,arch_db:stock_secondary_unit.view_template_property_form
msgid "Secondary unit"
@@ -97,6 +90,21 @@ msgid "Stock Product Secondary Unit"
msgstr "库存产品辅助单位"
#. module: stock_secondary_unit
#: model:ir.model,name:stock_secondary_unit.model_stock_secondary_unit_mixin
msgid "Stock Secondary Unit Mixin"
msgstr "库存辅助单位混合类"
#: model:ir.model.fields,help:stock_secondary_unit.field_stock_move__product_uom_qty
msgid ""
"This is the quantity of products from an inventory point of view. For moves "
"in the state 'done', this is the quantity of products that were actually "
"moved. For other moves, this is the quantity of product that is planned to "
"be moved. Lowering this quantity does not generate a backorder. Changing "
"this quantity on assigned moves affects the product reservation, and should "
"be done with care."
msgstr ""
#~ msgid "Second unit"
#~ msgstr "辅助单位"
#~ msgid "Secondary Qty"
#~ msgstr "辅助单位数量"
#~ msgid "Stock Secondary Unit Mixin"
#~ msgstr "库存辅助单位混合类"

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>