import warnings from Products.ERP5.mixin import composition from Products.ERP5.ERP5Site import ERP5Site def patch(): from AccessControl.PermissionRole import PermissionRole from Products.ERP5Type import Permissions def declareProtected(cls, permission, *name_list): roles = PermissionRole(permission) for name in name_list: setattr(cls, name + '__roles__', roles) ## ERP5Site declareProtected(ERP5Site, Permissions.AccessContentsInformation, 'getPortalBusinessStateTypeList', 'getPortalBusinessPathTypeList') def getPortalBusinessStateTypeList(self): """ Return business state types. """ return ('Business State',) ERP5Site.getPortalBusinessStateTypeList = getPortalBusinessStateTypeList def getPortalBusinessPathTypeList(self): """ Return business path types. """ return ('Business Path',) ERP5Site.getPortalBusinessPathTypeList = getPortalBusinessPathTypeList ## AmountGeneratorMixin class true: def __nonzero__(self): warnings.warn("Default value for 'generate_empty_amounts' parameter" " is False for new simulation", DeprecationWarning) return True true = true() from Products.ERP5.mixin.amount_generator import AmountGeneratorMixin for method_id in ('getAggregatedAmountList',): # getGeneratedAmountList m = getattr(AmountGeneratorMixin, method_id) f = m.im_func f = type(f)(f.func_code, f.func_globals, f.func_name, f.func_defaults[:3] + (true,), f.func_closure) m = type(m)(f, None, AmountGeneratorMixin) setattr(AmountGeneratorMixin, method_id, m) ## CompositionMixin composition._LEGACY_SIMULATION = True ## Movement from Products.ERP5.Document.Movement import Movement def isFrozen(self): """ Returns the frozen status of this movement. a movement in stopped, delivered or cancelled states is automatically frozen. If frozen is locally set to '0', we must check for a parent set to '1', in which case, we want the children to be frozen as well. BPM evaluation allows to set frozen state list per Business Path. """ business_path = self.getCausalityValue(portal_type='Business Path') if business_path is None: # XXX Hardcoded # Maybe, we should use getPortalCurrentInventoryStateList # and another portal method for cancelled (and deleted) # LOG("Movement, isFrozen", DEBUG, "Hardcoded state list") if self.getSimulationState() in ('stopped', 'delivered', 'cancelled'): return 1 else: # conditional BPM enabled frozen state check # BPM dynamic configuration if self.getSimulationState() in business_path.getFrozenStateList(): return True # manually frozen frozen = self._baseIsFrozen() if frozen == 0: self._baseSetFrozen(None) return frozen or False Movement.isFrozen = isFrozen ## SimulationMovement from Products.ERP5.Document.SimulationMovement import SimulationMovement try: del SimulationMovement.isFrozen except AttributeError: pass def isCompleted(self): """Zope publisher docstring. Documentation in ISimulationMovement""" # only available in BPM, so fail totally in case of working without BPM return self.getSimulationState() in self.getCausalityValue( portal_type='Business Path').getCompletedStateList() SimulationMovement.isCompleted = isCompleted def asComposedDocument(self, *args, **kw): # XXX: What delivery should be used to find amount generator lines ? # With the currently enabled code, entire branches in the simulation # tree get (temporary) deleted when new delivery lines are being built # (and don't have yet a specialise value). # With the commented code, changing the STC on a SIT generated from a # SPL/SO would have no impact (and would never make the SIT divergent). #return self.getRootSimulationMovement() \ # .getDeliveryValue() \ # .asComposedDocument(*args, **kw) while 1: delivery_value = self.getDeliveryValue() if delivery_value is not None: return delivery_value.asComposedDocument(*args, **kw) # below code is for compatibility with old rules grand_parent = self.getParentValue().getParentValue() if grand_parent.getPortalType() == 'Simulation Tool': return self.getOrderValue().asComposedDocument(*args, **kw) self = grand_parent SimulationMovement.asComposedDocument = asComposedDocument def isBuildable(self): """Simulation Movement buildable logic""" if self.getDeliveryValue() is not None: # already delivered return False # might be buildable - business path dependent business_path = self.getCausalityValue(portal_type='Business Path') explanation_value = self.getExplanationValue() if business_path is None or explanation_value is None: return True return len(business_path.filterBuildableMovementList([self])) == 1 SimulationMovement.isBuildable = isBuildable def _getApplicableRuleList(self): """ Search rules that match this movement, but don't try to look up successor trade_phases """ portal_rules = self.getPortalObject().portal_rules return portal_rules.searchRuleList(self, sort_on='version', sort_order='descending') SimulationMovement._getApplicableRuleList = _getApplicableRuleList patch()