changeset fbed27944e5e in modules/stock:default
details: https://hg.tryton.org/modules/stock?cmd=changeset;node=fbed27944e5e
description:
Use a single assign wizard
issue9422
review299961011
diffstat:
CHANGELOG | 1 +
__init__.py | 8 +-
shipment.py | 268 +++++++++++++--------------------
shipment.xml | 59 ++----
tests/scenario_stock_shipment_out.rst | 22 +-
view/shipment_assign_partial_form.xml | 8 +
6 files changed, 152 insertions(+), 214 deletions(-)
diffs (595 lines):
diff -r 74e127f01040 -r fbed27944e5e CHANGELOG
--- a/CHANGELOG Mon Jul 13 21:07:27 2020 +0200
+++ b/CHANGELOG Sat Jul 25 08:19:31 2020 +0200
@@ -1,3 +1,4 @@
+* Use a single assign wizard for all shipments
* Add access rules to product quantities by warehouse
* Add moves for product quantities by warehouse
* Enforce filling cost price of move
diff -r 74e127f01040 -r fbed27944e5e __init__.py
--- a/__init__.py Mon Jul 13 21:07:27 2020 +0200
+++ b/__init__.py Sat Jul 25 08:19:31 2020 +0200
@@ -30,11 +30,9 @@
shipment.ShipmentInReturn,
shipment.ShipmentOut,
shipment.ShipmentOutReturn,
- shipment.AssignShipmentOutAssignFailed,
shipment.ShipmentInternal,
+ shipment.AssignPartial,
shipment.Address,
- shipment.AssignShipmentInternalAssignFailed,
- shipment.AssignShipmentInReturnAssignFailed,
period.Period,
period.Cache,
product.Template,
@@ -57,9 +55,7 @@
res.User,
module='stock', type_='model')
Pool.register(
- shipment.AssignShipmentOut,
- shipment.AssignShipmentInternal,
- shipment.AssignShipmentInReturn,
+ shipment.Assign,
product.OpenProductQuantitiesByWarehouse,
product.RecomputeCostPrice,
product.ModifyCostPrice,
diff -r 74e127f01040 -r fbed27944e5e shipment.py
--- a/shipment.py Mon Jul 13 21:07:27 2020 +0200
+++ b/shipment.py Sat Jul 25 08:19:31 2020 +0200
@@ -8,7 +8,7 @@
from sql import Null
from trytond.i18n import gettext
-from trytond.model import Workflow, ModelView, ModelSQL, fields
+from trytond.model import Workflow, ModelView, ModelSQL, fields, dualmethod
from trytond.model.exceptions import AccessError
from trytond.modules.company import CompanyReport
from trytond.wizard import Wizard, StateTransition, StateView, Button
@@ -28,6 +28,43 @@
]
+class ShipmentAssignMixin(ShipmentMixin):
+
+ @classmethod
+ def assign_wizard(cls, shipments):
+ raise NotImplementedError
+
+ @property
+ def assign_moves(self):
+ raise NotImplementedError
+
+ @dualmethod
+ @ModelView.button
+ def assign_try(cls, shipments):
+ raise NotImplementedError
+
+ @dualmethod
+ def assign_reset(cls, shipments):
+ cls.wait(shipments)
+
+ @dualmethod
+ @ModelView.button
+ def assign_force(cls, shipments):
+ cls.assign(shipments)
+
+ @dualmethod
+ def assign_ignore(cls, shipments):
+ pool = Pool()
+ Move = pool.get('stock.move')
+ Move.write([
+ m for s in shipments for m in s.assign_moves
+ if m.assignation_required
+ and m.state in {'staging', 'draft'}], {
+ 'quantity': 0,
+ })
+ cls.assign(shipments)
+
+
class ShipmentIn(ShipmentMixin, Workflow, ModelSQL, ModelView):
"Supplier Shipment"
__name__ = 'stock.shipment.in'
@@ -457,7 +494,7 @@
})
-class ShipmentInReturn(ShipmentMixin, Workflow, ModelSQL, ModelView):
+class ShipmentInReturn(ShipmentAssignMixin, Workflow, ModelSQL, ModelView):
"Supplier Return Shipment"
__name__ = 'stock.shipment.in.return'
_rec_name = 'number'
@@ -736,7 +773,7 @@
@set_employee('assigned_by')
def assign(cls, shipments):
Move = Pool().get('stock.move')
- Move.assign([m for s in shipments for m in s.moves])
+ Move.assign([m for s in shipments for m in s.assign_moves])
@classmethod
@ModelView.button
@@ -764,7 +801,11 @@
def assign_wizard(cls, shipments):
pass
- @classmethod
+ @property
+ def assign_moves(self):
+ return self.moves
+
+ @dualmethod
@ModelView.button
def assign_try(cls, shipments, with_childs=None):
pool = Pool()
@@ -772,7 +813,7 @@
to_assign = defaultdict(list)
for shipment in shipments:
location_type = shipment.from_location.type
- for move in shipment.moves:
+ for move in shipment.assign_moves:
if move.assignation_required:
to_assign[location_type].append(move)
success = True
@@ -789,13 +830,8 @@
cls.assign(shipments)
return success
- @classmethod
- @ModelView.button
- def assign_force(cls, shipments):
- cls.assign(shipments)
-
-class ShipmentOut(ShipmentMixin, Workflow, ModelSQL, ModelView):
+class ShipmentOut(ShipmentAssignMixin, Workflow, ModelSQL, ModelView):
"Customer Shipment"
__name__ = 'stock.shipment.out'
_rec_name = 'number'
@@ -1134,6 +1170,9 @@
@Workflow.transition('assigned')
@set_employee('assigned_by')
def assign(cls, shipments):
+ pool = Pool()
+ Move = pool.get('stock.move')
+ Move.assign([m for s in shipments for m in s.assign_moves])
cls._sync_inventory_to_outgoing(shipments, quantity=False)
@classmethod
@@ -1347,11 +1386,16 @@
def assign_wizard(cls, shipments):
pass
- @classmethod
+ @property
+ def assign_moves(self):
+ return self.inventory_moves
+
+ @dualmethod
@ModelView.button
def assign_try(cls, shipments):
Move = Pool().get('stock.move')
- to_assign = [m for s in shipments for m in s.inventory_moves
+ to_assign = [
+ m for s in shipments for m in s.assign_moves
if m.assignation_required]
if Move.assign_try(to_assign):
cls.assign(shipments)
@@ -1359,13 +1403,6 @@
else:
return False
- @classmethod
- @ModelView.button
- def assign_force(cls, shipments):
- Move = Pool().get('stock.move')
- Move.assign([m for s in shipments for m in s.inventory_moves])
- cls.assign(shipments)
-
class ShipmentOutReturn(ShipmentMixin, Workflow, ModelSQL, ModelView):
"Customer Return Shipment"
@@ -1774,56 +1811,7 @@
cls.save(shipments)
-class AssignShipmentOutAssignFailed(ModelView):
- 'Assign Customer Shipment'
- __name__ = 'stock.shipment.out.assign.failed'
- inventory_moves = fields.Many2Many('stock.move', None, None,
- 'Inventory Moves', readonly=True,
- help="The inventory moves that were not assigned.")
-
- @staticmethod
- def default_inventory_moves():
- ShipmentOut = Pool().get('stock.shipment.out')
- shipment_id = Transaction().context.get('active_id')
- if not shipment_id:
- return []
- shipment = ShipmentOut(shipment_id)
- return [x.id for x in shipment.inventory_moves if x.state == 'draft']
-
-
-class AssignShipmentOut(Wizard):
- 'Assign Customer Shipment'
- __name__ = 'stock.shipment.out.assign'
- start = StateTransition()
- failed = StateView('stock.shipment.out.assign.failed',
- 'stock.shipment_out_assign_failed_view_form', [
- Button('Force Assign', 'force', 'tryton-forward',
- states={
- 'invisible': ~Id('stock',
- 'group_stock_force_assignment').in_(
- Eval('context', {}).get('groups', [])),
- }),
- Button('OK', 'end', 'tryton-ok', True),
- ])
- force = StateTransition()
-
- def transition_start(self):
- pool = Pool()
- Shipment = pool.get('stock.shipment.out')
-
- if Shipment.assign_try([Shipment(Transaction().context['active_id'])]):
- return 'end'
- else:
- return 'failed'
-
- def transition_force(self):
- Shipment = Pool().get('stock.shipment.out')
-
- Shipment.assign_force([Shipment(Transaction().context['active_id'])])
- return 'end'
-
-
-class ShipmentInternal(ShipmentMixin, Workflow, ModelSQL, ModelView):
+class ShipmentInternal(ShipmentAssignMixin, Workflow, ModelSQL, ModelView):
"Internal Shipment"
__name__ = 'stock.shipment.internal'
_rec_name = 'number'
@@ -2353,7 +2341,9 @@
@Workflow.transition('assigned')
@set_employee('assigned_by')
def assign(cls, shipments):
- pass
+ pool = Pool()
+ Move = pool.get('stock.move')
+ Move.assign([m for s in shipments for m in s.assign_moves])
@classmethod
@ModelView.button
@@ -2394,11 +2384,16 @@
def assign_wizard(cls, shipments):
pass
- @classmethod
+ @property
+ def assign_moves(self):
+ return self.outgoing_moves
+
+ @dualmethod
@ModelView.button
def assign_try(cls, shipments):
Move = Pool().get('stock.move')
- to_assign = [m for s in shipments for m in s.outgoing_moves
+ to_assign = [
+ m for s in shipments for m in s.assign_moves
if m.assignation_required]
if not to_assign or Move.assign_try(to_assign):
cls.assign(shipments)
@@ -2406,13 +2401,6 @@
else:
return False
- @classmethod
- @ModelView.button
- def assign_force(cls, shipments):
- Move = Pool().get('stock.move')
- Move.assign([m for s in shipments for m in s.outgoing_moves])
- cls.assign(shipments)
-
@property
def _move_planned_date(self):
'''
@@ -2457,102 +2445,60 @@
help="Check to send deliveries to the address.")
-class AssignShipmentInternalAssignFailed(ModelView):
- 'Assign Shipment Internal'
- __name__ = 'stock.shipment.internal.assign.failed'
- moves = fields.Many2Many('stock.move', None, None, 'Moves',
- readonly=True,
- help="The moves that were not assigned.")
-
- @staticmethod
- def default_moves():
- ShipmentInternal = Pool().get('stock.shipment.internal')
- shipment_id = Transaction().context.get('active_id')
- if not shipment_id:
- return []
- shipment = ShipmentInternal(shipment_id)
- return [x.id for x in shipment.outgoing_moves if x.state == 'draft']
-
-
-class AssignShipmentInternal(Wizard):
- 'Assign Shipment Internal'
- __name__ = 'stock.shipment.internal.assign'
+class Assign(Wizard):
+ "Assign Shipment"
+ __name__ = 'stock.shipment.assign'
start = StateTransition()
- failed = StateView('stock.shipment.internal.assign.failed',
- 'stock.shipment_internal_assign_failed_view_form', [
- Button('Force Assign', 'force', 'tryton-forward',
- states={
- 'invisible': ~Id('stock',
- 'group_stock_force_assignment').in_(
- Eval('context', {}).get('groups', [])),
- }),
- Button('OK', 'end', 'tryton-ok', True),
- ])
- force = StateTransition()
-
- def transition_start(self):
- pool = Pool()
- Shipment = pool.get('stock.shipment.internal')
-
- if Shipment.assign_try([Shipment(Transaction().context['active_id'])]):
- return 'end'
- else:
- return 'failed'
-
- def transition_force(self):
- Shipment = Pool().get('stock.shipment.internal')
-
- Shipment.assign_force([Shipment(Transaction().context['active_id'])])
- return 'end'
-
-
-class AssignShipmentInReturnAssignFailed(ModelView):
- 'Assign Supplier Return Shipment'
- __name__ = 'stock.shipment.in.return.assign.failed'
- moves = fields.Many2Many('stock.move', None, None, 'Moves',
- readonly=True,
- help="The moves that were not assigned.")
-
- @staticmethod
- def default_moves():
- ShipmentInternal = Pool().get('stock.shipment.in.return')
- shipment_id = Transaction().context.get('active_id')
- if not shipment_id:
- return []
- shipment = ShipmentInternal(shipment_id)
- return [x.id for x in shipment.moves if x.state == 'draft']
-
-
-class AssignShipmentInReturn(Wizard):
- 'Assign Supplier Return Shipment'
- __name__ = 'stock.shipment.in.return.assign'
- start = StateTransition()
- failed = StateView('stock.shipment.in.return.assign.failed',
- 'stock.shipment_in_return_assign_failed_view_form', [
- Button('Force Assign', 'force', 'tryton-forward',
+ partial = StateView(
+ 'stock.shipment.assign.partial',
+ 'stock.shipment_assign_partial_view_form', [
+ Button("Cancel", 'cancel', 'tryton-cancel'),
+ Button("Wait", 'end', 'tryton-ok', True),
+ Button("Ignore", 'ignore', 'tryton-forward'),
+ Button("Force", 'force', 'tryton-forward',
states={
'invisible': ~Id('stock',
'group_stock_force_assignment').in_(
Eval('context', {}).get('groups', [])),
}),
- Button('OK', 'end', 'tryton-ok', True),
])
+ cancel = StateTransition()
force = StateTransition()
+ ignore = StateTransition()
def transition_start(self):
- pool = Pool()
- Shipment = pool.get('stock.shipment.in.return')
-
- if Shipment.assign_try([Shipment(Transaction().context['active_id'])]):
+ if self.record.assign_try():
return 'end'
else:
- return 'failed'
+ return 'partial'
+
+ def default_partial(self, fields):
+ values = {}
+ if 'moves' in fields:
+ values['moves'] = [
+ m.id for m in self.record.assign_moves
+ if m.state in {'staging', 'draft'}]
+ return values
+
+ def transition_cancel(self):
+ self.record.assign_reset()
+ return 'end'
def transition_force(self):
- Shipment = Pool().get('stock.shipment.in.return')
+ self.record.assign_force()
+ return 'end'
+
+ def transition_ignore(self):
+ self.record.assign_ignore()
+ return 'end'
- Shipment.assign_force([Shipment(Transaction().context['active_id'])])
- return 'end'
+
+class AssignPartial(ModelView):
+ "Assign Shipment"
+ __name__ = 'stock.shipment.assign.partial'
+ moves = fields.Many2Many(
+ 'stock.move', None, None, "Moves", readonly=True,
+ help="The moves that were not assigned.")
class DeliveryNote(CompanyReport):
diff -r 74e127f01040 -r fbed27944e5e shipment.xml
--- a/shipment.xml Mon Jul 13 21:07:27 2020 +0200
+++ b/shipment.xml Sat Jul 25 08:19:31 2020 +0200
@@ -54,12 +54,6 @@
<menuitem parent="menu_stock" sequence="20"
action="act_shipment_in_form" id="menu_shipment_in_form"/>
- <record model="ir.action.wizard" id="wizard_shipment_in_return_assign">
- <field name="name">Assign Purchase Return Shipment</field>
- <field name="wiz_name">stock.shipment.in.return.assign</field>
- <field name="model">stock.shipment.in.return</field>
- </record>
-
<record model="ir.ui.view" id="shipment_in_return_view_form">
<field name="model">stock.shipment.in.return</field>
<field name="type">form</field>
@@ -122,18 +116,6 @@
action="act_shipment_in_return_form"
id="menu_shipment_in_return_form"/>
- <record model="ir.ui.view"
id="shipment_in_return_assign_failed_view_form">
- <field name="model">stock.shipment.in.return.assign.failed</field>
- <field name="type">form</field>
- <field name="name">shipment_in_return_assign_failed_form</field>
- </record>
-
- <record model="ir.action.wizard" id="wizard_shipment_out_assign">
- <field name="name">Assign Customer Shipment</field>
- <field name="wiz_name">stock.shipment.out.assign</field>
- <field name="model">stock.shipment.out</field>
- </record>
-
<record model="ir.ui.view" id="shipment_out_view_form">
<field name="model">stock.shipment.out</field>
<field name="type">form</field>
@@ -199,18 +181,6 @@
<menuitem parent="menu_stock" sequence="30"
action="act_shipment_out_form" id="menu_shipment_out_form"/>
- <record model="ir.ui.view" id="shipment_out_assign_failed_view_form">
- <field name="model">stock.shipment.out.assign.failed</field>
- <field name="type">form</field>
- <field name="name">shipment_out_assign_failed_form</field>
- </record>
-
- <record model="ir.action.wizard" id="wizard_shipment_internal_assign">
- <field name="name">Assign Shipment Internal</field>
- <field name="wiz_name">stock.shipment.internal.assign</field>
- <field name="model">stock.shipment.internal</field>
- </record>
-
<record model="ir.ui.view" id="shipment_internal_view_form">
<field name="model">stock.shipment.internal</field>
<field name="type">form</field>
@@ -288,12 +258,6 @@
action="act_shipment_internal_form"
id="menu_shipment_internal_form"/>
- <record model="ir.ui.view"
id="shipment_internal_assign_failed_view_form">
- <field name="model">stock.shipment.internal.assign.failed</field>
- <field name="type">form</field>
- <field name="name">shipment_internal_assign_failed_form</field>
- </record>
-
<record model="ir.ui.view" id="shipment_out_return_view_form">
<field name="model">stock.shipment.out.return</field>
<field name="type">form</field>
@@ -1069,5 +1033,28 @@
pyson="1"/>
<field name="rule_group" ref="rule_group_shipment_internal"/>
</record>
+
+ <record model="ir.ui.view" id="shipment_assign_partial_view_form">
+ <field name="model">stock.shipment.assign.partial</field>
+ <field name="type">form</field>
+ <field name="name">shipment_assign_partial_form</field>
+ </record>
+
+ <record model="ir.action.wizard" id="wizard_shipment_in_return_assign">
+ <field name="name">Assign Supplier Return Shipment</field>
+ <field name="wiz_name">stock.shipment.assign</field>
+ <field name="model">stock.shipment.in.return</field>
+ </record>
+ <record model="ir.action.wizard" id="wizard_shipment_out_assign">
+ <field name="name">Assign Customer Shipment</field>
+ <field name="wiz_name">stock.shipment.assign</field>
+ <field name="model">stock.shipment.out</field>
+ </record>
+ <record model="ir.action.wizard" id="wizard_shipment_internal_assign">
+ <field name="name">Assign Internal Shipment</field>
+ <field name="wiz_name">stock.shipment.assign</field>
+ <field name="model">stock.shipment.internal</field>
+ </record>
+
</data>
</tryton>
diff -r 74e127f01040 -r fbed27944e5e tests/scenario_stock_shipment_out.rst
--- a/tests/scenario_stock_shipment_out.rst Mon Jul 13 21:07:27 2020 +0200
+++ b/tests/scenario_stock_shipment_out.rst Sat Jul 25 08:19:31 2020 +0200
@@ -132,8 +132,10 @@
Assign the shipment now::
- >>> shipment_out.click('assign_try')
- False
+ >>> shipment_assign = Wizard('stock.shipment.assign', [shipment_out])
+ >>> len(shipment_assign.form.moves)
+ 1
+ >>> shipment_assign.execute('end')
>>> shipment_out.reload()
>>> len(shipment_out.outgoing_moves)
2
@@ -152,14 +154,12 @@
>>> len(set(planned_dates))
1
-Delete the draft move, assign and pack shipment::
+Ignore non assigned moves and pack shipment::
- >>> for move in shipment_out.inventory_moves:
- ... if move.state == 'draft':
- ... break
- >>> shipment_out.inventory_moves.remove(move)
- >>> shipment_out.click('assign_try')
- True
+ >>> shipment_assign = Wizard('stock.shipment.assign', [shipment_out])
+ >>> shipment_assign.execute('ignore')
+ >>> sorted([m.quantity for m in shipment_out.inventory_moves])
+ [0.0, 1.0]
>>> shipment_out.assigned_by == employee
True
>>> shipment_out.packed_by
@@ -174,7 +174,7 @@
>>> len(shipment_out.outgoing_moves)
2
>>> len(shipment_out.inventory_moves)
- 1
+ 2
>>> shipment_out.inventory_moves[0].state
'done'
>>> sum([m.quantity for m in shipment_out.inventory_moves]) == \
@@ -199,7 +199,7 @@
>>> len(shipment_out.outgoing_moves)
2
>>> len(shipment_out.inventory_moves)
- 1
+ 2
>>> shipment_out.inventory_moves[0].state
'done'
>>> sum([m.quantity for m in shipment_out.inventory_moves]) == \
diff -r 74e127f01040 -r fbed27944e5e view/shipment_assign_partial_form.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/view/shipment_assign_partial_form.xml Sat Jul 25 08:19:31 2020 +0200
@@ -0,0 +1,8 @@
+<?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. -->
+<form col="2">
+ <image name="tryton-warning" xexpand="0" xfill="0"/>
+ <separator string="Unable to assign these products:" id="unable"/>
+ <field name="moves" colspan="2" view_ids="stock.move_view_tree_simple"/>
+</form>