From b035935cefe7119155ab053626ee770f8191de80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 12 Oct 2020 20:31:27 +0200 Subject: [PATCH] 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 --- exceptions.py | 4 ++++ inventory.py | 36 +++++++++++++++++++++++++++++++++--- message.xml | 5 ++++- move.py | 6 +++--- 4 files changed, 44 insertions(+), 7 deletions(-) diff --git a/exceptions.py b/exceptions.py index 80c579c3f2..2933239c6c 100644 --- a/exceptions.py +++ b/exceptions.py @@ -32,5 +32,9 @@ class MoveFutureWarning(UserWarning): pass +class InventoryFutureWarning(UserWarning): + pass + + class ProductCostPriceError(ValidationError): pass diff --git a/inventory.py b/inventory.py index 134ad79c20..ea216c48b3 100644 --- a/inventory.py +++ b/inventory.py @@ -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 diff --git a/message.xml b/message.xml index 31b04ec816..e50f9a5fed 100644 --- a/message.xml +++ b/message.xml @@ -86,8 +86,11 @@ because the type does not support moves and location has existing moves. The source and destination of stock move must be different. - + The moves "%(moves)s" have effective dates in the future. + + The inventories "%(inventories)s" have dates in the future. + diff --git a/move.py b/move.py index e92ff8c2c6..3293bff180 100644 --- a/move.py +++ b/move.py @@ -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: