Commit 2f414c7f authored by Romain Courteaud's avatar Romain Courteaud

slapos_accounting:

* fix: do not use unrelated causality value
  Builder passes all movement used to generate all the invoice
* allow closing the invoice has soon as the stop date value is reached
* test: wip accounting checks
* do not access the object if not needed
* drop Entity_statOutstandingAmount
* wip Entity_hasOutstandingAmount
* wip: create from multiple invoices
  using Entity_getOutstandingAmountList
* group also outstanding amount by ledger
* drop PaymentTransaction_start
* use the same ledger than the payment transaction
* create Payment Transaction to pay all user's invoices
* improve Payment line title
* allow to pay invoices at a date
* test paying invoices
* test: fix create payment tests
* drop preferred_default_pre_payment_subscription_invoice_template_property
* test: templates were dropped
* drop preferred_default_pre_payment_template
* drop getPreferredAggregatedSubscriptionSaleTradeCondition
* drop preferred_aggregated_sale_trade_condition
* test: unused variable
* test: fixup testSlapOSAccountingConstraint
* test: fix trade condition retrieval
* drop preferred_instance_delivery_template_property
* drop slapos_accounting_instance_delivery_template
* drop slapos_accounting_instance_delivery_line_template
* drop preferred_aggregated_consumption_sale_trade_condition
* drop SlapOSAccountingSystemPreference
* keep organisation_module/slapos/bank_account
* disable packing list generation from tio xml
  this is not critical for now, and will be upgraded later
* fixConsistency is not called anymore on Hosting Subscription
* drop template_compute_node
* drop template_member
* test: there is no causality_state anymore on instance tree
* test: fix consistency on Hosting Subscription does not set the periodicity date
* drop unused script
* reduce number of sale trade condition to check
parent 9eba923a
...@@ -2,25 +2,33 @@ ...@@ -2,25 +2,33 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="Sale Packing List Line" module="erp5.portal_type"/> <global name="ActionInformation" module="Products.CMFCore.ActionInformation"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
<item>
<key> <string>action</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item> <item>
<key> <string>categories</string> </key> <key> <string>categories</string> </key>
<value> <value>
<tuple> <tuple>
<string>resource/service_module/slapos_instance_setup</string> <string>action_type/object_jio_action</string>
<string>quantity_unit/unit/piece</string>
<string>base_contribution/base_amount/invoicing/discounted</string>
<string>base_contribution/base_amount/invoicing/taxable</string>
<string>use/trade/sale</string>
</tuple> </tuple>
</value> </value>
</item> </item>
<item> <item>
<key> <string>default_reference</string> </key> <key> <string>category</string> </key>
<value> <string>1</string> </value> <value> <string>object_jio_action</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item> </item>
<item> <item>
<key> <string>description</string> </key> <key> <string>description</string> </key>
...@@ -28,68 +36,59 @@ ...@@ -28,68 +36,59 @@
<none/> <none/>
</value> </value>
</item> </item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>setup</string> </value> <value> <string>create_slapos_payment_transaction</string> </value>
</item> </item>
<item> <item>
<key> <string>index</string> </key> <key> <string>permissions</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent> <tuple>
<string>View</string>
</tuple>
</value> </value>
</item> </item>
<item> <item>
<key> <string>int_index</string> </key> <key> <string>priority</string> </key>
<value> <int>1</int> </value> <value> <float>60.0</float> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Sale Packing List Line</string> </value>
</item> </item>
<item> <item>
<key> <string>price</string> </key> <key> <string>title</string> </key>
<value> <float>0.0</float> </value> <value> <string>Create Payment Transaction</string> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>visible</string> </key>
<value> <string>Setup Line</string> </value> <value> <int>1</int> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="2" aka="AAAAAAAAAAI="> <record id="2" aka="AAAAAAAAAAI=">
<pickle> <pickle>
<global name="PersistentMapping" module="Persistence.mapping"/> <global name="Expression" module="Products.CMFCore.Expression"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
<item> <item>
<key> <string>data</string> </key> <key> <string>text</string> </key>
<value> <value> <string>string:${object_url}/Entity_viewCreatePaymentTransactionDialog</string> </value>
<dictionary>
<item>
<key> <string>movement</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="3" aka="AAAAAAAAAAM="> <record id="3" aka="AAAAAAAAAAM=">
<pickle> <pickle>
<global name="PersistentMapping" module="Persistence.mapping"/> <global name="Expression" module="Products.CMFCore.Expression"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
<item> <item>
<key> <string>data</string> </key> <key> <string>text</string> </key>
<value> <value> <string>python: portal.Base_checkPermission(\'accounting_module\', \'Add portal content\') and (context.getValidationState() == \'validated\')</string> </value>
<dictionary/>
</value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Sale Packing List" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Access_contents_information_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Add_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Delete_objects_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Modify_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>_View_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>_count</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_mt_index</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>_tree</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>default_destination_reference</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>SPL-34</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>slapos_accounting_instance_delivery_line_template</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Sale Packing List</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Slapos Accounting Instance Delivery Line Template</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Length" module="BTrees.Length"/>
</pickle>
<pickle> <int>0</int> </pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="OOBTree" module="BTrees.OOBTree"/>
</pickle>
<pickle>
<none/>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="OOBTree" module="BTrees.OOBTree"/>
</pickle>
<pickle>
<none/>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Sale Packing List Line" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>resource/service_module/slapos_instance_update</string>
<string>quantity_unit/unit/piece</string>
<string>base_contribution/base_amount/invoicing/discounted</string>
<string>base_contribution/base_amount/invoicing/taxable</string>
<string>use/trade/sale</string>
</tuple>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>1</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>update</string> </value>
</item>
<item>
<key> <string>index</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>int_index</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>language</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Sale Packing List Line</string> </value>
</item>
<item>
<key> <string>price</string> </key>
<value> <float>0.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Update Line</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>movement</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Sale Packing List" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Access_contents_information_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Add_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Delete_objects_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Modify_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>_View_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>source_section/organisation_module/slapos</string>
<string>source/organisation_module/slapos</string>
<string>destination_section/organisation_module/slapos</string>
<string>price_currency/currency_module/EUR</string>
<string>specialise/sale_trade_condition_module/slapos_consumption_trade_condition</string>
</tuple>
</value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>SPL-33</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>slapos_accounting_instance_delivery_template</string> </value>
</item>
<item>
<key> <string>language</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Sale Packing List</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Slapos Accounting Instance Delivery Template</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Property Sheet" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_count</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_mt_index</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>_tree</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>SlapOSAccountingSystemPreference</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Property Sheet</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Length" module="BTrees.Length"/>
</pickle>
<pickle> <int>0</int> </pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="OOBTree" module="BTrees.OOBTree"/>
</pickle>
<pickle>
<none/>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="OOBTree" module="BTrees.OOBTree"/>
</pickle>
<pickle>
<none/>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Standard Property" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>elementary_type/string</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>preferred_aggregated_consumption_sale_trade_condition_property</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Standard Property</string> </value>
</item>
<item>
<key> <string>preference</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>write_permission</string> </key>
<value> <string>Manage properties</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Standard Property" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>elementary_type/string</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>preferred_aggregated_sale_trade_condition_property</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Standard Property</string> </value>
</item>
<item>
<key> <string>preference</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>write_permission</string> </key>
<value> <string>Manage properties</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Standard Property" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>elementary_type/string</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>preferred_aggregated_subscription_sale_trade_condition_property</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Standard Property</string> </value>
</item>
<item>
<key> <string>preference</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>write_permission</string> </key>
<value> <string>Manage properties</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Standard Property" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_local_properties</string> </key>
<value>
<tuple>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>mode</string> </value>
</item>
<item>
<key> <string>type</string> </key>
<value> <string>string</string> </value>
</item>
</dictionary>
</tuple>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>elementary_type/string</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>preferred_default_pre_payment_subscription_invoice_template_property</string> </value>
</item>
<item>
<key> <string>mode</string> </key>
<value> <string>w</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Standard Property</string> </value>
</item>
<item>
<key> <string>preference</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>property_default</string> </key>
<value> <string>python: \'\'</string> </value>
</item>
<item>
<key> <string>write_permission</string> </key>
<value> <string>Manage properties</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Standard Property" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_local_properties</string> </key>
<value>
<tuple>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>mode</string> </value>
</item>
<item>
<key> <string>type</string> </key>
<value> <string>string</string> </value>
</item>
</dictionary>
</tuple>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>elementary_type/string</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>preferred_default_pre_payment_template_property</string> </value>
</item>
<item>
<key> <string>mode</string> </key>
<value> <string>w</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Standard Property</string> </value>
</item>
<item>
<key> <string>preference</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>property_default</string> </key>
<value> <string>python: \'\'</string> </value>
</item>
<item>
<key> <string>write_permission</string> </key>
<value> <string>Manage properties</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Standard Property" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_local_properties</string> </key>
<value>
<tuple>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>mode</string> </value>
</item>
<item>
<key> <string>type</string> </key>
<value> <string>string</string> </value>
</item>
</dictionary>
</tuple>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>elementary_type/string</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>preferred_instance_delivery_template_property</string> </value>
</item>
<item>
<key> <string>mode</string> </key>
<value> <string>w</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Standard Property</string> </value>
</item>
<item>
<key> <string>preference</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>property_default</string> </key>
<value> <string>python: \'\'</string> </value>
</item>
<item>
<key> <string>write_permission</string> </key>
<value> <string>Manage properties</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
if True:
return "disabled as not matching yet the virtual master design"
portal = context.getPortalObject() portal = context.getPortalObject()
portal.portal_catalog.searchAndActivate( portal.portal_catalog.searchAndActivate(
......
...@@ -10,7 +10,7 @@ if (context.getSimulationState() == 'confirmed')\ ...@@ -10,7 +10,7 @@ if (context.getSimulationState() == 'confirmed')\
and (context.getLedger() == 'automated')\ and (context.getLedger() == 'automated')\
and (context.getCausalityState() == 'solved')\ and (context.getCausalityState() == 'solved')\
and (0 < len(context.objectValues(portal_type="Sale Invoice Transaction Line"))\ and (0 < len(context.objectValues(portal_type="Sale Invoice Transaction Line"))\
and (context.getStopDate(now) < now)): and (context.getStopDate(now) <= now)):
if context.getSourcePayment("") == "": if context.getSourcePayment("") == "":
context.setSourcePayment(context.AccountingTransaction_getSourcePaymentItemList()[-1][1]) context.setSourcePayment(context.AccountingTransaction_getSourcePaymentItemList()[-1][1])
......
portal = context
result_list = []
if specialise_uid is None:
current_uid_list = []
elif same_type(specialise_uid, []) or same_type(specialise_uid, ()):
current_uid_list = list(specialise_uid)
else:
current_uid_list = [specialise_uid]
search_kw = {}
if portal_type is not None:
search_kw['portal_type'] = portal_type
if validation_state is not None:
search_kw['validation_state'] = validation_state
if destination_section__uid is not None:
search_kw['destination_section__uid'] = destination_section__uid
# This is REALLY INEFFICIENT.
# Keep it simple for now, as the goal is probably to drop all this script usage
while (current_uid_list):
specialise__uid = current_uid_list
current_uid_list = []
for sql_result in portal.portal_catalog(
specialise__uid=specialise__uid,
**search_kw
):
current_uid_list.append(sql_result.uid)
result_list.append(sql_result)
return result_list
from Products.ERP5Type.Message import translateString
from zExceptions import Unauthorized from zExceptions import Unauthorized
if REQUEST is not None: if REQUEST is not None:
raise Unauthorized raise Unauthorized
...@@ -7,72 +6,93 @@ portal = context.getPortalObject() ...@@ -7,72 +6,93 @@ portal = context.getPortalObject()
if not invoice_list: if not invoice_list:
raise ValueError('You need to provide at least one Invoice transaction') raise ValueError('You need to provide at least one Invoice transaction')
# For now consider a single value is passed, in future we intend to create payment_tag = 'Entity_createPaymentTransaction_%s' % context.getUid()
# a single payment per invoice.
current_invoice = invoice_list[0]
payment_tag = "sale_invoice_transaction_create_payment_%s" % current_invoice.getUid()
if context.REQUEST.get(payment_tag, None) is not None: if context.REQUEST.get(payment_tag, None) is not None:
raise ValueError('This script was already called twice on the same transaction ') raise ValueError('This script was already called twice on the same transaction ')
activate_kw = {
'tag': payment_tag
}
if current_invoice.SaleInvoiceTransaction_isLettered(): # Ensure all invoice use the same arrow and resource
first_invoice = invoice_list[0]
identical_dict = {
'getSource': first_invoice.getSource(),
'getSourceSection': first_invoice.getSourceSection(),
'getSourcePayment': first_invoice.getSourcePayment(),
'getDestination': first_invoice.getDestination(),
'getDestinationSection': first_invoice.getDestinationSection(),
'getPriceCurrency': first_invoice.getPriceCurrency(),
'getLedger': first_invoice.getLedger(),
}
price = 0
causality_uid_list = []
# Check that all invoice matches
for invoice in invoice_list:
for method_id, method_value in identical_dict.items():
if getattr(invoice, method_id)() != method_value:
raise ValueError('Invoices do not match on method: %s' % method_id)
if invoice.total_price:
price += invoice.total_price
causality_uid_list.append(invoice.payment_request_uid)
if invoice.SaleInvoiceTransaction_isLettered():
raise ValueError('This invoice is already lettered') raise ValueError('This invoice is already lettered')
context.serialize() if not price:
quantity = 0 raise ValueError('No total_price to pay')
for movement in current_invoice.searchFolder( if first_invoice.getDestinationSection() != context.getRelativeUrl():
portal_type='Sale Invoice Transaction Line', raise ValueError('Invoice not related to the context')
default_source_uid=[i.uid for i in context.Base_getReceivableAccountList()]):
quantity += movement.getQuantity()
if quantity >= 0: if start_date is None:
raise ValueError('You cannot generate Payment Transaction for zero or negative amounts.') start_date = DateTime()
current_payment = portal.accounting_module.newContent( # create the payment transaction
portal_type="Payment Transaction", payment_transaction = portal.accounting_module.newContent(
causality=current_invoice.getRelativeUrl(), portal_type='Payment Transaction',
source_section=current_invoice.getSourceSection(), created_by_builder=True,
source_project=current_invoice.getSourceProject(), causality_uid_set=causality_uid_list,
destination_section=current_invoice.getDestinationSection(), source_section=first_invoice.getSourceSection(),
destination_project=current_invoice.getDestinationProject(), source_payment=first_invoice.getSourcePayment(),
resource=current_invoice.getResource(), destination_section=first_invoice.getDestinationSection(),
price_currency=current_invoice.getResource(), destination_section_value=context,
specialise=current_invoice.getSpecialise(), start_date=start_date,
payment_mode=current_invoice.getPaymentMode(), payment_mode=payment_mode,
ledger=current_invoice.getLedger(), #specialise
start_date=current_invoice.getStartDate(), ledger=first_invoice.getLedger(),
stop_date=current_invoice.getStopDate(), resource=first_invoice.getResource(),
source_payment=current_invoice.getSourcePayment(), destination_administration=destination_administration,
# Workarround to not create default lines. activate_kw=activate_kw
created_by_builder=1
) )
current_payment.newContent( getAccountForUse = context.Base_getAccountForUse
portal_type="Accounting Transaction Line",
quantity=-1 * quantity,
source='account_module/receivable',
destination='account_module/payable',
start_date=current_invoice.getStartDate(),
stop_date=current_invoice.getStopDate())
current_payment.newContent( collection_account = getAccountForUse('collection')
portal_type="Accounting Transaction Line", payment_transaction.newContent(
quantity=1 * quantity, id='bank',
source='account_module/payment_to_encash', portal_type='Accounting Transaction Line',
destination='account_module/payment_to_encash', source_value=collection_account,
start_date=current_invoice.getStartDate(), destination_value=collection_account,
stop_date=current_invoice.getStopDate()) quantity=-price,
activate_kw=activate_kw,
)
comment = translateString("Initialised by Entity_createPaymentTransaction.") for index, line in enumerate(invoice_list):
if line.total_price:
payment_transaction.newContent(
id="receivable%s" % index,
title="receivable%s - %s" % (index, line.getSourceReference()),
portal_type='Accounting Transaction Line',
source=line.node_relative_url,
destination_value=getAccountForUse('payable'),
quantity=line.total_price,
activate_kw=activate_kw,
)
# Reindex with a tag to ensure that there will be no generation while the object isn't assert len(payment_transaction.checkConsistency()) == 0
# reindexed.
payment_tag ="sale_invoice_transaction_create_payment_%s" % current_invoice.getUid()
current_payment.activate(tag=payment_tag).immediateReindexObject()
comment = translateString("Initialised by Entity_createPaymentTransaction.") payment_transaction.start()
current_payment.PaymentTransaction_start(comment=comment)
# Set a flag on the request for prevent 2 calls on the same transaction # Set a flag on the request for prevent 2 calls on the same transaction
context.REQUEST.set(payment_tag, 1) context.REQUEST.set(payment_tag, 1)
return current_payment return payment_transaction
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>invoice_list, REQUEST=None</string> </value> <value> <string>invoice_list, destination_administration=None, payment_mode=None, start_date=None, REQUEST=None</string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
......
portal = context.getPortalObject()
Base_translateString = portal.Base_translateString
outstanding_amount = portal.restrictedTraverse(outstanding_amount)
# Check that the total_price matches the outstanding amount list
expected_price = context.Entity_getOutstandingAmountList(
include_planned=False,
at_date=date,
section_uid=outstanding_amount.getSourceSectionUid(),
resource_uid=outstanding_amount.getPriceCurrencyUid(),
ledger_uid=outstanding_amount.getLedgerUid(),
group_by_node=True
)[0].total_price
if total_price != expected_price:
return context.Base_renderForm(dialog_id, Base_translateString('Total Amount does not match'), level='error')
payment_transaction = context.Entity_createPaymentTransaction(
context.Entity_getOutstandingAmountList(
include_planned=False,
at_date=date,
section_uid=outstanding_amount.getSourceSectionUid(),
resource_uid=outstanding_amount.getPriceCurrencyUid(),
ledger_uid=outstanding_amount.getLedgerUid(),
group_by_node=False
),
start_date=date,
payment_mode=payment_mode
)
payment_transaction.stop()
return payment_transaction.Base_redirect()
...@@ -50,11 +50,11 @@ ...@@ -50,11 +50,11 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>specialise_uid, portal_type=None, validation_state=None, destination_section__uid=None</string> </value> <value> <string>date, payment_mode, outstanding_amount, total_price, dialog_id, **kw</string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>ERP5Site_searchRelatedInheritedSpecialiseList</string> </value> <value> <string>Entity_createPaymentTransactionAction</string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
"""return a list of invoices with the following attributes: """return a list of invoices with the following attributes:
- payment_request_uid: the uid of the invoice, we consider that payment request is the invoice. - payment_request_uid: the uid of the invoice
- node_relative_url : the url of the account ( if group_by_node=True is passed ).
- total_price: the amount left to pay for this invoice - total_price: the amount left to pay for this invoice
- getTotalPrice: the original amount of this invoice. - getTotalPrice: the original amount of this invoice.
Arguments: Arguments:
- group_by_node (default True)
If you pass group_by_node=False you have a list of all invoices,
without the breakdown by account but if you pass group_by_node=True,
you have on line for each account.
To display to the user the list of invoices he has to pay, pass group_by_node=False,
to create a list to pass to Entity_createPaymentTransaction, use group_by_node=True.
- at_date (default None) - at_date (default None)
- include_planned (default True)
In current configuration, planned transactions, are used only in Payment Transactions for invoices of non-debitable customers.
If you pass include_planned=True, you will get only unpaid invoices for which payment deadline is past
If you pass include_planned=False, you will get all unpaid invoices, also those for which payment deadline is not past
""" """
from Products.ZSQLCatalog.SQLCatalog import SimpleQuery, ComplexQuery
portal = context.getPortalObject() portal = context.getPortalObject()
params = dict() params = dict()
if at_date: if at_date:
params['at_date'] = at_date params['at_date'] = at_date
params['grouping_query'] = ComplexQuery(
params['grouping_reference'] = None SimpleQuery(grouping_reference=None),
SimpleQuery(grouping_date=at_date, comparison_operator=">"),
logical_operator="OR")
else:
params['grouping_reference'] = None
object_list = [] object_list = []
if include_planned:
simulation_state_tuple = ('stopped', 'delivered', 'planned', 'confirmed', 'started')
else:
simulation_state_tuple = ('stopped', 'delivered')
if section_uid is None:
params['group_by_mirror_section'] = True
else:
params['section_uid'] = section_uid
if resource_uid is None:
params['group_by_resource'] = True
else:
params['resource_uid'] = resource_uid
if ledger_uid is None:
params['group_by_ledger'] = True
else:
params['ledger_uid'] = ledger_uid
for (idx, brain) in enumerate(portal.portal_simulation.getInventoryList( for (idx, brain) in enumerate(portal.portal_simulation.getInventoryList(
mirror_section_uid=context.getUid(), mirror_section_uid=context.getUid(),
simulation_state=('stopped', 'delivered'), simulation_state=simulation_state_tuple,
group_by_payment_request=True,
group_by_node=group_by_node,
node_uid=[x.uid for x in context.Base_getReceivableAccountList()] or -1, node_uid=[x.uid for x in context.Base_getReceivableAccountList()] or -1,
**params )): **params )):
...@@ -26,13 +65,14 @@ for (idx, brain) in enumerate(portal.portal_simulation.getInventoryList( ...@@ -26,13 +65,14 @@ for (idx, brain) in enumerate(portal.portal_simulation.getInventoryList(
# directly in listbox. We should probably add support for this in getInventoryList instead # directly in listbox. We should probably add support for this in getInventoryList instead
# of this hack # of this hack
# XXX In our case, this hould be always None.
payment_request_uid = brain.payment_request_uid payment_request_uid = brain.payment_request_uid
if not payment_request_uid: if not payment_request_uid:
payment_request_uid = brain.getObject().getExplanationUid() payment_request_uid = brain.getObject().getExplanationUid()
payment_request = portal.portal_catalog.getObject(uid=payment_request_uid) payment_request = portal.portal_catalog.getObject(uid=payment_request_uid)
object_list.append(payment_request.asContext( object_list.append(payment_request.asContext(
section_uid=brain.section_uid, section_uid=brain.section_uid,
resource_uid=brain.resource_uid,
ledger_uid=brain.ledger_uid,
payment_request_uid=payment_request_uid, payment_request_uid=payment_request_uid,
node_uid=brain.node_uid, node_uid=brain.node_uid,
node_relative_url=brain.node_relative_url, node_relative_url=brain.node_relative_url,
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>at_date=None, **kw</string> </value> <value> <string>resource_uid=None, section_uid=None, group_by_node=True, at_date=None, include_planned=True, ledger_uid=None, **kw</string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
......
...@@ -50,11 +50,11 @@ ...@@ -50,11 +50,11 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>at_date=None, resource_uid=None, **kw</string> </value> <value> <string>*args, **kw</string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>Entity_statOutstandingAmount</string> </value> <value> <string>Entity_hasOutstandingAmount</string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
portal = context.getPortalObject()
params = {"node_category_strict_membership": ['account_type/asset/receivable',
'account_type/liability/payable']}
if at_date:
params['at_date'] = at_date
params['grouping_reference'] = None
if resource_uid is not None:
params["resource_uid"] = resource_uid
return portal.portal_simulation.getInventoryAssetPrice(
mirror_section_uid = context.getUid(),
simulation_state=('stopped', 'delivered'),
portal_type=portal.getPortalAccountingMovementTypeList(),
**params)
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ERP5 Form" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>action</string> </key>
<value> <string>Entity_createPaymentTransactionAction</string> </value>
</item>
<item>
<key> <string>action_title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>edit_order</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>encoding</string> </key>
<value> <string>UTF-8</string> </value>
</item>
<item>
<key> <string>enctype</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>group_list</string> </key>
<value>
<list>
<string>left</string>
<string>right</string>
<string>center</string>
<string>bottom</string>
<string>hidden</string>
</list>
</value>
</item>
<item>
<key> <string>groups</string> </key>
<value>
<dictionary>
<item>
<key> <string>bottom</string> </key>
<value>
<list>
<string>current_regularisation_request_listbox</string>
</list>
</value>
</item>
<item>
<key> <string>center</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>hidden</string> </key>
<value>
<list>
<string>current_regularisation_request_listbox_start_date</string>
</list>
</value>
</item>
<item>
<key> <string>left</string> </key>
<value>
<list>
<string>your_date</string>
<string>your_payment_mode</string>
<string>your_outstanding_amount</string>
<string>your_total_price</string>
</list>
</value>
</item>
<item>
<key> <string>right</string> </key>
<value>
<list/>
</value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Entity_viewCreatePaymentTransactionDialog</string> </value>
</item>
<item>
<key> <string>method</string> </key>
<value> <string>POST</string> </value>
</item>
<item>
<key> <string>name</string> </key>
<value> <string>Entity_viewCreatePaymentTransaction1Dialog</string> </value>
</item>
<item>
<key> <string>pt</string> </key>
<value> <string>form_dialog</string> </value>
</item>
<item>
<key> <string>row_length</string> </key>
<value> <int>4</int> </value>
</item>
<item>
<key> <string>stored_encoding</string> </key>
<value> <string>UTF-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Create Payment</string> </value>
</item>
<item>
<key> <string>unicode_mode</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>update_action</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>update_action_title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>columns</string>
<string>default_params</string>
<string>list_method</string>
<string>portal_types</string>
<string>sort_columns</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>current_regularisation_request_listbox</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>columns</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default_params</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>list_method</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>portal_types</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>sort_columns</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>columns</string> </key>
<value>
<list>
<tuple>
<string>reference</string>
<string> Reference</string>
</tuple>
<tuple>
<string>resource_title</string>
<string>Resource</string>
</tuple>
<tuple>
<string>start_date</string>
<string>Start Date</string>
</tuple>
<tuple>
<string>translated_simulation_state_title</string>
<string>State</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>default_params</string> </key>
<value>
<list>
<tuple>
<string>checked_permission</string>
<string>View</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_view_mode_listbox</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>list_method</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>portal_types</string> </key>
<value>
<list>
<tuple>
<string>Regularisation Request</string>
<string>Regularisation Request</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>sort_columns</string> </key>
<value>
<list>
<tuple>
<string>None</string>
<string>sorting disabled</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Current Regularisation Request</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: [(\'destination_decision__uid\', context.getUid())]</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="Method" module="Products.Formulator.MethodField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>method_name</string> </key>
<value> <string>portal_catalog</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>editable</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>current_regularisation_request_listbox_start_date</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>editable</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_date_time_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Start Date</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>default_now</string>
<string>required</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>your_date</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>default_now</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_date_time_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Date</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>first_item</string>
<string>items</string>
<string>required</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>your_outstanding_amount</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>first_item</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_list_field</string> </value>
</item>
<item>
<key> <string>first_item</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Supplier</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: [("%s (%s %s)" % (x.getSourceTitle(), x.total_price, x.getPriceCurrencyReference()), x.getRelativeUrl()) for x in context.Entity_getOutstandingAmountList(include_planned=False)] + [("", "")]</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>required</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>your_payment_mode</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_dialog_mode_category</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Payment Mode</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>required</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>your_total_price</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_view_mode_money_quantity</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Confirm Total Amount</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -32,7 +32,7 @@ open_sale_order = portal.getDefaultModule(portal_type=order_portal_type).newCont ...@@ -32,7 +32,7 @@ open_sale_order = portal.getDefaultModule(portal_type=order_portal_type).newCont
destination_section_value=payment_transaction.getDestinationSectionValue(), destination_section_value=payment_transaction.getDestinationSectionValue(),
destination_decision_value=payment_transaction.getDestinationDecisionValue(), destination_decision_value=payment_transaction.getDestinationDecisionValue(),
destination_project_value=payment_transaction.getDestinationProjectValue(), destination_project_value=payment_transaction.getDestinationProjectValue(),
ledger_value=portal.portal_categories.ledger.automated, ledger_value=payment_transaction.getLedgerValue(),
causality_value=payment_transaction, causality_value=payment_transaction,
price_currency_value=payment_transaction.getResourceValue(), price_currency_value=payment_transaction.getResourceValue(),
activate_kw=activate_kw activate_kw=activate_kw
......
from zExceptions import Unauthorized
if REQUEST is not None:
raise Unauthorized
if context.getPortalType() != "Payment Transaction":
raise Unauthorized
context.confirm(comment=comment)
context.start(comment=comment)
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
<global name="object" module="__builtin__"/>
<none/>
</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>_params</string> </key>
<value> <string>comment="", REQUEST=None</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>PaymentTransaction_start</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -45,17 +45,17 @@ payment_transaction = portal.accounting_module.newContent( ...@@ -45,17 +45,17 @@ payment_transaction = portal.accounting_module.newContent(
stop_date=now, stop_date=now,
specialise_value=tmp_sale_order.getSpecialiseValue(), specialise_value=tmp_sale_order.getSpecialiseValue(),
source_value=tmp_sale_order.getSourceValue(), source=tmp_sale_order.getSource(),
source_section_value=tmp_sale_order.getSourceSectionValue(), source_section=tmp_sale_order.getSourceSection(),
source_decision_value=tmp_sale_order.getSourceDecisionValue(), source_decision=tmp_sale_order.getSourceDecision(),
source_project_value=tmp_sale_order.getSourceProjectValue(), source_project=tmp_sale_order.getSourceProject(),
destination_value=tmp_sale_order.getDestinationValue(), destination=tmp_sale_order.getDestination(),
destination_section_value=tmp_sale_order.getDestinationSectionValue(), destination_section=tmp_sale_order.getDestinationSection(),
destination_decision_value=tmp_sale_order.getDestinationDecisionValue(), destination_decision=tmp_sale_order.getDestinationDecision(),
destination_project_value=tmp_sale_order.getDestinationProjectValue(), destination_project=tmp_sale_order.getDestinationProject(),
ledger_value=portal.portal_categories.ledger.automated, ledger_value=portal.portal_categories.ledger.automated,
resource_value=tmp_sale_order.getPriceCurrencyValue(), resource=tmp_sale_order.getPriceCurrency(),
created_by_builder=1, # XXX this prevent init script from creating lines. created_by_builder=1, # XXX this prevent init script from creating lines.
activate_kw={'tag':'%s_init' % context.getRelativeUrl()} activate_kw={'tag':'%s_init' % context.getRelativeUrl()}
) )
...@@ -87,6 +87,6 @@ if len(payment_transaction.checkConsistency()) != 0: ...@@ -87,6 +87,6 @@ if len(payment_transaction.checkConsistency()) != 0:
#tag = '%s_update' % context.getDestinationReference() #tag = '%s_update' % context.getDestinationReference()
comment = translateString("Deposit payment.") comment = translateString("Deposit payment.")
payment_transaction.PaymentTransaction_start(comment=comment) payment_transaction.start(comment=comment)
return payment_transaction return payment_transaction
...@@ -95,6 +95,8 @@ while count > 0 and len(trade_condition_list) == 0: ...@@ -95,6 +95,8 @@ while count > 0 and len(trade_condition_list) == 0:
filter_kw['source_project__uid'] = order.getSourceProjectUid() filter_kw['source_project__uid'] = order.getSourceProjectUid()
if order.hasPriceCurrency(): if order.hasPriceCurrency():
filter_kw['price_currency__uid'] = order.getPriceCurrencyUid() filter_kw['price_currency__uid'] = order.getPriceCurrencyUid()
if order.hasTradeConditionType():
filter_kw['trade_condition_type__uid'] = order.getTradeConditionTypeUid()
trade_condition_list = context.portal_domains.searchPredicateList( trade_condition_list = context.portal_domains.searchPredicateList(
predicate_context, predicate_context,
......
if True:
return "disabled as not matching yet the virtual master design"
from zExceptions import Unauthorized from zExceptions import Unauthorized
if REQUEST is not None: if REQUEST is not None:
raise Unauthorized raise Unauthorized
...@@ -20,7 +23,7 @@ if tioxml_dict is None: ...@@ -20,7 +23,7 @@ if tioxml_dict is None:
else: else:
compute_node = context.getContributorValue(portal_type="Compute Node") compute_node = context.getContributorValue(portal_type="Compute Node")
compute_node_project_document = compute_node.Item_getCurrentProjectValue() compute_node_project_document = compute_node.getFollowUpValue()
delivery_title = tioxml_dict['title'] delivery_title = tioxml_dict['title']
compute_node_project = None compute_node_project = None
......
...@@ -19,6 +19,10 @@ if invoice.getResource() != price_currency: ...@@ -19,6 +19,10 @@ if invoice.getResource() != price_currency:
causality_list = invoice.getCausalityList() causality_list = invoice.getCausalityList()
for simulation_movement in related_simulation_movement_path_list: for simulation_movement in related_simulation_movement_path_list:
simulation_movement = portal.restrictedTraverse(simulation_movement) simulation_movement = portal.restrictedTraverse(simulation_movement)
if not simulation_movement.getExplanation().startswith(invoice.getRelativeUrl()):
# Beware, the simulation movement may be not used to build the invoice
# related_simulation_movement_path_list is the movement_list used by the builder
continue
applied_rule = simulation_movement.getParentValue() applied_rule = simulation_movement.getParentValue()
if applied_rule.getParentId() != 'portal_simulation': if applied_rule.getParentId() != 'portal_simulation':
causality = applied_rule.getParentValue().getExplanationValue() causality = applied_rule.getParentValue().getExplanationValue()
......
...@@ -30,13 +30,13 @@ import transaction ...@@ -30,13 +30,13 @@ import transaction
from functools import wraps from functools import wraps
from Products.ERP5Type.tests.utils import createZODBPythonScript from Products.ERP5Type.tests.utils import createZODBPythonScript
from erp5.component.test.SlapOSTestCaseMixin import SlapOSTestCaseMixin, withAbort, TemporaryAlarmScript from erp5.component.test.SlapOSTestCaseMixin import SlapOSTestCaseMixin, withAbort, TemporaryAlarmScript
from unittest import expectedFailure
import os import os
import tempfile import tempfile
from DateTime import DateTime from DateTime import DateTime
AGGREGATE_SALE_TRADE_CONDITION_RELATIVE_URL = 'sale_trade_condition_module/slapos_aggregated_trade_condition_v3'
class Simulator: class Simulator:
def __init__(self, outfile, method, to_return=None): def __init__(self, outfile, method, to_return=None):
...@@ -521,6 +521,7 @@ class TestSlapOSGeneratePackingListFromTioXML(SlapOSTestCaseMixin): ...@@ -521,6 +521,7 @@ class TestSlapOSGeneratePackingListFromTioXML(SlapOSTestCaseMixin):
) )
return document return document
@expectedFailure
def test_ComputerConsumptionTioXMLFile_solveInvoicingGeneration_alarm(self): def test_ComputerConsumptionTioXMLFile_solveInvoicingGeneration_alarm(self):
document = self.createTioXMLFile() document = self.createTioXMLFile()
document.submit() document.submit()
......
...@@ -1998,8 +1998,8 @@ class TestSlapOSAggregatedDeliveryBuilder(SlapOSTestCaseMixin): ...@@ -1998,8 +1998,8 @@ class TestSlapOSAggregatedDeliveryBuilder(SlapOSTestCaseMixin):
return delivery_line return delivery_line
def test(self): def test(self):
person = self.portal.person_module.template_member\ person = self.portal.person_module\
.Base_createCloneDocument(batch_mode=1) .newContent(portal_type="Person")
delivery = self._createDelivery(destination_value=person, delivery = self._createDelivery(destination_value=person,
destination_decision_value=person) destination_decision_value=person)
delivery_line = self._addDeliveryLine(delivery) delivery_line = self._addDeliveryLine(delivery)
...@@ -2037,8 +2037,8 @@ class TestSlapOSAggregatedDeliveryBuilder(SlapOSTestCaseMixin): ...@@ -2037,8 +2037,8 @@ class TestSlapOSAggregatedDeliveryBuilder(SlapOSTestCaseMixin):
built_delivery_line.getResource()) built_delivery_line.getResource())
def test_many_lines(self): def test_many_lines(self):
person = self.portal.person_module.template_member\ person = self.portal.person_module\
.Base_createCloneDocument(batch_mode=1) .newContent(portal_type="Person")
delivery = self._createDelivery(destination_value=person, delivery = self._createDelivery(destination_value=person,
destination_decision_value=person) destination_decision_value=person)
setup_line_1 = self._addDeliveryLine(delivery) setup_line_1 = self._addDeliveryLine(delivery)
...@@ -2100,8 +2100,8 @@ class TestSlapOSAggregatedDeliveryBuilder(SlapOSTestCaseMixin): ...@@ -2100,8 +2100,8 @@ class TestSlapOSAggregatedDeliveryBuilder(SlapOSTestCaseMixin):
built_subscription_line.getResource()) built_subscription_line.getResource())
def test_added_after(self): def test_added_after(self):
person = self.portal.person_module.template_member\ person = self.portal.person_module\
.Base_createCloneDocument(batch_mode=1) .newContent(portal_type="Person")
delivery = self._createDelivery(destination_value=person, delivery = self._createDelivery(destination_value=person,
destination_decision_value=person) destination_decision_value=person)
delivery_line = self._addDeliveryLine(delivery) delivery_line = self._addDeliveryLine(delivery)
......
...@@ -11,7 +11,6 @@ from unittest import skip ...@@ -11,7 +11,6 @@ from unittest import skip
import transaction import transaction
AGGREGATE_SALE_TRADE_CONDITION_RELATIVE_URL = 'sale_trade_condition_module/slapos_aggregated_trade_condition_v3'
class TestHostingSubscription(TestSlapOSConstraintMixin): class TestHostingSubscription(TestSlapOSConstraintMixin):
...@@ -152,16 +151,14 @@ class TestSaleInvoiceTransaction(TestSlapOSConstraintMixin): ...@@ -152,16 +151,14 @@ class TestSaleInvoiceTransaction(TestSlapOSConstraintMixin):
def test_specialise_value(self): def test_specialise_value(self):
invoice = self.portal.accounting_module.newContent( invoice = self.portal.accounting_module.newContent(
portal_type='Sale Invoice Transaction') portal_type='Sale Invoice Transaction')
message = "Only SlapOS trade condition is allowed" message = "Arity Error for Relation ['specialise'] and Type " + \
"('Sale Trade Condition',), arity is equal to 0 but should be at least 1"
self.assertTrue(message in self.getMessageList(invoice)) self.assertTrue(message in self.getMessageList(invoice))
sale_condition = self.portal.sale_trade_condition_module.newContent( sale_condition = self.portal.sale_trade_condition_module.newContent(
portal_type='Sale Trade Condition') portal_type='Sale Trade Condition')
invoice.setSpecialise(sale_condition.getRelativeUrl()) invoice.setSpecialise(sale_condition.getRelativeUrl())
self.assertTrue(message in self.getMessageList(invoice))
invoice.setSpecialise(AGGREGATE_SALE_TRADE_CONDITION_RELATIVE_URL)
self.assertFalse(message in self.getMessageList(invoice)) self.assertFalse(message in self.getMessageList(invoice))
@withAbort @withAbort
...@@ -183,12 +180,38 @@ class TestSaleInvoiceTransaction(TestSlapOSConstraintMixin): ...@@ -183,12 +180,38 @@ class TestSaleInvoiceTransaction(TestSlapOSConstraintMixin):
@withAbort @withAbort
def test_trade_model_match_lines(self): def test_trade_model_match_lines(self):
message = "Defined Trade Model does not match Lines definition" message = "Defined Trade Model does not match Lines definition"
currency = self.portal.currency_module.EUR
sale_trade_condition = self.portal.sale_trade_condition_module.newContent(
portal_type="Sale Trade Condition",
reference="Tax/payment for: %s" % currency.getRelativeUrl(),
trade_condition_type="default",
# XXX hardcoded
specialise="business_process_module/slapos_ultimate_business_process",
price_currency_value=currency,
payment_condition_payment_mode='test-%s' % self.generateNewId()
)
sale_trade_condition.newContent(
portal_type="Trade Model Line",
reference="VAT",
resource="service_module/slapos_tax",
base_application="base_amount/invoicing/taxable",
trade_phase="slapos/tax",
price=0.2,
quantity=1.0,
membership_criterion_base_category=('price_currency', 'base_contribution'),
membership_criterion_category=(
'price_currency/%s' % currency.getRelativeUrl(),
'base_contribution/base_amount/invoicing/taxable'
)
)
sale_trade_condition.validate()
invoice = self.portal.accounting_module.newContent( invoice = self.portal.accounting_module.newContent(
portal_type='Sale Invoice Transaction', portal_type='Sale Invoice Transaction',
price_currency='currency_module/EUR', price_currency_value=currency,
specialise=AGGREGATE_SALE_TRADE_CONDITION_RELATIVE_URL) specialise_value=sale_trade_condition)
invoice.newContent(portal_type='Invoice Line', quantity=1., price=1., invoice.newContent(portal_type='Invoice Line', quantity=1., price=1.,
base_contribution='base_amount/invoicing/taxable') base_contribution='base_amount/invoicing/taxable')
self.tic()
self.assertFalse(message in self.getMessageList(invoice)) self.assertFalse(message in self.getMessageList(invoice))
self.portal.portal_workflow._jumpToStateFor(invoice, 'confirmed') self.portal.portal_workflow._jumpToStateFor(invoice, 'confirmed')
...@@ -202,20 +225,47 @@ class TestSaleInvoiceTransaction(TestSlapOSConstraintMixin): ...@@ -202,20 +225,47 @@ class TestSaleInvoiceTransaction(TestSlapOSConstraintMixin):
@withAbort @withAbort
def test_use_trade_sale_total_price_matches_delivery_constraint(self): def test_use_trade_sale_total_price_matches_delivery_constraint(self):
message = "Total price does not match related Sale Packing List" message = "Total price does not match related Sale Packing List"
currency = self.portal.currency_module.EUR
sale_trade_condition = self.portal.sale_trade_condition_module.newContent(
portal_type="Sale Trade Condition",
reference="Tax/payment for: %s" % currency.getRelativeUrl(),
trade_condition_type="default",
# XXX hardcoded
specialise="business_process_module/slapos_ultimate_business_process",
price_currency_value=currency,
payment_condition_payment_mode='test-%s' % self.generateNewId()
)
sale_trade_condition.newContent(
portal_type="Trade Model Line",
reference="VAT",
resource="service_module/slapos_tax",
base_application="base_amount/invoicing/taxable",
trade_phase="slapos/tax",
price=0.2,
quantity=1.0,
membership_criterion_base_category=('price_currency', 'base_contribution'),
membership_criterion_category=(
'price_currency/%s' % currency.getRelativeUrl(),
'base_contribution/base_amount/invoicing/taxable'
)
)
sale_trade_condition.validate()
delivery = self.portal.sale_packing_list_module.newContent( delivery = self.portal.sale_packing_list_module.newContent(
portal_type='Sale Packing List') portal_type='Sale Packing List')
delivery.newContent(portal_type='Sale Packing List Line', delivery.newContent(portal_type='Sale Packing List Line',
use='trade/sale', quantity=1., price=1.) use='trade/sale', quantity=1., price=1.)
invoice = self.portal.accounting_module.newContent( invoice = self.portal.accounting_module.newContent(
portal_type='Sale Invoice Transaction', portal_type='Sale Invoice Transaction',
causality=delivery.getRelativeUrl()) ledger="automated",
specialise_value=sale_trade_condition)
invoice_line = invoice.newContent(portal_type='Invoice Line', quantity=2., invoice_line = invoice.newContent(portal_type='Invoice Line', quantity=2.,
price=1., use='trade/sale') price=1., use='trade/sale')
self.assertFalse(message in self.getMessageList(invoice)) self.assertFalse(message in self.getMessageList(invoice))
self.portal.portal_workflow._jumpToStateFor(invoice, 'confirmed') self.portal.portal_workflow._jumpToStateFor(invoice, 'confirmed')
self.assertFalse(message in self.getMessageList(invoice)) self.assertFalse(message in self.getMessageList(invoice))
invoice.setSpecialise(AGGREGATE_SALE_TRADE_CONDITION_RELATIVE_URL) invoice.setCausalityValue(delivery)
self.assertTrue(message in self.getMessageList(invoice)) self.assertTrue(message in self.getMessageList(invoice))
invoice_line.setQuantity(1.) invoice_line.setQuantity(1.)
self.assertFalse(message in self.getMessageList(invoice)) self.assertFalse(message in self.getMessageList(invoice))
...@@ -304,9 +354,6 @@ class TestSalePackingList(TestSlapOSConstraintMixin): ...@@ -304,9 +354,6 @@ class TestSalePackingList(TestSlapOSConstraintMixin):
def test_source(self): def test_source(self):
self._test_category_arrow('source') self._test_category_arrow('source')
def test_source_section(self):
self._test_category_arrow('source_section')
@withAbort @withAbort
def test_specialise(self): def test_specialise(self):
category = 'specialise' category = 'specialise'
...@@ -345,28 +392,20 @@ class TestSalePackingList(TestSlapOSConstraintMixin): ...@@ -345,28 +392,20 @@ class TestSalePackingList(TestSlapOSConstraintMixin):
class TestSalePackingListLine(TestSlapOSConstraintMixin): class TestSalePackingListLine(TestSlapOSConstraintMixin):
@withAbort @withAbort
def test_property_existence(self): def test_property_existence(self):
message = 'Property existence error for property %s, this document has '\ message_quantity = 'No quantity defined'
'no such property or the property has never been set'
message_price = message % 'price'
message_quantity = message % 'quantity'
delivery_line = self.portal.sale_packing_list_module.newContent( delivery_line = self.portal.sale_packing_list_module.newContent(
portal_type='Sale Packing List').newContent( portal_type='Sale Packing List').newContent(
portal_type='Sale Packing List Line') portal_type='Sale Packing List Line')
self.assertTrue(message_price in self.getMessageList(delivery_line))
self.assertTrue(message_quantity in self.getMessageList(delivery_line)) self.assertTrue(message_quantity in self.getMessageList(delivery_line))
delivery_line.setQuantity(1.0) delivery_line.setQuantity(1.0)
self.assertTrue(message_price in self.getMessageList(delivery_line))
self.assertFalse(message_quantity in self.getMessageList(delivery_line))
delivery_line.setPrice(1.0)
self.assertFalse(message_price in self.getMessageList(delivery_line))
self.assertFalse(message_quantity in self.getMessageList(delivery_line)) self.assertFalse(message_quantity in self.getMessageList(delivery_line))
@withAbort @withAbort
def test_resource_arity(self): def test_resource_arity(self):
category = 'resource' category = 'resource'
message = "Arity Error for Relation ['%s'] and Type ('Data Operation', 'Service'), arity is"\ message = "Arity Error for Relation ['%s'] and Type ('Data Operation', 'Service', 'Software Product'), arity is"\
" equal to 0 but should be between 1 and 1" % category " equal to 0 but should be between 1 and 1" % category
message_2 = "Arity Error for Relation ['%s'] and Type ('Data Operation', 'Service'), arity is"\ message_2 = "Arity Error for Relation ['%s'] and Type ('Data Operation', 'Service', 'Software Product'), arity is"\
" equal to 2 but should be between 1 and 1" % category " equal to 2 but should be between 1 and 1" % category
delivery_line = self.portal.sale_packing_list_module.newContent( delivery_line = self.portal.sale_packing_list_module.newContent(
portal_type='Sale Packing List').newContent( portal_type='Sale Packing List').newContent(
......
...@@ -2,85 +2,12 @@ ...@@ -2,85 +2,12 @@
from erp5.component.test.SlapOSTestCaseMixin import SlapOSTestCaseMixin, simulate from erp5.component.test.SlapOSTestCaseMixin import SlapOSTestCaseMixin, simulate
import transaction import transaction
from DateTime import DateTime
class TestSlapOSAccountingInteractionWorkflow(SlapOSTestCaseMixin): class TestSlapOSAccountingInteractionWorkflow(SlapOSTestCaseMixin):
def beforeTearDown(self): def beforeTearDown(self):
transaction.abort() transaction.abort()
def _test_HostingSubscription_fixConsistency(self, day):
new_id = self.generateNewId()
item = self.portal.hosting_subscription_module.newContent(
portal_type='Hosting Subscription',
title="Subscription %s" % new_id,
reference="TESTSUB-%s" % new_id,
periodicity_hour_list=None,
periodicity_minute_list=None,
periodicity_month_day=None,
)
self.assertEqual(item.getPeriodicityHour(), None)
self.assertEqual(item.getPeriodicityMinute(), None)
self.assertEqual(item.getPeriodicityMonthDay(), None)
item.fixConsistency()
self.assertEqual(item.getPeriodicityHourList(), [0])
self.assertEqual(item.getPeriodicityMinuteList(), [0])
self.assertEqual(item.getPeriodicityMonthDay(), day)
@simulate('HostingSubscription_calculateSubscriptionStartDate',
'*args, **kwargs',
"""# Script body
from DateTime import DateTime
return DateTime('%s')
""" % DateTime('2012/01/15').ISO())
def test_HostingSubscription_fixConsistency(self):
self._test_HostingSubscription_fixConsistency(15)
@simulate('HostingSubscription_calculateSubscriptionStartDate',
'*args, **kwargs',
"""# Script body
from DateTime import DateTime
return DateTime('%s')
""" % DateTime('2012/01/29').ISO())
def test_HostingSubscription_fixConsistency_today_after_28(self):
self._test_HostingSubscription_fixConsistency(28)
def test_HostingSubscription_manageAfter(self):
class DummyTestException(Exception):
pass
def verify_fixConsistency_call(self):
# Check that fixConsistency is called on instance tree
if self.getRelativeUrl().startswith('hosting_subscription_module/'):
raise DummyTestException
else:
return self.fixConsistency_call()
# Replace serialize by a dummy method
HostingSubscriptionClass = self.portal.portal_types.getPortalTypeClass(
'Hosting Subscription')
HostingSubscriptionClass.fixConsistency_call = HostingSubscriptionClass.\
fixConsistency
HostingSubscriptionClass.fixConsistency = verify_fixConsistency_call
try:
# manage_afterAdd
self.assertRaises(
DummyTestException,
self.portal.hosting_subscription_module.newContent,
portal_type='Hosting Subscription')
# manage_afterClone
self.assertRaises(
DummyTestException,
self.portal.hosting_subscription_module.\
template_hosting_subscription.Base_createCloneDocument,
batch_mode=1)
finally:
self.portal.portal_types.resetDynamicDocumentsOnceAtTransactionBoundary()
transaction.commit()
@simulate('Delivery_calculate', @simulate('Delivery_calculate',
'*args, **kwargs', '*args, **kwargs',
"""# Script body """# Script body
...@@ -158,56 +85,3 @@ portal_workflow.doActionFor(context, action='edit_action', comment='Visited by D ...@@ -158,56 +85,3 @@ portal_workflow.doActionFor(context, action='edit_action', comment='Visited by D
portal_type = "Sale Invoice Transaction" portal_type = "Sale Invoice Transaction"
self._test_calculate(new_id, newContent, portal_type=portal_type, self._test_calculate(new_id, newContent, portal_type=portal_type,
start_date='2011/01/01') start_date='2011/01/01')
def test_InstanceTree_changePromise(self):
new_id = self.generateNewId()
project = self.addProject()
subscription = self.portal.instance_tree_module.newContent(
portal_type='Instance Tree',
title="Subscription %s" % new_id,
reference="TESTSUB-%s" % new_id,
follow_up_value=project
)
subscription.validate()
self.assertEqual(subscription.getCausalityState(), 'diverged')
request_kw = dict(
software_release='http://example.org',
software_type='http://example.org',
instance_xml=self.generateSafeXml(),
sla_xml=self.generateSafeXml(),
shared=False,
)
subscription.requestStart(**request_kw)
subscription.converge()
self.assertEqual(subscription.getCausalityState(), 'solved')
subscription.requestDestroy(**request_kw)
self.assertEqual(subscription.getCausalityState(), 'diverged')
def test_InstanceTree_changePromiseInDivergedState(self):
new_id = self.generateNewId()
project = self.addProject()
subscription = self.portal.instance_tree_module.newContent(
portal_type='Instance Tree',
title="Subscription %s" % new_id,
reference="TESTSUB-%s" % new_id,
follow_up_value=project
)
subscription.validate()
request_kw = dict(
software_release='http://example.org',
software_type='http://example.org',
instance_xml=self.generateSafeXml(),
sla_xml=self.generateSafeXml(),
shared=False,
)
subscription.requestStart(**request_kw)
self.assertEqual(subscription.getCausalityState(), 'diverged')
subscription.requestDestroy(**request_kw)
self.assertEqual(subscription.getCausalityState(), 'diverged')
...@@ -37,7 +37,7 @@ class TestDefaultInvoiceTransactionRule(SlapOSTestCaseMixin): ...@@ -37,7 +37,7 @@ class TestDefaultInvoiceTransactionRule(SlapOSTestCaseMixin):
resource, _, _, _, _, aggregate = self.bootstrapAllocableInstanceTree(is_accountable=True) resource, _, _, _, _, aggregate = self.bootstrapAllocableInstanceTree(is_accountable=True)
project = aggregate.getFollowUpValue() project = aggregate.getFollowUpValue()
trade_condition = aggregate.getFollowUpValue().getSpecialiseValue() trade_condition = project.getSourceProjectRelatedValue(portal_type="Sale Trade Condition")
source = trade_condition.getSourceSectionValue() source = trade_condition.getSourceSectionValue()
destination = aggregate.getDestinationSectionValue() destination = aggregate.getDestinationSectionValue()
business_process = trade_condition.getSpecialiseValue() business_process = trade_condition.getSpecialiseValue()
...@@ -178,7 +178,7 @@ class TestDefaultInvoiceRule(SlapOSTestCaseMixin): ...@@ -178,7 +178,7 @@ class TestDefaultInvoiceRule(SlapOSTestCaseMixin):
resource, _, _, _, _, aggregate = self.bootstrapAllocableInstanceTree(is_accountable=True) resource, _, _, _, _, aggregate = self.bootstrapAllocableInstanceTree(is_accountable=True)
project = aggregate.getFollowUpValue() project = aggregate.getFollowUpValue()
trade_condition = aggregate.getFollowUpValue().getSpecialiseValue() trade_condition = project.getSourceProjectRelatedValue(portal_type="Sale Trade Condition")
source = trade_condition.getSourceSectionValue() source = trade_condition.getSourceSectionValue()
destination = aggregate.getDestinationSectionValue() destination = aggregate.getDestinationSectionValue()
business_process = trade_condition.getSpecialiseValue() business_process = trade_condition.getSpecialiseValue()
...@@ -258,7 +258,7 @@ class TestDefaultInvoicingRule(SlapOSTestCaseMixin): ...@@ -258,7 +258,7 @@ class TestDefaultInvoicingRule(SlapOSTestCaseMixin):
resource, _, _, _, _, aggregate = self.bootstrapAllocableInstanceTree(is_accountable=True) resource, _, _, _, _, aggregate = self.bootstrapAllocableInstanceTree(is_accountable=True)
project = aggregate.getFollowUpValue() project = aggregate.getFollowUpValue()
trade_condition = aggregate.getFollowUpValue().getSpecialiseValue() trade_condition = project.getSourceProjectRelatedValue(portal_type="Sale Trade Condition")
source = trade_condition.getSourceSectionValue() source = trade_condition.getSourceSectionValue()
destination = aggregate.getDestinationSectionValue() destination = aggregate.getDestinationSectionValue()
business_process = trade_condition.getSpecialiseValue() business_process = trade_condition.getSpecialiseValue()
...@@ -390,7 +390,7 @@ class TestDefaultPaymentRule(SlapOSTestCaseMixin): ...@@ -390,7 +390,7 @@ class TestDefaultPaymentRule(SlapOSTestCaseMixin):
_, _, _, _, _, aggregate = self.bootstrapAllocableInstanceTree(is_accountable=True) _, _, _, _, _, aggregate = self.bootstrapAllocableInstanceTree(is_accountable=True)
project = aggregate.getFollowUpValue() project = aggregate.getFollowUpValue()
trade_condition = aggregate.getFollowUpValue().getSpecialiseValue() trade_condition = project.getSourceProjectRelatedValue(portal_type="Sale Trade Condition")
source = trade_condition.getSourceSectionValue() source = trade_condition.getSourceSectionValue()
destination = aggregate.getDestinationSectionValue() destination = aggregate.getDestinationSectionValue()
business_process = trade_condition.getSpecialiseValue() business_process = trade_condition.getSpecialiseValue()
...@@ -457,7 +457,7 @@ class TestHostingSubscriptionSimulation(SlapOSTestCaseMixin): ...@@ -457,7 +457,7 @@ class TestHostingSubscriptionSimulation(SlapOSTestCaseMixin):
software_product, _, _, _, _, self.instance_tree = self.bootstrapAllocableInstanceTree(is_accountable=True, base_price=9) software_product, _, _, _, _, self.instance_tree = self.bootstrapAllocableInstanceTree(is_accountable=True, base_price=9)
project = software_product.getFollowUpValue() project = software_product.getFollowUpValue()
trade_condition = project.getSpecialiseValue() trade_condition = project.getSourceProjectRelatedValue(portal_type="Sale Trade Condition")
# This test expect no accounting. # This test expect no accounting.
# Disable this by not setting a source section on the trade condition # Disable this by not setting a source section on the trade condition
trade_condition.edit(source_section=None) trade_condition.edit(source_section=None)
...@@ -715,7 +715,7 @@ class TestDefaultTradeModelRule(SlapOSTestCaseMixin): ...@@ -715,7 +715,7 @@ class TestDefaultTradeModelRule(SlapOSTestCaseMixin):
resource, _, _, _, _, aggregate = self.bootstrapAllocableInstanceTree(is_accountable=True) resource, _, _, _, _, aggregate = self.bootstrapAllocableInstanceTree(is_accountable=True)
project = aggregate.getFollowUpValue() project = aggregate.getFollowUpValue()
trade_condition = aggregate.getFollowUpValue().getSpecialiseValue() trade_condition = project.getSourceProjectRelatedValue(portal_type="Sale Trade Condition")
source = trade_condition.getSourceSectionValue() source = trade_condition.getSourceSectionValue()
destination = aggregate.getDestinationSectionValue() destination = aggregate.getDestinationSectionValue()
price_currency = trade_condition.getPriceCurrencyValue() price_currency = trade_condition.getPriceCurrencyValue()
...@@ -833,7 +833,7 @@ class TestDefaultDeliveryRule(SlapOSTestCaseMixin): ...@@ -833,7 +833,7 @@ class TestDefaultDeliveryRule(SlapOSTestCaseMixin):
def test(self): def test(self):
resource, _, _, _, _, aggregate = self.bootstrapAllocableInstanceTree(is_accountable=True) resource, _, _, _, _, aggregate = self.bootstrapAllocableInstanceTree(is_accountable=True)
project = aggregate.getFollowUpValue() project = aggregate.getFollowUpValue()
trade_condition = aggregate.getFollowUpValue().getSpecialiseValue() trade_condition = project.getSourceProjectRelatedValue(portal_type="Sale Trade Condition")
source = trade_condition.getSourceSectionValue() source = trade_condition.getSourceSectionValue()
destination = aggregate.getDestinationSectionValue() destination = aggregate.getDestinationSectionValue()
price_currency = trade_condition.getPriceCurrencyValue() price_currency = trade_condition.getPriceCurrencyValue()
...@@ -924,7 +924,7 @@ class TestDefaultDeliveryRuleConsumption(SlapOSTestCaseMixin): ...@@ -924,7 +924,7 @@ class TestDefaultDeliveryRuleConsumption(SlapOSTestCaseMixin):
def test(self): def test(self):
resource, _, _, _, _, aggregate = self.bootstrapAllocableInstanceTree(is_accountable=True) resource, _, _, _, _, aggregate = self.bootstrapAllocableInstanceTree(is_accountable=True)
project = aggregate.getFollowUpValue() project = aggregate.getFollowUpValue()
trade_condition = aggregate.getFollowUpValue().getSpecialiseValue() trade_condition = project.getSourceProjectRelatedValue(portal_type="Sale Trade Condition")
source = trade_condition.getSourceSectionValue() source = trade_condition.getSourceSectionValue()
destination = aggregate.getDestinationSectionValue() destination = aggregate.getDestinationSectionValue()
price_currency = trade_condition.getPriceCurrencyValue() price_currency = trade_condition.getPriceCurrencyValue()
......
...@@ -158,7 +158,9 @@ class TestSlapOSAccounting(SlapOSTestCaseMixin): ...@@ -158,7 +158,9 @@ class TestSlapOSAccounting(SlapOSTestCaseMixin):
def test_AccountingTransactionModule_getUnpaidInvoiceList(self): def test_AccountingTransactionModule_getUnpaidInvoiceList(self):
project = self.addProject() project = self.addProject()
person = self.makePerson(project, user=1) person = self.makePerson(project, user=1)
organisation = self.portal.organisation_module.newContent(
portal_type="Organisation"
)
sale_trade_condition = self.portal.sale_trade_condition_module.newContent( sale_trade_condition = self.portal.sale_trade_condition_module.newContent(
portal_type="Sale Trade Condition", portal_type="Sale Trade Condition",
reference=self.generateNewId(), reference=self.generateNewId(),
...@@ -166,12 +168,11 @@ class TestSlapOSAccounting(SlapOSTestCaseMixin): ...@@ -166,12 +168,11 @@ class TestSlapOSAccounting(SlapOSTestCaseMixin):
) )
sale_trade_condition.validate() sale_trade_condition.validate()
template = self.portal.restrictedTraverse( current_invoice = self.portal.accounting_module.newContent(
self.portal.portal_preferences.getPreferredDefaultPrePaymentSubscriptionInvoiceTemplate()) portal_type="Sale Invoice Transaction",
current_invoice = template.Base_createCloneDocument(batch_mode=1) created_by_builder=1,# to prevent init script to create lines
current_invoice.edit(
specialise_value=sale_trade_condition, specialise_value=sale_trade_condition,
source_section_value=organisation,
destination_value=person, destination_value=person,
destination_section_value=person, destination_section_value=person,
destination_decision_value=person, destination_decision_value=person,
...@@ -179,9 +180,20 @@ class TestSlapOSAccounting(SlapOSTestCaseMixin): ...@@ -179,9 +180,20 @@ class TestSlapOSAccounting(SlapOSTestCaseMixin):
stop_date=DateTime('2019/10/20'), stop_date=DateTime('2019/10/20'),
title='Fake Invoice for Demo User Functional', title='Fake Invoice for Demo User Functional',
price_currency="currency_module/EUR", price_currency="currency_module/EUR",
reference='1') reference='1',
ledger='automated'
)
cell = current_invoice["1"]["movement_0"] cell = current_invoice.newContent(
portal_type="Invoice Line",
resource="service_module/slapos_reservation_fee_2",
use="trade/sale",
quantity_unit="unit/piece",
base_contribution_list=[
"base_amount/invoicing/discounted",
"base_amount/invoicing/taxable"
]
)
cell.edit(quantity=1) cell.edit(quantity=1)
cell.setPrice(1) cell.setPrice(1)
...@@ -217,10 +229,29 @@ class TestSlapOSAccounting(SlapOSTestCaseMixin): ...@@ -217,10 +229,29 @@ class TestSlapOSAccounting(SlapOSTestCaseMixin):
[current_invoice.getRelativeUrl()]) [current_invoice.getRelativeUrl()])
self.login() self.login()
payment_template = self.portal.restrictedTraverse(
self.portal.portal_preferences.getPreferredDefaultPrePaymentTemplate())
payment = payment_template.Base_createCloneDocument(batch_mode=1)
payment = self.portal.accounting_module.newContent(
portal_type="Payment Transaction",
created_by_builder=1,# to prevent init script to create lines
source_section_value=organisation,
destination_value=person,
start_date=DateTime('2019/10/20'),
stop_date=DateTime('2019/10/20'),
title='Fake Payment for Demo User Functional',
ressource="currency_module/EUR",
price_currency="currency_module/EUR",
ledger='automated'
)
payment.newContent(
portal_type="Accounting Transaction Line",
destination="account_module/payable",
source="account_module/receivable"
)
payment.newContent(
portal_type="Accounting Transaction Line",
destination="account_module/payment_to_encash",
source="account_module/payment_to_encash"
)
for line in payment.contentValues(): for line in payment.contentValues():
if line.getSource() == "account_module/payment_to_encash": if line.getSource() == "account_module/payment_to_encash":
line.setQuantity(-1) line.setQuantity(-1)
...@@ -235,14 +266,11 @@ class TestSlapOSAccounting(SlapOSTestCaseMixin): ...@@ -235,14 +266,11 @@ class TestSlapOSAccounting(SlapOSTestCaseMixin):
payment.stop() payment.stop()
self.tic() self.tic()
is_lettered = False
letter = None letter = None
for line in current_invoice.contentValues(): for line in current_invoice.contentValues():
if line.getSource() == "account_module/receivable": if line.getSource() == "account_module/receivable":
is_lettered = True
letter = line.getGroupingReference() letter = line.getGroupingReference()
self.assertTrue(current_invoice.SaleInvoiceTransaction_isLettered())
self.assertTrue(is_lettered)
# is it groupped? # is it groupped?
is_lettered = False is_lettered = False
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
from erp5.component.test.SlapOSTestCaseMixin import \ from erp5.component.test.SlapOSTestCaseMixin import \
SlapOSTestCaseMixinWithAbort, SlapOSTestCaseMixin, simulate SlapOSTestCaseMixinWithAbort, SlapOSTestCaseMixin, simulate
from zExceptions import Unauthorized from zExceptions import Unauthorized
from unittest import expectedFailure
class TestSlapOSComputeNode_reportComputeNodeConsumption(SlapOSTestCaseMixinWithAbort): class TestSlapOSComputeNode_reportComputeNodeConsumption(SlapOSTestCaseMixinWithAbort):
...@@ -298,8 +299,7 @@ class TestSlapOSComputerConsumptionTioXMLFile_solveInvoicingGeneration( ...@@ -298,8 +299,7 @@ class TestSlapOSComputerConsumptionTioXMLFile_solveInvoicingGeneration(
new_id = self.generateNewId() new_id = self.generateNewId()
# Prepare compute_node # Prepare compute_node
self.compute_node = self.portal.compute_node_module.template_compute_node\ self.compute_node = self.createComputeNode()
.Base_createCloneDocument(batch_mode=1)
self.compute_node.edit( self.compute_node.edit(
title="Compute Node %s" % new_id, title="Compute Node %s" % new_id,
reference="TESTCOMP-%s" % new_id, reference="TESTCOMP-%s" % new_id,
...@@ -323,6 +323,7 @@ class TestSlapOSComputerConsumptionTioXMLFile_solveInvoicingGeneration( ...@@ -323,6 +323,7 @@ class TestSlapOSComputerConsumptionTioXMLFile_solveInvoicingGeneration(
return self.compute_node return self.compute_node
@expectedFailure
def test_solveInvoicingGeneration_REQUEST_disallowed(self): def test_solveInvoicingGeneration_REQUEST_disallowed(self):
document = self.createTioXMLFile() document = self.createTioXMLFile()
self.assertRaises( self.assertRaises(
...@@ -330,6 +331,7 @@ class TestSlapOSComputerConsumptionTioXMLFile_solveInvoicingGeneration( ...@@ -330,6 +331,7 @@ class TestSlapOSComputerConsumptionTioXMLFile_solveInvoicingGeneration(
document.ComputerConsumptionTioXMLFile_solveInvoicingGeneration, document.ComputerConsumptionTioXMLFile_solveInvoicingGeneration,
REQUEST={}) REQUEST={})
@expectedFailure
@simulate('ComputerConsumptionTioXMLFile_parseXml', @simulate('ComputerConsumptionTioXMLFile_parseXml',
'*args, **kwargs', '*args, **kwargs',
'return None') 'return None')
...@@ -352,6 +354,7 @@ class TestSlapOSComputerConsumptionTioXMLFile_solveInvoicingGeneration( ...@@ -352,6 +354,7 @@ class TestSlapOSComputerConsumptionTioXMLFile_solveInvoicingGeneration(
'category': "caté", 'category': "caté",
}], }],
} }
@expectedFailure
@simulate('ComputerConsumptionTioXMLFile_parseXml', @simulate('ComputerConsumptionTioXMLFile_parseXml',
'*args, **kwargs', '*args, **kwargs',
"return %s" % tio_dict) "return %s" % tio_dict)
...@@ -409,6 +412,7 @@ class TestSlapOSComputerConsumptionTioXMLFile_solveInvoicingGeneration( ...@@ -409,6 +412,7 @@ class TestSlapOSComputerConsumptionTioXMLFile_solveInvoicingGeneration(
'category': "caté", 'category': "caté",
}], }],
} }
@expectedFailure
@simulate('ComputerConsumptionTioXMLFile_parseXml', @simulate('ComputerConsumptionTioXMLFile_parseXml',
'*args, **kwargs', '*args, **kwargs',
"return %s" % tio_dict) "return %s" % tio_dict)
...@@ -475,6 +479,7 @@ class TestSlapOSComputerConsumptionTioXMLFile_solveInvoicingGeneration( ...@@ -475,6 +479,7 @@ class TestSlapOSComputerConsumptionTioXMLFile_solveInvoicingGeneration(
'category': "caté", 'category': "caté",
}], }],
} }
@expectedFailure
@simulate('ComputerConsumptionTioXMLFile_parseXml', @simulate('ComputerConsumptionTioXMLFile_parseXml',
'*args, **kwargs', '*args, **kwargs',
"return %s" % tio_dict) "return %s" % tio_dict)
...@@ -556,6 +561,7 @@ class TestSlapOSComputerConsumptionTioXMLFile_solveInvoicingGeneration( ...@@ -556,6 +561,7 @@ class TestSlapOSComputerConsumptionTioXMLFile_solveInvoicingGeneration(
'category': "caté", 'category': "caté",
}], }],
} }
@expectedFailure
@simulate('ComputerConsumptionTioXMLFile_parseXml', @simulate('ComputerConsumptionTioXMLFile_parseXml',
'*args, **kwargs', '*args, **kwargs',
"return %s" % tio_dict) "return %s" % tio_dict)
......
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2022 Nexedi SA and Contributors. All Rights Reserved.
#
##############################################################################
from erp5.component.test.testSlapOSERP5VirtualMasterScenario import TestSlapOSVirtualMasterScenarioMixin
from DateTime import DateTime
class PinnedDateTime(object):
"""
Context manager for changing the zope date
"""
def __init__(self, testinstance, datetime):
self.datetime = datetime
self.testinstance = testinstance
def __enter__(self):
self.testinstance.pinDateTime(self.datetime)
def __exit__(self, *args, **kw):
self.testinstance.unpinDateTime()
class TestSlapOSAccountingScenario(TestSlapOSVirtualMasterScenarioMixin):
def bootstrapAccountingTest(self):
currency, _, _, sale_person = self.bootstrapVirtualMasterTest()
self.tic()
self.logout()
# lets join as slapos administrator, which will manager the project
owner_reference = 'project-%s' % self.generateNewId()
self.joinSlapOS(self.web_site, owner_reference)
self.login()
owner_person = self.portal.portal_catalog.getResultValue(
portal_type="ERP5 Login",
reference=owner_reference).getParentValue()
self.tic()
self.logout()
self.login(sale_person.getUserId())
with PinnedDateTime(self, DateTime('2020/01/01')):
project_relative_url = self.addProject(
is_accountable=True,
person=owner_person,
currency=currency
)
self.tic()
self.logout()
self.login()
project = self.portal.restrictedTraverse(project_relative_url)
preference = self.portal.portal_preferences.slapos_default_system_preference
preference.edit(
preferred_subscription_assignment_category_list=[
'function/customer',
'role/client',
'destination_project/%s' % project.getRelativeUrl()
]
)
return owner_person, currency, project
def test_rejectedSubscriptionScenario(self):
"""
User does not pay the subscription, which is cancelled after some time
"""
_, _, project = self.bootstrapAccountingTest()
self.assertEqual(project.getValidationState(), "invalidated")
subscription_request = self.portal.portal_catalog.getResultValue(
portal_type="Subscription Request",
aggregate__uid=project.getUid()
)
self.assertEqual(subscription_request.getSimulationState(), "cancelled")
# Ensure no unexpected object has been created
# 2 assignment
# 2 sale trade condition
# 1 subscription requests
self.assertRelatedObjectCount(project, 5)
self.checkERP5StateBeforeExit()
def test_notPaidOpenOrderScenario(self):
"""
User does not pay the subscription, which is cancelled after some time
"""
with PinnedDateTime(self, DateTime('2020/05/19')):
owner_person, currency, project = self.bootstrapAccountingTest()
# Ensure no unexpected object has been created
# 2 assignment
# 2 sale trade condition
# 1 subscription requests
self.assertRelatedObjectCount(project, 5)
self.assertFalse(owner_person.Entity_hasOutstandingAmount())
self.assertFalse(owner_person.Entity_hasOutstandingAmount(include_planned=False))
self.assertEqual(project.getValidationState(), "validated")
subscription_request = self.portal.portal_catalog.getResultValue(
portal_type="Subscription Request",
aggregate__uid=project.getUid()
)
self.assertEqual(subscription_request.getSimulationState(), "submitted")
with PinnedDateTime(self, DateTime('2021/04/04')):
payment_transaction = owner_person.Person_addDepositPayment(99*10, currency.getRelativeUrl(), 1)
payment_transaction.PaymentTransaction_acceptDepositPayment()
self.tic()
self.assertTrue(owner_person.Entity_hasOutstandingAmount())
amount_list = owner_person.Entity_getOutstandingAmountList()
self.assertEquals(len(amount_list), 1)
self.assertEquals(amount_list[0].total_price, 24.384)
self.assertFalse(owner_person.Entity_hasOutstandingAmount(include_planned=False))
self.assertEqual(subscription_request.getSimulationState(), "invalidated")
open_sale_order = self.portal.portal_catalog.getResultValue(
portal_type="Open Sale Order Line",
aggregate__uid=project.getUid()
).getParentValue()
self.assertEqual(open_sale_order.getValidationState(), "validated")
# invoice is the same month's day of the person creation
# So, the open order period before '2021/04/03' starts on '2021/03/19'
self.assertEqual(open_sale_order.getStartDate(), DateTime('2021/03/19'))
self.assertEqual(open_sale_order.getStartDate(),
open_sale_order.getStopDate())
first_invoice = self.portal.portal_catalog.getResultValue(
portal_type="Invoice Line",
aggregate__uid=project.getUid()
).getParentValue()
self.assertEqual(first_invoice.getUid(), amount_list[0].payment_request_uid)
self.assertEqual(first_invoice.getSimulationState(), "confirmed")
self.assertEqual(first_invoice.getStartDate(), DateTime('2021/03/19'))
self.assertEqual(first_invoice.getStopDate(), DateTime('2021/04/19'))
# Discount and first subscription
self.assertEqual(first_invoice.getTotalPrice(), 24.384)
# Ensure no unexpected object has been created
# 1 accounting transaction
# 1 open order
# 2 assignment
# 2 simulation movements
# 1 sale packing list
# 2 sale trade condition
# 1 subscription requests
self.assertRelatedObjectCount(project, 10)
with PinnedDateTime(self, DateTime('2021/07/05')):
self.portal.portal_alarms.update_open_order_simulation.activeSense()
self.tic()
self.assertTrue(owner_person.Entity_hasOutstandingAmount())
amount_list = owner_person.Entity_getOutstandingAmountList()
self.assertEquals(len(amount_list), 1)
self.assertEquals(amount_list[0].total_price, 175.584)
self.assertTrue(owner_person.Entity_hasOutstandingAmount(include_planned=False))
amount_list = owner_person.Entity_getOutstandingAmountList(include_planned=False)
self.assertEquals(len(amount_list), 1)
self.assertEquals(amount_list[0].total_price, 125.184)
self.assertEqual(first_invoice.getSimulationState(), "stopped")
# Ensure no unexpected object has been created
# 4 accounting transactions
# 1 open order
# 2 assignment
# 8 simulation movements
# 4 sale packing list
# 2 sale trade condition
# 1 subscription requests
self.assertRelatedObjectCount(project, 22)
# Try to pay previous period
with PinnedDateTime(self, DateTime('2021/07/06')):
payment_transaction = owner_person.Entity_createPaymentTransaction(
owner_person.Entity_getOutstandingAmountList(
include_planned=False,
at_date=DateTime('2021/05/06'),
section_uid=first_invoice.getSourceSectionUid(),
resource_uid=first_invoice.getPriceCurrencyUid(),
ledger_uid=first_invoice.getLedgerUid(),
group_by_node=False
)
)
payment_transaction.stop()
self.assertEquals(payment_transaction.AccountingTransaction_getTotalCredit(), 74.78399999999999)
self.tic()
self.assertTrue(owner_person.Entity_hasOutstandingAmount())
amount_list = owner_person.Entity_getOutstandingAmountList()
self.assertEquals(len(amount_list), 1)
self.assertEquals(amount_list[0].total_price, 100.8)
self.assertTrue(owner_person.Entity_hasOutstandingAmount(include_planned=False))
amount_list = owner_person.Entity_getOutstandingAmountList(include_planned=False)
self.assertEquals(len(amount_list), 1)
self.assertEquals(amount_list[0].total_price, 50.4)
self.assertTrue(first_invoice.SaleInvoiceTransaction_isLettered())
# Ensure no unexpected object has been created
self.assertRelatedObjectCount(project, 22)
payment_tag = "Entity_createPaymentTransaction_%s" % owner_person.getUid()
owner_person.REQUEST.set(payment_tag, None)
payment_transaction = owner_person.Entity_createPaymentTransaction(
owner_person.Entity_getOutstandingAmountList(
include_planned=False,
section_uid=first_invoice.getSourceSectionUid(),
resource_uid=first_invoice.getPriceCurrencyUid(),
ledger_uid=first_invoice.getLedgerUid(),
group_by_node=False
)
)
payment_transaction.stop()
self.assertEquals(payment_transaction.AccountingTransaction_getTotalCredit(), 50.4)
self.tic()
self.assertTrue(owner_person.Entity_hasOutstandingAmount())
amount_list = owner_person.Entity_getOutstandingAmountList()
self.assertEquals(len(amount_list), 1)
self.assertEquals(amount_list[0].total_price, 50.4)
self.assertFalse(owner_person.Entity_hasOutstandingAmount(include_planned=False))
amount_list = owner_person.Entity_getOutstandingAmountList(include_planned=False)
self.assertEquals(len(amount_list), 0)
# Ensure no unexpected object has been created
self.assertRelatedObjectCount(project, 22)
with PinnedDateTime(self, DateTime('2021/07/06')):
self.checkERP5StateBeforeExit()
\ No newline at end of file
...@@ -2,25 +2,19 @@ ...@@ -2,25 +2,19 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="Sale Packing List Line" module="erp5.portal_type"/> <global name="Test Component" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
<item> <item>
<key> <string>categories</string> </key> <key> <string>default_reference</string> </key>
<value> <value> <string>testSlapOSERP5AccountingScenario</string> </value>
<tuple>
<string>resource/service_module/slapos_instance_cleanup</string>
<string>quantity_unit/unit/piece</string>
<string>base_contribution/base_amount/invoicing/discounted</string>
<string>base_contribution/base_amount/invoicing/taxable</string>
<string>use/trade/sale</string>
</tuple>
</value>
</item> </item>
<item> <item>
<key> <string>default_reference</string> </key> <key> <string>default_source_reference</string> </key>
<value> <string>1</string> </value> <value>
<none/>
</value>
</item> </item>
<item> <item>
<key> <string>description</string> </key> <key> <string>description</string> </key>
...@@ -30,35 +24,39 @@ ...@@ -30,35 +24,39 @@
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>destroy</string> </value> <value> <string>test.erp5.testSlapOSERP5AccountingScenario</string> </value>
</item> </item>
<item> <item>
<key> <string>index</string> </key> <key> <string>portal_type</string> </key>
<value> <value> <string>Test Component</string> </value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item> </item>
<item> <item>
<key> <string>int_index</string> </key> <key> <string>sid</string> </key>
<value> <int>1</int> </value> <value>
<none/>
</value>
</item> </item>
<item> <item>
<key> <string>language</string> </key> <key> <string>text_content_error_message</string> </key>
<value> <value>
<none/> <tuple/>
</value> </value>
</item> </item>
<item> <item>
<key> <string>portal_type</string> </key> <key> <string>text_content_warning_message</string> </key>
<value> <string>Sale Packing List Line</string> </value> <value>
<tuple/>
</value>
</item> </item>
<item> <item>
<key> <string>price</string> </key> <key> <string>version</string> </key>
<value> <float>0.0</float> </value> <value> <string>erp5</string> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>workflow_history</string> </key>
<value> <string>Destroy Line</string> </value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
...@@ -74,7 +72,7 @@ ...@@ -74,7 +72,7 @@
<value> <value>
<dictionary> <dictionary>
<item> <item>
<key> <string>movement</string> </key> <key> <string>component_validation_workflow</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value> </value>
...@@ -87,14 +85,25 @@ ...@@ -87,14 +85,25 @@
</record> </record>
<record id="3" aka="AAAAAAAAAAM="> <record id="3" aka="AAAAAAAAAAM=">
<pickle> <pickle>
<global name="PersistentMapping" module="Persistence.mapping"/> <global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
<item> <item>
<key> <string>data</string> </key> <key> <string>_log</string> </key>
<value> <value>
<dictionary/> <list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value> </value>
</item> </item>
</dictionary> </dictionary>
......
...@@ -33,11 +33,12 @@ class TestSlapOSEntityCreatePaymentMixin(SlapOSTestCaseMixin): ...@@ -33,11 +33,12 @@ class TestSlapOSEntityCreatePaymentMixin(SlapOSTestCaseMixin):
portal_type="Bank Account" portal_type="Bank Account"
) )
currency = self.portal.currency_module.newContent( currency = self.portal.currency_module.newContent(
portal_type="Currency" portal_type="Currency",
base_unit_quantity=0.1
) )
if person is None: if person is None:
person = self.portal.person_module.template_member\ person = self.portal.person_module\
.Base_createCloneDocument(batch_mode=1) .newContent(portal_type="Person")
invoice = self.createSaleInvoiceTransaction( invoice = self.createSaleInvoiceTransaction(
source_value=organisation, source_value=organisation,
...@@ -95,31 +96,29 @@ class TestSlapOSEntityCreatePaymentMixin(SlapOSTestCaseMixin): ...@@ -95,31 +96,29 @@ class TestSlapOSEntityCreatePaymentMixin(SlapOSTestCaseMixin):
expected_set = [ expected_set = [
'causality/%s' % invoice.getRelativeUrl(), 'causality/%s' % invoice.getRelativeUrl(),
'destination_section/%s' % invoice.getDestinationSection(), 'destination_section/%s' % invoice.getDestinationSection(),
'destination_project/%s' % invoice.getDestinationProject(), 'resource/%s' % invoice.getPriceCurrency(),
'price_currency/%s' % invoice.getPriceCurrency(),
'resource/%s' % invoice.getResource(),
'source_payment/%s' % invoice.getSourcePayment(), 'source_payment/%s' % invoice.getSourcePayment(),
'payment_mode/%s' % self.payment_mode, 'payment_mode/%s' % self.payment_mode,
'source_section/%s' % invoice.getSourceSection(), 'source_section/%s' % invoice.getSourceSection(),
#'source_project/%s' % invoice.getSourceProject(),
'ledger/%s' % invoice.getLedger(), 'ledger/%s' % invoice.getLedger(),
] ]
self.assertSameSet(expected_set, payment.getCategoryList()) self.assertSameSet(expected_set, payment.getCategoryList())
self.assertEqual(invoice.getStartDate(), payment.getStartDate()) self.assertEqual(invoice.getStartDate(), payment.getStartDate())
self.assertEqual(invoice.getStopDate(), payment.getStopDate()) self.assertEqual(invoice.getStartDate(), payment.getStopDate())
invoice_movement_list = invoice.getMovementList()
movement_list = payment.getMovementList() movement_list = payment.getMovementList()
self.assertEqual(2, len(movement_list))
bank_list = [q for q in movement_list bank_list = [q for q in movement_list
if q.getSource() == 'account_module/payment_to_encash'] if q.getSource() == 'account_module/payment_to_encash']
rec_list = [q for q in movement_list rec_list = [q for q in movement_list
if q.getSource() == 'account_module/receivable'] if q.getSource() == 'account_module/receivable']
self.assertEqual(1, len(bank_list)) self.assertEqual(1, len(bank_list))
self.assertEqual(1, len(rec_list)) self.assertEqual(len([q for q in invoice_movement_list
if q.getSource() == 'account_module/receivable']), len(rec_list))
def assertLine(line, quantity, category_list): def assertLine(line, quantity, category_list):
self.assertTrue(line.hasStartDate()) self.assertFalse(line.hasStartDate())
self.assertTrue(line.hasStopDate()) self.assertFalse(line.hasStopDate())
self.assertEqual(quantity, line.getQuantity()) self.assertEqual(quantity, line.getQuantity())
self.assertSameSet(category_list, line.getCategoryList()) self.assertSameSet(category_list, line.getCategoryList())
...@@ -127,18 +126,25 @@ class TestSlapOSEntityCreatePaymentMixin(SlapOSTestCaseMixin): ...@@ -127,18 +126,25 @@ class TestSlapOSEntityCreatePaymentMixin(SlapOSTestCaseMixin):
assertLine(bank_list[0], invoice_amount, [ assertLine(bank_list[0], invoice_amount, [
'destination/account_module/payment_to_encash', 'destination/account_module/payment_to_encash',
'source/account_module/payment_to_encash']) 'source/account_module/payment_to_encash'])
assertLine(rec_list[0], -1 * invoice_amount, [ for rec in rec_list:
assertLine(rec, -invoice_amount / len(rec_list), [
'destination/account_module/payable', 'destination/account_module/payable',
'source/account_module/receivable']) 'source/account_module/receivable'])
def fullBuild(self, person, invoice_list): def fullBuild(self, person, invoice_list):
payment = person.Entity_createPaymentTransaction(invoice_list) payment = person.Entity_createPaymentTransaction(person.Entity_getOutstandingAmountList(
include_planned=False,
section_uid=invoice_list[0].getSourceSectionUid(),
resource_uid=invoice_list[0].getPriceCurrencyUid(),
ledger_uid=invoice_list[0].getLedgerUid(),
group_by_node=False
), payment_mode=self.payment_mode, start_date=invoice_list[0].getStartDate())
self.assertNotEqual(None, payment) self.assertNotEqual(None, payment)
return payment return payment
def resetPaymentTag(self, invoice): def resetPaymentTag(self, person):
payment_tag = "sale_invoice_transaction_create_payment_%s" % invoice.getUid() payment_tag = "Entity_createPaymentTransaction_%s" % person.getUid()
invoice.REQUEST.set(payment_tag, None) person.REQUEST.set(payment_tag, None)
def _test(self): def _test(self):
person, invoice = self.makeSaleInvoiceTransaction() person, invoice = self.makeSaleInvoiceTransaction()
...@@ -157,7 +163,7 @@ class TestSlapOSEntityCreatePaymentMixin(SlapOSTestCaseMixin): ...@@ -157,7 +163,7 @@ class TestSlapOSEntityCreatePaymentMixin(SlapOSTestCaseMixin):
payment = self.fullBuild(person, [invoice]) payment = self.fullBuild(person, [invoice])
self.assertPayment(payment, invoice) self.assertPayment(payment, invoice)
self.tic() self.tic()
self.resetPaymentTag(invoice) self.resetPaymentTag(person)
# Create twice, generate 2 payments # Create twice, generate 2 payments
payment = self.fullBuild(person, [invoice]) payment = self.fullBuild(person, [invoice])
...@@ -181,7 +187,7 @@ class TestSlapOSEntityCreatePaymentMixin(SlapOSTestCaseMixin): ...@@ -181,7 +187,7 @@ class TestSlapOSEntityCreatePaymentMixin(SlapOSTestCaseMixin):
payment = self.fullBuild(person, [invoice]) payment = self.fullBuild(person, [invoice])
self.commit() self.commit()
# Request was over, so emulate start a new one # Request was over, so emulate start a new one
self.resetPaymentTag(invoice) self.resetPaymentTag(person)
# Should we take into account that a payment is ongoing? # Should we take into account that a payment is ongoing?
payment2 = self.fullBuild(person, [invoice]) payment2 = self.fullBuild(person, [invoice])
...@@ -198,7 +204,7 @@ class TestSlapOSEntityCreatePaymentMixin(SlapOSTestCaseMixin): ...@@ -198,7 +204,7 @@ class TestSlapOSEntityCreatePaymentMixin(SlapOSTestCaseMixin):
payment = self.fullBuild(person, [invoice]) payment = self.fullBuild(person, [invoice])
payment.cancel() payment.cancel()
self.tic() self.tic()
self.resetPaymentTag(invoice) self.resetPaymentTag(person)
payment = self.fullBuild(person, [invoice]) payment = self.fullBuild(person, [invoice])
self.tic() self.tic()
...@@ -212,8 +218,9 @@ class TestSlapOSEntityCreatePaymentMixin(SlapOSTestCaseMixin): ...@@ -212,8 +218,9 @@ class TestSlapOSEntityCreatePaymentMixin(SlapOSTestCaseMixin):
invoice_2.confirm() invoice_2.confirm()
invoice_2.stop() invoice_2.stop()
self.tic() self.tic()
payment_list = [self.fullBuild(person, [invoice_1]), payment_list = [self.fullBuild(person, [invoice_1])]
self.fullBuild(person, [invoice_2])] self.resetPaymentTag(person)
payment_list.append(self.fullBuild(person, [invoice_2]))
self.tic() self.tic()
self.assertEqual(2, len(payment_list)) self.assertEqual(2, len(payment_list))
......
...@@ -8,6 +8,7 @@ Consumption Document Module | view ...@@ -8,6 +8,7 @@ Consumption Document Module | view
Hosting Subscription | periodicity Hosting Subscription | periodicity
Instance Tree | jump_to_related_open_order_line Instance Tree | jump_to_related_open_order_line
Payment Transaction | related_payzen_event Payment Transaction | related_payzen_event
Person | create_slapos_payment_transaction
Root Applied Rule Causality Causality Movement Group | view Root Applied Rule Causality Causality Movement Group | view
Sale Invoice Transaction | create_slapos_reversal Sale Invoice Transaction | create_slapos_reversal
Sale Packing List | jump_related_aggregated_packing_list Sale Packing List | jump_related_aggregated_packing_list
......
...@@ -8,9 +8,7 @@ business_process_module/slapos_subscription_business_process ...@@ -8,9 +8,7 @@ business_process_module/slapos_subscription_business_process
business_process_module/slapos_subscription_business_process/** business_process_module/slapos_subscription_business_process/**
business_process_module/slapos_ultimate_business_process business_process_module/slapos_ultimate_business_process
organisation_module/slapos organisation_module/slapos
sale_packing_list_module/slapos_accounting_instance_delivery_line_template organisation_module/slapos/bank_account
sale_packing_list_module/slapos_accounting_instance_delivery_line_template/**
sale_packing_list_module/slapos_accounting_instance_delivery_template
sale_trade_condition_module/default_subscription_trade_condition sale_trade_condition_module/default_subscription_trade_condition
sale_trade_condition_module/default_subscription_trade_condition/** sale_trade_condition_module/default_subscription_trade_condition/**
sale_trade_condition_module/slapos_aggregated_consumption_trade_condition sale_trade_condition_module/slapos_aggregated_consumption_trade_condition
......
...@@ -12,7 +12,6 @@ account_module/receivable ...@@ -12,7 +12,6 @@ account_module/receivable
account_module/refundable_vat account_module/refundable_vat
account_module/sales account_module/sales
business_process_module/slapos_ultimate_business_process business_process_module/slapos_ultimate_business_process
organisation_module/slapos/bank_account
portal_rules/slapos_delivery_root_simulation_rule portal_rules/slapos_delivery_root_simulation_rule
portal_rules/slapos_invoice_root_simulation_rule portal_rules/slapos_invoice_root_simulation_rule
portal_rules/slapos_invoice_simulation_rule portal_rules/slapos_invoice_simulation_rule
......
...@@ -54,9 +54,6 @@ portal_solvers/Automatic Quantity Adopt Solver ...@@ -54,9 +54,6 @@ portal_solvers/Automatic Quantity Adopt Solver
portal_solvers/Automatic Quantity Adopt Solver/** portal_solvers/Automatic Quantity Adopt Solver/**
quantity_unit_conversion_module/slapos_time_month quantity_unit_conversion_module/slapos_time_month
quantity_unit_conversion_module/slapos_time_month/** quantity_unit_conversion_module/slapos_time_month/**
sale_packing_list_module/slapos_accounting_instance_delivery_line_template
sale_packing_list_module/slapos_accounting_instance_delivery_line_template/**
sale_packing_list_module/slapos_accounting_instance_delivery_template
service_module/cpu_load_percent service_module/cpu_load_percent
service_module/disk_used service_module/disk_used
service_module/memory_used service_module/memory_used
......
...@@ -6,7 +6,6 @@ SlapOSAccountingSaleInvoiceTransactionConstraint ...@@ -6,7 +6,6 @@ SlapOSAccountingSaleInvoiceTransactionConstraint
SlapOSAccountingSalePackingListConstraint SlapOSAccountingSalePackingListConstraint
SlapOSAccountingSalePackingListLineConstraint SlapOSAccountingSalePackingListLineConstraint
SlapOSAccountingSaleTradeConditionConstraint SlapOSAccountingSaleTradeConditionConstraint
SlapOSAccountingSystemPreference
SlapOSCloudContractAccounting SlapOSCloudContractAccounting
SlapOSCloudContractLineAccounting SlapOSCloudContractLineAccounting
SlapOSLedgerConstraint SlapOSLedgerConstraint
......
...@@ -5,5 +5,6 @@ test.erp5.testSlapOSAccountingInteractionWorkflow ...@@ -5,5 +5,6 @@ test.erp5.testSlapOSAccountingInteractionWorkflow
test.erp5.testSlapOSAccountingRule test.erp5.testSlapOSAccountingRule
test.erp5.testSlapOSAccountingSkins test.erp5.testSlapOSAccountingSkins
test.erp5.testSlapOSConsumptionSkins test.erp5.testSlapOSConsumptionSkins
test.erp5.testSlapOSERP5AccountingScenario
test.erp5.testSlapOSEntityCreatePayment test.erp5.testSlapOSEntityCreatePayment
test.erp5.testSlapOSSaleSupply test.erp5.testSlapOSSaleSupply
\ No newline at end of file
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