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>

Reply via email to