Commit 5c09e2e2 authored by Julien Muchembled's avatar Julien Muchembled

Simulation: splitted expand, performance improvements and bugfixes

All interactions and activity tags are reviewed to fix bugs like duplicated
root applied rules, and also reduces the amount of duplicated/useless work, e.g:
- Simulation trees are not expanded anymore when simulated objects are modified.
- 'expand' activities are merged (i.e. dropped) with any other 'expand' activity
  for an ancestor.
New implementation exposes new API that hides much complexity to the developper
about activity dependencies.

By default, expand() now automatically defers any work if the current
transaction takes too long time. This method also gains a parameter to
explicitely choose when to expand, which is often important in unit tests or
solvers. In particular, when postponing work, it takes care of setting proper
activity dependencies.
- If you have any code requiring to expand everything immediately, you'll have
  to replace 'expand()' by 'expand(expand_policy="immediate")'.
- On the contrary, you should replace any 'activate().expand()' by
  'expand(expand_policy="deferred")'.
expand() still accepts activity parameters for any extra needs.

In causality workflow, 'building' state is clarified and now means
« delivery may diverge but we can't know now ». A delivery remains in draft
as long as it does not contain any movement built from simulation.
After init/clone/builder/etc. scripts used to call 'startBuilding' &
'updateCausalityState': this calls must be removed since only
SimulatedDeliveryBuilder should take care of move to 'building' state and
workflows now triggers 'updateCausalityState'.

Disguised interactions have been unhardcoded and either deleted, or moved to
appropriate interaction workflows, which have been reorganized. Those
that triggers update of portal_workflow can be easily customized or disabled.

New API:
- updateSimulation() on deliveries and subscription items. It takes care of
  creating root applied rule, expanding and reindexing parts of simulation
  trees. It somehow replaces:
  - Delivery_updateSimulation
  - Delivery_updateAppliedRule
  - Delivery.applyToDeliveryRelatedMovement
  - Delivery.updateAppliedRule
  - Delivery.expand
  - Delivery.expandRuleRelatedToMovement
  - SubscriptionItem.expand
  - SubscriptionItem.updateAppliedRule
- Delivery.localBuild() is the new way to do local building and replaces
  Delivery_expandAndBuild. Private method Delivery._localBuild replaces
  Delivery_buildOnComposedDocument.
- Simulation Movements that are being built by a builder are reindexed with
  the following tag: 'built:<delivery_path>'. Any after_path_and_method_id
  dependency against 'related_simulation_movement_path_list' and reindexing
  methods should be replaced by this after_tag.

After builder scripts used to confirm the delivery in a separate activity,
which was useless.
parent fb246bec
......@@ -56,11 +56,6 @@ context.setSourceReference(None)\n
context.setReference(None)\n
context.setDestinationReference(None)\n
context.setSolver(None)\n
\n
# Initialize Causality Workflow\n
if hasattr(context, \'startBuilding\'):\n
context.startBuilding()\n
context.updateCausalityState()\n
</string> </value>
</item>
<item>
......
......@@ -59,7 +59,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>AccountingRuleCell_getRuleReference</string> </value>
<value> <string>AccountingTransaction_getRuleReference</string> </value>
</item>
</dictionary>
</pickle>
......
......@@ -50,23 +50,15 @@
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>from Products.CMFCore.utils import getToolByName\n
\n
transaction = context\n
preference_tool = getToolByName(context, \'portal_preferences\')\n
\n
transaction.edit (\n
<value> <string>preference_tool = context.getPortalObject().portal_preferences\n
context.edit(\n
source_section = preference_tool.getPreferredAccountingTransactionSourceSection(),\n
resource = preference_tool.getPreferredAccountingTransactionCurrency())\n
\n
if hasattr(transaction, \'startBuilding\') :\n
transaction.startBuilding()\n
transaction.updateCausalityState()\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>*args, **kw</string> </value>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
......
......@@ -59,7 +59,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>SaleInvoiceTransaction_getRuleReference</string> </value>
<value> <string>Invoice_getRuleReference</string> </value>
</item>
</dictionary>
</pickle>
......
......@@ -57,13 +57,6 @@ payment_transaction = context\n
# initialize accounting_workflow to planned state\n
if payment_transaction.getSimulationState() == "draft":\n
payment_transaction.plan(comment=translateString("Initialised by Delivery Builder."))\n
\n
# First set the payment transaction in the building state on the causality workflow\n
payment_transaction.startBuilding()\n
\n
# Then an activity should put the causality state in diverged or solved\n
payment_transaction.activate(after_path_and_method_id=(related_simulation_movement_path_list,\n
(\'immediateReindexObject\',\'recursiveImmediateReindexObject\'))).updateCausalityState()\n
</string> </value>
</item>
<item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>return \'default_invoice_rule\'\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>PurchaseInvoiceTransaction_getRuleReference</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>delivery = state_change[\'object\']\n
delivery.Delivery_expandAndBuild()\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>state_change</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Delivery_Build</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -50,7 +50,7 @@
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>state_change[\'object\'].Delivery_updateSimulation()\n
<value> <string>state_change[\'object\'].localBuild()\n
</string> </value>
</item>
<item>
......@@ -59,7 +59,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Delivery_createRule</string> </value>
<value> <string>Delivery_localBuild</string> </value>
</item>
</dictionary>
</pickle>
......
......@@ -24,7 +24,7 @@
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string>Delivery_Build</string> </value>
<value> <string>Delivery_localBuild</string> </value>
</item>
<item>
<key> <string>description</string> </key>
......
......@@ -10,6 +10,10 @@
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
......@@ -20,7 +24,7 @@
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string>Delivery_updateSimulation</string> </value>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
......
......@@ -10,6 +10,10 @@
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
......@@ -20,7 +24,7 @@
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string>Delivery_Build</string> </value>
<value> <string>Delivery_localBuild</string> </value>
</item>
<item>
<key> <string>description</string> </key>
......
......@@ -37,6 +37,7 @@
<key> <string>tested_property</string> </key>
<value>
<tuple>
<string>specialise</string>
<string>source_section</string>
<string>destination_section</string>
<string>source_payment</string>
......
......@@ -37,6 +37,7 @@
<key> <string>tested_property</string> </key>
<value>
<tuple>
<string>specialise</string>
<string>source_section</string>
<string>destination_section</string>
<string>source_payment</string>
......
......@@ -71,9 +71,11 @@ for builder_id in builder_id_list:\n
serialization_tag = \'build:%s\' % delivery_portal_type\n
index_tag = \'index:%s\' % delivery_portal_type\n
after_tag = index_tag\n
# depend on reindexing so that select methods\n
# do not return movements that are already built\n
after_method_id = (\'recursiveImmediateReindexObject\',\n
\'immediateReindexObject\',\n
\'Delivery_updateAppliedRule\')\n
\'_updateSimulation\')\n
activate_kw = dict(tag=index_tag)\n
builder.activate(\n
serialization_tag=serialization_tag,\n
......
......@@ -54,14 +54,6 @@
the new Invoice.\n
"""\n
from Products.ERP5Type.Message import translateString\n
try:\n
from Products.CMFCore.WorkflowCore import WorkflowException\n
except ImportError:\n
# WorkflowException has not always been allowed in restricted\n
# environment, in this case, make sure WorkflowException is \n
# defined \n
class WorkflowException(Exception):\n
pass\n
\n
if related_simulation_movement_path_list is None:\n
raise RuntimeError, \'related_simulation_movement_path_list is missing. Update ERP5 Product.\'\n
......@@ -80,26 +72,10 @@ if not invoice.hasTitle() and related_packing_list.hasTitle():\n
\n
# initialize accounting_workflow to confirmed state\n
if invoice.getSimulationState() == \'draft\':\n
try :\n
context.getPortalObject().portal_workflow.doActionFor(\n
invoice, \'confirm_action\',\n
comment=translateString(\'Initialised by Delivery Builder.\'),\n
skip_period_validation=1)\n
except WorkflowException, e:\n
# The user cannot pass the transition, it\'s OK\n
pass\n
\n
if invoice.getSimulationState() == \'draft\':\n
# call the workflow method, if the user cannot perform this operation.\n
invoice.confirm(comment=translateString(\'Initialised by Delivery Builder.\'),)\n
\n
\n
# First set the invoice in the building state on the causality workflow\n
invoice.startBuilding()\n
\n
# Then an activity should put the causality state in diverged or solved\n
invoice.activate(after_path_and_method_id=(related_simulation_movement_path_list,\n
(\'immediateReindexObject\',\'recursiveImmediateReindexObject\'))).updateCausalityState()\n
invoice.Delivery_confirm()\n
else:\n
# call builder just same as after script of \'confirm\' transition\n
invoice.localBuild()\n
</string> </value>
</item>
<item>
......
......@@ -50,64 +50,12 @@
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>"""\n
Builds the delivery.\n
"""\n
from Products.ERP5Type.Log import log\n
delivery = sci[\'object\']\n
delivery_portal_type = delivery.getPortalType()\n
portal_deliveries = sci.getPortal().portal_deliveries\n
\n
builder_by_ptype = {\n
\'Sale Invoice\' : \'advanced_sale_invoice_transaction_builder\',\n
\'Purchase Invoice\' : \'advanced_purchase_invoice_transaction_builder\',\n
}\n
\n
if builder_by_ptype.has_key(delivery_portal_type) :\n
builder = getattr(portal_deliveries, builder_by_ptype[delivery_portal_type], None)\n
if builder is None :\n
log(\'erp5_advanced_invoicing\',\n
\'unable to build : no builder in %s\' % builder_by_ptype[delivery_portal_type])\n
return\n
\n
# build accounting lines\n
method_id_list = (\'expand\', \'edit\', \'updateAppliedRule\', \'Delivery_updateAppliedRule\',\n
\'immediateReindexObject\', \'recursiveImmediateReindexObject\')\n
\n
explanation_uid_list = [delivery.getUid(), ]\n
packing_list = delivery.getCausalityValue(\n
portal_type=(\'Sale Packing List\',\n
\'Purchase Packing List\'))\n
if packing_list is not None:\n
explanation_uid_list.append(packing_list.getUid())\n
order = packing_list.getCausalityValue(\n
portal_type=(\'Sale Order\',\n
\'Purchase Order\'))\n
if order is not None:\n
explanation_uid_list.append(order.getUid())\n
\n
\n
tag = \'invoice_transaction_build_%s\' % delivery.getRelativeUrl()\n
builder.activate(\n
activity=\'SQLQueue\',\n
after_method_id=method_id_list,\n
tag=tag,\n
activate_kw=dict(tag=tag)).build(activate_kw=dict(tag=tag),\n
explanation_uid=explanation_uid_list)\n
\n
# build related payment transactions\n
portal_deliveries.payment_transaction_builder.activate(\n
activity=\'SQLQueue\',\n
after_method_id=method_id_list).build(explanation_uid=explanation_uid_list)\n
\n
# set the object in building state.\n
delivery.startBuilding()\n
delivery.activate(after_tag=tag).updateCausalityState()\n
<value> <string>state_change[\'object\'].localBuild()\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>sci</string> </value>
<value> <string>state_change</string> </value>
</item>
<item>
<key> <string>id</string> </key>
......
......@@ -10,6 +10,10 @@
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
......@@ -20,7 +24,7 @@
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string>Delivery_createRule</string> </value>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
......
......@@ -56,7 +56,7 @@ if portal.portal_workflow.isTransitionPossible(context, \'calculate\'):\n
else:\n
# Make sure no other node is moving the delivery\n
# to \'diverged\' or \'solved\' state.\n
context.serialize()\n
context.serializeCausalityState()\n
</string> </value>
</item>
<item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>from Products.ERP5Type.Errors import SimulationError\n
\n
delivery = context\n
delivery_type = context.getPortalType()\n
\n
# XXX The following dict is only for backward compatibility.\n
applied_rule_dict = {\n
\'Pay Sheet Transaction\': \'default_invoice_rule\',\n
\'Payment Transaction\': \'default_invoice_rule\',\n
\n
\'Purchase Packing List\': \'default_delivery_rule\',\n
\'Purchase Invoice Transaction\': \'default_invoice_rule\',\n
\n
\'Sale Order\': \'default_order_rule\',\n
\'Sale Packing List\': \'default_delivery_rule\',\n
\'Sale Invoice Transaction\': \'default_invoice_rule\',\n
\n
\'Internal Packing List\': None,\n
\'Returned Sale Packing List\': None,\n
\n
\'Accounting Rule Cell\': None,\n
\'Accounting Transaction\': None,\n
\'Production Packing List\': None,\n
\'Production Report\': None,\n
\'Pay Sheet Model\': None,\n
\n
\'Amortisation Transaction\' : None,\n
\'Task Report\': \'default_delivery_rule\',\n
}\n
\n
try:\n
applied_rule = delivery.getRuleReference()\n
except SimulationError:\n
marker = []\n
applied_rule = applied_rule_dict.get(delivery_type, marker)\n
if applied_rule is marker:\n
raise\n
\n
if applied_rule is None:\n
# No need to add a rule, but still we need to expand the delivery\n
# if at least one of its movements is simulated.\n
for m in delivery.getMovementList():\n
if m.isSimulated():\n
delivery.activate(activate_kw=activate_kw).expand(**kw)\n
return\n
elif applied_rule:\n
delivery.updateAppliedRule(rule_reference=applied_rule, activate_kw=activate_kw, **kw)\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>activate_kw=None, **kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Delivery_updateAppliedRule</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>delivery = context\n
delivery_path = delivery.getPath()\n
expand_tag = delivery_path + \'_expand\'\n
tag = delivery_path + \'_updateAppliedRule\'\n
\n
priority = 3\n
\n
# These parameters are passed to activate for expand and reindexObject,\n
# so Delivery_updateAppliedRule will wait for the creation and indexing of\n
# Applied Rules and Simulation Movements by another Delivery_updateAppliedRule.\n
# This is required for finding an existing Applied Rule by the catalog, and\n
# avoiding needless conflicts.\n
activate_kw = { \n
\'tag\': expand_tag,\n
\'priority\': priority,\n
}\n
\n
# Serialization is required for avoiding parallel executions of updateAppliedRule\n
# which may generate multiple Root Applied Rules.\n
delivery.activate(\n
after_tag=expand_tag,\n
tag=tag,\n
priority=priority,\n
serialization_tag=tag,\n
).Delivery_updateAppliedRule(activate_kw=activate_kw)\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Delivery_updateSimulation</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -28,7 +28,7 @@
<key> <string>after_script_name</string> </key>
<value>
<list>
<string>Delivery_calculateCausalityState</string>
<string>Delivery_calculate</string>
</list>
</value>
</item>
......
......@@ -59,7 +59,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Delivery_calculateCausalityState</string> </value>
<value> <string>Delivery_calculate</string> </value>
</item>
</dictionary>
</pickle>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>delivery = state_change[\'object\']\n
activate_kw = state_change[\'kwargs\'].get(\'activate_kw\') or {}\n
tag = delivery.getPath() + \'_calculate\'\n
delivery.activate(after_tag=tag, **activate_kw).updateCausalityState()\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>state_change</string> </value>
</item>
<item>
<key> <string>_proxy_roles</string> </key>
<value>
<tuple>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Delivery_afterEdit</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -60,8 +60,6 @@ split_and_defer = 0\n
listbox = state_change[\'kwargs\'].get(\'listbox\')\n
split_movement_list = []\n
if listbox is not None:\n
# Create Delivery Applied Rule (if required)\n
delivery.Delivery_updateAppliedRule()\n
for line in listbox:\n
url = line[\'listbox_key\']\n
choice = line[\'choice\']\n
......
......@@ -57,7 +57,6 @@ divergence_to_adopt_list = state_change[\'kwargs\'].get(\'divergence_to_adopt_li
\n
if len(delivery_solve_property_dict) or len(divergence_to_accept_list) \\\n
or len(divergence_to_adopt_list):\n
delivery.Delivery_updateAppliedRule()\n
delivery_relative_url = delivery.getRelativeUrl()\n
delivery_builder_list = delivery.getBuilderList()\n
if len(delivery_solve_property_dict):\n
......@@ -68,9 +67,6 @@ if len(delivery_solve_property_dict) or len(divergence_to_accept_list) \\\n
delivery_builder.solveDivergence(delivery_relative_url,\n
divergence_to_accept_list=divergence_to_accept_list,\n
divergence_to_adopt_list=divergence_to_adopt_list)\n
# There could be a pending \'Delivery_calculate\' activity if we solved from\n
# \'calculating\' state, so wait that it is gone before updating causality state.\n
delivery.activate(after_tag=delivery.getPath() + \'_calculate\').updateCausalityState()\n
</string> </value>
</item>
<item>
......
......@@ -62,9 +62,6 @@ if not len(split_movement_list):\n
\n
tag = delivery.getPath() + \'_split\'\n
\n
# Create Delivery Applied Rule (if required)\n
delivery.Delivery_updateAppliedRule()\n
\n
for movement in split_movement_list:\n
delivery.getPortalObject().portal_simulation.solveMovement(\n
movement, None, \'SplitAndDefer\', start_date=start_date,\n
......
......@@ -53,12 +53,11 @@
<value> <string>delivery = state_change[\'object\']\n
\n
portal = delivery.getPortalObject()\n
solver_tool = getattr(portal, \'portal_solvers\', None)\n
solver_process_tool = getattr(portal, \'portal_solver_processes\', None)\n
\n
if solver_tool is None or solver_process_tool is None:\n
try:\n
portal.portal_solvers\n
portal.portal_solver_processes\n
except AttributeError:\n
delivery.diverge()\n
return\n
else:\n
solver_tag = \'%s_solve\' % delivery.getPath()\n
delivery.activate(tag=solver_tag).Delivery_solveDivergenceAutomatically()\n
......
......@@ -10,6 +10,10 @@
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
......@@ -20,7 +24,7 @@
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string>Delivery_afterEdit</string> </value>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
......
......@@ -10,6 +10,10 @@
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
......
......@@ -28,7 +28,7 @@
<key> <string>after_script_name</string> </key>
<value>
<list>
<string>DeliveryMovement_calculateCausalityState</string>
<string>DeliveryMovement_calculate</string>
</list>
</value>
</item>
......@@ -56,7 +56,8 @@
<key> <string>method_id</string> </key>
<value>
<list>
<string>_set.*</string>
<string>_set(?!LastId$|Ob$|Object$)</string>
<string>manage_afterAdd</string>
</list>
</value>
</item>
......
......@@ -59,7 +59,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>DeliveryMovement_calculateCausalityState</string> </value>
<value> <string>DeliveryMovement_calculate</string> </value>
</item>
</dictionary>
</pickle>
......
......@@ -40,7 +40,7 @@
</item>
<item>
<key> <string>description</string> </key>
<value> <string>call updateAppliedRule after a modification</string> </value>
<value> <string>Reexpand root applied rule if the setter involves a movement that should be linked to a root simulation movement.</string> </value>
</item>
<item>
<key> <string>guard</string> </key>
......
......@@ -69,6 +69,8 @@ for simulation_movement in simulation_movement_list:\n
# \'order\' category is deprecated. it is kept for compatibility.\n
if simulation_movement.getOrder() == delivery_movement.getRelativeUrl():\n
simulation_movement.setOrder(None)\n
\n
context.DeliveryMovement_updateSimulation(state_change)\n
</string> </value>
</item>
<item>
......
......@@ -50,7 +50,15 @@
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>state_change[\'object\'].getRootDeliveryValue().Delivery_updateSimulation()\n
<value> <string>movement = state_change[\'object\']\n
if not movement.isGeneratedBySimulation():\n
# A setter was called on a movement that should be linked to\n
# a root simulation movement, which usually copies the movement.\n
# If there\'s a new movement in the delivery (e.g. _setObject),\n
# the root applied rule must be reexpanded in order to generate\n
# the missing simulation movement.\n
# XXX: Otherwise, it should be enough to reexpand the related SM.\n
movement.getRootDeliveryValue().updateSimulation(expand_root=1)\n
</string> </value>
</item>
<item>
......
......@@ -28,7 +28,7 @@
<key> <string>after_script_name</string> </key>
<value>
<list>
<string>Order_expandAppliedRule</string>
<string>Delivery_updateSimulation</string>
</list>
</value>
</item>
......@@ -50,7 +50,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>expand_simulation</string> </value>
<value> <string>expand_root</string> </value>
</item>
<item>
<key> <string>method_id</string> </key>
......
......@@ -40,7 +40,9 @@
</item>
<item>
<key> <string>description</string> </key>
<value> <string>reindex simulation after workflow state change, to keep consistency</string> </value>
<value> <string>reindex simulation after workflow state change, to keep consistency\r\n
\r\n
XXX: Something more reliable than a hardcoded list of methods from simulation workflows should be implemented.</string> </value>
</item>
<item>
<key> <string>guard</string> </key>
......@@ -50,7 +52,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>reindex_simulation</string> </value>
<value> <string>reindex_related</string> </value>
</item>
<item>
<key> <string>method_id</string> </key>
......@@ -60,7 +62,6 @@
<string>close</string>
<string>confirm</string>
<string>deliver</string>
<string>open</string>
<string>order</string>
<string>plan</string>
<string>setReady</string>
......@@ -72,7 +73,7 @@
</item>
<item>
<key> <string>once_per_transaction</string> </key>
<value> <int>0</int> </value>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>portal_type_filter</string> </key>
......
......@@ -28,7 +28,7 @@
<key> <string>after_script_name</string> </key>
<value>
<list>
<string>OrderMovement_expandAppliedRule</string>
<string>Delivery_updateCausalityState</string>
</list>
</value>
</item>
......@@ -50,13 +50,14 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>expand_simulation</string> </value>
<value> <string>update_causality</string> </value>
</item>
<item>
<key> <string>method_id</string> </key>
<value>
<list>
<string>_set.*</string>
<string>calculate</string>
<string>startBuilding</string>
</list>
</value>
</item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="InteractionDefinition" module="Products.ERP5.Interaction"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_url</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>activate_script_name</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>after_script_name</string> </key>
<value>
<list>
<string>Delivery_updateSimulation</string>
</list>
</value>
</item>
<item>
<key> <string>before_commit_script_name</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>call updateAppliedRule after a modification</string> </value>
</item>
<item>
<key> <string>guard</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>update_simulation</string> </value>
</item>
<item>
<key> <string>method_id</string> </key>
<value>
<list>
<string>_set(?!LastId$|Ob$|Object$)</string>
</list>
</value>
</item>
<item>
<key> <string>once_per_transaction</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>portal_type_filter</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>script_name</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>temporary_document_disallowed</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>trigger_type</string> </key>
<value> <int>2</int> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -50,28 +50,7 @@
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>"""\n
+-----+ +--------+\n
|Order| |Delivery| \n
+-----+ +--------+\n
| /\n
[AR] / \n
`--[SM] (1) \n
| \n
[AR] \n
`--[SM] (2)\n
| \n
...\n
\n
This script reindex simulation movements in (1), so that delivery builder select movement in (2)\n
with an up to date simulation state. We reindex simulation movements with the tag _updateAppliedRule,\n
because that delivery builder builds after that tag.\n
"""\n
\n
delivery = state_change[\'object\']\n
tag = \'%s_expand\' % delivery.getPath()\n
delivery.applyToDeliveryRelatedMovement(method_id=\'recursiveReindexObject\',\n
activate_kw=dict(tag=tag))\n
<value> <string>state_change[\'object\'].updateSimulation(create_root=1, index_related=1)\n
</string> </value>
</item>
<item>
......
......@@ -50,7 +50,7 @@
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>state_change[\'object\'].Delivery_updateSimulation()\n
<value> <string>state_change[\'object\'].updateSimulation(calculate=1)\n
</string> </value>
</item>
<item>
......@@ -59,7 +59,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Delivery_updateSimulation</string> </value>
<value> <string>Delivery_updateCausalityState</string> </value>
</item>
</dictionary>
</pickle>
......
......@@ -50,7 +50,7 @@
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>state_change[\'object\'].Delivery_updateSimulation()\n
<value> <string>state_change[\'object\'].updateSimulation(expand_root=1)\n
</string> </value>
</item>
<item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="InteractionWorkflowDefinition" module="Products.ERP5.InteractionWorkflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>creation_guard</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>This workflow manage the expand of the simulation related to an order movement</string> </value>
</item>
<item>
<key> <string>groups</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>order_movement_simulation_interaction_workflow</string> </value>
</item>
<item>
<key> <string>manager_bypass</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Order Movement Interaction Workflow</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Interaction" module="Products.ERP5.Interaction"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_mapping</string> </key>
<value>
<dictionary/>
</value>
</item>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>interactions</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="InteractionDefinition" module="Products.ERP5.Interaction"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_url</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>activate_script_name</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>after_script_name</string> </key>
<value>
<list>
<string>OrderMovement_expandAppliedRule</string>
</list>
</value>
</item>
<item>
<key> <string>before_commit_script_name</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>guard</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>unlink_simulation</string> </value>
</item>
<item>
<key> <string>method_id</string> </key>
<value>
<list>
<string>manage_beforeDelete</string>
</list>
</value>
</item>
<item>
<key> <string>once_per_transaction</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>portal_type_filter</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>script_name</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>temporary_document_disallowed</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>trigger_type</string> </key>
<value> <int>2</int> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Scripts" module="Products.DCWorkflow.Scripts"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_mapping</string> </key>
<value>
<dictionary/>
</value>
</item>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>scripts</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>order_movement = state_change[\'object\']\n
\n
order_movement.getExplanationValue().expandAppliedRuleRelatedToOrder()\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>state_change</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>OrderMovement_expandAppliedRule</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>order_movement = state_change[\'object\']\n
\n
# Clean simulation\n
simulation_movement_list = order_movement.getOrderRelatedValueList(\n
portal_type="Simulation Movement")\n
for simulation_movement in simulation_movement_list:\n
if simulation_movement.getDelivery() == order_movement.getRelativeUrl():\n
simulation_movement.setDelivery(None)\n
# \'order\' category is deprecated. it is kept for compatibility.\n
if simulation_movement.getOrder() == order_movement.getRelativeUrl():\n
simulation_movement.setOrder(None)\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>state_change</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>OrderMovement_unlinkSimulation</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Variables" module="Products.DCWorkflow.Variables"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_mapping</string> </key>
<value>
<dictionary/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>variables</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Worklists" module="Products.DCWorkflow.Worklists"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_mapping</string> </key>
<value>
<dictionary/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>worklists</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="InteractionWorkflowDefinition" module="Products.ERP5.InteractionWorkflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>creation_guard</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>This workflow manage the expand of the simulation related to an order</string> </value>
</item>
<item>
<key> <string>groups</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>order_simulation_interaction_workflow</string> </value>
</item>
<item>
<key> <string>manager_bypass</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Order Interaction Workflow</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Interaction" module="Products.ERP5.Interaction"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_mapping</string> </key>
<value>
<dictionary/>
</value>
</item>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>interactions</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="InteractionDefinition" module="Products.ERP5.Interaction"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_url</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>activate_script_name</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>after_script_name</string> </key>
<value>
<list>
<string>Order_reindexAppliedRule</string>
</list>
</value>
</item>
<item>
<key> <string>before_commit_script_name</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>XXX \r\n
The purpose of this interaction is to reindex the simulation movement related to an order when the simulation state is changed.\r\n
Currently, method ids are hardcoded, and it could be better to use a generic trigger method if possible.</string> </value>
</item>
<item>
<key> <string>guard</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>reindex_simulation</string> </value>
</item>
<item>
<key> <string>method_id</string> </key>
<value>
<list>
<string>cancel</string>
<string>close</string>
<string>confirm</string>
<string>deliver</string>
<string>open</string>
<string>order</string>
<string>plan</string>
<string>start</string>
<string>submit</string>
</list>
</value>
</item>
<item>
<key> <string>once_per_transaction</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>portal_type_filter</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>script_name</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>temporary_document_disallowed</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>trigger_type</string> </key>
<value> <int>2</int> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Scripts" module="Products.DCWorkflow.Scripts"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_mapping</string> </key>
<value>
<dictionary/>
</value>
</item>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>scripts</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>order = state_change[\'object\']\n
\n
order.expandAppliedRuleRelatedToOrder()\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>state_change</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Order_expandAppliedRule</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>order = state_change[\'object\']\n
\n
applied_rule = order.getCausalityRelatedValue(portal_type=\'Applied Rule\')\n
if applied_rule is not None:\n
applied_rule.recursiveReindexObject()\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>state_change</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Order_reindexAppliedRule</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Variables" module="Products.DCWorkflow.Variables"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_mapping</string> </key>
<value>
<dictionary/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>variables</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Worklists" module="Products.DCWorkflow.Worklists"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_mapping</string> </key>
<value>
<dictionary/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>worklists</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -56,7 +56,7 @@
<key> <string>method_id</string> </key>
<value>
<list>
<string>_set.*</string>
<string>_set(?!LastId$|Ob$|Object$|Delivery$|DeliveryValue$)</string>
</list>
</value>
</item>
......
......@@ -50,31 +50,18 @@
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>state_change[\'object\'].calculate()\n
<value> <string>delivery = state_change[\'object\'].getExplanationValue()\n
try:\n
delivery.aq_explicit.getCausalityState\n
except AttributeError:\n
return\n
delivery.activate(tag=\'expand:\'+delivery.getPath()).Delivery_calculate()\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>state_change</string> </value>
</item>
<item>
<key> <string>_proxy_roles</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Authenticated</string>
<string>Author</string>
<string>Manager</string>
<string>Member</string>
<string>Owner</string>
<string>Reviewer</string>
</tuple>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>SimulationMovement_calculateCausalityState</string> </value>
......
......@@ -12,8 +12,6 @@ embedded_workflow
local_permission_interaction_workflow
movement_resource_interaction_workflow
notification_message_workflow
order_movement_simulation_interaction_workflow
order_simulation_interaction_workflow
person_interaction_workflow
processing_status_workflow
query_workflow
......
......@@ -78,9 +78,11 @@ for builder_id in builder_id_list:\n
serialization_tag = \'build:%s\' % delivery_portal_type\n
index_tag = \'index:%s\' % delivery_portal_type\n
after_tag = index_tag\n
# depend on reindexing so that select methods\n
# do not return movements that are already built\n
after_method_id = (\'recursiveImmediateReindexObject\',\n
\'immediateReindexObject\',\n
\'Delivery_updateAppliedRule\')\n
\'_updateSimulation\')\n
activate_kw = dict(tag=index_tag)\n
builder.activate(\n
serialization_tag=serialization_tag,\n
......
......@@ -75,9 +75,11 @@ for builder_id in builder_id_list:\n
serialization_tag = \'build:%s\' % delivery_portal_type\n
index_tag = \'index:%s\' % delivery_portal_type\n
after_tag = index_tag\n
# depend on reindexing so that select methods\n
# do not return movements that are already built\n
after_method_id = (\'recursiveImmediateReindexObject\',\n
\'immediateReindexObject\',\n
\'Delivery_updateAppliedRule\')\n
\'_updateSimulation\')\n
activate_kw = dict(tag=index_tag)\n
builder.activate(\n
serialization_tag=serialization_tag,\n
......
......@@ -57,16 +57,6 @@
<none/>
</value>
</item>
<item>
<key> <string>delivery_after_generation_method_id</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>delivery_after_generation_script_id</string> </key>
<value> <string>Invoice_reindexRelatedSimulation</string> </value>
</item>
<item>
<key> <string>delivery_cell_collect_order</string> </key>
<value>
......
......@@ -57,16 +57,6 @@
<none/>
</value>
</item>
<item>
<key> <string>delivery_after_generation_method_id</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>delivery_after_generation_script_id</string> </key>
<value> <string>Invoice_reindexRelatedSimulation</string> </value>
</item>
<item>
<key> <string>delivery_cell_collect_order</string> </key>
<value>
......
......@@ -69,3 +69,6 @@ class DummyDelivery(Delivery):
def setCausalityState(self, state):
"""Directly sets a causality state."""
self.causality_state = state
def serializeCausalityState(self):
pass
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>request = context.REQUEST\n
Base_translateString = context.Base_translateString\n
\n
listbox = request.get(\'listbox\')\n
start_date = context.getStartDate()\n
stop_date = context.getStopDate()\n
tag = context.getPath() + \'_split\'\n
\n
split_and_defer = 0\n
\n
if listbox is not None:\n
context.updateAppliedRule("default_delivery_rule")\n
for line in listbox.values():\n
url = line[\'listbox_key\']\n
quantity = line[\'quantity\']\n
movement = context.restrictedTraverse(url)\n
movement.edit(quantity=str(quantity))\n
choice = line[\'choice\']\n
if choice == \'SplitAndDefer\':\n
split_and_defer = 1\n
context.portal_simulation.solveMovement(movement, None, "SplitAndDefer", \n
start_date=start_date, stop_date=stop_date, \n
activate_kw={\'tag\':tag})\n
elif choice == \'CopyToTarget\':\n
context.portal_simulation.solveMovement(movement, None,"CopyToTarget", activate_kw={\'tag\':tag})\n
\n
context.activate(after_tag=tag).updateCausalityState()\n
\n
if split_and_defer:\n
context_portal_type = context.getPortalType()\n
explanation_uid_list = [context.getUid()]\n
# Create delivery\n
if context_portal_type == \'Internal Packing List\':\n
delivery_builder = context.portal_deliveries.serp_internal_packing_list_builder\n
elif context_portal_type == \'Purchase Packing List\':\n
order = context.getCausalityValue()\n
explanation_uid_list.append(order.getUid())\n
delivery_builder = context.portal_deliveries.purchase_packing_list_builder\n
\n
delivery_builder.activate(activity=\'SQLQueue\', after_tag=tag).build(explanation_uid=explanation_uid_list)\n
\n
message = Base_translateString("${obj_portal_type} updated.", mapping={\'obj_portal_type\':context.getTranslatedPortalType()})\n
message = message.replace(\' \', \'+\')\n
\n
redirect_url = \'%s/%s?%s\' % (context.absolute_url(), form_id, \n
\'portal_status_message=%s\' % message)\n
context.REQUEST[ \'RESPONSE\' ].redirect( redirect_url )\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>form_id, dialog_id=\'\', **kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>AmortisationTransaction_doSolveActions</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -56,14 +56,6 @@
the new Invoice.\n
"""\n
from Products.ERP5Type.Message import translateString\n
try:\n
from Products.CMFCore.WorkflowCore import WorkflowException\n
except ImportError:\n
# WorkflowException has not always been allowed in restricted\n
# environment, in this case, make sure WorkflowException is \n
# defined \n
class WorkflowException(Exception):\n
pass\n
\n
if related_simulation_movement_path_list is None:\n
raise RuntimeError, \'related_simulation_movement_path_list is missing. Update ERP5 Product.\'\n
......@@ -101,24 +93,11 @@ if not invoice.hasTitle() and related_packing_list is not None and \\\n
invoice.setTitle(related_packing_list.getTitle())\n
\n
# initialize accounting_workflow to confirmed state\n
confirm_tag = \'%s_confirm\' % invoice.getPath()\n
if invoice.getSimulationState() == \'draft\':\n
invoice.activate(after_path_and_method_id=(related_simulation_movement_path_list,\n
(\'immediateReindexObject\',\'recursiveImmediateReindexObject\')),\n
tag=confirm_tag).Delivery_confirm()\n
invoice.Delivery_confirm()\n
else:\n
# call builder just same as after script of \'confirm\' transition\n
invoice.activate(after_path_and_method_id=(related_simulation_movement_path_list,\n
(\'immediateReindexObject\',\'recursiveImmediateReindexObject\')),\n
tag=confirm_tag).Delivery_expandAndBuild()\n
\n
# First set the invoice in the building state on the causality workflow\n
invoice.startBuilding()\n
\n
# Then an activity should put the causality state in diverged or solved\n
invoice.activate(after_path_and_method_id=(related_simulation_movement_path_list,\n
(\'immediateReindexObject\',\'recursiveImmediateReindexObject\')),\n
after_tag=confirm_tag).updateCausalityState()\n
invoice.localBuild()\n
]]></string> </value>
......
......@@ -61,23 +61,22 @@
# on the Transaction and delete resource on the lines.\n
# TODO: this is a Property Assignment Movement Group\n
\n
accounting_line_portal_type = context.getPortalAccountingMovementTypeList()\n
resources_keys = {}\n
for line in context.contentValues(portal_type=accounting_line_portal_type):\n
resources_keys[line.getResource()] = 1\n
\n
if len(resources_keys.keys()) == 1 :\n
line_list = context.objectValues(\n
portal_type=context.getPortalAccountingMovementTypeList())\n
resource_set = set(line.getResource() for line in line_list)\n
try:\n
resource, = resource_set\n
except ValueError:\n
raise ValueError("%s doesn\'t have only one resource %s" % (\n
context.getPath(), list(resource_set)))\n
if context.getResource() != resource:\n
# set the resource on the transaction\n
context.setResource(resources_keys.keys()[0])\n
# and delete on the invoice lines, so that if the user\n
# changes the ressource on the transaction, it also change on \n
# the lines. \n
for line in context.contentValues(portal_type=accounting_line_portal_type):\n
line.setResource(None)\n
assert(line.getResource() == context.getResource())\n
else :\n
raise ValueError, "%s doesn\'t have only one resource %s" % (\n
context.getPath(), resources_keys.keys())\n
context.setResource(resource)\n
# and delete on the invoice lines, so that if the user changes\n
# the ressource on the transaction, it also change on the lines.\n
for line in line_list:\n
line.setResource(None)\n
assert line.getResource() == resource\n
\n
# round debit / credit on created transaction.\n
context.AccountingTransaction_roundDebitCredit()\n
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>return context.applyToDeliveryRelatedMovement(\n
method_id=\'recursiveReindexObject\')\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Invoice_reindexRelatedSimulation</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>order = state_change[\'object\']\n
\n
order.applyToOrderRelatedMovement(method_id=\'expand\')\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>state_change</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Order_appliedToRelatedMovement</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -50,46 +50,8 @@
</item>
<item>
<key> <string>_body</string> </key>
<value> <string encoding="cdata"><![CDATA[
order = state_change[\'object\']\n
business_process = order.getSpecialiseValue()\n
\n
# When a business process is selected as specialise, ProductionOrderModelRule can be used.\n
# But another one is selected, ProductionOrderRule is still used.\n
if (business_process is not None and\n
business_process.getPortalType() in context.getPortalBusinessProcessTypeList()):\n
rule_reference=\'default_production_order_model_rule\'\n
builder_list = []\n
for path in business_process.getBuildablePathValueList(order):\n
builder_list.extend(path.getDeliveryBuilderValueList())\n
else:\n
rule_reference=\'default_production_order_rule\'\n
builder_list = [\n
order.portal_deliveries.production_report_builder,\n
order.portal_deliveries.production_packing_list_builder\n
]\n
\n
order_path = order.getPath()\n
tag = order_path + \'_updateAppliedRule\'\n
expand_tag = order_path + \'_expand\'\n
activate_kw = {\'tag\':expand_tag, \'priority\':3}\n
order.activate(tag=tag, after_tag=expand_tag).updateAppliedRule(rule_reference=rule_reference, activate_kw=activate_kw)\n
\n
for i in xrange(len(builder_list)):\n
if i > 0:\n
after_tag = (tag, expand_tag, \'%s_builder_%s\' % (order_path, i-1))\n
else:\n
after_tag = (tag, expand_tag)\n
builder_list[i].activate(\n
activity=\'SQLQueue\',\n
after_tag=after_tag,\n
tag=\'%s_builder_%s\' % (order_path, i),\n
priority=3).build(explanation_uid=order.getUid(),\n
activate_kw=activate_kw)\n
]]></string> </value>
<value> <string>state_change[\'object\'].localBuild()\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>order = state_change[\'object\']\n
business_process = order.getSpecialiseValue()\n
\n
# When a business process is selected as specialise, ProductionOrderModelRule can be used.\n
# But another one is selected, ProductionOrderRule is still used.\n
if (business_process is not None and\n
business_process.getPortalType() in context.getPortalBusinessProcessTypeList()):\n
rule_reference=\'default_production_order_model_rule\'\n
else:\n
rule_reference=\'default_production_order_rule\'\n
\n
path = order.getPath()\n
tag = \'%s_updateAppliedRule\' % path\n
expand_tag = \'%s_expand\' % path\n
activate_kw = {\'tag\':expand_tag, \'priority\':3}\n
order.activate(tag=tag, after_tag=expand_tag).updateAppliedRule(rule_reference=rule_reference, activate_kw=activate_kw)\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>state_change, **kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Order_createOrderRule</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="StateDefinition" module="Products.DCWorkflow.States"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>closed</string> </value>
</item>
<item>
<key> <string>permission_roles</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Closed</string> </value>
</item>
<item>
<key> <string>transitions</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>type_list</string> </key>
<value>
<tuple/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<tuple>
<global name="PersistentMapping" module="Persistence.mapping"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>Access contents information</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>Add portal content</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>Delete objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>Modify portal content</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>View</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
</tuple>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="StateDefinition" module="Products.DCWorkflow.States"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>open</string> </value>
</item>
<item>
<key> <string>permission_roles</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Open</string> </value>
</item>
<item>
<key> <string>transitions</string> </key>
<value>
<tuple>
<string>close</string>
<string>close_action</string>
</tuple>
</value>
</item>
<item>
<key> <string>type_list</string> </key>
<value>
<tuple/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<tuple>
<global name="PersistentMapping" module="Persistence.mapping"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>Access contents information</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>Add portal content</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>Delete objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>Modify portal content</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>View</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
</tuple>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -10,6 +10,10 @@
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
......@@ -20,7 +24,7 @@
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string>Order_appliedToRelatedMovement</string> </value>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="TransitionDefinition" module="Products.DCWorkflow.Transitions"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_url</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>guard</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>close</string> </value>
</item>
<item>
<key> <string>new_state_id</string> </key>
<value> <string>closed</string> </value>
</item>
<item>
<key> <string>script_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>trigger_type</string> </key>
<value> <int>2</int> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="TransitionDefinition" module="Products.DCWorkflow.Transitions"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_url</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string>close</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>guard</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>close_action</string> </value>
</item>
<item>
<key> <string>new_state_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>script_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>trigger_type</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="TransitionDefinition" module="Products.DCWorkflow.Transitions"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_url</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>guard</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>informDeliveryList</string> </value>
</item>
<item>
<key> <string>new_state_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>script_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>trigger_type</string> </key>
<value> <int>2</int> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="TransitionDefinition" module="Products.DCWorkflow.Transitions"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_url</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>guard</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>open</string> </value>
</item>
<item>
<key> <string>new_state_id</string> </key>
<value> <string>open</string> </value>
</item>
<item>
<key> <string>script_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>trigger_type</string> </key>
<value> <int>2</int> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="TransitionDefinition" module="Products.DCWorkflow.Transitions"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_url</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string>open</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>guard</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>open_action</string> </value>
</item>
<item>
<key> <string>new_state_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>script_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>trigger_type</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -10,6 +10,10 @@
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
......@@ -20,7 +24,7 @@
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string>Order_createOrderRule</string> </value>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
......
......@@ -10,6 +10,10 @@
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
......@@ -20,7 +24,7 @@
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string>Order_createOrderRule</string> </value>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>packing_list = state_change[\'object\']\n
\n
activate_kw = {}\n
related_order = packing_list.getCausalityValue()\n
path = packing_list.getPath()\n
tag = \'%s_updateAppliedRule\' % path\n
expand_tag = \'%s_expand\' % path\n
activate_kw = {\'tag\':expand_tag,\'priority\':3}\n
after_tag_list = [expand_tag]\n
if related_order is not None:\n
# XXX is it really required?\n
after_tag_list.append(\'%s_expand\' % related_order.getPath())\n
\n
packing_list.activate(after_tag=after_tag_list,\n
tag=tag,\n
priority=3).Delivery_updateAppliedRule(activate_kw=activate_kw)\n
\n
\n
# Make sure to reindex related simulation movement if we are already\n
# simulated, call reindexObject, not immediateReindexObject so that\n
# catalogObjectList will be called with many objects\n
# XXX is it really required?\n
packing_list.activate(after_tag=after_tag_list,\n
tag=tag,\n
priority=3).applyToDeliveryRelatedMovement(method_id=\'reindexObject\')\n
\n
if packing_list.getCausalityState() == \'draft\':\n
packing_list.startBuilding()\n
# XXX is it really required?\n
packing_list.activate(\n
after_tag = tag,\n
).updateCausalityState()\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>state_change, **kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>PackingList_updateAppliedRule</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -10,6 +10,10 @@
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
......@@ -20,7 +24,7 @@
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string>PackingList_updateAppliedRule</string> </value>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
......
......@@ -10,6 +10,10 @@
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
......@@ -20,7 +24,7 @@
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string>PackingList_updateAppliedRule</string> </value>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
......
......@@ -59,7 +59,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>SaleOrder_getRuleReference</string> </value>
<value> <string>OpenOrder_getRuleReference</string> </value>
</item>
</dictionary>
</pickle>
......
......@@ -50,22 +50,15 @@
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>subscription_item_dict = dict()\n
<value> <string>subscription_item_set = set()\n
\n
for open_order_line in context.contentValues():\n
for path in [open_order_line] + open_order_line.getCellValueList():\n
for item in path.getAggregateValueList():\n
if item.providesIExpandableItem(): # XXX hack to make it fails\n
subscription_item_dict[item] = 1\n
\n
# XXX tag / after tag !\n
for item in subscription_item_dict:\n
activate_kw = dict(tag=\'%s_expand\' % item.getPath())\n
applied_rule = item.getCausalityRelatedValue(portal_type=\'Applied Rule\')\n
if applied_rule is not None:\n
applied_rule.activate(activate_kw=activate_kw).expand(activate_kw=activate_kw)\n
else:\n
item.activate(activate_kw=activate_kw).expand(activate_kw=activate_kw)\n
for open_order_line in context.objectValues():\n
for ob in [open_order_line] + open_order_line.getCellValueList():\n
for item in ob.getAggregateValueList():\n
if getattr(item.aq_explicit, \'updateSimulation\', None) is not None and \\\n
item not in subscription_item_set:\n
subscription_item_set.add(item)\n
item.updateSimulation(expand_root=1)\n
</string> </value>
</item>
<item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>return \'default_order_rule\'\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>OpenPurchaseOrder_getRuleReference</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>return \'default_order_rule\'\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>OpenSaleOrder_getRuleReference</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -50,15 +50,10 @@
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>path = state_change[\'object\']\n
open_order_type_list = state_change.getPortal().getPortalOpenOrderTypeList()\n
\n
def getOpenOrder(path):\n
if path.getPortalType() in open_order_type_list:\n
return path\n
return getOpenOrder(path.getParentValue())\n
\n
getOpenOrder(path).OpenOrder_updateSimulation()\n
<value> <string>ob = state_change[\'object\']\n
while not ob.isOpenOrderType():\n
ob = ob.getParentValue()\n
ob.OpenOrder_updateSimulation()\n
</string> </value>
</item>
<item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>return None\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>PaySheetModel_getRuleReference</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -117,18 +117,7 @@ Please visit ERP5: %(url)s\n
subject="[ERP5 Task] %s" % task_report.getTitle(), \n
message=message)\n
\n
# Then, modify state\n
confirm_tag = \'%s_confirm\' % task_report.getPath()\n
task_report.activate(after_path_and_method_id=(related_simulation_movement_path_list,\n
(\'immediateReindexObject\',\'recursiveImmediateReindexObject\')),\n
tag=confirm_tag).Delivery_confirm()\n
\n
# First set the task_report in the building state\n
task_report.startBuilding()\n
# Then an activity should put the causality state in diverged or solved\n
task_report.activate(after_path_and_method_id=(related_simulation_movement_path_list,\n
(\'immediateReindexObject\',\'recursiveImmediateReindexObject\')),\n
after_tag=confirm_tag).updateCausalityState()\n
task_report.Delivery_confirm()\n
</string> </value>
</item>
<item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>portal = sci.getPortal()\n
if portal.hasObject(\'accounting_module\'):\n
portal.portal_deliveries.task_invoice_builder.activate(\n
after_method_id = [ \'expand\', \n
\'recursiveImmediateReindexObject\',\n
\'immediateReindexObject\' ],\n
).build()\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>sci</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>PackingList_buildInvoice</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>packing_list = state_change[\'object\']\n
\n
activate_kw = {}\n
related_order = packing_list.getCausalityValue()\n
path = packing_list.getPath()\n
tag = \'%s_updateAppliedRule\' % path\n
expand_tag = \'%s_expand\' % path\n
activate_kw = {\'tag\':expand_tag,\'priority\':3}\n
after_tag_list = [expand_tag]\n
if related_order is not None:\n
# XXX is it really required?\n
after_tag_list.append(\'%s_expand\' % related_order.getPath())\n
\n
packing_list.activate(after_tag=after_tag_list,\n
tag=tag,\n
priority=3).Delivery_updateAppliedRule(activate_kw=activate_kw)\n
\n
\n
# Make sure to reindex related simulation movement if we are already\n
# simulated, call reindexObject, not immediateReindexObject so that\n
# catalogObjectList will be called with many objects\n
# XXX is it really required?\n
packing_list.activate(after_tag=after_tag_list,\n
tag=tag,\n
priority=3).applyToDeliveryRelatedMovement(method_id=\'reindexObject\')\n
\n
if packing_list.getCausalityState() == \'draft\':\n
packing_list.startBuilding()\n
# XXX is it really required?\n
packing_list.activate(\n
after_tag = tag,\n
).updateCausalityState()\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>state_change, **kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>PackingList_updateAppliedRule</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -74,8 +74,6 @@ Please look at this URL:\n
task_report.ERP5Site_getAbsoluteUrl(), task_report.getRelativeUrl())\n
portal.portal_notifications.sendMessage(sender=source_person, recipient=destination_decision_person,\n
subject="Task Report Finished", message=message)\n
\n
container.PackingList_updateAppliedRule(state_change)\n
</string> </value>
</item>
<item>
......
......@@ -10,6 +10,10 @@
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string>Confirm Task</string> </value>
......@@ -20,7 +24,7 @@
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string>PackingList_updateAppliedRule</string> </value>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
......
......@@ -10,6 +10,10 @@
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string>Start Task</string> </value>
......@@ -20,7 +24,7 @@
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string>PackingList_updateAppliedRule</string> </value>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>task = state_change[\'object\']\n
\n
task.applyToOrderRelatedMovement(method_id=\'expand\')\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>state_change</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Task_appliedToRelatedMovement</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -50,17 +50,7 @@
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>task = state_change[\'object\']\n
\n
path = task.getPath()\n
tag = \'%s_updateAppliedRule\' % path\n
expand_tag = \'%s_expand\' % path\n
activate_kw = {\'tag\':expand_tag, \'priority\':3}\n
\n
task.activate(tag=tag, after_tag=expand_tag).Delivery_updateAppliedRule(activate_kw=activate_kw)\n
\n
delivery_builder = task.portal_deliveries.task_report_builder\n
delivery_builder.activate(activity=\'SQLQueue\',after_tag=(tag, expand_tag)).build(explanation_uid=task.getUid())\n
<value> <string>state_change[\'object\'].localBuild()\n
</string> </value>
</item>
<item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>task = state_change[\'object\']\n
\n
path = task.getPath()\n
tag = \'%s_updateAppliedRule\' % path\n
expand_tag = \'%s_expand\' % path\n
activate_kw = {\'tag\':expand_tag, \'priority\':3}\n
\n
task.activate(tag=tag, after_tag=expand_tag).Delivery_updateAppliedRule(activate_kw=activate_kw)\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>state_change, **kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Task_createOrderRule</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -10,6 +10,10 @@
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string>Cancel Task</string> </value>
......@@ -20,7 +24,7 @@
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string>Task_appliedToRelatedMovement</string> </value>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
......
......@@ -10,6 +10,10 @@
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string>Order Task</string> </value>
......@@ -20,7 +24,7 @@
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string>Task_createOrderRule</string> </value>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
......
......@@ -10,6 +10,10 @@
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string>Plan Task</string> </value>
......@@ -42,7 +46,7 @@
</item>
<item>
<key> <string>script_name</string> </key>
<value> <string>Task_createOrderRule</string> </value>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>return context.asComposedDocument().build(explanation=context)\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Delivery_buildOnComposedDocument</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>delivery = context\n
delivery_path = delivery.getPath()\n
path_and_method_id = (delivery_path, (\'immediateReindexObject\', \'recursiveImmediateReindexObject\'))\n
expand_tag = delivery_path + \'_expand\'\n
tag = delivery_path + \'_updateAppliedRule\'\n
after_tag = [expand_tag]\n
\n
# wait for expand activities of related documents.\n
# XXX ideally, it should be calculated by explanation tree, instead of causalities.\n
for causality in delivery.getCausalityValueList():\n
causality_path = causality.getPath()\n
after_tag.append(\'%s_expand\' % causality_path)\n
after_tag.append(\'%s_updateAppliedRule\' % causality_path)\n
\n
priority = 3\n
activate_kw = { \n
\'tag\': expand_tag,\n
\'priority\':priority,\n
}\n
delivery.activate(\n
activity=\'SQLQueue\',\n
after_path_and_method_id=path_and_method_id,\n
after_tag=after_tag,\n
tag=tag,\n
priority=priority,\n
serialization_tag=tag,\n
).Delivery_updateAppliedRule(activate_kw=activate_kw)\n
delivery.activate(activity=\'SQLQueue\', after_tag=(tag, expand_tag)).Delivery_buildOnComposedDocument()\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Delivery_expandAndBuild</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -50,7 +50,9 @@
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>return False\n
<value> <string># XXX: Using reference to select a rule (for a root applied rule) is wrong\n
# and should be replaced by predicate and workflow state.\n
return False\n
</string> </value>
</item>
<item>
......
......@@ -45,10 +45,6 @@
</list>
</value>
</item>
<item>
<key> <string>delivery_after_generation_script_id</string> </key>
<value> <string>Invoice_reindexRelatedSimulation</string> </value>
</item>
<item>
<key> <string>delivery_cell_collect_order</string> </key>
<value>
......
......@@ -65,7 +65,7 @@ index_tag = \'index:\' + delivery_portal_type\n
after_method_id = (\'recursiveImmediateReindexObject\',\n
\'immediateReindexObject\',\n
\'expand\',\n
\'Delivery_updateAppliedRule\')\n
\'_updateSimulation\')\n
activate_kw = dict(tag=index_tag)\n
builder.activate(\n
serialization_tag=serialization_tag,\n
......
......@@ -71,9 +71,11 @@ for builder_id in builder_id_list:\n
serialization_tag = \'build:%s\' % delivery_portal_type\n
index_tag = \'index:%s\' % delivery_portal_type\n
after_tag = index_tag\n
# depend on reindexing so that select methods\n
# do not return movements that are already built\n
after_method_id = (\'recursiveImmediateReindexObject\',\n
\'immediateReindexObject\',\n
\'Delivery_updateAppliedRule\')\n
\'_updateSimulation\')\n
activate_kw = dict(tag=index_tag)\n
builder.activate(\n
serialization_tag=serialization_tag,\n
......
......@@ -70,9 +70,11 @@ for builder_id in builder_id_list:\n
serialization_tag = \'build:%s\' % delivery_portal_type\n
index_tag = \'index:%s\' % delivery_portal_type\n
after_tag = index_tag\n
# depend on reindexing so that select methods\n
# do not return movements that are already built\n
after_method_id = (\'recursiveImmediateReindexObject\',\n
\'immediateReindexObject\',\n
\'Delivery_updateAppliedRule\')\n
\'_updateSimulation\')\n
activate_kw = dict(tag=index_tag)\n
builder.activate(\n
serialization_tag=serialization_tag,\n
......
......@@ -50,23 +50,18 @@
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>from Products.ERP5Type.Message import translateString\n
\n
if REQUEST is not None:\n
<value> <string>if REQUEST is not None:\n
from zExceptions import Unauthorized\n
raise Unauthorized(script.id)\n
\n
packing_list = context\n
\n
# Modify state\n
packing_list_state = packing_list.getSimulationState()\n
if packing_list_state == "draft":\n
packing_list.confirm(comment=translateString(\'Initialised by Delivery Builder.\'))\n
if context.getSimulationState() == "draft":\n
from Products.ERP5Type.Message import translateString\n
context.confirm(comment=translateString(\'Initialised by Delivery Builder.\'))\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>REQUEST=None, **kw</string> </value>
<value> <string>REQUEST=None</string> </value>
</item>
<item>
<key> <string>id</string> </key>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>return \'default_order_rule\'\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>InternalOrder_getRuleReference</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>return None\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>InternalPackingList_getRuleReference</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -59,7 +59,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Task_getRuleReference</string> </value>
<value> <string>Order_getRuleReference</string> </value>
</item>
</dictionary>
</pickle>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>request = context.REQUEST\n
\n
listbox = request.get(\'listbox\')\n
start_date = context.getStartDate()\n
stop_date = context.getStopDate()\n
tag = context.getPath() + \'_split\'\n
\n
split_and_defer = 0\n
\n
if listbox is not None:\n
context.updateAppliedRule("default_delivery_rule")\n
for line_key in listbox:\n
line = listbox[line_key]\n
url = line[\'listbox_key\']\n
quantity = line[\'quantity\']\n
movement = context.restrictedTraverse(url)\n
movement.setProperty(\'quantity\', quantity, type=\'float\')\n
choice = line[\'choice\']\n
if choice == \'SplitAndDefer\':\n
split_and_defer = 1\n
context.portal_simulation.solveMovement(movement, None, "SplitAndDefer", start_date=start_date, stop_date=stop_date, activate_kw={\'tag\':tag})\n
elif choice == \'CopyToTarget\':\n
context.portal_simulation.solveMovement(movement, None,"CopyToTarget")\n
\n
context.updateCausalityState()\n
\n
if split_and_defer:\n
# Create delivery\n
order = context.getCausalityValue()\n
applied_rule = order.getCausalityRelatedValue(portal_type="Applied Rule")\n
\n
order_portal_type = order.getPortalType()\n
if order_portal_type == \'Sale Order\':\n
delivery_builder = order.portal_deliveries.sale_packing_list_builder\n
elif order_portal_type == \'Purchase Order\':\n
delivery_builder = order.portal_deliveries.purchase_packing_list_builder\n
\n
explanation_uid_list = [order.getUid(),context.getUid()]\n
delivery_builder.activate(activity=\'SQLQueue\',after_tag=tag).build(explanation_uid=explanation_uid_list)\n
\n
\n
_ = context.Base_translateString\n
return context.Base_redirect(form_id, keep_items=\n
dict(portal_status_message=_(\'Packing List updated.\')))\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>form_id, dialog_id=\'\', **kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>PackingList_doSolveActions</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -59,7 +59,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>TaskReport_getRuleReference</string> </value>
<value> <string>PackingList_getRuleReference</string> </value>
</item>
</dictionary>
</pickle>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>return \'default_order_rule\'\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>PurchaseOrder_getRuleReference</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -50,31 +50,13 @@
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>if related_simulation_movement_path_list is None:\n
raise RuntimeError, \'related_simulation_movement_path_list is missing. Update ERP5 Product.\'\n
\n
packing_list = context\n
\n
# First, copy Order properties\n
packing_list.PackingList_copyOrderProperties()\n
\n
# Then, modify state\n
confirm_tag = \'%s_confirm\' % packing_list.getPath()\n
packing_list.activate(after_path_and_method_id=(related_simulation_movement_path_list,\n
(\'immediateReindexObject\',\'recursiveImmediateReindexObject\')),\n
tag=confirm_tag).Delivery_confirm()\n
\n
# First set the packing_list in the building state\n
packing_list.startBuilding()\n
# Then an activity should put the causality state in diverged or solved\n
packing_list.activate(after_path_and_method_id=(related_simulation_movement_path_list,\n
(\'immediateReindexObject\',\'recursiveImmediateReindexObject\')),\n
after_tag=confirm_tag).updateCausalityState()\n
<value> <string>context.PackingList_copyOrderProperties()\n
context.Delivery_confirm()\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>related_simulation_movement_path_list=None</string> </value>
<value> <string>related_simulation_movement_path_list</string> </value>
</item>
<item>
<key> <string>id</string> </key>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>return \'default_delivery_rule\'\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>PurchasePackingList_getRuleReference</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>return \'default_delivery_rule\'\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>ReturnedPurchasePackingList_getRuleReference</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>return \'default_delivery_rule\'\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>ReturnedSalePackingList_getRuleReference</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -50,33 +50,13 @@
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>if related_simulation_movement_path_list is None:\n
raise RuntimeError, \'related_simulation_movement_path_list is missing. Update ERP5 Product.\'\n
\n
from Products.ERP5Type.Message import translateString\n
\n
packing_list = context\n
\n
# First, copy Order properties\n
packing_list.PackingList_copyOrderProperties()\n
\n
# Then, modify state\n
confirm_tag = \'%s_confirm\' % packing_list.getPath()\n
packing_list.activate(after_path_and_method_id=(related_simulation_movement_path_list,\n
(\'immediateReindexObject\',\'recursiveImmediateReindexObject\')),\n
tag=confirm_tag).Delivery_confirm()\n
\n
# First set the packing_list in the building state\n
packing_list.startBuilding()\n
# Then an activity should put the causality state in diverged or solved\n
packing_list.activate(after_path_and_method_id=(related_simulation_movement_path_list,\n
(\'immediateReindexObject\',\'recursiveImmediateReindexObject\')),\n
after_tag=confirm_tag).updateCausalityState()\n
<value> <string>context.PackingList_copyOrderProperties()\n
context.Delivery_confirm()\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>related_simulation_movement_path_list=None</string> </value>
<value> <string>related_simulation_movement_path_list</string> </value>
</item>
<item>
<key> <string>id</string> </key>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>return \'default_delivery_rule\'\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>SalePackingList_getRuleReference</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>order = state_change[\'object\']\n
\n
order.applyToOrderRelatedMovement(method_id=\'expand\')\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>state_change</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Order_appliedToRelatedMovement</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>order = state_change[\'object\']\n
order.Delivery_updateSimulation()\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>state_change, **kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Order_createOrderRule</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -10,6 +10,10 @@
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
......@@ -20,7 +24,7 @@
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string>Order_appliedToRelatedMovement</string> </value>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
......
......@@ -24,7 +24,7 @@
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string>Order_createOrderRule</string> </value>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="TransitionDefinition" module="Products.DCWorkflow.Transitions"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_url</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>guard</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>informDeliveryList</string> </value>
</item>
<item>
<key> <string>new_state_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>script_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>trigger_type</string> </key>
<value> <int>2</int> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -10,6 +10,10 @@
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
......@@ -20,7 +24,7 @@
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string>Order_createOrderRule</string> </value>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
......
......@@ -10,6 +10,10 @@
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
......@@ -20,7 +24,7 @@
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string>Order_createOrderRule</string> </value>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>delivery = state_change[\'object\']\n
delivery.Delivery_updateSimulation()\n
\n
if delivery.getCausalityState() == \'draft\':\n
delivery.startBuilding()\n
path = delivery.getPath()\n
delivery.activate(\n
after_tag = (path + \'_calculate\', path + \'_updateAppliedRule\'),\n
).updateCausalityState()\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>state_change, **kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>PackingList_updateAppliedRule</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -10,6 +10,10 @@
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
......@@ -20,7 +24,7 @@
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string>PackingList_updateAppliedRule</string> </value>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
......
......@@ -10,6 +10,10 @@
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
......@@ -20,7 +24,7 @@
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string>PackingList_updateAppliedRule</string> </value>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
......
......@@ -24,7 +24,7 @@
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string>PackingList_updateAppliedRule</string> </value>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
......
......@@ -24,7 +24,7 @@
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string>PackingList_updateAppliedRule</string> </value>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
......
......@@ -52,7 +52,7 @@
<key> <string>_body</string> </key>
<value> <string>delivery = state_change[\'object\'].getParentValue()\n
if delivery.isDelivery:\n
delivery.Delivery_updateSimulation()\n
delivery.updateSimulation(expand_related=1)\n
</string> </value>
</item>
<item>
......
......@@ -73,7 +73,7 @@ class AmortisationRule(RuleMixin):
# Simulation workflow
security.declareProtected(Permissions.ModifyPortalContent, 'expand')
def expand(self, applied_rule, force=0, **kw):
def expand(self, applied_rule, expand_policy=None, activate_kw={}):
"""
Expands the current movement downward.
......@@ -82,6 +82,8 @@ class AmortisationRule(RuleMixin):
An applied rule can be expanded only if its parent movement
is expanded.
"""
assert expand_policy == "immediate" and not activate_kw
invalid_state_list = self.getPortalUpdatableAmortisationTransactionStateList()
to_aggregate_movement_list = []
......
......@@ -40,13 +40,10 @@ from Products.ERP5Type.Base import WorkflowMethod
from Products.ERP5Type.Globals import PersistentMapping
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Type.TransactionalVariable import getTransactionalVariable
from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod
from Products.ERP5.ExpandPolicy import TREE_DELIVERED_CACHE_KEY
from Products.ERP5.mixin.explainable import ExplainableMixin
from Products.ERP5.mixin.rule import RuleMixin
TREE_DELIVERED_CACHE_KEY = 'AppliedRule._isTreeDelivered_cache'
TREE_DELIVERED_CACHE_ENABLED = 'TREE_DELIVERED_CACHE_ENABLED'
class AppliedRule(XMLObject, ExplainableMixin):
"""
An applied rule holds a list of simulation movements.
......@@ -83,7 +80,8 @@ class AppliedRule(XMLObject, ExplainableMixin):
)
# Declarative interfaces
zope.interface.implements(interfaces.IMovementCollection,)
zope.interface.implements(interfaces.IExpandable,
interfaces.IMovementCollection)
def tpValues(self) :
""" show the content in the left pane of the ZMI """
......@@ -95,74 +93,17 @@ class AppliedRule(XMLObject, ExplainableMixin):
"""Tells whether generated movement needs to be accounted or not."""
return self.getSpecialiseValue().isAccountable(movement)
security.declareProtected(Permissions.ModifyPortalContent, 'expand')
@UnrestrictedMethod
def expand(self, **kw):
"""
Expands the current movement downward.
-> new status -> expanded
An applied rule can be expanded only if its parent movement
is expanded.
"""
tv = getTransactionalVariable()
cache = tv.setdefault(TREE_DELIVERED_CACHE_KEY, {})
cache_enabled = cache.get(TREE_DELIVERED_CACHE_ENABLED, 0)
# enable cache
if not cache_enabled:
cache[TREE_DELIVERED_CACHE_ENABLED] = 1
rule = self.getSpecialiseValue()
if rule is not None:
rule.expand(self,**kw)
# disable and clear cache
if not cache_enabled:
try:
del tv[TREE_DELIVERED_CACHE_KEY]
except KeyError:
pass
security.declarePrivate("getSimulationState")
def getSimulationState(self):
return
security.declareProtected(Permissions.ModifyPortalContent, 'solve')
def solve(self, solution_list):
"""
Solve inconsistency according to a certain number of solutions
templates. This updates the
-> new status -> solved
This applies a solution to an applied rule. Once
the solution is applied, the parent movement is checked.
If it does not diverge, the rule is reexpanded. If not,
diverge is called on the parent movement.
"""
rule = self.getSpecialiseValue()
if rule is not None:
rule.solve(self)
security.declareProtected(Permissions.ModifyPortalContent, 'diverge')
def diverge(self):
"""
-> new status -> diverged
This basically sets the rule to "diverged"
and blocks expansion process
security.declareProtected(Permissions.ModifyPortalContent, 'expand')
def expand(self, *args, **kw):
"""Expand this applied rule to create new documents inside the applied rule
"""
rule = self.getSpecialiseValue()
if rule is not None:
rule.diverge(self)
self.getSpecialiseValue().expand(self, *args, **kw)
# Solvers
security.declareProtected(Permissions.AccessContentsInformation,
'isStable')
def isStable(self):
"""
Tells whether the rule is stable or not.
"""
return self.getSpecialiseValue().isStable(self)
security.declareProtected(Permissions.AccessContentsInformation,
'isDivergent')
def isDivergent(self, sim_mvt):
......@@ -205,26 +146,21 @@ class AppliedRule(XMLObject, ExplainableMixin):
see SimulationMovement._isTreeDelivered
"""
tv = getTransactionalVariable()
cache = tv.setdefault(TREE_DELIVERED_CACHE_KEY, {})
cache_enabled = cache.get(TREE_DELIVERED_CACHE_ENABLED, 0)
def getTreeDelivered(applied_rule):
for movement in applied_rule.objectValues():
def getTreeDelivered():
for movement in self.objectValues():
if movement._isTreeDelivered():
return True
return False
try:
cache = getTransactionalVariable()[TREE_DELIVERED_CACHE_KEY]
except KeyError:
return getTreeDelivered()
rule_key = self.getRelativeUrl()
if cache_enabled:
try:
return cache[rule_key]
except:
result = getTreeDelivered(self)
cache[rule_key] = result
return result
else:
return getTreeDelivered(self)
try:
return cache[rule_key]
except KeyError:
cache[rule_key] = result = getTreeDelivered()
return result
security.declareProtected(Permissions.AccessContentsInformation,
'getMovementList')
......@@ -234,59 +170,6 @@ class AppliedRule(XMLObject, ExplainableMixin):
"""
return self.objectValues(portal_type=RuleMixin.movement_type)
security.declareProtected(Permissions.AccessContentsInformation,
'getIndexableChildSimulationMovementValueList')
def getIndexableChildSimulationMovementValueList(self):
return [x for x in self.getIndexableChildValueList()
if x.getPortalType() == 'Simulation Movement']
security.declarePublic('recursiveImmediateReindexSimulationMovement')
def recursiveImmediateReindexSimulationMovement(self, **kw):
"""
Applies immediateReindexObject recursively to Simulation Movements
"""
# Reindex direct children
root_indexable = int(getattr(self.getPortalObject(), 'isIndexable', 1))
for movement in self.objectValues():
if movement.isIndexable and root_indexable:
movement.immediateReindexObject(**kw)
# Go recursively
for movement in self.objectValues():
for applied_rule in movement.objectValues():
applied_rule.recursiveImmediateReindexSimulationMovement(**kw)
security.declarePublic('recursiveReindexSimulationMovement')
def recursiveReindexSimulationMovement(self, activate_kw=None, **kw):
if self.isIndexable:
if activate_kw is None:
activate_kw = {}
reindex_kw = self.getDefaultReindexParameterDict()
if reindex_kw is not None:
reindex_activate_kw = reindex_kw.pop('activate_kw', None)
if reindex_activate_kw is not None:
reindex_activate_kw = reindex_activate_kw.copy()
if activate_kw is not None:
# activate_kw parameter takes precedence
reindex_activate_kw.update(activate_kw)
activate_kw = reindex_activate_kw
kw.update(reindex_kw)
group_id_list = []
if kw.get("group_id", "") not in ('', None):
group_id_list.append(kw.get("group_id", ""))
if kw.get("sql_catalog_id", "") not in ('', None):
group_id_list.append(kw.get("sql_catalog_id", ""))
group_id = ' '.join(group_id_list)
self.activate(
group_method_id='portal_catalog/catalogObjectList',
expand_method_id='getIndexableChildSimulationMovementValueList',
alternate_method_id='alternateReindexObject',
group_id=group_id,
serialization_tag=self.getRootDocumentPath(),
**activate_kw).recursiveImmediateReindexSimulationMovement(**kw)
def _migrateSimulationTree(self, get_matching_key,
get_original_property_dict, root_rule=None):
"""Migrate an entire simulation tree in order to use new rules
......@@ -480,7 +363,7 @@ class AppliedRule(XMLObject, ExplainableMixin):
AppliedRule.isIndexable = SimulationMovement.isIndexable = \
ConstantGetter('isIndexable', value=False)
mixin.updateMovementCollection = updateMovementCollection
self.expand()
self.expand("immediate")
finally:
mixin.updateMovementCollection = orig_updateMovementCollection
del AppliedRule.isIndexable, SimulationMovement.isIndexable
......@@ -512,7 +395,7 @@ class AppliedRule(XMLObject, ExplainableMixin):
return rule_dict
initial_rule_dict = fillRuleDict()
try:
self.expand()
self.expand("immediate")
except ConflictError:
raise
except Exception:
......
......@@ -30,20 +30,18 @@
import zope.interface
from Products.CMFCore.utils import getToolByName
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet, interfaces
from Products.ERP5Type.Accessor.Constant import PropertyGetter as ConstantGetter
from Products.ERP5Type.Errors import SimulationError
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5.Document.ImmobilisationDelivery import ImmobilisationDelivery
from Products.ERP5.mixin.amount_generator import AmountGeneratorMixin
from Products.ERP5.mixin.composition import CompositionMixin
from Products.ERP5.mixin.rule import SimulableMixin
from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod
from zLOG import LOG, PROBLEM
class Delivery(XMLObject, ImmobilisationDelivery,
class Delivery(XMLObject, ImmobilisationDelivery, SimulableMixin,
CompositionMixin, AmountGeneratorMixin):
"""
Each time delivery is modified, it MUST launch a reindexing of
......@@ -321,12 +319,6 @@ class Delivery(XMLObject, ImmobilisationDelivery,
container_list.append(m)
return container_list
def applyToDeliveryRelatedMovement(self, portal_type='Simulation Movement',
method_id='expand', **kw):
for simulation_movement in self._getAllRelatedSimulationMovementList():
# And apply
getattr(simulation_movement.getObject(), method_id)(**kw)
#######################################################
# Causality computation
security.declareProtected(Permissions.AccessContentsInformation, 'isConvergent')
......@@ -394,6 +386,16 @@ class Delivery(XMLObject, ImmobilisationDelivery,
else:
self.converge()
def updateSimulation(self, calculate=False, **kw):
if calculate:
path = self.getPath()
self.activate(
after_tag=('built:'+path, 'expand:'+path),
after_path_and_method_id=(path, '_localBuild'),
).updateCausalityState()
if kw:
super(Delivery, self).updateSimulation(**kw)
def splitAndDeferMovementList(self, start_date=None, stop_date=None,
movement_uid_list=[], delivery_solver=None,
target_solver='CopyToTarget', delivery_builder=None):
......@@ -434,8 +436,9 @@ class Delivery(XMLObject, ImmobilisationDelivery,
movement.activate(tag=solver_tag).Movement_solveMovement(
delivery_solver, target_solver)
tag_list.append(solver_tag)
kw = {'after_tag': tag_list[:], 'tag': expand_tag}
for s_m in deferred_simulation_movement_list:
s_m.activate(after_tag=tag_list[:], tag=expand_tag).expand()
s_m.expand('deferred', activate_kw=kw)
tag_list.append(expand_tag)
detached_movement_url_list = []
......@@ -476,9 +479,7 @@ class Delivery(XMLObject, ImmobilisationDelivery,
Reindex children and simulation
"""
self.recursiveReindexObject(*k, **kw)
# NEW: we never rexpand simulation - This is a task for DSolver / TSolver
# Make sure expanded simulation is still OK (expand and reindex)
# self.activate().applyToDeliveryRelatedMovement(method_id = 'expand')
# do not reexpand simulation: this is a task for DSolver / TSolver
#######################################################
# Stock Management
......@@ -685,150 +686,50 @@ class Delivery(XMLObject, ImmobilisationDelivery,
##########################################################################
# Applied Rule stuff
@UnrestrictedMethod # XXX-JPS What is this ?
def updateAppliedRule(self, rule_reference=None, rule_id=None, **kw):
"""
Create a new Applied Rule if none is related, or call expand
on the existing one.
The chosen applied rule will be the validated rule with reference ==
rule_reference, and the higher version number.
"""
if rule_id is not None:
from warnings import warn
warn('rule_id to updateAppliedRule is deprecated; use rule_reference instead',
DeprecationWarning)
rule_reference = rule_id
if rule_reference is None:
return
# only expand if we are not in a "too early" or "too late" state
if (self.getSimulationState() in
self.getPortalDraftOrderStateList()):
return
portal_rules = getToolByName(self, 'portal_rules')
res = portal_rules.searchFolder(reference=rule_reference,
validation_state="validated", sort_on='version',
sort_order='descending') # XXX validated is Hardcoded !
if len(res) > 0:
rule_id = res[0].getId()
security.declareProtected(Permissions.AccessContentsInformation,
'localBuild')
def localBuild(self, activity_kw=()):
"""Activate builders for this delivery
The generated activity will find all buildable business links for this
delivery, and call related builders, which will select all simulation
movements part of the same explanation(s) as the delivery.
XXX: Consider moving it to SimulableMixin if it's useful for
Subscription Items.
"""
# XXX: Previous implementation waited for expand activities of related
# documents and even suggested to look at explanation tree,
# instead of causalities. Is it required ?
kw = {'priority': 3}
kw.update(activity_kw)
after_tag = kw.pop('after_tag', None)
if isinstance(after_tag, basestring):
after_tag = [after_tag]
else:
raise ValueError, 'No such rule as %r is found' % rule_reference
after_tag = list(after_tag) if after_tag else []
after_tag.append('expand:' + self.getPath())
self.activate(after_tag=after_tag, **kw)._localBuild()
self._createAppliedRule(rule_id, **kw)
def _localBuild(self):
"""Do an immediate local build for this delivery"""
return self.asComposedDocument().build(explanation=self)
def _createAppliedRule(self, rule_id, activate_kw=None, **kw):
"""
Create a new Applied Rule is none is related, or call expand
on the existing one.
"""
# Look up if existing applied rule
my_applied_rule_list = self.getCausalityRelatedValueList(
portal_type='Applied Rule')
my_applied_rule = None
if len(my_applied_rule_list) == 0:
if self.isSimulated():
# No need to create a DeliveryRule
# if we are already in the simulation process
pass
else:
# Create a new applied order rule (portal_rules.order_rule)
portal_rules = getToolByName(self, 'portal_rules')
portal_simulation = getToolByName(self, 'portal_simulation')
my_applied_rule = portal_rules[rule_id].\
constructNewAppliedRule(portal_simulation,
activate_kw=activate_kw)
# Set causality
my_applied_rule.setCausalityValue(self)
# We must make sure this rule is indexed
# now in order not to create another one later
my_applied_rule.reindexObject(activate_kw=activate_kw, **kw)
elif len(my_applied_rule_list) == 1:
# Re expand the rule if possible
my_applied_rule = my_applied_rule_list[0]
else:
raise SimulationError('Delivery %s has more than one applied'
' rule.' % self.getRelativeUrl())
my_applied_rule_id = None
expand_activate_kw = {}
if my_applied_rule is not None:
my_applied_rule_id = my_applied_rule.getId()
expand_activate_kw['after_path_and_method_id'] = (
my_applied_rule.getPath(),
['immediateReindexObject', 'recursiveImmediateReindexObject'])
# We are now certain we have a single applied rule
# It is time to expand it
self.activate(activate_kw=activate_kw, **expand_activate_kw).expand(
applied_rule_id=my_applied_rule_id,
activate_kw=activate_kw, **kw)
security.declareProtected(Permissions.ModifyPortalContent, 'expand')
# deprecated - see ExpandableMixin
@UnrestrictedMethod
def expand(self, applied_rule_id=None, activate_kw=None,**kw):
"""
Reexpand applied rule
Also reexpand all rules related to movements
NOTE: seems to be deprecated ?
"""
excluded_rule_path_list = []
if applied_rule_id is not None:
my_applied_rule = self.portal_simulation.get(applied_rule_id, None)
if my_applied_rule is not None:
excluded_rule_path_list.append(my_applied_rule.getPath())
my_applied_rule.expand(activate_kw=activate_kw,**kw)
# once expanded, the applied_rule must be reindexed
# because some simulation_movement may change even
# if there are not edited (acquisition)
#
# XXX yo thinks that this is excessive. First of all, we may
# need to reindex simulation movements but not applied rules
# here. So we should skip reindexing applied rules.
# In addition, the policy is "copy everything required to
# simulation movements", so acquisitions should not matter to
# indexing. The only exception is the simulation state.
# I think, if each simulation movement remembers the previous
# state, we can avoid unnecessary reindexing.
my_applied_rule.recursiveReindexSimulationMovement(activate_kw=activate_kw)
else:
LOG("ERP5", PROBLEM,
"Could not expand applied rule %s for delivery %s" %\
(applied_rule_id, self.getId()))
self.expandRuleRelatedToMovement(
excluded_rule_path_list=excluded_rule_path_list,
activate_kw=activate_kw,
**kw)
security.declareProtected(Permissions.ModifyPortalContent,
'expandRuleRelatedToMovement')
def expandRuleRelatedToMovement(self,excluded_rule_path_list=None,
activate_kw=None,**kw):
"""
Some delivery movement may be related to another applied rule than
the one related to the delivery. Delivery movements may be related
to many simulation movements from many different root applied rules,
so it is required to expand the applied rule parent to related
simulation movements.
exclude_rule_path : do not expand this applied rule (or children
applied rule)
"""
excluded_rule_path_list = set(excluded_rule_path_list or ())
to_expand = sorted(set(sm.getParentValue()
for sm in self._getAllRelatedSimulationMovementList()
if sm.getRootAppliedRule().getPath() not in excluded_rule_path_list),
key=lambda x: x.getRelativeUrl())
prev_ar = None
for ar in to_expand:
if not ar.aq_inContextOf(prev_ar):
ar.expand(activate_kw=activate_kw, **kw)
ar.recursiveReindexSimulationMovement(activate_kw=activate_kw)
prev_ar = ar
def updateAppliedRule(self, rule_reference=None, rule_id=None, **kw):
reference = self.getRuleReference()
if (rule_id or rule_reference) != reference:
raise RuntimeError("expected %r as rule reference, got %r"
% (reference, rule_reference))
self._updateSimulation(create_root=1) # should it be always reexpanded ?
def _createRootAppliedRule(self):
portal = self.getPortalObject()
# Only create RAR if we are not in a "too early" or "too late" state.
if self.getSimulationState() not in portal.getPortalDraftOrderStateList():
return super(Delivery, self)._createRootAppliedRule()
security.declareProtected( Permissions.AccessContentsInformation,
'getRootCausalityValueList')
......@@ -894,15 +795,6 @@ class Delivery(XMLObject, ImmobilisationDelivery,
# since the main purpose of this method is superceded
# by IDivergenceController
def getRuleReference(self):
"""Returns an appropriate rule reference."""
method = self._getTypeBasedMethod('getRuleReference')
if method is not None:
return method()
else:
raise SimulationError('%s_getRuleReference script is missing.'
% self.getPortalType().replace(' ', ''))
security.declareProtected( Permissions.AccessContentsInformation,
'getRootSpecialiseValue')
def getRootSpecialiseValue(self, portal_type_list):
......
......@@ -78,12 +78,7 @@ class ImmobilisableItem(Item, Amount):
, PropertySheet.Amortisation
)
# FIXME: ImmobilisableItem have to implement IExpandableItem, but they do
# not have 'expand' method at the time beeing, simulation methods used here
# have different names.
zope.interface.implements(interfaces.IExpandableItem,
interfaces.IImmobilisationItem)
zope.interface.implements(interfaces.IImmobilisationItem)
# IExpandableItem interface implementation
def getSimulationMovementSimulationState(self, simulation_movement):
......@@ -101,12 +96,6 @@ class ImmobilisableItem(Item, Amount):
return 'planned'
return 'draft'
def expand(self, applied_rule_id=None, activate_kw=None, **kw):
"""Expand is not implemented that way for now...
"""
pass
security.declareProtected(Permissions.AccessContentsInformation,
'getImmobilisationRelatedMovementList')
def getImmobilisationRelatedMovementList(self,
......@@ -1076,7 +1065,7 @@ class ImmobilisableItem(Item, Amount):
my_applied_rule = my_applied_rule_list[-1]
# We are now certain we have a single applied rule
# It is time to expand it
my_applied_rule.expand()
my_applied_rule.expand('immediate') # XXX: can it be done by activity ?
security.declareProtected(Permissions.AccessContentsInformation,
'expandAmortisation')
......
......@@ -37,9 +37,11 @@ from Products.ERP5Type.Base import Base
#from Products.ERP5.Core import MetaNode, MetaResource
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Type.TransactionalVariable import getTransactionalVariable
from Products.ERP5.mixin.amount_generator import AmountGeneratorMixin
from Products.ERP5.mixin.composition import CompositionMixin
from Products.ERP5.Document.Amount import Amount
from Products.ERP5.Document.SimulatedDeliveryBuilder import BUILDING_KEY
from zLOG import LOG, WARNING
......@@ -582,6 +584,23 @@ class Movement(XMLObject, Amount, CompositionMixin, AmountGeneratorMixin):
return (len(self.getDeliveryRelatedValueList()) > 0) or\
(len(self.getOrderRelatedValueList()) > 0)
security.declareProtected(Permissions.AccessContentsInformation,
'isGeneratedBySimulation')
def isGeneratedBySimulation(self):
"""
Returns true if the movement is linked to a simulation movement whose
parent is not a root applied rule, even if the movement is being built.
Otherwise, this means the movement is or should be linked to a root
simulation movement.
"""
simulation_movement = self.getDeliveryRelatedValue()
if simulation_movement is not None and \
not simulation_movement.getParentValue().isRootAppliedRule():
return True
building = getTransactionalVariable().get(BUILDING_KEY, ())
return self in building or self.getRootDeliveryValue() in building
# New Causality API
security.declareProtected( Permissions.AccessContentsInformation,
'getOrderQuantity')
......
......@@ -27,10 +27,8 @@
#
##############################################################################
import zope.interface
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet, interfaces
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5.Document.Supply import Supply
class OpenOrder(Supply):
......@@ -45,9 +43,6 @@ class OpenOrder(Supply):
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative interfaces
zope.interface.implements(interfaces.IExpandable)
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
......@@ -59,23 +54,3 @@ class OpenOrder(Supply):
, PropertySheet.Order
, PropertySheet.Version
)
# Expandable Interface Implementation
def expand(self, *args, **kw):
"""
Any Open Order Line / Open Order Cell which does not relate
(aggregate) to a Subscription Item must be expanded
through the default rule.
What would be nice is to use the SubscriptionItemRule to expand
lines one by one so that an Item can be used at any time.
expansion logic is provided by the OpenOrder or by the
SubscriptionItem
Others are expanded by their Item
NOTE-JPS: not sure if it is really necessary to keep this
since only used by one client and tiolive. For tiolive
it will be dropped out
"""
......@@ -29,7 +29,7 @@
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.Utils import deprecated
from Products.ERP5.Document.Delivery import Delivery
from warnings import warn
......@@ -115,74 +115,14 @@ class Order(Delivery):
"""Returns the total quantity for this Order. """
kw.setdefault('portal_type', self.getPortalOrderMovementTypeList())
return Delivery.getTotalQuantity(self, **kw)
def applyToDeliveryRelatedMovement(self, portal_type='Simulation Movement',
method_id='expand',**kw):
"""
Warning: does not work if it was not catalogued immediately
"""
@deprecated
def applyToOrderRelatedMovement(self, method_id='expand', **kw):
# WARNING: does not work if it was not catalogued immediately
# 'order' category is deprecated. it is kept for compatibility.
for my_simulation_movement in self.getDeliveryRelatedValueList(
portal_type='Simulation Movement') or \
self.getOrderRelatedValueList(
portal_type='Simulation Movement'):
# And apply
getattr(my_simulation_movement, method_id)(**kw)
for m in self.contentValues(filter={'portal_type': \
self.getPortalMovementTypeList()}):
# Find related in simulation
for m in self.getMovementList():
for my_simulation_movement in m.getDeliveryRelatedValueList(
portal_type='Simulation Movement') or \
m.getOrderRelatedValueList(
portal_type='Simulation Movement'):
# And apply
getattr(my_simulation_movement, method_id)(**kw)
for c in m.contentValues(filter={'portal_type':
self.getPortalMovementTypeList()}):
for my_simulation_movement in c.getDeliveryRelatedValueList(
portal_type='Simulation Movement') or \
c.getOrderRelatedValueList(
portal_type='Simulation Movement'):
# And apply
getattr(my_simulation_movement, method_id)(**kw)
# 'order' category is deprecated. it is kept for compatibility.
applyToOrderRelatedMovement = applyToDeliveryRelatedMovement
def applyToOrderRelatedAppliedRule(self, method_id='expand',**kw):
my_applied_rule = self.getCausalityRelatedValue( \
portal_type='Applied Rule')
getattr(my_applied_rule.getObject(), method_id)(**kw)
def manage_beforeDelete(self, item, container):
"""
Delete related Applied Rule
"""
for o in self.getCausalityRelatedValueList(portal_type='Applied Rule'):
o.getParentValue().deleteContent(o.getId())
Delivery.manage_beforeDelete(self, item, container)
##########################################################################
# Applied Rule stuff
def updateAppliedRule(self, rule_id=None, rule_reference=None, **kw):
"""XXX FIXME: Kept for compatibility.
updateAppliedRule must be called with a rule_reference in a workflow
script.
"""
if rule_id is None and rule_reference is None:
warn('Relying on a default order rule is deprecated; ' \
'rule_reference must be specified explicitly.',
DeprecationWarning)
rule_reference = 'default_order_rule'
Delivery.updateAppliedRule(self, rule_id=rule_id,
rule_reference=rule_reference, **kw)
def expandAppliedRuleRelatedToOrder(self, activate_kw=None,**kw):
"""
Expand the applied rule related
"""
applied_rule_list = self.getCausalityRelatedValueList(
portal_type='Applied Rule')
for applied_rule in applied_rule_list:
# XXX Missing activate keys
applied_rule.activate(activate_kw=activate_kw).expand(**kw)
......@@ -108,18 +108,3 @@ class PackingList(Delivery):
return 0
return 1
##########################################################################
# Applied Rule stuff
def updateAppliedRule(self, rule_id=None, rule_reference=None, **kw):
"""XXX FIXME: Kept for compatibility.
updateAppliedRule must be called with a rule_reference in a workflow
script.
"""
if rule_id is None and rule_reference is None:
warn('Relying on a default delivery rule is deprecated; ' \
'rule_reference must be specified explicitly.',
DeprecationWarning)
rule_reference = 'default_delivery_rule'
Delivery.updateAppliedRule(self, rule_id=rule_id,
rule_reference=rule_reference, **kw)
......@@ -122,9 +122,8 @@ class QuantitySplitSolver(SolverMixin, ConfigurableMixin, XMLObject):
new_movement.setStopDate(stop_date)
if activate_kw:
new_movement.setDefaultActivateParameterDict({})
# XXX we need to call expand on both simulation_movement and new_movement here?
# simulation_movement.expand(activate_kw=activate_kw)
# new_movement.expand(activate_kw=activate_kw)
simulation_movement.expand(activate_kw=activate_kw)
new_movement.expand(activate_kw=activate_kw)
# Finish solving
if self.getPortalObject().portal_workflow.isTransitionPossible(
self, 'succeed'):
......
......@@ -31,9 +31,16 @@ from zLOG import LOG, BLATHER
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5.mixin.builder import BuilderMixin, SelectMethodError
from Products.ERP5Type.TransactionalVariable import getTransactionalVariable
from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod
from Products.ERP5Type.CopySupport import CopyError, tryMethodCallWithTemporaryPermission
# Quite ugly way to avoid useless expand when building lines
# in a delivery that already have lines and a root applied rule.
# For example, it's normally useless to expand after building
# accounting lines in an invoice with manually created invoice lines.
BUILDING_KEY = 'building_from_portal_simulation'
class SimulatedDeliveryBuilder(BuilderMixin):
"""
Delivery Builder objects allow to gather multiple Simulation Movements
......@@ -137,6 +144,12 @@ class SimulatedDeliveryBuilder(BuilderMixin):
Create the relation between simulation movement
and delivery movement.
"""
delivery = delivery_movement.getExplanationValue()
building = getTransactionalVariable()[BUILDING_KEY]
if delivery in building:
building.add(delivery_movement)
simulation_movement.recursiveReindexObject(activate_kw=dict(
activate_kw or (), tag='built:'+delivery.getPath()))
BuilderMixin._setDeliveryMovementProperties(
self, delivery_movement,
simulation_movement, property_dict,
......@@ -151,12 +164,22 @@ class SimulatedDeliveryBuilder(BuilderMixin):
# Delivery will probably diverge now, but this is not the job of
# Delivery Builder to resolve such problem.
# Use Solver instead.
simulation_movement.edit(delivery_ratio=0)
simulation_movement._setDeliveryRatio(0)
else:
simulation_movement.edit(delivery_ratio=1)
simulation_movement.edit(delivery_value=delivery_movement,
activate_kw=activate_kw)
simulation_movement._setDeliveryRatio(1)
delivery_movement = delivery_movement.getRelativeUrl()
if simulation_movement.getDeliveryList() != [delivery_movement]:
simulation_movement._setDelivery(delivery_movement)
if not simulation_movement.isTempDocument():
try:
getCausalityState = delivery.aq_explicit.getCausalityState
except AttributeError:
return
if getCausalityState() == 'building':
# Make sure no other node is changing state of the delivery
delivery.serializeCausalityState()
else:
delivery.startBuilding()
# Simulation consistency propagation
security.declareProtected(Permissions.ModifyPortalContent,
......@@ -337,6 +360,10 @@ class SimulatedDeliveryBuilder(BuilderMixin):
new_delivery_id = str(delivery_module.generateNewId())
delivery = super(SimulatedDeliveryBuilder, self)._createDelivery(
delivery_module, movement_list, activate_kw)
# Interactions will usually trigger reindexing of related SM when
# simulation state changes. Disable them for this transaction
# because we already do this in _setDeliveryMovementProperties
delivery.updateSimulation(index_related=0)
else:
# from duplicated original delivery
cp = tryMethodCallWithTemporaryPermission(
......@@ -353,6 +380,25 @@ class SimulatedDeliveryBuilder(BuilderMixin):
return delivery
def _processDeliveryLineGroup(self, delivery, movement_group_node,
*args, **kw):
building = getTransactionalVariable().setdefault(BUILDING_KEY, set())
if None in building:
super(SimulatedDeliveryBuilder, self)._processDeliveryLineGroup(
delivery, movement_group_node, *args, **kw)
return
building.add(None)
try:
for movement in movement_group_node.getMovementList():
if not movement.isTempDocument():
building.add(delivery)
break
super(SimulatedDeliveryBuilder, self)._processDeliveryLineGroup(
delivery, movement_group_node, *args, **kw)
finally:
building.remove(None)
building.discard(delivery)
def _createDeliveryLine(self, delivery, movement_list, activate_kw):
"""
Refer to the docstring in GeneratedDeliveryBuilder.
......
......@@ -27,21 +27,16 @@
#
##############################################################################
import transaction
import zope.interface
from AccessControl import ClassSecurityInfo
from Products.CMFCore.utils import getToolByName
from Products.ERP5Type import Permissions, PropertySheet, interfaces
from Products.ERP5Type.TransactionalVariable import getTransactionalVariable
from Products.ERP5.Document.Movement import Movement
from Products.ERP5.ExpandPolicy import policy_dict, TREE_DELIVERED_CACHE_KEY
from zLOG import LOG, WARNING
from Acquisition import aq_base
from Products.ERP5.Document.AppliedRule import TREE_DELIVERED_CACHE_KEY, TREE_DELIVERED_CACHE_ENABLED
from Products.ERP5.mixin.property_recordable import PropertyRecordableMixin
from Products.ERP5.mixin.explainable import ExplainableMixin
......@@ -120,7 +115,8 @@ class SimulationMovement(PropertyRecordableMixin, Movement, ExplainableMixin):
)
# Declarative interfaces
zope.interface.implements(interfaces.IPropertyRecordable, )
zope.interface.implements(interfaces.IExpandable,
interfaces.IPropertyRecordable)
def tpValues(self) :
""" show the content in the left pane of the ZMI """
......@@ -134,22 +130,6 @@ class SimulationMovement(PropertyRecordableMixin, Movement, ExplainableMixin):
"""
return self._baseGetPrice(default) # Call the price method
security.declareProtected( Permissions.AccessContentsInformation,
'getCausalityState')
def getCausalityState(self):
"""
Returns the current state in causality
"""
return getattr(aq_base(self), 'causality_state', 'solved')
security.declareProtected( Permissions.ModifyPortalContent,
'setCausalityState')
def setCausalityState(self, value):
"""
Change causality state
"""
self.causality_state = value
security.declareProtected( Permissions.AccessContentsInformation,
'getSimulationState')
def getSimulationState(self, id_only=1):
......@@ -171,22 +151,19 @@ class SimulationMovement(PropertyRecordableMixin, Movement, ExplainableMixin):
if order is not None:
return order.getSimulationState()
parent = self.getParentValue()
applied_rule = self.getParentValue()
parent = applied_rule.getParentValue()
try:
try:
parent_state = parent.getSimulationState()
except AttributeError:
item = parent.getCausalityValue(
portal_type=self.getPortalItemTypeList())
if interfaces.IExpandableItem.providedBy(item):
return item.getSimulationMovementSimulationState(self)
raise
return parent_to_movement_simulation_state[parent_state]
except (KeyError, AttributeError):
if isinstance(parent, SimulationMovement):
return parent_to_movement_simulation_state[parent.getSimulationState()]
getState = applied_rule.getCausalityValue() \
.aq_explicit.getSimulationMovementSimulationState
except (AttributeError, KeyError):
LOG('SimulationMovement.getSimulationState', WARNING,
'Could not acquire simulation state from %s'
% self.getRelativeUrl(), error=True)
return None
else:
return getState(self)
security.declareProtected( Permissions.AccessContentsInformation,
'getTranslatedSimulationStateTitle')
......@@ -255,35 +232,6 @@ class SimulationMovement(PropertyRecordableMixin, Movement, ExplainableMixin):
#######################################################
# Causality Workflow Methods
security.declareProtected(Permissions.ModifyPortalContent, 'calculate')
def calculate(self):
"""Move related delivery in 'calculating' state by activity
Activity to update causality state is delayed until all related simulation
movement are reindexed.
This method should be only called by
simulation_movement_causality_interaction_workflow.
"""
delivery = self.getDeliveryValue()
if delivery is not None:
delivery = delivery.getRootDeliveryValue()
tv = getTransactionalVariable()
path = self.getPath()
delivery_path = delivery.getPath()
key = 'SimulationMovement.calculate', delivery_path
try:
tv[key].append(path)
except KeyError:
tv[key] = [path]
def before_commit():
method_id_list = ('immediateReindexObject',
'recursiveImmediateReindexObject')
tag = delivery_path + '_calculate'
delivery.activate(tag=tag).Delivery_calculate(activate_kw=
{'after_path_and_method_id': (tv[key], method_id_list)})
tv[key] = None # disallow further calls to 'calculate'
transaction.get().addBeforeCommitHook(before_commit)
security.declarePrivate('_getApplicableRuleList')
def _getApplicableRuleList(self):
""" Search rules that match this movement
......@@ -297,25 +245,32 @@ class SimulationMovement(PropertyRecordableMixin, Movement, ExplainableMixin):
sort_order='descending')
security.declareProtected(Permissions.ModifyPortalContent, 'expand')
def expand(self, **kw):
"""
def expand(self, expand_policy=None, **kw):
"""Update applied rules inside this simulation movement and expand them
Checks all existing applied rules and make sure they still apply.
Checks for other possible rules and starts expansion process (instanciates
applied rules and calls expand on them).
"""
policy_dict[expand_policy](**kw).expand(self)
def _expandNow(self, maybe_expand):
"""
First get all applicable rules,
then, delete all applied rules that no longer match and are not linked to
a delivery,
a delivery, or expand those that still apply,
finally, apply new rules if no rule with the same type is already applied.
"""
tv = getTransactionalVariable()
cache = tv.setdefault(TREE_DELIVERED_CACHE_KEY, {})
cache_enabled = cache.get(TREE_DELIVERED_CACHE_ENABLED, 0)
# enable cache
if not cache_enabled:
cache[TREE_DELIVERED_CACHE_ENABLED] = 1
# XXX: Although policy is "copy everything required to simulation
# movements", we must reindex in case that simulation state has
# changed.
# Also, if this movement is edited (by 'expand' call on the parent),
# there's already a reindexing activity so this does nothing; but if
# 'expand' was deferred for this movement, this will generate a
# second & useless reindexing activity.
# All this could be avoided if each simulation movement remembered
# the previous state.
self.reindexObject()
applicable_rule_dict = {}
for rule in self._getApplicableRuleList():
reference = rule.getReference()
......@@ -339,28 +294,10 @@ class SimulationMovement(PropertyRecordableMixin, Movement, ExplainableMixin):
else:
self._delObject(applied_rule.getId())
else:
applied_rule.expand(**kw)
maybe_expand(rule, applied_rule)
for rule in applicable_rule_list:
rule.constructNewAppliedRule(self, **kw).expand(**kw)
self.setCausalityState('expanded')
# disable and clear cache
if not cache_enabled:
try:
del tv[TREE_DELIVERED_CACHE_KEY]
except KeyError:
pass
security.declareProtected(Permissions.ModifyPortalContent, 'diverge')
def diverge(self):
"""
-> new status -> diverged
Movements which diverge can not be expanded
"""
self.setCausalityState('diverged')
maybe_expand(rule, rule.constructNewAppliedRule(self))
security.declareProtected( Permissions.AccessContentsInformation,
'getExplanationValue')
......@@ -580,7 +517,7 @@ class SimulationMovement(PropertyRecordableMixin, Movement, ExplainableMixin):
# 'recursiveImmediateReindexObject']))
# activity.edit()
def _isTreeDelivered(self, ignore_first=0):
def _isTreeDelivered(self):
"""
checks if subapplied rules of this movement (going down the complete
simulation tree) have a child with a delivery relation.
......@@ -588,32 +525,23 @@ class SimulationMovement(PropertyRecordableMixin, Movement, ExplainableMixin):
see AppliedRule._isTreeDelivered
"""
tv = getTransactionalVariable()
cache = tv.setdefault(TREE_DELIVERED_CACHE_KEY, {})
cache_enabled = cache.get(TREE_DELIVERED_CACHE_ENABLED, 0)
def getTreeDelivered(movement, ignore_first=0):
if not ignore_first:
if len(movement.getDeliveryList()) > 0:
return True
for applied_rule in movement.objectValues():
def getTreeDelivered():
if self.getDeliveryList():
return True
for applied_rule in self.objectValues():
if applied_rule._isTreeDelivered():
return True
return False
if ignore_first:
rule_key = (self.getRelativeUrl(), 1)
else:
rule_key = self.getRelativeUrl()
if cache_enabled:
try:
return cache[rule_key]
except KeyError:
result = getTreeDelivered(self, ignore_first=ignore_first)
cache[rule_key] = result
return result
else:
return getTreeDelivered(self, ignore_first=ignore_first)
try:
cache = getTransactionalVariable()[TREE_DELIVERED_CACHE_KEY]
except KeyError:
return getTreeDelivered()
rule_key = self.getRelativeUrl()
try:
return cache[rule_key]
except KeyError:
cache[rule_key] = result = getTreeDelivered()
return result
security.declareProtected(Permissions.AccessContentsInformation,
'isBuildable')
......
......@@ -180,8 +180,9 @@ class SolverProcess(XMLObject, ActiveProcess):
"""
Start solving
"""
isTransitionPossible = self.getPortalObject().portal_workflow.isTransitionPossible
for solver in self.contentValues(portal_type=self.getPortalObject().getPortalTargetSolverTypeList()):
portal = self.getPortalObject()
isTransitionPossible = portal.portal_workflow.isTransitionPossible
for solver in self.objectValues(portal_type=portal.getPortalTargetSolverTypeList()):
if solver.isTempObject():
solver_type = solver.getPortalTypeValue()
# Since multiple documents may need the same solver, activity must be
......
......@@ -30,19 +30,18 @@
import zope.interface
from AccessControl import ClassSecurityInfo
from Products.CMFCore.utils import getToolByName
from Products.ERP5Type import Permissions, PropertySheet, interfaces
from Products.ERP5Type.Errors import SimulationError
from Products.ERP5.Document.Item import Item
from Products.ERP5.mixin.composition import CompositionMixin
from Products.ERP5.mixin.rule import MovementGeneratorMixin
from Products.ERP5.mixin.rule import MovementGeneratorMixin, SimulableMixin
from Products.ERP5.mixin.periodicity import PeriodicityMixin
from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod
from Products.ERP5Type.Base import Base
from zLOG import LOG
class SubscriptionItem(Item, CompositionMixin, MovementGeneratorMixin, PeriodicityMixin):
class SubscriptionItem(Item, CompositionMixin, MovementGeneratorMixin,
SimulableMixin, PeriodicityMixin):
"""
A SubscriptionItem is an Item which expands itself
into simulation movements which represent the item future.
......@@ -70,37 +69,15 @@ class SubscriptionItem(Item, CompositionMixin, MovementGeneratorMixin, Periodici
)
# Declarative interfaces
zope.interface.implements(interfaces.IExpandableItem,
interfaces.IMovementGenerator,
zope.interface.implements(interfaces.IMovementGenerator,
)
# IExpandable interface implementation
@UnrestrictedMethod # YXU - Is it a good permission setting?
def expand(self, applied_rule_id=None, activate_kw=None, **kw):
"""
Lookup start / stop properties in related Open Order
or Path and expand.
"""
def _createRootAppliedRule(self):
# only try to expand if we are not in draft state
if self.getValidationState() in ('draft', ): # XXX-JPS harcoded
return
return super(SubscriptionItem, self)._createRootAppliedRule()
# do not expand if no bp/stc is applied
if self.getSpecialiseValue() is None:
return
# use hint if provided (but what for ?) XXX-JPS
if applied_rule_id is not None:
portal_simulation = getToolByName(self, 'portal_simulation')
my_applied_rule = portal_simulation[applied_rule_id]
else:
my_applied_rule = self._getRootAppliedRule(activate_kw=activate_kw)
# Pass expand
if my_applied_rule is not None:
my_applied_rule.expand(activate_kw=activate_kw, **kw) # XXX-JPS why **kw ?
# IExpandableItem interface implementation
def getSimulationMovementSimulationState(self, simulation_movement):
"""Returns the simulation state for this simulation movement.
......@@ -120,139 +97,6 @@ class SubscriptionItem(Item, CompositionMixin, MovementGeneratorMixin, Periodici
"""
return False
def getRuleReference(self):
"""Returns an appropriate rule reference.
XXX Copy/Paste from delivery
"""
method = self._getTypeBasedMethod('getRuleReference')
if method is not None:
return method()
else:
raise SimulationError('%s_getRuleReference script is missing.'
% self.getPortalType().replace(' ', ''))
@UnrestrictedMethod # XXX-JPS What is this ?
def updateAppliedRule(self, rule_reference=None, rule_id=None, **kw):
"""
Create a new Applied Rule if none is related, or call expand
on the existing one.
The chosen applied rule will be the validated rule with reference ==
rule_reference, and the higher version number.
"""
if rule_id is not None:
from warnings import warn
warn('rule_id to updateAppliedRule is deprecated; use rule_reference instead',
DeprecationWarning)
rule_reference = rule_id
if rule_reference is None:
return
portal_rules = getToolByName(self, 'portal_rules')
res = portal_rules.searchFolder(reference=rule_reference,
validation_state="validated", sort_on='version',
sort_order='descending') # XXX validated is Hardcoded !
if len(res) > 0:
rule_id = res[0].getId()
else:
raise ValueError, 'No such rule as %r is found' % rule_reference
self._createAppliedRule(rule_id, **kw)
def _createAppliedRule(self, rule_id, activate_kw=None, **kw):
"""
Create a new Applied Rule is none is related, or call expand
on the existing one.
"""
# Look up if existing applied rule
my_applied_rule_list = self.getCausalityRelatedValueList(
portal_type='Applied Rule')
my_applied_rule = None
if len(my_applied_rule_list) == 0:
if self.isSimulated():
# No need to create a DeliveryRule
# if we are already in the simulation process
pass
else:
# Create a new applied order rule (portal_rules.order_rule)
portal_rules = getToolByName(self, 'portal_rules')
portal_simulation = getToolByName(self, 'portal_simulation')
my_applied_rule = portal_rules[rule_id].\
constructNewAppliedRule(portal_simulation,
activate_kw=activate_kw)
# Set causality
my_applied_rule.setCausalityValue(self)
# We must make sure this rule is indexed
# now in order not to create another one later
my_applied_rule.reindexObject(activate_kw=activate_kw, **kw)
elif len(my_applied_rule_list) == 1:
# Re expand the rule if possible
my_applied_rule = my_applied_rule_list[0]
else:
raise SimulationError('Delivery %s has more than one applied'
' rule.' % self.getRelativeUrl())
my_applied_rule_id = None
expand_activate_kw = {}
if my_applied_rule is not None:
my_applied_rule_id = my_applied_rule.getId()
expand_activate_kw['after_path_and_method_id'] = (
my_applied_rule.getPath(),
['immediateReindexObject', 'recursiveImmediateReindexObject'])
# We are now certain we have a single applied rule
# It is time to expand it
self.activate(activate_kw=activate_kw, **expand_activate_kw).expand(
applied_rule_id=my_applied_rule_id,
activate_kw=activate_kw, **kw)
def _getRootAppliedRule(self, tested_base_category_list=None,
activate_kw=None):
"""
Returns existing root applied rule or, if none,
create a new one a return it
"""
# Look up if existing applied rule
my_applied_rule_list = self.getCausalityRelatedValueList(
portal_type='Applied Rule')
my_applied_rule = None
if len(my_applied_rule_list) == 0:
if self.isSimulated():
# No need to create a DeliveryRule
# if we are already in the simulation process
pass
else:
# Create a new applied order rule (portal_rules.order_rule)
portal_rules = getToolByName(self, 'portal_rules')
portal_simulation = getToolByName(self, 'portal_simulation')
search_rule_kw = { 'sort_on': 'version', 'sort_order': 'descending' }
if self.getRuleReference() is None:
rule_value_list = portal_rules.searchRuleList(self, **search_rule_kw)
if len(rule_value_list) > 1:
raise SimulationError('Expandable Document %s has more than one'
' matching rule.' % self.getRelativeUrl())
else:
rule_value_list = portal_rules.searchRuleList(self,
reference=self.getRuleReference(), **search_rule_kw)
if len(rule_value_list):
rule_value = rule_value_list[0]
my_applied_rule = rule_value.constructNewAppliedRule(portal_simulation,
activate_kw=activate_kw)
# Set causality
my_applied_rule.setCausalityValue(self)
# We must make sure this rule is indexed
# now in order not to create another one later
my_applied_rule.reindexObject(activate_kw=activate_kw) # XXX-JPS removed **kw
elif len(my_applied_rule_list) == 1:
# Re expand the rule if possible
my_applied_rule = my_applied_rule_list[0]
else:
raise SimulationError('Expandable Document %s has more than one root'
' applied rule.' % self.getRelativeUrl())
return my_applied_rule
# IMovementGenerator interface implementation
def _getUpdatePropertyDict(self, input_movement):
# Default implementation bellow can be overriden by subclasses
......@@ -268,7 +112,6 @@ class SubscriptionItem(Item, CompositionMixin, MovementGeneratorMixin, Periodici
"""
from Products.ERP5Type.Document import newTempMovement
result = []
catalog_tool = getToolByName(self, 'portal_catalog')
# Try to find the source open order
open_order_movement_list = self.getAggregateRelatedValueList(
......@@ -293,7 +136,7 @@ class SubscriptionItem(Item, CompositionMixin, MovementGeneratorMixin, Periodici
price = movement.getPrice()
price_currency = movement.getPriceCurrency()
base_application_list = movement.getBaseApplicationList()
base_contribution_list = movement.getBaseContributionList()
base_contribution_list = movhement.getBaseContributionList()
use_list = movement.getUseList()
specialise = movement.getSpecialise()
......
......@@ -112,7 +112,7 @@ class TradeModelSolver(AcceptSolver):
if not simulation_movement.isPropertyRecorded(property_id):
simulation_movement.recordProperty(property_id)
simulation_movement.setMappedProperty(property_id, value)
simulation_movement.expand(activate_kw=activate_kw)
simulation_movement.expand('immediate')
# Third, adopt changes on trade model related lines.
# XXX non-linear case is not yet supported.
......
......@@ -125,7 +125,8 @@ class UnifySolver(AcceptSolver):
if not simulation_movement.isPropertyRecorded(solved_property):
simulation_movement.recordProperty(solved_property)
simulation_movement.setMappedProperty(solved_property, value)
simulation_movement.expand(activate_kw=activate_kw)
# XXX: would it be safe to expand by activity ?
simulation_movement.expand('immediate')
# Finish solving
if portal.portal_workflow.isTransitionPossible(self, 'succeed'):
self.succeed()
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2012 Nexedi SARL and Contributors. All Rights Reserved.
# Julien Muchembled <jm@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly advised to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
##############################################################################
from time import time
import transaction
from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod
from Products.ERP5Type.Utils import convertToLowerCase
from Products.ERP5Type.TransactionalVariable import getTransactionalVariable
# XXX: Consider moving it to ERP5Type if it implements recursion policies
# for anything other than expand.
# XXX: Policy of deferred expands currently is currently hardcoded to the
# preferred one, which is itself hardcoded to "vertical_time_bound".
# If any parameter is added to policies in order to make them customizable,
# Base class should probably handle this automatically by:
# - keeping all parameters in a 'kw' attribute and;
# - activating with something like 'expand(policy, **self.kw)'
# It may also be better if that 'kw' does not mix up several kinds of
# parameters, for example those that are specific to the policy
# (e.g. policy_kw), and other for expand() itself (e.g. expand_kw).
# Any extension to the API must be reviewed first.
# Put there to avoid circular import loop.
TREE_DELIVERED_CACHE_KEY = 'AppliedRule._isTreeDelivered'
policy_dict = {} # {None: preferred, 'foo_bar': FooBar}
VERTICAL_EXPAND_TIMEOUT = 5 # XXX: hardcoded for the moment
class _Policy(object):
"""Base class of policies for RuleMixin.expand and SimulationMovement.expand
"""
class __metaclass__(type):
"""Automatically register policies in policy_dict"""
def __init__(cls, name, bases, d):
type.__init__(cls, name, bases, d)
if name[0] != '_':
policy_dict[convertToLowerCase(name)[1:]] = cls
def __init__(self, activate_kw=None):
self.activate_kw = activate_kw
@UnrestrictedMethod
def expand(self, *args):
"""Initialize context, and really start to expand"""
tv = getTransactionalVariable()
assert TREE_DELIVERED_CACHE_KEY not in tv, "already expanding"
self.context = args[-1]
with self.context.defaultActivateParameterDict(self.activate_kw, True):
tv[TREE_DELIVERED_CACHE_KEY] = {}
try:
self(*args)
finally:
del tv[TREE_DELIVERED_CACHE_KEY]
# lazy computation of root applied rule path
def __getattr__(self, attr):
if attr == 'merge_parent':
self.merge_parent = value = self.context.getRootAppliedRule().getPath()
else:
object.__getattribute__(self, attr)
return value
def deferAll(self):
self.test = self.activate
def activate(self, context):
context.activate(merge_parent=self.merge_parent) \
.expand(activate_kw=self.activate_kw)
def __call__(self, *args):
context = args[-1]
if self.test(context):
args[0]._expandNow(self, *args[1:])
class Deferred(_Policy):
"""Do not expand anything in the current transaction, but do it by activity"""
# We won't expand at all so we override expand() to avoid wasting time on
# initializing anything.
def expand(self, *args):
context = args[-1]
kw = self.activate_kw
context.activate(merge_parent=context.getRootAppliedRule().getPath(),
**(kw or {})).expand(activate_kw=kw)
class Immediate(_Policy):
"""Expand everything immediately"""
# Optimize by overriding '__call__' instead of 'test'
#test = lambda *args: True
def __call__(self, *args):
args[0]._expandNow(self, *args[1:])
class VerticalTimeBound(_Policy):
"""Vertical recursion, limited by duration
Expand immediately only if the current transaction is young enough.
Defer by activity otherwise.
"""
def __init__(self, **kw):
super(VerticalTimeBound, self).__init__(**kw)
self.stop = transaction.get().start_time + VERTICAL_EXPAND_TIMEOUT
def test(self, context):
if time() < self.stop:
return True
self.deferAll()
self.test(context)
# XXX: Should be a function reading system preferences
preferred = VerticalTimeBound
policy_dict[None] = preferred
......@@ -322,12 +322,26 @@ class FakeMovement:
"""
return self.__movement_list
def setDeliveryValue(self, object):
def isTempDocument(self):
for movement in self.__movement_list:
if movement.isTempDocument():
return True
return False
def _setDelivery(self, object):
"""
Set Delivery value for each movement
"""
for movement in self.__movement_list:
movement.edit(delivery_value=object)
movement._setDelivery(object)
def getDeliveryList(self):
"""
Only used to know if _setDeliveryValue needs to be called.
Be careful: behaviour differs from CMFCategory in that returned
list may include None, when there is at least 1 unlinked SM.
"""
return list(set(x.getDelivery() for x in self.__movement_list))
def getDeliveryValue(self):
"""
......@@ -335,13 +349,10 @@ class FakeMovement:
configure DeliveryBuilder well...).
Be careful.
"""
result = None
for movement in self.__movement_list:
mvt_delivery = movement.getDeliveryValue()
if mvt_delivery is not None:
result = mvt_delivery
break
return result
return mvt_delivery
def getRelativeUrl(self):
"""
......@@ -351,7 +362,7 @@ class FakeMovement:
"""
return self.__movement_list[0].getRelativeUrl()
def setDeliveryRatio(self, delivery_ratio):
def _setDeliveryRatio(self, delivery_ratio):
"""
Calculate delivery_ratio
"""
......@@ -359,15 +370,15 @@ class FakeMovement:
for movement in self.__movement_list:
total_quantity += movement.getMappedProperty('quantity')
if total_quantity != 0:
if total_quantity:
for movement in self.__movement_list:
quantity = movement.getMappedProperty('quantity')
movement.edit(delivery_ratio=quantity*float(delivery_ratio)/total_quantity)
movement._setDeliveryRatio(quantity*float(delivery_ratio)/total_quantity)
else:
# Distribute equally ratio to all movement
# Distribute equally ratio to all movements
mvt_ratio = float(delivery_ratio) / len(self.__movement_list)
for movement in self.__movement_list:
movement.edit(delivery_ratio=mvt_ratio)
movement._setDeliveryRatio(mvt_ratio)
def getPrice(self):
"""
......@@ -450,19 +461,12 @@ class FakeMovement:
price_dict = self._getPriceDict()
return sum(price * quantity for price, quantity in price_dict.items())
def recursiveReindexObject(self):
def recursiveReindexObject(self, *args, **kw):
"""
Reindex all movements
"""
for movement in self.getMovementList():
movement.recursiveReindexObject()
def immediateReindexObject(self):
"""
Reindex immediately all movements
"""
for movement in self.getMovementList():
movement.immediateReindexObject()
movement.recursiveReindexObject(*args, **kw)
def getPath(self):
"""
......@@ -509,23 +513,6 @@ class FakeMovement:
else:
raise NotImplementedError
def edit(self, activate_kw=None, **kw):
"""
Written in order to call edit in delivery builder,
as it is the generic way to modify object.
activate_kw is here for compatibility reason with Base.edit,
it will not be used here.
"""
for key in kw.keys():
if key == 'delivery_ratio':
self.setDeliveryRatio(kw[key])
elif key == 'delivery_value':
self.setDeliveryValue(kw[key])
else:
raise FakeMovementError,\
"Could not call edit on Fakemovement with parameters: %r" % key
def __repr__(self):
repr_str = '<%s object at 0x%x for %r' % (self.__class__.__name__,
id(self),
......
......@@ -79,5 +79,5 @@ class Copy(TargetSolver):
simulation_movement.recordProperty(property_id)
simulation_movement.edit(**value_dict)
# XXX can we use activity for further expand?
simulation_movement.expand()
# XXX: would it be safe to expand by activity ?
simulation_movement.expand('immediate')
......@@ -73,8 +73,8 @@ class CopyAndPropagate(TargetSolver):
quantity_ratio=quantity_ratio,
value_dict=value_dict,
property_id=property_id)
# XXX can we use activity for further expand?
simulation_movement.expand()
# XXX: would it be safe to expand by activity ?
simulation_movement.expand('immediate')
def _solveRecursively(self, simulation_movement, is_last_movement=1,
quantity_ratio=None, value_dict=None,
......
......@@ -98,11 +98,11 @@ class SplitAndDefer(CopyToTarget):
if stop_date is not None:
new_movement.recordProperty('stop_date')
new_movement.edit(stop_date=stop_date)
new_movement.activate(**self.additional_parameters).expand()
new_movement.expand(activate_kw=self.additional_parameters)
# adopt new quantity on original simulation movement
simulation_movement.edit(quantity=new_movement_quantity)
simulation_movement.setDefaultActivateParameterDict(self.activate_kw)
simulation_movement.activate(**self.additional_parameters).expand()
simulation_movement.expand(activate_kw=self.additional_parameters)
# SplitAndDefer solves the divergence at the current level, no need to
# backtrack.
......@@ -26,11 +26,13 @@
#
##############################################################################
from zLOG import LOG, INFO
from Products.ERP5Type.Tool.BaseTool import BaseTool
from AccessControl import ClassSecurityInfo
from Products.ERP5Type.Globals import InitializeClass, DTMLFile
from Products.ERP5Type import Permissions
from Products.ERP5 import _dtmldir
from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod
class RuleTool(BaseTool):
"""
......@@ -135,5 +137,15 @@ class RuleTool(BaseTool):
return rule_list
security.declarePrivate('updateSimulation')
@UnrestrictedMethod
def updateSimulation(self, message_list):
expandable_dict = {}
for m in message_list:
expandable_dict.setdefault(m[0], {}).update(m[2])
for expandable, kw in expandable_dict.iteritems():
LOG("RuleTool", INFO, "Updating simulation for %s: %r"
% (expandable.getPath(), kw))
expandable._updateSimulation(**kw)
InitializeClass(RuleTool)
......@@ -54,11 +54,6 @@
context.setSourceReference(None)\n
context.setDestinationReference(None)\n
context.setSolver(None)\n
\n
# Initialize Causality Workflow\n
if hasattr(context, \'startBuilding\'):\n
context.startBuilding()\n
context.updateCausalityState()\n
</string> </value>
</item>
<item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>error_list = []\n
return_list = []\n
\n
for object in context.portal_simulation.objectValues():\n
# Reexpand to propagate new rules\n
object.expand()\n
\n
for object in context.portal_simulation.objectValues():\n
#print "#### Indexing inside the folder %s ####" % \'portal_simulation\'\n
# Reindex\n
error_list += context.reindexAll(object=object,request=context)\n
\n
nb_types = {}\n
\n
for error in error_list:\n
# We count the number of each portal type\n
if error[1]==\'portal_type\':\n
type = error[3]\n
if nb_types.has_key(type):\n
nb_types[type] = nb_types[type] + 1\n
else:\n
nb_types[type] = 1\n
else:\n
#print error\n
return_list.append(error)\n
\n
for type in nb_types.keys():\n
# Find the number of each portal type in the catalog\n
count_result = context.portal_catalog.countResults(portal_type=type)\n
nb_catalog = count_result[0][0]\n
if nb_types[type] != nb_catalog:\n
message = "XXX Warning for %s: there is %i lines in the catalog instead of %i" % \\\n
(type,nb_catalog,nb_types[type])\n
return_list.append((\'Count Error\', \'PortalRoot_reindexAll\',1,message))\n
#else: print "%s: %i" % (type,nb_types[type])\n
\n
return return_list\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>request=None</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>ERP5Site_reindexSimulation</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1052.3622"
height="744.09448"
id="svg2"
version="1.1"
inkscape:version="0.48.3.1 r9886"
sodipodi:docname="simulation.svg">
<title
id="title3064">Interactions and activity dependencies in simulation</title>
<defs
id="defs4">
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Lstart"
style="overflow:visible">
<path
id="path4232"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt"
transform="scale(0.8) translate(12.5,0)" />
</marker>
<marker
inkscape:stockid="DotM"
orient="auto"
refY="0.0"
refX="0.0"
id="DotM"
style="overflow:visible">
<path
id="path4824"
d="M -2.5,-1.0 C -2.5,1.7600000 -4.7400000,4.0 -7.5,4.0 C -10.260000,4.0 -12.5,1.7600000 -12.5,-1.0 C -12.5,-3.7600000 -10.260000,-6.0 -7.5,-6.0 C -4.7400000,-6.0 -2.5,-3.7600000 -2.5,-1.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt"
transform="scale(0.4) translate(7.4, 1)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Lend"
style="overflow:visible;">
<path
id="path5518"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lend-6"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path5518-6"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
transform="matrix(-0.8,0,0,-0.8,-10,0)" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.74318519"
inkscape:cx="387.99291"
inkscape:cy="372.04724"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:showpageshadow="true"
units="mm"
fit-margin-top="1"
fit-margin-bottom="1"
fit-margin-left="1"
fit-margin-right="1"
inkscape:snap-object-midpoints="false"
inkscape:snap-bbox="false"
inkscape:connector-spacing="10"
inkscape:window-width="1280"
inkscape:window-height="756"
inkscape:window-x="-4"
inkscape:window-y="-4"
inkscape:window-maximized="1">
<inkscape:grid
type="xygrid"
id="grid3022"
units="mm"
empspacing="10"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true"
spacingx="5mm"
spacingy="5mm"
dotted="true" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>Interactions and activity dependencies in simulation</dc:title>
<dc:date>2012-05-29</dc:date>
<dc:description />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Calque 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-308.26449)">
<text
xml:space="preserve"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:Monospace"
x="70.866142"
y="396.84717"
id="text3024"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3026"
x="70.866142"
y="396.84717">build</tspan></text>
<rect
style="fill:none;stroke:#000000;stroke-width:1.77165353;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="rect5230"
width="106.29922"
height="53.149612"
x="53.149601"
y="361.41409"
ry="26.574806" />
<text
xml:space="preserve"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:Monospace"
x="425.1969"
y="379.13065"
id="text3024-0"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3026-8"
x="425.1969"
y="379.13065">SM.recursiveImmediateReindexObject</tspan><tspan
sodipodi:role="line"
x="425.1969"
y="401.63065"
id="tspan5261"> tag = built:&lt;delivery_path&gt;</tspan></text>
<rect
style="fill:none;stroke:#000000;stroke-width:1.77165353;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="rect5230-5"
width="407.48029"
height="70.866119"
x="407.48035"
y="343.69757" />
<text
xml:space="preserve"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:Monospace"
x="478.3465"
y="503.14636"
id="text3024-0-0"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3026-8-6"
x="478.3465"
y="503.14636">D._updateSimulation(create_root, index_related,</tspan><tspan
sodipodi:role="line"
x="478.3465"
y="525.64636"
id="tspan5292"> expand_root, expand_related)</tspan><tspan
sodipodi:role="line"
x="478.3465"
y="548.14636"
id="tspan5261-4"> tag = expand:&lt;delivery_path&gt;</tspan><tspan
sodipodi:role="line"
x="478.3465"
y="570.64636"
id="tspan5290"> after_tag = build:&lt;delivery_path&gt;</tspan></text>
<rect
style="fill:none;stroke:#000000;stroke-width:1.77165353;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="rect5230-5-6"
width="549.21259"
height="124.01569"
x="460.62994"
y="467.71338"
inkscape:connector-avoid="true" />
<text
xml:space="preserve"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:Monospace"
x="70.866165"
y="591.72913"
id="text3024-0-3"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="70.866165"
y="591.72913"
id="tspan5261-0">D.Delivery_calculate</tspan><tspan
sodipodi:role="line"
x="70.866165"
y="614.22913"
id="tspan5323"> tag = expand:&lt;delivery_path&gt;</tspan></text>
<rect
style="fill:none;stroke:#000000;stroke-width:1.77165353;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="rect5230-5-5"
width="354.33069"
height="70.866112"
x="53.149612"
y="556.29602"
inkscape:connector-avoid="true" />
<path
style="fill:none;stroke:#000000;stroke-width:0.99999988;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:7.99999998, 7.99999998;stroke-dashoffset:0;marker-end:url(#Arrow1Lend)"
d="m 159.44881,380.35897 248.0315,0"
id="path5327"
inkscape:connector-type="polyline"
inkscape:connector-curvature="3"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:7.99999992, 7.99999992;stroke-dashoffset:0;marker-end:url(#Arrow1Lend)"
d="m 159.44883,396.84715 301.1811,70.86613"
id="path5329"
inkscape:connector-type="polyline"
inkscape:connector-curvature="3"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:7.99999988, 7.99999988;stroke-dashoffset:0;marker-end:url(#Arrow1Lend)"
d="m 106.29921,414.5637 0,141.73228"
id="path5329-4"
inkscape:connector-type="polyline"
inkscape:connector-curvature="3"
sodipodi:nodetypes="cc" />
<text
xml:space="preserve"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:Monospace"
x="53.149605"
y="733.46136"
id="text6720"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="53.149605"
y="733.46136"
id="tspan6724">startBuilding / calculate</tspan></text>
<rect
style="fill:none;stroke:#000000;stroke-width:1.77165341;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="rect5230-4"
width="301.18112"
height="53.149609"
x="35.433048"
y="698.02826"
ry="26.574804" />
<path
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:8.0000002, 8.0000002;stroke-dashoffset:0;marker-mid:none;marker-end:url(#Arrow1Lend-6)"
d="m 177.16535,627.16208 0,70.86618"
id="path7170"
inkscape:connector-type="polyline"
inkscape:connector-curvature="3" />
<text
xml:space="preserve"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:Monospace"
x="53.14959"
y="892.91022"
id="text3024-0-3-2"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="53.14959"
y="892.91022"
id="tspan5261-0-9">D.updateCausalityState</tspan><tspan
sodipodi:role="line"
x="53.14959"
y="915.41022"
id="tspan5323-4"> after_tag = expand:&lt;delivey_path&gt;</tspan><tspan
sodipodi:role="line"
x="53.14959"
y="937.91022"
id="tspan7567"> built:&lt;delivery_path&gt;</tspan></text>
<rect
style="fill:none;stroke:#000000;stroke-width:1.77165353;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="rect5230-5-5-3"
width="407.48035"
height="106.29918"
x="35.433037"
y="857.47711"
inkscape:connector-avoid="true" />
<path
style="fill:none;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:8.00000011, 8.00000011;stroke-dashoffset:0;marker-mid:none;marker-end:url(#Arrow1Lend-6);display:inline"
d="m 177.16535,751.17786 0,106.29922"
id="path7569"
inkscape:connector-type="polyline"
inkscape:connector-curvature="3"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Lend-6)"
d="m 354.33071,857.47707 0,-230.31495"
id="path7939"
inkscape:connector-type="polyline"
inkscape:connector-curvature="3"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#DotM);marker-end:url(#Arrow1Lend-6);display:inline"
d="m 425.19685,538.57944 35.43307,0"
id="path8125"
inkscape:connector-type="polyline"
inkscape:connector-curvature="3"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Lend-6)"
d="m 637.79528,467.7133 0,-53.1496"
id="path8127"
inkscape:connector-type="polyline"
inkscape:connector-curvature="3"
inkscape:transform-center-x="17.716536"
inkscape:transform-center-y="-246.25662" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Lend-6)"
d="m 425.19685,857.47707 0,-442.91338"
id="path4597"
inkscape:connector-type="polyline"
inkscape:connector-curvature="3"
sodipodi:nodetypes="cc" />
<text
xml:space="preserve"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:Monospace"
x="566.92914"
y="804.32758"
id="text3024-0-3-3"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="566.92914"
y="804.32758"
id="tspan5323-7">D._localBuild</tspan><tspan
sodipodi:role="line"
x="566.92914"
y="826.82758"
id="tspan3839"> after_tag = expand:&lt;delivery_path&gt;</tspan></text>
<rect
style="fill:none;stroke:#000000;stroke-width:1.77165353;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="rect5230-5-5-5"
width="425.19684"
height="70.866112"
x="549.21259"
y="768.89447"
inkscape:connector-avoid="true" />
<text
xml:space="preserve"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:Monospace"
x="513.77954"
y="680.31171"
id="text3024-0-3-3-3"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="513.77954"
y="680.31171"
id="tspan5323-7-5">reindexing</tspan><tspan
sodipodi:role="line"
x="513.77954"
y="702.81171"
id="tspan3839-6"> tag = expand:&lt;delivery_path&gt;</tspan></text>
<rect
style="fill:none;stroke:#000000;stroke-width:1.77165353;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="rect5230-5-5-5-2"
width="354.33075"
height="70.866112"
x="496.06299"
y="644.8786"
inkscape:connector-avoid="true" />
<text
xml:space="preserve"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:Monospace"
x="513.77942"
y="928.34332"
id="text3024-0-3-3-9"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="513.77942"
y="928.34332"
id="tspan5323-7-1">expand</tspan><tspan
sodipodi:role="line"
x="513.77942"
y="950.84332"
id="tspan3839-2"> tag = expand:&lt;delivery_path&gt;</tspan></text>
<rect
style="fill:none;stroke:#000000;stroke-width:1.77165353;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="rect5230-5-5-5-7"
width="354.33075"
height="70.866112"
x="496.06296"
y="892.91022"
inkscape:connector-avoid="true" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Lend-6);display:inline"
d="m 921.25984,768.89441 0,-177.16536"
id="path4453"
inkscape:connector-type="polyline"
inkscape:connector-curvature="3" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#DotM);marker-end:url(#Arrow1Lend-6)"
d="m 425.19685,680.31173 70.86614,-2e-5"
id="path4639"
inkscape:connector-type="polyline"
inkscape:connector-curvature="3"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:8, 8;stroke-dashoffset:0;marker-end:url(#Arrow1Lend-6)"
d="m 513.77953,892.91015 0,-177.16535"
id="path4825"
inkscape:connector-type="polyline"
inkscape:connector-curvature="3" />
<path
style="fill:none;stroke:#000000;stroke-width:0.99921262;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:7.99370116, 7.99370116;stroke-dashoffset:0;marker-end:url(#Arrow1Lend-6)"
d="M 496.06299,892.91016 372.04724,627.16215"
id="path3049"
inkscape:connector-type="polyline"
inkscape:connector-curvature="3" />
<path
style="fill:none;stroke:#000000;stroke-width:0.99921262;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Lend-6)"
d="m 442.91338,875.19362 262.74802,0 c 1.5,0 3,-1.5 3,-3 l 0,-32.43307"
id="path3048"
inkscape:connector-type="orthogonal"
inkscape:connector-curvature="3"
sodipodi:nodetypes="ccc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Lend-6)"
d="m 442.91339,928.34322 53.14961,0"
id="path4198"
inkscape:connector-type="polyline"
inkscape:connector-curvature="3" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Lend-6)"
d="m 744.09449,839.76055 0,53.1496"
id="path4384"
inkscape:connector-type="polyline"
inkscape:connector-curvature="3" />
<path
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:8, 8;stroke-dashoffset:0;marker-end:url(#Arrow1Lend-6)"
d="m 708.66142,591.72905 0,53.14961"
id="path4570"
inkscape:connector-type="polyline"
inkscape:connector-curvature="3" />
<path
style="fill:none;stroke:#000000;stroke-width:0.99921262;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:7.99370079, 7.99370079;stroke-dashoffset:0;marker-end:url(#Arrow1Lend-6)"
d="M 70.866142,414.5637 C 35.433071,556.29598 35.433071,627.16212 53.149606,698.02826"
id="path3053"
sodipodi:nodetypes="cc"
inkscape:connector-curvature="3" />
<path
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:8, 8;stroke-dashoffset:0;marker-end:url(#Arrow1Lend-6)"
d="m 992.12598,591.72905 0,336.61417 -141.73228,0"
id="path4214"
inkscape:connector-type="orthogonal"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#DotM)"
d="m 549.2126,804.32748 -194.88189,0"
id="path4402"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Lend-6);display:inline"
d="m 708.66142,768.89441 0,-53.14961"
id="path4590"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-size:14px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
x="519.49603"
y="871.1936"
id="text4778"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4780"
x="519.49603"
y="871.1936">after_path_and_method_id</tspan></text>
<text
xml:space="preserve"
style="font-size:14px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
x="-499.53085"
y="149.93913"
id="text4790"
sodipodi:linespacing="125%"
transform="matrix(0.20867807,-0.97798439,0.97798439,0.20867807,0,0)"
inkscape:transform-center-x="-21.15626"
inkscape:transform-center-y="15.10145"><tspan
sodipodi:role="line"
id="tspan4792"
x="-499.53085"
y="149.93913">_setObject</tspan></text>
<text
xml:space="preserve"
style="font-size:14px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
x="875.2049"
y="-69.862999"
id="text4786-7"
sodipodi:linespacing="125%"
transform="matrix(0.43080996,0.90244267,-0.90244267,0.43080996,0,0)"><tspan
sodipodi:role="line"
id="tspan4788-5"
x="875.2049"
y="-69.862999">_set*</tspan></text>
<path
style="fill:none;stroke:#000000;stroke-width:0.99921262;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:7.99370079, 7.99370079;stroke-dashoffset:0;marker-end:url(#Arrow1Lend-6)"
d="m 779.52756,892.91015 0,-35.43307 53.14961,0 0,35.43307"
id="path3068"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-size:18px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
x="35.433071"
y="999.20935"
id="text3066"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3068"
x="35.433071"
y="999.20935">This describes activity messages related to Simulation Tool when a Delivery Builder is invoked.</tspan><tspan
sodipodi:role="line"
x="35.433071"
y="1021.7094"
id="tspan3070">Continuous lines represent dependencies. Dashed lines show calls: if target is squared, then it's by activity.</tspan><tspan
sodipodi:role="line"
x="35.433071"
y="1044.2094"
id="tspan3072" /></text>
<path
style="fill:none;stroke:#000000;stroke-width:0.99921260000000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:7.99370079000000011, 7.99370079000000011;marker-end:url(#Arrow1Lend-6);stroke-dashoffset:0;marker-start:url(#Arrow1Lstart)"
d="m 885.82677,768.89441 c 0,-159.44883 0,-159.44883 -354.33071,-159.44883 -194.88189,0 17.71654,-88.58268 -389.76378,-194.88188"
id="path3074"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csc" />
</g>
</svg>
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2009 Nexedi SA and Contributors. All Rights Reserved.
# Jean-Paul Smets-Solanes <jp@nexedi.com>
# Copyright (c) 2012 Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
......@@ -29,29 +28,21 @@
"""
Products.ERP5.interfaces.expandable
"""
from zope.interface import Interface
class IExpandable(Interface):
"""Common Interface for Applied Rules and Simulation Movements
"""
An Expandable class provides methods which trigger
the generation of the root applied rule of a simulation tree
and its expansion. Classes which implement IExpandable include
Deliveries (whenever can be the cause of an Applied Rule),
Items (whenever they are the cause of a movement sequence)
such as Subscription Items or Immobilisation Items, Movements
(which have been previously built).
"""
def expand(applied_rule_id=None, activate_kw=None, **kw):
def expand(expand_policy=None, activate_kw=None):
"""
Expand the current Expandable class into the simulation.
If no applied_rule_id is provided, try first to find
appropriate applied rule if any to start expansion process.
Update subobjects of this document and expand them
expand_policy -- string defining whether a node in the simulation tree
should be expand immediately or in a separate activity,
or None to use the preferred policy
applied_rule_id -- a hint parameter (optional), which can
be provided to reindex the whole
simulation tree from the root applied rule
activate_kw -- activity parameters, required to control
activity constraints
activate_kw -- (TO BE EXPLAINED BY KAZ)
Available policies: immediate, deferred, vertical_time_bound
"""
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2011 Nexedi SA and Contributors. All Rights Reserved.
#
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
"""
Products.ERP5.interfaces.expandable_item
"""
from Products.ERP5.interfaces.expandable import IExpandable
class IExpandableItem(IExpandable):
""" An expandable item is an item that generate simulation, such as a
Subscription Item or an Immobilisation Item.
Such items are also responsible for returning the simulation state of the
movements they build.
"""
def getSimulationMovementSimulationState(simulation_movement):
"""Returns the simulation state of this simulation movement, unless it is
built and related to a delivery.
"""
......@@ -37,8 +37,7 @@ class IRule(IMovementCollectionUpdater):
Documents which implement IRule can be used to
expand applied rules in ERP5 simulation.
"""
def constructNewAppliedRule(context, id=None,
activate_kw=None, **kw):
def constructNewAppliedRule(context, **kw):
"""
Create a new applied rule in the context.
......@@ -48,13 +47,10 @@ class IRule(IMovementCollectionUpdater):
context -- usually, a parent simulation movement of the
newly created applied rule
activate_kw -- activity parameters, required to control
activity constraints
kw -- XXX-JPS probably wrong interface specification
kw -- optional parameters which can be passed to Folder API
"""
def expand(applied_rule, **kw):
def expand(applied_rule, expand_policy=None, activate_kw=None):
"""
Expand this applied rule to create new documents inside the
applied rule.
......@@ -66,6 +62,14 @@ class IRule(IMovementCollectionUpdater):
of compensation are implemented through
IMovementCollectionUpdater API
kw -- XXX-JPS probably wrong interface specification
activate_kw should probably be defined explicitely here
applied_rule -- applied rule to expand
expand_policy -- string defining whether a node in the simulation tree
should be expand immediately or in a separate activity,
or None to use the preferred policy
activate_kw -- activity parameters, required to control
activity constraints
Available policies: immediate, deferred, vertical_time_bound
"""
......@@ -26,12 +26,16 @@
#
##############################################################################
import transaction
import zope.interface
from AccessControl import ClassSecurityInfo
from Acquisition import aq_base
from Products.CMFCore.utils import getToolByName
from Products.ERP5Type import Permissions, interfaces
from Products.ERP5Type.Base import Base
from Products.ERP5Type.Core.Predicate import Predicate
from Products.ERP5Type.Errors import SimulationError
from Products.ERP5Type.TransactionalVariable import getTransactionalVariable
from Products.ERP5.ExpandPolicy import policy_dict
from Products.ERP5.MovementCollectionDiff import _getPropertyAndCategoryList
from zLOG import LOG
......@@ -153,8 +157,7 @@ class RuleMixin(Predicate):
movement_type = 'Simulation Movement'
# Implementation of IRule
def constructNewAppliedRule(self, context, id=None,
activate_kw=None, **kw):
def constructNewAppliedRule(self, context, **kw):
"""
Create a new applied rule in the context.
......@@ -170,14 +173,8 @@ class RuleMixin(Predicate):
kw -- XXX-JPS probably wrong interface specification
"""
if id is None:
id = context.generateNewId()
if getattr(aq_base(context), id, None) is None:
context.newContent(id=id,
portal_type='Applied Rule',
specialise_value=self,
activate_kw=activate_kw)
return context.get(id)
return context.newContent(portal_type='Applied Rule',
specialise_value=self, **kw)
if 0: # XXX-JPS - if people are stupid enough not to configfure predicates,
# it is not our role to be clever for them
......@@ -192,7 +189,7 @@ class RuleMixin(Predicate):
return False
return super(RuleMixin, self).test(*args, **kw)
def expand(self, applied_rule, **kw):
def expand(self, applied_rule, expand_policy=None, **kw):
"""
Expand this applied rule to create new documents inside the
applied rule.
......@@ -202,13 +199,17 @@ class RuleMixin(Predicate):
by a decision (ie. a resource is changed), then we
should not try to compensate such a decision.
"""
# Update movements
policy_dict[expand_policy](**kw).expand(self, applied_rule)
def _expandNow(self, maybe_expand, applied_rule):
# Update moveme-nts
# NOTE-JPS: it is OK to make rounding a standard parameter of rules
# although rounding in simulation is not recommended at all
self.updateMovementCollection(applied_rule, movement_generator=self._getMovementGenerator(applied_rule))
self.updateMovementCollection(applied_rule,
movement_generator=self._getMovementGenerator(applied_rule))
# And forward expand
for movement in applied_rule.getMovementList():
movement.expand(**kw)
maybe_expand(movement)
security.declareProtected(Permissions.AccessContentsInformation,
'isAccountable')
......@@ -474,3 +475,130 @@ class RuleMixin(Predicate):
new_movement = self._newProfitAndLossMovement(prevision_movement)
movement_collection_diff.addNewMovement(new_movement)
class SimulableMixin(Base):
def updateSimulation(self, **kw):
"""Create/update related simulation trees by activity
This method is used to maintain related objects in simulation trees:
- hiding complexity of activity dependencies
- avoiding duplicate work
Repeated calls of this method for the same delivery will result in a single
call to _updateSimulation. Grouping may happen at the end of the transaction
or by the grouping method.
See _updateSimulation for accepted parameters.
"""
tv = getTransactionalVariable()
key = 'SimulableMixin.updateSimulation', self.getUid()
item_list = kw.items()
try:
kw, ignore = tv[key]
kw.update(item_list)
except KeyError:
ignore = set()
tv[key] = kw, ignore
def before_commit():
if kw:
path = self.getPath()
if aq_base(self.unrestrictedTraverse(path, None)) is aq_base(self):
self.activate(
activity='SQLQueue',
group_method_id='portal_rules/updateSimulation',
tag='expand:' + path,
after_tag='built:'+ path, # see SimulatedDeliveryBuilder
priority=3,
)._updateSimulation(**kw)
tv[key] = None # disallow further calls to 'updateSimulation' for self
transaction.get().addBeforeCommitHook(before_commit)
for k, v in item_list:
if not v:
ignore.add(k)
elif k not in ignore:
continue
del kw[k]
def _updateSimulation(self, create_root=0, expand_root=0,
expand_related=0, index_related=0):
"""
Depending on set parameters, this method will:
create_root -- if a root applied rule is missing, create and expand it
expand_root -- expand related root applied rule,
create it before if missing
expand_related -- reindex related simulation movements (recursively)
index_related -- expand related simulation movements
"""
if create_root or expand_root:
applied_rule = self._getRootAppliedRule()
if applied_rule is None:
applied_rule = self._createRootAppliedRule()
expand_root = applied_rule is not None
activate_kw = {'tag': 'expand:'+self.getPath()}
if expand_root:
applied_rule.expand(activate_kw=activate_kw)
else:
applied_rule = None
if expand_related:
for movement in self._getAllRelatedSimulationMovementList():
movement = movement.getObject()
if not movement.aq_inContextOf(applied_rule):
# XXX: make sure this will also reindex of all sub-objects recursively
movement.expand(activate_kw=activate_kw)
elif index_related:
for movement in self._getAllRelatedSimulationMovementList():
movement = movement.getObject()
if not movement.aq_inContextOf(applied_rule):
movement.recursiveReindexObject(activate_kw=activate_kw)
def getRuleReference(self):
"""Returns an appropriate rule reference
XXX: Using reference to select a rule (for a root applied rule) is wrong
and should be replaced by predicate and workflow state.
"""
method = self._getTypeBasedMethod('getRuleReference')
if method is None:
raise SimulationError("Missing type-based 'getRuleReference' script for "
+ repr(self))
return method()
def _getRootAppliedRule(self):
"""Get related root applied rule if it exists"""
applied_rule_list = self.getCausalityRelatedValueList(
portal_type='Applied Rule')
if len(applied_rule_list) == 1:
return applied_rule_list[0]
elif applied_rule_list:
raise SimulationError('%r has more than one applied rule.' % self)
def _createRootAppliedRule(self):
"""Create a root applied rule"""
# XXX: Consider moving this first test to Delivery
if self.isSimulated():
# No need to have a root applied rule
# if we are already in the simulation process
return
rule_reference = self.getRuleReference()
if rule_reference:
portal = self.getPortalObject()
rule_list = portal.portal_catalog.unrestrictedSearchResults(
portal_type=portal.getPortalRuleTypeList(),
validation_state="validated", reference=rule_reference,
sort_on='version', sort_order='descending')
if rule_list:
applied_rule = rule_list[0].constructNewAppliedRule(
portal.portal_simulation, is_indexable=False)
applied_rule._setCausalityValue(self)
del applied_rule.isIndexable
applied_rule.immediateReindexObject()
self.serialize() # prevent duplicate root Applied Rule
return applied_rule
raise SimulationError("No such rule as %r is found" % rule_reference)
def manage_beforeDelete(self, item, container):
"""Delete related Applied Rule"""
for o in self.getCausalityRelatedValueList(portal_type='Applied Rule'):
o.getParentValue().deleteContent(o.getId())
super(SimulableMixin, self).manage_beforeDelete(item, container)
......@@ -677,15 +677,6 @@ class TestAccountingRules(TestAccountingRulesMixin, ERP5TypeTestCase):
invoice._delObject(invoice_line.getId())
invoice.recursiveReindexObject()
def stepUpdateAppliedRule(self, sequence, **kw) :
""" update the applied rule for the invoice. In the UI, the call to
updateAppliedRule is made in an interraction workflow when you edit
an invoice or its content."""
# edit is done through interaction workflow, so we just call 'edit'
# on the invoice (but this is not necessary)
invoice=sequence.get('invoice')
invoice.edit()
def stepCreateSimpleInvoiceTwoLines(self, sequence, **kw) :
"""
similar to stepCreateSimpleInvoice, but replace
......@@ -1784,7 +1775,7 @@ class TestAccountingRules(TestAccountingRulesMixin, ERP5TypeTestCase):
@newSimulationExpectedFailure
def test_05a_SimpleInvoiceReExpandAddLine(self, quiet=QUIET,
run=RUN_ALL_TESTS):
""" Add a new line then updateAppliedRule.
""" Add a new line then updateSimulation.
Create an empty invoice, plan, add a line so that this
invoice is the same as `SimpleInvoice`, confirm it then check
accounting lines
......@@ -1951,7 +1942,7 @@ class TestAccountingRules(TestAccountingRulesMixin, ERP5TypeTestCase):
if not run:
return
if not quiet:
message = 'Test Simple Invoice Rule (many updateAppliedRule)'
message = 'Test Simple Invoice Rule (many updateSimulation)'
ZopeTestCase._print('\n%s ' % message)
LOG('Testing... ', INFO, message)
......@@ -1974,7 +1965,6 @@ class TestAccountingRules(TestAccountingRulesMixin, ERP5TypeTestCase):
stepTic """ +
("""
stepEditInvoiceLine
stepUpdateAppliedRule
stepTic""" * 4) +
"""
stepConfirmInvoice
......
......@@ -280,7 +280,7 @@ class TestAdvancedInvoice(TestSaleInvoiceMixin, ERP5TypeTestCase):
invoice_transaction = invoice.getCausalityRelatedValue()
self.assertNotEquals(invoice_transaction, None)
self.assertEquals('draft', invoice_transaction.getCausalityState())
self.assertEquals('solved', invoice_transaction.getCausalityState())
def test_AcceptQuantityDivergenceOnInvoiceWithStoppedPackingList(self, quiet=quiet, run=RUN_ALL_TESTS):
"""Accept divergence with stopped packing list"""
......
......@@ -31,7 +31,6 @@ import unittest
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
from AccessControl.SecurityManagement import newSecurityManager
from Products.ERP5Form.Form import ERP5Form
from Products.ERP5.tests.utils import newSimulationExpectedFailure
class TestICal(ERP5TypeTestCase):
......@@ -165,7 +164,6 @@ class TestICal(ERP5TypeTestCase):
feed_dict = self.getICalFeed(module)
self.assertEquals(feed_dict['STATUS'], 'CANCELLED')
@newSimulationExpectedFailure
def test_02_renderTask(self, quiet=0, run=run_all_test):
"""
Task - is rendered as "todo".
......
......@@ -669,20 +669,12 @@ class TestInvoiceMixin(TestPackingListMixin):
def stepCheckTwoInvoices(self,sequence=None, sequence_list=None, **kw):
""" checks invoice properties are well set. """
# Now we will check that we have two invoices created
packing_list = sequence.get('packing_list')
invoice_list = packing_list.getCausalityRelatedValueList(
portal_type=self.invoice_portal_type)
self.assertEquals(len(invoice_list),1)
invoice = invoice_list[0]
self.assertEquals(invoice.getSimulationState(), 'confirmed')
sequence.edit(invoice=invoice)
new_packing_list = sequence.get('new_packing_list')
new_invoice_list = new_packing_list.getCausalityRelatedValueList(
portal_type=self.invoice_portal_type)
self.assertEquals(len(new_invoice_list),1)
new_invoice = new_invoice_list[0]
self.assertEquals(new_invoice.getSimulationState(), 'confirmed')
sequence.edit(new_invoice=new_invoice)
for x in '', 'new_':
packing_list = sequence.get(x + 'packing_list')
invoice, = packing_list.getCausalityRelatedValueList(
portal_type=self.invoice_portal_type)
self.assertEqual(invoice.getSimulationState(), 'confirmed')
sequence.set(x + 'invoice', invoice)
def stepStartTwoInvoices(self,sequence=None, sequence_list=None, **kw):
""" start both invoices. """
......@@ -781,50 +773,28 @@ class TestInvoiceMixin(TestPackingListMixin):
newSecurityManager(None, user)
def stepEditInvoice(self, sequence=None, sequence_list=None, **kw):
"""Edit the current invoice, to trigger updateAppliedRule."""
"""Edit the current invoice, to trigger updateSimulation."""
invoice = sequence.get('invoice')
invoice.edit()
# call updateAppliedRule directly, don't rely on edit interactions
rule_reference = 'default_invoice_rule'
self.assertNotEquals(0,
len(self.portal.portal_rules.searchFolder(reference=rule_reference)))
invoice.updateAppliedRule(rule_reference=rule_reference)
invoice.edit(description='This invoice was edited!')
def stepCheckInvoiceRuleNotAppliedOnInvoiceEdit(self,
sequence=None, sequence_list=None, **kw):
"""If we call edit on the invoice, invoice rule should not be
applied on lines created by delivery builder."""
invoice = sequence.get('invoice')
# FIXME: empty applied rule should not be created
#self.assertEquals(len(invoice.getCausalityRelatedValueList(
# portal_type=self.applied_rule_portal_type)), 0)
for invoice_mvt in invoice.getMovementList():
self.assertEquals(len(invoice_mvt.getOrderRelatedValueList(
portal_type=self.simulation_movement_portal_type)), 0)
self.assertEqual([], invoice.getCausalityRelatedValueList())
def stepEditPackingList(self, sequence=None, sequence_list=None, **kw):
"""Edit the current packing list, to trigger updateAppliedRule."""
"""Edit the current packing list, to trigger updateSimulation."""
packing_list = sequence.get('packing_list')
packing_list.edit()
# call updateAppliedRule directly, don't rely on edit interactions
rule_reference = 'default_delivery_rule'
self.assertNotEquals(0,
len(self.portal.portal_rules.searchFolder(reference=rule_reference)))
packing_list.updateAppliedRule(rule_reference=rule_reference)
packing_list.edit(description='This packing list was edited!')
def stepCheckDeliveryRuleNotAppliedOnPackingListEdit(self,
sequence=None, sequence_list=None, **kw):
"""If we call edit on the packing list, delivery rule should not be
applied on lines created by delivery builder."""
packing_list = sequence.get('packing_list')
# FIXME: empty applied rule should not be created
#self.assertEquals(len(packing_list.getCausalityRelatedValueList(
# portal_type=self.applied_rule_portal_type)), 0)
for delivery_mvt in packing_list.getMovementList():
self.assertEquals(len(delivery_mvt.getOrderRelatedValueList(
portal_type=self.simulation_movement_portal_type)), 0)
self.assertEqual([], packing_list.getCausalityRelatedValueList())
def stepDecreaseInvoiceLineQuantity(self, sequence=None, sequence_list=None,
**kw):
......@@ -1037,14 +1007,9 @@ class TestInvoiceMixin(TestPackingListMixin):
# check which activities are failing
self.assertTrue(str(exc).startswith('tic is looping forever.'),
'%s does not start with "tic is looping forever."' % str(exc))
msg_list = ['/'.join(x.object_path) for x in
self.getActivityTool().getMessageList()]
self.assertTrue(invoice.getPath() in msg_list, '%s in %s' %
(invoice.getPath(), msg_list))
method_id_list = [x.method_id for x in
self.getActivityTool().getMessageList()]
self.assertTrue('Delivery_buildOnComposedDocument' in method_id_list, '%s in %s' %
('Delivery_buildOnComposedDocument', method_id_list))
msg_list = [('/'.join(x.object_path), x.method_id)
for x in self.getActivityTool().getMessageList()]
self.assertTrue((invoice.getPath(), '_localBuild') in msg_list, msg_list)
# flush failing activities
activity_tool = self.getActivityTool()
activity_tool.manageClearActivities(keep=0)
......@@ -2613,7 +2578,7 @@ class TestSaleInvoice(TestSaleInvoiceMixin, TestInvoice, ERP5TypeTestCase):
We want to prevent this from happening:
- Create a packing list
- An invoice is created from packing list
- Invoice is edited, updateAppliedRule is called
- Invoice is edited, updateSimulation is called
- A new Invoice Rule is created for this invoice, and accounting
movements for this invoice are present twice in the simulation.
"""
......@@ -2633,9 +2598,9 @@ class TestSaleInvoice(TestSaleInvoiceMixin, TestInvoice, ERP5TypeTestCase):
stepTic
stepCheckInvoiceBuilding
stepEditInvoice
stepTic
stepCheckInvoiceRuleNotAppliedOnInvoiceEdit
stepCheckInvoicesConsistency
stepTic
""")
sequence_list.play(self, quiet=quiet)
......@@ -2652,9 +2617,8 @@ class TestSaleInvoice(TestSaleInvoiceMixin, TestInvoice, ERP5TypeTestCase):
base_sequence +
"""
stepEditPackingList
stepCheckDeliveryRuleNotAppliedOnPackingListEdit
stepCheckInvoicesConsistency
stepTic
stepCheckDeliveryRuleNotAppliedOnPackingListEdit
""")
sequence_list.play(self, quiet=quiet)
......@@ -2725,6 +2689,7 @@ class TestSaleInvoice(TestSaleInvoiceMixin, TestInvoice, ERP5TypeTestCase):
base_sequence +
"""
stepAddPackingListLine
stepTic
stepSetContainerFullQuantity
stepTic
stepSetReadyPackingList
......
......@@ -1134,23 +1134,13 @@ class TestOrderMixin(SubcontentReindexingWrapper):
order_line = sequence.get('order_line')
order_line.getParentValue().manage_delObjects([order_line.getId()])
def stepCheckOrderSimulationStable(self, sequence=None, \
sequence_list=None, **kw):
def stepCheckOrderConvergent(self, sequence=None, sequence_list=None, **kw):
"""
Tests that the simulation related to the order is stable and not
divergent
"""
order = sequence.get('order')
order_movement_list = order.getMovementList()
related_simulation_list = []
for order_movement in order_movement_list:
related_simulation_list.extend(order_movement.getOrderRelatedValueList())
related_applied_rule_list = {}
for simulation_mvt in related_simulation_list:
self.assertFalse(simulation_mvt.isDivergent())
related_applied_rule_list[simulation_mvt.getParentValue()]=1
for applied_rule in related_applied_rule_list.keys():
self.assertTrue(applied_rule.isStable())
self.assertTrue(order.isConvergent())
def stepPackingListAdoptPrevision(self,sequence=None, sequence_list=None,
**kw):
......@@ -2078,7 +2068,7 @@ class TestOrder(TestOrderMixin, ERP5TypeTestCase):
stepConfirmOrder \
stepTic \
stepCheckOrderSimulation \
stepCheckOrderSimulationStable \
stepCheckOrderConvergent \
'
sequence_list.addSequenceString(sequence_string)
# XXX XXX FIXME
......@@ -2109,7 +2099,7 @@ class TestOrder(TestOrderMixin, ERP5TypeTestCase):
stepTic \
stepCheckOrderSimulation \
stepCheckDeliveryBuilding \
stepCheckOrderSimulationStable \
stepCheckOrderConvergent \
'
# sequence_list.addSequenceString(sequence_string)
......
......@@ -31,7 +31,6 @@ import unittest
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
from DateTime import DateTime
from Products.ERP5.tests.utils import newSimulationExpectedFailure
class TestProject(ERP5TypeTestCase):
""" Test for Project API and scripts and forms
......@@ -110,7 +109,6 @@ class TestProject(ERP5TypeTestCase):
self.tic()
@newSimulationExpectedFailure
def testProject_getSourceProjectRelatedTaskReportList(self):
"""
Basic Test if the script behaviour as expected.
......
......@@ -368,9 +368,9 @@ return context.generatePredicate(
kw['trade_phase_relative_url'] = []
self.assertEqual(len(rule_tool.searchRuleList(self.sm, **kw)), 1)
def test_08_updateAppliedRule(self, quiet=quiet, run=run_all_test):
def test_08_createRootAppliedRule(self, quiet=quiet, run=run_all_test):
"""
test that when updateAppliedRule is called, the rule with the correct
test that when updateSimulation is called, the rule with the correct
reference and higher version is used
XXX as expand is triggered here, make sure rules won't be created forever
......@@ -396,24 +396,28 @@ return context.generatePredicate(
self.tic()
# delivery_rule_2 should be applied
self.pl.updateAppliedRule('default_delivery_rule')
self.pl.updateSimulation(create_root=1)
self.tic()
self.assertEquals(self.pl.getCausalityRelatedValue().getSpecialise(),
root_applied_rule, = self.pl.getCausalityRelatedValueList()
self.assertEquals(root_applied_rule.getSpecialise(),
delivery_rule_2.getRelativeUrl())
self.getSimulationTool().manage_delObjects(
ids=[self.pl.getCausalityRelatedId()])
self.getSimulationTool()._delObject(root_applied_rule.getId())
# increase version of delivery_rule_1
delivery_rule_1.setVersion("testRule.3")
self.tic()
# delivery_rule_1 should be applied
self.pl.updateAppliedRule('default_delivery_rule')
self.pl.updateSimulation(create_root=1)
self.tic()
self.assertEquals(self.pl.getCausalityRelatedValue().getSpecialise(),
root_applied_rule, = self.pl.getCausalityRelatedValueList()
self.assertEquals(root_applied_rule.getSpecialise(),
delivery_rule_1.getRelativeUrl())
self.getSimulationTool()._delObject(root_applied_rule.getId())
self.tic()
def test_09_expandTwoRules(self, quiet=quiet, run=run_all_test):
"""
test that when expand is called on a simulation movement, if two rules
......@@ -443,47 +447,40 @@ return context.generatePredicate(
test_method_id='invoice_rule_script')
invoicing_rule_2.validate()
# clear simulation
self.getSimulationTool().manage_delObjects(
ids=list(self.getSimulationTool().objectIds()))
self.tic()
self.pl.updateAppliedRule('default_delivery_rule')
self.pl.updateSimulation(create_root=1)
self.tic()
# check that only one invoicing rule (higher version) was applied
root_applied_rule = self.pl.getCausalityRelatedValue()
root_applied_rule, = self.pl.getCausalityRelatedValueList()
self.assertEquals(root_applied_rule.getSpecialise(),
delivery_rule.getRelativeUrl())
self.assertEquals(root_applied_rule.objectCount(), 1)
movement = root_applied_rule.objectValues()[0]
self.assertEquals(movement.objectCount(), 1)
applied_rule = movement.objectValues()[0]
movement, = root_applied_rule.objectValues()
applied_rule, = movement.objectValues()
self.assertEquals(applied_rule.getSpecialise(),
invoicing_rule_2.getRelativeUrl())
# increase version of other rule, clean simulation and check again
self.getSimulationTool().manage_delObjects(
ids=[self.pl.getCausalityRelatedId()])
self.getSimulationTool()._delObject(root_applied_rule.getId())
invoicing_rule_1.setVersion('testRule.3')
self.tic()
self.pl.updateAppliedRule('default_delivery_rule')
self.pl.updateSimulation(create_root=1)
self.tic()
# check that only one invoicing rule (higher version) was applied
root_applied_rule = self.pl.getCausalityRelatedValue()
root_applied_rule, = self.pl.getCausalityRelatedValueList()
self.assertEquals(root_applied_rule.getSpecialise(),
delivery_rule.getRelativeUrl())
self.assertEquals(root_applied_rule.objectCount(), 1)
movement = root_applied_rule.objectValues()[0]
self.assertEquals(movement.objectCount(), 1)
applied_rule = movement.objectValues()[0]
movement, = root_applied_rule.objectValues()
applied_rule, = movement.objectValues()
self.assertEquals(applied_rule.getSpecialise(),
invoicing_rule_1.getRelativeUrl())
self.getSimulationTool()._delObject(root_applied_rule.getId())
self.tic()
def test_10_expandAddsRule(self, quiet=quiet, run=run_all_test):
"""
test that if a rule didn't match previously, and does now, it should apply
......@@ -508,20 +505,14 @@ return context.generatePredicate(
test_method_id='delivery_rule_script')
invoicing_rule_1.validate()
# clear simulation
self.getSimulationTool().manage_delObjects(
ids=list(self.getSimulationTool().objectIds()))
self.pl.updateSimulation(create_root=1)
self.tic()
self.pl.updateAppliedRule('default_delivery_rule')
self.tic()
root_applied_rule = self.pl.getCausalityRelatedValue()
root_applied_rule, = self.pl.getCausalityRelatedValueList()
# check that no invoicing rule was applied
self.assertEquals(root_applied_rule.getSpecialise(),
delivery_rule.getRelativeUrl())
self.assertEquals(root_applied_rule.objectCount(), 1)
movement = root_applied_rule.objectValues()[0]
movement, = root_applied_rule.objectValues()
self.assertEquals(movement.objectCount(), 0)
# change rule script so that it matches and test again
......@@ -529,17 +520,8 @@ return context.generatePredicate(
root_applied_rule.expand()
self.tic()
self.assertEquals(root_applied_rule.getRelativeUrl(),
self.pl.getCausalityRelated())
self.assertEquals(root_applied_rule.getSpecialise(),
delivery_rule.getRelativeUrl())
self.assertEquals(root_applied_rule.getSpecialise(),
delivery_rule.getRelativeUrl())
self.assertEquals(root_applied_rule.objectCount(), 1)
movement = root_applied_rule.objectValues()[0]
self.assertEquals(movement.objectCount(), 1)
invoicing_rule_1_applied_rule = movement.objectValues()[0]
self.assertEquals(list(root_applied_rule.objectValues()), [movement])
invoicing_rule_1_applied_rule, = movement.objectValues()
self.assertEquals(invoicing_rule_1_applied_rule.getSpecialise(),
invoicing_rule_1.getRelativeUrl())
......@@ -557,24 +539,17 @@ return context.generatePredicate(
root_applied_rule.expand()
self.tic()
self.assertEquals(root_applied_rule.getRelativeUrl(),
self.pl.getCausalityRelated())
self.assertEquals(root_applied_rule.getSpecialise(),
delivery_rule.getRelativeUrl())
self.assertEquals(root_applied_rule.getSpecialise(),
delivery_rule.getRelativeUrl())
self.assertEquals(root_applied_rule.objectCount(), 1)
movement = root_applied_rule.objectValues()[0]
self.assertEquals(movement.objectCount(), 2)
applied_rule_list = sorted(movement.objectValues(),
key=lambda x: x.getSpecialiseValue().getReference())
self.assertEquals(list(root_applied_rule.objectValues()), [movement])
applied_rule_1, applied_rule_2 = sorted(movement.objectValues(),
key=lambda x: x.getSpecialiseReference())
# check the 1st applied rule is an application of invoicing_rule_1
self.assertEquals(applied_rule_list[0].getSpecialise(),
self.assertEquals(applied_rule_1.getSpecialise(),
invoicing_rule_n.getRelativeUrl())
self.assertEquals(applied_rule_list[1].getSpecialise(),
self.assertEquals(applied_rule_2.getSpecialise(),
invoicing_rule_2.getRelativeUrl())
self.getSimulationTool()._delObject(root_applied_rule.getId())
self.tic()
def test_11_expandRemovesRule(self, quiet=quiet, run=run_all_test):
"""
......@@ -600,23 +575,15 @@ return context.generatePredicate(
test_method_id='invoice_rule_script')
invoicing_rule_1.validate()
# clear simulation
self.getSimulationTool().manage_delObjects(
ids=list(self.getSimulationTool().objectIds()))
self.pl.updateSimulation(create_root=1)
self.tic()
self.pl.updateAppliedRule('default_delivery_rule')
self.tic()
root_applied_rule = self.pl.getCausalityRelatedValue()
root_applied_rule, = self.pl.getCausalityRelatedValueList()
# check that the invoicing rule was applied
self.assertEquals(root_applied_rule.getSpecialise(),
delivery_rule.getRelativeUrl())
self.assertEquals(root_applied_rule.objectCount(), 1)
movement = root_applied_rule.objectValues()[0]
self.assertEquals(movement.objectCount(), 1)
applied_rule = movement.objectValues()[0]
movement, = root_applied_rule.objectValues()
applied_rule, = movement.objectValues()
self.assertEquals(applied_rule.getSpecialise(),
invoicing_rule_1.getRelativeUrl())
......@@ -627,12 +594,7 @@ return context.generatePredicate(
root_applied_rule.expand()
self.tic()
self.assertEquals(root_applied_rule.getRelativeUrl(),
self.pl.getCausalityRelated())
self.assertEquals(root_applied_rule.getSpecialise(),
delivery_rule.getRelativeUrl())
self.assertEquals(root_applied_rule.objectCount(), 1)
movement = root_applied_rule.objectValues()[0]
self.assertEquals(list(root_applied_rule.objectValues()), [movement])
self.assertEquals(movement.objectCount(), 0)
# change the test method to one that fails, and test that the rule is
......@@ -641,12 +603,7 @@ return context.generatePredicate(
root_applied_rule.expand()
self.tic()
self.assertEquals(root_applied_rule.getRelativeUrl(),
self.pl.getCausalityRelated())
self.assertEquals(root_applied_rule.getSpecialise(),
delivery_rule.getRelativeUrl())
self.assertEquals(root_applied_rule.objectCount(), 1)
movement = root_applied_rule.objectValues()[0]
self.assertEquals(list(root_applied_rule.objectValues()), [movement])
self.assertEquals(movement.objectCount(), 0)
# change the test to one that succeeds, revalidate, expand, add a delivery
......@@ -659,18 +616,11 @@ return context.generatePredicate(
root_applied_rule.expand()
self.tic()
self.assertEquals(root_applied_rule.getRelativeUrl(),
self.pl.getCausalityRelated())
self.assertEquals(root_applied_rule.getSpecialise(),
delivery_rule.getRelativeUrl())
self.assertEquals(root_applied_rule.objectCount(), 1)
movement = root_applied_rule.objectValues()[0]
self.assertEquals(movement.objectCount(), 1)
applied_rule = movement.objectValues()[0]
self.assertEquals(list(root_applied_rule.objectValues()), [movement])
applied_rule, = movement.objectValues()
self.assertEquals(applied_rule.getSpecialise(),
invoicing_rule_1.getRelativeUrl())
self.assertEquals(applied_rule.objectCount(), 1)
sub_movement = applied_rule.objectValues()[0]
sub_movement, = applied_rule.objectValues()
sub_movement.setDeliveryValue(self.pl.line)
......@@ -678,20 +628,16 @@ return context.generatePredicate(
root_applied_rule.expand()
self.tic()
self.assertEquals(root_applied_rule.getRelativeUrl(),
self.pl.getCausalityRelated())
self.assertEquals(root_applied_rule.getSpecialise(),
delivery_rule.getRelativeUrl())
self.assertEquals(root_applied_rule.objectCount(), 1)
movement = root_applied_rule.objectValues()[0]
self.assertEquals(movement.objectCount(), 1)
applied_rule = movement.objectValues()[0]
self.assertEquals(list(root_applied_rule.objectValues()), [movement])
self.assertEquals(list(movement.objectValues()), [applied_rule])
self.assertEquals(applied_rule.getSpecialise(),
invoicing_rule_1.getRelativeUrl())
self.assertEquals(applied_rule.objectCount(), 1)
sub_movement = applied_rule.objectValues()[0]
self.assertEquals(list(applied_rule.objectValues()), [sub_movement])
self.assertEquals(sub_movement.getDelivery(), self.pl.line.getRelativeUrl())
self.getSimulationTool()._delObject(root_applied_rule.getId())
self.tic()
def test_12_expandReplacesRule(self, quiet=quiet, run=run_all_test):
"""
test that if a rule matched previously and does not anymore, and another
......@@ -721,23 +667,15 @@ return context.generatePredicate(
test_method_id='invoice_rule_script')
invoicing_rule_2.validate()
# clear simulation
self.getSimulationTool().manage_delObjects(
ids=list(self.getSimulationTool().objectIds()))
self.pl.updateSimulation(create_root=1)
self.tic()
self.pl.updateAppliedRule('default_delivery_rule')
self.tic()
root_applied_rule = self.pl.getCausalityRelatedValue()
root_applied_rule, = self.pl.getCausalityRelatedValueList()
# check that the invoicing rule 2 was applied
self.assertEquals(root_applied_rule.getSpecialise(),
delivery_rule.getRelativeUrl())
self.assertEquals(root_applied_rule.objectCount(), 1)
movement = root_applied_rule.objectValues()[0]
self.assertEquals(movement.objectCount(), 1)
applied_rule = movement.objectValues()[0]
movement, = root_applied_rule.objectValues()
applied_rule, = movement.objectValues()
self.assertEquals(applied_rule.getSpecialise(),
invoicing_rule_2.getRelativeUrl())
......@@ -747,39 +685,29 @@ return context.generatePredicate(
root_applied_rule.expand()
self.tic()
self.assertEquals(root_applied_rule.getRelativeUrl(),
self.pl.getCausalityRelated())
self.assertEquals(root_applied_rule.getSpecialise(),
delivery_rule.getRelativeUrl())
self.assertEquals(root_applied_rule.objectCount(), 1)
movement = root_applied_rule.objectValues()[0]
self.assertEquals(movement.objectCount(), 1)
applied_rule = movement.objectValues()[0]
self.assertEquals(list(root_applied_rule.objectValues()), [movement])
applied_rule, = movement.objectValues()
self.assertEquals(applied_rule.getSpecialise(),
invoicing_rule_1.getRelativeUrl())
# change the test of invoicing rule 2 to one that succeeds, add a delivery
# relation, expand, and test that the invoicing rule 1 is still there
invoicing_rule_2.setTestMethodId('invoice_rule_script')
sub_movement = applied_rule.objectValues()[0]
sub_movement, = applied_rule.objectValues()
sub_movement.setDeliveryValue(self.pl.line)
root_applied_rule.expand()
self.tic()
self.assertEquals(root_applied_rule.getRelativeUrl(),
self.pl.getCausalityRelated())
self.assertEquals(root_applied_rule.getSpecialise(),
delivery_rule.getRelativeUrl())
self.assertEquals(root_applied_rule.objectCount(), 1)
movement = root_applied_rule.objectValues()[0]
self.assertEquals(movement.objectCount(), 1)
applied_rule = movement.objectValues()[0]
self.assertEquals(list(root_applied_rule.objectValues()), [movement])
self.assertEquals(list(movement.objectValues()), [applied_rule])
self.assertEquals(applied_rule.getSpecialise(),
invoicing_rule_1.getRelativeUrl())
self.assertEquals(applied_rule.objectCount(), 1)
sub_movement = applied_rule.objectValues()[0]
self.assertEquals(list(applied_rule.objectValues()), [sub_movement])
self.assertEquals(sub_movement.getDelivery(), self.pl.line.getRelativeUrl())
self.getSimulationTool()._delObject(root_applied_rule.getId())
self.tic()
def test_suite():
suite = unittest.TestSuite()
......
......@@ -458,13 +458,13 @@ class TestTaskMixin:
self.assertEqual(task_line.getDescription(),
task_report_line.getDescription())
def stepVerifyTaskReportCausalityState(self, sequence=None,
def stepAssertDraftCausalityState(self, sequence=None,
sequence_list=None, **kw):
"""
Verify that confirmed task report starts building and gets solved.
"""
task_report = sequence.get('task_report')
self.assertEqual(task_report.getCausalityState(), 'solved')
self.assertEqual(task_report.getCausalityState(), 'draft')
def stepVerifyTaskReportNoPrice(self, sequence=None,
sequence_list=None, **kw):
......@@ -625,7 +625,7 @@ class TestTask(TestTaskMixin, ERP5TypeTestCase):
sequence_string = self.default_task_report_sequence + '\
stepConfirmTaskReport \
stepTic \
stepVerifyTaskReportCausalityState \
stepAssertDraftCausalityState \
stepStartTaskReport \
stepFinishTaskReport \
stepCloseTaskReport \
......
......@@ -370,8 +370,8 @@ class TestTradeModelLine(TestTradeModelLineMixin):
def checkWithoutBPM(self, order):
self.commit()# clear transactional cache
order.getSpecialiseValue()._setSpecialise(None)
self.assertRaises(ValueError, order.expand,
applied_rule_id=order.getCausalityRelatedId(portal_type='Applied Rule'))
self.assertRaises(ValueError, order.getCausalityRelatedValue(
portal_type='Applied Rule').expand, 'immediate')
self.abort()
def checkModelLineOnDelivery(self, delivery):
......
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