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 @@
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Sale Packing List Line" module="erp5.portal_type"/>
<global name="ActionInformation" module="Products.CMFCore.ActionInformation"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>resource/service_module/slapos_instance_setup</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>
<string>action_type/object_jio_action</string>
</tuple>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>1</string> </value>
<key> <string>category</string> </key>
<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>
<key> <string>description</string> </key>
......@@ -28,68 +36,59 @@
<none/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>setup</string> </value>
<value> <string>create_slapos_payment_transaction</string> </value>
</item>
<item>
<key> <string>index</string> </key>
<key> <string>permissions</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
<tuple>
<string>View</string>
</tuple>
</value>
</item>
<item>
<key> <string>int_index</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Sale Packing List Line</string> </value>
<key> <string>priority</string> </key>
<value> <float>60.0</float> </value>
</item>
<item>
<key> <string>price</string> </key>
<value> <float>0.0</float> </value>
<key> <string>title</string> </key>
<value> <string>Create Payment Transaction</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Setup Line</string> </value>
<key> <string>visible</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
<global name="Expression" module="Products.CMFCore.Expression"/>
</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>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/Entity_viewCreatePaymentTransactionDialog</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
<key> <string>text</string> </key>
<value> <string>python: portal.Base_checkPermission(\'accounting_module\', \'Add portal content\') and (context.getValidationState() == \'validated\')</string> </value>
</item>
</dictionary>
</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.portal_catalog.searchAndActivate(
......
......@@ -10,7 +10,7 @@ if (context.getSimulationState() == 'confirmed')\
and (context.getLedger() == 'automated')\
and (context.getCausalityState() == 'solved')\
and (0 < len(context.objectValues(portal_type="Sale Invoice Transaction Line"))\
and (context.getStopDate(now) < now)):
and (context.getStopDate(now) <= now)):
if context.getSourcePayment("") == "":
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
if REQUEST is not None:
raise Unauthorized
......@@ -7,72 +6,93 @@ portal = context.getPortalObject()
if not invoice_list:
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
# a single payment per invoice.
current_invoice = invoice_list[0]
payment_tag = "sale_invoice_transaction_create_payment_%s" % current_invoice.getUid()
payment_tag = 'Entity_createPaymentTransaction_%s' % context.getUid()
if context.REQUEST.get(payment_tag, None) is not None:
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')
context.serialize()
quantity = 0
for movement in current_invoice.searchFolder(
portal_type='Sale Invoice Transaction Line',
default_source_uid=[i.uid for i in context.Base_getReceivableAccountList()]):
quantity += movement.getQuantity()
if not price:
raise ValueError('No total_price to pay')
if first_invoice.getDestinationSection() != context.getRelativeUrl():
raise ValueError('Invoice not related to the context')
if quantity >= 0:
raise ValueError('You cannot generate Payment Transaction for zero or negative amounts.')
if start_date is None:
start_date = DateTime()
current_payment = portal.accounting_module.newContent(
portal_type="Payment Transaction",
causality=current_invoice.getRelativeUrl(),
source_section=current_invoice.getSourceSection(),
source_project=current_invoice.getSourceProject(),
destination_section=current_invoice.getDestinationSection(),
destination_project=current_invoice.getDestinationProject(),
resource=current_invoice.getResource(),
price_currency=current_invoice.getResource(),
specialise=current_invoice.getSpecialise(),
payment_mode=current_invoice.getPaymentMode(),
ledger=current_invoice.getLedger(),
start_date=current_invoice.getStartDate(),
stop_date=current_invoice.getStopDate(),
source_payment=current_invoice.getSourcePayment(),
# Workarround to not create default lines.
created_by_builder=1
# create the payment transaction
payment_transaction = portal.accounting_module.newContent(
portal_type='Payment Transaction',
created_by_builder=True,
causality_uid_set=causality_uid_list,
source_section=first_invoice.getSourceSection(),
source_payment=first_invoice.getSourcePayment(),
destination_section=first_invoice.getDestinationSection(),
destination_section_value=context,
start_date=start_date,
payment_mode=payment_mode,
#specialise
ledger=first_invoice.getLedger(),
resource=first_invoice.getResource(),
destination_administration=destination_administration,
activate_kw=activate_kw
)
current_payment.newContent(
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())
getAccountForUse = context.Base_getAccountForUse
current_payment.newContent(
portal_type="Accounting Transaction Line",
quantity=1 * quantity,
source='account_module/payment_to_encash',
destination='account_module/payment_to_encash',
start_date=current_invoice.getStartDate(),
stop_date=current_invoice.getStopDate())
collection_account = getAccountForUse('collection')
payment_transaction.newContent(
id='bank',
portal_type='Accounting Transaction Line',
source_value=collection_account,
destination_value=collection_account,
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
# reindexed.
payment_tag ="sale_invoice_transaction_create_payment_%s" % current_invoice.getUid()
current_payment.activate(tag=payment_tag).immediateReindexObject()
assert len(payment_transaction.checkConsistency()) == 0
comment = translateString("Initialised by Entity_createPaymentTransaction.")
current_payment.PaymentTransaction_start(comment=comment)
payment_transaction.start()
# Set a flag on the request for prevent 2 calls on the same transaction
context.REQUEST.set(payment_tag, 1)
return current_payment
return payment_transaction
......@@ -50,7 +50,7 @@
</item>
<item>
<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>
<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 @@
</item>
<item>
<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>
<key> <string>id</string> </key>
<value> <string>ERP5Site_searchRelatedInheritedSpecialiseList</string> </value>
<value> <string>Entity_createPaymentTransactionAction</string> </value>
</item>
</dictionary>
</pickle>
......
"""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
- getTotalPrice: the original amount of this invoice.
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)
- 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()
params = dict()
if at_date:
params['at_date'] = at_date
params['grouping_reference'] = None
params['grouping_query'] = ComplexQuery(
SimpleQuery(grouping_reference=None),
SimpleQuery(grouping_date=at_date, comparison_operator=">"),
logical_operator="OR")
else:
params['grouping_reference'] = None
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(
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,
**params )):
......@@ -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
# of this hack
# XXX In our case, this hould be always None.
payment_request_uid = brain.payment_request_uid
if not payment_request_uid:
payment_request_uid = brain.getObject().getExplanationUid()
payment_request = portal.portal_catalog.getObject(uid=payment_request_uid)
object_list.append(payment_request.asContext(
section_uid=brain.section_uid,
resource_uid=brain.resource_uid,
ledger_uid=brain.ledger_uid,
payment_request_uid=payment_request_uid,
node_uid=brain.node_uid,
node_relative_url=brain.node_relative_url,
......
......@@ -50,7 +50,7 @@
</item>
<item>
<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>
<key> <string>id</string> </key>
......
......@@ -50,11 +50,11 @@
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>at_date=None, resource_uid=None, **kw</string> </value>
<value> <string>*args, **kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Entity_statOutstandingAmount</string> </value>
<value> <string>Entity_hasOutstandingAmount</string> </value>
</item>
</dictionary>
</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
destination_section_value=payment_transaction.getDestinationSectionValue(),
destination_decision_value=payment_transaction.getDestinationDecisionValue(),
destination_project_value=payment_transaction.getDestinationProjectValue(),
ledger_value=portal.portal_categories.ledger.automated,
ledger_value=payment_transaction.getLedgerValue(),
causality_value=payment_transaction,
price_currency_value=payment_transaction.getResourceValue(),
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(
stop_date=now,
specialise_value=tmp_sale_order.getSpecialiseValue(),
source_value=tmp_sale_order.getSourceValue(),
source_section_value=tmp_sale_order.getSourceSectionValue(),
source_decision_value=tmp_sale_order.getSourceDecisionValue(),
source_project_value=tmp_sale_order.getSourceProjectValue(),
destination_value=tmp_sale_order.getDestinationValue(),
destination_section_value=tmp_sale_order.getDestinationSectionValue(),
destination_decision_value=tmp_sale_order.getDestinationDecisionValue(),
destination_project_value=tmp_sale_order.getDestinationProjectValue(),
source=tmp_sale_order.getSource(),
source_section=tmp_sale_order.getSourceSection(),
source_decision=tmp_sale_order.getSourceDecision(),
source_project=tmp_sale_order.getSourceProject(),
destination=tmp_sale_order.getDestination(),
destination_section=tmp_sale_order.getDestinationSection(),
destination_decision=tmp_sale_order.getDestinationDecision(),
destination_project=tmp_sale_order.getDestinationProject(),
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.
activate_kw={'tag':'%s_init' % context.getRelativeUrl()}
)
......@@ -87,6 +87,6 @@ if len(payment_transaction.checkConsistency()) != 0:
#tag = '%s_update' % context.getDestinationReference()
comment = translateString("Deposit payment.")
payment_transaction.PaymentTransaction_start(comment=comment)
payment_transaction.start(comment=comment)
return payment_transaction
......@@ -95,6 +95,8 @@ while count > 0 and len(trade_condition_list) == 0:
filter_kw['source_project__uid'] = order.getSourceProjectUid()
if order.hasPriceCurrency():
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(
predicate_context,
......
if True:
return "disabled as not matching yet the virtual master design"
from zExceptions import Unauthorized
if REQUEST is not None:
raise Unauthorized
......@@ -20,7 +23,7 @@ if tioxml_dict is None:
else:
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']
compute_node_project = None
......
......@@ -19,6 +19,10 @@ if invoice.getResource() != price_currency:
causality_list = invoice.getCausalityList()
for simulation_movement in related_simulation_movement_path_list:
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()
if applied_rule.getParentId() != 'portal_simulation':
causality = applied_rule.getParentValue().getExplanationValue()
......
......@@ -30,13 +30,13 @@ import transaction
from functools import wraps
from Products.ERP5Type.tests.utils import createZODBPythonScript
from erp5.component.test.SlapOSTestCaseMixin import SlapOSTestCaseMixin, withAbort, TemporaryAlarmScript
from unittest import expectedFailure
import os
import tempfile
from DateTime import DateTime
AGGREGATE_SALE_TRADE_CONDITION_RELATIVE_URL = 'sale_trade_condition_module/slapos_aggregated_trade_condition_v3'
class Simulator:
def __init__(self, outfile, method, to_return=None):
......@@ -521,6 +521,7 @@ class TestSlapOSGeneratePackingListFromTioXML(SlapOSTestCaseMixin):
)
return document
@expectedFailure
def test_ComputerConsumptionTioXMLFile_solveInvoicingGeneration_alarm(self):
document = self.createTioXMLFile()
document.submit()
......
......@@ -1998,8 +1998,8 @@ class TestSlapOSAggregatedDeliveryBuilder(SlapOSTestCaseMixin):
return delivery_line
def test(self):
person = self.portal.person_module.template_member\
.Base_createCloneDocument(batch_mode=1)
person = self.portal.person_module\
.newContent(portal_type="Person")
delivery = self._createDelivery(destination_value=person,
destination_decision_value=person)
delivery_line = self._addDeliveryLine(delivery)
......@@ -2037,8 +2037,8 @@ class TestSlapOSAggregatedDeliveryBuilder(SlapOSTestCaseMixin):
built_delivery_line.getResource())
def test_many_lines(self):
person = self.portal.person_module.template_member\
.Base_createCloneDocument(batch_mode=1)
person = self.portal.person_module\
.newContent(portal_type="Person")
delivery = self._createDelivery(destination_value=person,
destination_decision_value=person)
setup_line_1 = self._addDeliveryLine(delivery)
......@@ -2100,8 +2100,8 @@ class TestSlapOSAggregatedDeliveryBuilder(SlapOSTestCaseMixin):
built_subscription_line.getResource())
def test_added_after(self):
person = self.portal.person_module.template_member\
.Base_createCloneDocument(batch_mode=1)
person = self.portal.person_module\
.newContent(portal_type="Person")
delivery = self._createDelivery(destination_value=person,
destination_decision_value=person)
delivery_line = self._addDeliveryLine(delivery)
......
......@@ -11,7 +11,6 @@ from unittest import skip
import transaction
AGGREGATE_SALE_TRADE_CONDITION_RELATIVE_URL = 'sale_trade_condition_module/slapos_aggregated_trade_condition_v3'
class TestHostingSubscription(TestSlapOSConstraintMixin):
......@@ -152,16 +151,14 @@ class TestSaleInvoiceTransaction(TestSlapOSConstraintMixin):
def test_specialise_value(self):
invoice = self.portal.accounting_module.newContent(
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))
sale_condition = self.portal.sale_trade_condition_module.newContent(
portal_type='Sale Trade Condition')
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))
@withAbort
......@@ -183,12 +180,38 @@ class TestSaleInvoiceTransaction(TestSlapOSConstraintMixin):
@withAbort
def test_trade_model_match_lines(self):
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(
portal_type='Sale Invoice Transaction',
price_currency='currency_module/EUR',
specialise=AGGREGATE_SALE_TRADE_CONDITION_RELATIVE_URL)
price_currency_value=currency,
specialise_value=sale_trade_condition)
invoice.newContent(portal_type='Invoice Line', quantity=1., price=1.,
base_contribution='base_amount/invoicing/taxable')
self.tic()
self.assertFalse(message in self.getMessageList(invoice))
self.portal.portal_workflow._jumpToStateFor(invoice, 'confirmed')
......@@ -202,20 +225,47 @@ class TestSaleInvoiceTransaction(TestSlapOSConstraintMixin):
@withAbort
def test_use_trade_sale_total_price_matches_delivery_constraint(self):
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(
portal_type='Sale Packing List')
delivery.newContent(portal_type='Sale Packing List Line',
use='trade/sale', quantity=1., price=1.)
invoice = self.portal.accounting_module.newContent(
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.,
price=1., use='trade/sale')
self.assertFalse(message in self.getMessageList(invoice))
self.portal.portal_workflow._jumpToStateFor(invoice, 'confirmed')
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))
invoice_line.setQuantity(1.)
self.assertFalse(message in self.getMessageList(invoice))
......@@ -304,9 +354,6 @@ class TestSalePackingList(TestSlapOSConstraintMixin):
def test_source(self):
self._test_category_arrow('source')
def test_source_section(self):
self._test_category_arrow('source_section')
@withAbort
def test_specialise(self):
category = 'specialise'
......@@ -345,28 +392,20 @@ class TestSalePackingList(TestSlapOSConstraintMixin):
class TestSalePackingListLine(TestSlapOSConstraintMixin):
@withAbort
def test_property_existence(self):
message = 'Property existence error for property %s, this document has '\
'no such property or the property has never been set'
message_price = message % 'price'
message_quantity = message % 'quantity'
message_quantity = 'No quantity defined'
delivery_line = self.portal.sale_packing_list_module.newContent(
portal_type='Sale Packing List').newContent(
portal_type='Sale Packing List Line')
self.assertTrue(message_price in self.getMessageList(delivery_line))
self.assertTrue(message_quantity in self.getMessageList(delivery_line))
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))
@withAbort
def test_resource_arity(self):
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
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
delivery_line = self.portal.sale_packing_list_module.newContent(
portal_type='Sale Packing List').newContent(
......
......@@ -2,85 +2,12 @@
from erp5.component.test.SlapOSTestCaseMixin import SlapOSTestCaseMixin, simulate
import transaction
from DateTime import DateTime
class TestSlapOSAccountingInteractionWorkflow(SlapOSTestCaseMixin):
def beforeTearDown(self):
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',
'*args, **kwargs',
"""# Script body
......@@ -158,56 +85,3 @@ portal_workflow.doActionFor(context, action='edit_action', comment='Visited by D
portal_type = "Sale Invoice Transaction"
self._test_calculate(new_id, newContent, portal_type=portal_type,
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):
resource, _, _, _, _, aggregate = self.bootstrapAllocableInstanceTree(is_accountable=True)
project = aggregate.getFollowUpValue()
trade_condition = aggregate.getFollowUpValue().getSpecialiseValue()
trade_condition = project.getSourceProjectRelatedValue(portal_type="Sale Trade Condition")
source = trade_condition.getSourceSectionValue()
destination = aggregate.getDestinationSectionValue()
business_process = trade_condition.getSpecialiseValue()
......@@ -178,7 +178,7 @@ class TestDefaultInvoiceRule(SlapOSTestCaseMixin):
resource, _, _, _, _, aggregate = self.bootstrapAllocableInstanceTree(is_accountable=True)
project = aggregate.getFollowUpValue()
trade_condition = aggregate.getFollowUpValue().getSpecialiseValue()
trade_condition = project.getSourceProjectRelatedValue(portal_type="Sale Trade Condition")
source = trade_condition.getSourceSectionValue()
destination = aggregate.getDestinationSectionValue()
business_process = trade_condition.getSpecialiseValue()
......@@ -258,7 +258,7 @@ class TestDefaultInvoicingRule(SlapOSTestCaseMixin):
resource, _, _, _, _, aggregate = self.bootstrapAllocableInstanceTree(is_accountable=True)
project = aggregate.getFollowUpValue()
trade_condition = aggregate.getFollowUpValue().getSpecialiseValue()
trade_condition = project.getSourceProjectRelatedValue(portal_type="Sale Trade Condition")
source = trade_condition.getSourceSectionValue()
destination = aggregate.getDestinationSectionValue()
business_process = trade_condition.getSpecialiseValue()
......@@ -390,7 +390,7 @@ class TestDefaultPaymentRule(SlapOSTestCaseMixin):
_, _, _, _, _, aggregate = self.bootstrapAllocableInstanceTree(is_accountable=True)
project = aggregate.getFollowUpValue()
trade_condition = aggregate.getFollowUpValue().getSpecialiseValue()
trade_condition = project.getSourceProjectRelatedValue(portal_type="Sale Trade Condition")
source = trade_condition.getSourceSectionValue()
destination = aggregate.getDestinationSectionValue()
business_process = trade_condition.getSpecialiseValue()
......@@ -457,7 +457,7 @@ class TestHostingSubscriptionSimulation(SlapOSTestCaseMixin):
software_product, _, _, _, _, self.instance_tree = self.bootstrapAllocableInstanceTree(is_accountable=True, base_price=9)
project = software_product.getFollowUpValue()
trade_condition = project.getSpecialiseValue()
trade_condition = project.getSourceProjectRelatedValue(portal_type="Sale Trade Condition")
# This test expect no accounting.
# Disable this by not setting a source section on the trade condition
trade_condition.edit(source_section=None)
......@@ -715,7 +715,7 @@ class TestDefaultTradeModelRule(SlapOSTestCaseMixin):
resource, _, _, _, _, aggregate = self.bootstrapAllocableInstanceTree(is_accountable=True)
project = aggregate.getFollowUpValue()
trade_condition = aggregate.getFollowUpValue().getSpecialiseValue()
trade_condition = project.getSourceProjectRelatedValue(portal_type="Sale Trade Condition")
source = trade_condition.getSourceSectionValue()
destination = aggregate.getDestinationSectionValue()
price_currency = trade_condition.getPriceCurrencyValue()
......@@ -833,7 +833,7 @@ class TestDefaultDeliveryRule(SlapOSTestCaseMixin):
def test(self):
resource, _, _, _, _, aggregate = self.bootstrapAllocableInstanceTree(is_accountable=True)
project = aggregate.getFollowUpValue()
trade_condition = aggregate.getFollowUpValue().getSpecialiseValue()
trade_condition = project.getSourceProjectRelatedValue(portal_type="Sale Trade Condition")
source = trade_condition.getSourceSectionValue()
destination = aggregate.getDestinationSectionValue()
price_currency = trade_condition.getPriceCurrencyValue()
......@@ -924,7 +924,7 @@ class TestDefaultDeliveryRuleConsumption(SlapOSTestCaseMixin):
def test(self):
resource, _, _, _, _, aggregate = self.bootstrapAllocableInstanceTree(is_accountable=True)
project = aggregate.getFollowUpValue()
trade_condition = aggregate.getFollowUpValue().getSpecialiseValue()
trade_condition = project.getSourceProjectRelatedValue(portal_type="Sale Trade Condition")
source = trade_condition.getSourceSectionValue()
destination = aggregate.getDestinationSectionValue()
price_currency = trade_condition.getPriceCurrencyValue()
......
......@@ -158,7 +158,9 @@ class TestSlapOSAccounting(SlapOSTestCaseMixin):
def test_AccountingTransactionModule_getUnpaidInvoiceList(self):
project = self.addProject()
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(
portal_type="Sale Trade Condition",
reference=self.generateNewId(),
......@@ -166,12 +168,11 @@ class TestSlapOSAccounting(SlapOSTestCaseMixin):
)
sale_trade_condition.validate()
template = self.portal.restrictedTraverse(
self.portal.portal_preferences.getPreferredDefaultPrePaymentSubscriptionInvoiceTemplate())
current_invoice = template.Base_createCloneDocument(batch_mode=1)
current_invoice.edit(
current_invoice = self.portal.accounting_module.newContent(
portal_type="Sale Invoice Transaction",
created_by_builder=1,# to prevent init script to create lines
specialise_value=sale_trade_condition,
source_section_value=organisation,
destination_value=person,
destination_section_value=person,
destination_decision_value=person,
......@@ -179,9 +180,20 @@ class TestSlapOSAccounting(SlapOSTestCaseMixin):
stop_date=DateTime('2019/10/20'),
title='Fake Invoice for Demo User Functional',
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.setPrice(1)
......@@ -217,10 +229,29 @@ class TestSlapOSAccounting(SlapOSTestCaseMixin):
[current_invoice.getRelativeUrl()])
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():
if line.getSource() == "account_module/payment_to_encash":
line.setQuantity(-1)
......@@ -235,14 +266,11 @@ class TestSlapOSAccounting(SlapOSTestCaseMixin):
payment.stop()
self.tic()
is_lettered = False
letter = None
for line in current_invoice.contentValues():
if line.getSource() == "account_module/receivable":
is_lettered = True
letter = line.getGroupingReference()
self.assertTrue(is_lettered)
self.assertTrue(current_invoice.SaleInvoiceTransaction_isLettered())
# is it groupped?
is_lettered = False
......
......@@ -8,6 +8,7 @@
from erp5.component.test.SlapOSTestCaseMixin import \
SlapOSTestCaseMixinWithAbort, SlapOSTestCaseMixin, simulate
from zExceptions import Unauthorized
from unittest import expectedFailure
class TestSlapOSComputeNode_reportComputeNodeConsumption(SlapOSTestCaseMixinWithAbort):
......@@ -298,8 +299,7 @@ class TestSlapOSComputerConsumptionTioXMLFile_solveInvoicingGeneration(
new_id = self.generateNewId()
# Prepare compute_node
self.compute_node = self.portal.compute_node_module.template_compute_node\
.Base_createCloneDocument(batch_mode=1)
self.compute_node = self.createComputeNode()
self.compute_node.edit(
title="Compute Node %s" % new_id,
reference="TESTCOMP-%s" % new_id,
......@@ -323,6 +323,7 @@ class TestSlapOSComputerConsumptionTioXMLFile_solveInvoicingGeneration(
return self.compute_node
@expectedFailure
def test_solveInvoicingGeneration_REQUEST_disallowed(self):
document = self.createTioXMLFile()
self.assertRaises(
......@@ -330,6 +331,7 @@ class TestSlapOSComputerConsumptionTioXMLFile_solveInvoicingGeneration(
document.ComputerConsumptionTioXMLFile_solveInvoicingGeneration,
REQUEST={})
@expectedFailure
@simulate('ComputerConsumptionTioXMLFile_parseXml',
'*args, **kwargs',
'return None')
......@@ -352,6 +354,7 @@ class TestSlapOSComputerConsumptionTioXMLFile_solveInvoicingGeneration(
'category': "caté",
}],
}
@expectedFailure
@simulate('ComputerConsumptionTioXMLFile_parseXml',
'*args, **kwargs',
"return %s" % tio_dict)
......@@ -409,6 +412,7 @@ class TestSlapOSComputerConsumptionTioXMLFile_solveInvoicingGeneration(
'category': "caté",
}],
}
@expectedFailure
@simulate('ComputerConsumptionTioXMLFile_parseXml',
'*args, **kwargs',
"return %s" % tio_dict)
......@@ -475,6 +479,7 @@ class TestSlapOSComputerConsumptionTioXMLFile_solveInvoicingGeneration(
'category': "caté",
}],
}
@expectedFailure
@simulate('ComputerConsumptionTioXMLFile_parseXml',
'*args, **kwargs',
"return %s" % tio_dict)
......@@ -556,6 +561,7 @@ class TestSlapOSComputerConsumptionTioXMLFile_solveInvoicingGeneration(
'category': "caté",
}],
}
@expectedFailure
@simulate('ComputerConsumptionTioXMLFile_parseXml',
'*args, **kwargs',
"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 @@
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Sale Packing List Line" module="erp5.portal_type"/>
<global name="Test Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>categories</string> </key>
<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>
<key> <string>default_reference</string> </key>
<value> <string>testSlapOSERP5AccountingScenario</string> </value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>1</string> </value>
<key> <string>default_source_reference</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>description</string> </key>
......@@ -30,35 +24,39 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>destroy</string> </value>
<value> <string>test.erp5.testSlapOSERP5AccountingScenario</string> </value>
</item>
<item>
<key> <string>index</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
<key> <string>portal_type</string> </key>
<value> <string>Test Component</string> </value>
</item>
<item>
<key> <string>int_index</string> </key>
<value> <int>1</int> </value>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>language</string> </key>
<key> <string>text_content_error_message</string> </key>
<value>
<none/>
<tuple/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Sale Packing List Line</string> </value>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>price</string> </key>
<value> <float>0.0</float> </value>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Destroy Line</string> </value>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
......@@ -74,7 +72,7 @@
<value>
<dictionary>
<item>
<key> <string>movement</string> </key>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
......@@ -87,14 +85,25 @@
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<key> <string>_log</string> </key>
<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>
</item>
</dictionary>
......
......@@ -33,11 +33,12 @@ class TestSlapOSEntityCreatePaymentMixin(SlapOSTestCaseMixin):
portal_type="Bank Account"
)
currency = self.portal.currency_module.newContent(
portal_type="Currency"
portal_type="Currency",
base_unit_quantity=0.1
)
if person is None:
person = self.portal.person_module.template_member\
.Base_createCloneDocument(batch_mode=1)
person = self.portal.person_module\
.newContent(portal_type="Person")
invoice = self.createSaleInvoiceTransaction(
source_value=organisation,
......@@ -95,31 +96,29 @@ class TestSlapOSEntityCreatePaymentMixin(SlapOSTestCaseMixin):
expected_set = [
'causality/%s' % invoice.getRelativeUrl(),
'destination_section/%s' % invoice.getDestinationSection(),
'destination_project/%s' % invoice.getDestinationProject(),
'price_currency/%s' % invoice.getPriceCurrency(),
'resource/%s' % invoice.getResource(),
'resource/%s' % invoice.getPriceCurrency(),
'source_payment/%s' % invoice.getSourcePayment(),
'payment_mode/%s' % self.payment_mode,
'source_section/%s' % invoice.getSourceSection(),
#'source_project/%s' % invoice.getSourceProject(),
'ledger/%s' % invoice.getLedger(),
]
self.assertSameSet(expected_set, payment.getCategoryList())
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()
self.assertEqual(2, len(movement_list))
bank_list = [q for q in movement_list
if q.getSource() == 'account_module/payment_to_encash']
rec_list = [q for q in movement_list
if q.getSource() == 'account_module/receivable']
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):
self.assertTrue(line.hasStartDate())
self.assertTrue(line.hasStopDate())
self.assertFalse(line.hasStartDate())
self.assertFalse(line.hasStopDate())
self.assertEqual(quantity, line.getQuantity())
self.assertSameSet(category_list, line.getCategoryList())
......@@ -127,18 +126,25 @@ class TestSlapOSEntityCreatePaymentMixin(SlapOSTestCaseMixin):
assertLine(bank_list[0], invoice_amount, [
'destination/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',
'source/account_module/receivable'])
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)
return payment
def resetPaymentTag(self, invoice):
payment_tag = "sale_invoice_transaction_create_payment_%s" % invoice.getUid()
invoice.REQUEST.set(payment_tag, None)
def resetPaymentTag(self, person):
payment_tag = "Entity_createPaymentTransaction_%s" % person.getUid()
person.REQUEST.set(payment_tag, None)
def _test(self):
person, invoice = self.makeSaleInvoiceTransaction()
......@@ -157,7 +163,7 @@ class TestSlapOSEntityCreatePaymentMixin(SlapOSTestCaseMixin):
payment = self.fullBuild(person, [invoice])
self.assertPayment(payment, invoice)
self.tic()
self.resetPaymentTag(invoice)
self.resetPaymentTag(person)
# Create twice, generate 2 payments
payment = self.fullBuild(person, [invoice])
......@@ -181,7 +187,7 @@ class TestSlapOSEntityCreatePaymentMixin(SlapOSTestCaseMixin):
payment = self.fullBuild(person, [invoice])
self.commit()
# 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?
payment2 = self.fullBuild(person, [invoice])
......@@ -198,7 +204,7 @@ class TestSlapOSEntityCreatePaymentMixin(SlapOSTestCaseMixin):
payment = self.fullBuild(person, [invoice])
payment.cancel()
self.tic()
self.resetPaymentTag(invoice)
self.resetPaymentTag(person)
payment = self.fullBuild(person, [invoice])
self.tic()
......@@ -212,8 +218,9 @@ class TestSlapOSEntityCreatePaymentMixin(SlapOSTestCaseMixin):
invoice_2.confirm()
invoice_2.stop()
self.tic()
payment_list = [self.fullBuild(person, [invoice_1]),
self.fullBuild(person, [invoice_2])]
payment_list = [self.fullBuild(person, [invoice_1])]
self.resetPaymentTag(person)
payment_list.append(self.fullBuild(person, [invoice_2]))
self.tic()
self.assertEqual(2, len(payment_list))
......
......@@ -8,6 +8,7 @@ Consumption Document Module | view
Hosting Subscription | periodicity
Instance Tree | jump_to_related_open_order_line
Payment Transaction | related_payzen_event
Person | create_slapos_payment_transaction
Root Applied Rule Causality Causality Movement Group | view
Sale Invoice Transaction | create_slapos_reversal
Sale Packing List | jump_related_aggregated_packing_list
......
......@@ -8,9 +8,7 @@ business_process_module/slapos_subscription_business_process
business_process_module/slapos_subscription_business_process/**
business_process_module/slapos_ultimate_business_process
organisation_module/slapos
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
organisation_module/slapos/bank_account
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
......
......@@ -12,7 +12,6 @@ account_module/receivable
account_module/refundable_vat
account_module/sales
business_process_module/slapos_ultimate_business_process
organisation_module/slapos/bank_account
portal_rules/slapos_delivery_root_simulation_rule
portal_rules/slapos_invoice_root_simulation_rule
portal_rules/slapos_invoice_simulation_rule
......
......@@ -54,9 +54,6 @@ 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/**
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/disk_used
service_module/memory_used
......
......@@ -6,7 +6,6 @@ SlapOSAccountingSaleInvoiceTransactionConstraint
SlapOSAccountingSalePackingListConstraint
SlapOSAccountingSalePackingListLineConstraint
SlapOSAccountingSaleTradeConditionConstraint
SlapOSAccountingSystemPreference
SlapOSCloudContractAccounting
SlapOSCloudContractLineAccounting
SlapOSLedgerConstraint
......
......@@ -5,5 +5,6 @@ test.erp5.testSlapOSAccountingInteractionWorkflow
test.erp5.testSlapOSAccountingRule
test.erp5.testSlapOSAccountingSkins
test.erp5.testSlapOSConsumptionSkins
test.erp5.testSlapOSERP5AccountingScenario
test.erp5.testSlapOSEntityCreatePayment
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