diff --git a/modules/stock/CHANGELOG b/modules/stock/CHANGELOG
index 26599a0e7d..ad62a66796 100644
--- a/modules/stock/CHANGELOG
+++ b/modules/stock/CHANGELOG
@@ -1,3 +1,4 @@
+* Add a group that is allowed to cancel done shipments and moves
Version 7.8.0 - 2025-12-15
--------------------------
diff --git a/modules/stock/move.py b/modules/stock/move.py
index 6c4d793136..563c191f1c 100644
--- a/modules/stock/move.py
+++ b/modules/stock/move.py
@@ -18,7 +18,7 @@ from trytond.model import (
from trytond.model.exceptions import AccessError
from trytond.modules.product import price_digits, round_price
from trytond.pool import Pool
-from trytond.pyson import Bool, Eval, If, TimeDelta
+from trytond.pyson import Bool, Eval, Id, If, TimeDelta
from trytond.tools import cached_property, grouped_slice, reduce_ids
from trytond.transaction import Transaction, without_check_access
@@ -464,7 +464,12 @@ class Move(Workflow, ModelSQL, ModelView):
))
cls._buttons.update({
'cancel': {
- 'invisible': ~Eval('state').in_(['draft', 'assigned']),
+ 'invisible': (
+ (Eval('state') == 'cancelled')
+ | ((Eval('state') == 'done')
+ & ~Id('stock',
+ 'group_stock_cancellation').in_(
+ Eval('context', {}).get('groups', [])))),
'readonly': Eval('shipment') | Eval('_parent_shipment'),
'depends': ['state', 'shipment'],
},
diff --git a/modules/stock/shipment.py b/modules/stock/shipment.py
index ee208ea710..93b7b23de9 100644
--- a/modules/stock/shipment.py
+++ b/modules/stock/shipment.py
@@ -511,7 +511,12 @@ class ShipmentIn(
))
cls._buttons.update({
'cancel': {
- 'invisible': Eval('state').in_(['cancelled', 'done']),
+ 'invisible': (
+ (Eval('state') == 'cancelled')
+ | ((Eval('state') == 'done')
+ & ~Id('stock',
+ 'group_stock_cancellation').in_(
+ Eval('context', {}).get('groups', [])))),
'depends': ['state'],
},
'draft': {
@@ -914,7 +919,12 @@ class ShipmentInReturn(
))
cls._buttons.update({
'cancel': {
- 'invisible': Eval('state').in_(['cancelled', 'done']),
+ 'invisible': (
+ (Eval('state') == 'cancelled')
+ | ((Eval('state') == 'done')
+ & ~Id('stock',
+ 'group_stock_cancellation').in_(
+ Eval('context', {}).get('groups', [])))),
'depends': ['state'],
},
'draft': {
@@ -1314,7 +1324,12 @@ class ShipmentOut(
))
cls._buttons.update({
'cancel': {
- 'invisible': Eval('state').in_(['cancelled', 'done']),
+ 'invisible': (
+ (Eval('state') == 'cancelled')
+ | ((Eval('state') == 'done')
+ & ~Id('stock',
+ 'group_stock_cancellation').in_(
+ Eval('context', {}).get('groups', [])))),
'depends': ['state'],
},
'draft': {
@@ -1984,7 +1999,12 @@ class ShipmentOutReturn(
))
cls._buttons.update({
'cancel': {
- 'invisible': Eval('state').in_(['cancelled', 'done']),
+ 'invisible': (
+ (Eval('state') == 'cancelled')
+ | ((Eval('state') == 'done')
+ & ~Id('stock',
+ 'group_stock_cancellation').in_(
+ Eval('context', {}).get('groups', [])))),
'depends': ['state'],
},
'draft': {
@@ -2489,8 +2509,12 @@ class ShipmentInternal(
))
cls._buttons.update({
'cancel': {
- 'invisible': Eval('state').in_(
- ['cancelled', 'shipped', 'done']),
+ 'invisible': (
+ (Eval('state') == 'cancelled')
+ | (Eval('state').in_(['shipped', 'done'])
+ & ~Id('stock',
+ 'group_stock_cancellation').in_(
+ Eval('context', {}).get('groups', [])))),
'depends': ['state'],
},
'draft': {
diff --git a/modules/stock/stock.xml b/modules/stock/stock.xml
index cef73475ff..66e15f736e 100644
--- a/modules/stock/stock.xml
+++ b/modules/stock/stock.xml
@@ -14,6 +14,10 @@ this repository contains the full copyright notices and license terms. -->
Stock Force Assignment
+
+ Stock Cancellation
+
+
@@ -29,6 +33,10 @@ this repository contains the full copyright notices and license terms. -->
+
+
+
+
tryton-stock