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): ...@@ -48,110 +48,42 @@ class BPMDeliveryRule(BPMRule):
security = ClassSecurityInfo() security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation) security.declareObjectProtected(Permissions.AccessContentsInformation)
# Default Properties def _getInputMovementList(self, applied_rule):
property_sheets = ( PropertySheet.Base """Returns list of input movements for applied rule"""
, PropertySheet.XMLObject order = applied_rule.getDefaultCausalityValue()
, PropertySheet.CategoryCore if order is not None:
, PropertySheet.DublinCore return order.getMovementList(
, PropertySheet.Task portal_type=order.getPortalDeliveryMovementTypeList())
, PropertySheet.AppliedRule 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') security.declareProtected(Permissions.ModifyPortalContent, 'expand')
def expand(self, applied_rule, delivery_movement_type_list=None, **kw): def expand(self, applied_rule, force=0, **kw):
""" add_list, modify_dict, \
Expands the additional Delivery movements to a new simulation tree. delete_list = self._getCompensatedMovementList(applied_rule, **kw)
Expand is only allowed to create or modify simulation movements for
delivery lines which are not already linked to another simulation
movement.
If the movement is not in current state, has no delivered child, and not # delete not needed movements
in delivery movements, it can be deleted. for movement_id in delete_list:
Else if the movement is not in current state, it can be modified. applied_rule._delObject(movement_id)
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)
# Create or modify movements # update existing
for deliv_mvt in delivery_movement_list: for movement, property_dict in modify_dict.items():
sim_mvt = deliv_mvt.getDeliveryRelatedValue() applied_rule[movement].edit(**property_dict)
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,
**property_dict # add new ones
) for movement_dict in add_list:
elif sim_mvt in existing_movement_list: movement_id = applied_rule._get_id(movement_dict.pop('id', None))
if sim_mvt not in immutable_movement_list: new_movement = applied_rule.newContent(id=movement_id,
# modification allowed portal_type=self.movement_type, **movement_dict)
# 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')
# Now we can set the last expand simulation state to the current state
applied_rule.setLastExpandSimulationState(delivery.getSimulationState())
# Pass to base class # Pass to base class
BPMRule.expand(self, applied_rule, **kw) BPMRule.expand(self, applied_rule, force=force, **kw) # Simulation workflow
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
...@@ -44,23 +44,11 @@ class BPMInvoicingRule(BPMRule): ...@@ -44,23 +44,11 @@ class BPMInvoicingRule(BPMRule):
# CMF Type Definition # CMF Type Definition
meta_type = 'ERP5 BPM Invoicing Rule' meta_type = 'ERP5 BPM Invoicing Rule'
portal_type = 'BPM Invoicing Rule' portal_type = 'BPM Invoicing Rule'
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
# Declarative security # Declarative security
security = ClassSecurityInfo() security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation) security.declareObjectProtected(Permissions.AccessContentsInformation)
# Default Properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore
, PropertySheet.Task
, PropertySheet.AppliedRule
)
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'isAccountable') 'isAccountable')
def isAccountable(self, movement): def isAccountable(self, movement):
...@@ -73,13 +61,11 @@ class BPMInvoicingRule(BPMRule): ...@@ -73,13 +61,11 @@ class BPMInvoicingRule(BPMRule):
return 0 return 0
#### Helper methods for expand #### Helper methods for expand
def _generatePrevisionList(self, applied_rule, **kw): def _getExpandablePropertyUpdateDict(self, applied_rule, movement, business_path,
return_list = []
for prevision_dict in BPMRule._generatePrevisionList(self, applied_rule,
**kw): **kw):
prevision_dict['deliverable'] = 1 return {
return_list.append(prevision_dict) 'deliverable': 1
return return_list }
security.declareProtected(Permissions.ModifyPortalContent, 'expand') security.declareProtected(Permissions.ModifyPortalContent, 'expand')
def expand(self, applied_rule, force=0, **kw): def expand(self, applied_rule, force=0, **kw):
...@@ -94,7 +80,6 @@ class BPMInvoicingRule(BPMRule): ...@@ -94,7 +80,6 @@ class BPMInvoicingRule(BPMRule):
""" """
parent_movement = applied_rule.getParentValue() parent_movement = applied_rule.getParentValue()
if parent_movement is not None: if parent_movement is not None:
if not parent_movement.isFrozen():
add_list, modify_dict, \ add_list, modify_dict, \
delete_list = self._getCompensatedMovementList(applied_rule, **kw) delete_list = self._getCompensatedMovementList(applied_rule, **kw)
for movement_id in delete_list: for movement_id in delete_list:
...@@ -115,6 +100,10 @@ class BPMInvoicingRule(BPMRule): ...@@ -115,6 +100,10 @@ class BPMInvoicingRule(BPMRule):
# Pass to base class # Pass to base class
BPMRule.expand(self, applied_rule, force=force, **kw) 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): def isDeliverable(self, movement):
return movement.getResource() is not None return movement.getResource() is not None
...@@ -30,10 +30,8 @@ ...@@ -30,10 +30,8 @@
############################################################################## ##############################################################################
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet from Products.ERP5Type import Permissions
from Products.ERP5.Document.BPMRule import BPMRule
from Products.ERP5.Document.BPMDeliveryRule import BPMDeliveryRule from Products.ERP5.Document.BPMDeliveryRule import BPMDeliveryRule
from zLOG import LOG, WARNING
class BPMOrderRule(BPMDeliveryRule): class BPMOrderRule(BPMDeliveryRule):
""" """
...@@ -49,117 +47,19 @@ class BPMOrderRule(BPMDeliveryRule): ...@@ -49,117 +47,19 @@ class BPMOrderRule(BPMDeliveryRule):
security = ClassSecurityInfo() security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation) security.declareObjectProtected(Permissions.AccessContentsInformation)
# Default Properties def _getInputMovementList(self, applied_rule):
property_sheets = ( PropertySheet.Base """Returns list of input movements for applied rule"""
, 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 = []
order = applied_rule.getDefaultCausalityValue() order = applied_rule.getDefaultCausalityValue()
business_process = applied_rule.getBusinessProcessValue()
if order is not None: if order is not None:
order_movement_list = order.getMovementList( return order.getMovementList(
portal_type=order.getPortalOrderMovementTypeList()) portal_type=order.getPortalOrderMovementTypeList())
# check existing movements return []
for simulation_movement in applied_rule.contentValues(
portal_type=self.movement_type): def _getExpandablePropertyUpdateDict(self, applied_rule, movement, business_path,
if not simulation_movement.isFrozen(): **kw):
movement_order = simulation_movement.getOrderValue() return {
if movement_order in order_movement_list: 'order_value': movement,
existing_movement_list.append(simulation_movement) 'order_ratio': 1,
else: 'delivery_ratio': 1,
applied_rule._delObject(simulation_movement.getId()) 'deliverable': 1,
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)
...@@ -69,6 +69,7 @@ class BPMRule(Rule): ...@@ -69,6 +69,7 @@ class BPMRule(Rule):
, PropertySheet.Predicate , PropertySheet.Predicate
, PropertySheet.Reference , PropertySheet.Reference
, PropertySheet.Version , PropertySheet.Version
, PropertySheet.AppliedRule
) )
#### Helpers #### Helpers
...@@ -198,8 +199,6 @@ class BPMRule(Rule): ...@@ -198,8 +199,6 @@ class BPMRule(Rule):
movement.getRelativeUrl()) movement.getRelativeUrl())
return (add_list, modify_dict, delete_list) return (add_list, modify_dict, delete_list)
security.declareProtected(Permissions.AccessContentsInformation,
'_getExpandablePropertyDict')
def _getExpandablePropertyDict(self, applied_rule, movement, business_path, def _getExpandablePropertyDict(self, applied_rule, movement, business_path,
**kw): **kw):
""" """
...@@ -238,33 +237,40 @@ class BPMRule(Rule): ...@@ -238,33 +237,40 @@ class BPMRule(Rule):
property_dict['start_date'] = movement.getStartDate() property_dict['start_date'] = movement.getStartDate()
property_dict['stop_date'] = movement.getStopDate() 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 property_dict['causality_value'] = business_path
# rule specific
property_dict.update(**self._getExpandablePropertyUpdateDict(applied_rule,
movement, business_path, **kw))
return property_dict return property_dict
def _generatePrevisionList(self, applied_rule, **kw): 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 ...) based on its context (parent movement, delivery, configuration ...)
These previsions are returned as dictionaries. These previsions are returned as dictionaries.
""" """
# XXX support list of movements input_movement_list = self._getInputMovementList(applied_rule)
context_movement = applied_rule.getParentValue()
business_process = applied_rule.getBusinessProcessValue() business_process = applied_rule.getBusinessProcessValue()
movement_and_path_list = [] input_movement_and_path_list = []
business_path_list = []
for input_movement in input_movement_list:
for business_path in business_process.getPathValueList( for business_path in business_process.getPathValueList(
self.getProperty('trade_phase_list'), self.getProperty('trade_phase_list'),
context_movement): input_movement):
movement_and_path_list.append((context_movement, business_path)) 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(movement_and_path_list) > 1: if len(business_path_list) > 1:
raise NotImplementedError raise NotImplementedError
for movement, business_path in movement_and_path_list: prevision_dict_list = []
property_dict = self._getExpandablePropertyDict( for input_movement, business_path in input_movement_and_path_list:
applied_rule, movement, business_path) prevision_dict_list.append(self._getExpandablePropertyDict(applied_rule,
property_dict['deliverable'] = 1 input_movement, business_path))
return [property_dict] 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