From d1bafbfe85abad11aeb9c9794d9d0b4e2d39a5ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 3 Feb 2021 21:19:06 +0100 Subject: [PATCH] Add wizard to add lots and sequence for lot number issue9800 review326511002 --- __init__.py | 5 +- stock.py | 53 ++++++++++++---- stock.xml | 6 ++ tests/scenario_stock_lot_unit_move_add.rst | 72 ++++++++++++++++++++++ tests/test_stock_lot_unit.py | 4 ++ 5 files changed, 126 insertions(+), 14 deletions(-) create mode 100644 tests/scenario_stock_lot_unit_move_add.rst diff --git a/__init__.py b/__init__.py index 242d0429c7..6237703102 100644 --- a/__init__.py +++ b/__init__.py @@ -5,7 +5,9 @@ from trytond.pool import Pool from . import product from . import stock -__all__ = ['register'] +from .stock import LotUnitMixin + +__all__ = ['LotUnitMixin', 'register'] def register(): @@ -13,6 +15,7 @@ def register(): product.Template, product.Product, stock.Lot, + stock.MoveAddLotsStartLot, stock.Move, stock.Inventory, stock.ShipmentIn, diff --git a/stock.py b/stock.py index 6504eca5b7..7cbbe8526a 100644 --- a/stock.py +++ b/stock.py @@ -10,8 +10,7 @@ from trytond.pyson import Eval, Bool from .exceptions import LotUnitQuantityError -class Lot(metaclass=PoolMeta): - __name__ = 'stock.lot' +class LotUnitMixin: unit = fields.Many2One( 'product.uom', "Unit", @@ -21,7 +20,7 @@ class Lot(metaclass=PoolMeta): depends=['product_default_uom_category'], help="The biggest unit for the lot.") unit_quantity = fields.Float( - "Quantity", digits=(16, Eval('unit_digits', 2)), + "Unit Quantity", digits=(16, Eval('unit_digits', 2)), states={ 'required': Bool(Eval('unit')), 'invisible': ~Eval('unit'), @@ -36,19 +35,10 @@ class Lot(metaclass=PoolMeta): unit_digits = fields.Function( fields.Integer("Unit Digits"), 'on_change_with_unit_digits') - @classmethod - def __setup__(cls): - super(Lot, cls).__setup__() - cls._modify_no_move += [ - ('unit', 'done', 'stock_lot_unit.msg_change_unit'), - ('unit_quantity', 'done', - 'stock_lot_unit.msg_change_unit_quantity'), - ] - @fields.depends('product', methods=['on_change_unit']) def on_change_product(self): try: - super(Lot, self).on_change_product() + super().on_change_product() except AttributeError: pass if self.product and self.product.lot_unit: @@ -72,6 +62,43 @@ class Lot(metaclass=PoolMeta): return self.unit.digits +class Lot(LotUnitMixin, metaclass=PoolMeta): + __name__ = 'stock.lot' + + @classmethod + def __setup__(cls): + super(Lot, cls).__setup__() + cls._modify_no_move += [ + ('unit', 'done', 'stock_lot_unit.msg_change_unit'), + ('unit_quantity', 'done', + 'stock_lot_unit.msg_change_unit_quantity'), + ] + + +class MoveAddLotsStartLot(LotUnitMixin, metaclass=PoolMeta): + __name__ = 'stock.move.add.lots.start.lot' + + @fields.depends( + 'unit', 'unit_quantity', 'quantity', 'parent', '_parent_parent.unit') + def _set_lot_values(self, lot): + pool = Pool() + Uom = pool.get('product.uom') + super()._set_lot_values(lot) + self.unit = lot.unit + self.unit_quantity = lot.unit_quantity + if self.parent.unit: + maximum_quantity = Uom.compute_qty( + lot.unit, lot.unit_quantity, self.parent.unit, round=False) + if self.quantity > maximum_quantity: + self.quantity = self.parent.unit.round(maximum_quantity) + + def _get_lot_values(self, move): + values = super()._get_lot_values(move) + values['unit'] = self.unit + values['unit_quantity'] = self.unit_quantity + return values + + class Move(metaclass=PoolMeta): __name__ = 'stock.move' diff --git a/stock.xml b/stock.xml index d4115e9d43..59e5a2d692 100644 --- a/stock.xml +++ b/stock.xml @@ -14,5 +14,11 @@ this repository contains the full copyright notices and license terms. --> lot_list + + + stock.move.add.lots.start.lot + + lot_list + diff --git a/tests/scenario_stock_lot_unit_move_add.rst b/tests/scenario_stock_lot_unit_move_add.rst new file mode 100644 index 0000000000..854464f69f --- /dev/null +++ b/tests/scenario_stock_lot_unit_move_add.rst @@ -0,0 +1,72 @@ +================================ +Stock Lot Unit Move Add Scenario +================================ + +Imports:: + + >>> from decimal import Decimal + >>> from proteus import Model, Wizard + >>> from trytond.tests.tools import activate_modules + >>> from trytond.modules.company.tests.tools import create_company + +Activate modules:: + + >>> config = activate_modules('stock_lot_unit') + +Create company:: + + >>> _ = create_company() + +Create product:: + + >>> ProductUom = Model.get('product.uom') + >>> ProductTemplate = Model.get('product.template') + >>> unit, = ProductUom.find([('name', '=', 'Unit')]) + + >>> template = ProductTemplate() + >>> template.name = 'Product' + >>> template.default_uom = unit + >>> template.type = 'goods' + >>> template.list_price = Decimal('20') + >>> template.save() + >>> product, = template.products + +Get stock locations:: + + >>> Location = Model.get('stock.location') + >>> storage_loc, = Location.find([('code', '=', 'STO')]) + >>> customer_loc, = Location.find([('code', '=', 'CUS')]) + +Create a move:: + + >>> Move = Model.get('stock.move') + >>> move = Move() + >>> move.from_location = storage_loc + >>> move.to_location = customer_loc + >>> move.product = product + >>> move.quantity = 5 + >>> move.unit_price = Decimal('20') + >>> move.save() + +Create a lot:: + + >>> Lot = Model.get('stock.lot') + >>> lot = Lot(number='01', product=product) + >>> lot.unit = unit + >>> lot.unit_quantity = 1 + >>> lot.save() + +Add a lot:: + + >>> add_lots = Wizard('stock.move.add.lots', [move]) + >>> lot = add_lots.form.lots.new() + >>> lot.quantity + 5.0 + >>> lot.product = product # proteus does not set reverse domain + >>> lot.number = '01' + >>> lot.unit == unit + True + >>> lot.unit_quantity + 1.0 + >>> lot.quantity + 1.0 diff --git a/tests/test_stock_lot_unit.py b/tests/test_stock_lot_unit.py index 780017ddfb..eb654bd53c 100644 --- a/tests/test_stock_lot_unit.py +++ b/tests/test_stock_lot_unit.py @@ -22,4 +22,8 @@ def suite(): tearDown=doctest_teardown, encoding='utf-8', checker=doctest_checker, optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)) + suite.addTests(doctest.DocFileSuite('scenario_stock_lot_unit_move_add.rst', + tearDown=doctest_teardown, encoding='utf-8', + checker=doctest_checker, + optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)) return suite