Commit 339339d4 authored by Vincent Pelletier's avatar Vincent Pelletier

Use a more explicit variable naming where the action is taken on a simulation movement.

Remove LOG mesage.
Improve docstrings.
Improve coding style.
Add a warning about a strange behaviour in SplitQuantity.



git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@6867 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent bd876d4b
...@@ -31,25 +31,26 @@ from TargetSolver import TargetSolver ...@@ -31,25 +31,26 @@ from TargetSolver import TargetSolver
class CopyToTarget(TargetSolver): class CopyToTarget(TargetSolver):
""" """
Copy values simulation movement as target. This is Copy values simulation movement as target. This is
only acceptable for root movements. The meaning of only acceptable for root movements. The meaning of
this solver of other movements is far from certain. this solver of other movements is far from certain.
""" """
def _generateValueDeltaDict(self, movement): def _generateValueDeltaDict(self, simulation_movement):
""" """
Get interesting value Get interesting values
XXX: better description is possible. But is it needed ?
""" """
# Get interesting value # Get interesting value
old_quantity = movement.getQuantity() old_quantity = simulation_movement.getQuantity()
old_start_date = movement.getStartDate() old_start_date = simulation_movement.getStartDate()
old_stop_date = movement.getStopDate() old_stop_date = simulation_movement.getStopDate()
new_quantity = movement.getDeliveryQuantity() * \ new_quantity = simulation_movement.getDeliveryQuantity() * \
movement.getDeliveryRatio() simulation_movement.getDeliveryRatio()
new_start_date = movement.getDeliveryStartDateList()[0] new_start_date = simulation_movement.getDeliveryStartDateList()[0]
new_stop_date = movement.getDeliveryStopDateList()[0] new_stop_date = simulation_movement.getDeliveryStopDateList()[0]
# Calculate delta # Calculate delta
quantity_ratio = 0 quantity_ratio = 0
if old_quantity not in (None,0.0): if old_quantity not in (None,0.0): # XXX: What if quantity happens to be an integer ?
quantity_ratio = new_quantity / old_quantity quantity_ratio = new_quantity / old_quantity
start_date_delta = 0 start_date_delta = 0
stop_date_delta = 0 stop_date_delta = 0
...@@ -63,51 +64,51 @@ class CopyToTarget(TargetSolver): ...@@ -63,51 +64,51 @@ class CopyToTarget(TargetSolver):
'stop_date_delta': stop_date_delta, 'stop_date_delta': stop_date_delta,
} }
def solve(self, movement): def solve(self, simulation_movement):
""" """
Adopt values as new target Adopt values as new target
""" """
value_dict = self._generateValueDeltaDict(movement) value_dict = self._generateValueDeltaDict(simulation_movement)
# Modify recursively simulation movement # Modify recursively simulation movement
self._recursivelySolve(movement, **value_dict) self._recursivelySolve(simulation_movement, **value_dict)
def _generateValueDict(self, movement, quantity_ratio=1, def _generateValueDict(self, simulation_movement, quantity_ratio=1,
start_date_delta=0, stop_date_delta=0, start_date_delta=0, stop_date_delta=0,
**value_delta_dict): **value_delta_dict):
""" """
Generate values to save on movement. Generate values to save on simulation movement.
""" """
value_dict = {} value_dict = {}
# Modify quantity, start_date, stop_date # Modify quantity, start_date, stop_date
start_date = movement.getStartDate() start_date = simulation_movement.getStartDate()
if start_date is not None: if start_date is not None:
value_dict['start_date'] = start_date + start_date_delta value_dict['start_date'] = start_date + start_date_delta
stop_date = movement.getStopDate() stop_date = simulation_movement.getStopDate()
if stop_date is not None: if stop_date is not None:
value_dict['stop_date'] = stop_date + stop_date_delta value_dict['stop_date'] = stop_date + stop_date_delta
value_dict['quantity'] = movement.getQuantity() * quantity_ratio value_dict['quantity'] = simulation_movement.getQuantity() * quantity_ratio
return value_dict return value_dict
def _getParentParameters(self, movement, def _getParentParameters(self, simulation_movement,
**value_delta_dict): **value_delta_dict):
""" """
Get parent movement, and its value delta dict. Get parent movement, and its value delta dict.
""" """
applied_rule = movement.getParentValue() applied_rule = simulation_movement.getParentValue()
parent_movement = applied_rule.getParentValue() parent_movement = applied_rule.getParentValue()
if parent_movement.getPortalType() != "Simulation Movement": if parent_movement.getPortalType() != "Simulation Movement":
parent_movement = None parent_movement = None
return parent_movement, value_delta_dict return parent_movement, value_delta_dict
def _recursivelySolve(self, movement, **value_delta_dict): def _recursivelySolve(self, simulation_movement, **value_delta_dict):
""" """
Update value of the current simulation movement, and update his parent Update value of the current simulation movement, and update
movement. his parent movement.
""" """
value_dict = self._generateValueDict(movement, **value_delta_dict) value_dict = self._generateValueDict(simulation_movement, **value_delta_dict)
movement.edit(**value_dict) simulation_movement.edit(**value_dict)
parent_movement, parent_value_delta_dict = \ parent_movement, parent_value_delta_dict = \
self._getParentParameters(movement, **value_delta_dict) self._getParentParameters(simulation_movement, **value_delta_dict)
if parent_movement is not None: if parent_movement is not None:
# Modify the parent movement # Modify the parent movement
self._recursivelySolve(parent_movement, **parent_value_delta_dict) self._recursivelySolve(parent_movement, **parent_value_delta_dict)
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
# from Products.ERP5.Tool.SimulationTool import registerTargetSolver # from Products.ERP5.Tool.SimulationTool import registerTargetSolver
from CopyToTarget import CopyToTarget from CopyToTarget import CopyToTarget
from zLOG import LOG
class ProfitAndLoss(CopyToTarget): class ProfitAndLoss(CopyToTarget):
""" """
...@@ -45,13 +44,17 @@ class ProfitAndLoss(CopyToTarget): ...@@ -45,13 +44,17 @@ class ProfitAndLoss(CopyToTarget):
Movement difference as a profit (ie. a quantity coming from nowhere) Movement difference as a profit (ie. a quantity coming from nowhere)
Accumulate into delivered movement Accumulate into delivered movement
""" """
LOG('profit and loss called on movement', 0, repr(movement))
delivery_line = movement.getDeliveryValue() delivery_line = movement.getDeliveryValue()
delivery_line_quantity = delivery_line.getQuantity() delivery_line_quantity = delivery_line.getQuantity()
if delivery_line_quantity is not None: if delivery_line_quantity is not None:
target_quantity = delivery_line_quantity * movement.getDeliveryRatio() target_quantity = delivery_line_quantity * movement.getDeliveryRatio()
added_quantity = movement.getQuantity() - target_quantity added_quantity = movement.getQuantity() - target_quantity
movement.edit(profit_quantity=added_quantity) movement.edit(profit_quantity = added_quantity)
delivery = movement.getDeliveryValue() delivery = movement.getDeliveryValue()
if delivery is not None: if delivery is not None:
delivery.activate(after_path_and_method_id=(movement.getPath(), ['immediateReindexObject', 'recursiveImmediateReindexObject'])).edit() delivery.activate(
after_path_and_method_id = (
movement.getPath(),
['immediateReindexObject', 'recursiveImmediateReindexObject']
)
).edit()
...@@ -35,7 +35,7 @@ class Redirect(TargetSolver): ...@@ -35,7 +35,7 @@ class Redirect(TargetSolver):
Redirects all simulation movements to new target Redirects all simulation movements to new target
""" """
def solve(self, movement, new_target): def solve(self, simulation_movement, new_target):
""" """
Updates all sources and destinations to new values defined Updates all sources and destinations to new values defined
in self by mapping in self by mapping
...@@ -46,15 +46,15 @@ class Redirect(TargetSolver): ...@@ -46,15 +46,15 @@ class Redirect(TargetSolver):
""" """
for p in ('source', 'destination'): for p in ('source', 'destination'):
for q in ('source', 'destination'): for q in ('source', 'destination'):
if movement.getProperty(p) == getattr(self, q): if simulation_movement.getProperty(p) == getattr(self, q):
self.setProperty(p, getattr(self, 'target_%s' % q)) self.setProperty(p, getattr(self, 'target_%s' % q))
break break
for p in ('source_section', 'destination_section'): for p in ('source_section', 'destination_section'):
for q in ('source_section', 'destination_section'): for q in ('source_section', 'destination_section'):
if movement.getProperty(p) == getattr(self, q): if simulation_movement.getProperty(p) == getattr(self, q):
self.setProperty(p, getattr(self, 'target_%s' % q)) self.setProperty(p, getattr(self, 'target_%s' % q))
break break
delivery_value = movement.getDeliveryValue() # Get delivery movement delivery_value = simulation_movement.getDeliveryValue() # Get delivery movement
if delivery_value is not None: if delivery_value is not None:
delivery_value = delivery_value.getDeliveryValue() # Get root delivery delivery_value = delivery_value.getDeliveryValue() # Get root delivery
if delivery_value is not None: if delivery_value is not None:
......
...@@ -42,39 +42,39 @@ class SplitAndDefer(CopyToTarget): ...@@ -42,39 +42,39 @@ class SplitAndDefer(CopyToTarget):
(excessive qty is not covered) (excessive qty is not covered)
""" """
def solve(self, movement): def solve(self, simulation_movement):
""" """
Split a movement and accumulate Split a simulation movement and accumulate
""" """
movement_quantity = movement.getQuantity() movement_quantity = simulation_movement.getQuantity()
delivery_quantity = movement.getDeliveryQuantity() delivery_quantity = simulation_movement.getDeliveryQuantity()
new_movement_quantity = delivery_quantity * movement.getDeliveryRatio() new_movement_quantity = delivery_quantity * simulation_movement.getDeliveryRatio()
if movement_quantity > new_movement_quantity: if movement_quantity > new_movement_quantity:
split_index = 0 split_index = 0
new_id = "%s_split_%s" % (movement.getId(), split_index) new_id = "%s_split_%s" % (simulation_movement.getId(), split_index)
while getattr(movement.aq_parent, new_id, None) is not None: while getattr(simulation_movement.aq_parent, new_id, None) is not None:
split_index += 1 split_index += 1
new_id = "%s_split_%s" % (movement.getId(), split_index) new_id = "%s_split_%s" % (simulation_movement.getId(), split_index)
# Adopt different dates for defferred movements # Adopt different dates for defferred movements
new_movement = movement.aq_parent.newContent( new_movement = simulation_movement.aq_parent.newContent(
portal_type="Simulation Movement", portal_type="Simulation Movement",
id=new_id, id=new_id,
efficiency=movement.getEfficiency(), efficiency=simulation_movement.getEfficiency(),
start_date=self.start_date, start_date=self.start_date,
stop_date=self.stop_date, stop_date=self.stop_date,
order=movement.getOrder(), order=simulation_movement.getOrder(),
deliverable=movement.isDeliverable(), deliverable=simulation_movement.isDeliverable(),
quantity=movement_quantity-new_movement_quantity, quantity=movement_quantity-new_movement_quantity,
source = movement.getSource(), source = simulation_movement.getSource(),
destination = movement.getDestination(), destination = simulation_movement.getDestination(),
source_section = movement.getSourceSection(), source_section = simulation_movement.getSourceSection(),
resource = movement.getResource(), resource = simulation_movement.getResource(),
destination_section = movement.getDestinationSection(), destination_section = simulation_movement.getDestinationSection(),
activate_kw=self.activate_kw, activate_kw=self.activate_kw,
**self.additional_parameters **self.additional_parameters
) )
new_movement.activate(**self.additional_parameters).expand() new_movement.activate(**self.additional_parameters).expand()
movement._v_activate_kw = self.activate_kw simulation_movement._v_activate_kw = self.activate_kw
movement.activate(**self.additional_parameters).expand() simulation_movement.activate(**self.additional_parameters).expand()
CopyToTarget.solve(self, movement) CopyToTarget.solve(self, simulation_movement)
...@@ -31,34 +31,46 @@ from CopyToTarget import CopyToTarget ...@@ -31,34 +31,46 @@ from CopyToTarget import CopyToTarget
from zLOG import LOG from zLOG import LOG
class SplitQuantity(CopyToTarget): class SplitQuantity(CopyToTarget):
"""
Split a simulation movement based on a resource quantity.
"""
def solve(self, movement): def solve(self, simulation_movement):
""" """
Split a movement based on a given quantity From simulation_movement, generate new_movement containing self.quantity
resources, of start_date self.start_date and stop_date self.stop_date.
movement.quantity is updated
XXX incomplete docstring
""" """
split_index = 0 split_index = 0
new_id = "%s_split_%s" % (movement.getId(), split_index) new_id = "%s_split_%s" % (simulation_movement.getId(), split_index)
while getattr(movement.aq_parent, new_id, None) is not None: while getattr(simulation_movement.aq_parent, new_id, None) is not None:
split_index += 1 split_index += 1
new_id = "%s_split_%s" % (movement.getId(), split_index) new_id = "%s_split_%s" % (simulation_movement.getId(), split_index)
# Adopt different dates for defferred movements # Adopt different dates for defferred movements
new_movement = movement.aq_parent.newContent( new_movement = simulation_movement.aq_parent.newContent(
portal_type="Simulation Movement", portal_type = "Simulation Movement",
id=new_id, id = new_id,
efficiency=movement.getEfficiency(), efficiency = simulation_movement.getEfficiency(),
start_date=self.start_date, start_date = self.start_date,
stop_date=self.stop_date, stop_date = self.stop_date,
# XXX resource # XXX resource
order=movement.getOrder(), order = simulation_movement.getOrder(),
deliverable=movement.isDeliverable(), deliverable = simulation_movement.isDeliverable(),
quantity=self.quantity, quantity = self.quantity,
source = movement.getSource(), source = simulation_movement.getSource(),
destination = movement.getDestination(), destination = simulation_movement.getDestination(),
source_section = movement.getSourceSection(), source_section = simulation_movement.getSourceSection(),
destination_section = movement.getDestinationSection(), destination_section = simulation_movement.getDestinationSection(),
activate_kw=self.activate_kw, activate_kw = self.activate_kw,
**self.additional_parameters **self.additional_parameters
) )
movement._v_activate_kw = self.activate_kw simulation_movement._v_activate_kw = self.activate_kw
movement.edit(quantity=(movement.getQuantity() - self.quantity) * movement.getDeliveryRatio()) simulation_movement.edit (
quantity = (simulation_movement.getQuantity() - self.quantity)
* simulation_movement.getDeliveryRatio()
)
#XXX: vincent: I don't understand why it's multiplicated.
return new_movement return new_movement
...@@ -44,9 +44,12 @@ class TargetSolver: ...@@ -44,9 +44,12 @@ class TargetSolver:
- call 'updateNewTarget' on Applied rule - call 'updateNewTarget' on Applied rule
to update parent target to update parent target
This class is the base class for all target solvers.
It's virtual due to "solve", which needs to be overloaded.
""" """
def __init__(self, additional_parameters=None,activate_kw=None,**kw): def __init__(self, additional_parameters=None, activate_kw=None, **kw):
""" """
Creates an instance of TargetSolver with parameters Creates an instance of TargetSolver with parameters
""" """
...@@ -69,11 +72,14 @@ class TargetSolver: ...@@ -69,11 +72,14 @@ class TargetSolver:
XXX: maybe we do not need to pass previous_target as parameter XXX: maybe we do not need to pass previous_target as parameter
(since we accumulate it) (since we accumulate it)
This function must be implemented by the actual solver which derivates
from this class.
""" """
def solveDelivery(self, delivery): def solveDelivery(self, delivery):
""" """
Called in case it is needed for the solving process Solves the whole delivery.
""" """
# Then apply to all movements # Then apply to all movements
for movement in delivery.getMovementList(): for movement in delivery.getMovementList():
...@@ -81,9 +87,9 @@ class TargetSolver: ...@@ -81,9 +87,9 @@ class TargetSolver:
def solveMovement(self, movement): def solveMovement(self, movement):
""" """
Called in case it is needed for the solving process Solves a movement.
""" """
# apply to all movements # Apply to all simulation movements
simulation_movement_list = movement.getDeliveryRelatedValueList( simulation_movement_list = movement.getDeliveryRelatedValueList(
portal_type="Simulation Movement") portal_type="Simulation Movement")
solved_movement_list = [] solved_movement_list = []
...@@ -100,4 +106,3 @@ class TargetSolver: ...@@ -100,4 +106,3 @@ class TargetSolver:
# XXX this is not the job of TargetSolver to create new Delivery ! # XXX this is not the job of TargetSolver to create new Delivery !
pass pass
...@@ -30,40 +30,41 @@ from CopyToTarget import CopyToTarget ...@@ -30,40 +30,41 @@ from CopyToTarget import CopyToTarget
class TransformationSourcingCopyToTarget(CopyToTarget): class TransformationSourcingCopyToTarget(CopyToTarget):
""" """
Copy values simulation movement as target, and Copy values simulation movement as target, and
recursively solve the sourcing tree. recursively solve the sourcing tree.
""" """
def _generateValueDeltaDict(self, movement): def _generateValueDeltaDict(self, simulation_movement):
""" """
Get interesting value Get interesting value
""" """
value_dict = CopyToTarget._generateValueDict(self, movement) value_dict = CopyToTarget._generateValueDict(self, simulation_movement)
value_dict.update({ value_dict.update({
'aggregate_list': movement.getDeliveryValue().getAggregateList(), 'aggregate_list':
simulation_movement.getDeliveryValue().getAggregateList(),
}) })
return value_dict return value_dict
def _generateValueDict(self, movement, aggregate_list=None, def _generateValueDict(self, simulation_movement, aggregate_list = None,
**value_delta_dict): **value_delta_dict):
""" """
Generate values to save on movement. Generate values to save on movement.
""" """
value_dict = CopyToTarget._generateValueDict(self, movement, value_dict = CopyToTarget._generateValueDict(self, simulation_movement,
**value_delta_dict) **value_delta_dict)
# Modify aggregate_list # Modify aggregate_list
if aggregate_list is not None: if aggregate_list is not None:
value_dict['aggregate_list'] = aggregate_list value_dict['aggregate_list'] = aggregate_list
return value_dict return value_dict
def _getParentParameters(self, movement, def _getParentParameters(self, simulation_movement,
**value_delta_dict): **value_delta_dict):
""" """
Get parent movement, and its value delta dict. Get parent movement, and its value delta dict.
""" """
applied_rule = movement.getParentValue() applied_rule = simulation_movement.getParentValue()
rule = applied_rule.getSpecialiseValue() rule = applied_rule.getSpecialiseValue()
if rule.getPortalType() != "Transformation Sourcing Rule": if rule.getPortalType() != "Transformation Sourcing Rule":
value_delta_dict.pop('aggregate_list', None) value_delta_dict.pop('aggregate_list', None)
return CopyToTarget._getParentParameters(self, movement, return CopyToTarget._getParentParameters(self, simulation_movement,
**value_delta_dict) **value_delta_dict)
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