changeset 695c8ac24f64 in modules/stock:default
details: https://hg.tryton.org/modules/stock?cmd=changeset&node=695c8ac24f64
description:
Allow shipments to be automatically assigned
issue9513
review318011002
diffstat:
CHANGELOG | 1 +
ir.py | 4 ++++
move.py | 26 +++++++++++++++++++++++++-
shipment.py | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++-----
shipment.xml | 49 ++++++++++++++++++++++++++++++++++++-------------
5 files changed, 119 insertions(+), 19 deletions(-)
diffs (273 lines):
diff -r 57b7fe208133 -r 695c8ac24f64 CHANGELOG
--- a/CHANGELOG Sun Apr 11 22:25:13 2021 +0100
+++ b/CHANGELOG Mon Apr 12 18:33:33 2021 +0200
@@ -1,3 +1,4 @@
+* Allow shipments to be automatically assigned
* Rename inventory count quantity_added to quantity
* Add document source on move of product quantities by warehouse
* Add relate from assigned shipment to products quantities by warehouse
diff -r 57b7fe208133 -r 695c8ac24f64 ir.py
--- a/ir.py Sun Apr 11 22:25:13 2021 +0100
+++ b/ir.py Mon Apr 12 18:33:33 2021 +0200
@@ -18,4 +18,8 @@
"Reschedule Supplier Return Shipments"),
('stock.shipment.internal|reschedule',
"Reschedule Internal Shipments"),
+ ('stock.shipment.out|assign_cron',
+ "Assign Customer Shipments"),
+ ('stock.shipment.internal|assign_cron',
+ "Assign Internal Shipments"),
])
diff -r 57b7fe208133 -r 695c8ac24f64 move.py
--- a/move.py Sun Apr 11 22:25:13 2021 +0100
+++ b/move.py Mon Apr 12 18:33:33 2021 +0200
@@ -301,7 +301,8 @@
'on_change_with_cost_price_required')
assignation_required = fields.Function(
fields.Boolean('Assignation Required'),
- 'on_change_with_assignation_required')
+ 'on_change_with_assignation_required',
+ searcher='search_assignation_required')
@classmethod
def __setup__(cls):
@@ -488,6 +489,29 @@
self.quantity
and self.from_location.type in {'storage', 'view'})
+ @classmethod
+ def search_assignation_required(cls, name, clause):
+ operators = {
+ '=': 'in',
+ '!=': 'not in',
+ }
+ reverse = {
+ '=': '!=',
+ '!=': '=',
+ }
+ if clause[1] in operators:
+ if not clause[2]:
+ operator = reverse[clause[1]]
+ else:
+ operator = clause[1]
+ return [
+ ('quantity', '!=', 0),
+ ('from_location.type', operators[operator], [
+ 'storage', 'view']),
+ ]
+ else:
+ return []
+
@staticmethod
def _get_shipment():
'Return list of Model names for shipment Reference'
diff -r 57b7fe208133 -r 695c8ac24f64 shipment.py
--- a/shipment.py Sun Apr 11 22:25:13 2021 +0100
+++ b/shipment.py Mon Apr 12 18:33:33 2021 +0200
@@ -30,6 +30,12 @@
class ShipmentAssignMixin(ShipmentMixin):
+ _assign_moves_field = None
+
+ partially_assigned = fields.Function(
+ fields.Boolean("Partially Assigned"),
+ 'get_partially_assigned',
+ searcher='search_partially_assigned')
@classmethod
def assign_wizard(cls, shipments):
@@ -37,7 +43,7 @@
@property
def assign_moves(self):
- raise NotImplementedError
+ return getattr(self, self._assign_moves_field)
@dualmethod
@ModelView.button
@@ -65,6 +71,48 @@
})
cls.assign(shipments)
+ @classmethod
+ def _get_assign_domain(cls):
+ pool = Pool()
+ Date = pool.get('ir.date')
+ return [
+ ('state', '=', 'waiting'),
+ ('planned_date', '=', Date.today()),
+ ]
+
+ @classmethod
+ def assign_cron(cls):
+ shipments = cls.search(cls._get_assign_domain())
+ cls.assign_try(shipments)
+
+ def get_partially_assigned(self, name):
+ return any(m.state == 'assigned' for m in self.assign_moves
+ if m.assignation_required)
+
+ @classmethod
+ def search_partially_assigned(cls, name, clause):
+ operators = {
+ '=': 'where',
+ '!=': 'not where',
+ }
+ reverse = {
+ '=': '!=',
+ '!=': '=',
+ }
+ if clause[1] in operators:
+ if not clause[2]:
+ operator = reverse[clause[1]]
+ else:
+ operator = clause[1]
+ return [
+ (cls._assign_moves_field, operators[operator], [
+ ('state', '=', 'assigned'),
+ ('assignation_required', '=', True),
+ ]),
+ ]
+ else:
+ return []
+
class ShipmentIn(ShipmentMixin, Workflow, ModelSQL, ModelView):
"Supplier Shipment"
@@ -515,6 +563,8 @@
"Supplier Return Shipment"
__name__ = 'stock.shipment.in.return'
_rec_name = 'number'
+ _assign_moves_field = 'moves'
+
effective_date = fields.Date('Effective Date',
states={
'readonly': Eval('state').in_(['cancelled', 'done']),
@@ -830,10 +880,6 @@
def assign_wizard(cls, shipments):
pass
- @property
- def assign_moves(self):
- return self.moves
-
@dualmethod
@ModelView.button
def assign_try(cls, shipments, with_childs=None):
@@ -880,6 +926,7 @@
"Customer Shipment"
__name__ = 'stock.shipment.out'
_rec_name = 'number'
+ _assign_moves_field = 'moves'
effective_date = fields.Date('Effective Date',
states={
'readonly': Eval('state').in_(['cancelled', 'done']),
@@ -1934,6 +1981,7 @@
"Internal Shipment"
__name__ = 'stock.shipment.internal'
_rec_name = 'number'
+ _assign_moves_field = 'moves'
effective_date = fields.Date('Effective Date',
states={
'readonly': Eval('state').in_(['cancelled', 'done']),
diff -r 57b7fe208133 -r 695c8ac24f64 shipment.xml
--- a/shipment.xml Sun Apr 11 22:25:13 2021 +0100
+++ b/shipment.xml Mon Apr 12 18:33:33 2021 +0200
@@ -93,18 +93,26 @@
<field name="act_window" ref="act_shipment_in_return_form"/>
</record>
<record model="ir.action.act_window.domain"
- id="act_shipment_in_return_form_domain_assigned">
- <field name="name">Assigned</field>
- <field name="sequence" eval="30"/>
- <field name="domain" eval="[('state', '=', 'assigned')]"
pyson="1"/>
+ id="act_shipment_in_return_form_domain_waiting">
+ <field name="name">Waiting</field>
+ <field name="sequence" eval="20"/>
+ <field name="domain" eval="[('state', '=', 'waiting')]" pyson="1"/>
<field name="count" eval="True"/>
<field name="act_window" ref="act_shipment_in_return_form"/>
</record>
<record model="ir.action.act_window.domain"
- id="act_shipment_in_return_form_domain_waiting">
- <field name="name">Waiting</field>
- <field name="sequence" eval="20"/>
- <field name="domain" eval="[('state', '=', 'waiting')]" pyson="1"/>
+ id="act_shipment_in_return_form_domain_available">
+ <field name="name">Partially Assigned</field>
+ <field name="sequence" eval="30"/>
+ <field name="domain" eval="[('partially_assigned', '=', 'True')]"
pyson="1"/>
+ <field name="count" eval="True"/>
+ <field name="act_window" ref="act_shipment_in_return_form"/>
+ </record>
+ <record model="ir.action.act_window.domain"
+ id="act_shipment_in_return_form_domain_assigned">
+ <field name="name">Assigned</field>
+ <field name="sequence" eval="40"/>
+ <field name="domain" eval="[('state', '=', 'assigned')]"
pyson="1"/>
<field name="count" eval="True"/>
<field name="act_window" ref="act_shipment_in_return_form"/>
</record>
@@ -163,23 +171,30 @@
<field name="count" eval="True"/>
<field name="act_window" ref="act_shipment_out_form"/>
</record>
+ <record model="ir.action.act_window.domain"
id="act_shipment_out_form_domain_available">
+ <field name="name">Partially Assigned</field>
+ <field name="sequence" eval="30"/>
+ <field name="domain" eval="[('partially_assigned', '=', True)]"
pyson="1"/>
+ <field name="count" eval="True"/>
+ <field name="act_window" ref="act_shipment_out_form"/>
+ </record>
<record model="ir.action.act_window.domain"
id="act_shipment_out_form_domain_assigned">
<field name="name">Assigned</field>
- <field name="sequence" eval="30"/>
+ <field name="sequence" eval="40"/>
<field name="domain" eval="[('state', '=', 'assigned')]"
pyson="1"/>
<field name="count" eval="True"/>
<field name="act_window" ref="act_shipment_out_form"/>
</record>
<record model="ir.action.act_window.domain"
id="act_shipment_out_form_domain_picked">
<field name="name">Picked</field>
- <field name="sequence" eval="40"/>
+ <field name="sequence" eval="50"/>
<field name="domain" eval="[('state', '=', 'picked')]" pyson="1"/>
<field name="count" eval="True"/>
<field name="act_window" ref="act_shipment_out_form"/>
</record>
<record model="ir.action.act_window.domain"
id="act_shipment_out_form_domain_packed">
<field name="name">Packed</field>
- <field name="sequence" eval="50"/>
+ <field name="sequence" eval="60"/>
<field name="domain" eval="[('state', '=', 'packed')]" pyson="1"/>
<field name="count" eval="True"/>
<field name="act_window" ref="act_shipment_out_form"/>
@@ -248,9 +263,17 @@
<field name="act_window" ref="act_shipment_internal_form"/>
</record>
<record model="ir.action.act_window.domain"
+ id="act_shipment_internal_form_domain_available">
+ <field name="name">Partially Assigned</field>
+ <field name="sequence" eval="30"/>
+ <field name="domain" eval="[('partially_assigned', '=', True)]"
pyson="1"/>
+ <field name="count" eval="True"/>
+ <field name="act_window" ref="act_shipment_internal_form"/>
+ </record>
+ <record model="ir.action.act_window.domain"
id="act_shipment_internal_form_domain_assigned">
<field name="name">Assigned</field>
- <field name="sequence" eval="30"/>
+ <field name="sequence" eval="40"/>
<field name="domain" eval="[('state', '=', 'assigned')]"
pyson="1"/>
<field name="count" eval="True"/>
<field name="act_window" ref="act_shipment_internal_form"/>
@@ -258,7 +281,7 @@
<record model="ir.action.act_window.domain"
id="act_shipment_internal_form_domain_shipped">
<field name="name">Shipped</field>
- <field name="sequence" eval="40"/>
+ <field name="sequence" eval="50"/>
<field name="domain" eval="[('state', '=', 'shipped')]" pyson="1"/>
<field name="act_window" ref="act_shipment_internal_form"/>
</record>