Commit 93a0f39f authored by Jérome Perrin's avatar Jérome Perrin

simulation: introduce MovementGeneratorMixin._updateGeneratedMovementList

This allows custom movement generators to set ad-hoc properties on
generated movements depending on properties of the corresponding
input movement.

There was already _getUpdatePropertyDict which is similar, but was
sometimes not enough because it can only be use to set extra
properties on all movements.

As a result, when we needed a rule with custom properties on
generated movements, we resorted to overriding getGeneratedMovementList
and duplicating the full logic of the method. Existing cases have
been updated to use the new _updateGeneratedMovementList and in the
case of InventoryAssetPriceAccountingRuleMovementGenerator we no
longer need to duplicate the logic.

Also remove the comment suggesting overriding getGeneratedMovementList
in subclasses, now several "extension" methods exists, so it should
not be needed to override getGeneratedMovementList, every needs
should be coverred by defining _updateGeneratedMovementList or
_getUpdatePropertyDict
parent 6c6a8098
......@@ -124,11 +124,18 @@ class InvoiceTransactionRuleMovementGenerator(MovementGeneratorMixin):
kw = {'delivery': None, 'resource': resource, 'price': 1}
return kw
def getGeneratedMovementList(self, movement_list=None, rounding=False):
movement_list = super(InvoiceTransactionRuleMovementGenerator, self).getGeneratedMovementList(movement_list=movement_list, rounding=rounding)
def _updateGeneratedMovementList(self, input_movement, generated_movement_list):
portal = self._applied_rule.getPortalObject()
for arrow in 'destination', 'source':
for movement in movement_list:
generated_movement_list = super(
InvoiceTransactionRuleMovementGenerator,
self,
)._updateGeneratedMovementList(
input_movement,
generated_movement_list,
)
for arrow, sign in ('destination', 1), ('source', -1):
for movement in generated_movement_list:
resource = movement.getResource()
if resource is not None:
section = movement.getDefaultAcquiredValue(arrow + '_section')
......@@ -144,13 +151,8 @@ class InvoiceTransactionRuleMovementGenerator(MovementGeneratorMixin):
categories=('price_currency/' + currency_url,
'resource/' + resource)))
if exchange_ratio is not None:
if arrow == 'destination':
sign = 1
else:
sign = -1
movement.setProperty(arrow + '_total_asset_price', movement.getQuantity() * exchange_ratio * sign)
return movement_list
return generated_movement_list
def _getInputMovementList(self, movement_list=None, rounding=False):
simulation_movement = self._applied_rule.getParentValue()
......
......@@ -32,67 +32,37 @@ from erp5.component.document.InvoiceTransactionSimulationRule import (InvoiceTra
class InventoryAssetPriceAccountingRuleMovementGenerator(InvoiceTransactionRuleMovementGenerator):
"""
"""
# CMF Type Definition
meta_type = 'ERP5 Inventory Asset Price Accounting Simulation Rule'
portal_type = 'Inventory Asset Price Accounting Simulation Rule'
# XXX: Copy/paste from erp5.component.mixin.RuleMixin to support Transit use case
def getGeneratedMovementList(self, movement_list=None, rounding=False):
"""
Returns a list of movements generated by that rule.
movement_list - optional IMovementList which can be passed explicitely
rounding - boolean argument, which controls if rounding shall be applied on
generated movements or not
NOTE:
- implement rounding appropriately (True or False seems
simplistic)
def _updateGeneratedMovementList(self, input_movement, generated_movement_list):
"""Support Transit use case
"""
# Default implementation below can be overriden by subclasses
# however it should be generic enough not to be overriden
# by most classes
# Results will be appended to result
result = []
# Build a list of movement and business path
input_movement_list = self._getInputMovementList(
movement_list=movement_list, rounding=rounding)
for input_movement in input_movement_list:
# Merge movement and business path properties (core implementation)
# Lookup Business Process through composition (NOT UNION)
business_process = input_movement.asComposedDocument()
explanation = self._applied_rule # We use applied rule as local explanation
trade_phase = self._getTradePhaseList(input_movement, business_process) # XXX-JPS not convenient to handle
update_property_dict = self._getUpdatePropertyDict(input_movement)
for movement in business_process.getTradePhaseMovementList(explanation, input_movement,
trade_phase=trade_phase, delay_mode=None,
update_property_dict=update_property_dict):
# PATCH-BEGIN
update_dict = {}
if movement.getLedger() in ('stock/stock/entree',
'stock/preparation/entree',
'stock/transit/sortie',
'stock/customs/entree'):
update_dict['start_date'] = update_dict['stop_date'] = input_movement.getStopDate()
elif movement.getLedger() in ('stock/stock/sortie',
'stock/preparation/sortie',
'stock/transit/entree'):
update_dict['start_date'] = update_dict['stop_date'] = input_movement.getStartDate()
movement._edit(**update_dict)
input_movement.log("%r (input_movement=%r): ledger=%r, start_date=%r, stop_date=%r" %
(movement,
input_movement,
movement.getLedger(),
movement.getStartDate(),
movement.getStopDate()))
# PATCH-END
result.append(movement)
# And return list of generated movements
return result
generated_movement_list = super(
InventoryAssetPriceAccountingRuleMovementGenerator,
self,
)._updateGeneratedMovementList(
input_movement,
generated_movement_list,
)
for movement in generated_movement_list:
update_dict = {}
if movement.getLedger() in ('stock/stock/entree',
'stock/preparation/entree',
'stock/transit/sortie',
'stock/customs/entree'):
update_dict['start_date'] = update_dict['stop_date'] = input_movement.getStopDate()
elif movement.getLedger() in ('stock/stock/sortie',
'stock/preparation/sortie',
'stock/transit/entree'):
update_dict['start_date'] = update_dict['stop_date'] = input_movement.getStartDate()
movement._edit(**update_dict)
input_movement.log("%r (input_movement=%r): ledger=%r, start_date=%r, stop_date=%r" %
(movement,
input_movement,
movement.getLedger(),
movement.getStartDate(),
movement.getStopDate()))
return generated_movement_list
def _getInputMovementList(self, movement_list=None, rounding=False):
simulation_movement = self._applied_rule.getParentValue()
......@@ -115,7 +85,12 @@ class InventoryAssetPriceAccountingRuleMovementGenerator(InvoiceTransactionRuleM
return update_property_dict
class InventoryAssetPriceAccountingSimulationRule(InvoiceTransactionSimulationRule):
# CMF Type Definition
meta_type = 'ERP5 Inventory Asset Price Accounting Simulation Rule'
portal_type = 'Inventory Asset Price Accounting Simulation Rule'
def _getMovementGenerator(self, context):
return InventoryAssetPriceAccountingRuleMovementGenerator(
applied_rule=context, rule=self)
......@@ -74,9 +74,6 @@ class MovementGeneratorMixin(object):
- implement rounding appropriately (True or False seems
simplistic)
"""
# Default implementation below can be overriden by subclasses
# however it should be generic enough not to be overriden
# by most classes
# Results will be appended to result
result = []
# Build a list of movement and business path
......@@ -89,9 +86,13 @@ class MovementGeneratorMixin(object):
explanation = self._applied_rule # We use applied rule as local explanation
trade_phase = self._getTradePhaseList(input_movement, business_process) # XXX-JPS not convenient to handle
update_property_dict = self._getUpdatePropertyDict(input_movement)
result.extend(business_process.getTradePhaseMovementList(explanation, input_movement,
trade_phase=trade_phase, delay_mode=None,
update_property_dict=update_property_dict))
generated_movement_list = business_process.getTradePhaseMovementList(
explanation,
input_movement,
trade_phase=trade_phase,
delay_mode=None,
update_property_dict=update_property_dict)
result.extend(self._updateGeneratedMovementList(input_movement, generated_movement_list))
# And return list of generated movements
return result
......@@ -102,6 +103,9 @@ class MovementGeneratorMixin(object):
# Other movement generators usually want to reset delivery.
return {'delivery': input_movement.getRelativeUrl()}
def _updateGeneratedMovementList(self, input_movement, generated_movement_list):
return generated_movement_list
def _getTradePhaseList(self, input_movement, business_process): # XXX-JPS WEIRD
if self._trade_phase_list:
return self._trade_phase_list
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment