Prevent doing moves in the future
issue9355 review327351002
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -28,5 +28,9 @@ class MoveOriginWarning(UserWarning):
|
||||
pass
|
||||
|
||||
|
||||
class MoveFutureWarning(UserWarning):
|
||||
pass
|
||||
|
||||
|
||||
class ProductCostPriceError(ValidationError):
|
||||
pass
|
||||
|
||||
@@ -86,5 +86,8 @@ 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">
|
||||
<field name="text">The moves "%(moves)s" have effective dates in the future.</field>
|
||||
</record>
|
||||
</data>
|
||||
</tryton>
|
||||
|
||||
@@ -21,7 +21,7 @@ from trytond.pool import Pool
|
||||
|
||||
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 @@ class Move(Workflow, ModelSQL, ModelView):
|
||||
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')
|
||||
|
||||
@@ -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'
|
||||
@@ -1552,4 +1552,9 @@ def suite():
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user