Commit d0f0cf5d authored by Romain Courteaud's avatar Romain Courteaud

Automate invoice cancellation.

Cancel invoice if user removes his instances.
parent 8de90af7
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Alarm" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>active_sense_method_id</string> </key>
<value> <string>Alarm_cancelInvoiceRelatedToSuspendedRegularisationRequest</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>slapos_crm_cancel_invoice</string> </value>
</item>
<item>
<key> <string>periodicity_hour</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>periodicity_hour_frequency</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>periodicity_minute</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>periodicity_minute_frequency</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>periodicity_month</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>periodicity_month_day</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>periodicity_start_date</string> </key>
<value>
<object>
<klass>
<global name="DateTime" module="DateTime.DateTime"/>
</klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1288051200.0</float>
<string>GMT</string>
</tuple>
</state>
</object>
</value>
</item>
<item>
<key> <string>periodicity_week</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Alarm</string> </value>
</item>
<item>
<key> <string>sense_method_id</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Cancel Invoice</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Service" 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>
</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>
</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>
</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>
</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>aggregated_portal_type</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>quantity_unit/unit/piece</string>
<string>use/crm/regularisation_request</string>
</tuple>
</value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>CRMINVCAN</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>slapos_crm_invoice_cancellation</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Service</string> </value>
</item>
<item>
<key> <string>required_aggregated_portal_type</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Invoice Cancellation</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAU=</string> </persistent>
</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>
<record id="5" aka="AAAAAAAAAAU=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>edit_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAY=</string> </persistent>
</value>
</item>
<item>
<key> <string>validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAc=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="6" aka="AAAAAAAAAAY=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
</pickle>
<pickle>
<tuple>
<none/>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>edit</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <string>zope</string> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>0.0.0.0</string> </value>
</item>
<item>
<key> <string>state</string> </key>
<value> <string>current</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global id="6.1" name="DateTime" module="DateTime.DateTime"/>
</klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1362653568.12</float>
<string>GMT+1</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>edit</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <string>zope</string> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAg=</string> </persistent>
</value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>0.0.0.0</string> </value>
</item>
<item>
<key> <string>state</string> </key>
<value> <string>current</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass> <reference id="6.1"/> </klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1362653568.14</float>
<string>GMT+1</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>edit</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <string>zope</string> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>925.9612.52779.40533</string> </value>
</item>
<item>
<key> <string>state</string> </key>
<value> <string>current</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass> <reference id="6.1"/> </klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1362653576.18</float>
<string>GMT+1</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>edit</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <string>zope</string> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>925.9613.31605.59289</string> </value>
</item>
<item>
<key> <string>state</string> </key>
<value> <string>current</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass> <reference id="6.1"/> </klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1362653640.85</float>
<string>GMT+1</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</tuple>
</pickle>
</record>
<record id="7" aka="AAAAAAAAAAc=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
</pickle>
<pickle>
<tuple>
<none/>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <string>zope</string> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global id="7.1" name="DateTime" module="DateTime.DateTime"/>
</klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1362653568.09</float>
<string>GMT+1</string>
</tuple>
</state>
</object>
</value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>draft</string> </value>
</item>
</dictionary>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate_action</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <string>zope</string> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass> <reference id="7.1"/> </klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1362653657.42</float>
<string>GMT+1</string>
</tuple>
</state>
</object>
</value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>draft</string> </value>
</item>
</dictionary>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <string>zope</string> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass> <reference id="7.1"/> </klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1362653657.43</float>
<string>GMT+1</string>
</tuple>
</state>
</object>
</value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</tuple>
</pickle>
</record>
<record id="8" aka="AAAAAAAAAAg=">
<pickle>
<global name="Message" module="Products.ERP5Type.Message"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default</string> </key>
<value> <string>Object copied from ${source_item}</string> </value>
</item>
<item>
<key> <string>domain</string> </key>
<value> <string>erp5_ui</string> </value>
</item>
<item>
<key> <string>mapping</string> </key>
<value>
<dictionary>
<item>
<key> <string>source_item</string> </key>
<value> <string>/erp5/service_module/slapos_crm_information</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>message</string> </key>
<value> <string>Object copied from ${source_item}</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>portal = context.getPortalObject()\n
portal.portal_catalog.searchAndActivate(\n
portal_type="Regularisation Request", \n
simulation_state=["suspended"],\n
method_id=\'RegularisationRequest_cancelInvoiceIfPersonOpenOrderIsEmpty\',\n
activate_kw={\'tag\': tag}\n
)\n
context.activate(after_tag=tag).getId()\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>tag, fixit, params</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Alarm_cancelInvoiceRelatedToSuspendedRegularisationRequest</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -92,6 +92,7 @@ if (ticket is None) and int(person.Entity_statBalance()) > 0:\n ...@@ -92,6 +92,7 @@ if (ticket is None) and int(person.Entity_statBalance()) > 0:\n
source_project_value=context,\n source_project_value=context,\n
title=\'Account regularisation expected for "%s"\' % context.getTitle(),\n title=\'Account regularisation expected for "%s"\' % context.getTitle(),\n
destination_decision_value=context,\n destination_decision_value=context,\n
destination_value=context,\n
start_date=DateTime(),\n start_date=DateTime(),\n
resource=portal.portal_preferences.getPreferredRegularisationRequestResource(),\n resource=portal.portal_preferences.getPreferredRegularisationRequestResource(),\n
)\n )\n
...@@ -100,17 +101,10 @@ if (ticket is None) and int(person.Entity_statBalance()) > 0:\n ...@@ -100,17 +101,10 @@ if (ticket is None) and int(person.Entity_statBalance()) > 0:\n
\n \n
ticket.reindexObject(activate_kw={\'tag\': tag})\n ticket.reindexObject(activate_kw={\'tag\': tag})\n
\n \n
# Inform user that the ticket has been created.\n mail_message = ticket.RegularisationRequest_checkToSendUniqEvent(\n
mail_message = portal.event_module.newContent(\n portal.portal_preferences.getPreferredRegularisationRequestResource(),\n
portal_type=\'Mail Message\',\n \'Invoice payment requested\',\n
start_date=DateTime(),\n """Dear user,\n
destination_value=person,\n
follow_up=ticket.getRelativeUrl(),\n
source_value=ticket.getSourceValue(),\n
title=\'Invoice payment requested\',\n
resource=ticket.getResource(),\n
text_content="""\n
Dear user,\n
\n \n
A new invoice has been generated. \n A new invoice has been generated. \n
You can access it in your invoice section at %s.\n You can access it in your invoice section at %s.\n
...@@ -119,10 +113,8 @@ Do not hesitate to visit the web forum (http://community.slapos.org/forum) in ca ...@@ -119,10 +113,8 @@ Do not hesitate to visit the web forum (http://community.slapos.org/forum) in ca
\n \n
Regards,\n Regards,\n
The slapos team\n The slapos team\n
""" % portal.portal_preferences.getPreferredSlaposWebSiteUrl())\n """ % portal.portal_preferences.getPreferredSlaposWebSiteUrl(),\n
portal.portal_workflow.doActionFor(mail_message, \'start_action\', send_mail=True, comment=\'Requested manual payment.\')\n \'Requested manual payment.\')\n
mail_message.stop(comment=\'Requested manual payment.\')\n
mail_message.deliver(comment=\'Requested manual payment.\')\n
\n \n
return ticket, mail_message\n return ticket, mail_message\n
\n \n
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>from zExceptions import Unauthorized\n
if REQUEST is not None:\n
raise Unauthorized\n
\n
mail_message = None\n
invoice_list = []\n
\n
state = context.getSimulationState()\n
person = context.getSourceProjectValue(portal_type="Person")\n
if (state != \'suspended\') or \\\n
(person is None):\n
return mail_message, invoice_list\n
else:\n
portal = context.getPortalObject()\n
\n
open_order = portal.portal_catalog.getResultValue(\n
portal_type="Open Sale Order",\n
validation_state="validated",\n
default_destination_decision_uid=person.getUid())\n
\n
if (open_order is None) or \\\n
(open_order.getValidationState() != "validated") or \\\n
(len(open_order.contentValues(portal_type="Open Sale Order Line")) != 0):\n
return mail_message, invoice_list\n
else:\n
assert open_order.getDestinationDecisionUid() == person.getUid()\n
ticket = context\n
\n
for payment in portal.portal_catalog(\n
portal_type="Payment Transaction", \n
payment_mode_uid=portal.portal_categories.payment_mode.payzen.getUid(),\n
default_destination_section_uid=person.getUid(),\n
simulation_state=["started"],\n
):\n
\n
if payment.PaymentTransaction_getPayzenId()[1] is None:\n
invoice = payment.getCausalityValue(portal_type="Sale Invoice Transaction")\n
assert payment.getDestinationSectionUid() == person.getUid()\n
invoice.SaleInvoiceTransaction_createReversalPayzenTransaction()\n
invoice_list.append(invoice.getRelativeUrl())\n
\n
# XXX Hardcoded\n
cancel_service = portal.service_module.slapos_crm_invoice_cancellation\n
mail_message = ticket.RegularisationRequest_checkToSendUniqEvent(\n
cancel_service.getRelativeUrl(),\n
\'Cancellation of your bill\',\n
"""Hello,\n
\n
Thank you to have used our decentralized Cloud Computing service slapos.org.\n
\n
We noticed that all your instances have been removed upon receiving your bill, so we conclude that the instances that you requested were not being used but probably ordered then forgotten.\n
\n
To not to charge our first users a "non use" of our service, we have choosen to cancel your bill. That\'s mean: *You have nothing to pay us.*\n
\n
We hope to see you using our services in the future.\n
\n
Regards,\n
The slapos team\n
""",\n
\'Cancelled payment.\')\n
\n
return mail_message, invoice_list\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>REQUEST=None</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>RegularisationRequest_cancelInvoiceIfPersonOpenOrderIsEmpty</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string encoding="cdata"><![CDATA[
from zExceptions import Unauthorized\n
if REQUEST is not None:\n
raise Unauthorized\n
\n
portal = context.getPortalObject()\n
ticket = context\n
service = portal.restrictedTraverse(service_relative_url)\n
assert service.getPortalType() == "Service"\n
event_portal_type = "Mail Message"\n
\n
# XXX TODO\n
# # Prevent to create 2 tickets during the same transaction\n
# transactional_variable = getTransactionalVariable()\n
# if tag in transactional_variable:\n
# raise RuntimeError, \'ticket %s already exist\' % tag\n
# else:\n
# transactional_variable[tag] = None\n
\n
event = portal.portal_catalog.getResultValue(\n
portal_type=event_portal_type,\n
default_resource_uid=service.getUid(),\n
default_follow_up_uid=ticket.getUid(),\n
)\n
\n
if (event is None) and (ticket.getSimulationState() == \'suspended\'):\n
tag = "%s_addUniqEvent_%s" % (ticket.getUid(), service.getUid())\n
if (portal.portal_activities.countMessageWithTag(tag) > 0):\n
# The event is already under creation but can not be fetched from catalog\n
return None\n
\n
# Prevent concurrent transaction to create 2 events for the same ticket\n
ticket.edit(resource=service_relative_url)\n
\n
event = portal.event_module.newContent(\n
portal_type=event_portal_type,\n
start_date=DateTime(),\n
destination=ticket.getDestination(),\n
follow_up=ticket.getRelativeUrl(),\n
source=context.getSource(),\n
title=title,\n
resource=service_relative_url,\n
text_content=text_content,\n
)\n
\n
portal.portal_workflow.doActionFor(event, \'start_action\', send_mail=True, comment=comment)\n
event.stop(comment=comment)\n
event.deliver(comment=comment)\n
event.reindexObject(activate_kw={\'tag\': tag})\n
\n
return event\n
]]></string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>service_relative_url, title, text_content, comment, REQUEST=None</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>RegularisationRequest_checkToSendUniqEvent</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -174,3 +174,67 @@ portal_workflow.doActionFor(context, action='edit_action', comment='Visited by R ...@@ -174,3 +174,67 @@ portal_workflow.doActionFor(context, action='edit_action', comment='Visited by R
self.assertEqual( self.assertEqual(
'Visited by RegularisationRequest_invalidateIfPersonBalanceIsOk', 'Visited by RegularisationRequest_invalidateIfPersonBalanceIsOk',
ticket.workflow_history['edit_workflow'][-1]['comment']) ticket.workflow_history['edit_workflow'][-1]['comment'])
class TestSlapOSCrmCancelInvoiceRelatedToSuspendedRegularisationRequest(testSlapOSMixin):
def beforeTearDown(self):
transaction.abort()
def createRegularisationRequest(self):
new_id = self.generateNewId()
return self.portal.regularisation_request_module.newContent(
portal_type='Regularisation Request',
title="Test Reg. Req.%s" % new_id,
reference="TESTREGREQ-%s" % new_id,
)
def _simulateRegularisationRequest_cancelInvoiceIfPersonOpenOrderIsEmpty(self):
script_name = 'RegularisationRequest_cancelInvoiceIfPersonOpenOrderIsEmpty'
if script_name in self.portal.portal_skins.custom.objectIds():
raise ValueError('Precondition failed: %s exists in custom' % script_name)
createZODBPythonScript(self.portal.portal_skins.custom,
script_name,
'*args, **kwargs',
'# Script body\n'
"""portal_workflow = context.portal_workflow
portal_workflow.doActionFor(context, action='edit_action', comment='Visited by RegularisationRequest_cancelInvoiceIfPersonOpenOrderIsEmpty') """ )
transaction.commit()
def _dropRegularisationRequest_cancelInvoiceIfPersonOpenOrderIsEmpty(self):
script_name = 'RegularisationRequest_cancelInvoiceIfPersonOpenOrderIsEmpty'
if script_name in self.portal.portal_skins.custom.objectIds():
self.portal.portal_skins.custom.manage_delObjects(script_name)
transaction.commit()
def test_alarm_not_suspended_regularisation_request(self):
ticket = self.createRegularisationRequest()
ticket.validate()
self.tic()
self._simulateRegularisationRequest_cancelInvoiceIfPersonOpenOrderIsEmpty()
try:
self.portal.portal_alarms.\
slapos_crm_cancel_invoice.activeSense()
self.tic()
finally:
self._dropRegularisationRequest_cancelInvoiceIfPersonOpenOrderIsEmpty()
self.assertNotEqual(
'Visited by RegularisationRequest_cancelInvoiceIfPersonOpenOrderIsEmpty',
ticket.workflow_history['edit_workflow'][-1]['comment'])
def test_alarm_suspended_regularisation_request(self):
ticket = self.createRegularisationRequest()
ticket.validate()
ticket.suspend()
self.tic()
self._simulateRegularisationRequest_cancelInvoiceIfPersonOpenOrderIsEmpty()
try:
self.portal.portal_alarms.\
slapos_crm_cancel_invoice.activeSense()
self.tic()
finally:
self._dropRegularisationRequest_cancelInvoiceIfPersonOpenOrderIsEmpty()
self.assertEqual(
'Visited by RegularisationRequest_cancelInvoiceIfPersonOpenOrderIsEmpty',
ticket.workflow_history['edit_workflow'][-1]['comment'])
...@@ -57,6 +57,10 @@ class TestSlapOSPerson_checkToCreateRegularisationRequest(testSlapOSMixin): ...@@ -57,6 +57,10 @@ class TestSlapOSPerson_checkToCreateRegularisationRequest(testSlapOSMixin):
self.assertEquals(ticket.getSourceProject(), person.getRelativeUrl()) self.assertEquals(ticket.getSourceProject(), person.getRelativeUrl())
self.assertEquals(ticket.getTitle(), self.assertEquals(ticket.getTitle(),
'Account regularisation expected for "%s"' % person.getTitle()) 'Account regularisation expected for "%s"' % person.getTitle())
self.assertEquals(ticket.getDestination(),
person.getRelativeUrl())
self.assertEquals(ticket.getDestinationDecision(),
person.getRelativeUrl())
self.assertEquals(event.getPortalType(), 'Mail Message') self.assertEquals(event.getPortalType(), 'Mail Message')
self.assertTrue(event.getStartDate() >= before_date) self.assertTrue(event.getStartDate() >= before_date)
self.assertTrue(event.getStopDate() <= after_date) self.assertTrue(event.getStopDate() <= after_date)
...@@ -65,8 +69,7 @@ class TestSlapOSPerson_checkToCreateRegularisationRequest(testSlapOSMixin): ...@@ -65,8 +69,7 @@ class TestSlapOSPerson_checkToCreateRegularisationRequest(testSlapOSMixin):
person.getRelativeUrl()) person.getRelativeUrl())
self.assertEquals(event.getSource(), self.assertEquals(event.getSource(),
ticket.getSource()) ticket.getSource())
expected_text_content = """ expected_text_content = """Dear user,
Dear user,
A new invoice has been generated. A new invoice has been generated.
You can access it in your invoice section at http://foobar.org/. You can access it in your invoice section at http://foobar.org/.
...@@ -101,6 +104,9 @@ The slapos team ...@@ -101,6 +104,9 @@ The slapos team
self.assertEquals(event2, None) self.assertEquals(event2, None)
@simulate('Entity_statBalance', '*args, **kwargs', 'return "0"') @simulate('Entity_statBalance', '*args, **kwargs', 'return "0"')
@simulate('RegularisationRequest_checkToSendUniqEvent',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
def test_addRegularisationRequest_balance_ok(self): def test_addRegularisationRequest_balance_ok(self):
person = self.createPerson() person = self.createPerson()
ticket, event = person.Person_checkToCreateRegularisationRequest() ticket, event = person.Person_checkToCreateRegularisationRequest()
...@@ -217,3 +223,381 @@ class TestSlapOSRegularisationRequest_invalidateIfPersonBalanceIsOk( ...@@ -217,3 +223,381 @@ class TestSlapOSRegularisationRequest_invalidateIfPersonBalanceIsOk(
ticket.suspend() ticket.suspend()
ticket.RegularisationRequest_invalidateIfPersonBalanceIsOk() ticket.RegularisationRequest_invalidateIfPersonBalanceIsOk()
self.assertEquals(ticket.getSimulationState(), 'suspended') self.assertEquals(ticket.getSimulationState(), 'suspended')
class TestSlapOSRegularisationRequest_checkToSendUniqEvent(testSlapOSMixin):
def beforeTearDown(self):
transaction.abort()
def createPerson(self):
new_id = self.generateNewId()
return self.portal.person_module.newContent(
portal_type='Person',
title="Person %s" % new_id,
reference="TESTPERS-%s" % new_id,
)
def createRegularisationRequest(self):
new_id = self.generateNewId()
return self.portal.regularisation_request_module.newContent(
portal_type='Regularisation Request',
title="Test Reg. Req.%s" % new_id,
reference="TESTREGREQ-%s" % new_id,
resource='foo/bar',
)
def test_checkToSendUniqEvent_no_event(self):
person = self.createPerson()
ticket = self.createRegularisationRequest()
ticket.edit(
source='organisation_module/slapos',
destination_value=person,
source_project_value=person)
ticket.validate()
ticket.suspend()
before_date = DateTime()
event = ticket.RegularisationRequest_checkToSendUniqEvent(
'service_module/slapos_crm_spam', 'foo title', 'foo content', 'foo comment')
after_date = DateTime()
self.assertEquals(ticket.getSimulationState(), 'suspended')
self.assertEquals(ticket.getResource(), 'service_module/slapos_crm_spam')
self.assertEquals(event.getPortalType(), 'Mail Message')
self.assertEquals(event.getSimulationState(), 'delivered')
self.assertTrue(event.getStartDate() >= before_date)
self.assertTrue(event.getStopDate() <= after_date)
self.assertEquals(event.getTitle(), "foo title")
self.assertEquals(event.getResource(), 'service_module/slapos_crm_spam')
self.assertEquals(event.getFollowUp(), ticket.getRelativeUrl())
self.assertEquals(event.getSource(), "organisation_module/slapos")
self.assertEquals(event.getDestination(), person.getRelativeUrl())
self.assertEquals(event.getTextContent(), 'foo content')
def test_checkToSendUniqEvent_service_required(self):
ticket = self.createRegularisationRequest()
self.assertRaises(
AssertionError,
ticket.RegularisationRequest_checkToSendUniqEvent,
ticket.getRelativeUrl(), '', '', ''
)
def test_checkToSendUniqEvent_call_twice_with_tic(self):
person = self.createPerson()
ticket = self.createRegularisationRequest()
ticket.edit(
source='organisation_module/slapos',
destination_value=person,
source_project_value=person)
ticket.validate()
ticket.suspend()
event = ticket.RegularisationRequest_checkToSendUniqEvent(
'service_module/slapos_crm_spam', 'foo title', 'foo content', 'foo comment')
self.tic()
event2 = ticket.RegularisationRequest_checkToSendUniqEvent(
'service_module/slapos_crm_spam', 'foo2 title', 'foo2 content', 'foo2 comment')
self.assertEquals(event.getTitle(), "foo title")
self.assertEquals(event.getTextContent(), 'foo content')
self.assertEquals(event.getRelativeUrl(), event2.getRelativeUrl())
def test_checkToSendUniqEvent_manual_event(self):
person = self.createPerson()
ticket = self.createRegularisationRequest()
ticket.edit(
source='organisation_module/slapos',
destination_value=person,
source_project_value=person)
ticket.validate()
ticket.suspend()
event = self.portal.event_module.newContent(
portal_type="Mail Message",
follow_up=ticket.getRelativeUrl(),
resource='service_module/slapos_crm_spam',
)
self.tic()
event2 = ticket.RegularisationRequest_checkToSendUniqEvent(
'service_module/slapos_crm_spam', 'foo2 title', 'foo2 content', 'foo2 comment')
self.assertEquals(ticket.getResource(), 'foo/bar')
self.assertNotEquals(event.getTitle(), 'foo2 title')
self.assertEquals(event.getTextContent(), None)
self.assertEquals(event.getSimulationState(), 'draft')
self.assertEquals(event.getRelativeUrl(), event2.getRelativeUrl())
def test_checkToSendUniqEvent_not_suspended(self):
person = self.createPerson()
ticket = self.createRegularisationRequest()
ticket.edit(
source='organisation_module/slapos',
destination_value=person,
source_project_value=person)
ticket.validate()
event = ticket.RegularisationRequest_checkToSendUniqEvent(
'service_module/slapos_crm_spam', 'foo2 title', 'foo2 content', 'foo2 comment')
self.assertEquals(event, None)
def test_checkToSendUniqEvent_event_not_reindexed(self):
person = self.createPerson()
ticket = self.createRegularisationRequest()
ticket.edit(
source='organisation_module/slapos',
destination_value=person,
source_project_value=person)
ticket.validate()
ticket.suspend()
event = ticket.RegularisationRequest_checkToSendUniqEvent(
'service_module/slapos_crm_spam', 'foo title', 'foo content', 'foo comment')
transaction.commit()
event2 = ticket.RegularisationRequest_checkToSendUniqEvent(
'service_module/slapos_crm_spam', 'foo2 title', 'foo2 content', 'foo2 comment')
self.assertNotEquals(event, event2)
self.assertEquals(event2, None)
def test_checkToSendUniqEvent_REQUEST_disallowed(self):
ticket = self.createRegularisationRequest()
self.assertRaises(
Unauthorized,
ticket.RegularisationRequest_checkToSendUniqEvent,
'', '', '', '',
REQUEST={})
class TestSlapOSRegularisationRequest_cancelInvoiceIfPersonOpenOrderIsEmpty(
testSlapOSMixin):
def beforeTearDown(self):
transaction.abort()
def createPerson(self):
new_id = self.generateNewId()
return self.portal.person_module.newContent(
portal_type='Person',
title="Person %s" % new_id,
reference="TESTPERS-%s" % new_id,
)
def createRegularisationRequest(self):
new_id = self.generateNewId()
return self.portal.regularisation_request_module.newContent(
portal_type='Regularisation Request',
title="Test Reg. Req.%s" % new_id,
reference="TESTREGREQ-%s" % new_id,
resource='foo/bar',
)
def createOpenOrder(self):
new_id = self.generateNewId()
return self.portal.open_sale_order_module.newContent(
portal_type='Open Sale Order',
title="Test Open Order %s" % new_id,
reference="TESTOPENORDER-%s" % new_id,
)
def createSaleInvoiceTransaction(self):
new_id = self.generateNewId()
return self.portal.accounting_module.newContent(
portal_type='Sale Invoice Transaction',
title="Test Sale Invoice %s" % new_id,
reference="TESTSALEINVOICE-%s" % new_id,
)
def createPaymentTransaction(self):
new_id = self.generateNewId()
return self.portal.accounting_module.newContent(
portal_type='Payment Transaction',
title="Test Payment %s" % new_id,
reference="TESTPAYMENT-%s" % new_id,
)
def test_cancelInvoiceIfPersonOpenOrderIsEmpty_REQUEST_disallowed(self):
ticket = self.createRegularisationRequest()
self.assertRaises(
Unauthorized,
ticket.RegularisationRequest_cancelInvoiceIfPersonOpenOrderIsEmpty,
REQUEST={})
@simulate('SaleInvoiceTransaction_createReversalPayzenTransaction',
'*args, **kwargs',
'context.portal_workflow.doActionFor(' \
'context, action="edit_action", ' \
'comment="Visited by SaleInvoiceTransaction_createReversalPayzenTransaction")')
@simulate('RegularisationRequest_checkToSendUniqEvent',
'service_relative_url, title, text_content, comment, REQUEST=None',
'context.portal_workflow.doActionFor(' \
'context, action="edit_action", ' \
'comment="Visited by RegularisationRequest_checkToSendUniqEvent ' \
'%s %s %s %s" % (service_relative_url, title, text_content, comment))\n' \
'return "fooevent"')
def test_cancelInvoiceIfPersonOpenOrderIsEmpty_invoice_to_cancel(self):
person = self.createPerson()
ticket = self.createRegularisationRequest()
ticket.edit(
destination_value=person,
source_project_value=person)
ticket.validate()
ticket.suspend()
order = self.createOpenOrder()
order.edit(destination_decision_value=person)
self.portal.portal_workflow._jumpToStateFor(order, 'validated')
invoice = self.createSaleInvoiceTransaction()
invoice.edit(
payment_mode="payzen",
)
payment = self.createPaymentTransaction()
payment.edit(
payment_mode="payzen",
causality_value=invoice,
destination_section_value=person)
self.portal.portal_workflow._jumpToStateFor(payment, 'started')
self.tic()
event, invoice_list = \
ticket.RegularisationRequest_cancelInvoiceIfPersonOpenOrderIsEmpty()
expected_service = 'service_module/slapos_crm_invoice_cancellation'
expected_title = 'Cancellation of your bill'
expected_text= """Hello,
Thank you to have used our decentralized Cloud Computing service slapos.org.
We noticed that all your instances have been removed upon receiving your bill, so we conclude that the instances that you requested were not being used but probably ordered then forgotten.
To not to charge our first users a "non use" of our service, we have choosen to cancel your bill. That's mean: *You have nothing to pay us.*
We hope to see you using our services in the future.
Regards,
The slapos team
"""
expected_comment = 'Cancelled payment.'
self.assertEqual(
'Visited by RegularisationRequest_checkToSendUniqEvent %s %s %s %s' % \
(expected_service, expected_title, expected_text, expected_comment),
ticket.workflow_history['edit_workflow'][-1]['comment'])
self.assertEqual(
'Visited by SaleInvoiceTransaction_createReversalPayzenTransaction',
invoice.workflow_history['edit_workflow'][-1]['comment'])
self.assertEqual(event, "fooevent")
self.assertEqual(invoice_list, [invoice.getRelativeUrl()])
@simulate('SaleInvoiceTransaction_createReversalPayzenTransaction',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
@simulate('RegularisationRequest_checkToSendUniqEvent',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
def test_cancelInvoiceIfPersonOpenOrderIsEmpty_not_suspended_ticket(self):
person = self.createPerson()
ticket = self.createRegularisationRequest()
ticket.edit(
destination_value=person,
source_project_value=person)
ticket.validate()
event, invoice_list = \
ticket.RegularisationRequest_cancelInvoiceIfPersonOpenOrderIsEmpty()
self.assertEqual(event, None)
self.assertEqual(invoice_list, [])
@simulate('SaleInvoiceTransaction_createReversalPayzenTransaction',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
@simulate('RegularisationRequest_checkToSendUniqEvent',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
def test_cancelInvoiceIfPersonOpenOrderIsEmpty_no_person_related(self):
ticket = self.createRegularisationRequest()
ticket.validate()
ticket.suspend()
event, invoice_list = \
ticket.RegularisationRequest_cancelInvoiceIfPersonOpenOrderIsEmpty()
self.assertEqual(event, None)
self.assertEqual(invoice_list, [])
@simulate('SaleInvoiceTransaction_createReversalPayzenTransaction',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
@simulate('RegularisationRequest_checkToSendUniqEvent',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
def test_cancelInvoiceIfPersonOpenOrderIsEmpty_no_open_order(self):
person = self.createPerson()
ticket = self.createRegularisationRequest()
ticket.edit(
destination_value=person,
source_project_value=person)
ticket.validate()
ticket.suspend()
event, invoice_list = \
ticket.RegularisationRequest_cancelInvoiceIfPersonOpenOrderIsEmpty()
self.assertEqual(event, None)
self.assertEqual(invoice_list, [])
@simulate('SaleInvoiceTransaction_createReversalPayzenTransaction',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
@simulate('RegularisationRequest_checkToSendUniqEvent',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
def test_cancelInvoiceIfPersonOpenOrderIsEmpty_with_open_order_line(self):
person = self.createPerson()
ticket = self.createRegularisationRequest()
ticket.edit(
destination_value=person,
source_project_value=person)
ticket.validate()
ticket.suspend()
order = self.createOpenOrder()
order.edit(destination_decision_value=person)
order.newContent(portal_type="Open Sale Order Line")
self.portal.portal_workflow._jumpToStateFor(order, 'validated')
self.tic()
event, invoice_list = \
ticket.RegularisationRequest_cancelInvoiceIfPersonOpenOrderIsEmpty()
self.assertEqual(event, None)
self.assertEqual(invoice_list, [])
@simulate('SaleInvoiceTransaction_createReversalPayzenTransaction',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
@simulate('RegularisationRequest_checkToSendUniqEvent',
'service_relative_url, title, text_content, comment, REQUEST=None',
'context.portal_workflow.doActionFor(' \
'context, action="edit_action", ' \
'comment="Visited by RegularisationRequest_checkToSendUniqEvent ' \
'%s %s %s %s" % (service_relative_url, title, text_content, comment))\n' \
'return "fooevent"')
def test_cancelInvoiceIfPersonOpenOrderIsEmpty_no_invoice(self):
person = self.createPerson()
ticket = self.createRegularisationRequest()
ticket.edit(
destination_value=person,
source_project_value=person)
ticket.validate()
ticket.suspend()
order = self.createOpenOrder()
order.edit(destination_decision_value=person)
self.portal.portal_workflow._jumpToStateFor(order, 'validated')
self.tic()
event, invoice_list = \
ticket.RegularisationRequest_cancelInvoiceIfPersonOpenOrderIsEmpty()
self.assertEqual(event, "fooevent")
self.assertEqual(invoice_list, [])
12 13
\ No newline at end of file \ No newline at end of file
service_module/slapos_crm_acknowledgement service_module/slapos_crm_acknowledgement
service_module/slapos_crm_complaint service_module/slapos_crm_complaint
service_module/slapos_crm_information service_module/slapos_crm_information
service_module/slapos_crm_spam service_module/slapos_crm_spam
\ No newline at end of file service_module/slapos_crm_invoice_cancellation
\ No newline at end of file
...@@ -2,6 +2,7 @@ service_module/slapos_crm_acknowledgement ...@@ -2,6 +2,7 @@ service_module/slapos_crm_acknowledgement
service_module/slapos_crm_complaint service_module/slapos_crm_complaint
service_module/slapos_crm_information service_module/slapos_crm_information
service_module/slapos_crm_spam service_module/slapos_crm_spam
service_module/slapos_crm_invoice_cancellation
support_request_module/slapos_crm_support_request_template support_request_module/slapos_crm_support_request_template
regularisation_request_module/slapos_crm_regularisation_request_template regularisation_request_module/slapos_crm_regularisation_request_template
event_module/slapos_crm_web_message_template event_module/slapos_crm_web_message_template
\ No newline at end of file
event_module/slapos_crm_web_message_template event_module/slapos_crm_web_message_template
portal_alarms/slapos_crm_cancel_invoice
portal_alarms/slapos_crm_create_regularisation_request portal_alarms/slapos_crm_create_regularisation_request
portal_alarms/slapos_crm_invalidate_suspended_regularisation_request portal_alarms/slapos_crm_invalidate_suspended_regularisation_request
regularisation_request_module/slapos_crm_regularisation_request_template regularisation_request_module/slapos_crm_regularisation_request_template
service_module/slapos_crm_acknowledgement service_module/slapos_crm_acknowledgement
service_module/slapos_crm_complaint service_module/slapos_crm_complaint
service_module/slapos_crm_information service_module/slapos_crm_information
service_module/slapos_crm_invoice_cancellation
service_module/slapos_crm_spam service_module/slapos_crm_spam
support_request_module/slapos_crm_support_request_template support_request_module/slapos_crm_support_request_template
\ 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