Use MultiSelection for lot_required
issue7851 review249911002
This commit is contained in:
1 parent
7d76c8cb2c
commit
57032ecb96
7 files changed
+64
-66
No files matched your search
@@ -1,3 +1,4 @@
|
||||
* Use MultiSelection for lot_required
|
||||
* Synchronize lot on internal shipment
|
||||
|
||||
Version 5.2.0 - 2019-05-06
|
||||
|
||||
@@ -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,
|
||||
|
||||
+54
-20
@@ -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])
|
||||
@@ -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',
|
||||
|
||||
@@ -112,36 +112,6 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<field name="action" ref="act_move_form_relate_lot"/>
|
||||
</record>
|
||||
|
||||
<record model="stock.lot.type" id="type_supplier">
|
||||
<field name="code">supplier</field>
|
||||
<field name="name">Supplier</field>
|
||||
</record>
|
||||
<record model="stock.lot.type" id="type_customer">
|
||||
<field name="code">customer</field>
|
||||
<field name="name">Customer</field>
|
||||
</record>
|
||||
<record model="stock.lot.type" id="type_lost_found">
|
||||
<field name="code">lost_found</field>
|
||||
<field name="name">Lost and Found</field>
|
||||
</record>
|
||||
<record model="stock.lot.type" id="type_storage">
|
||||
<field name="code">storage</field>
|
||||
<field name="name">Storage</field>
|
||||
</record>
|
||||
<record model="stock.lot.type" id="type_production">
|
||||
<field name="code">production</field>
|
||||
<field name="name">Production</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record model="ir.model.access" id="access_lot_type">
|
||||
<field name="model" search="[('model', '=', 'stock.lot.type')]"/>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="False"/>
|
||||
<field name="perm_create" eval="False"/>
|
||||
<field name="perm_delete" eval="False"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="move_view_form">
|
||||
<field name="model">stock.move</field>
|
||||
<field name="inherit" ref="stock.move_view_form"/>
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -5,7 +5,7 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<xpath expr="/form/notebook/page[@id='general']" position="after">
|
||||
<page string="Lots" name="lot_required">
|
||||
<label name="lot_required"/>
|
||||
<field name="lot_required" widget="multiselection" yexpand="0"/>
|
||||
<field name="lot_required" yexpand="0"/>
|
||||
</page>
|
||||
</xpath>
|
||||
</data>
|
||||
Reference in new issue
Block a user