From 57032ecb96907abc162f13111c178aabc62268ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 20 Sep 2019 11:32:02 +0200 Subject: [PATCH] Use MultiSelection for lot_required issue7851 review249911002 --- CHANGELOG | 1 + __init__.py | 2 - product.py | 74 +++++++++++++++++------ stock.py | 13 ---- stock.xml | 30 --------- tests/scenario_stock_lot_shipment_out.rst | 8 +++ view/template_form.xml | 2 +- 7 files changed, 64 insertions(+), 66 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9e2771b2f3..4f79d99bd4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Use MultiSelection for lot_required * Synchronize lot on internal shipment Version 5.2.0 - 2019-05-06 diff --git a/__init__.py b/__init__.py index f324d49ede..85afe5cfc9 100644 --- a/__init__.py +++ b/__init__.py @@ -10,7 +10,6 @@ def register(): Pool.register( stock.Lot, stock.LotByLocationContext, - stock.LotType, stock.Move, stock.ShipmentIn, stock.ShipmentOut, @@ -23,7 +22,6 @@ def register(): stock.InventoryCountSearch, product.Template, product.Product, - product.TemplateLotType, module='stock_lot', type_='model') Pool.register( stock.InventoryCount, diff --git a/product.py b/product.py index a5ce32ea99..e0accc3cfc 100644 --- a/product.py +++ b/product.py @@ -1,41 +1,75 @@ # This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. -from trytond.model import ModelSQL, fields +from sql import Table + +from trytond.config import config +from trytond.model import fields from trytond.pyson import Eval from trytond.pool import PoolMeta - -__all__ = ['Template', 'Product', 'TemplateLotType'] +from trytond.transaction import Transaction class Template(metaclass=PoolMeta): __name__ = 'product.template' - # TODO to replace with a Multiple Selection - lot_required = fields.Many2Many('product.template-stock.lot.type', - 'template', 'type', 'Lot Required', + lot_required = fields.MultiSelection([ + ('supplier', "Supplier"), + ('customer', "Customer"), + ('lost_found', "Lost and Found"), + ('storage', "Storage"), + ('production', "Production"), + ], "Lot Required", help='The type of location for which lot is required', states={ 'invisible': ~Eval('type').in_(['goods', 'assets']), }, depends=['type']) + @classmethod + def __register__(cls, module): + connection = Transaction().connection + cursor = connection.cursor() + + super().__register__(module) + + table_h = cls.__table_handler__(module) + template_lot_type_table_name = config.get( + 'table', 'product.template-stock.lot.type', + default='product.template-stock.lot.type' .replace('.', '_')) + lot_type_table_name = config.get( + 'table', 'stock.lot.type', + default='stock.lot.type'.replace('.', '_')) + + # Migration from 5.2: fill lot_required + if (table_h.table_exist(template_lot_type_table_name) + and table_h.table_exist(lot_type_table_name)): + table = cls.__table__() + template_lot_type = Table(template_lot_type_table_name) + lot_type = Table(lot_type_table_name) + + cursor_select = connection.cursor() + cursor_select.execute(*template_lot_type.select( + template_lot_type.template, + distinct_on=template_lot_type.template)) + for template_id, in cursor_select: + cursor.execute(*template_lot_type + .join(lot_type, + condition=template_lot_type.type == lot_type.id) + .select( + lot_type.code, + where=template_lot_type.template == template_id)) + value = cls.lot_required.sql_format([t for t, in cursor]) + cursor.execute(*table.update( + [table.lot_required], [value], + where=table.id == template_id)) + table_h.drop_table('product.template-stock.lot.type', + template_lot_type_table_name) + table_h.drop_table('stock.lot.type', lot_type_table_name) + class Product(metaclass=PoolMeta): __name__ = 'product.product' def lot_is_required(self, from_, to): 'Is product lot required for move with "from_" and "to" location ?' - lot_required = [t.code for t in self.lot_required] - for location in (from_, to): - if location.type in lot_required: - return True - - -class TemplateLotType(ModelSQL): - 'Template - Stock Lot Type' - __name__ = 'product.template-stock.lot.type' - - template = fields.Many2One('product.template', 'Template', required=True, - select=True, ondelete='CASCADE') - type = fields.Many2One('stock.lot.type', 'Type', required=True, - ondelete='CASCADE') + return any(l.type in (self.lot_required or []) for l in [from_, to]) diff --git a/stock.py b/stock.py index 34a9063153..699f336b29 100644 --- a/stock.py +++ b/stock.py @@ -12,12 +12,6 @@ from trytond.tools import grouped_slice from trytond.transaction import Transaction from trytond.modules.stock import StockMixin -__all__ = ['Lot', 'LotType', 'Move', 'ShipmentIn', 'ShipmentOut', - 'LotByLocationContext', 'ShipmentOutReturn', - 'Period', 'PeriodCacheLot', - 'Inventory', 'InventoryLine', 'InventoryCount', 'InventoryCountSearch', - 'LotByLocationContext'] - def check_no_move(func): def find_moves(cls, records, state=None): @@ -111,13 +105,6 @@ class LotByLocationContext(ModelView): return self.forecast_date -class LotType(ModelSQL, ModelView): - "Stock Lot Type" - __name__ = 'stock.lot.type' - name = fields.Char('Name', required=True, translate=True) - code = fields.Char('Code', required=True) - - class Move(metaclass=PoolMeta): __name__ = 'stock.move' lot = fields.Many2One('stock.lot', 'Lot', diff --git a/stock.xml b/stock.xml index bf90f7bf6d..fbb37187eb 100644 --- a/stock.xml +++ b/stock.xml @@ -112,36 +112,6 @@ this repository contains the full copyright notices and license terms. --> - - supplier - Supplier - - - customer - Customer - - - lost_found - Lost and Found - - - storage - Storage - - - production - Production - - - - - - - - - - - stock.move diff --git a/tests/scenario_stock_lot_shipment_out.rst b/tests/scenario_stock_lot_shipment_out.rst index 44541cf031..ea2b371394 100644 --- a/tests/scenario_stock_lot_shipment_out.rst +++ b/tests/scenario_stock_lot_shipment_out.rst @@ -39,6 +39,7 @@ Create product:: >>> template.default_uom = unit >>> template.type = 'goods' >>> template.list_price = Decimal('20') + >>> template.lot_required = ['storage'] >>> template.save() >>> product, = template.products @@ -95,6 +96,13 @@ Assign the shipment:: >>> len(shipment_out.outgoing_moves) 1 +Try to pack without lot:: + + >>> shipment_out.click('pack') # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ... + RequiredValidationError: ... + Set 2 lots:: >>> Lot = Model.get('stock.lot') diff --git a/view/template_form.xml b/view/template_form.xml index aac79adaa4..a279c14da5 100644 --- a/view/template_form.xml +++ b/view/template_form.xml @@ -5,7 +5,7 @@ this repository contains the full copyright notices and license terms. -->