changeset 6b5f97da147a in modules/stock_lot:default
details: https://hg.tryton.org/modules/stock_lot?cmd=changeset&node=6b5f97da147a
description:
Add lot traceability
issue10792
review387871002
diffstat:
CHANGELOG | 1 +
__init__.py | 1 +
stock.py | 118 ++++++++++++++++++++++++++++++++++++++++++++++++
stock.xml | 111 ++++++++++++++++++++++++++++++++++++++------
view/lot_form.xml | 5 ++
view/lot_trace_tree.xml | 10 ++++
6 files changed, 229 insertions(+), 17 deletions(-)
diffs (309 lines):
diff -r aa9101381f03 -r 6b5f97da147a CHANGELOG
--- a/CHANGELOG Thu Feb 03 23:13:27 2022 +0100
+++ b/CHANGELOG Sat Mar 19 22:44:15 2022 +0100
@@ -1,3 +1,4 @@
+* Add lot traceability
* Add support for Python 3.10
* Remove support for Python 3.6
diff -r aa9101381f03 -r 6b5f97da147a __init__.py
--- a/__init__.py Thu Feb 03 23:13:27 2022 +0100
+++ b/__init__.py Sat Mar 19 22:44:15 2022 +0100
@@ -12,6 +12,7 @@
def register():
Pool.register(
stock.Lot,
+ stock.LotTrace,
stock.LotByLocationContext,
stock.LotsByLocations,
stock.LotByWarehouseContext,
diff -r aa9101381f03 -r 6b5f97da147a stock.py
--- a/stock.py Thu Feb 03 23:13:27 2022 +0100
+++ b/stock.py Sat Mar 19 22:44:15 2022 +0100
@@ -89,6 +89,10 @@
cls._modify_no_move = [
('product', None, 'stock_lot.msg_change_product'),
]
+ cls._buttons.update({
+ 'upward_traces': {},
+ 'downward_traces': {},
+ })
@classmethod
def get_quantity(cls, lots, name):
@@ -139,6 +143,120 @@
def write(cls, *args):
super(Lot, cls).write(*args)
+ @classmethod
+ @ModelView.button_action('stock_lot.act_lot_trace_upward_relate')
+ def upward_traces(cls, lots):
+ pass
+
+ @classmethod
+ @ModelView.button_action('stock_lot.act_lot_trace_downward_relate')
+ def downward_traces(cls, lots):
+ pass
+
+
+class LotTrace(ModelSQL, ModelView):
+ "Lot Trace"
+ __name__ = 'stock.lot.trace'
+
+ product = fields.Many2One(
+ 'product.product', "Product",
+ context={
+ 'company': Eval('company', -1),
+ },
+ depends=['company'])
+ lot = fields.Many2One('stock.lot', "Lot")
+
+ quantity = fields.Float("Quantity", digits='unit')
+ unit = fields.Many2One('product.uom', "Unit")
+
+ company = fields.Many2One('company.company', "Company")
+ date = fields.Date("Date")
+ shipment = fields.Reference("Shipment", 'get_shipments')
+ document = fields.Function(
+ fields.Reference("Document", 'get_documents'), 'get_document')
+
+ upward_traces = fields.Function(
+ fields.Many2Many(
+ 'stock.lot.trace', None, None, "Upward Traces"),
+ 'get_upward_traces')
+ downward_traces = fields.Function(
+ fields.Many2Many(
+ 'stock.lot.trace', None, None, "Downward Traces"),
+ 'get_downward_traces')
+
+ @classmethod
+ def __setup__(cls):
+ super().__setup__()
+ cls._order.insert(0, ('date', 'ASC'))
+
+ @classmethod
+ def table_query(cls):
+ pool = Pool()
+ Move = pool.get('stock.move')
+ move = Move.__table__()
+ return (
+ move.select(
+ *cls._columns(move),
+ where=move.state == 'done'))
+
+ @classmethod
+ def _columns(cls, move):
+ return [
+ move.id.as_('id'),
+ move.create_uid.as_('create_uid'),
+ move.create_date.as_('create_date'),
+ move.write_uid.as_('write_uid'),
+ move.write_date.as_('write_date'),
+ move.product.as_('product'),
+ move.lot.as_('lot'),
+ move.quantity.as_('quantity'),
+ move.uom.as_('unit'),
+ move.company.as_('company'),
+ move.effective_date.as_('date'),
+ move.shipment.as_('shipment'),
+ ]
+
+ def get_rec_name(self, name):
+ return self.document.rec_name if self.document else str(self.id)
+
+ @classmethod
+ def get_shipments(cls):
+ pool = Pool()
+ Move = pool.get('stock.move')
+ return Move.get_shipment()
+
+ @classmethod
+ def get_documents(cls):
+ return cls.get_shipments()
+
+ def get_document(self, name):
+ if self.shipment:
+ return str(self.shipment)
+
+ @classmethod
+ def _is_trace_move(cls, move):
+ return move.state == 'done'
+
+ @classmethod
+ def _trace_move_order_key(cls, move):
+ return (move.effective_date,)
+
+ def get_upward_traces(self, name):
+ return list(map(int, sorted(filter(
+ self._is_trace_move, self._get_upward_traces()),
+ key=self._trace_move_order_key)))
+
+ def _get_upward_traces(self):
+ return set()
+
+ def get_downward_traces(self, name):
+ return list(map(int, sorted(filter(
+ self._is_trace_move, self._get_downward_traces()),
+ key=self._trace_move_order_key)))
+
+ def _get_downward_traces(self):
+ return set()
+
class LotByLocationContext(ModelView):
'Lot by Location'
diff -r aa9101381f03 -r 6b5f97da147a stock.xml
--- a/stock.xml Thu Feb 03 23:13:27 2022 +0100
+++ b/stock.xml Sat Mar 19 22:44:15 2022 +0100
@@ -51,6 +51,100 @@
<field name="perm_delete" eval="True"/>
</record>
+ <record model="ir.model.button" id="lot_upward_traces_button">
+ <field name="name">upward_traces</field>
+ <field name="string">Upward Traces</field>
+ <field name="model" search="[('model', '=', 'stock.lot')]"/>
+ </record>
+
+ <record model="ir.model.button" id="lot_downward_traces_button">
+ <field name="name">downward_traces</field>
+ <field name="string">Downward Traces</field>
+ <field name="model" search="[('model', '=', 'stock.lot')]"/>
+ </record>
+
+ <record model="ir.ui.view" id="lot_trace_view_tree_upward">
+ <field name="model">stock.lot.trace</field>
+ <field name="type">tree</field>
+ <field name="field_childs">upward_traces</field>
+ <field name="name">lot_trace_tree</field>
+ </record>
+
+ <record model="ir.ui.view" id="lot_trace_view_tree_downward">
+ <field name="model">stock.lot.trace</field>
+ <field name="type">tree</field>
+ <field name="field_childs">downward_traces</field>
+ <field name="name">lot_trace_tree</field>
+ </record>
+
+ <record model="ir.action.act_window" id="act_lot_trace_upward_relate">
+ <field name="name">Upward Traces</field>
+ <field name="res_model">stock.lot.trace</field>
+ <field
+ name="domain"
+ eval="[('lot', 'in', Eval('active_ids', []))]"
+ pyson="1"/>
+ </record>
+ <record model="ir.action.act_window.view"
id="act_lot_trace_upward_relate_view1">
+ <field name="sequence" eval="10"/>
+ <field name="view" ref="lot_trace_view_tree_upward"/>
+ <field name="act_window" ref="act_lot_trace_upward_relate"/>
+ </record>
+ <record model="ir.action.keyword"
id="act_lot_trace_upward_relate_keyword1">
+ <field name="keyword">form_relate</field>
+ <field name="model">stock.lot,-1</field>
+ <field name="action" ref="act_lot_trace_upward_relate"/>
+ </record>
+
+ <record model="ir.action.act_window"
id="act_lot_trace_downward_relate">
+ <field name="name">Downward Traces</field>
+ <field name="res_model">stock.lot.trace</field>
+ <field
+ name="domain"
+ eval="[('lot', 'in', Eval('active_ids', []))]"
+ pyson="1"/>
+ </record>
+ <record model="ir.action.act_window.view"
id="act_lot_trace_downward_relate_view1">
+ <field name="sequence" eval="10"/>
+ <field name="view" ref="lot_trace_view_tree_downward"/>
+ <field name="act_window" ref="act_lot_trace_downward_relate"/>
+ </record>
+ <record model="ir.action.keyword"
id="act_lot_trace_downward_relate_keyword1">
+ <field name="keyword">form_relate</field>
+ <field name="model">stock.lot,-1</field>
+ <field name="action" ref="act_lot_trace_downward_relate"/>
+ </record>
+
+ <record model="ir.rule.group" id="rule_group_lot_trace_companies">
+ <field name="name">User in companies</field>
+ <field name="model" search="[('model', '=', 'stock.lot.trace')]"/>
+ <field name="global_p" eval="True"/>
+ </record>
+ <record model="ir.rule" id="rule_lot_trace_companies">
+ <field
+ name="domain"
+ eval="[('company', 'in', Eval('companies', []))]"
+ pyson="1"/>
+ <field name="rule_group" ref="rule_group_lot_trace_companies"/>
+ </record>
+
+ <record model="ir.model.access" id="access_lot_trace">
+ <field name="model" search="[('model', '=', 'stock.lot.trace')]"/>
+ <field name="perm_read" eval="False"/>
+ <field name="perm_write" eval="False"/>
+ <field name="perm_create" eval="False"/>
+ <field name="perm_delete" eval="False"/>
+ </record>
+
+ <record model="ir.model.access" id="access_lot_trace_group_stock">
+ <field name="model" search="[('model', '=', 'stock.lot.trace')]"/>
+ <field name="group" ref="stock.group_stock"/>
+ <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="lots_by_location_context_view_form">
<field name="model">stock.lots_by_location.context</field>
<field name="type">form</field>
@@ -163,23 +257,6 @@
<field name="action" ref="act_location_quantity_list"/>
</record>
- <record model="ir.action.act_window" id="act_move_form_relate_lot">
- <field name="name">Moves</field>
- <field name="res_model">stock.move</field>
- <field name="domain"
- eval="[If(Eval('active_ids', []) == [Eval('active_id')],
('lot', '=', Eval('active_id')), ('lot', 'in', Eval('active_ids')))]"
- pyson="1"/>
- <field name="order"
- eval="[('effective_date', 'DESC'), ('planned_date', 'DESC')]"
- pyson="1"/>
- </record>
- <record model="ir.action.keyword"
- id="act_move_form_relate_lot_keyword1">
- <field name="keyword">form_relate</field>
- <field name="model">stock.lot,-1</field>
- <field name="action" ref="act_move_form_relate_lot"/>
- </record>
-
<record model="ir.ui.view" id="move_view_form">
<field name="model">stock.move</field>
<field name="inherit" ref="stock.move_view_form"/>
diff -r aa9101381f03 -r 6b5f97da147a view/lot_form.xml
--- a/view/lot_form.xml Thu Feb 03 23:13:27 2022 +0100
+++ b/view/lot_form.xml Sat Mar 19 22:44:15 2022 +0100
@@ -6,4 +6,9 @@
<field name="number"/>
<label name="product"/>
<field name="product"/>
+
+ <group id="relates" colspan="4" col="-1">
+ <button name="upward_traces" icon="tryton-arrow-up"/>
+ <button name="downward_traces" icon="tryton-arrow-down"/>
+ </group>
</form>
diff -r aa9101381f03 -r 6b5f97da147a view/lot_trace_tree.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/view/lot_trace_tree.xml Sat Mar 19 22:44:15 2022 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
+this repository contains the full copyright notices and license terms. -->
+<tree>
+ <field name="document" expand="2"/>
+ <field name="product" expand="1"/>
+ <field name="lot" expand="1"/>
+ <field name="quantity" symbol="unit"/>
+ <field name="date"/>
+</tree>