Commit 6c718d67 authored by Łukasz Nowak's avatar Łukasz Nowak

- merge BPMDeliveryRule and BPMPOrderRule common parts

 - provide new experimental, private methods in order to minimize code duplication between rules
 - simplify and unhardcode


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@28139 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 815e33a7
......@@ -48,110 +48,42 @@ class BPMDeliveryRule(BPMRule):
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Default Properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore
, PropertySheet.Task
, PropertySheet.AppliedRule
)
def _getInputMovementList(self, applied_rule):
"""Returns list of input movements for applied rule"""
order = applied_rule.getDefaultCausalityValue()
if order is not None:
return order.getMovementList(
portal_type=order.getPortalDeliveryMovementTypeList())
return []
def _getExpandablePropertyUpdateDict(self, applied_rule, movement, business_path,
**kw):
return {
'order_value': movement,
'delivery_value': movement,
'order_ratio': 1,
'delivery_ratio': 1,
'deliverable': 1,
}
# Simulation workflow
security.declareProtected(Permissions.ModifyPortalContent, 'expand')
def expand(self, applied_rule, delivery_movement_type_list=None, **kw):
"""
Expands the additional Delivery movements to a new simulation tree.
Expand is only allowed to create or modify simulation movements for
delivery lines which are not already linked to another simulation
movement.
def expand(self, applied_rule, force=0, **kw):
add_list, modify_dict, \
delete_list = self._getCompensatedMovementList(applied_rule, **kw)
If the movement is not in current state, has no delivered child, and not
in delivery movements, it can be deleted.
Else if the movement is not in current state, it can be modified.
Else, it cannot be modified.
"""
existing_movement_list = []
immutable_movement_list = []
delivery = applied_rule.getDefaultCausalityValue()
if delivery_movement_type_list is None:
delivery_movement_type_list = self.getPortalDeliveryMovementTypeList()
if delivery is not None:
delivery_movement_list = delivery.getMovementList(
portal_type=delivery_movement_type_list)
# Check existing movements
for movement in applied_rule.contentValues(
portal_type=self.movement_type):
if not movement.isFrozen():
movement_delivery = movement.getDeliveryValue()
if not movement._isTreeDelivered(ignore_first=1) and \
movement_delivery not in delivery_movement_list:
applied_rule._delObject(movement.getId())
else:
existing_movement_list.append(movement)
else:
existing_movement_list.append(movement)
immutable_movement_list.append(movement)
# delete not needed movements
for movement_id in delete_list:
applied_rule._delObject(movement_id)
# Create or modify movements
for deliv_mvt in delivery_movement_list:
sim_mvt = deliv_mvt.getDeliveryRelatedValue()
if sim_mvt is None:
# create a new deliv_mvt
if deliv_mvt.getParentUid() == deliv_mvt.getExplanationUid():
# We are on a line
new_id = deliv_mvt.getId()
else:
# We are on a cell
new_id = "%s_%s" % (deliv_mvt.getParentId(), deliv_mvt.getId())
# Generate the simulation deliv_mvt
property_dict = self.self._getExpandablePropertyDict(applied_rule,
deliv_mvt)
new_sim_mvt = applied_rule.newContent(
portal_type=self.movement_type,
id=new_id,
order_value=deliv_mvt,
order_ratio=1,
delivery_value=deliv_mvt,
delivery_ratio=1,
deliverable=1,
# update existing
for movement, property_dict in modify_dict.items():
applied_rule[movement].edit(**property_dict)
**property_dict
)
elif sim_mvt in existing_movement_list:
if sim_mvt not in immutable_movement_list:
# modification allowed
# XXX Hardcoded value
sim_mvt.edit(
delivery_value=deliv_mvt,
delivery_ratio=1,
deliverable=1,
force_update=1,
**property_dict
)
else:
# modification disallowed, must compensate
raise NotImplementedError('BPM *have* to support')
# add new ones
for movement_dict in add_list:
movement_id = applied_rule._get_id(movement_dict.pop('id', None))
new_movement = applied_rule.newContent(id=movement_id,
portal_type=self.movement_type, **movement_dict)
# Now we can set the last expand simulation state to the current state
applied_rule.setLastExpandSimulationState(delivery.getSimulationState())
# Pass to base class
BPMRule.expand(self, applied_rule, **kw)
security.declareProtected(Permissions.AccessContentsInformation, 'isStable')
def isStable(self, applied_rule):
"""
Checks that the applied_rule is stable
"""
return 0
# Deliverability / orderability
def isOrderable(self, movement):
return 1
def isDeliverable(self, movement):
if movement.getSimulationState() in movement \
.getPortalDraftOrderStateList():
return 0
return 1
BPMRule.expand(self, applied_rule, force=force, **kw) # Simulation workflow
......@@ -44,23 +44,11 @@ class BPMInvoicingRule(BPMRule):
# CMF Type Definition
meta_type = 'ERP5 BPM Invoicing Rule'
portal_type = 'BPM Invoicing Rule'
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Default Properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore
, PropertySheet.Task
, PropertySheet.AppliedRule
)
security.declareProtected(Permissions.AccessContentsInformation,
'isAccountable')
def isAccountable(self, movement):
......@@ -73,13 +61,11 @@ class BPMInvoicingRule(BPMRule):
return 0
#### Helper methods for expand
def _generatePrevisionList(self, applied_rule, **kw):
return_list = []
for prevision_dict in BPMRule._generatePrevisionList(self, applied_rule,
**kw):
prevision_dict['deliverable'] = 1
return_list.append(prevision_dict)
return return_list
def _getExpandablePropertyUpdateDict(self, applied_rule, movement, business_path,
**kw):
return {
'deliverable': 1
}
security.declareProtected(Permissions.ModifyPortalContent, 'expand')
def expand(self, applied_rule, force=0, **kw):
......@@ -94,27 +80,30 @@ class BPMInvoicingRule(BPMRule):
"""
parent_movement = applied_rule.getParentValue()
if parent_movement is not None:
if not parent_movement.isFrozen():
add_list, modify_dict, \
delete_list = self._getCompensatedMovementList(applied_rule, **kw)
for movement_id in delete_list:
applied_rule._delObject(movement_id)
add_list, modify_dict, \
delete_list = self._getCompensatedMovementList(applied_rule, **kw)
for movement_id in delete_list:
applied_rule._delObject(movement_id)
for movement, prop_dict in modify_dict.items():
applied_rule[movement].edit(**prop_dict)
for movement, prop_dict in modify_dict.items():
applied_rule[movement].edit(**prop_dict)
for movement_dict in add_list:
if 'id' in movement_dict.keys():
mvmt_id = applied_rule._get_id(movement_dict.pop('id'))
new_mvmt = applied_rule.newContent(id=mvmt_id,
portal_type=self.movement_type)
else:
new_mvmt = applied_rule.newContent(portal_type=self.movement_type)
new_mvmt.edit(**movement_dict)
for movement_dict in add_list:
if 'id' in movement_dict.keys():
mvmt_id = applied_rule._get_id(movement_dict.pop('id'))
new_mvmt = applied_rule.newContent(id=mvmt_id,
portal_type=self.movement_type)
else:
new_mvmt = applied_rule.newContent(portal_type=self.movement_type)
new_mvmt.edit(**movement_dict)
# Pass to base class
BPMRule.expand(self, applied_rule, force=force, **kw)
def _getInputMovementList(self, applied_rule):
"""Returns list of input movements for applied rule"""
return [applied_rule.getParentValue()]
def isDeliverable(self, movement):
return movement.getResource() is not None
......@@ -30,10 +30,8 @@
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5.Document.BPMRule import BPMRule
from Products.ERP5Type import Permissions
from Products.ERP5.Document.BPMDeliveryRule import BPMDeliveryRule
from zLOG import LOG, WARNING
class BPMOrderRule(BPMDeliveryRule):
"""
......@@ -49,117 +47,19 @@ class BPMOrderRule(BPMDeliveryRule):
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Default Properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore
, PropertySheet.Task
, PropertySheet.AppliedRule
)
# Simulation workflow
security.declareProtected(Permissions.ModifyPortalContent, 'expand')
def expand(self, applied_rule, force=0, **kw):
"""
Expands the Order to a new simulation tree.
expand is only allowed to modify a simulation movement if it doesn't
have a delivery relation yet.
If the movement is in ordered or planned state, has no delivered
child, and is not in order, it can be deleted.
Else, if the movement is in ordered or planned state, has no
delivered child, and is in order, it can be modified.
Else, it cannot be modified.
"""
existing_movement_list = []
immutable_movement_list = []
def _getInputMovementList(self, applied_rule):
"""Returns list of input movements for applied rule"""
order = applied_rule.getDefaultCausalityValue()
business_process = applied_rule.getBusinessProcessValue()
if order is not None:
order_movement_list = order.getMovementList(
return order.getMovementList(
portal_type=order.getPortalOrderMovementTypeList())
# check existing movements
for simulation_movement in applied_rule.contentValues(
portal_type=self.movement_type):
if not simulation_movement.isFrozen():
movement_order = simulation_movement.getOrderValue()
if movement_order in order_movement_list:
existing_movement_list.append(simulation_movement)
else:
applied_rule._delObject(simulation_movement.getId())
else:
existing_movement_list.append(simulation_movement)
immutable_movement_list.append(simulation_movement)
# this dict simulates getOrderRelatedValue, but it will not work if an
# order was generated from multiple applied rules
order_movement_dict = {}
for s_m in applied_rule.objectValues():
order_movement = s_m.getOrderValue()
if order_movement is not None:
order_movement_dict[order_movement.getPath()] = s_m
# Create or modify movements
for order_movement in order_movement_list:
related_order = order_movement_dict.get(order_movement.getPath(),
None)
if related_order is None:
related_order = order_movement.getOrderRelatedValue()
movement_and_path_list = []
for business_path in business_process.getPathValueList(
self.getProperty('trade_phase_list'),
order_movement):
movement_and_path_list.append((order_movement, business_path))
if len(movement_and_path_list) > 1:
raise NotImplementedError
for movement, business_path in movement_and_path_list:
property_dict = self._getExpandablePropertyDict(
applied_rule, movement,
business_path)
property_dict.update(order_value=order_movement)
if related_order is None:
# Generate a simulation movement
# Do not try to create meaningfull IDs, as order movement can be
# hierarchical
applied_rule.newContent(
portal_type=self.movement_type,
order_ratio=1,
delivery_ratio=1,
deliverable=1,
**property_dict)
elif related_order in existing_movement_list:
if related_order not in immutable_movement_list:
# modification allowed
related_order.edit(
**property_dict)
else:
# modification disallowed, must compensate
raise NotImplementedError('BPM *have* to support compensation')
# Now we can set the last expand simulation state to the current
# state
applied_rule.setLastExpandSimulationState(
order.getSimulationState())
# Pass to base class
BPMRule.expand(self, applied_rule, force=force, **kw)
security.declareProtected(Permissions.AccessContentsInformation, 'isStable')
def isStable(self, applied_rule):
"""
Checks that the applied_rule is stable
"""
LOG('OrderRule.isStable', WARNING, 'Not Implemented')
return 1
security.declareProtected(Permissions.AccessContentsInformation,
'isDivergent')
def isDivergent(self, movement):
"""
Checks that the movement is divergent
"""
return BPMRule.isDivergent(self, movement)
return []
def _getExpandablePropertyUpdateDict(self, applied_rule, movement, business_path,
**kw):
return {
'order_value': movement,
'order_ratio': 1,
'delivery_ratio': 1,
'deliverable': 1,
}
......@@ -69,6 +69,7 @@ class BPMRule(Rule):
, PropertySheet.Predicate
, PropertySheet.Reference
, PropertySheet.Version
, PropertySheet.AppliedRule
)
#### Helpers
......@@ -198,8 +199,6 @@ class BPMRule(Rule):
movement.getRelativeUrl())
return (add_list, modify_dict, delete_list)
security.declareProtected(Permissions.AccessContentsInformation,
'_getExpandablePropertyDict')
def _getExpandablePropertyDict(self, applied_rule, movement, business_path,
**kw):
"""
......@@ -238,33 +237,40 @@ class BPMRule(Rule):
property_dict['start_date'] = movement.getStartDate()
property_dict['stop_date'] = movement.getStopDate()
# save a relation to supply path for builders XXX which category
# save a relation to business path
property_dict['causality_value'] = business_path
# rule specific
property_dict.update(**self._getExpandablePropertyUpdateDict(applied_rule,
movement, business_path, **kw))
return property_dict
def _generatePrevisionList(self, applied_rule, **kw):
"""
Generate a list of movements, that should be children of this rule,
Generate a list of dictionaries, that contain calculated content of
current Simulation Movements in applied rule.
based on its context (parent movement, delivery, configuration ...)
These previsions are returned as dictionaries.
"""
# XXX support list of movements
context_movement = applied_rule.getParentValue()
input_movement_list = self._getInputMovementList(applied_rule)
business_process = applied_rule.getBusinessProcessValue()
movement_and_path_list = []
for business_path in business_process.getPathValueList(
self.getProperty('trade_phase_list'),
context_movement):
movement_and_path_list.append((context_movement, business_path))
if len(movement_and_path_list) > 1:
input_movement_and_path_list = []
business_path_list = []
for input_movement in input_movement_list:
for business_path in business_process.getPathValueList(
self.getProperty('trade_phase_list'),
input_movement):
input_movement_and_path_list.append((input_movement, business_path))
business_path not in business_path_list and business_path_list \
.append(business_path)
if len(business_path_list) > 1:
raise NotImplementedError
for movement, business_path in movement_and_path_list:
property_dict = self._getExpandablePropertyDict(
applied_rule, movement, business_path)
property_dict['deliverable'] = 1
return [property_dict]
prevision_dict_list = []
for input_movement, business_path in input_movement_and_path_list:
prevision_dict_list.append(self._getExpandablePropertyDict(applied_rule,
input_movement, business_path))
return prevision_dict_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