changeset fa9e653fb9db in modules/stock:default
details: https://hg.tryton.org/modules/stock?cmd=changeset;node=fa9e653fb9db
description:
Prevent doing moves in the future
issue9355
review327351002
diffstat:
CHANGELOG | 1 +
exceptions.py | 4 +
message.xml | 3 +
move.py | 25 +++++++++++-
tests/scenario_stock_move_in_future.rst | 71 +++++++++++++++++++++++++++++++++
tests/test_stock.py | 5 ++
6 files changed, 108 insertions(+), 1 deletions(-)
diffs (163 lines):
diff -r 139297ec4faa -r fa9e653fb9db CHANGELOG
--- a/CHANGELOG Sat Oct 03 23:47:19 2020 +0200
+++ b/CHANGELOG Sun Oct 04 23:57:37 2020 +0200
@@ -1,3 +1,4 @@
+* Add warning to prevent move in the future
* Add relate to open inventory lines
* Use simplified view for moves list on shipments
* Add a relate from product to its moves
diff -r 139297ec4faa -r fa9e653fb9db exceptions.py
--- a/exceptions.py Sat Oct 03 23:47:19 2020 +0200
+++ b/exceptions.py Sun Oct 04 23:57:37 2020 +0200
@@ -28,5 +28,9 @@
pass
+class MoveFutureWarning(UserWarning):
+ pass
+
+
class ProductCostPriceError(ValidationError):
pass
diff -r 139297ec4faa -r fa9e653fb9db message.xml
--- a/message.xml Sat Oct 03 23:47:19 2020 +0200
+++ b/message.xml Sun Oct 04 23:57:37 2020 +0200
@@ -86,5 +86,8 @@
<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">
+ <field name="text">The moves "%(moves)s" have effective dates in
the future.</field>
+ </record>
</data>
</tryton>
diff -r 139297ec4faa -r fa9e653fb9db move.py
--- a/move.py Sat Oct 03 23:47:19 2020 +0200
+++ b/move.py Sun Oct 04 23:57:37 2020 +0200
@@ -21,7 +21,7 @@
from trytond.modules.product import price_digits, round_price
-from .exceptions import MoveOriginWarning
+from .exceptions import MoveOriginWarning, MoveFutureWarning
STATES = {
'readonly': Eval('state').in_(['cancelled', 'assigned', 'done']),
@@ -616,6 +616,29 @@
def do(cls, moves):
pool = Pool()
Product = pool.get('product.product')
+ Date = pool.get('ir.date')
+ Warning = pool.get('res.user.warning')
+ today_cache = {}
+
+ def in_future(move):
+ if move.company not in today_cache:
+ with Transaction().set_context(company=move.company.id):
+ today_cache[move.company] = Date.today()
+ today = today_cache[move.company]
+ if move.effective_date and move.effective_date > today:
+ return move
+ future_moves = list(filter(in_future, moves))
+ if future_moves:
+ names = ', '.join(m.rec_name for m in future_moves[:5])
+ if len(future_moves) > 5:
+ names += '...'
+ warning_name = (
+ '%s.effective_date_future' % hashlib.md5(
+ str(future_moves).encode('utf-8')).hexdigest())
+ if Warning.check(warning_name):
+ raise MoveFutureWarning(warning_name,
+ gettext('stock.msg_effective_date_in_the_future',
+ moves=names))
def set_cost_values(cost_values):
Value = Product.multivalue_model('cost_price')
diff -r 139297ec4faa -r fa9e653fb9db tests/scenario_stock_move_in_future.rst
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/scenario_stock_move_in_future.rst Sun Oct 04 23:57:37 2020 +0200
@@ -0,0 +1,71 @@
+=============================
+Stock Move In Future Scenario
+=============================
+
+Imports::
+
+ >>> import datetime
+ >>> from dateutil.relativedelta import relativedelta
+ >>> from decimal import Decimal
+ >>> from proteus import Model
+ >>> from trytond.tests.tools import activate_modules
+ >>> from trytond.modules.company.tests.tools import (
+ ... create_company, get_company)
+ >>> today = datetime.date.today()
+ >>> tomorrow = today + relativedelta(days=1)
+
+Activate modules::
+
+ >>> config = activate_modules('stock')
+
+Create company::
+
+ >>> _ = create_company()
+ >>> company = get_company()
+
+Create product::
+
+ >>> ProductUom = Model.get('product.uom')
+ >>> ProductTemplate = Model.get('product.template')
+ >>> Product = Model.get('product.product')
+ >>> unit, = ProductUom.find([('name', '=', 'Unit')])
+ >>> template = ProductTemplate()
+ >>> template.name = 'Product'
+ >>> template.default_uom = unit
+ >>> template.type = 'goods'
+ >>> template.list_price = Decimal('20')
+ >>> template.save()
+ >>> product, = template.products
+ >>> product.cost_price = Decimal('1')
+ >>> product.save()
+
+Get stock locations::
+
+ >>> Location = Model.get('stock.location')
+ >>> supplier_loc, = Location.find([('code', '=', 'SUP')])
+ >>> storage_loc, = Location.find([('code', '=', 'STO')])
+
+A warning is raised when doing a move in the future::
+
+ >>> Move = Model.get('stock.move')
+ >>> move = Move()
+ >>> move.product = product
+ >>> move.quantity = 1
+ >>> move.from_location = supplier_loc
+ >>> move.to_location = storage_loc
+ >>> move.currency = company.currency
+ >>> move.effective_date = tomorrow
+ >>> move.quantity = 2
+ >>> move.unit_price = Decimal('1')
+ >>> move.save()
+ >>> move.click('do') # doctest: +IGNORE_EXCEPTION_DETAIL
+ Traceback (most recent call last):
+ ...
+ MoveFutureWarning: ...
+
+But it can be done for today::
+
+ >>> move.effective_date = today
+ >>> move.click('do')
+ >>> move.state
+ 'done'
diff -r 139297ec4faa -r fa9e653fb9db tests/test_stock.py
--- a/tests/test_stock.py Sat Oct 03 23:47:19 2020 +0200
+++ b/tests/test_stock.py Sun Oct 04 23:57:37 2020 +0200
@@ -1552,4 +1552,9 @@
tearDown=doctest_teardown, encoding='utf-8',
checker=doctest_checker,
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
+ suite.addTests(doctest.DocFileSuite(
+ 'scenario_stock_move_in_future.rst',
+ tearDown=doctest_teardown, encoding='utf-8',
+ checker=doctest_checker,
+ optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
return suite