Manage move in future at inventory level

As the inventory creates and do the moves in the same transaction, the warning
about effective date in future can not be ignored (the ids change).
Also the warning name should be based on an ordered list of record to ensure to
generate always the same name.

issue9707
review328441002
This commit is contained in:
Cédric Krier committed 2020-10-12 20:31:27 +02:00
1 parent 7eca5377da
commit b035935cef
4 files changed
+44 -7

No files matched your search

+4
View File
@@ -32,5 +32,9 @@ class MoveFutureWarning(UserWarning):
pass
class InventoryFutureWarning(UserWarning):
pass
class ProductCostPriceError(ValidationError):
pass
+33 -3
View File
@@ -1,5 +1,7 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import hashlib
from sql import Null
from trytond.i18n import gettext
@@ -10,7 +12,8 @@ from trytond.transaction import Transaction
from trytond.pool import Pool
from trytond.wizard import Wizard, StateView, StateTransition, Button
from .exceptions import InventoryValidationError, InventoryCountWarning
from .exceptions import (
InventoryValidationError, InventoryCountWarning, InventoryFutureWarning)
class Inventory(Workflow, ModelSQL, ModelView):
@@ -145,7 +148,32 @@ class Inventory(Workflow, ModelSQL, ModelView):
@ModelView.button
@Workflow.transition('done')
def confirm(cls, inventories):
Move = Pool().get('stock.move')
pool = Pool()
Move = pool.get('stock.move')
Date = pool.get('ir.date')
Warning = pool.get('res.user.warning')
today_cache = {}
def in_future(inventory):
if inventory.company not in today_cache:
with Transaction().set_context(company=inventory.company.id):
today_cache[inventory.company] = Date.today()
today = today_cache[inventory.company]
if inventory.date > today:
return inventory
future_inventories = sorted(filter(in_future, inventories))
if future_inventories:
names = ', '.join(i.rec_name for i in future_inventories[:5])
if len(future_inventories) > 5:
names + '...'
warning_name = (
'%s.date_future' % hashlib.md5(
str(future_inventories).encode('utf-8')).hexdigest())
if Warning.check(warning_name):
raise InventoryFutureWarning(warning_name,
gettext('stock.msg_inventory_date_in_the_future',
inventories=names))
moves = []
for inventory in inventories:
keys = set()
@@ -162,7 +190,9 @@ class Inventory(Workflow, ModelSQL, ModelView):
moves.append(move)
if moves:
Move.save(moves)
Move.do(moves)
# Skip MoveFutureWarning as it is newly created moves
with Transaction().set_user(0):
Move.do(moves)
@classmethod
@ModelView.button
+4 -1
View File
@@ -86,8 +86,11 @@ because the type does not support moves and location has existing moves.</field>
<record model="ir.message" id="msg_move_from_to_location">
<field name="text">The source and destination of stock move must be different.</field>
</record>
<record model="ir.message" id="msg_effective_date_in_the_future">
<record model="ir.message" id="msg_move_effective_date_in_the_future">
<field name="text">The moves "%(moves)s" have effective dates in the future.</field>
</record>
<record model="ir.message" id="msg_inventory_date_in_the_future">
<field name="text">The inventories "%(inventories)s" have dates in the future.</field>
</record>
</data>
</tryton>
+3 -3
View File
@@ -627,7 +627,7 @@ class Move(Workflow, ModelSQL, ModelView):
today = today_cache[move.company]
if move.effective_date and move.effective_date > today:
return move
future_moves = list(filter(in_future, moves))
future_moves = sorted(filter(in_future, moves))
if future_moves:
names = ', '.join(m.rec_name for m in future_moves[:5])
if len(future_moves) > 5:
@@ -637,7 +637,7 @@ class Move(Workflow, ModelSQL, ModelView):
str(future_moves).encode('utf-8')).hexdigest())
if Warning.check(warning_name):
raise MoveFutureWarning(warning_name,
gettext('stock.msg_effective_date_in_the_future',
gettext('stock.msg_move_effective_date_in_the_future',
moves=names))
def set_cost_values(cost_values):
@@ -842,7 +842,7 @@ class Move(Workflow, ModelSQL, ModelView):
return ((move.from_location.type in types)
^ (move.to_location.type in types)
and not move.origin)
moves = list(filter(no_origin, moves))
moves = sorted(filter(no_origin, moves))
if moves:
names = ', '.join(m.rec_name for m in moves[:5])
if len(moves) > 5: