diff --git a/modules/sale/stock.py b/modules/sale/stock.py
index cd028330b2..1380526809 100644
--- a/modules/sale/stock.py
+++ b/modules/sale/stock.py
@@ -49,6 +49,13 @@ class ShipmentOut(metaclass=PoolMeta):
return super(ShipmentOut, cls).draft(shipments)
+ @classmethod
+ @ModelView.button
+ @Workflow.transition('shipped')
+ @process_sale('outgoing_moves')
+ def ship(cls, shipments):
+ super().ship(shipments)
+
@classmethod
@ModelView.button
@Workflow.transition('done')
diff --git a/modules/stock/CHANGELOG b/modules/stock/CHANGELOG
index c30fdf6d80..676e782bad 100644
--- a/modules/stock/CHANGELOG
+++ b/modules/stock/CHANGELOG
@@ -1,3 +1,4 @@
+* Add shipped state to customer shipment
Version 7.2.0 - 2024-04-29
--------------------------
diff --git a/modules/stock/shipment.py b/modules/stock/shipment.py
index e4097546d9..5ea743c4e1 100644
--- a/modules/stock/shipment.py
+++ b/modules/stock/shipment.py
@@ -1258,6 +1258,7 @@ class ShipmentOut(
origins = fields.Function(fields.Char('Origins'), 'get_origins')
picked_by = employee_field("Picked By")
packed_by = employee_field("Packed By")
+ shipped_by = employee_field("Shipped By")
done_by = employee_field("Done By")
state = fields.Selection([
('draft', 'Draft'),
@@ -1265,6 +1266,7 @@ class ShipmentOut(
('assigned', 'Assigned'),
('picked', 'Picked'),
('packed', 'Packed'),
+ ('shipped', "Shipped"),
('done', 'Done'),
('cancelled', 'Cancelled'),
], "State", readonly=True, sort=False,
@@ -1280,7 +1282,7 @@ class ShipmentOut(
(t.state, Index.Equality()),
where=t.state.in_([
'draft', 'waiting', 'assigned',
- 'picked', 'packed'])),
+ 'picked', 'packed', 'shipped'])),
})
cls._transitions |= set((
('draft', 'waiting'),
@@ -1289,9 +1291,11 @@ class ShipmentOut(
('assigned', 'picked'),
('assigned', 'packed'),
('picked', 'packed'),
+ ('packed', 'shipped'),
('packed', 'done'),
('packed', 'waiting'),
('packed', 'picked'),
+ ('shipped', 'done'),
('assigned', 'waiting'),
('waiting', 'waiting'),
('waiting', 'draft'),
@@ -1300,6 +1304,7 @@ class ShipmentOut(
('assigned', 'cancelled'),
('picked', 'cancelled'),
('packed', 'cancelled'),
+ ('shipped', 'cancelled'),
('cancelled', 'draft'),
))
cls._buttons.update({
@@ -1349,6 +1354,10 @@ class ShipmentOut(
'depends': [
'state', 'warehouse_storage', 'warehouse_output'],
},
+ 'ship': {
+ 'invisible': Eval('state') != 'packed',
+ 'depends': ['state'],
+ },
'do': {
'invisible': Eval('state') != 'packed',
},
@@ -1678,6 +1687,17 @@ class ShipmentOut(
Move.save(moves)
Move.save(imoves)
+ @classmethod
+ @ModelView.button
+ @Workflow.transition('shipped')
+ @set_employee('shipped_by')
+ def ship(cls, shipments):
+ pool = Pool()
+ Move = pool.get('stock.move')
+ Move.delete([
+ m for s in shipments for m in s.outgoing_moves
+ if m.state == 'staging'])
+
@classmethod
@ModelView.button
@Workflow.transition('done')
diff --git a/modules/stock/shipment.xml b/modules/stock/shipment.xml
index ba28d49901..f550132190 100644
--- a/modules/stock/shipment.xml
+++ b/modules/stock/shipment.xml
@@ -205,6 +205,13 @@ this repository contains the full copyright notices and license terms. -->
+
+ Shipped
+
+
+
+
+
All
@@ -628,6 +635,13 @@ this repository contains the full copyright notices and license terms. -->
Pack
+
+ stock.shipment.out
+ ship
+ Ship
+ Are you sure you want to ship the shipment?
+
+
stock.shipment.out
do
diff --git a/modules/stock/tests/scenario_stock_shipment_out.rst b/modules/stock/tests/scenario_stock_shipment_out.rst
index e750a6ad4b..b364ba6864 100644
--- a/modules/stock/tests/scenario_stock_shipment_out.rst
+++ b/modules/stock/tests/scenario_stock_shipment_out.rst
@@ -100,6 +100,7 @@ Add two shipment lines of same product::
>>> shipment_out.number
>>> shipment_out.picked_by
>>> shipment_out.packed_by
+ >>> shipment_out.shipped_by
>>> shipment_out.done_by
Set the shipment state to waiting::
@@ -163,6 +164,7 @@ Ignore non assigned moves and pack shipment::
[0.0, 1.0]
>>> shipment_out.picked_by
>>> shipment_out.packed_by
+ >>> shipment_out.shipped_by
>>> shipment_out.done_by
>>> picking_list = Report('stock.shipment.out.picking_list')
@@ -171,10 +173,12 @@ Ignore non assigned moves and pack shipment::
>>> shipment_out.click('pick')
>>> assertEqual(shipment_out.picked_by, employee)
>>> shipment_out.packed_by
+ >>> shipment_out.shipped_by
>>> shipment_out.done_by
>>> shipment_out.click('pack')
>>> assertEqual(shipment_out.packed_by, employee)
+ >>> shipment_out.shipped_by
>>> shipment_out.done_by
>>> [m.state for m in shipment_out.outgoing_moves]
['assigned']
@@ -188,6 +192,12 @@ Ignore non assigned moves and pack shipment::
>>> delivery_note = Report('stock.shipment.out.delivery_note')
>>> _ = delivery_note.execute([shipment_out])
+Set the state as Shipped::
+
+ >>> shipment_out.click('ship')
+ >>> assertEqual(shipment_out.shipped_by, employee)
+ >>> shipment_out.done_by
+
Set the state as Done::
>>> shipment_out.click('do')
diff --git a/modules/stock/view/shipment_out_form.xml b/modules/stock/view/shipment_out_form.xml
index 3918ed06d5..89ba9affbc 100644
--- a/modules/stock/view/shipment_out_form.xml
+++ b/modules/stock/view/shipment_out_form.xml
@@ -35,6 +35,8 @@ this repository contains the full copyright notices and license terms. -->
+
+
@@ -48,6 +50,7 @@ this repository contains the full copyright notices and license terms. -->
+