Commit 1eac6784 authored by Yusuke Muraoka's avatar Yusuke Muraoka

Also last path movements must has causality


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@27339 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 1c71f517
...@@ -38,6 +38,37 @@ from Products.ERP5.Document.Rule import Rule ...@@ -38,6 +38,37 @@ from Products.ERP5.Document.Rule import Rule
from Products.ERP5.Document.SimulationMovement import SimulationMovement from Products.ERP5.Document.SimulationMovement import SimulationMovement
from Products.ERP5Type.Errors import TransformationRuleError from Products.ERP5Type.Errors import TransformationRuleError
class TransformationMovementFactory:
referable_product_attr_name_list = ['resource',
'quantity', 'quantity_unit',
'variation_category_list',
'variation_property_dict']
def __init__(self):
self.product = None # base information to use for making movements
self.produced_list = list()
self.consumed_list = list()
def requestProduced(self, **produced):
self.produced_list.append(produced)
def requestConsumed(self, **consumed):
self.consumed_list.append(consumed)
def makeMovements(self, applied_rule):
"""
make movements under the applied_rule by requests
"""
request_list = ((self.produced_list, -1),
( self.consumed_list, 1))
for (request_list, rate) in request_list:
for request in request_list:
d = self.product.copy()
d.update(request)
d['quantity'] *= rate
movement = applied_rule.newContent(portal_type="Simulation Movement")
movement.edit(**d)
class TransformationRuleMixin(Base): class TransformationRuleMixin(Base):
security = ClassSecurityInfo() security = ClassSecurityInfo()
...@@ -163,11 +194,13 @@ class TransformationRule(TransformationRuleMixin, Rule): ...@@ -163,11 +194,13 @@ class TransformationRule(TransformationRuleMixin, Rule):
_list += self._getHeadPathByTradePhaseList(next_path, trade_phase_set) _list += self._getHeadPathByTradePhaseList(next_path, trade_phase_set)
return _list return _list
def getFactory(self):
return TransformationMovementFactory()
security.declareProtected(Permissions.ModifyPortalContent, 'expand') security.declareProtected(Permissions.ModifyPortalContent, 'expand')
def expand(self, applied_rule, **kw): def expand(self, applied_rule, **kw):
""" """
""" """
parent_movement = applied_rule.getParentValue() parent_movement = applied_rule.getParentValue()
transformation = self.getTransformation(movement=parent_movement) transformation = self.getTransformation(movement=parent_movement)
...@@ -180,126 +213,143 @@ class TransformationRule(TransformationRuleMixin, Rule): ...@@ -180,126 +213,143 @@ class TransformationRule(TransformationRuleMixin, Rule):
# get head of production path from business process with trade_phase_list # get head of production path from business process with trade_phase_list
head_production_path_list = self.getHeadProductionPathList(transformation, head_production_path_list = self.getHeadProductionPathList(transformation,
business_process) business_process)
factory = self.getFactory()
product_resource = transformation.getResource() factory.product = dict(
product_quantity = parent_movement.getNetQuantity() resource=transformation.getResource(),
product_quantity_unit = parent_movement.getQuantityUnit() quantity=parent_movement.getNetQuantity(),
product_variation_category_list = parent_movement.getVariationCategoryList() quantity_unit=parent_movement.getQuantityUnit(),
product_variation_property_dict = parent_movement.getVariationPropertyDict() variation_category_list=parent_movement.getVariationCategoryList(),
variation_property_dict=parent_movement.getVariationPropertyDict(),)
# consumed amounts are sorted by phase, but not ordered.
amount_dict = {} amount_dict = {}
# XXX Transformation.getAggregatedAmountList is useless, it can not have trade_phase, because Amout. # XXX Transformation.getAggregatedAmountList is useless for this, it can not have trade_phase, because Amout.
for amount in transformation.objectValues(portal_type='Transformation Transformed Resource'): for amount in transformation.objectValues(portal_type='Transformation Transformed Resource'):
phase = amount.getTradePhase() phase = amount.getTradePhase()
amount_dict.setdefault(phase, [])
amount_dict[phase].append(amount)
product_destination = None
for (phase, amount_list) in amount_dict.items():
if phase not in trade_phase_list: if phase not in trade_phase_list:
raise TransformationRuleError,\ raise TransformationRuleError,\
"Trade phase %r is not part of Business Process %r" % (phase, business_process) "Trade phase %r is not part of Business Process %r" % (phase, business_process)
amount_dict.setdefault(phase, [])
amount_dict[phase].append(amount)
last_phase_path_list = list() # to keep phase_path_list
last_prop_dict = dict()
for (phase, amount_list) in amount_dict.items():
phase_path_list = business_process.getPathValueList(phase) phase_path_list = business_process.getPathValueList(phase)
""" """
XXX: In this context, we assume quantity as ratio, XXX: In this context, we assume quantity as ratio,
but this notion is consistent with transformation. but this "quantity as ratio" is consistent with transformation.
""" """
if sum(map(lambda path: path.getQuantity(), phase_path_list)) != 1: if sum(map(lambda path: path.getQuantity(), phase_path_list)) != 1:
raise TransformationRuleError,\ raise TransformationRuleError,\
"sum ratio of Trade Phase %r of Business Process %r is not one" % (phase, business_process) "sum ratio of Trade Phase %r of Business Process %r is not one"\
% (phase, business_process)
for path in phase_path_list: for path in phase_path_list:
start_date = path.getExpectedStartDate(explanation) start_date = path.getExpectedStartDate(explanation)
stop_date = path.getExpectedStopDate(explanation) stop_date = path.getExpectedStopDate(explanation)
predecessor_remaining_phase_list = path.getPredecessorValue()\ predecessor_remaining_phase_list = path.getPredecessorValue()\
.getRemainingTradePhaseList(explanation, .getRemainingTradePhaseList(explanation,
trade_phase_list=trade_phase_list) trade_phase_list=trade_phase_list)
successor_remaining_phase_list = path.getSuccessorValue()\ successor_remaining_phase_list = path.getSuccessorValue()\
.getRemainingTradePhaseList(explanation, .getRemainingTradePhaseList(explanation,
trade_phase_list=trade_phase_list) trade_phase_list=trade_phase_list)
if len(successor_remaining_trade_phase_list) == 0: destination = path.getDestination()
"""
Destinations of last paths for transformation must be same, # checking which is not last path of transformation
because paths for transformation must be integrated finally, if len(successor_remaining_phase_list) != 0:
# partial produced movement
valid graph factory.requestProduced(
a -- causality_value=path,
\-- start_date=start_date,
X- b stop_date=stop_date,
/-- # when last path of transformation, path.getQuantity() will be return 1.
c -- quantity=factory.product['quantity'] * path.getQuantity(),
destination=destination,
invalid graph #destination_section=???,
a ------- b trade_phase_value_list=successor_remaining_phase_list)
c ------- d
"""
if product_destination is None:
product_destination = path.getDestination()
if product_destination != path.getDestination():
raise TransformationRuleError,\
"Transformation %r is not integrated on Business Process %r" % (transformation, business_process)
else: else:
# partial product movement # for making movement of last product of the transformation
movement = applied_rule.newContent(portal_type="Simulation Movement") last_phase_path_list.append(path)
movement.edit(causality_value=path,
start_date=path.getExpectedStartDate(explanation), # path params must be same
stop_date=path.getExpectedStopDate(explanation), if last_prop_dict.get('start_date', None) is None:
resource=product_resource, last_prop_dict['start_date'] = start_date
quantity=-(product_quantity * path.getQuantity()), if last_prop_dict.get('stop_date', None) is None:
quantity_unit=product_quantity_unit, last_prop_dict['stop_date'] = stop_date
variation_category_list=product_variation_category_list, # trade phase of product is must be empty []
variation_property_dict=product_variation_property_dict, if last_prop_dict.get('trade_phase_value_list', None) is None:
destination=path.getDestination(), last_prop_dict['trade_phase_value_list'] = successor_remaining_phase_list
#destination_section=???, if last_prop_dict.get('destination', None) is None:
trade_phase_value_list=successor_remaining_trade_phase_list) last_prop_dict['destination'] = destination
if last_prop_dict['start_date'] != start_date or\
last_prop_dict['stop_date'] != stop_date or\
last_prop_dict['trade_phase_value_list'] != successor_remaining_phase_list or\
last_prop_dict['destination'] != destination:
raise TransformationRuleError,\
"""Returned property is different on Transformation %r and Business Process %r"""\
% (transformation, business_process)
# when the path is part of production but not first, consume previous partial product # when the path is part of production but not first, consume previous partial product
if path not in head_production_path_list: if path not in head_production_path_list:
# consumed partial product movement factory.requestConsumed(
movement = applied_rule.newContent(portal_type="Simulation Movement") causality_value=path,
movement.edit(causality_value=path, start_date=start_date,
start_date=start_date, stop_date=stop_date,
stop_date=stop_date, quantity=factory.product['quantity'] * path.getQuantity(),
resource=product_resource, source=path.getSource(),
quantity=product_quantity * path.getQuantity(), #source_section=???,
quantity_unit=product_quantity_unit, trade_phase_value_list=predecessor_remaining_phase_list)
variation_category_list=product_variation_category_list,
variation_property_dict=product_variation_property_dict, # consumed movement
source=path.getSource(),
#source_section=???,
trade_phase_value_list=predecessor_remaining_trade_phase_list)
# consumption movement
for amount in amount_list: for amount in amount_list:
consumed_resource = amount.getResource() factory.requestConsumed(
consumed_quantity = product_quantity * amount.getQuantity() / amount.getEfficiency() causality_value=path,
consumed_quantity_unit = amount.getQuantityUnit() start_date=start_date,
stop_date=stop_date,
# consume resource resource=amount.getResource(),
movement = applied_rule.newContent(portal_type="Simulation Movement") quantity=factory.product['quantity'] * amount.getQuantity()\
movement.edit(causality_value=path, / amount.getEfficiency() * path.getQuantity(),
start_date=start_date, quantity_unit=amount.getQuantityUnit(),
stop_date=stop_date, source=path.getSource(),
resource=consumed_resource, #source_section=???,
quantity=consumed_quantity * path.getQuantity(), trade_phase=path.getTradePhase())
quantity_unit=consumed_quantity_unit,
source=path.getSource(),
#source_section=???,
trade_phase=path.getTradePhase())
# product movement
movement = applied_rule.newContent(portal_type="Simulation Movement")
movement.edit(start_date=path.getExpectedStartDate(explanation),
stop_date=path.getExpectedStopDate(explanation),
resource=product_resource,
quantity=-(product_quantity),
quantity_unit=product_quantity_unit,
variation_category_list=product_variation_category_list,
variation_property_dict=product_variation_property_dict,
destination=product_destination,
#destination_section=???,
)
"""
valid graph for transformation
a --- b --- c
a --
\
X b
/
c --
invalid graph
a ------- b
c ------- d
-- b
/
a X
\
-- c
"""
# when empty
if last_phase_path_list is None or len(last_phase_path_list) == 0:
raise TransformationRuleError,\
"""Could not make the product by Transformation %r and Business Process %r,
which last_phase_path_list is empty.""" % (transformation, business_process)
factory.requestProduced(
causality_value_list=last_phase_path_list,
# when last path of transformation, path.getQuantity() will be return 1.
quantity=factory.product['quantity'] * path.getQuantity(),
#destination_section=???,
**last_prop_dict)
factory.makeMovements(applied_rule)
Rule.expand(self, applied_rule, **kw) Rule.expand(self, applied_rule, **kw)
...@@ -222,18 +222,18 @@ class TestMRPImplementation(TestMRPMixin, ERP5TypeTestCase): ...@@ -222,18 +222,18 @@ class TestMRPImplementation(TestMRPMixin, ERP5TypeTestCase):
# assertion # assertion
expected_value_set = set([ expected_value_set = set([
('business_process_module/1/p2', 'product_module/1', 'mrp/p3', -10), (('business_process_module/1/p2',), 'product_module/1', 'mrp/p3', -10),
('business_process_module/1/p2', 'product_module/2', 'mrp/p2', 30), (('business_process_module/1/p2',), 'product_module/2', 'mrp/p2', 30),
('business_process_module/1/p2', 'product_module/3', 'mrp/p2', 10), (('business_process_module/1/p2',), 'product_module/3', 'mrp/p2', 10),
('business_process_module/1/p3', 'product_module/1', 'mrp/p3', 10), (('business_process_module/1/p3',), 'product_module/1', 'mrp/p3', 10),
('business_process_module/1/p3', 'product_module/4', 'mrp/p3', 40), (('business_process_module/1/p3',), 'product_module/4', 'mrp/p3', 40),
('business_process_module/1/p3', 'product_module/5', 'mrp/p3', 10), (('business_process_module/1/p3',), 'product_module/5', 'mrp/p3', 10),
(None, 'product_module/1', None, -10)]) (('business_process_module/1/p3',), 'product_module/1', None, -10)])
movement_list = applied_rule.objectValues() movement_list = applied_rule.objectValues()
self.assertEquals(len(expected_value_set), len(movement_list)) self.assertEquals(len(expected_value_set), len(movement_list))
movement_value_set = set([]) movement_value_set = set([])
for movement in movement_list: for movement in movement_list:
movement_value_set |= set([(movement.getCausality(), movement_value_set |= set([(tuple(movement.getCausalityList()),
movement.getResource(), movement.getResource(),
movement.getTradePhase(), movement.getTradePhase(),
movement.getQuantity())]) movement.getQuantity())])
...@@ -263,16 +263,16 @@ class TestMRPImplementation(TestMRPMixin, ERP5TypeTestCase): ...@@ -263,16 +263,16 @@ class TestMRPImplementation(TestMRPMixin, ERP5TypeTestCase):
# assertion # assertion
expected_value_set = set([ expected_value_set = set([
('business_process_module/2/p2', 'product_module/2', 'mrp/p2', 30), (('business_process_module/2/p2',), 'product_module/2', 'mrp/p2', 30),
('business_process_module/2/p2', 'product_module/3', 'mrp/p2', 10), (('business_process_module/2/p2',), 'product_module/3', 'mrp/p2', 10),
('business_process_module/2/p3', 'product_module/4', 'mrp/p3', 40), (('business_process_module/2/p3',), 'product_module/4', 'mrp/p3', 40),
('business_process_module/2/p3', 'product_module/5', 'mrp/p3', 10), (('business_process_module/2/p3',), 'product_module/5', 'mrp/p3', 10),
(None, 'product_module/1', None, -10)]) (('business_process_module/2/p2', 'business_process_module/2/p3'), 'product_module/1', None, -10)])
movement_list = applied_rule.objectValues() movement_list = applied_rule.objectValues()
self.assertEquals(len(expected_value_set), len(movement_list)) self.assertEquals(len(expected_value_set), len(movement_list))
movement_value_set = set([]) movement_value_set = set([])
for movement in movement_list: for movement in movement_list:
movement_value_set |= set([(movement.getCausality(), movement_value_set |= set([(tuple(movement.getCausalityList()),
movement.getResource(), movement.getResource(),
movement.getTradePhase(), movement.getTradePhase(),
movement.getQuantity())]) movement.getQuantity())])
......
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