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