Commit cc8ae8bf authored by Romain Courteaud's avatar Romain Courteaud

slapos_crm:

* drop preferred_support_request_template_property
* drop slapos_crm_support_request_template
* fixup slapos_crm_create_regularisation_request tests
* reactivate slapos_crm_create_regularisation_request
* test slapos_crm_invalidate_suspended_regularisation_request is ok
* test slapos_crm_check_software_installation_state
* test slapos_crm_check_instance_in_error
* test slapos_crm_update_support_request_state
* desactivate Person_getSubscriptionRequestFirstUnpaidInvoiceList
* drop Person_getSubscriptionRequestFirstUnpaidInvoiceList
* do not count all Support Requests
  limit parameter with count is meaningless, as count return 1 result
* update Base_getSupportRequestInProgress usage
* XXX disable ticket.notify and ticket.requestEvent
* wip script to create Support Request and Event
* search a matching Trade Condition to generate a Support Request
* update ComputeNode_checkState to use new scripts
* test ComputeNode_checkSoftwareInstallationState
* deliver outgoing events
* test InstanceTree_checkSoftwareInstanceState
* Project_createSupportRequestWithCausality already checks if Support Request exists
* no need to check twice the object portal type
* test SupportRequest_updateMonitoringState
* activate one more alarm
* revert  Send Mail on pending tickets
  nexedi/slapos.core!417
  Virtual Master's manager are responsible to handle the tickets through their worklist.
  Not user.
  Virtual Master's manager can send email from the Ticket to directly ping a user.
* drop ticket_slap_interface_workflow
* test ComputeNode_hasContactedRecently
  Do not check if there is a packing list. It is unrelated to the contact.
* Base_getOpenRelatedTicketList was dropped
* ComputeNode_checkAndUpdateAllocationScope was dropped
* test: simplify
* set comment in the event workflow history
* send Mail Message
* unify event creation
  Reuse Ticket_createProjectEvent
* do not pass a empty list of node_uid
* no need to manually handle the notification message
* create the Regularisation Request from a Trade Condition instead of a template
* use notification message title instead of the ticket title
* use Entity_hasOutstandingAmount
  Entity_getOutstandingAmount is meaningless in case of multiple source_section and multiple currencies.
  Entity_hasOutstandingAmount will only report True or False.
* test RegularisationRequest_invalidateIfPersonBalanceIsOk
* test RegularisationRequest_checkToTriggerNextEscalationStep
* test RegularisationRequest_triggerStopReminderEscalation
* test RegularisationRequest_triggerStopAcknowledgmentEscalation
* test RegularisationRequest_triggerDeleteReminderEscalation
* test RegularisationRequest_stopInstanceTreeList
* test RegularisationRequest_deleteInstanceTreeList
* fixup RegularisationRequest_checkToSendUniqEvent tests
* fixup RegularisationRequest_checkToTriggerNextEscalationStep tests
* fixup InstanceTree_stopFromRegularisationRequest tests
* fixup InstanceTree_deleteFromRegularisationRequest tests
* drop slapos_crm_regularisation_request_template
* drop slapos_crm_web_message_template
* drop preferred_web_message_template_property
* drop slapos_ticket_trade_condition
* drop update_destination_for_slapos
* drop allocation_tester
* drop template_software_installation
* drop template_instance_tree
* drop template_member
* test: fixup person title
* test: fixup: ensure tickets can be created
* test: fixup creation of instance tree
* test: fixup instance tree creation
* test: ComputeNode_getTicketRelatedList was dropped
* test: rss feed will be used by virtual manager production
* test: ticket.approveRegistration was dropped
* ExactMatch
parent d9981cfd
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<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>action_type/object_jio_action</string>
</tuple>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_jio_action</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>slapos_user_pending_ticket_report</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>View</string>
</tuple>
</value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>50.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Send Pending Ticket Report</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/Person_viewSlapOSPendingTicketDialog</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<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>action_type/object_jio_action</string>
</tuple>
</value>
</item>
<item>
<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>
<value>
<none/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>update_destination_for_slapos</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>View</string>
</tuple>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Action Information</string> </value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>5.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Update Destination with all Slapos Users</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/SiteMessage_setSlapOSUserSourceAndDestinatationList</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>python: object.getSimulationState() in (\'draft\',)</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Web Message" 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>destination/organisation_module/slapos</string>
</tuple>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>Web-TEMPLATE</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>slapos_crm_web_message_template</string> </value>
</item>
<item>
<key> <string>language</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Web Message</string> </value>
</item>
<item>
<key> <string>start_date</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1359036420.0</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Template Web Message</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</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>edit_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>event_simulation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<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="3.1" name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global id="3.2" name="DateTime" module="DateTime.DateTime"/>
<global id="3.3" name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1359031769.94</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>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="3.1"/> </klass>
<tuple>
<reference id="3.2"/>
<reference id="3.3"/>
<none/>
</tuple>
<state>
<tuple>
<float>1359031776.9</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>924.10465.40641.49049</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="3.1"/> </klass>
<tuple>
<reference id="3.2"/>
<reference id="3.3"/>
<none/>
</tuple>
<state>
<tuple>
<float>1359031807.25</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>924.10466.8112.9318</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="3.1"/> </klass>
<tuple>
<reference id="3.2"/>
<reference id="3.3"/>
<none/>
</tuple>
<state>
<tuple>
<float>1359031829.43</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>924.10466.32280.31095</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="3.1"/> </klass>
<tuple>
<reference id="3.2"/>
<reference id="3.3"/>
<none/>
</tuple>
<state>
<tuple>
<float>1359031845.87</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>924.10466.50233.37427</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="3.1"/> </klass>
<tuple>
<reference id="3.2"/>
<reference id="3.3"/>
<none/>
</tuple>
<state>
<tuple>
<float>1359032280.41</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>924.10474.620.30208</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="3.1"/> </klass>
<tuple>
<reference id="3.2"/>
<reference id="3.3"/>
<none/>
</tuple>
<state>
<tuple>
<float>1359032348.56</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>924.10475.9470.10171</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="3.1"/> </klass>
<tuple>
<reference id="3.2"/>
<reference id="3.3"/>
<none/>
</tuple>
<state>
<tuple>
<float>1359032859.02</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>924.10483.42744.12902</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="3.1"/> </klass>
<tuple>
<reference id="3.2"/>
<reference id="3.3"/>
<none/>
</tuple>
<state>
<tuple>
<float>1359032919.02</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>937.58325.30915.36881</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="3.1"/> </klass>
<tuple>
<reference id="3.2"/>
<reference id="3.3"/>
<none/>
</tuple>
<state>
<tuple>
<float>1411993815.1</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<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>answer_portal_type</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>answer_template</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>create_event</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>respond_event_portal_type</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>respond_event_resource</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>respond_event_text_content</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>respond_event_title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>send_mail</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>simulation_state</string> </key>
<value> <string>draft</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1359031770.04</float>
<string>GMT+1</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</tuple>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Person" 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>__translation_dict</string> </key>
<value>
<dictionary/>
</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>default_reference</string> </key>
<value> <string>allocation_tester</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>first_name</string> </key>
<value> <string>Member</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>allocation_tester</string> </value>
</item>
<item>
<key> <string>last_name</string> </key>
<value> <string>Template</string> </value>
</item>
<item>
<key> <string>password</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAU=</string> </persistent>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Person</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Allocation tester</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>
<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>default</string> </key>
<value> <string>{SSHA}f1gAG3A53rfwjkLB/+Ex89MtocZz/4V9K4TZ</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -10,13 +10,17 @@ ...@@ -10,13 +10,17 @@
<key> <string>active_sense_method_id</string> </key> <key> <string>active_sense_method_id</string> </key>
<value> <string>Alarm_checkComputeNodeState</string> </value> <value> <string>Alarm_checkComputeNodeState</string> </value>
</item> </item>
<item>
<key> <string>automatic_solve</string> </key>
<value> <int>0</int> </value>
</item>
<item> <item>
<key> <string>description</string> </key> <key> <string>description</string> </key>
<value> <string>Check if a public or a friend compute_node contacted master recently and create a ticket if the compute_node stops to contact master after some time.</string> </value> <value> <string>Check if a public or a friend compute_node contacted master recently and create a ticket if the compute_node stops to contact master after some time.</string> </value>
</item> </item>
<item> <item>
<key> <string>enabled</string> </key> <key> <string>enabled</string> </key>
<value> <int>0</int> </value> <value> <int>1</int> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
</item> </item>
<item> <item>
<key> <string>enabled</string> </key> <key> <string>enabled</string> </key>
<value> <int>0</int> </value> <value> <int>1</int> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
</item> </item>
<item> <item>
<key> <string>enabled</string> </key> <key> <string>enabled</string> </key>
<value> <int>0</int> </value> <value> <int>1</int> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
......
<?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_sendPendingTicketReminder</string> </value>
</item>
<item>
<key> <string>automatic_solve</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>Send a Mail Message with a Reminder in case the user has Tickets to respond</string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>slapos_crm_send_pending_ticket_reminder</string> </value>
</item>
<item>
<key> <string>periodicity_hour</string> </key>
<value>
<tuple>
<int>6</int>
</tuple>
</value>
</item>
<item>
<key> <string>periodicity_hour_frequency</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>periodicity_minute</string> </key>
<value>
<tuple>
<int>0</int>
</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="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<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>periodicity_week_day</string> </key>
<value>
<tuple>
<string>Tuesday</string>
</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>Check compute_node\'s state</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Regularisation Request" 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>Author</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Modify_portal_content_Permission</string> </key>
<value>
<tuple>
<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>Author</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>source_section/organisation_module/slapos</string>
<string>source_trade/organisation_module/slapos</string>
<string>source/organisation_module/slapos</string>
</tuple>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>RR-TEMPLATE</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>slapos_crm_regularisation_request_template</string> </value>
</item>
<item>
<key> <string>language</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Regularisation Request</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Template Regularisation Request</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</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>edit_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>ticket_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<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="3.1" name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global id="3.2" name="DateTime" module="DateTime.DateTime"/>
<global id="3.3" name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1362477335.16</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.6675.50749.18380</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="3.1"/> </klass>
<tuple>
<reference id="3.2"/>
<reference id="3.3"/>
<none/>
</tuple>
<state>
<tuple>
<float>1362477411.34</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.6676.56132.30788</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="3.1"/> </klass>
<tuple>
<reference id="3.2"/>
<reference id="3.3"/>
<none/>
</tuple>
<state>
<tuple>
<float>1362477422.73</float>
<string>GMT+1</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<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>simulation_state</string> </key>
<value> <string>draft</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global id="4.1" name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global id="4.2" name="DateTime" module="DateTime.DateTime"/>
<global id="4.3" name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1362477335.18</float>
<string>GMT+1</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>cancel_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>simulation_state</string> </key>
<value> <string>draft</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass> <reference id="4.1"/> </klass>
<tuple>
<reference id="4.2"/>
<reference id="4.3"/>
<none/>
</tuple>
<state>
<tuple>
<float>1362477430.94</float>
<string>GMT+1</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>cancel</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>simulation_state</string> </key>
<value> <string>cancelled</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass> <reference id="4.1"/> </klass>
<tuple>
<reference id="4.2"/>
<reference id="4.3"/>
<none/>
</tuple>
<state>
<tuple>
<float>1362477430.95</float>
<string>GMT+1</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</tuple>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Sale Trade Condition" 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>_identity_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_range_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>source/organisation_module/slapos</string>
<string>source_section/organisation_module/slapos</string>
</tuple>
</value>
</item>
<item>
<key> <string>comment</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_ticket_trade_condition</string> </value>
</item>
<item>
<key> <string>language</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Sale Trade Condition</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>SlapOS Ticket Trade Condition</string> </value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>001</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/>
</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="Support Request" 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>Author</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Modify_portal_content_Permission</string> </key>
<value>
<tuple>
<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>Author</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>source_section/organisation_module/slapos</string>
<string>source_trade/organisation_module/slapos</string>
<string>source/organisation_module/slapos</string>
</tuple>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>SR-TEMPLATE</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>slapos_crm_support_request_template</string> </value>
</item>
<item>
<key> <string>language</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Support Request</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Template Support Request</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</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>edit_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>ticket_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<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="3.1" name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global id="3.2" name="DateTime" module="DateTime.DateTime"/>
<global id="3.3" name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1358438248.01</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>924.574.28012.55057</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="3.1"/> </klass>
<tuple>
<reference id="3.2"/>
<reference id="3.3"/>
<none/>
</tuple>
<state>
<tuple>
<float>1358438325.39</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>924.574.49639.23278</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="3.1"/> </klass>
<tuple>
<reference id="3.2"/>
<reference id="3.3"/>
<none/>
</tuple>
<state>
<tuple>
<float>1358438330.71</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>924.574.55464.10342</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="3.1"/> </klass>
<tuple>
<reference id="3.2"/>
<reference id="3.3"/>
<none/>
</tuple>
<state>
<tuple>
<float>1358438806.26</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>924.582.50574.51046</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="3.1"/> </klass>
<tuple>
<reference id="3.2"/>
<reference id="3.3"/>
<none/>
</tuple>
<state>
<tuple>
<float>1358438893.68</float>
<string>GMT+1</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<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>simulation_state</string> </key>
<value> <string>draft</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global id="4.1" name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global id="4.2" name="DateTime" module="DateTime.DateTime"/>
<global id="4.3" name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1358438248.02</float>
<string>GMT+1</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>cancel_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>simulation_state</string> </key>
<value> <string>draft</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass> <reference id="4.1"/> </klass>
<tuple>
<reference id="4.2"/>
<reference id="4.3"/>
<none/>
</tuple>
<state>
<tuple>
<float>1359118345.43</float>
<string>GMT+1</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>cancel</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>simulation_state</string> </key>
<value> <string>cancelled</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass> <reference id="4.1"/> </klass>
<tuple>
<reference id="4.2"/>
<reference id="4.3"/>
<none/>
</tuple>
<state>
<tuple>
<float>1359118345.44</float>
<string>GMT+1</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</tuple>
</pickle>
</record>
</ZopeData>
...@@ -5,10 +5,6 @@ ...@@ -5,10 +5,6 @@
</chain> </chain>
<chain> <chain>
<type>Regularisation Request</type> <type>Regularisation Request</type>
<workflow>edit_workflow, pricing_interaction_workflow, ticket_interaction_workflow, ticket_slap_interface_workflow, ticket_workflow</workflow> <workflow>edit_workflow, pricing_interaction_workflow, ticket_interaction_workflow, ticket_workflow</workflow>
</chain>
<chain>
<type>Support Request</type>
<workflow>ticket_slap_interface_workflow</workflow>
</chain> </chain>
</workflow_chain> </workflow_chain>
\ No newline at end of file
<?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_regularisation_request_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_support_request_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_web_message_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>
...@@ -3,24 +3,19 @@ portal = context.getPortalObject() ...@@ -3,24 +3,19 @@ portal = context.getPortalObject()
person_uid_list = [] person_uid_list = []
for (_, brain) in enumerate(portal.portal_simulation.getInventoryList( for (_, brain) in enumerate(portal.portal_simulation.getInventoryList(
simulation_state=('stopped', 'delivered'), simulation_state=('stopped', 'delivered'),
parent_payment_mode_uid = [
portal.portal_categories.payment_mode.payzen.getUid(),
portal.portal_categories.payment_mode.wechat.getUid()],
group_by_mirror_section=True, group_by_mirror_section=True,
portal_type=portal.getPortalAccountingMovementTypeList(), portal_type=portal.getPortalAccountingMovementTypeList(),
node_uid=[x.uid for x in context.Base_getReceivableAccountList()], node_uid=[x.uid for x in context.Base_getReceivableAccountList()] or -1,
grouping_reference=None)): parent__ledger__uid=portal.portal_categories.ledger.automated.getUid(),
grouping_reference=None
)):
payment_request_uid = brain.payment_request_uid section_uid = brain.getDestinationSectionUid(portal_type="Person")
if not payment_request_uid:
payment_request_uid = brain.getObject().getExplanationUid()
payment_request = portal.portal_catalog.getObject(uid=payment_request_uid)
section_uid = payment_request.getDestinationSectionUid(portal_type="Person")
if section_uid is not None: if section_uid is not None:
person_uid_list.append(section_uid) person_uid_list.append(section_uid)
portal.portal_catalog.searchAndActivate( if person_uid_list:
portal.portal_catalog.searchAndActivate(
portal_type="Person", portal_type="Person",
validation_state="validated", validation_state="validated",
uid=person_uid_list, uid=person_uid_list,
......
...@@ -3,7 +3,7 @@ sub_tag = "RegularisationRequest_stopInstanceTreeList" ...@@ -3,7 +3,7 @@ sub_tag = "RegularisationRequest_stopInstanceTreeList"
portal.portal_catalog.searchAndActivate( portal.portal_catalog.searchAndActivate(
portal_type="Regularisation Request", portal_type="Regularisation Request",
simulation_state=["suspended"], simulation_state=["suspended"],
default_resource_uid=[ resource__uid=[
portal.service_module.slapos_crm_stop_acknowledgement.getUid(), portal.service_module.slapos_crm_stop_acknowledgement.getUid(),
portal.service_module.slapos_crm_delete_reminder.getUid(), portal.service_module.slapos_crm_delete_reminder.getUid(),
portal.service_module.slapos_crm_delete_acknowledgement.getUid(), portal.service_module.slapos_crm_delete_acknowledgement.getUid(),
......
...@@ -2,7 +2,7 @@ portal = context.getPortalObject() ...@@ -2,7 +2,7 @@ portal = context.getPortalObject()
portal.portal_catalog.searchAndActivate( portal.portal_catalog.searchAndActivate(
portal_type="Regularisation Request", portal_type="Regularisation Request",
simulation_state=["suspended"], simulation_state=["suspended"],
default_resource_uid=portal.service_module.slapos_crm_acknowledgement.getUid(), resource__uid=portal.service_module.slapos_crm_acknowledgement.getUid(),
method_id='RegularisationRequest_triggerAcknowledgmentEscalation', method_id='RegularisationRequest_triggerAcknowledgmentEscalation',
activate_kw={'tag': tag} activate_kw={'tag': tag}
) )
......
...@@ -2,7 +2,7 @@ portal = context.getPortalObject() ...@@ -2,7 +2,7 @@ portal = context.getPortalObject()
portal.portal_catalog.searchAndActivate( portal.portal_catalog.searchAndActivate(
portal_type="Regularisation Request", portal_type="Regularisation Request",
simulation_state=["suspended"], simulation_state=["suspended"],
default_resource_uid=portal.service_module.slapos_crm_stop_reminder.getUid(), resource__uid=portal.service_module.slapos_crm_stop_reminder.getUid(),
method_id='RegularisationRequest_triggerStopReminderEscalation', method_id='RegularisationRequest_triggerStopReminderEscalation',
activate_kw={'tag': tag} activate_kw={'tag': tag}
) )
......
...@@ -15,7 +15,8 @@ if (slap_state in ['start_requested', 'stop_requested']): ...@@ -15,7 +15,8 @@ if (slap_state in ['start_requested', 'stop_requested']):
software_type=instance_tree.getSourceReference(), software_type=instance_tree.getSourceReference(),
instance_xml=instance_tree.getTextContent(), instance_xml=instance_tree.getTextContent(),
sla_xml=instance_tree.getSlaXml(), sla_xml=instance_tree.getSlaXml(),
shared=instance_tree.isRootSlave() shared=instance_tree.isRootSlave(),
project_reference=instance_tree.getFollowUpReference()
) )
return True return True
return False return False
...@@ -15,7 +15,8 @@ if (slap_state == 'start_requested'): ...@@ -15,7 +15,8 @@ if (slap_state == 'start_requested'):
software_type=instance_tree.getSourceReference(), software_type=instance_tree.getSourceReference(),
instance_xml=instance_tree.getTextContent(), instance_xml=instance_tree.getTextContent(),
sla_xml=instance_tree.getSlaXml(), sla_xml=instance_tree.getSlaXml(),
shared=instance_tree.isRootSlave() shared=instance_tree.isRootSlave(),
project_reference=instance_tree.getFollowUpReference()
) )
return True return True
return False return False
...@@ -16,27 +16,15 @@ ticket_portal_type = "Regularisation Request" ...@@ -16,27 +16,15 @@ ticket_portal_type = "Regularisation Request"
ticket = portal.portal_catalog.getResultValue( ticket = portal.portal_catalog.getResultValue(
portal_type=ticket_portal_type, portal_type=ticket_portal_type,
default_destination_uid=person.getUid(), destination__uid=person.getUid(),
simulation_state=['suspended', 'validated'], simulation_state=['suspended', 'validated'],
) )
if ticket is not None: if ticket is not None:
return ticket, None return ticket, None
outstanding_amount = person.Entity_statSlapOSOutstandingAmount() mail_message = None
if person.Entity_hasOutstandingAmount():
# Amount to be ignored, as it comes from the first invoice generated
# after the subscription. We do not take it into account as no service
# was provided yet.
unpaid_invoice_amount = 0
for invoice in person.Person_getSubscriptionRequestFirstUnpaidInvoiceList():
unpaid_invoice_amount += invoice.getTotalPrice()
# It can't be smaller, we are considernig all open invoices are from unpaid_payment_amount
if round(float(outstanding_amount), 2) == round(float(unpaid_invoice_amount), 2):
return ticket, None
if int(outstanding_amount) > 0:
tag = "%s_addRegularisationRequest_inProgress" % person.getUid() tag = "%s_addRegularisationRequest_inProgress" % person.getUid()
if (portal.portal_activities.countMessageWithTag(tag) > 0): if (portal.portal_activities.countMessageWithTag(tag) > 0):
# The regularisation request is already under creation but can not be fetched from catalog # The regularisation request is already under creation but can not be fetched from catalog
...@@ -47,28 +35,18 @@ if int(outstanding_amount) > 0: ...@@ -47,28 +35,18 @@ if int(outstanding_amount) > 0:
person.serialize() person.serialize()
# Time to create the ticket # Time to create the ticket
regularisation_request_template = portal.restrictedTraverse( comment = 'New automatic ticket for %s' % context.getTitle()
portal.portal_preferences.getPreferredRegularisationRequestTemplate()) ticket = context.Entity_createTicketFromTradeCondition(
ticket = regularisation_request_template.Base_createCloneDocument(batch_mode=1) portal.service_module.slapos_crm_monitoring.getRelativeUrl(),
ticket.edit( 'Account regularisation expected for "%s"' % context.getTitle(),
title='Account regularisation expected for "%s"' % context.getTitle(), '',
destination_decision_value=context, portal_type='Regularisation Request',
destination_value=context, comment=comment
start_date=DateTime(),
resource=portal.portal_preferences.getPreferredRegularisationRequestResource(),
) )
ticket.validate(comment='New automatic ticket for %s' % context.getTitle()) ticket.suspend(comment=comment)
ticket.suspend(comment='New automatic ticket for %s' % context.getTitle())
ticket.reindexObject(activate_kw={'tag': tag}) ticket.reindexObject(activate_kw={'tag': tag})
# Notify using user's language
language = context.getLanguage("en")
notification_message = context.getPortalObject().portal_notifications.getDocumentValue(
reference="slapos-crm.create.regularisation.request",
language=language)
if notification_message is None:
subject = 'Invoice payment requested' subject = 'Invoice payment requested'
body = """Dear %s, body = """Dear %s,
...@@ -78,27 +56,17 @@ You can access it in your invoice section at %s. ...@@ -78,27 +56,17 @@ You can access it in your invoice section at %s.
Regards, Regards,
The slapos team The slapos team
""" % (context.getTitle(), portal.portal_preferences.getPreferredSlaposWebSiteUrl()) """ % (context.getTitle(), portal.portal_preferences.getPreferredSlaposWebSiteUrl())
notification_message_reference = "slapos-crm.create.regularisation.request"
else:
notification_mapping_dict = {
'user_name': context.getTitle()}
subject = notification_message.getTitle()
# Preserve HTML else convert to text
if notification_message.getContentType() == "text/html":
body = notification_message.asEntireHTML(
substitution_method_parameter_dict={'mapping_dict':notification_mapping_dict})
else:
body = notification_message.asText(
substitution_method_parameter_dict={'mapping_dict':notification_mapping_dict})
mail_message = ticket.RegularisationRequest_checkToSendUniqEvent( mail_message = ticket.RegularisationRequest_checkToSendUniqEvent(
portal.portal_preferences.getPreferredRegularisationRequestResource(), portal.portal_preferences.getPreferredRegularisationRequestResource(),
subject, subject,
body, body,
'Requested manual payment.') 'Requested manual payment.',
notification_message=notification_message_reference,
return ticket, mail_message substitution_method_parameter_dict={
'user_name': context.getTitle()
},
)
return ticket, None return ticket, mail_message
portal = context.getPortalObject()
from erp5.component.module.DateUtils import addToDate
from Products.ZSQLCatalog.SQLCatalog import Query
from DateTime import DateTime
unpaid_list = []
subscription_request_list = portal.portal_catalog(
portal_type="Subscription Request",
simulation_state=["ordered", "confirmed"],
default_destination_section_uid=context.getUid(),
# Select "Subscription Request" with most likely unpaid invoices, recently generated.
creation_date=Query(creation_date=addToDate(DateTime(), to_add={'day': -20}), range="min"))
for subscription_request in subscription_request_list:
first_invoice = subscription_request.SubscriptionRequest_verifyPaymentBalanceIsReady()
if first_invoice is not None and not first_invoice.SaleInvoiceTransaction_isLettered():
unpaid_list.append(first_invoice)
return unpaid_list
...@@ -18,8 +18,8 @@ event_portal_type = "Mail Message" ...@@ -18,8 +18,8 @@ event_portal_type = "Mail Message"
event = portal.portal_catalog.getResultValue( event = portal.portal_catalog.getResultValue(
portal_type=event_portal_type, portal_type=event_portal_type,
default_resource_uid=service.getUid(), resource__uid=service.getUid(),
default_follow_up_uid=ticket.getUid(), follow_up__uid=ticket.getUid(),
) )
if (event is None) and (ticket.getSimulationState() == 'suspended'): if (event is None) and (ticket.getSimulationState() == 'suspended'):
...@@ -31,21 +31,15 @@ if (event is None) and (ticket.getSimulationState() == 'suspended'): ...@@ -31,21 +31,15 @@ if (event is None) and (ticket.getSimulationState() == 'suspended'):
# Prevent concurrent transaction to create 2 events for the same ticket # Prevent concurrent transaction to create 2 events for the same ticket
ticket.edit(resource=service_relative_url) ticket.edit(resource=service_relative_url)
event = portal.event_module.newContent( event = ticket.Ticket_createProjectEvent(
portal_type=event_portal_type, title, 'outgoing', 'Mail Message',
start_date=DateTime(), service_relative_url,
destination=ticket.getDestination(),
follow_up=ticket.getRelativeUrl(),
source=context.getSource(),
title=title,
resource=service_relative_url,
text_content=text_content, text_content=text_content,
source_project_value=ticket.getSourceProjectValue(), content_type='text/plain',
notification_message=notification_message,
substitution_method_parameter_dict=substitution_method_parameter_dict,
comment=comment
) )
event.start(send_mail=True, comment=comment)
event.stop(comment=comment)
event.deliver(comment=comment)
event.reindexObject(activate_kw={'tag': tag}) event.reindexObject(activate_kw={'tag': tag})
return event return event
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>service_relative_url, title, text_content, comment, REQUEST=None</string> </value> <value> <string>service_relative_url, title, text_content, comment, notification_message=None, substitution_method_parameter_dict=None, REQUEST=None</string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
......
...@@ -11,14 +11,16 @@ event_portal_type = "Mail Message" ...@@ -11,14 +11,16 @@ event_portal_type = "Mail Message"
event = portal.portal_catalog.getResultValue( event = portal.portal_catalog.getResultValue(
portal_type=event_portal_type, portal_type=event_portal_type,
default_resource_uid=current_service.getUid(), resource__uid=current_service.getUid(),
default_follow_up_uid=ticket.getUid(), follow_up__uid=ticket.getUid(),
simulation_state="delivered", simulation_state="delivered",
) )
if (ticket.getSimulationState() == 'suspended') and (event is not None) and (ticket.getResource() == current_service_relative_url): if (ticket.getSimulationState() == 'suspended') and (event is not None) and (ticket.getResource() == current_service_relative_url):
if (DateTime() - event.getStartDate()) > delay_period_in_days: if (DateTime() - event.getStartDate()) > delay_period_in_days:
ticket.RegularisationRequest_checkToSendUniqEvent(next_service_relative_url, title, text_content, comment) ticket.RegularisationRequest_checkToSendUniqEvent(next_service_relative_url, title, text_content, comment,
notification_message=notification_message,
substitution_method_parameter_dict=substitution_method_parameter_dict)
return event.getRelativeUrl() return event.getRelativeUrl()
return None return None
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>delay_period_in_days, current_service_relative_url, next_service_relative_url, title, text_content, comment, REQUEST=None</string> </value> <value> <string>delay_period_in_days, current_service_relative_url, next_service_relative_url, title, text_content, comment, notification_message=None, substitution_method_parameter_dict=None, REQUEST=None</string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
......
...@@ -13,7 +13,7 @@ if (state == 'suspended') and \ ...@@ -13,7 +13,7 @@ if (state == 'suspended') and \
portal.portal_catalog.searchAndActivate( portal.portal_catalog.searchAndActivate(
portal_type="Instance Tree", portal_type="Instance Tree",
validation_state=["validated"], validation_state=["validated"],
default_destination_section_uid=person.getUid(), destination_section__uid=person.getUid(),
method_id='InstanceTree_deleteFromRegularisationRequest', method_id='InstanceTree_deleteFromRegularisationRequest',
method_args=(person.getRelativeUrl(),), method_args=(person.getRelativeUrl(),),
activate_kw={'tag': tag} activate_kw={'tag': tag}
......
...@@ -8,21 +8,5 @@ if (state not in ('suspended', 'validated')) or \ ...@@ -8,21 +8,5 @@ if (state not in ('suspended', 'validated')) or \
(person is None): (person is None):
return return
outstanding_amount = person.Entity_statSlapOSOutstandingAmount() if not person.Entity_hasOutstandingAmount():
context.invalidate(comment="Automatically disabled as balance is ok")
# Amount to be ignored, as it comes from the first invoice generated
# after the subscription. We do not take it into account as no service
# was provided yet.
unpaid_invoice_amount = 0
for invoice in person.Person_getSubscriptionRequestFirstUnpaidInvoiceList():
unpaid_invoice_amount += invoice.getTotalPrice()
# It can't be smaller, we are considernig all open invoices are from unpaid_payment_amount
if round(float(outstanding_amount), 2) == round(float(unpaid_invoice_amount), 2):
context.invalidate(comment="Automatically disabled as balance is %s" % outstanding_amount)
return
if (int(outstanding_amount) > 0):
return
context.invalidate(comment="Automatically disabled as balance is %s" % outstanding_amount)
...@@ -13,7 +13,7 @@ if (state == 'suspended') and \ ...@@ -13,7 +13,7 @@ if (state == 'suspended') and \
portal.portal_catalog.searchAndActivate( portal.portal_catalog.searchAndActivate(
portal_type="Instance Tree", portal_type="Instance Tree",
validation_state=["validated"], validation_state=["validated"],
default_destination_section_uid=person.getUid(), destination_section__uid=person.getUid(),
method_id='InstanceTree_stopFromRegularisationRequest', method_id='InstanceTree_stopFromRegularisationRequest',
method_args=(person.getRelativeUrl(),), method_args=(person.getRelativeUrl(),),
activate_kw={'tag': tag} activate_kw={'tag': tag}
......
...@@ -2,19 +2,10 @@ from zExceptions import Unauthorized ...@@ -2,19 +2,10 @@ from zExceptions import Unauthorized
if REQUEST is not None: if REQUEST is not None:
raise Unauthorized raise Unauthorized
portal = context.getPortalObject()
ndays = 15 ndays = 15
language = "en"
recipient = context.getDestinationSectionValue()
if recipient is not None:
language = recipient.getLanguage("en")
notification_message = portal.portal_notifications.getDocumentValue( subject = 'Reminder: invoice payment requested'
language=language, reference="slapos-crm.acknowledgment.escalation") body = """Dear user,
if notification_message is None:
subject = 'Reminder: invoice payment requested'
body = """Dear user,
We would like to remind you the unpaid invoice you have on %s. We would like to remind you the unpaid invoice you have on %s.
If no payment is done during the coming days, we will stop all your current instances to free some hardware resources. If no payment is done during the coming days, we will stop all your current instances to free some hardware resources.
...@@ -23,21 +14,6 @@ Regards, ...@@ -23,21 +14,6 @@ Regards,
The slapos team The slapos team
""" % context.getPortalObject().portal_preferences.getPreferredSlaposWebSiteUrl() """ % context.getPortalObject().portal_preferences.getPreferredSlaposWebSiteUrl()
else:
notification_mapping_dict = {
'user_name': context.getDestinationSectionTitle(),
'days': ndays}
subject = notification_message.getTitle()
# Preserve HTML else convert to text
if notification_message.getContentType() == "text/html":
body = notification_message.asEntireHTML(
substitution_method_parameter_dict={'mapping_dict':notification_mapping_dict})
else:
body = notification_message.asText(
substitution_method_parameter_dict={'mapping_dict':notification_mapping_dict})
return context.RegularisationRequest_checkToTriggerNextEscalationStep( return context.RegularisationRequest_checkToTriggerNextEscalationStep(
delay_period_in_days=ndays, delay_period_in_days=ndays,
current_service_relative_url='service_module/slapos_crm_acknowledgement', current_service_relative_url='service_module/slapos_crm_acknowledgement',
...@@ -45,4 +21,9 @@ return context.RegularisationRequest_checkToTriggerNextEscalationStep( ...@@ -45,4 +21,9 @@ return context.RegularisationRequest_checkToTriggerNextEscalationStep(
title=subject, title=subject,
text_content=body, text_content=body,
comment='Stopping reminder.', comment='Stopping reminder.',
notification_message="slapos-crm.acknowledgment.escalation",
substitution_method_parameter_dict={
'user_name': context.getDestinationSectionTitle(),
'days': ndays
}
) )
...@@ -2,19 +2,10 @@ from zExceptions import Unauthorized ...@@ -2,19 +2,10 @@ from zExceptions import Unauthorized
if REQUEST is not None: if REQUEST is not None:
raise Unauthorized raise Unauthorized
portal = context.getPortalObject()
ndays = 10 ndays = 10
language = "en"
recipient = context.getDestinationSectionValue()
if recipient is not None:
language = recipient.getLanguage("en")
notification_message = portal.portal_notifications.getDocumentValue( subject = 'Acknowledgment: instances deleted'
language=language, reference="slapos-crm.delete.reminder.escalation") body = """Dear user,
if notification_message is None:
subject = 'Acknowledgment: instances deleted'
body = """Dear user,
Despite our last reminder, you still have an unpaid invoice on %s. Despite our last reminder, you still have an unpaid invoice on %s.
We will now delete all your instances. We will now delete all your instances.
...@@ -22,20 +13,6 @@ We will now delete all your instances. ...@@ -22,20 +13,6 @@ We will now delete all your instances.
Regards, Regards,
The slapos team The slapos team
""" % context.getPortalObject().portal_preferences.getPreferredSlaposWebSiteUrl() """ % context.getPortalObject().portal_preferences.getPreferredSlaposWebSiteUrl()
else:
notification_mapping_dict = {
'user_name': context.getDestinationSectionTitle(),
'days': ndays}
subject = notification_message.getTitle()
# Preserve HTML else convert to text
if notification_message.getContentType() == "text/html":
body = notification_message.asEntireHTML(
substitution_method_parameter_dict={'mapping_dict':notification_mapping_dict})
else:
body = notification_message.asText(
substitution_method_parameter_dict={'mapping_dict':notification_mapping_dict})
return context.RegularisationRequest_checkToTriggerNextEscalationStep( return context.RegularisationRequest_checkToTriggerNextEscalationStep(
delay_period_in_days=ndays, delay_period_in_days=ndays,
...@@ -44,4 +21,9 @@ return context.RegularisationRequest_checkToTriggerNextEscalationStep( ...@@ -44,4 +21,9 @@ return context.RegularisationRequest_checkToTriggerNextEscalationStep(
title=subject, title=subject,
text_content=body, text_content=body,
comment='Deleting acknowledgment.', comment='Deleting acknowledgment.',
notification_message="slapos-crm.delete.reminder.escalation",
substitution_method_parameter_dict={
'user_name': context.getDestinationSectionTitle(),
'days': ndays
}
) )
...@@ -2,19 +2,9 @@ from zExceptions import Unauthorized ...@@ -2,19 +2,9 @@ from zExceptions import Unauthorized
if REQUEST is not None: if REQUEST is not None:
raise Unauthorized raise Unauthorized
portal = context.getPortalObject()
ndays = 7 ndays = 7
language = "en" subject = 'Last reminder: invoice payment requested'
recipient = context.getDestinationSectionValue() body = """Dear user,
if recipient is not None:
language = recipient.getLanguage("en")
notification_message = portal.portal_notifications.getDocumentValue(
language=language, reference="slapos-crm.stop.acknowledgment.escalation")
if notification_message is None:
subject = 'Last reminder: invoice payment requested'
body = """Dear user,
We would like to remind you the unpaid invoice you have on %s. We would like to remind you the unpaid invoice you have on %s.
If no payment is done during the coming days, we will delete all your instances. If no payment is done during the coming days, we will delete all your instances.
...@@ -22,20 +12,6 @@ If no payment is done during the coming days, we will delete all your instances. ...@@ -22,20 +12,6 @@ If no payment is done during the coming days, we will delete all your instances.
Regards, Regards,
The slapos team The slapos team
""" % context.getPortalObject().portal_preferences.getPreferredSlaposWebSiteUrl() """ % context.getPortalObject().portal_preferences.getPreferredSlaposWebSiteUrl()
else:
notification_mapping_dict = {
'user_name': context.getDestinationSectionTitle(),
'days': ndays}
subject = notification_message.getTitle()
# Preserve HTML else convert to text
if notification_message.getContentType() == "text/html":
body = notification_message.asEntireHTML(
substitution_method_parameter_dict={'mapping_dict':notification_mapping_dict})
else:
body = notification_message.asText(
substitution_method_parameter_dict={'mapping_dict':notification_mapping_dict})
return context.RegularisationRequest_checkToTriggerNextEscalationStep( return context.RegularisationRequest_checkToTriggerNextEscalationStep(
delay_period_in_days=ndays, delay_period_in_days=ndays,
...@@ -44,4 +20,9 @@ return context.RegularisationRequest_checkToTriggerNextEscalationStep( ...@@ -44,4 +20,9 @@ return context.RegularisationRequest_checkToTriggerNextEscalationStep(
title=subject, title=subject,
text_content=body, text_content=body,
comment='Deleting reminder.', comment='Deleting reminder.',
notification_message="slapos-crm.stop.acknowledgment.escalation",
substitution_method_parameter_dict={
'user_name': context.getDestinationSectionTitle(),
'days': ndays
}
) )
...@@ -2,19 +2,10 @@ from zExceptions import Unauthorized ...@@ -2,19 +2,10 @@ from zExceptions import Unauthorized
if REQUEST is not None: if REQUEST is not None:
raise Unauthorized raise Unauthorized
portal = context.getPortalObject()
ndays = 7 ndays = 7
language = "en"
recipient = context.getDestinationSectionValue()
if recipient is not None:
language = recipient.getLanguage("en")
notification_message = portal.portal_notifications.getDocumentValue( subject = 'Acknowledgment: instances stopped'
language=language, reference="slapos-crm.stop.reminder.escalation") body = """Dear user,
if notification_message is None:
subject = 'Acknowledgment: instances stopped'
body = """Dear user,
Despite our last reminder, you still have an unpaid invoice on %s. Despite our last reminder, you still have an unpaid invoice on %s.
We will now stop all your current instances to free some hardware resources. We will now stop all your current instances to free some hardware resources.
...@@ -22,20 +13,6 @@ We will now stop all your current instances to free some hardware resources. ...@@ -22,20 +13,6 @@ We will now stop all your current instances to free some hardware resources.
Regards, Regards,
The slapos team The slapos team
""" % context.getPortalObject().portal_preferences.getPreferredSlaposWebSiteUrl() """ % context.getPortalObject().portal_preferences.getPreferredSlaposWebSiteUrl()
else:
notification_mapping_dict = {
'user_name': context.getDestinationSectionTitle(),
'days': ndays}
subject = notification_message.getTitle()
# Preserve HTML else convert to text
if notification_message.getContentType() == "text/html":
body = notification_message.asEntireHTML(
substitution_method_parameter_dict={'mapping_dict':notification_mapping_dict})
else:
body = notification_message.asText(
substitution_method_parameter_dict={'mapping_dict':notification_mapping_dict})
return context.RegularisationRequest_checkToTriggerNextEscalationStep( return context.RegularisationRequest_checkToTriggerNextEscalationStep(
delay_period_in_days=ndays, delay_period_in_days=ndays,
...@@ -44,4 +21,9 @@ return context.RegularisationRequest_checkToTriggerNextEscalationStep( ...@@ -44,4 +21,9 @@ return context.RegularisationRequest_checkToTriggerNextEscalationStep(
title=subject, title=subject,
text_content=body, text_content=body,
comment='Stopping acknowledgment.', comment='Stopping acknowledgment.',
notification_message="slapos-crm.stop.reminder.escalation",
substitution_method_parameter_dict={
'user_name': context.getDestinationSectionTitle(),
'days': ndays
}
) )
...@@ -9,11 +9,11 @@ monitor_enabled_category = portal.restrictedTraverse( ...@@ -9,11 +9,11 @@ monitor_enabled_category = portal.restrictedTraverse(
if monitor_enabled_category is not None: if monitor_enabled_category is not None:
portal.portal_catalog.searchAndActivate( portal.portal_catalog.searchAndActivate(
portal_type = 'Compute Node', portal_type='Compute Node',
validation_state = 'validated', validation_state='validated',
default_monitor_scope_uid = monitor_enabled_category.getUid(), monitor_scope__uid=monitor_enabled_category.getUid(),
method_id = 'ComputeNode_checkState', method_id='ComputeNode_checkState',
activate_kw = {'tag':tag} activate_kw={'tag':tag}
) )
context.activate(after_tag=tag).getId() context.activate(after_tag=tag).getId()
...@@ -9,11 +9,11 @@ monitor_enabled_category = portal.restrictedTraverse( ...@@ -9,11 +9,11 @@ monitor_enabled_category = portal.restrictedTraverse(
if monitor_enabled_category is not None: if monitor_enabled_category is not None:
portal.portal_catalog.searchAndActivate( portal.portal_catalog.searchAndActivate(
portal_type = 'Compute Node', portal_type='Compute Node',
validation_state = 'validated', validation_state='validated',
default_monitor_scope_uid = monitor_enabled_category.getUid(), monitor_scope__uid=monitor_enabled_category.getUid(),
method_id = 'ComputeNode_checkSoftwareInstallationState', method_id='ComputeNode_checkSoftwareInstallationState',
activate_kw = {'tag':tag} activate_kw={'tag':tag}
) )
context.activate(after_tag=tag).getId() context.activate(after_tag=tag).getId()
portal = context.getPortalObject()
portal.portal_catalog.searchAndActivate(
portal_type = 'Person',
method_id = 'Person_sendPendingTicketReminder',
activate_kw = {'tag':tag}
)
context.activate(after_tag=tag).getId()
<?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>tag, fixit, params</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Alarm_sendPendingTicketReminder</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -4,10 +4,10 @@ default_resource_uid = portal.restrictedTraverse("service_module/slapos_crm_moni ...@@ -4,10 +4,10 @@ default_resource_uid = portal.restrictedTraverse("service_module/slapos_crm_moni
portal.portal_catalog.searchAndActivate( portal.portal_catalog.searchAndActivate(
portal_type='Support Request', portal_type='Support Request',
simulation_state=['validated', 'suspended'], simulation_state=['validated', 'suspended'],
default_resource_uid=default_resource_uid, resource__uid=default_resource_uid,
default_aggregate_portal_type=["Instance Tree"], aggregate__portal_type=["Instance Tree"],
method_id='SupportRequest_updateMonitoringState', method_id='SupportRequest_updateMonitoringState',
activate_kw = {'tag':tag} activate_kw={'tag':tag}
) )
context.activate(after_tag=tag).getId() context.activate(after_tag=tag).getId()
from DateTime import DateTime from DateTime import DateTime
portal = context.getPortalObject() portal = context.getPortalObject()
if context.getMonitorScope() == "disabled" or \ if (context.getMonitorScope() == "disabled") or \
portal.ERP5Site_isSupportRequestCreationClosed(): portal.ERP5Site_isSupportRequestCreationClosed():
return return
software_installation_list = portal.portal_catalog( software_installation_list = portal.portal_catalog(
portal_type='Software Installation', portal_type='Software Installation',
default_aggregate_uid=context.getUid(), aggregate__uid=context.getUid(),
validation_state='validated', validation_state='validated',
sort_on=(('creation_date', 'DESC'),) sort_on=(('creation_date', 'DESC'),)
) )
...@@ -24,15 +24,20 @@ for software_installation in software_installation_list: ...@@ -24,15 +24,20 @@ for software_installation in software_installation_list:
# Give it 12 hours to deploy. # Give it 12 hours to deploy.
continue continue
if software_installation.getSlapState() != 'start_requested':
continue
reference = software_installation.getReference() reference = software_installation.getReference()
d = software_installation.getAccessStatus() d = software_installation.getAccessStatus()
if d.get("no_data", None) == 1: if d.get("no_data", None) == 1:
should_notify = True
last_contact = "No Contact Information"
ticket_title = "[MONITORING] No information for %s on %s" % (reference, compute_node_reference) ticket_title = "[MONITORING] No information for %s on %s" % (reference, compute_node_reference)
description = "The software release %s did not started to build on %s since %s" % \ description = "The software release %s did not started to build on %s since %s" % \
(software_installation.getUrlString(), compute_node_title, software_installation.getCreationDate()) (software_installation.getUrlString(), compute_node_title, software_installation.getCreationDate())
else: else:
last_contact = DateTime(d.get('created_at')) last_contact = DateTime(d.get('created_at'))
if d.get("text").startswith("building"): if d.get("text").startswith("#building"):
should_notify = True should_notify = True
ticket_title = "[MONITORING] %s is building for too long on %s" % (reference, compute_node_reference) ticket_title = "[MONITORING] %s is building for too long on %s" % (reference, compute_node_reference)
description = "The software release %s is building for mode them 12 hours on %s, started on %s" % \ description = "The software release %s is building for mode them 12 hours on %s, started on %s" % \
...@@ -48,42 +53,33 @@ for software_installation in software_installation_list: ...@@ -48,42 +53,33 @@ for software_installation in software_installation_list:
if should_notify: if should_notify:
support_request = person.Base_getSupportRequestInProgress( project = context.getFollowUpValue()
title=ticket_title, support_request = project.Project_createSupportRequestWithCausality(
aggregate=context.getRelativeUrl()) ticket_title,
description,
if support_request is None: causality=context.getRelativeUrl(),
person.notify(support_request_title=ticket_title, destination_decision=project.getDestination()
support_request_description=description, )
aggregate=context.getRelativeUrl())
support_request_relative_url = context.REQUEST.get("support_request_relative_url")
if support_request_relative_url is None:
return
support_request = portal.restrictedTraverse(support_request_relative_url)
if support_request is None: if support_request is None:
return return
# Send Notification message notification_message_reference = 'slapos-crm-compute_node_software_installation_state.notification'
notification_reference = 'slapos-crm-compute_node_software_installation_state.notification'
notification_message = portal.portal_notifications.getDocumentValue(
reference=notification_reference)
if notification_message is None:
message = """%s""" % description
else:
mapping_dict = {'compute_node_title':context.getTitle(),
'compute_node_id':reference,
'last_contact':last_contact}
message = notification_message.asText(
substitution_method_parameter_dict={'mapping_dict':mapping_dict})
event = support_request.SupportRequest_getLastEvent(ticket_title) event = support_request.SupportRequest_getLastEvent(ticket_title)
if event is None: if event is None:
support_request.notify(message_title=ticket_title, message=message) support_request.Ticket_createProjectEvent(
ticket_title, 'outgoing', 'Web Message',
portal.service_module.slapos_crm_information.getRelativeUrl(),
text_content=description,
content_type='text/plain',
notification_message=notification_message_reference,
#language=XXX,
substitution_method_parameter_dict={
'compute_node_title':context.getTitle(),
'compute_node_id':reference,
'last_contact':last_contact
}
)
support_request_list.append(support_request) support_request_list.append(support_request)
......
from DateTime import DateTime from DateTime import DateTime
portal = context.getPortalObject() portal = context.getPortalObject()
if context.getMonitorScope() == "disabled" or \ if (context.getMonitorScope() == "disabled") or \
portal.ERP5Site_isSupportRequestCreationClosed(): portal.ERP5Site_isSupportRequestCreationClosed():
return return
...@@ -54,7 +54,7 @@ if not should_notify: ...@@ -54,7 +54,7 @@ if not should_notify:
if compute_partition_uid_list: if compute_partition_uid_list:
instance_list = portal.portal_catalog( instance_list = portal.portal_catalog(
portal_type='Software Instance', portal_type='Software Instance',
default_aggregate_uid=compute_partition_uid_list) aggregate__uid=compute_partition_uid_list)
if instance_list: if instance_list:
should_notify = True should_notify = True
...@@ -76,45 +76,36 @@ if not should_notify: ...@@ -76,45 +76,36 @@ if not should_notify:
context.getTitle(), context.getReference(), last_contact) context.getTitle(), context.getReference(), last_contact)
if should_notify: if should_notify:
support_request = person.Base_getSupportRequestInProgress( support_request = context.Base_getSupportRequestInProgress(
title=node_ticket_title, title=node_ticket_title)
aggregate=context.getRelativeUrl())
if support_request is None: if support_request is None:
support_request = person.Base_getSupportRequestInProgress( project = context.getFollowUpValue()
title=ticket_title, support_request = project.Project_createSupportRequestWithCausality(
aggregate=context.getRelativeUrl()) ticket_title,
description,
if support_request is None: causality=context.getRelativeUrl(),
person.notify(support_request_title=ticket_title, destination_decision=project.getDestination()
support_request_description=description, )
aggregate=context.getRelativeUrl())
support_request_relative_url = context.REQUEST.get("support_request_relative_url")
if support_request_relative_url is None:
return
support_request = portal.restrictedTraverse(support_request_relative_url)
if support_request is None: if support_request is None:
return return
# Send Notification message
notification_message = portal.portal_notifications.getDocumentValue(
reference=notification_message_reference)
if notification_message is None:
message = """%s""" % description
else:
mapping_dict = {'compute_node_title':context.getTitle(),
'compute_node_id':reference,
'last_contact':last_contact,
'issue_document_reference': issue_document_reference}
message = notification_message.asText(
substitution_method_parameter_dict={'mapping_dict': mapping_dict})
event = support_request.SupportRequest_getLastEvent(ticket_title) event = support_request.SupportRequest_getLastEvent(ticket_title)
if event is None: if event is None:
support_request.notify(message_title=ticket_title, message=message) support_request.Ticket_createProjectEvent(
ticket_title, 'outgoing', 'Web Message',
portal.service_module.slapos_crm_information.getRelativeUrl(),
text_content=description,
content_type='text/plain',
notification_message=notification_message_reference,
#language=XXX,
substitution_method_parameter_dict={
'compute_node_title':context.getTitle(),
'compute_node_id':reference,
'last_contact':last_contact,
'issue_document_reference': issue_document_reference
}
)
return support_request return support_request
portal = context.getPortalObject()
compute_node = context compute_node = context
now_date = DateTime() now_date = DateTime()
...@@ -15,13 +14,4 @@ if message_dict.has_key('created_at'): ...@@ -15,13 +14,4 @@ if message_dict.has_key('created_at'):
contact_date = DateTime(message_dict.get('created_at').encode('utf-8')) contact_date = DateTime(message_dict.get('created_at').encode('utf-8'))
return (now_date - contact_date) < maximum_days return (now_date - contact_date) < maximum_days
# If no access status information, check in consumption report
for sale_packing_list in portal.portal_catalog(
portal_type="Sale Packing List Line",
simulation_state="delivered",
default_aggregate_uid=compute_node.getUid(),
sort_on=[('movement.start_date', 'DESC')],
limit=1):
return (now_date - sale_packing_list.getStartDate()) < maximum_days
return False return False
...@@ -96,14 +96,17 @@ ...@@ -96,14 +96,17 @@
<key> <string>left</string> </key> <key> <string>left</string> </key>
<value> <value>
<list> <list>
<string>my_monitor_scope</string> <string>my_title</string>
<string>my_reference</string>
</list> </list>
</value> </value>
</item> </item>
<item> <item>
<key> <string>right</string> </key> <key> <string>right</string> </key>
<value> <value>
<list/> <list>
<string>my_monitor_scope</string>
</list>
</value> </value>
</item> </item>
</dictionary> </dictionary>
......
...@@ -2,19 +2,20 @@ from Products.ERP5Type.Cache import CachingMethod ...@@ -2,19 +2,20 @@ from Products.ERP5Type.Cache import CachingMethod
portal = context.getPortalObject() portal = context.getPortalObject()
def isSupportRequestCreationClosed(destination_decision=None): def isSupportRequestCreationClosed(destination_decision=None):
limit = portal.portal_preferences.getPreferredSupportRequestCreationLimit(5) limit = int(portal.portal_preferences.getPreferredSupportRequestCreationLimit(5))
kw = {} kw = {
kw['limit'] = limit 'limit': limit,
kw['portal_type'] = 'Support Request' 'portal_type': 'Support Request',
kw['simulation_state'] = ["validated","submitted"] 'simulation_state': ["validated", "submitted"],
kw['default_resource_uid'] = portal.service_module.slapos_crm_monitoring.getUid() 'resource__uid': portal.service_module.slapos_crm_monitoring.getUid()
}
if destination_decision: if destination_decision:
kw['default_destination_decision_uid'] = context.restrictedTraverse( kw['destination_decision__uid'] = context.restrictedTraverse(
destination_decision).getUid() destination_decision).getUid()
support_request_amount = context.portal_catalog.countResults(**kw)[0][0] support_request_amount_list = context.portal_catalog(**kw)
return support_request_amount >= int(limit) return limit <= len(support_request_amount_list)
return CachingMethod(isSupportRequestCreationClosed, return CachingMethod(isSupportRequestCreationClosed,
......
portal = context.getPortalObject()
destination_decision_value = context
# Create a temp Sale Order to find the trade condition
now = DateTime()
module = portal.portal_trash
tmp_sale_order = module.newContent(
portal_type='Sale Order',
temp_object=True,
trade_condition_type="ticket",
start_date=now,
destination_value=destination_decision_value,
destination_decision_value=destination_decision_value,
source_project=source_project,
ledger_value=portal.portal_categories.ledger.automated
)
tmp_sale_order.SaleOrder_applySaleTradeCondition(batch_mode=1, force=1)
"""
if tmp_sale_order.getSpecialise(None) is None:
raise AssertionError('Can not find a trade condition to generate the Support Request')
"""
resource = portal.restrictedTraverse(resource)
ticket = portal.getDefaultModule(portal_type).newContent(
portal_type=portal_type,
title=title,
description=text_content,
start_date=tmp_sale_order.getStartDate(),
source=tmp_sale_order.getSource(),
source_section=tmp_sale_order.getSourceSection(),
source_project=tmp_sale_order.getSourceProject(),
destination=tmp_sale_order.getDestination(),
destination_section=tmp_sale_order.getDestinationSection(),
destination_project=tmp_sale_order.getDestinationProject(),
destination_decision=tmp_sale_order.getDestinationDecision(),
specialise=tmp_sale_order.getSpecialise(),
causality=causality,
# Ensure resoure is Monitoring
resource_value=resource,
quantity_unit=resource.getQuantityUnit(),
base_contribution_list=resource.getBaseContributionList(),
use=resource.getUse(),
quantity=1,
price=0
)
ticket.validate(comment=comment)
return ticket
...@@ -50,11 +50,11 @@ ...@@ -50,11 +50,11 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string></string> </value> <value> <string>resource, title, text_content, portal_type=\'Support Request\', source_project=None, causality=None, comment=None</string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>Person_getSubscriptionRequestFirstUnpaidInvoiceList</string> </value> <value> <string>Entity_createTicketFromTradeCondition</string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
...@@ -4,10 +4,6 @@ from erp5.component.module.DateUtils import addToDate ...@@ -4,10 +4,6 @@ from erp5.component.module.DateUtils import addToDate
instance_tree = context instance_tree = context
portal = context.getPortalObject() portal = context.getPortalObject()
if instance_tree.getMonitorScope() == "disabled":
# Don't generate ticket if Monitor Scope is marked to disable
return
if portal.ERP5Site_isSupportRequestCreationClosed(): if portal.ERP5Site_isSupportRequestCreationClosed():
# Stop ticket creation # Stop ticket creation
return return
...@@ -20,14 +16,11 @@ if (date_check_limit - instance_tree.getCreationDate()) < 0: ...@@ -20,14 +16,11 @@ if (date_check_limit - instance_tree.getCreationDate()) < 0:
software_instance_list = context.portal_catalog( software_instance_list = context.portal_catalog(
portal_type=["Software Instance", "Slave Instance"], portal_type=["Software Instance", "Slave Instance"],
specialise_uid=instance_tree.getUid(), specialise__uid=instance_tree.getUid(),
**{"slapos_item.slap_state": ["start_requested"]}) **{"slapos_item.slap_state": ["start_requested"]})
has_newest_allocated_instance = False
has_unallocated_instance = False
failing_instance = None
# Check if at least one software Instance is Allocated # Check if at least one software Instance is Allocated
notification_message_reference = None
for instance in software_instance_list: for instance in software_instance_list:
if (date_check_limit - instance.getCreationDate()) < 0: if (date_check_limit - instance.getCreationDate()) < 0:
continue continue
...@@ -36,19 +29,48 @@ for instance in software_instance_list: ...@@ -36,19 +29,48 @@ for instance in software_instance_list:
continue continue
compute_partition = instance.getAggregateValue() compute_partition = instance.getAggregateValue()
if compute_partition is not None: if compute_partition is None:
has_newest_allocated_instance = True notification_message_reference = 'slapos-crm-instance-tree-instance-allocation.notification'
if instance.getPortalType() == "Software Instance" and \ elif (instance.getPortalType() == "Software Instance") and \
compute_partition.getParentValue().getMonitorScope() == "enabled" and \ (compute_partition.getParentValue().getMonitorScope() == "enabled") and \
instance.SoftwareInstance_hasReportedError(tolerance=30): instance.SoftwareInstance_hasReportedError(tolerance=30):
return context.InstanceTree_createSupportRequestEvent(
instance, 'slapos-crm-instance-tree-instance-state.notification') notification_message_reference = 'slapos-crm-instance-tree-instance-state.notification'
if notification_message_reference is not None:
ticket_title = "Instance Tree %s is failing." % context.getTitle()
error_message = instance.SoftwareInstance_hasReportedError(include_message=True)
description = "%s contains software instances which are unallocated or reporting errors." % (
context.getTitle())
if error_message:
description += "\n\nMessage: %s" % str(error_message)
else: else:
has_unallocated_instance = True error_message = "No message!"
failing_instance = instance
if has_unallocated_instance and has_newest_allocated_instance: project = context.getFollowUpValue()
return context.InstanceTree_createSupportRequestEvent( support_request = project.Project_createSupportRequestWithCausality(
failing_instance, 'slapos-crm-instance-tree-instance-allocation.notification') ticket_title,
description,
causality=context.getRelativeUrl(),
destination_decision=context.getDestinationSectionValue()
)
if support_request is None:
return
return event = support_request.SupportRequest_getLastEvent(ticket_title)
if event is None:
support_request.Ticket_createProjectEvent(
ticket_title, 'outgoing', 'Web Message',
portal.service_module.slapos_crm_information.getRelativeUrl(),
text_content=description,
content_type='text/plain',
notification_message=notification_message_reference,
#language=XXX,
substitution_method_parameter_dict={
'instance_tree_title':context.getTitle(),
'instance': instance.getTitle(),
'error_text': error_message
}
)
return
portal = context.getPortalObject()
person = context.getDestinationSectionValue()
if person is None or portal.ERP5Site_isSupportRequestCreationClosed(person.getRelativeUrl()):
# Stop ticket creation
return
ticket_title = "Instance Tree %s is failing." % context.getTitle()
error_message = instance.SoftwareInstance_hasReportedError(include_message=True)
description = "%s contains software instances which are unallocated or reporting errors." % (
context.getTitle())
if error_message:
description += "\n\nMessage: %s" % error_message
else:
error_message = "No message!"
support_request = person.Base_getSupportRequestInProgress(
title=ticket_title,
aggregate=context.getRelativeUrl())
if support_request is None:
person.notify(support_request_title=ticket_title,
support_request_description=description,
aggregate=context.getRelativeUrl())
support_request_relative_url = context.REQUEST.get("support_request_relative_url")
if support_request_relative_url is None:
return
support_request = portal.restrictedTraverse(support_request_relative_url)
if support_request is None:
return
if support_request.getSimulationState() not in ["validated", "suspended"]:
support_request.validate()
# Send Notification message
message = description
notification_message = portal.portal_notifications.getDocumentValue(
reference=notification_message_reference)
if notification_message is not None:
mapping_dict = {'instance_tree_title':context.getTitle(),
'instance': instance.getTitle(),
'error_text': error_message}
message = notification_message.asText(
substitution_method_parameter_dict={'mapping_dict':mapping_dict})
event = support_request.SupportRequest_getLastEvent(ticket_title)
if event is None:
support_request.notify(message_title=ticket_title, message=message)
return context.REQUEST.get("ticket_notified_item")
from Products.ZSQLCatalog.SQLCatalog import ComplexQuery, SimpleQuery
portal = context.getPortalObject()
person_uid = context.getUid()
query = ComplexQuery(
ComplexQuery(
SimpleQuery(portal_type=["Support Request", "Regularisation Request"]),
SimpleQuery(simulation_state="suspended"),
SimpleQuery(destination_decision_uid=person_uid),
logical_operator='and'),
ComplexQuery(
SimpleQuery(portal_type="Upgrade Decision"),
SimpleQuery(simulation_state="confirmed"),
SimpleQuery(destination_decision_uid=person_uid),
logical_operator='and'),
logical_operator='or')
return portal.portal_catalog(query=query, **kw)
portal = context.getPortalObject()
pending_ticket_list_amount = len(context.Person_getSlapOSPendingTicket())
notification_message = portal.portal_notifications.getDocumentValue(
reference="slapos-crm-person-pending-ticket-notification")
if notification_message is not None:
mapping_dict = {'username': context.getTitle(),
'amount': pending_ticket_list_amount,
'website': portal.portal_preferences.getPreferredSlaposWebSiteUrl()}
return notification_message.getTitle(), notification_message.asText(
substitution_method_parameter_dict={'mapping_dict': mapping_dict})
message = """ You have %s pending tickets """ % pending_ticket_list_amount
return message, message
<?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></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Person_getSlapOSPendingTicketMessageTemplate</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
amount = len(context.Person_getSlapOSPendingTicket())
if amount > 0:
title, reminder_message = context.Person_getSlapOSPendingTicketMessageTemplate()
return context.Person_sendSlapOSPendingTicketNotification(
title,
reminder_message,
batch_mode=1
)
<?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></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Person_sendPendingTicketReminder</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
portal = context.getPortalObject()
start_date = DateTime()
# Rely on Trade condition (like in ticket to set the proper sender)
trade_condition = portal.sale_trade_condition_module.slapos_ticket_trade_condition
event_kw = {
'portal_type' : "Mail Message",
'title' : response_event_title,
'resource' : "service_module/slapos_crm_information",
'source' : trade_condition.getSource(),
'destination' : context.getRelativeUrl(),
'start_date' : start_date,
'text_content' : response_event_text_content,
'content_type' : 'text/plain',
}
# Create event
event = portal.event_module.newContent(**event_kw)
event.start(send_mail=True, comment="Sent via Person_sendSlapOSPendingTicketNotification")
if batch_mode:
return event
message = portal.Base_translateString('New event created.')
return event.Base_redirect(keep_items={'portal_status_message': message})
<?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>response_event_title, response_event_text_content, batch_mode=False, **kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Person_sendSlapOSPendingTicketNotification</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?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>_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/>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>action</string> </key>
<value> <string>Person_sendSlapOSPendingTicketNotification</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>listbox</string>
</list>
</value>
</item>
<item>
<key> <string>center</string> </key>
<value>
<list>
<string>your_response_event_title</string>
<string>your_response_event_text_content</string>
</list>
</value>
</item>
<item>
<key> <string>hidden</string> </key>
<value>
<list>
<string>listbox_delivery_start_date</string>
</list>
</value>
</item>
<item>
<key> <string>left</string> </key>
<value>
<list>
<string>my_title</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>Person_viewSlapOSPendingTicketDialog</string> </value>
</item>
<item>
<key> <string>method</string> </key>
<value> <string>POST</string> </value>
</item>
<item>
<key> <string>name</string> </key>
<value> <string>Person_viewSlapOSPendingTicket</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>Send Pending Ticket Report</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>description</string>
<string>editable</string>
<string>editable_columns</string>
<string>list_method</string>
<string>portal_types</string>
<string>selection_name</string>
<string>sort</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>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>
<item>
<key> <string>target</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>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable_columns</string> </key>
<value> <string></string> </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>selection_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>sort</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</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>getTitle</string>
<string>Title</string>
</tuple>
<tuple>
<string>translated_portal_type</string>
<string>Event Type</string>
</tuple>
<tuple>
<string>delivery.start_date</string>
<string>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/>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>List of all Support Requests related to the follow up ticket</string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>editable_columns</string> </key>
<value>
<list>
<tuple>
<string>delivery.start_date</string>
<string>Date</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">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>portal_types</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>selection_name</string> </key>
<value> <string>person_pending_ticket_view_selection</string> </value>
</item>
<item>
<key> <string>sort</string> </key>
<value>
<list>
<tuple>
<string>delivery.start_date</string>
<string>asc</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Tickets</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Method" module="Products.Formulator.MethodField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>method_name</string> </key>
<value> <string>Person_getSlapOSPendingTicket</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="DateTimeField" module="Products.Formulator.StandardFields"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>listbox_delivery_start_date</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>datetime_out_of_range</string> </key>
<value> <string>The date and time you entered were out of range.</string> </value>
</item>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
<item>
<key> <string>not_datetime</string> </key>
<value> <string>You did not enter a valid date and time.</string> </value>
</item>
<item>
<key> <string>required_not_found</string> </key>
<value> <string>Input is required but no input given.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>allow_empty_time</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>ampm_time_style</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>date_only</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>date_separator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default_now</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>end_datetime</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden_day_is_last_day</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hide_day</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>input_order</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>input_style</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>start_datetime</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>time_separator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>timezone_style</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>sub_form</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>allow_empty_time</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>ampm_time_style</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>date_only</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>date_separator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default_now</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>end_datetime</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden_day_is_last_day</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hide_day</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>input_order</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>input_style</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>start_datetime</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>time_separator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>timezone_style</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>allow_empty_time</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>ampm_time_style</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string>date_field</string> </value>
</item>
<item>
<key> <string>date_only</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>date_separator</string> </key>
<value> <string>/</string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>default_now</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>The Date</string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>end_datetime</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>hidden_day_is_last_day</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>hide_day</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>input_order</string> </key>
<value> <string>ymd</string> </value>
</item>
<item>
<key> <string>input_style</string> </key>
<value> <string>text</string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>start_datetime</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>time_separator</string> </key>
<value> <string>:</string> </value>
</item>
<item>
<key> <string>timezone_style</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Date</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<tuple>
<global name="BasicForm" module="Products.Formulator.Form"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string></string> </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>fields</string> </key>
<value>
<dictionary>
<item>
<key> <string>ampm</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
<item>
<key> <string>day</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAU=</string> </persistent>
</value>
</item>
<item>
<key> <string>hour</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAY=</string> </persistent>
</value>
</item>
<item>
<key> <string>minute</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAc=</string> </persistent>
</value>
</item>
<item>
<key> <string>month</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAg=</string> </persistent>
</value>
</item>
<item>
<key> <string>timezone</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAk=</string> </persistent>
</value>
</item>
<item>
<key> <string>year</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAo=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>group_list</string> </key>
<value>
<list>
<string>Default</string>
<string>date</string>
<string>time</string>
</list>
</value>
</item>
<item>
<key> <string>groups</string> </key>
<value>
<dictionary>
<item>
<key> <string>Default</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>date</string> </key>
<value>
<list>
<string>year</string>
<string>month</string>
<string>day</string>
</list>
</value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<list>
<string>hour</string>
<string>minute</string>
<string>ampm</string>
<string>timezone</string>
</list>
</value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>method</string> </key>
<value> <string>POST</string> </value>
</item>
<item>
<key> <string>name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>stored_encoding</string> </key>
<value> <string>ISO-8859-1</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Basic Form</string> </value>
</item>
<item>
<key> <string>unicode_mode</string> </key>
<value> <int>0</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<tuple>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>preferences/getPreferredDateOrder | string:ymd</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<tuple>
<global name="StringField" module="Products.Formulator.StandardFields"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>ampm</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>
<item>
<key> <string>required_not_found</string> </key>
<value> <string>Input is required but no input given.</string> </value>
</item>
<item>
<key> <string>too_long</string> </key>
<value> <string>Too much input was given.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_maxwidth</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_width</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_length</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>
<item>
<key> <string>truncate</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_maxwidth</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_width</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_length</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>
<item>
<key> <string>truncate</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_maxwidth</string> </key>
<value> <int>2</int> </value>
</item>
<item>
<key> <string>display_width</string> </key>
<value> <int>2</int> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <int>2</int> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>am/pm</string> </value>
</item>
<item>
<key> <string>truncate</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <int>0</int> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="5" aka="AAAAAAAAAAU=">
<pickle>
<tuple>
<global name="IntegerField" module="Products.Formulator.StandardFields"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>day</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>
<item>
<key> <string>integer_out_of_range</string> </key>
<value> <string>The integer you entered was out of range.</string> </value>
</item>
<item>
<key> <string>not_integer</string> </key>
<value> <string>You did not enter an integer.</string> </value>
</item>
<item>
<key> <string>required_not_found</string> </key>
<value> <string>Input is required but no input given.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_maxwidth</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_width</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>end</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>start</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_maxwidth</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_width</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>end</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>start</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_maxwidth</string> </key>
<value> <int>2</int> </value>
</item>
<item>
<key> <string>display_width</string> </key>
<value> <int>2</int> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>end</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>start</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Day</string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <int>0</int> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="6" aka="AAAAAAAAAAY=">
<pickle>
<tuple>
<global name="IntegerField" module="Products.Formulator.StandardFields"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>hour</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>
<item>
<key> <string>integer_out_of_range</string> </key>
<value> <string>The integer you entered was out of range.</string> </value>
</item>
<item>
<key> <string>not_integer</string> </key>
<value> <string>You did not enter an integer.</string> </value>
</item>
<item>
<key> <string>required_not_found</string> </key>
<value> <string>Input is required but no input given.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_maxwidth</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_width</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>end</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>start</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_maxwidth</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_width</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>end</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>start</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_maxwidth</string> </key>
<value> <int>2</int> </value>
</item>
<item>
<key> <string>display_width</string> </key>
<value> <int>2</int> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>end</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>start</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Hour</string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <int>0</int> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="7" aka="AAAAAAAAAAc=">
<pickle>
<tuple>
<global name="IntegerField" module="Products.Formulator.StandardFields"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>minute</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>
<item>
<key> <string>integer_out_of_range</string> </key>
<value> <string>The integer you entered was out of range.</string> </value>
</item>
<item>
<key> <string>not_integer</string> </key>
<value> <string>You did not enter an integer.</string> </value>
</item>
<item>
<key> <string>required_not_found</string> </key>
<value> <string>Input is required but no input given.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_maxwidth</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_width</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>end</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>start</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_maxwidth</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_width</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>end</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>start</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_maxwidth</string> </key>
<value> <int>2</int> </value>
</item>
<item>
<key> <string>display_width</string> </key>
<value> <int>2</int> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>end</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>start</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Minute</string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <int>0</int> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="8" aka="AAAAAAAAAAg=">
<pickle>
<tuple>
<global name="IntegerField" module="Products.Formulator.StandardFields"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>month</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>
<item>
<key> <string>integer_out_of_range</string> </key>
<value> <string>The integer you entered was out of range.</string> </value>
</item>
<item>
<key> <string>not_integer</string> </key>
<value> <string>You did not enter an integer.</string> </value>
</item>
<item>
<key> <string>required_not_found</string> </key>
<value> <string>Input is required but no input given.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_maxwidth</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_width</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>end</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>start</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_maxwidth</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_width</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>end</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>start</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_maxwidth</string> </key>
<value> <int>2</int> </value>
</item>
<item>
<key> <string>display_width</string> </key>
<value> <int>2</int> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>end</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>start</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Month</string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <int>0</int> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="9" aka="AAAAAAAAAAk=">
<pickle>
<tuple>
<global name="ListField" module="Products.Formulator.StandardFields"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>timezone</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>
<item>
<key> <string>required_not_found</string> </key>
<value> <string>Input is required but no input given.</string> </value>
</item>
<item>
<key> <string>unknown_selection</string> </key>
<value> <string>You selected an item that was not in the list.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra_item</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>first_item</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>size</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra_item</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>first_item</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>size</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string>GMT</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra_item</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>first_item</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>items</string> </key>
<value>
<list>
<tuple>
<string>GMT-12</string>
<string>GMT-12</string>
</tuple>
<tuple>
<string>GMT-11</string>
<string>GMT-11</string>
</tuple>
<tuple>
<string>GMT-10</string>
<string>GMT-10</string>
</tuple>
<tuple>
<string>GMT-9</string>
<string>GMT-9</string>
</tuple>
<tuple>
<string>GMT-8</string>
<string>GMT-8</string>
</tuple>
<tuple>
<string>GMT-7</string>
<string>GMT-7</string>
</tuple>
<tuple>
<string>GMT-6</string>
<string>GMT-6</string>
</tuple>
<tuple>
<string>GMT-5</string>
<string>GMT-5</string>
</tuple>
<tuple>
<string>GMT-4</string>
<string>GMT-4</string>
</tuple>
<tuple>
<string>GMT-3</string>
<string>GMT-3</string>
</tuple>
<tuple>
<string>GMT-2</string>
<string>GMT-2</string>
</tuple>
<tuple>
<string>GMT-1</string>
<string>GMT-1</string>
</tuple>
<tuple>
<string>GMT</string>
<string>GMT</string>
</tuple>
<tuple>
<string>GMT+1</string>
<string>GMT+1</string>
</tuple>
<tuple>
<string>GMT+2</string>
<string>GMT+2</string>
</tuple>
<tuple>
<string>GMT+3</string>
<string>GMT+3</string>
</tuple>
<tuple>
<string>GMT+4</string>
<string>GMT+4</string>
</tuple>
<tuple>
<string>GMT+5</string>
<string>GMT+5</string>
</tuple>
<tuple>
<string>GMT+6</string>
<string>GMT+6</string>
</tuple>
<tuple>
<string>GMT+7</string>
<string>GMT+7</string>
</tuple>
<tuple>
<string>GMT+8</string>
<string>GMT+8</string>
</tuple>
<tuple>
<string>GMT+9</string>
<string>GMT+9</string>
</tuple>
<tuple>
<string>GMT+10</string>
<string>GMT+10</string>
</tuple>
<tuple>
<string>GMT+11</string>
<string>GMT+11</string>
</tuple>
<tuple>
<string>GMT+12</string>
<string>GMT+12</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>size</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Timezone</string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <int>0</int> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="10" aka="AAAAAAAAAAo=">
<pickle>
<tuple>
<global name="IntegerField" module="Products.Formulator.StandardFields"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>year</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>
<item>
<key> <string>integer_out_of_range</string> </key>
<value> <string>The integer you entered was out of range.</string> </value>
</item>
<item>
<key> <string>not_integer</string> </key>
<value> <string>You did not enter an integer.</string> </value>
</item>
<item>
<key> <string>required_not_found</string> </key>
<value> <string>Input is required but no input given.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_maxwidth</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_width</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>end</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>start</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_maxwidth</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_width</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>end</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>start</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_maxwidth</string> </key>
<value> <int>4</int> </value>
</item>
<item>
<key> <string>display_width</string> </key>
<value> <int>4</int> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>end</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>start</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Year</string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <int>0</int> </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>editable</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_title</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>
<item>
<key> <string>target</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>target</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_ticket_title</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewCRMFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</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</string>
<string>editable</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>your_response_event_text_content</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>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>default</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </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>target</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>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_text_content</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewCRMFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Message</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: context.Person_getSlapOSPendingTicketMessageTemplate()[1]</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>default</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>your_response_event_title</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>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>default</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>target</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>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_string_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Title</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: "You have %s pending tickets to take action" % (len(context.Person_getSlapOSPendingTicket()))</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
portal = context.getPortalObject()
project = context
causality_value = portal.restrictedTraverse(causality)
if causality_value.Base_getSupportRequestInProgress(title=title) is not None:
return
destination_decision_value = portal.restrictedTraverse(destination_decision)
return destination_decision_value.Entity_createTicketFromTradeCondition(
portal.service_module.slapos_crm_monitoring.getRelativeUrl(),
title,
text_content,
source_project=project.getRelativeUrl(),
causality=causality
)
...@@ -50,11 +50,11 @@ ...@@ -50,11 +50,11 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>instance, notification_message_reference</string> </value> <value> <string>title, text_content, causality, destination_decision</string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>InstanceTree_createSupportRequestEvent</string> </value> <value> <string>Project_createSupportRequestWithCausality</string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
from DateTime import DateTime
portal = context.getPortalObject()
open_sale_order_list = portal.portal_catalog(
portal_type="Open Sale Order",
children_portal_type="Open Sale Order Line",
validation_state="validated")
context.edit(
source=context.organisation_module.slapos,
destination=[i.getDestination() for i in open_sale_order_list])
return context.Base_redirect()
<?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></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>SiteMessage_setSlapOSUserSourceAndDestinatationList</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
portal = context.getPortalObject() portal = context.getPortalObject()
return portal.portal_catalog.getResultValue( return portal.portal_catalog.getResultValue(
title=title, title={'query': title, 'key': 'ExactMatch'},
follow_up_uid=context.getUid(), follow_up__uid=context.getUid(),
portal_type=portal.getPortalEventTypeList(), portal_type=portal.getPortalEventTypeList(),
sort_on=[('delivery.start_date', 'DESC')]) sort_on=[('delivery.start_date', 'DESC')])
""" Close Support Request which are related to a Destroy Requested Instance. """
portal = context.getPortalObject()
if context.getSimulationState() == "invalidated":
return
document = context.getAggregateValue()
if document is not None and document.getSlapState() == "destroy_requested":
person = context.getDestinationDecision(portal_type="Person")
if not person:
return
# Send Notification message
message = """ Closing this ticket as the Instance Tree was destroyed by the user.
"""
notification_message = portal.portal_notifications.getDocumentValue(
reference="slapos-crm-support-request-close-destroyed-notification")
if notification_message is not None:
mapping_dict = {'instance_tree_title': document.getTitle()}
message = notification_message.asText(
substitution_method_parameter_dict={'mapping_dict':mapping_dict})
ticket_title = "Instance Tree was destroyed was destroyed by the user"
event = context.SupportRequest_getLastEvent(ticket_title)
if event is None:
context.notify(message_title=ticket_title, message=message)
context.invalidate()
return context.REQUEST.get("ticket_notified_item")
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_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></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>SupportRequest_updateMonitoringDestroyRequestedState</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
""" Close Support Request which are related to a Destroy Requested Instance. """
portal = context.getPortalObject()
if context.getSimulationState() == "invalidated": if context.getSimulationState() == "invalidated":
return return
document = context.getAggregateValue(portal_type="Instance Tree") document = context.getCausalityValue(portal_type="Instance Tree")
if document is None: if document is None:
return return
if document.getPortalType() == "Instance Tree": if document.getSlapState() == "destroy_requested":
if document.getSlapState() == "destroy_requested":
return context.SupportRequest_updateMonitoringDestroyRequestedState() # Send Notification message
message = """ Closing this ticket as the Instance Tree was destroyed by the user.
"""
ticket_title = "Instance Tree was destroyed was destroyed by the user"
event = context.SupportRequest_getLastEvent(ticket_title)
if event is None:
context.Ticket_createProjectEvent(
ticket_title, 'outgoing', 'Web Message',
portal.service_module.slapos_crm_information.getRelativeUrl(),
text_content=message,
content_type='text/plain',
notification_message="slapos-crm-support-request-close-destroyed-notification",
#language=XXX,
substitution_method_parameter_dict={
'instance_tree_title': document.getTitle()
}
)
context.invalidate()
return event
"""Generic script to add event
It creates new Event for any context which become follow_up of created Event.
"""
portal = context.getPortalObject()
ticket = context
if direction == 'outgoing':
source_relative_url = source or ticket.getSource()
source_section_relative_url = ticket.getSourceSection()
source_project_relative_url = ticket.getSourceProject()
destination_relative_url = destination or ticket.getDestination()
destination_section_relative_url = ticket.getDestinationSection()
destination_project_relative_url = ticket.getDestinationProject()
elif direction == 'incoming':
source_relative_url = source or ticket.getDestination()
source_section_relative_url = ticket.getDestinationSection()
source_project_relative_url = ticket.getDestinationProject()
destination_relative_url = destination or ticket.getSource()
destination_section_relative_url = ticket.getSourceSection()
destination_project_relative_url = ticket.getSourceProject()
else:
raise NotImplementedError('The specified direction is not handled: %r' % (direction,))
event_kw = {
'portal_type': portal_type,
'resource': resource,
'source': source_relative_url,
'source_section': source_section_relative_url,
'source_project': source_project_relative_url,
'destination': destination_relative_url,
'destination_section': destination_section_relative_url,
'destination_project': destination_project_relative_url,
'start_date': DateTime(),
'follow_up_value': ticket,
'language': language,
'text_content': text_content,
'content_type': content_type,
}
# Create event
module = portal.getDefaultModule(portal_type=portal_type)
event = module.newContent(**event_kw)
if notification_message:
event.Event_setTextContentFromNotificationMessage(
notification_message,
language=language,
substitution_method_parameter_dict=substitution_method_parameter_dict
)
# Prefer using the notification message title
# as it will be correctly translated
if not event.hasTitle():
event.edit(title=title)
if not keep_draft:
if direction == 'incoming':
# Support event_workflow and event_simulation_workflow
if portal.portal_workflow.isTransitionPossible(event, 'receive'):
event.receive(comment=comment)
if portal.portal_workflow.isTransitionPossible(event, 'stop'):
event.stop(comment=comment)
else:
event.plan(comment=comment)
event.start(comment=comment, send_mail=(portal_type == 'Mail Message'))
event.stop(comment=comment)
event.deliver(comment=comment)
return event
...@@ -50,11 +50,11 @@ ...@@ -50,11 +50,11 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>**kw</string> </value> <value> <string>title, direction, portal_type, resource, text_content, content_type, notification_message=None, substitution_method_parameter_dict=None, keep_draft=False, source=None, destination=None, language=None, comment=None, **kw</string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>Person_getSlapOSPendingTicket</string> </value> <value> <string>Ticket_createProjectEvent</string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
...@@ -21,149 +21,344 @@ ...@@ -21,149 +21,344 @@
# #
############################################################################## ##############################################################################
from erp5.component.test.SlapOSTestCaseMixin import \ from erp5.component.test.SlapOSTestCaseMixin import \
SlapOSTestCaseMixin, SlapOSTestCaseMixinWithAbort SlapOSTestCaseMixin,SlapOSTestCaseMixinWithAbort, simulate
from DateTime import DateTime from DateTime import DateTime
import difflib
import transaction
from zExceptions import Unauthorized
class TestSlapOSCRMCreateRegularisationRequest(SlapOSTestCaseMixin):
def createFinalInvoice(self, person): class TestSlapOSCRMCreateRegularisationRequestAlarm(SlapOSTestCaseMixin):
template = self.portal.restrictedTraverse( def createFinalInvoice(self, person, grouping_reference=None,
self.portal.portal_preferences.getPreferredDefaultPrePaymentSubscriptionInvoiceTemplate()) ledger="automated",
current_invoice = template.Base_createCloneDocument(batch_mode=1) source="account_module/receivable",
is_stopped=True):
current_invoice.edit( current_invoice = self.portal.accounting_module.newContent(
destination_value=person, portal_type="Sale Invoice Transaction",
destination_section_value=person, destination_section_value=person,
destination_decision_value=person,
start_date=DateTime('2019/10/20'), start_date=DateTime('2019/10/20'),
stop_date=DateTime('2019/10/20'), stop_date=DateTime('2019/10/20'),
title='Fake Invoice for Demo User Functional', title='Fake Invoice for Demo User Functional',
price_currency="currency_module/EUR", resource="currency_module/EUR",
reference='1') reference='1',
ledger=ledger)
cell = current_invoice["1"]["movement_0"] current_invoice.receivable.edit(
cell.edit(quantity=1) source=source,
cell.setPrice(1) quantity=1,
price=1,
grouping_reference=grouping_reference
)
current_invoice.plan() current_invoice.plan()
current_invoice.confirm() current_invoice.confirm()
current_invoice.startBuilding() if is_stopped:
current_invoice.reindexObject()
current_invoice.stop() current_invoice.stop()
self.tic() self.tic()
current_invoice.Delivery_manageBuildingCalculatingDelivery()
self.tic()
applied_rule = current_invoice.getCausalityRelated(portal_type="Applied Rule")
for sm in self.portal.portal_catalog(portal_type='Simulation Movement',
simulation_state=['draft', 'planned', None],
left_join_list=['delivery_uid'],
delivery_uid=None,
path="%%%s%%" % applied_rule):
if sm.getDelivery() is not None:
continue
root_applied_rule = sm.getRootAppliedRule()
root_applied_rule_path = root_applied_rule.getPath()
sm.getCausalityValue(portal_type='Business Link').build(
path='%s/%%' % root_applied_rule_path)
return current_invoice return current_invoice
def test_createRegularisationRequest_expected_person(self): #################################################################
# slapos_crm_create_regularisation_request
#################################################################
def test_Person_checkToCreateRegularisationRequest_alarm_expectedPerson(self):
new_id = self.generateNewId() new_id = self.generateNewId()
person = self.portal.person_module.newContent( person = self.portal.person_module.newContent(
portal_type='Person', portal_type='Person',
title="Test person %s" % new_id title="Test person %s" % new_id
) )
person.validate() person.validate()
self.createFinalInvoice(person) self.createFinalInvoice(person)
self.tic() self.tic()
alarm = self.portal.portal_alarms.\ self._test_alarm(
slapos_crm_create_regularisation_request self.portal.portal_alarms.slapos_crm_create_regularisation_request,
self._test_alarm(alarm, person, "Person_checkToCreateRegularisationRequest") person,
'Person_checkToCreateRegularisationRequest'
)
def test_createRegularisationRequest_not_validated(self): def test_Person_checkToCreateRegularisationRequest_alarm_started(self):
new_id = self.generateNewId() new_id = self.generateNewId()
person = self.portal.person_module.newContent( person = self.portal.person_module.newContent(
portal_type='Person', portal_type='Person',
title="Test person %s" % new_id title="Test person %s" % new_id
) )
person.validate() person.validate()
self.createFinalInvoice(person) self.createFinalInvoice(person, is_stopped=False)
person.invalidate()
self.tic() self.tic()
alarm = self.portal.portal_alarms.\ self._test_alarm_not_visited(
slapos_crm_create_regularisation_request self.portal.portal_alarms.slapos_crm_create_regularisation_request,
self._test_alarm_not_visited(alarm, person, "Person_checkToCreateRegularisationRequest") person,
'Person_checkToCreateRegularisationRequest'
)
def test_createRegularisationRequest_payment_stopped(self): def test_Person_checkToCreateRegularisationRequest_alarm_lettered(self):
new_id = self.generateNewId() new_id = self.generateNewId()
person = self.portal.person_module.newContent( person = self.portal.person_module.newContent(
portal_type='Person', portal_type='Person',
title="Test person %s" % new_id title="Test person %s" % new_id
) )
person.validate() person.validate()
current_invoice = self.createFinalInvoice(person) self.createFinalInvoice(person, grouping_reference="foobar")
payment_template = self.portal.restrictedTraverse( self.tic()
self.portal.portal_preferences.getPreferredDefaultPrePaymentTemplate()) self._test_alarm_not_visited(
payment = payment_template.Base_createCloneDocument(batch_mode=1) self.portal.portal_alarms.slapos_crm_create_regularisation_request,
person,
for line in payment.contentValues(): 'Person_checkToCreateRegularisationRequest'
if line.getSource() == "account_module/payment_to_encash": )
line.setQuantity(-1)
elif line.getSource() == "account_module/receivable":
line.setQuantity(1)
payment.confirm() def test_Person_checkToCreateRegularisationRequest_alarm_noLedger(self):
payment.start() new_id = self.generateNewId()
payment.setCausalityValue(current_invoice) person = self.portal.person_module.newContent(
payment.setDestinationSectionValue(person) portal_type='Person',
title="Test person %s" % new_id
)
person.validate()
self.createFinalInvoice(person, ledger=None)
self.tic()
self._test_alarm_not_visited(
self.portal.portal_alarms.slapos_crm_create_regularisation_request,
person,
'Person_checkToCreateRegularisationRequest'
)
payment.stop() def test_Person_checkToCreateRegularisationRequest_alarm_noReceivable(self):
new_id = self.generateNewId()
person = self.portal.person_module.newContent(
portal_type='Person',
title="Test person %s" % new_id
)
person.validate()
self.createFinalInvoice(person, source="account_module/bank")
self.tic() self.tic()
self._test_alarm_not_visited(
self.portal.portal_alarms.slapos_crm_create_regularisation_request,
person,
'Person_checkToCreateRegularisationRequest'
)
def test_Person_checkToCreateRegularisationRequest_alarm_notValidatedPerson(self):
new_id = self.generateNewId()
person = self.portal.person_module.newContent(
portal_type='Person',
title="Test person %s" % new_id
)
person.validate()
person.invalidate()
self.createFinalInvoice(person)
self.tic() self.tic()
alarm = self.portal.portal_alarms.\ self._test_alarm_not_visited(
slapos_crm_create_regularisation_request self.portal.portal_alarms.slapos_crm_create_regularisation_request,
self._test_alarm_not_visited(alarm, person, "Person_checkToCreateRegularisationRequest") person,
'Person_checkToCreateRegularisationRequest'
)
def test_createRegularisationRequest_payment_started(self): def test_Person_checkToCreateRegularisationRequest_alarm_noInvoice(self):
new_id = self.generateNewId() new_id = self.generateNewId()
person = self.portal.person_module.newContent( person = self.portal.person_module.newContent(
portal_type='Person', portal_type='Person',
title="Test person %s" % new_id title="Test person %s" % new_id
) )
person.validate() person.validate()
self.tic()
self._test_alarm_not_visited(
self.portal.portal_alarms.slapos_crm_create_regularisation_request,
person,
'Person_checkToCreateRegularisationRequest'
)
@simulate('NotificationTool_getDocumentValue',
'reference=None, language="en"',
'assert reference == "slapos-crm.create.regularisation.request"\n' \
'return')
@simulate('Entity_hasOutstandingAmount', '*args, **kwargs', 'return True')
def test_Person_checkToCreateRegularisationRequest_script_paymentRequested(self):
for preference in \
self.portal.portal_catalog(portal_type="System Preference"):
preference = preference.getObject()
if preference.getPreferenceState() == 'global':
preference.setPreferredSlaposWebSiteUrl('http://foobar.org/')
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
current_invoice = self.createFinalInvoice(person) self.createFinalInvoice(person)
payment_template = self.portal.restrictedTraverse( self.tic()
self.portal.portal_preferences.getPreferredDefaultPrePaymentTemplate())
payment = payment_template.Base_createCloneDocument(batch_mode=1)
for line in payment.contentValues(): before_date = DateTime()
if line.getSource() == "account_module/payment_to_encash": ticket, event = person.Person_checkToCreateRegularisationRequest()
line.setQuantity(-1) after_date = DateTime()
elif line.getSource() == "account_module/receivable":
line.setQuantity(1)
payment.confirm() self.tic()
payment.start()
payment.setCausalityValue(current_invoice)
payment.setDestinationSectionValue(person)
self.assertEqual(ticket.getPortalType(), 'Regularisation Request')
self.assertEqual(ticket.getSimulationState(), 'suspended')
self.assertEqual(ticket.getResource(),
'service_module/slapos_crm_acknowledgement')
self.assertEqual(ticket.getTitle(),
'Account regularisation expected for "%s"' % person.getTitle())
self.assertEqual(ticket.getDestination(),
person.getRelativeUrl())
self.assertEqual(ticket.getDestinationDecision(),
person.getRelativeUrl())
self.assertEqual(event.getPortalType(), 'Mail Message')
self.assertEqual(event.getFollowUp(), ticket.getRelativeUrl())
self.assertEqual(event.getResource(),
'service_module/slapos_crm_acknowledgement')
self.assertTrue(event.getStartDate() >= before_date)
self.assertTrue(event.getStopDate() <= after_date)
self.assertEqual(event.getTitle(), "Invoice payment requested")
self.assertEqual(event.getDestination(),
person.getRelativeUrl())
self.assertEqual(event.getSource(),
ticket.getSource())
expected_text_content = """Dear %s,
A new invoice has been generated.
You can access it in your invoice section at http://foobar.org/.
Regards,
The slapos team
""" % person.getTitle()
self.assertEqual(event.getTextContent(), expected_text_content,
'\n'.join([x for x in difflib.unified_diff(
event.getTextContent().splitlines(),
expected_text_content.splitlines())]))
self.assertEqual(event.getSimulationState(), 'delivered')
@simulate('NotificationTool_getDocumentValue',
'reference=None, language="en"',
'assert reference == "slapos-crm.create.regularisation.request"\n' \
'return context.restrictedTraverse(' \
'context.REQUEST["test_addRegularisationRequest_notification_message"])')
@simulate('Entity_hasOutstandingAmount', '*args, **kwargs', 'return True')
def test_Person_checkToCreateRegularisationRequest_script_notificationMessage(self):
for preference in \
self.portal.portal_catalog(portal_type="System Preference"):
preference = preference.getObject()
if preference.getPreferenceState() == 'global':
preference.setPreferredSlaposWebSiteUrl('http://foobar.org/')
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
new_id = self.generateNewId()
notification_message = self.portal.notification_message_module.newContent(
portal_type="Notification Message",
title='Test NM title %s' % new_id,
text_content='Test NM content\n%s\n' % new_id,
content_type='text/plain',
)
self.portal.REQUEST\
['test_addRegularisationRequest_notification_message'] = \
notification_message.getRelativeUrl()
before_date = DateTime()
ticket, event = person.Person_checkToCreateRegularisationRequest()
after_date = DateTime()
self.assertEqual(ticket.getPortalType(), 'Regularisation Request')
self.assertEqual(ticket.getSimulationState(), 'suspended')
self.assertEqual(ticket.getSourceProject(), None)
self.assertEqual(ticket.getResource(),
'service_module/slapos_crm_acknowledgement')
self.assertEqual(ticket.getTitle(),
'Account regularisation expected for "%s"' % person.getTitle())
self.assertEqual(ticket.getDestination(),
person.getRelativeUrl())
self.assertEqual(ticket.getDestinationDecision(),
person.getRelativeUrl())
self.assertEqual(event.getPortalType(), 'Mail Message')
self.assertEqual(event.getResource(),
'service_module/slapos_crm_acknowledgement')
self.assertTrue(event.getStartDate() >= before_date)
self.assertTrue(event.getStopDate() <= after_date)
self.assertEqual(event.getTitle(),
'Test NM title %s' % new_id)
self.assertEqual(event.getDestination(),
person.getRelativeUrl())
self.assertEqual(event.getSource(),
ticket.getSource())
expected_text_content = 'Test NM content\n%s\n' % new_id
self.assertEqual(event.getTextContent(), expected_text_content,
'\n'.join([x for x in difflib.unified_diff(
event.getTextContent().splitlines(),
expected_text_content.splitlines())]))
self.assertEqual(event.getSimulationState(), 'delivered')
# def test_addRegularisationRequest_do_not_duplicate_ticket(self):
# person = self.createPerson()
# ticket = person.Person_checkToCreateRegularisationRequest()
# ticket2 = person.Person_checkToCreateRegularisationRequest()
# self.assertEqual(ticket.getRelativeUrl(), ticket2.getRelativeUrl())
@simulate('Entity_hasOutstandingAmount', '*args, **kwargs', 'return True')
def test_Person_checkToCreateRegularisationRequest_script_doNotDuplicateTicketIfNotReindexed(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket, event = person.Person_checkToCreateRegularisationRequest()
transaction.commit()
ticket2, event2 = person.Person_checkToCreateRegularisationRequest()
self.assertNotEqual(ticket, None)
self.assertNotEqual(event, None)
self.assertEqual(ticket2, None)
self.assertEqual(event2, None)
@simulate('Entity_hasOutstandingAmount', '*args, **kwargs', 'return False')
@simulate('RegularisationRequest_checkToSendUniqEvent',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
def test_Person_checkToCreateRegularisationRequest_script_balanceOk(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket, event = person.Person_checkToCreateRegularisationRequest()
self.assertEqual(ticket, None)
self.assertEqual(event, None)
@simulate('Entity_hasOutstandingAmount', '*args, **kwargs', 'return True')
def test_Person_checkToCreateRegularisationRequest_script_existingSuspendedTicket(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket, event = person.Person_checkToCreateRegularisationRequest()
transaction.commit()
self.tic() self.tic()
alarm = self.portal.portal_alarms.\ ticket2, event2 = person.Person_checkToCreateRegularisationRequest()
slapos_crm_create_regularisation_request self.assertNotEqual(ticket, None)
self._test_alarm(alarm, person, "Person_checkToCreateRegularisationRequest") self.assertNotEqual(event, None)
self.assertEqual(ticket2.getRelativeUrl(), ticket.getRelativeUrl())
self.assertEqual(event2, None)
@simulate('Entity_hasOutstandingAmount', '*args, **kwargs', 'return True')
def test_Person_checkToCreateRegularisationRequest_script_existingValidatedTicket(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket, event = person.Person_checkToCreateRegularisationRequest()
ticket.validate()
transaction.commit()
self.tic()
ticket2, event2 = person.Person_checkToCreateRegularisationRequest()
self.assertNotEqual(ticket, None)
self.assertNotEqual(event, None)
self.assertEqual(ticket2.getRelativeUrl(), ticket.getRelativeUrl())
self.assertEqual(event2, None)
@simulate('Entity_hasOutstandingAmount', '*args, **kwargs', 'return True')
def test_Person_checkToCreateRegularisationRequest_script_existingInvalidatedTicket(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = person.Person_checkToCreateRegularisationRequest()[0]
ticket.invalidate()
transaction.commit()
self.tic()
ticket2, event2 = person.Person_checkToCreateRegularisationRequest()
self.assertNotEqual(ticket2.getRelativeUrl(), ticket.getRelativeUrl())
self.assertNotEqual(event2, None)
def test_Person_checkToCreateRegularisationRequest_script_REQUEST_disallowed(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
self.assertRaises(
Unauthorized,
person.Person_checkToCreateRegularisationRequest,
REQUEST={})
class TestSlapOSCrmInvalidateSuspendedRegularisationRequest(SlapOSTestCaseMixinWithAbort):
def createRegularisationRequest(self): def createRegularisationRequest(self):
new_id = self.generateNewId() new_id = self.generateNewId()
...@@ -173,7 +368,10 @@ class TestSlapOSCrmInvalidateSuspendedRegularisationRequest(SlapOSTestCaseMixinW ...@@ -173,7 +368,10 @@ class TestSlapOSCrmInvalidateSuspendedRegularisationRequest(SlapOSTestCaseMixinW
reference="TESTREGREQ-%s" % new_id, reference="TESTREGREQ-%s" % new_id,
) )
def test_invalidateSuspendedRegularisationRequest_validated_regularisation_request(self): #################################################################
# slapos_crm_invalidate_suspended_regularisation_request
#################################################################
def test_RegularisationRequest_invalidateIfPersonBalanceIsOk_alarm_validatedRegularisationRequest(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
ticket.validate() ticket.validate()
self.tic() self.tic()
...@@ -181,7 +379,7 @@ class TestSlapOSCrmInvalidateSuspendedRegularisationRequest(SlapOSTestCaseMixinW ...@@ -181,7 +379,7 @@ class TestSlapOSCrmInvalidateSuspendedRegularisationRequest(SlapOSTestCaseMixinW
slapos_crm_invalidate_suspended_regularisation_request slapos_crm_invalidate_suspended_regularisation_request
self._test_alarm(alarm, ticket, "RegularisationRequest_invalidateIfPersonBalanceIsOk") self._test_alarm(alarm, ticket, "RegularisationRequest_invalidateIfPersonBalanceIsOk")
def test_invalidateSuspendedRegularisationRequest_suspended_regularisation_request(self): def test_RegularisationRequest_invalidateIfPersonBalanceIsOk_alarm_suspendedRegularisationRequest(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
ticket.validate() ticket.validate()
ticket.suspend() ticket.suspend()
...@@ -190,7 +388,7 @@ class TestSlapOSCrmInvalidateSuspendedRegularisationRequest(SlapOSTestCaseMixinW ...@@ -190,7 +388,7 @@ class TestSlapOSCrmInvalidateSuspendedRegularisationRequest(SlapOSTestCaseMixinW
slapos_crm_invalidate_suspended_regularisation_request slapos_crm_invalidate_suspended_regularisation_request
self._test_alarm(alarm, ticket, "RegularisationRequest_invalidateIfPersonBalanceIsOk") self._test_alarm(alarm, ticket, "RegularisationRequest_invalidateIfPersonBalanceIsOk")
def test_invalidateSuspendedRegularisationRequest_invalidated_regularisation_request(self): def test_RegularisationRequest_invalidateIfPersonBalanceIsOk_alarm_invalidatedRegularisationRequest(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
ticket.validate() ticket.validate()
ticket.invalidate() ticket.invalidate()
...@@ -199,6 +397,53 @@ class TestSlapOSCrmInvalidateSuspendedRegularisationRequest(SlapOSTestCaseMixinW ...@@ -199,6 +397,53 @@ class TestSlapOSCrmInvalidateSuspendedRegularisationRequest(SlapOSTestCaseMixinW
slapos_crm_invalidate_suspended_regularisation_request slapos_crm_invalidate_suspended_regularisation_request
self._test_alarm_not_visited(alarm, ticket, "RegularisationRequest_invalidateIfPersonBalanceIsOk") self._test_alarm_not_visited(alarm, ticket, "RegularisationRequest_invalidateIfPersonBalanceIsOk")
def test_RegularisationRequest_invalidateIfPersonBalanceIsOk_script_REQUESTdisallowed(self):
ticket = self.createRegularisationRequest()
self.assertRaises(
Unauthorized,
ticket.RegularisationRequest_invalidateIfPersonBalanceIsOk,
REQUEST={})
@simulate('Entity_hasOutstandingAmount', '*args, **kwargs', 'return False')
def test_RegularisationRequest_invalidateIfPersonBalanceIsOk_script_matchingCase(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest()
ticket.edit(destination_decision_value=person)
ticket.validate()
ticket.suspend()
ticket.RegularisationRequest_invalidateIfPersonBalanceIsOk()
self.assertEqual(ticket.getSimulationState(), 'invalidated')
@simulate('Entity_hasOutstandingAmount', '*args, **kwargs', 'return False')
def test_RegularisationRequest_invalidateIfPersonBalanceIsOk_script_validated(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest()
ticket.edit(destination_decision_value=person)
ticket.validate()
ticket.RegularisationRequest_invalidateIfPersonBalanceIsOk()
self.assertEqual(ticket.getSimulationState(), 'invalidated')
@simulate('Entity_hasOutstandingAmount', '*args, **kwargs', 'return False')
def test_RegularisationRequest_invalidateIfPersonBalanceIsOk_script_noPerson(self):
ticket = self.createRegularisationRequest()
ticket.validate()
ticket.suspend()
ticket.RegularisationRequest_invalidateIfPersonBalanceIsOk()
self.assertEqual(ticket.getSimulationState(), 'suspended')
@simulate('Entity_hasOutstandingAmount', '*args, **kwargs', 'return True')
def test_RegularisationRequest_invalidateIfPersonBalanceIsOk_script_wrongBalance(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest()
ticket.edit(destination_decision_value=person)
ticket.validate()
ticket.suspend()
ticket.RegularisationRequest_invalidateIfPersonBalanceIsOk()
self.assertEqual(ticket.getSimulationState(), 'suspended')
class TestSlapOSCrmTriggerEscalationOnAcknowledgmentRegularisationRequest(SlapOSTestCaseMixinWithAbort): class TestSlapOSCrmTriggerEscalationOnAcknowledgmentRegularisationRequest(SlapOSTestCaseMixinWithAbort):
...@@ -210,7 +455,10 @@ class TestSlapOSCrmTriggerEscalationOnAcknowledgmentRegularisationRequest(SlapOS ...@@ -210,7 +455,10 @@ class TestSlapOSCrmTriggerEscalationOnAcknowledgmentRegularisationRequest(SlapOS
reference="TESTREGREQ-%s" % new_id, reference="TESTREGREQ-%s" % new_id,
) )
def test_triggerAcknowledgmentEscalation_matching_regularisation_request(self): #################################################################
# slapos_crm_trigger_acknowledgment_escalation
#################################################################
def test_RegularisationRequest_triggerAcknowledgmentEscalation_alarm_matchingRegularisationRequest(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_acknowledgement') ticket.edit(resource='service_module/slapos_crm_acknowledgement')
ticket.validate() ticket.validate()
...@@ -222,7 +470,7 @@ class TestSlapOSCrmTriggerEscalationOnAcknowledgmentRegularisationRequest(SlapOS ...@@ -222,7 +470,7 @@ class TestSlapOSCrmTriggerEscalationOnAcknowledgmentRegularisationRequest(SlapOS
self._test_alarm(alarm, ticket, self._test_alarm(alarm, ticket,
"RegularisationRequest_triggerAcknowledgmentEscalation") "RegularisationRequest_triggerAcknowledgmentEscalation")
def test_triggerAcknowledgmentEscalation_not_suspended(self): def test_RegularisationRequest_triggerAcknowledgmentEscalation_alarm_notSuspendedRegularisationRequest(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_acknowledgement') ticket.edit(resource='service_module/slapos_crm_acknowledgement')
ticket.validate() ticket.validate()
...@@ -234,7 +482,7 @@ class TestSlapOSCrmTriggerEscalationOnAcknowledgmentRegularisationRequest(SlapOS ...@@ -234,7 +482,7 @@ class TestSlapOSCrmTriggerEscalationOnAcknowledgmentRegularisationRequest(SlapOS
"RegularisationRequest_triggerAcknowledgmentEscalation") "RegularisationRequest_triggerAcknowledgmentEscalation")
def test_triggerAcknowledgmentEscalation_not_expected_resource(self): def test_RegularisationRequest_triggerAcknowledgmentEscalation_alarm_notExpectedResource(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
ticket.validate() ticket.validate()
ticket.suspend() ticket.suspend()
...@@ -245,6 +493,46 @@ class TestSlapOSCrmTriggerEscalationOnAcknowledgmentRegularisationRequest(SlapOS ...@@ -245,6 +493,46 @@ class TestSlapOSCrmTriggerEscalationOnAcknowledgmentRegularisationRequest(SlapOS
self._test_alarm_not_visited(alarm, ticket, self._test_alarm_not_visited(alarm, ticket,
"RegularisationRequest_triggerAcknowledgmentEscalation") "RegularisationRequest_triggerAcknowledgmentEscalation")
def test_RegularisationRequest_triggerAcknowledgmentEscalation_script_REQUESTdisallowed(self):
ticket = self.createRegularisationRequest()
self.assertRaises(
Unauthorized,
ticket.RegularisationRequest_triggerAcknowledgmentEscalation,
REQUEST={})
@simulate('RegularisationRequest_checkToTriggerNextEscalationStep',
'delay_period_in_days, current_service_relative_url, ' \
'next_service_relative_url, title, text_content, comment, ' \
'notification_message=None, substitution_method_parameter_dict=None, ' \
'REQUEST=None',
'context.portal_workflow.doActionFor(' \
'context, action="edit_action", ' \
'comment="Visited by RegularisationRequest_checkToTriggerNextEscalationStep ' \
'%s %s %s %s %s %s %s %s" % (delay_period_in_days, current_service_relative_url, next_service_relative_url, title, text_content, comment, notification_message, substitution_method_parameter_dict))')
def test_RegularisationRequest_triggerAcknowledgmentEscalation_script_matchingEvent(self):
ticket = self.createRegularisationRequest()
ticket.RegularisationRequest_triggerAcknowledgmentEscalation()
self.assertEqual(
'Visited by RegularisationRequest_checkToTriggerNextEscalationStep ' \
'%s %s %s %s %s %s %s %s' % \
(15,
'service_module/slapos_crm_acknowledgement',
'service_module/slapos_crm_stop_reminder',
'Reminder: invoice payment requested',
"""Dear user,
We would like to remind you the unpaid invoice you have on %s.
If no payment is done during the coming days, we will stop all your current instances to free some hardware resources.
Regards,
The slapos team
""" % self.portal.portal_preferences.getPreferredSlaposWebSiteUrl(),
'Stopping reminder.',
'slapos-crm.acknowledgment.escalation',
"{'user_name': None, 'days': 15}"),
ticket.workflow_history['edit_workflow'][-1]['comment'])
class TestSlapOSCrmTriggerEscalationOnStopReminderRegularisationRequest(SlapOSTestCaseMixinWithAbort): class TestSlapOSCrmTriggerEscalationOnStopReminderRegularisationRequest(SlapOSTestCaseMixinWithAbort):
def createRegularisationRequest(self): def createRegularisationRequest(self):
...@@ -255,7 +543,10 @@ class TestSlapOSCrmTriggerEscalationOnStopReminderRegularisationRequest(SlapOSTe ...@@ -255,7 +543,10 @@ class TestSlapOSCrmTriggerEscalationOnStopReminderRegularisationRequest(SlapOSTe
reference="TESTREGREQ-%s" % new_id, reference="TESTREGREQ-%s" % new_id,
) )
def test_triggerStopReminderEscalation_matching_regularisation_request(self): #################################################################
# slapos_crm_trigger_stop_reminder_escalation
#################################################################
def test_RegularisationRequest_triggerStopReminderEscalation_alarm_matchingRegularisationRequest(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_stop_reminder') ticket.edit(resource='service_module/slapos_crm_stop_reminder')
ticket.validate() ticket.validate()
...@@ -267,7 +558,7 @@ class TestSlapOSCrmTriggerEscalationOnStopReminderRegularisationRequest(SlapOSTe ...@@ -267,7 +558,7 @@ class TestSlapOSCrmTriggerEscalationOnStopReminderRegularisationRequest(SlapOSTe
self._test_alarm(alarm, ticket, self._test_alarm(alarm, ticket,
"RegularisationRequest_triggerStopReminderEscalation") "RegularisationRequest_triggerStopReminderEscalation")
def test_triggerStopReminderEscalation_not_suspended(self): def test_RegularisationRequest_triggerStopReminderEscalation_alarm_notSuspended(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_stop_reminder') ticket.edit(resource='service_module/slapos_crm_stop_reminder')
ticket.validate() ticket.validate()
...@@ -278,7 +569,7 @@ class TestSlapOSCrmTriggerEscalationOnStopReminderRegularisationRequest(SlapOSTe ...@@ -278,7 +569,7 @@ class TestSlapOSCrmTriggerEscalationOnStopReminderRegularisationRequest(SlapOSTe
self._test_alarm_not_visited(alarm, ticket, self._test_alarm_not_visited(alarm, ticket,
"RegularisationRequest_triggerStopReminderEscalation") "RegularisationRequest_triggerStopReminderEscalation")
def test_triggerStopReminderEscalation_not_expected_resource(self): def test_RegularisationRequest_triggerStopReminderEscalation_alarm_notExpectedResource(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
ticket.validate() ticket.validate()
ticket.suspend() ticket.suspend()
...@@ -289,6 +580,46 @@ class TestSlapOSCrmTriggerEscalationOnStopReminderRegularisationRequest(SlapOSTe ...@@ -289,6 +580,46 @@ class TestSlapOSCrmTriggerEscalationOnStopReminderRegularisationRequest(SlapOSTe
self._test_alarm_not_visited(alarm, ticket, self._test_alarm_not_visited(alarm, ticket,
"RegularisationRequest_triggerStopReminderEscalation") "RegularisationRequest_triggerStopReminderEscalation")
def test_RegularisationRequest_triggerStopReminderEscalation_script_REQUESTdisallowed(self):
ticket = self.createRegularisationRequest()
self.assertRaises(
Unauthorized,
ticket.RegularisationRequest_triggerStopReminderEscalation,
REQUEST={})
@simulate('RegularisationRequest_checkToTriggerNextEscalationStep',
'delay_period_in_days, current_service_relative_url, ' \
'next_service_relative_url, title, text_content, comment, ' \
'notification_message=None, substitution_method_parameter_dict=None, ' \
'REQUEST=None',
'context.portal_workflow.doActionFor(' \
'context, action="edit_action", ' \
'comment="Visited by RegularisationRequest_checkToTriggerNextEscalationStep ' \
'%s %s %s %s %s %s %s %s" % (delay_period_in_days, current_service_relative_url, next_service_relative_url, title, text_content, comment, notification_message, substitution_method_parameter_dict))')
def test_RegularisationRequest_triggerStopReminderEscalation_script_matchingEvent(self):
ticket = self.createRegularisationRequest()
ticket.RegularisationRequest_triggerStopReminderEscalation()
self.assertEqual(
'Visited by RegularisationRequest_checkToTriggerNextEscalationStep ' \
'%s %s %s %s %s %s %s %s' % \
(7,
'service_module/slapos_crm_stop_reminder',
'service_module/slapos_crm_stop_acknowledgement',
'Acknowledgment: instances stopped',
"""Dear user,
Despite our last reminder, you still have an unpaid invoice on %s.
We will now stop all your current instances to free some hardware resources.
Regards,
The slapos team
""" % self.portal.portal_preferences.getPreferredSlaposWebSiteUrl(),
'Stopping acknowledgment.',
'slapos-crm.stop.reminder.escalation',
"{'user_name': None, 'days': 7}"),
ticket.workflow_history['edit_workflow'][-1]['comment'])
class TestSlapOSCrmTriggerEscalationOnStopAcknowledgmentRegularisationRequest(SlapOSTestCaseMixinWithAbort): class TestSlapOSCrmTriggerEscalationOnStopAcknowledgmentRegularisationRequest(SlapOSTestCaseMixinWithAbort):
def createRegularisationRequest(self): def createRegularisationRequest(self):
...@@ -299,7 +630,10 @@ class TestSlapOSCrmTriggerEscalationOnStopAcknowledgmentRegularisationRequest(Sl ...@@ -299,7 +630,10 @@ class TestSlapOSCrmTriggerEscalationOnStopAcknowledgmentRegularisationRequest(Sl
reference="TESTREGREQ-%s" % new_id, reference="TESTREGREQ-%s" % new_id,
) )
def test_triggerStopAcknowledgmentEscalation_matching_regularisation_request(self): #################################################################
# slapos_crm_trigger_stop_acknowledgment_escalation
#################################################################
def test_RegularisationRequest_triggerStopAcknowledgmentEscalation_alarm_matchingRegularisationRequest(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_stop_acknowledgement') ticket.edit(resource='service_module/slapos_crm_stop_acknowledgement')
ticket.validate() ticket.validate()
...@@ -311,7 +645,7 @@ class TestSlapOSCrmTriggerEscalationOnStopAcknowledgmentRegularisationRequest(Sl ...@@ -311,7 +645,7 @@ class TestSlapOSCrmTriggerEscalationOnStopAcknowledgmentRegularisationRequest(Sl
self._test_alarm(alarm, ticket, self._test_alarm(alarm, ticket,
"RegularisationRequest_triggerStopAcknowledgmentEscalation") "RegularisationRequest_triggerStopAcknowledgmentEscalation")
def test_triggerStopAcknowledgmentEscalation_not_suspended(self): def test_RegularisationRequest_triggerStopAcknowledgmentEscalation_alarm_notSuspended(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_stop_acknowledgement') ticket.edit(resource='service_module/slapos_crm_stop_acknowledgement')
ticket.validate() ticket.validate()
...@@ -322,7 +656,7 @@ class TestSlapOSCrmTriggerEscalationOnStopAcknowledgmentRegularisationRequest(Sl ...@@ -322,7 +656,7 @@ class TestSlapOSCrmTriggerEscalationOnStopAcknowledgmentRegularisationRequest(Sl
self._test_alarm_not_visited(alarm, ticket, self._test_alarm_not_visited(alarm, ticket,
"RegularisationRequest_triggerStopAcknowledgmentEscalation") "RegularisationRequest_triggerStopAcknowledgmentEscalation")
def test_triggerStopAcknowledgmentEscalation_not_expected_resource(self): def test_RegularisationRequest_triggerStopAcknowledgmentEscalation_alarm_notExpectedResource(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
ticket.validate() ticket.validate()
ticket.suspend() ticket.suspend()
...@@ -333,6 +667,46 @@ class TestSlapOSCrmTriggerEscalationOnStopAcknowledgmentRegularisationRequest(Sl ...@@ -333,6 +667,46 @@ class TestSlapOSCrmTriggerEscalationOnStopAcknowledgmentRegularisationRequest(Sl
self._test_alarm_not_visited(alarm, ticket, self._test_alarm_not_visited(alarm, ticket,
"RegularisationRequest_triggerStopAcknowledgmentEscalation") "RegularisationRequest_triggerStopAcknowledgmentEscalation")
def test_RegularisationRequest_triggerStopAcknowledgmentEscalation_script_REQUESTdisallowed(self):
ticket = self.createRegularisationRequest()
self.assertRaises(
Unauthorized,
ticket.RegularisationRequest_triggerStopAcknowledgmentEscalation,
REQUEST={})
@simulate('RegularisationRequest_checkToTriggerNextEscalationStep',
'delay_period_in_days, current_service_relative_url, ' \
'next_service_relative_url, title, text_content, comment, ' \
'notification_message=None, substitution_method_parameter_dict=None, ' \
'REQUEST=None',
'context.portal_workflow.doActionFor(' \
'context, action="edit_action", ' \
'comment="Visited by RegularisationRequest_checkToTriggerNextEscalationStep ' \
'%s %s %s %s %s %s %s %s" % (delay_period_in_days, current_service_relative_url, next_service_relative_url, title, text_content, comment, notification_message, substitution_method_parameter_dict))')
def test_RegularisationRequest_triggerStopAcknowledgmentEscalation_script_matchingEvent(self):
ticket = self.createRegularisationRequest()
ticket.RegularisationRequest_triggerStopAcknowledgmentEscalation()
self.assertEqual(
'Visited by RegularisationRequest_checkToTriggerNextEscalationStep ' \
'%s %s %s %s %s %s %s %s' % \
(7,
'service_module/slapos_crm_stop_acknowledgement',
'service_module/slapos_crm_delete_reminder',
'Last reminder: invoice payment requested',
"""Dear user,
We would like to remind you the unpaid invoice you have on %s.
If no payment is done during the coming days, we will delete all your instances.
Regards,
The slapos team
""" % self.portal.portal_preferences.getPreferredSlaposWebSiteUrl(),
'Deleting reminder.',
'slapos-crm.stop.acknowledgment.escalation',
"{'user_name': None, 'days': 7}"),
ticket.workflow_history['edit_workflow'][-1]['comment'])
class TestSlapOSCrmTriggerEscalationOnDeleteReminderRegularisationRequest(SlapOSTestCaseMixinWithAbort): class TestSlapOSCrmTriggerEscalationOnDeleteReminderRegularisationRequest(SlapOSTestCaseMixinWithAbort):
def createRegularisationRequest(self): def createRegularisationRequest(self):
...@@ -343,7 +717,10 @@ class TestSlapOSCrmTriggerEscalationOnDeleteReminderRegularisationRequest(SlapOS ...@@ -343,7 +717,10 @@ class TestSlapOSCrmTriggerEscalationOnDeleteReminderRegularisationRequest(SlapOS
reference="TESTREGREQ-%s" % new_id, reference="TESTREGREQ-%s" % new_id,
) )
def test_triggerDeleteReminderEscalation_matching_regularisation_request(self): #################################################################
# slapos_crm_trigger_delete_reminder_escalation
#################################################################
def test_RegularisationRequest_triggerDeleteReminderEscalation_alarm_matchingRegularisationRequest(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_delete_reminder') ticket.edit(resource='service_module/slapos_crm_delete_reminder')
ticket.validate() ticket.validate()
...@@ -354,7 +731,7 @@ class TestSlapOSCrmTriggerEscalationOnDeleteReminderRegularisationRequest(SlapOS ...@@ -354,7 +731,7 @@ class TestSlapOSCrmTriggerEscalationOnDeleteReminderRegularisationRequest(SlapOS
slapos_crm_trigger_delete_reminder_escalation slapos_crm_trigger_delete_reminder_escalation
self._test_alarm(alarm, ticket, "RegularisationRequest_triggerDeleteReminderEscalation") self._test_alarm(alarm, ticket, "RegularisationRequest_triggerDeleteReminderEscalation")
def test_triggerDeleteReminderEscalation_not_suspended(self): def test_RegularisationRequest_triggerDeleteReminderEscalation_alarm_notSuspended(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_delete_reminder') ticket.edit(resource='service_module/slapos_crm_delete_reminder')
ticket.validate() ticket.validate()
...@@ -364,8 +741,7 @@ class TestSlapOSCrmTriggerEscalationOnDeleteReminderRegularisationRequest(SlapOS ...@@ -364,8 +741,7 @@ class TestSlapOSCrmTriggerEscalationOnDeleteReminderRegularisationRequest(SlapOS
slapos_crm_trigger_delete_reminder_escalation slapos_crm_trigger_delete_reminder_escalation
self._test_alarm_not_visited(alarm, ticket, "RegularisationRequest_triggerDeleteReminderEscalation") self._test_alarm_not_visited(alarm, ticket, "RegularisationRequest_triggerDeleteReminderEscalation")
def test_RegularisationRequest_triggerDeleteReminderEscalation_alarm_notExpectedResource(self):
def test_triggerDeleteReminderEscalation_not_expected_resource(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
ticket.validate() ticket.validate()
ticket.suspend() ticket.suspend()
...@@ -375,6 +751,46 @@ class TestSlapOSCrmTriggerEscalationOnDeleteReminderRegularisationRequest(SlapOS ...@@ -375,6 +751,46 @@ class TestSlapOSCrmTriggerEscalationOnDeleteReminderRegularisationRequest(SlapOS
slapos_crm_trigger_delete_reminder_escalation slapos_crm_trigger_delete_reminder_escalation
self._test_alarm_not_visited(alarm, ticket, "RegularisationRequest_triggerDeleteReminderEscalation") self._test_alarm_not_visited(alarm, ticket, "RegularisationRequest_triggerDeleteReminderEscalation")
def test_RegularisationRequest_triggerDeleteReminderEscalation_script_REQUESTdisallowed(self):
ticket = self.createRegularisationRequest()
self.assertRaises(
Unauthorized,
ticket.RegularisationRequest_triggerDeleteReminderEscalation,
REQUEST={})
@simulate('RegularisationRequest_checkToTriggerNextEscalationStep',
'delay_period_in_days, current_service_relative_url, ' \
'next_service_relative_url, title, text_content, comment, ' \
'notification_message=None, substitution_method_parameter_dict=None, ' \
'REQUEST=None',
'context.portal_workflow.doActionFor(' \
'context, action="edit_action", ' \
'comment="Visited by RegularisationRequest_checkToTriggerNextEscalationStep ' \
'%s %s %s %s %s %s %s %s" % (delay_period_in_days, current_service_relative_url, next_service_relative_url, title, text_content, comment, notification_message, substitution_method_parameter_dict))')
def test_RegularisationRequest_triggerDeleteReminderEscalation_script_matchingEvent(self):
ticket = self.createRegularisationRequest()
ticket.RegularisationRequest_triggerDeleteReminderEscalation()
self.assertEqual(
'Visited by RegularisationRequest_checkToTriggerNextEscalationStep ' \
'%s %s %s %s %s %s %s %s' % \
(10,
'service_module/slapos_crm_delete_reminder',
'service_module/slapos_crm_delete_acknowledgement',
'Acknowledgment: instances deleted',
"""Dear user,
Despite our last reminder, you still have an unpaid invoice on %s.
We will now delete all your instances.
Regards,
The slapos team
""" % self.portal.portal_preferences.getPreferredSlaposWebSiteUrl(),
'Deleting acknowledgment.',
'slapos-crm.delete.reminder.escalation',
"{'user_name': None, 'days': 10}"),
ticket.workflow_history['edit_workflow'][-1]['comment'])
class TestSlapOSCrmStopInstanceTree(SlapOSTestCaseMixinWithAbort): class TestSlapOSCrmStopInstanceTree(SlapOSTestCaseMixinWithAbort):
def createRegularisationRequest(self): def createRegularisationRequest(self):
...@@ -385,7 +801,10 @@ class TestSlapOSCrmStopInstanceTree(SlapOSTestCaseMixinWithAbort): ...@@ -385,7 +801,10 @@ class TestSlapOSCrmStopInstanceTree(SlapOSTestCaseMixinWithAbort):
reference="TESTREGREQ-%s" % new_id, reference="TESTREGREQ-%s" % new_id,
) )
def test_stopInstanceTree_matching_regularisation_request(self): #################################################################
# slapos_crm_trigger_delete_reminder_escalation
#################################################################
def test_RegularisationRequest_stopInstanceTreeList_alarm_matchingRegularisationRequest(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_delete_reminder') ticket.edit(resource='service_module/slapos_crm_delete_reminder')
ticket.validate() ticket.validate()
...@@ -396,7 +815,7 @@ class TestSlapOSCrmStopInstanceTree(SlapOSTestCaseMixinWithAbort): ...@@ -396,7 +815,7 @@ class TestSlapOSCrmStopInstanceTree(SlapOSTestCaseMixinWithAbort):
slapos_crm_stop_instance_tree slapos_crm_stop_instance_tree
self._test_alarm(alarm, ticket, "RegularisationRequest_stopInstanceTreeList") self._test_alarm(alarm, ticket, "RegularisationRequest_stopInstanceTreeList")
def test_stopInstanceTree_matching_regularisation_request_2(self): def test_RegularisationRequest_stopInstanceTreeList_alarm_matchingRegularisationRequest2(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_stop_acknowledgement') ticket.edit(resource='service_module/slapos_crm_stop_acknowledgement')
ticket.validate() ticket.validate()
...@@ -407,7 +826,7 @@ class TestSlapOSCrmStopInstanceTree(SlapOSTestCaseMixinWithAbort): ...@@ -407,7 +826,7 @@ class TestSlapOSCrmStopInstanceTree(SlapOSTestCaseMixinWithAbort):
slapos_crm_stop_instance_tree slapos_crm_stop_instance_tree
self._test_alarm(alarm, ticket, "RegularisationRequest_stopInstanceTreeList") self._test_alarm(alarm, ticket, "RegularisationRequest_stopInstanceTreeList")
def test_stopInstanceTree_not_suspended(self): def test_RegularisationRequest_stopInstanceTreeList_alarm_notSuspended(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_stop_acknowledgement') ticket.edit(resource='service_module/slapos_crm_stop_acknowledgement')
ticket.validate() ticket.validate()
...@@ -417,8 +836,7 @@ class TestSlapOSCrmStopInstanceTree(SlapOSTestCaseMixinWithAbort): ...@@ -417,8 +836,7 @@ class TestSlapOSCrmStopInstanceTree(SlapOSTestCaseMixinWithAbort):
slapos_crm_stop_instance_tree slapos_crm_stop_instance_tree
self._test_alarm_not_visited(alarm, ticket, "RegularisationRequest_stopInstanceTreeList") self._test_alarm_not_visited(alarm, ticket, "RegularisationRequest_stopInstanceTreeList")
def test_RegularisationRequest_stopInstanceTreeList_alarm_otherResource(self):
def test_stopInstanceTree_other_resource(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_acknowledgement') ticket.edit(resource='service_module/slapos_acknowledgement')
ticket.validate() ticket.validate()
...@@ -429,6 +847,183 @@ class TestSlapOSCrmStopInstanceTree(SlapOSTestCaseMixinWithAbort): ...@@ -429,6 +847,183 @@ class TestSlapOSCrmStopInstanceTree(SlapOSTestCaseMixinWithAbort):
slapos_crm_stop_instance_tree slapos_crm_stop_instance_tree
self._test_alarm_not_visited(alarm, ticket, "RegularisationRequest_stopInstanceTreeList") self._test_alarm_not_visited(alarm, ticket, "RegularisationRequest_stopInstanceTreeList")
def createInstanceTree(self):
new_id = self.generateNewId()
instance_tree = self.portal.instance_tree_module\
.newContent(portal_type="Instance Tree")
instance_tree.edit(
reference="TESTHS-%s" % new_id,
)
instance_tree.validate()
self.portal.portal_workflow._jumpToStateFor(
instance_tree, 'start_requested')
return instance_tree
def test_RegularisationRequest_stopInstanceTreeList_script_REQUESTdisallowed(self):
ticket = self.createRegularisationRequest()
self.assertRaises(
Unauthorized,
ticket.RegularisationRequest_stopInstanceTreeList,
'footag',
REQUEST={})
@simulate('InstanceTree_stopFromRegularisationRequest',
'person, REQUEST=None',
'context.portal_workflow.doActionFor(' \
'context, action="edit_action", ' \
'comment="Visited by InstanceTree_stopFromRegularisationRequest ' \
'%s" % (person))')
def test_RegularisationRequest_stopInstanceTreeList_script_matchingSubscription(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest()
instance_tree = self.createInstanceTree()
ticket.edit(
destination_decision_value=person,
resource='service_module/slapos_crm_stop_acknowledgement',
)
ticket.validate()
ticket.suspend()
instance_tree.edit(
destination_section=person.getRelativeUrl(),
)
self.tic()
result = ticket.\
RegularisationRequest_stopInstanceTreeList('footag')
self.assertTrue(result)
self.tic()
self.assertEqual(
'Visited by InstanceTree_stopFromRegularisationRequest ' \
'%s' % person.getRelativeUrl(),
instance_tree.workflow_history['edit_workflow'][-1]['comment'])
@simulate('InstanceTree_stopFromRegularisationRequest',
'person, REQUEST=None',
'context.portal_workflow.doActionFor(' \
'context, action="edit_action", ' \
'comment="Visited by InstanceTree_stopFromRegularisationRequest ' \
'%s" % (person))')
def test_RegularisationRequest_stopInstanceTreeList_script_matchingSubscription2(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest()
instance_tree = self.createInstanceTree()
ticket.edit(
destination_decision_value=person,
resource='service_module/slapos_crm_delete_reminder',
)
ticket.validate()
ticket.suspend()
instance_tree.edit(
destination_section=person.getRelativeUrl(),
)
self.tic()
result = ticket.\
RegularisationRequest_stopInstanceTreeList('footag')
self.assertTrue(result)
self.tic()
self.assertEqual(
'Visited by InstanceTree_stopFromRegularisationRequest ' \
'%s' % person.getRelativeUrl(),
instance_tree.workflow_history['edit_workflow'][-1]['comment'])
@simulate('InstanceTree_stopFromRegularisationRequest',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
def test_RegularisationRequest_stopInstanceTreeList_script_otherSubscription(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest()
self.createInstanceTree()
ticket.edit(
destination_decision_value=person,
resource='service_module/slapos_crm_stop_acknowledgement',
)
ticket.validate()
ticket.suspend()
self.tic()
result = ticket.\
RegularisationRequest_stopInstanceTreeList('footag')
self.assertTrue(result)
self.tic()
@simulate('InstanceTree_stopFromRegularisationRequest',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
def test_RegularisationRequest_stopInstanceTreeList_script_noPerson(self):
ticket = self.createRegularisationRequest()
ticket.edit(
resource='service_module/slapos_crm_stop_acknowledgement',
)
ticket.validate()
ticket.suspend()
self.tic()
result = ticket.\
RegularisationRequest_stopInstanceTreeList('footag')
self.assertFalse(result)
self.tic()
@simulate('InstanceTree_stopFromRegularisationRequest',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
def test_RegularisationRequest_stopInstanceTreeList_script_notSuspended(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest()
self.createInstanceTree()
ticket.edit(
destination_decision_value=person,
resource='service_module/slapos_crm_stop_acknowledgement',
)
ticket.validate()
self.tic()
result = ticket.\
RegularisationRequest_stopInstanceTreeList('footag')
self.assertFalse(result)
self.tic()
@simulate('InstanceTree_stopFromRegularisationRequest',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
def test_RegularisationRequest_stopInstanceTreeList_script_otherResource(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest()
self.createInstanceTree()
ticket.edit(
destination_decision_value=person,
resource='service_module/slapos_crm_acknowledgement',
)
ticket.validate()
ticket.suspend()
self.tic()
result = ticket.\
RegularisationRequest_stopInstanceTreeList('footag')
self.assertFalse(result)
self.tic()
class TestSlapOSCrmDeleteInstanceTree(SlapOSTestCaseMixinWithAbort): class TestSlapOSCrmDeleteInstanceTree(SlapOSTestCaseMixinWithAbort):
...@@ -438,9 +1033,13 @@ class TestSlapOSCrmDeleteInstanceTree(SlapOSTestCaseMixinWithAbort): ...@@ -438,9 +1033,13 @@ class TestSlapOSCrmDeleteInstanceTree(SlapOSTestCaseMixinWithAbort):
portal_type='Regularisation Request', portal_type='Regularisation Request',
title="Test Reg. Req.%s" % new_id, title="Test Reg. Req.%s" % new_id,
reference="TESTREGREQ-%s" % new_id, reference="TESTREGREQ-%s" % new_id,
resource='foo/bar',
) )
def test_deleteInstanceTree_matching_regularisation_request(self): #################################################################
# slapos_crm_delete_instance_tree
#################################################################
def test_RegularisationRequest_deleteInstanceTreeList_alarm_matchingRegularisationRequest(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_delete_acknowledgement') ticket.edit(resource='service_module/slapos_crm_delete_acknowledgement')
ticket.validate() ticket.validate()
...@@ -451,7 +1050,7 @@ class TestSlapOSCrmDeleteInstanceTree(SlapOSTestCaseMixinWithAbort): ...@@ -451,7 +1050,7 @@ class TestSlapOSCrmDeleteInstanceTree(SlapOSTestCaseMixinWithAbort):
slapos_crm_delete_instance_tree slapos_crm_delete_instance_tree
self._test_alarm(alarm, ticket, "RegularisationRequest_deleteInstanceTreeList") self._test_alarm(alarm, ticket, "RegularisationRequest_deleteInstanceTreeList")
def test_deleteInstanceTree_not_suspended(self): def test_RegularisationRequest_deleteInstanceTreeList_alarm_notSuspended(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_delete_acknowledgement') ticket.edit(resource='service_module/slapos_crm_delete_acknowledgement')
ticket.validate() ticket.validate()
...@@ -461,8 +1060,7 @@ class TestSlapOSCrmDeleteInstanceTree(SlapOSTestCaseMixinWithAbort): ...@@ -461,8 +1060,7 @@ class TestSlapOSCrmDeleteInstanceTree(SlapOSTestCaseMixinWithAbort):
slapos_crm_delete_instance_tree slapos_crm_delete_instance_tree
self._test_alarm_not_visited(alarm, ticket, "RegularisationRequest_deleteInstanceTreeList") self._test_alarm_not_visited(alarm, ticket, "RegularisationRequest_deleteInstanceTreeList")
def test_RegularisationRequest_deleteInstanceTreeList_alarm_otherResource(self):
def test_deleteInstanceTree_other_resource(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_delete_reminder') ticket.edit(resource='service_module/slapos_crm_delete_reminder')
ticket.validate() ticket.validate()
...@@ -473,22 +1071,167 @@ class TestSlapOSCrmDeleteInstanceTree(SlapOSTestCaseMixinWithAbort): ...@@ -473,22 +1071,167 @@ class TestSlapOSCrmDeleteInstanceTree(SlapOSTestCaseMixinWithAbort):
slapos_crm_delete_instance_tree slapos_crm_delete_instance_tree
self._test_alarm_not_visited(alarm, ticket, "RegularisationRequest_deleteInstanceTreeList") self._test_alarm_not_visited(alarm, ticket, "RegularisationRequest_deleteInstanceTreeList")
def createInstanceTree(self):
new_id = self.generateNewId()
instance_tree = self.portal.instance_tree_module\
.newContent(portal_type="Instance Tree")
instance_tree.edit(
reference="TESTHS-%s" % new_id,
)
instance_tree.validate()
self.portal.portal_workflow._jumpToStateFor(
instance_tree, 'start_requested')
return instance_tree
def test_RegularisationRequest_deleteInstanceTreeList_script_REQUESTdisallowed(self):
ticket = self.createRegularisationRequest()
self.assertRaises(
Unauthorized,
ticket.RegularisationRequest_deleteInstanceTreeList,
'footag',
REQUEST={})
@simulate('InstanceTree_deleteFromRegularisationRequest',
'person, REQUEST=None',
'context.portal_workflow.doActionFor(' \
'context, action="edit_action", ' \
'comment="Visited by InstanceTree_deleteFromRegularisationRequest ' \
'%s" % (person))')
def test_RegularisationRequest_deleteInstanceTreeList_script_matchingSubscription(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest()
instance_tree = self.createInstanceTree()
ticket.edit(
destination_decision_value=person,
resource='service_module/slapos_crm_delete_acknowledgement',
)
ticket.validate()
ticket.suspend()
instance_tree.edit(
destination_section=person.getRelativeUrl(),
)
self.tic()
result = ticket.\
RegularisationRequest_deleteInstanceTreeList('footag')
self.assertTrue(result)
self.tic()
self.assertEqual(
'Visited by InstanceTree_deleteFromRegularisationRequest ' \
'%s' % person.getRelativeUrl(),
instance_tree.workflow_history['edit_workflow'][-1]['comment'])
@simulate('InstanceTree_deleteFromRegularisationRequest',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
def test_RegularisationRequest_deleteInstanceTreeList_script_otherSubscription(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest()
self.createInstanceTree()
ticket.edit(
destination_decision_value=person,
resource='service_module/slapos_crm_delete_acknowledgement',
)
ticket.validate()
ticket.suspend()
self.tic()
result = ticket.\
RegularisationRequest_deleteInstanceTreeList('footag')
self.assertTrue(result)
self.tic()
@simulate('InstanceTree_deleteFromRegularisationRequest',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
def test_RegularisationRequest_deleteInstanceTreeList_script_noPerson(self):
ticket = self.createRegularisationRequest()
ticket.edit(
resource='service_module/slapos_crm_delete_acknowledgement',
)
ticket.validate()
ticket.suspend()
self.tic()
result = ticket.\
RegularisationRequest_deleteInstanceTreeList('footag')
self.assertFalse(result)
self.tic()
@simulate('InstanceTree_deleteFromRegularisationRequest',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
def test_RegularisationRequest_deleteInstanceTreeList_script_notSuspended(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest()
self.createInstanceTree()
ticket.edit(
destination_decision_value=person,
resource='service_module/slapos_crm_delete_acknowledgement',
)
ticket.validate()
self.tic()
result = ticket.\
RegularisationRequest_deleteInstanceTreeList('footag')
self.assertFalse(result)
self.tic()
@simulate('InstanceTree_deleteFromRegularisationRequest',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
def test_RegularisationRequest_deleteInstanceTreeList_script_otherResource(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest()
self.createInstanceTree()
ticket.edit(
destination_decision_value=person,
resource='service_module/slapos_crm_delete_reminder',
)
ticket.validate()
ticket.suspend()
self.tic()
result = ticket.\
RegularisationRequest_deleteInstanceTreeList('footag')
self.assertFalse(result)
self.tic()
class TestSlapOSCrmMonitoringCheckComputeNodeState(SlapOSTestCaseMixinWithAbort): class TestSlapOSCrmMonitoringCheckComputeNodeState(SlapOSTestCaseMixinWithAbort):
def test_checkComputeNodeState_public_compute_node_state(self): #################################################################
# slapos_crm_check_compute_node_state
#################################################################
def test_ComputeNode_checkState_alarm_monitoredComputeNodeState(self):
self._makeComputeNode(self.addProject()) self._makeComputeNode(self.addProject())
self.compute_node.edit(allocation_scope='open')
self.tic() self.tic()
self.assertEqual(self.compute_node.getMonitorScope(), "enabled") self.assertEqual(self.compute_node.getMonitorScope(), "enabled")
self.tic()
alarm = self.portal.portal_alarms.\ alarm = self.portal.portal_alarms.\
slapos_crm_check_compute_node_state slapos_crm_check_compute_node_state
self._test_alarm(alarm, self.compute_node, "ComputeNode_checkState") self._test_alarm(alarm, self.compute_node, "ComputeNode_checkState")
def _test_alarm_check_compute_node_state_selected(self, allocation_scope, def _test_alarm_check_compute_node_state_selected(self, allocation_scope,
monitor_scope=None): monitor_scope=None):
self._makeComputeNode() self._makeComputeNode(self.addProject())
self.compute_node.edit(allocation_scope=allocation_scope) self.compute_node.edit(allocation_scope=allocation_scope)
self.tic() self.tic()
if monitor_scope is not None: if monitor_scope is not None:
...@@ -512,115 +1255,517 @@ class TestSlapOSCrmMonitoringCheckComputeNodeState(SlapOSTestCaseMixinWithAbort) ...@@ -512,115 +1255,517 @@ class TestSlapOSCrmMonitoringCheckComputeNodeState(SlapOSTestCaseMixinWithAbort)
slapos_crm_check_compute_node_state slapos_crm_check_compute_node_state
self._test_alarm_not_visited(alarm, self.compute_node, "ComputeNode_checkState") self._test_alarm_not_visited(alarm, self.compute_node, "ComputeNode_checkState")
def test_checkComputeNodeState_compute_node_state_on_public_compute_node_with_monitor_scope_disabled(self): def test_ComputeNode_checkState_alarm_openAllocationAndDisabledMonitor(self):
self._test_checkComputeNodeState_compute_node_state_not_selected( self._test_checkComputeNodeState_compute_node_state_not_selected(
allocation_scope='open', allocation_scope='open',
monitor_scope="disabled") monitor_scope="disabled")
def test_checkComputeNodeState_compute_node_state_closed_forever_compute_node(self): def test_ComputeNode_checkState_alarm_closedForeverAllocation(self):
self._test_checkComputeNodeState_compute_node_state_not_selected( self._test_checkComputeNodeState_compute_node_state_not_selected(
allocation_scope='closed/forever') allocation_scope='close/forever')
def test_checkComputeNodeState_compute_node_state_closed_mantainence_compute_node(self): def test_ComputeNode_checkState_alarm_closedMaintainanceAllocation(self):
self._test_checkComputeNodeState_compute_node_state_not_selected( self._test_alarm_check_compute_node_state_selected(
allocation_scope='closed/maintenance') allocation_scope='close/maintenance')
def test_checkComputeNodeState_compute_node_state_closed_termination_compute_node(self): def test_ComputeNode_checkState_alarm_closedTerminationAllocation(self):
self._test_checkComputeNodeState_compute_node_state_not_selected( self._test_alarm_check_compute_node_state_selected(
allocation_scope='closed/termination') allocation_scope='close/termination')
def test_alarm_check_compute_node_state_closed_noallocation_compute_node(self): def test_ComputeNode_checkState_alarm_closedNoAllocation(self):
self._test_alarm_check_compute_node_state_selected( self._test_alarm_check_compute_node_state_selected(
allocation_scope='close/noallocation') allocation_scope='close/noallocation')
@simulate('ERP5Site_isSupportRequestCreationClosed', '*args, **kwargs','return 0')
def test_ComputeNode_checkState_script_oldAccessStatus(self):
compute_node, _ = self._makeComputeNode(self.addProject())
try:
d = DateTime() - 1.1
self.pinDateTime(d)
compute_node.setAccessStatus("")
finally:
self.unpinDateTime()
compute_node_support_request = compute_node.ComputeNode_checkState()
self.assertNotEqual(compute_node_support_request, None)
self.assertIn("[MONITORING] Lost contact with compute_node",
compute_node_support_request.getTitle())
self.assertIn("has not contacted the server for more than 30 minutes",
compute_node_support_request.getDescription())
self.assertIn(d.strftime("%Y/%m/%d %H:%M:%S"),
compute_node_support_request.getDescription())
@simulate('ERP5Site_isSupportRequestCreationClosed', '*args, **kwargs','return 0')
def test_ComputeNode_checkState_script_noAccessStatus(self):
compute_node, _ = self._makeComputeNode(self.addProject())
compute_node_support_request = compute_node.ComputeNode_checkState()
self.assertNotEqual(compute_node_support_request, None)
self.assertIn("[MONITORING] Lost contact with compute_node",
compute_node_support_request.getTitle())
self.assertIn("has not contacted the server (No Contact Information)",
compute_node_support_request.getDescription())
def _makeNotificationMessage(self, reference):
notification_message = self.portal.notification_message_module.newContent(
portal_type="Notification Message",
title='The Compute Node %s has not contacted the server for more than 24 hours' % reference,
text_content='Test NM content<br/>%s<br/>' % reference,
content_type='text/html',
)
return notification_message.getRelativeUrl()
def _getGeneratedSupportRequest(self, compute_node_uid, request_title):
support_request = self.portal.portal_catalog.getResultValue(
portal_type='Support Request',
title=request_title,
simulation_state='validated',
causality__uid=compute_node_uid
)
return support_request
@simulate('ERP5Site_isSupportRequestCreationClosed', '*args, **kwargs','return 0')
@simulate('NotificationTool_getDocumentValue',
'reference=None, **kw',
'assert reference == "slapos-crm-compute_node_check_state.notification", reference\n' \
'return context.restrictedTraverse(' \
'context.REQUEST["test_ComputeNode_checkState_notify"])')
def test_ComputeNode_checkState_script_notify(self):
compute_node, _ = self._makeComputeNode(self.addProject())
try:
self.pinDateTime(DateTime()-1.1)
compute_node.setAccessStatus("")
finally:
self.unpinDateTime()
self.portal.REQUEST['test_ComputeNode_checkState_notify'] = \
self._makeNotificationMessage(compute_node.getReference())
compute_node.ComputeNode_checkState()
self.tic()
ticket_title = "[MONITORING] Lost contact with compute_node %s" % compute_node.getReference()
ticket = self._getGeneratedSupportRequest(compute_node.getUid(), ticket_title)
self.assertNotEqual(ticket, None)
event_list = ticket.getFollowUpRelatedValueList()
self.assertEqual(len(event_list), 1)
event = event_list[0]
self.assertEqual(
event.getTitle(),
self.portal.restrictedTraverse(
self.portal.REQUEST['test_ComputeNode_checkState_notify']
).getTitle()
)
self.assertIn(compute_node.getReference(), event.getTextContent())
self.assertEqual(event.getFollowUp(), ticket.getRelativeUrl())
self.assertEqual(event.getSourceProject(), compute_node.getFollowUp())
self.assertEqual(ticket.getSourceProject(), compute_node.getFollowUp())
self.assertEqual(ticket.getCausality(), compute_node.getRelativeUrl())
self.assertEqual(ticket.getSimulationState(), "validated")
self.assertEqual(event.getSimulationState(), "delivered")
self.assertEqual(event.getPortalType(), "Web Message")
@simulate('ERP5Site_isSupportRequestCreationClosed', '*args, **kwargs','return 0')
@simulate('NotificationTool_getDocumentValue',
'reference=None, **kw',
'assert reference == "slapos-crm-compute_node_check_state.notification"\n' \
'return context.restrictedTraverse(' \
'context.REQUEST["test_ComputeNode_checkState_empty_cache_notify"])')
def test_ComputeNode_checkState_script_emptyCacheNotify(self):
compute_node, _ = self._makeComputeNode(self.addProject())
self.portal.REQUEST['test_ComputeNode_checkState_empty_cache_notify'] = \
self._makeNotificationMessage(compute_node.getReference())
compute_node.ComputeNode_checkState()
self.tic()
ticket_title = "[MONITORING] Lost contact with compute_node %s" % compute_node.getReference()
ticket = self._getGeneratedSupportRequest(compute_node.getUid(), ticket_title)
self.assertNotEqual(ticket, None)
event_list = ticket.getFollowUpRelatedValueList()
self.assertEqual(len(event_list), 1)
event = event_list[0]
self.assertEqual(
event.getTitle(),
self.portal.restrictedTraverse(
self.portal.REQUEST['test_ComputeNode_checkState_empty_cache_notify']
).getTitle()
)
self.assertIn(compute_node.getReference(), event.getTextContent())
self.assertEqual(event.getFollowUp(), ticket.getRelativeUrl())
self.assertEqual(event.getSourceProject(), compute_node.getFollowUp())
self.assertEqual(ticket.getSourceProject(), compute_node.getFollowUp())
self.assertEqual(ticket.getCausality(), compute_node.getRelativeUrl())
self.assertEqual(ticket.getSimulationState(), "validated")
self.assertEqual(event.getSimulationState(), "delivered")
self.assertEqual(event.getPortalType(), "Web Message")
@simulate('ERP5Site_isSupportRequestCreationClosed', '*args, **kwargs','return 0')
@simulate('NotificationTool_getDocumentValue',
'reference=None, **kw',
'assert reference == "slapos-crm-compute_node_check_stalled_instance_state.notification", reference\n' \
'return context.restrictedTraverse(' \
'context.REQUEST["test_ComputeNode_checkState_stalled_instance"])')
def test_ComputeNode_checkState_script_stalledInstance(self):
compute_node, _ = self._makeComputeNode(self.addProject())
self._makeComplexComputeNode(self.addProject())
compute_node = self.compute_node
self.portal.REQUEST['test_ComputeNode_checkState_stalled_instance'] = \
self._makeNotificationMessage(compute_node.getReference())
# Computer is getting access
compute_node.setAccessStatus("")
try:
self.pinDateTime(DateTime()-1.1)
self.start_requested_software_instance.setAccessStatus("")
finally:
self.unpinDateTime()
compute_node.ComputeNode_checkState()
self.tic()
ticket_title = "[MONITORING] Compute Node %s has a stalled instance process" % compute_node.getReference()
ticket = self._getGeneratedSupportRequest(compute_node.getUid(), ticket_title)
self.assertNotEqual(ticket, None)
event_list = ticket.getFollowUpRelatedValueList()
self.assertEqual(len(event_list), 1)
event = event_list[0]
self.assertEqual(
event.getTitle(),
self.portal.restrictedTraverse(
self.portal.REQUEST['test_ComputeNode_checkState_stalled_instance']
).getTitle()
)
self.assertIn(compute_node.getReference(), event.getTextContent())
self.assertEqual(event.getFollowUp(), ticket.getRelativeUrl())
self.assertEqual(event.getSourceProject(), compute_node.getFollowUp())
self.assertEqual(ticket.getSourceProject(), compute_node.getFollowUp())
self.assertEqual(ticket.getCausality(), compute_node.getRelativeUrl())
self.assertEqual(ticket.getSimulationState(), "validated")
self.assertEqual(event.getSimulationState(), "delivered")
self.assertEqual(event.getPortalType(), "Web Message")
@simulate('ERP5Site_isSupportRequestCreationClosed', '*args, **kwargs','return 0')
@simulate('NotificationTool_getDocumentValue',
'reference=None, **kw',
'assert reference == "slapos-crm-compute_node_check_stalled_instance_state.notification", reference\n' \
'return context.restrictedTraverse(' \
'context.REQUEST["test_ComputeNode_checkState_stalled_instance"])')
def test_ComputeNode_checkState_script_stalledInstanceSingle(self):
compute_node, _ = self._makeComputeNode(self.addProject())
self._makeComplexComputeNode(self.addProject())
compute_node = self.compute_node
self.portal.REQUEST['test_ComputeNode_checkState_stalled_instance'] = \
self._makeNotificationMessage(compute_node.getReference())
# Computer is getting access
compute_node.setAccessStatus("")
try:
self.pinDateTime(DateTime()-1.1)
self.start_requested_software_instance.setAccessStatus("")
self.start_requested_software_installation.setAccessStatus("")
finally:
self.unpinDateTime()
compute_node.ComputeNode_checkState()
self.tic()
ticket_title = "[MONITORING] Compute Node %s has a stalled instance process" % compute_node.getReference()
ticket = self._getGeneratedSupportRequest(compute_node.getUid(), ticket_title)
self.assertNotEqual(ticket, None)
event_list = ticket.getFollowUpRelatedValueList()
self.assertEqual(len(event_list), 1)
event = event_list[0]
self.assertEqual(
event.getTitle(),
self.portal.restrictedTraverse(
self.portal.REQUEST['test_ComputeNode_checkState_stalled_instance']
).getTitle()
)
self.assertIn(compute_node.getReference(), event.getTextContent())
self.assertEqual(event.getFollowUp(), ticket.getRelativeUrl())
self.assertEqual(event.getSourceProject(), compute_node.getFollowUp())
self.assertEqual(ticket.getSourceProject(), compute_node.getFollowUp())
self.assertEqual(ticket.getCausality(), compute_node.getRelativeUrl())
self.assertEqual(ticket.getSimulationState(), "validated")
self.assertEqual(event.getSimulationState(), "delivered")
self.assertEqual(event.getPortalType(), "Web Message")
class TestSlapOSCrmMonitoringCheckComputeNodeSoftwareInstallation(SlapOSTestCaseMixinWithAbort): class TestSlapOSCrmMonitoringCheckComputeNodeSoftwareInstallation(SlapOSTestCaseMixinWithAbort):
def test_checkSoftwareInstallationState_run_on_open_public(self): #################################################################
# slapos_crm_check_software_installation_state
#################################################################
def test_ComputeNode_checkSoftwareInstallationState_alarm_monitorEnabled(self):
self._makeComputeNode(self.addProject()) self._makeComputeNode(self.addProject())
self.compute_node.edit(allocation_scope = 'open') self.compute_node.edit(monitor_scope="enabled")
self.tic() self.tic()
alarm = self.portal.portal_alarms.\ alarm = self.portal.portal_alarms.\
slapos_crm_check_software_installation_state slapos_crm_check_software_installation_state
self._test_alarm(alarm, self.compute_node, "ComputeNode_checkSoftwareInstallationState") self._test_alarm(alarm, self.compute_node, "ComputeNode_checkSoftwareInstallationState")
def test_checkSoftwareInstallationState_dont_run_on_open_public_with_monitor_scope_disabled(self): def test_ComputeNode_checkSoftwareInstallationState_alarm_invalidated(self):
self._makeComputeNode(self.addProject()) self._makeComputeNode(self.addProject())
self.compute_node.edit(allocation_scope = 'open') self.compute_node.edit(monitor_scope="enabled")
self.tic() self.compute_node.invalidate()
self.compute_node.edit(monitor_scope = 'disabled')
self.tic() self.tic()
alarm = self.portal.portal_alarms.\ alarm = self.portal.portal_alarms.\
slapos_crm_check_software_installation_state slapos_crm_check_software_installation_state
self._test_alarm_not_visited(alarm, self.compute_node, "ComputeNode_checkSoftwareInstallationState") self._test_alarm_not_visited(alarm, self.compute_node, "ComputeNode_checkSoftwareInstallationState")
def _test_checkSoftwareInstallationState_not_run_on_close(self, allocation_scope): def test_ComputeNode_checkSoftwareInstallationState_alarm_monitorDisabled(self):
self._makeComputeNode(self.addProject()) self._makeComputeNode(self.addProject())
self.compute_node.edit(allocation_scope=allocation_scope) self.compute_node.edit(monitor_scope="disabled")
self.tic()
if monitor_scope is not None:
self.compute_node.edit(monitor_scope=monitor_scope)
self.tic() self.tic()
alarm = self.portal.portal_alarms.\ alarm = self.portal.portal_alarms.\
slapos_crm_check_software_installation_state slapos_crm_check_software_installation_state
self._test_alarm_not_visited(alarm, self.compute_node, "ComputeNode_checkSoftwareInstallationState") self._test_alarm_not_visited(alarm, self.compute_node, "ComputeNode_checkSoftwareInstallationState")
def _test_alarm_run_on_close(self, allocation_scope,): def _makeNotificationMessage(self, reference):
self._makeComputeNode() notification_message = self.portal.notification_message_module.newContent(
self.compute_node.edit(allocation_scope=allocation_scope) portal_type="Notification Message",
self.tic() title='The Compute Node %s is building for too long' % reference,
text_content='Test NM content<br/>%s<br/>' % reference,
content_type='text/html',
)
return notification_message.getRelativeUrl()
def _getGeneratedSupportRequest(self, compute_node_uid, request_title):
return self.portal.portal_catalog.getResultValue(
portal_type='Support Request',
title=request_title,
simulation_state='validated',
causality__uid=compute_node_uid
)
alarm = self.portal.portal_alarms.\ @simulate('ERP5Site_isSupportRequestCreationClosed', '*args, **kwargs','return 0')
slapos_crm_check_software_installation_state @simulate('NotificationTool_getDocumentValue',
self._test_alarm(alarm, self.compute_node, "ComputeNode_checkSoftwareInstallationState") 'reference=None, **kw',
'assert reference == "slapos-crm-compute_node_software_installation_state.notification", reference\n' \
'return context.restrictedTraverse(' \
'context.REQUEST["test_ComputeNode_checkSoftwareInstallationState_notify"])')
def test_ComputeNode_checkSoftwareInstallationState_script_notifyNoInformation(self):
try:
self.pinDateTime(DateTime()-1.1)
compute_node, _ = self._makeComputeNode(self.addProject())
self._makeComplexComputeNode(self.addProject())
compute_node = self.compute_node
finally:
self.unpinDateTime()
def test_alarm_not_run_on_close_forever(self): self.tic()
self._test_alarm_not_run_on_close('close/forever') self.portal.REQUEST['test_ComputeNode_checkSoftwareInstallationState_notify'] = \
self._makeNotificationMessage(compute_node.getReference())
def test_alarm_not_run_on_close_maintainence(self): compute_node.ComputeNode_checkSoftwareInstallationState()
self._test_alarm_not_run_on_close('close/maintenence', monitor_scope="disabled") self.tic()
def test_alarm_not_run_on_close_outdated(self): ticket_title = "[MONITORING] No information for %s on %s" % (
self._test_alarm_not_run_on_close('close/outdated', monitor_scope="disabled") self.start_requested_software_installation.getReference(),
compute_node.getReference()
)
if 0:
raise NotImplementedError(ticket_title)
ticket = self._getGeneratedSupportRequest(compute_node.getUid(), ticket_title)
self.assertNotEqual(ticket, None)
event_list = ticket.getFollowUpRelatedValueList()
self.assertEqual(len(event_list), 1)
event = event_list[0]
self.assertEqual(
event.getTitle(),
self.portal.restrictedTraverse(
self.portal.REQUEST['test_ComputeNode_checkSoftwareInstallationState_notify']
).getTitle()
)
self.assertIn(compute_node.getReference(), event.getTextContent())
self.assertEqual(event.getFollowUp(), ticket.getRelativeUrl())
self.assertEqual(event.getSourceProject(), compute_node.getFollowUp())
self.assertEqual(ticket.getSourceProject(), compute_node.getFollowUp())
self.assertEqual(ticket.getCausality(), compute_node.getRelativeUrl())
self.assertEqual(ticket.getSimulationState(), "validated")
self.assertEqual(event.getSimulationState(), "delivered")
self.assertEqual(event.getPortalType(), "Web Message")
@simulate('ERP5Site_isSupportRequestCreationClosed', '*args, **kwargs','return 0')
@simulate('NotificationTool_getDocumentValue',
'reference=None, **kw',
'assert reference == "slapos-crm-compute_node_software_installation_state.notification", reference\n' \
'return context.restrictedTraverse(' \
'context.REQUEST["test_ComputeNode_checkSoftwareInstallationState_notify"])')
def test_ComputeNode_checkSoftwareInstallationState_script_notifySlow(self):
try:
self.pinDateTime(DateTime()-1.1)
compute_node, _ = self._makeComputeNode(self.addProject())
self._makeComplexComputeNode(self.addProject())
compute_node = self.compute_node
finally:
self.unpinDateTime()
self.start_requested_software_installation.setBuildingStatus("building")
self.tic()
self.portal.REQUEST['test_ComputeNode_checkSoftwareInstallationState_notify'] = \
self._makeNotificationMessage(compute_node.getReference())
def test_alarm_not_run_on_close_termination(self): compute_node.ComputeNode_checkSoftwareInstallationState()
self._test_alarm_not_run_on_close('close/termination', monitor_scope="disabled") self.tic()
def test_alarm_not_run_on_close_noallocation(self): ticket_title = "[MONITORING] %s is building for too long on %s" % (
self._test_alarm_not_run_on_close('close/noallocation', monitor_scope="disabled") self.start_requested_software_installation.getReference(),
compute_node.getReference()
)
ticket = self._getGeneratedSupportRequest(compute_node.getUid(), ticket_title)
self.assertNotEqual(ticket, None)
event_list = ticket.getFollowUpRelatedValueList()
self.assertEqual(len(event_list), 1)
event = event_list[0]
self.assertEqual(
event.getTitle(),
self.portal.restrictedTraverse(
self.portal.REQUEST['test_ComputeNode_checkSoftwareInstallationState_notify']
).getTitle()
)
self.assertIn(compute_node.getReference(), event.getTextContent())
self.assertEqual(event.getFollowUp(), ticket.getRelativeUrl())
self.assertEqual(event.getSourceProject(), compute_node.getFollowUp())
self.assertEqual(ticket.getSourceProject(), compute_node.getFollowUp())
self.assertEqual(ticket.getCausality(), compute_node.getRelativeUrl())
self.assertEqual(ticket.getSimulationState(), "validated")
self.assertEqual(event.getSimulationState(), "delivered")
self.assertEqual(event.getPortalType(), "Web Message")
@simulate('ERP5Site_isSupportRequestCreationClosed', '*args, **kwargs','return 0')
@simulate('NotificationTool_getDocumentValue',
'reference=None, **kw',
'assert reference == "slapos-crm-compute_node_software_installation_state.notification", reference\n' \
'return context.restrictedTraverse(' \
'context.REQUEST["test_ComputeNode_checkSoftwareInstallationState_notify"])')
def test_ComputeNode_checkSoftwareInstallationState_script_recentBuild(self):
compute_node, _ = self._makeComputeNode(self.addProject())
self._makeComplexComputeNode(self.addProject())
compute_node = self.compute_node
self.start_requested_software_installation.setBuildingStatus("building")
self.tic()
self.portal.REQUEST['test_ComputeNode_checkSoftwareInstallationState_notify'] = \
self._makeNotificationMessage(compute_node.getReference())
def test_alarm_run_on_close_maintainence(self): compute_node.ComputeNode_checkSoftwareInstallationState()
self._test_alarm_run_on_close('close/maintenence') self.tic()
def test_alarm_run_on_close_outdated(self): ticket_title = "[MONITORING] %s is building for too long on %s" % (
self._test_alarm_run_on_close('close/outdated') self.start_requested_software_installation.getReference(),
compute_node.getReference()
)
ticket = self._getGeneratedSupportRequest(compute_node.getUid(), ticket_title)
self.assertEqual(ticket, None)
@simulate('ERP5Site_isSupportRequestCreationClosed', '*args, **kwargs','return 0')
@simulate('NotificationTool_getDocumentValue',
'reference=None, **kw',
'assert reference == "slapos-crm-compute_node_software_installation_state.notification", reference\n' \
'return context.restrictedTraverse(' \
'context.REQUEST["test_ComputeNode_checkSoftwareInstallationState_notify"])')
def test_ComputeNode_checkSoftwareInstallationState_script_notifyError(self):
try:
self.pinDateTime(DateTime()-1.1)
compute_node, _ = self._makeComputeNode(self.addProject())
self._makeComplexComputeNode(self.addProject())
compute_node = self.compute_node
finally:
self.unpinDateTime()
self.start_requested_software_installation.setErrorStatus("")
self.tic()
self.portal.REQUEST['test_ComputeNode_checkSoftwareInstallationState_notify'] = \
self._makeNotificationMessage(compute_node.getReference())
def test_alarm_run_on_close_termination(self): compute_node.ComputeNode_checkSoftwareInstallationState()
self._test_alarm_run_on_close('close/termination') self.tic()
def test_alarm_run_on_close_noallocation(self): ticket_title = "[MONITORING] %s is failing to build on %s" % (
self._test_alarm_run_on_close('close/noallocation') self.start_requested_software_installation.getReference(),
compute_node.getReference()
)
ticket = self._getGeneratedSupportRequest(compute_node.getUid(), ticket_title)
self.assertNotEqual(ticket, None)
event_list = ticket.getFollowUpRelatedValueList()
self.assertEqual(len(event_list), 1)
event = event_list[0]
self.assertEqual(
event.getTitle(),
self.portal.restrictedTraverse(
self.portal.REQUEST['test_ComputeNode_checkSoftwareInstallationState_notify']
).getTitle()
)
self.assertIn(compute_node.getReference(), event.getTextContent())
self.assertEqual(event.getFollowUp(), ticket.getRelativeUrl())
self.assertEqual(event.getSourceProject(), compute_node.getFollowUp())
self.assertEqual(ticket.getSourceProject(), compute_node.getFollowUp())
self.assertEqual(ticket.getCausality(), compute_node.getRelativeUrl())
self.assertEqual(ticket.getSimulationState(), "validated")
self.assertEqual(event.getSimulationState(), "delivered")
self.assertEqual(event.getPortalType(), "Web Message")
@simulate('ERP5Site_isSupportRequestCreationClosed', '*args, **kwargs','return 0')
@simulate('NotificationTool_getDocumentValue',
'reference=None, **kw',
'assert reference == "slapos-crm-compute_node_software_installation_state.notification", reference\n' \
'return context.restrictedTraverse(' \
'context.REQUEST["test_ComputeNode_checkSoftwareInstallationState_notify"])')
def test_ComputeNode_checkSoftwareInstallationState_script_oldBuild(self):
try:
self.pinDateTime(DateTime()-1.1)
compute_node, _ = self._makeComputeNode(self.addProject())
self._makeComplexComputeNode(self.addProject())
compute_node = self.compute_node
finally:
self.unpinDateTime()
self.start_requested_software_installation.setAccessStatus("")
self.tic()
self.portal.REQUEST['test_ComputeNode_checkSoftwareInstallationState_notify'] = \
self._makeNotificationMessage(compute_node.getReference())
def test_checkSoftwareInstallationState_not_run_on_close_forever(self): compute_node.ComputeNode_checkSoftwareInstallationState()
self._test_checkSoftwareInstallationState_not_run_on_close('close/forever') self.tic()
def test_checkSoftwareInstallationState_not_run_on_close_maintainence(self): ticket_title = "[MONITORING] %s is failing to build on %s" % (
self._test_checkSoftwareInstallationState_not_run_on_close('close/maintenence') self.start_requested_software_installation.getReference(),
compute_node.getReference()
)
ticket = self._getGeneratedSupportRequest(compute_node.getUid(), ticket_title)
def test_checkSoftwareInstallationState_not_run_on_close_outdated(self): self.assertEqual(ticket, None)
self._test_checkSoftwareInstallationState_not_run_on_close('close/outdated')
def test_checkSoftwareInstallationState_not_run_on_close_termination(self):
self._test_checkSoftwareInstallationState_not_run_on_close('close/termination')
class TestSlapOSCrmMonitoringCheckInstanceInError(SlapOSTestCaseMixinWithAbort): class TestSlapOSCrmMonitoringCheckInstanceInError(SlapOSTestCaseMixinWithAbort):
def _makeInstanceTree(self): def _makeInstanceTree(self):
person = self.portal.person_module.template_member\ person = self.portal.person_module\
.Base_createCloneDocument(batch_mode=1) .newContent(portal_type="Person")
instance_tree = self.portal\ instance_tree = self.portal\
.instance_tree_module.template_instance_tree\ .instance_tree_module\
.Base_createCloneDocument(batch_mode=1) .newContent(portal_type="Instance Tree")
instance_tree.validate() instance_tree.validate()
new_id = self.generateNewId() new_id = self.generateNewId()
instance_tree.edit( instance_tree.edit(
...@@ -632,57 +1777,235 @@ class TestSlapOSCrmMonitoringCheckInstanceInError(SlapOSTestCaseMixinWithAbort): ...@@ -632,57 +1777,235 @@ class TestSlapOSCrmMonitoringCheckInstanceInError(SlapOSTestCaseMixinWithAbort):
return instance_tree return instance_tree
def _makeSoftwareInstance(self, instance_tree): @simulate('ERP5Site_isSupportRequestCreationClosed', '','return 0')
def test_InstanceTree_checkSoftwareInstanceState_alarm_validated(self):
kw = dict(
software_release=instance_tree.getUrlString(),
software_type=self.generateNewSoftwareType(),
instance_xml=self.generateSafeXml(),
sla_xml=self.generateSafeXml(),
shared=False,
software_title=instance_tree.getTitle(),
state='started'
)
instance_tree.requestStart(**kw)
instance_tree.requestInstance(**kw)
def test_checkInstanceInError_validated_instance_tree(self):
host_sub = self._makeInstanceTree() host_sub = self._makeInstanceTree()
self.tic() self.tic()
alarm = self.portal.portal_alarms.\ alarm = self.portal.portal_alarms.\
slapos_crm_check_instance_in_error slapos_crm_check_instance_in_error
self._test_alarm(alarm, host_sub, "InstanceTree_checkSoftwareInstanceState") self._test_alarm(alarm, host_sub, "InstanceTree_checkSoftwareInstanceState")
def test_checkInstanceInError_validated_instance_tree_with_monitor_disabled(self): @simulate('ERP5Site_isSupportRequestCreationClosed', '','return 0')
def test_InstanceTree_checkSoftwareInstanceState_alarm_archived(self):
host_sub = self._makeInstanceTree() host_sub = self._makeInstanceTree()
host_sub.edit(monitor_scope="disabled") host_sub.archive()
self.tic() self.tic()
alarm = self.portal.portal_alarms.\ alarm = self.portal.portal_alarms.\
slapos_crm_check_instance_in_error slapos_crm_check_instance_in_error
self._test_alarm(alarm, host_sub, "InstanceTree_checkSoftwareInstanceState") self._test_alarm_not_visited(alarm, host_sub, "InstanceTree_checkSoftwareInstanceState")
# This is an un-optimal case, as the query cannot be used in negated form def _makeNotificationMessage(self, reference):
# on the searchAndActivate, so we end up callind the script in any situation. notification_message = self.portal.notification_message_module.newContent(
self.assertEqual('Visited by InstanceTree_checkSoftwareInstanceState', portal_type="Notification Message",
host_sub.workflow_history['edit_workflow'][-1]['comment']) title='The Compute Node %s is building for too long' % reference,
text_content='Test NM content<br/>%s<br/>' % reference,
content_type='text/html',
)
return notification_message.getRelativeUrl()
def _getGeneratedSupportRequest(self, compute_node_uid, request_title):
return self.portal.portal_catalog.getResultValue(
portal_type='Support Request',
title=request_title,
simulation_state='validated',
causality__uid=compute_node_uid
)
def test_checkInstanceInError_archived_instance_tree(self): @simulate('ERP5Site_isSupportRequestCreationClosed', '','return 0')
host_sub = self._makeInstanceTree() @simulate('NotificationTool_getDocumentValue',
host_sub.archive() 'reference=None, **kw',
'assert reference == "slapos-crm-instance-tree-instance-state.notification", reference\n' \
'return context.restrictedTraverse(' \
'context.REQUEST["test_InstanceTree_checkSoftwareInstanceState_notify"])')
def test_InstanceTree_checkSoftwareInstanceState_script_notifyError(self):
try:
self.pinDateTime(DateTime()-1.1)
self._makeComputeNode(self.addProject())
self._makeComplexComputeNode(self.addProject())
software_instance = self.start_requested_software_instance
instance_tree = software_instance.getSpecialiseValue()
software_instance.setErrorStatus("")
finally:
self.unpinDateTime()
self.portal.REQUEST['test_InstanceTree_checkSoftwareInstanceState_notify'] = \
self._makeNotificationMessage(instance_tree.getReference())
self.tic() self.tic()
alarm = self.portal.portal_alarms.\
slapos_crm_check_instance_in_error instance_tree.InstanceTree_checkSoftwareInstanceState()
self._test_alarm_not_visited(alarm, host_sub, "InstanceTree_checkSoftwareInstanceState") self.tic()
ticket_title = "Instance Tree %s is failing." % (
instance_tree.getTitle()
)
ticket = self._getGeneratedSupportRequest(instance_tree.getUid(), ticket_title)
self.assertNotEqual(ticket, None)
event_list = ticket.getFollowUpRelatedValueList()
self.assertEqual(len(event_list), 1)
event = event_list[0]
self.assertEqual(
event.getTitle(),
self.portal.restrictedTraverse(
self.portal.REQUEST['test_InstanceTree_checkSoftwareInstanceState_notify']
).getTitle()
)
self.assertIn(instance_tree.getReference(), event.getTextContent())
self.assertEqual(event.getFollowUp(), ticket.getRelativeUrl())
self.assertEqual(event.getSourceProject(), instance_tree.getFollowUp())
self.assertEqual(ticket.getSourceProject(), instance_tree.getFollowUp())
self.assertEqual(ticket.getCausality(), instance_tree.getRelativeUrl())
self.assertEqual(ticket.getSimulationState(), "validated")
self.assertEqual(event.getSimulationState(), "delivered")
self.assertEqual(event.getPortalType(), "Web Message")
@simulate('ERP5Site_isSupportRequestCreationClosed', '','return 0')
def test_InstanceTree_checkSoftwareInstanceState_script_notifyErrorTolerance(self):
try:
self.pinDateTime(DateTime()-1.1)
self._makeComputeNode(self.addProject())
self._makeComplexComputeNode(self.addProject())
software_instance = self.start_requested_software_instance
instance_tree = software_instance.getSpecialiseValue()
finally:
self.unpinDateTime()
software_instance.setErrorStatus("")
self.portal.REQUEST['test_InstanceTree_checkSoftwareInstanceState_notify'] = \
self._makeNotificationMessage(instance_tree.getReference())
self.tic()
instance_tree.InstanceTree_checkSoftwareInstanceState()
self.tic()
ticket_title = "Instance Tree %s is failing." % (
instance_tree.getTitle()
)
ticket = self._getGeneratedSupportRequest(instance_tree.getUid(), ticket_title)
self.assertEqual(ticket, None)
@simulate('ERP5Site_isSupportRequestCreationClosed', '','return 0')
@simulate('NotificationTool_getDocumentValue',
'reference=None, **kw',
'assert reference == "slapos-crm-instance-tree-instance-allocation.notification", reference\n' \
'return context.restrictedTraverse(' \
'context.REQUEST["test_InstanceTree_checkSoftwareInstanceState_notify"])')
def test_InstanceTree_checkSoftwareInstanceState_script_notifyNotAllocated(self):
try:
self.pinDateTime(DateTime()-1.1)
self._makeComputeNode(self.addProject())
self._makeComplexComputeNode(self.addProject())
software_instance = self.start_requested_software_instance
instance_tree = software_instance.getSpecialiseValue()
finally:
self.unpinDateTime()
self.portal.REQUEST['test_InstanceTree_checkSoftwareInstanceState_notify'] = \
self._makeNotificationMessage(instance_tree.getReference())
self.tic()
software_instance.edit(aggregate=None)
instance_tree.InstanceTree_checkSoftwareInstanceState()
self.tic()
ticket_title = "Instance Tree %s is failing." % (
instance_tree.getTitle()
)
ticket = self._getGeneratedSupportRequest(instance_tree.getUid(), ticket_title)
self.assertNotEqual(ticket, None)
event_list = ticket.getFollowUpRelatedValueList()
self.assertEqual(len(event_list), 1)
event = event_list[0]
self.assertEqual(
event.getTitle(),
self.portal.restrictedTraverse(
self.portal.REQUEST['test_InstanceTree_checkSoftwareInstanceState_notify']
).getTitle()
)
self.assertIn(instance_tree.getReference(), event.getTextContent())
self.assertEqual(event.getFollowUp(), ticket.getRelativeUrl())
self.assertEqual(event.getSourceProject(), instance_tree.getFollowUp())
self.assertEqual(ticket.getSourceProject(), instance_tree.getFollowUp())
self.assertEqual(ticket.getCausality(), instance_tree.getRelativeUrl())
self.assertEqual(ticket.getSimulationState(), "validated")
self.assertEqual(event.getSimulationState(), "delivered")
self.assertEqual(event.getPortalType(), "Web Message")
@simulate('ERP5Site_isSupportRequestCreationClosed', '','return 0')
def test_InstanceTree_checkSoftwareInstanceState_script_tooEarly(self):
try:
self.pinDateTime(DateTime())
self._makeComputeNode(self.addProject())
self._makeComplexComputeNode(self.addProject())
software_instance = self.start_requested_software_instance
instance_tree = software_instance.getSpecialiseValue()
software_instance.setErrorStatus("")
finally:
self.unpinDateTime()
self.portal.REQUEST['test_InstanceTree_checkSoftwareInstanceState_notify'] = \
self._makeNotificationMessage(instance_tree.getReference())
self.tic()
instance_tree.InstanceTree_checkSoftwareInstanceState()
self.tic()
ticket_title = "Instance Tree %s is failing." % (
instance_tree.getTitle()
)
ticket = self._getGeneratedSupportRequest(instance_tree.getUid(), ticket_title)
self.assertEqual(ticket, None)
@simulate('ERP5Site_isSupportRequestCreationClosed', '','return 1')
def test_InstanceTree_checkSoftwareInstanceState_script_closed(self):
try:
self.pinDateTime(DateTime()-1)
self._makeComputeNode(self.addProject())
self._makeComplexComputeNode(self.addProject())
software_instance = self.start_requested_software_instance
instance_tree = software_instance.getSpecialiseValue()
software_instance.setErrorStatus("")
finally:
self.unpinDateTime()
self.portal.REQUEST['test_InstanceTree_checkSoftwareInstanceState_notify'] = \
self._makeNotificationMessage(instance_tree.getReference())
self.tic()
instance_tree.InstanceTree_checkSoftwareInstanceState()
self.tic()
ticket_title = "Instance Tree %s is failing." % (
instance_tree.getTitle()
)
ticket = self._getGeneratedSupportRequest(instance_tree.getUid(), ticket_title)
self.assertEqual(ticket, None)
class TestSlaposCrmUpdateSupportRequestState(SlapOSTestCaseMixinWithAbort): class TestSlaposCrmUpdateSupportRequestState(SlapOSTestCaseMixinWithAbort):
def _makeSupportRequest(self): def _makeSupportRequest(self):
person = self.portal.person_module.template_member\ person = self.portal.person_module\
.Base_createCloneDocument(batch_mode=1) .newContent(portal_type="Person")
"""
support_request = self.portal.restrictedTraverse( support_request = self.portal.restrictedTraverse(
self.portal.portal_preferences.getPreferredSupportRequestTemplate()).\ self.portal.portal_preferences.getPreferredSupportRequestTemplate()).\
Base_createCloneDocument(batch_mode=1) Base_createCloneDocument(batch_mode=1)"""
support_request = self.portal.support_request_module.newContent(
portal_type="Support Request"
)
support_request.validate() support_request.validate()
new_id = self.generateNewId() new_id = self.generateNewId()
support_request.edit( support_request.edit(
...@@ -694,11 +2017,11 @@ class TestSlaposCrmUpdateSupportRequestState(SlapOSTestCaseMixinWithAbort): ...@@ -694,11 +2017,11 @@ class TestSlaposCrmUpdateSupportRequestState(SlapOSTestCaseMixinWithAbort):
return support_request return support_request
def _makeInstanceTree(self): def _makeInstanceTree(self):
person = self.portal.person_module.template_member\ person = self.portal.person_module\
.Base_createCloneDocument(batch_mode=1) .newContent(portal_type="Person")
instance_tree = self.portal\ instance_tree = self.portal\
.instance_tree_module.template_instance_tree\ .instance_tree_module\
.Base_createCloneDocument(batch_mode=1) .newContent(portal_type="Instance Tree")
instance_tree.validate() instance_tree.validate()
new_id = self.generateNewId() new_id = self.generateNewId()
instance_tree.edit( instance_tree.edit(
...@@ -710,7 +2033,7 @@ class TestSlaposCrmUpdateSupportRequestState(SlapOSTestCaseMixinWithAbort): ...@@ -710,7 +2033,7 @@ class TestSlaposCrmUpdateSupportRequestState(SlapOSTestCaseMixinWithAbort):
return instance_tree return instance_tree
def test_updateSupportRequestState_monitoring(self): def test_SupportRequest_updateMonitoringState_alarm_monitoring(self):
support_request = self._makeSupportRequest() support_request = self._makeSupportRequest()
support_request.setResource("service_module/slapos_crm_monitoring") support_request.setResource("service_module/slapos_crm_monitoring")
hs = self._makeInstanceTree() hs = self._makeInstanceTree()
...@@ -720,7 +2043,7 @@ class TestSlaposCrmUpdateSupportRequestState(SlapOSTestCaseMixinWithAbort): ...@@ -720,7 +2043,7 @@ class TestSlaposCrmUpdateSupportRequestState(SlapOSTestCaseMixinWithAbort):
slapos_crm_update_support_request_state slapos_crm_update_support_request_state
self._test_alarm(alarm, support_request, "SupportRequest_updateMonitoringState") self._test_alarm(alarm, support_request, "SupportRequest_updateMonitoringState")
def test_updateSupportRequestState_not_monitoring(self): def test_SupportRequest_updateMonitoringState_alarm_notResource(self):
support_request = self._makeSupportRequest() support_request = self._makeSupportRequest()
hs = self._makeInstanceTree() hs = self._makeInstanceTree()
support_request.setAggregateValue(hs) support_request.setAggregateValue(hs)
...@@ -729,11 +2052,116 @@ class TestSlaposCrmUpdateSupportRequestState(SlapOSTestCaseMixinWithAbort): ...@@ -729,11 +2052,116 @@ class TestSlaposCrmUpdateSupportRequestState(SlapOSTestCaseMixinWithAbort):
slapos_crm_update_support_request_state slapos_crm_update_support_request_state
self._test_alarm_not_visited(alarm, support_request, "SupportRequest_updateMonitoringState") self._test_alarm_not_visited(alarm, support_request, "SupportRequest_updateMonitoringState")
def test_SupportRequest_updateMonitoringState_alarm_notValidated(self):
support_request = self._makeSupportRequest()
support_request.setResource("service_module/slapos_crm_monitoring")
support_request.invalidate()
hs = self._makeInstanceTree()
support_request.setAggregateValue(hs)
self.tic()
alarm = self.portal.portal_alarms.\
slapos_crm_update_support_request_state
self._test_alarm_not_visited(alarm, support_request, "SupportRequest_updateMonitoringState")
class TestSlaposCrmSendPendingTicket_reminder(SlapOSTestCaseMixinWithAbort): def test_SupportRequest_updateMonitoringState_alarm_noInstanceTree(self):
support_request = self._makeSupportRequest()
def test_sendPendingTicketReminder(self): support_request.setResource("service_module/slapos_crm_monitoring")
person = self.makePerson(self.addProject()) self.tic()
alarm = self.portal.portal_alarms.\ alarm = self.portal.portal_alarms.\
slapos_crm_send_pending_ticket_reminder slapos_crm_update_support_request_state
self._test_alarm(alarm, person, "Person_sendPendingTicketReminder") self._test_alarm_not_visited(alarm, support_request, "SupportRequest_updateMonitoringState")
def _makeNotificationMessage(self, reference):
notification_message = self.portal.notification_message_module.newContent(
portal_type="Notification Message",
title='Closing Support Request %s' % reference,
text_content='Test NM content<br/>%s<br/>' % reference,
content_type='text/html',
)
return notification_message.getRelativeUrl()
@simulate('ERP5Site_isSupportRequestCreationClosed', '','return 0')
@simulate('NotificationTool_getDocumentValue',
'reference=None, **kw',
'assert reference == "slapos-crm-support-request-close-destroyed-notification", reference\n' \
'return context.restrictedTraverse(' \
'context.REQUEST["test_SupportRequest_updateMonitoringState_notify"])')
def test_SupportRequest_updateMonitoringState_script_notifyClose(self):
support_request = self._makeSupportRequest()
support_request.setResource("service_module/slapos_crm_monitoring")
instance_tree = self._makeInstanceTree()
support_request.setCausalityValue(instance_tree)
self.tic()
self.portal.REQUEST['test_SupportRequest_updateMonitoringState_notify'] = \
self._makeNotificationMessage(instance_tree.getReference())
self.tic()
self.portal.portal_workflow._jumpToStateFor(instance_tree, "destroy_requested")
support_request.SupportRequest_updateMonitoringState()
self.tic()
ticket = support_request
event_list = ticket.getFollowUpRelatedValueList()
self.assertEqual(len(event_list), 1)
event = event_list[0]
self.assertEqual(
event.getTitle(),
self.portal.restrictedTraverse(
self.portal.REQUEST['test_SupportRequest_updateMonitoringState_notify']
).getTitle()
)
self.assertIn(instance_tree.getReference(), event.getTextContent())
self.assertEqual(event.getFollowUp(), ticket.getRelativeUrl())
self.assertEqual(event.getSourceProject(), instance_tree.getFollowUp())
self.assertEqual(ticket.getSourceProject(), instance_tree.getFollowUp())
self.assertEqual(ticket.getCausality(), instance_tree.getRelativeUrl())
self.assertEqual(ticket.getSimulationState(), "invalidated")
self.assertEqual(event.getSimulationState(), "delivered")
self.assertEqual(event.getPortalType(), "Web Message")
@simulate('ERP5Site_isSupportRequestCreationClosed', '','return 0')
def test_SupportRequest_updateMonitoringState_script_notDestroyed(self):
support_request = self._makeSupportRequest()
support_request.setResource("service_module/slapos_crm_monitoring")
instance_tree = self._makeInstanceTree()
support_request.setCausalityValue(instance_tree)
self.tic()
self.portal.REQUEST['test_SupportRequest_updateMonitoringState_notify'] = \
self._makeNotificationMessage(instance_tree.getReference())
self.tic()
support_request.SupportRequest_updateMonitoringState()
self.tic()
ticket = support_request
event_list = ticket.getFollowUpRelatedValueList()
self.assertEqual(len(event_list), 0)
self.assertEqual(ticket.getSimulationState(), "validated")
@simulate('ERP5Site_isSupportRequestCreationClosed', '','return 0')
def test_SupportRequest_updateMonitoringState_script_invalidated(self):
support_request = self._makeSupportRequest()
support_request.setResource("service_module/slapos_crm_monitoring")
instance_tree = self._makeInstanceTree()
support_request.setCausalityValue(instance_tree)
self.tic()
self.portal.REQUEST['test_SupportRequest_updateMonitoringState_notify'] = \
self._makeNotificationMessage(instance_tree.getReference())
self.tic()
support_request.invalidate()
support_request.SupportRequest_updateMonitoringState()
self.tic()
ticket = support_request
event_list = ticket.getFollowUpRelatedValueList()
self.assertEqual(len(event_list), 0)
self.assertEqual(ticket.getSimulationState(), "invalidated")
...@@ -26,200 +26,15 @@ from erp5.component.test.SlapOSTestCaseMixin import \ ...@@ -26,200 +26,15 @@ from erp5.component.test.SlapOSTestCaseMixin import \
SlapOSTestCaseMixin,SlapOSTestCaseMixinWithAbort, simulate SlapOSTestCaseMixin,SlapOSTestCaseMixinWithAbort, simulate
from zExceptions import Unauthorized from zExceptions import Unauthorized
from DateTime import DateTime from DateTime import DateTime
import difflib
class TestSlapOSPerson_checkToCreateRegularisationRequest(SlapOSTestCaseMixinWithAbort):
@simulate('NotificationTool_getDocumentValue',
'reference=None, language="en"',
'assert reference == "slapos-crm.create.regularisation.request"\n' \
'return')
@simulate('Entity_statOutstandingAmount', '*args, **kwargs', 'return "1"')
def test_addRegularisationRequest_payment_requested(self):
for preference in \
self.portal.portal_catalog(portal_type="System Preference"):
preference = preference.getObject()
if preference.getPreferenceState() == 'global':
preference.setPreferredSlaposWebSiteUrl('http://foobar.org/')
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
before_date = DateTime()
ticket, event = person.Person_checkToCreateRegularisationRequest()
after_date = DateTime()
self.assertEqual(ticket.getPortalType(), 'Regularisation Request')
self.assertEqual(ticket.getSimulationState(), 'suspended')
self.assertEqual(ticket.getSourceProject(), person.getRelativeUrl())
self.assertEqual(ticket.getResource(),
'service_module/slapos_crm_acknowledgement')
self.assertEqual(ticket.getTitle(),
'Account regularisation expected for "%s"' % person.getTitle())
self.assertEqual(ticket.getDestination(),
person.getRelativeUrl())
self.assertEqual(ticket.getDestinationDecision(),
person.getRelativeUrl())
self.assertEqual(event.getPortalType(), 'Mail Message')
self.assertEqual(event.getResource(),
'service_module/slapos_crm_acknowledgement')
self.assertTrue(event.getStartDate() >= before_date)
self.assertTrue(event.getStopDate() <= after_date)
self.assertEqual(event.getTitle(), "Invoice payment requested")
self.assertEqual(event.getDestination(),
person.getRelativeUrl())
self.assertEqual(event.getSource(),
ticket.getSource())
expected_text_content = """Dear Member Template,
A new invoice has been generated.
You can access it in your invoice section at http://foobar.org/.
Regards,
The slapos team
"""
self.assertEqual(event.getTextContent(), expected_text_content,
'\n'.join([x for x in difflib.unified_diff(
event.getTextContent().splitlines(),
expected_text_content.splitlines())]))
self.assertEqual(event.getSimulationState(), 'delivered')
@simulate('NotificationTool_getDocumentValue', class TestSlapOSRegularisationRequest_checkToSendUniqEvent(SlapOSTestCaseMixin):
'reference=None, language="en"', def afterSetUp(self):
'assert reference == "slapos-crm.create.regularisation.request"\n' \ SlapOSTestCaseMixin.afterSetUp(self)
'return context.restrictedTraverse(' \ expected_slapos_organisation = self.portal.organisation_module.newContent(
'context.REQUEST["test_addRegularisationRequest_notification_message"])') default_email_coordinate_text="foo@example.org"
@simulate('Entity_statOutstandingAmount', '*args, **kwargs', 'return "1"')
def test_addRegularisationRequest_notification_message(self):
for preference in \
self.portal.portal_catalog(portal_type="System Preference"):
preference = preference.getObject()
if preference.getPreferenceState() == 'global':
preference.setPreferredSlaposWebSiteUrl('http://foobar.org/')
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
new_id = self.generateNewId()
notification_message = self.portal.notification_message_module.newContent(
portal_type="Notification Message",
title='Test NM title %s' % new_id,
text_content='Test NM content\n%s\n' % new_id,
content_type='text/plain',
) )
self.portal.REQUEST\ self.expected_slapos_organisation = expected_slapos_organisation.getRelativeUrl()
['test_addRegularisationRequest_notification_message'] = \
notification_message.getRelativeUrl()
before_date = DateTime()
ticket, event = person.Person_checkToCreateRegularisationRequest()
after_date = DateTime()
self.assertEqual(ticket.getPortalType(), 'Regularisation Request')
self.assertEqual(ticket.getSimulationState(), 'suspended')
self.assertEqual(ticket.getSourceProject(), person.getRelativeUrl())
self.assertEqual(ticket.getResource(),
'service_module/slapos_crm_acknowledgement')
self.assertEqual(ticket.getTitle(),
'Account regularisation expected for "%s"' % person.getTitle())
self.assertEqual(ticket.getDestination(),
person.getRelativeUrl())
self.assertEqual(ticket.getDestinationDecision(),
person.getRelativeUrl())
self.assertEqual(event.getPortalType(), 'Mail Message')
self.assertEqual(event.getResource(),
'service_module/slapos_crm_acknowledgement')
self.assertTrue(event.getStartDate() >= before_date)
self.assertTrue(event.getStopDate() <= after_date)
self.assertEqual(event.getTitle(),
'Test NM title %s' % new_id)
self.assertEqual(event.getDestination(),
person.getRelativeUrl())
self.assertEqual(event.getSource(),
ticket.getSource())
expected_text_content = 'Test NM content\n%s\n' % new_id
self.assertEqual(event.getTextContent(), expected_text_content,
'\n'.join([x for x in difflib.unified_diff(
event.getTextContent().splitlines(),
expected_text_content.splitlines())]))
self.assertEqual(event.getSimulationState(), 'delivered')
# def test_addRegularisationRequest_do_not_duplicate_ticket(self):
# person = self.createPerson()
# ticket = person.Person_checkToCreateRegularisationRequest()
# ticket2 = person.Person_checkToCreateRegularisationRequest()
# self.assertEqual(ticket.getRelativeUrl(), ticket2.getRelativeUrl())
@simulate('Entity_statOutstandingAmount', '*args, **kwargs', 'return "1"')
def test_addRegularisationRequest_do_not_duplicate_ticket_if_not_reindexed(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket, event = person.Person_checkToCreateRegularisationRequest()
transaction.commit()
ticket2, event2 = person.Person_checkToCreateRegularisationRequest()
self.assertNotEqual(ticket, None)
self.assertNotEqual(event, None)
self.assertEqual(ticket2, None)
self.assertEqual(event2, None)
@simulate('Entity_statOutstandingAmount', '*args, **kwargs', 'return "0"')
@simulate('RegularisationRequest_checkToSendUniqEvent',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
def test_addRegularisationRequest_balance_ok(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket, event = person.Person_checkToCreateRegularisationRequest()
self.assertEqual(ticket, None)
self.assertEqual(event, None)
@simulate('Entity_statOutstandingAmount', '*args, **kwargs', 'return "1"')
def test_addRegularisationRequest_existing_suspended_ticket(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket, event = person.Person_checkToCreateRegularisationRequest()
transaction.commit()
self.tic()
ticket2, event2 = person.Person_checkToCreateRegularisationRequest()
self.assertNotEqual(ticket, None)
self.assertNotEqual(event, None)
self.assertEqual(ticket2.getRelativeUrl(), ticket.getRelativeUrl())
self.assertEqual(event2, None)
@simulate('Entity_statOutstandingAmount', '*args, **kwargs', 'return "1"')
def test_addRegularisationRequest_existing_validated_ticket(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket, event = person.Person_checkToCreateRegularisationRequest()
ticket.validate()
transaction.commit()
self.tic()
ticket2, event2 = person.Person_checkToCreateRegularisationRequest()
self.assertNotEqual(ticket, None)
self.assertNotEqual(event, None)
self.assertEqual(ticket2.getRelativeUrl(), ticket.getRelativeUrl())
self.assertEqual(event2, None)
@simulate('Entity_statOutstandingAmount', '*args, **kwargs', 'return "1"')
def test_addRegularisationRequest_existing_invalidated_ticket(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = person.Person_checkToCreateRegularisationRequest()[0]
ticket.invalidate()
transaction.commit()
self.tic()
ticket2, event2 = person.Person_checkToCreateRegularisationRequest()
self.assertNotEqual(ticket2.getRelativeUrl(), ticket.getRelativeUrl())
self.assertNotEqual(event2, None)
def test_addRegularisationRequest_REQUEST_disallowed(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
self.assertRaises(
Unauthorized,
person.Person_checkToCreateRegularisationRequest,
REQUEST={})
class TestSlapOSRegularisationRequest_invalidateIfPersonBalanceIsOk(
SlapOSTestCaseMixinWithAbort):
def createRegularisationRequest(self): def createRegularisationRequest(self):
new_id = self.generateNewId() new_id = self.generateNewId()
...@@ -227,67 +42,40 @@ class TestSlapOSRegularisationRequest_invalidateIfPersonBalanceIsOk( ...@@ -227,67 +42,40 @@ class TestSlapOSRegularisationRequest_invalidateIfPersonBalanceIsOk(
portal_type='Regularisation Request', portal_type='Regularisation Request',
title="Test Reg. Req.%s" % new_id, title="Test Reg. Req.%s" % new_id,
reference="TESTREGREQ-%s" % new_id, reference="TESTREGREQ-%s" % new_id,
resource='foo/bar',
) )
def test_invalidateIfPersonBalanceIsOk_REQUEST_disallowed(self): def test_checkToSendUniqEvent_noEvent(self):
ticket = self.createRegularisationRequest()
self.assertRaises(
Unauthorized,
ticket.RegularisationRequest_invalidateIfPersonBalanceIsOk,
REQUEST={})
@simulate('Entity_statOutstandingAmount', '*args, **kwargs', 'return "0"')
def test_invalidateIfPersonBalanceIsOk_matching_case(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest()
ticket.edit(source_project_value=person)
ticket.validate()
ticket.suspend()
ticket.RegularisationRequest_invalidateIfPersonBalanceIsOk()
self.assertEqual(ticket.getSimulationState(), 'invalidated')
@simulate('Entity_statOutstandingAmount', '*args, **kwargs', 'return "0"')
def test_invalidateIfPersonBalanceIsOk_validated(self):
project = self.addProject() project = self.addProject()
person = self.makePerson(project, index=0, user=0) person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
ticket.edit(source_project_value=person) ticket.edit(
ticket.validate() source=self.expected_slapos_organisation,
ticket.RegularisationRequest_invalidateIfPersonBalanceIsOk() destination_value=person,
self.assertEqual(ticket.getSimulationState(), 'invalidated') source_project_value=person)
@simulate('Entity_statOutstandingAmount', '*args, **kwargs', 'return "0"')
def test_invalidateIfPersonBalanceIsOk_no_person(self):
ticket = self.createRegularisationRequest()
ticket.validate() ticket.validate()
ticket.suspend() ticket.suspend()
ticket.RegularisationRequest_invalidateIfPersonBalanceIsOk() before_date = DateTime()
self.assertEqual(ticket.getSimulationState(), 'suspended') event = ticket.RegularisationRequest_checkToSendUniqEvent(
'service_module/slapos_crm_spam', 'foo title', 'foo content', 'foo comment')
after_date = DateTime()
@simulate('Entity_statOutstandingAmount', '*args, **kwargs', 'return "1"')
def test_invalidateIfPersonBalanceIsOk_wrong_balance(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest()
ticket.edit(source_project_value=person)
ticket.validate()
ticket.suspend()
ticket.RegularisationRequest_invalidateIfPersonBalanceIsOk()
self.assertEqual(ticket.getSimulationState(), 'suspended') self.assertEqual(ticket.getSimulationState(), 'suspended')
self.assertEqual(ticket.getResource(), 'service_module/slapos_crm_spam')
class TestSlapOSRegularisationRequest_checkToSendUniqEvent(SlapOSTestCaseMixin): self.assertEqual(event.getPortalType(), 'Mail Message')
self.assertEqual(event.getSimulationState(), 'delivered')
def createRegularisationRequest(self): self.assertTrue(event.getStartDate() >= before_date)
new_id = self.generateNewId() self.assertTrue(event.getStopDate() <= after_date)
return self.portal.regularisation_request_module.newContent( self.assertEqual(event.getTitle(), "foo title")
portal_type='Regularisation Request', self.assertEqual(event.getResource(), 'service_module/slapos_crm_spam')
title="Test Reg. Req.%s" % new_id, self.assertEqual(event.getFollowUp(), ticket.getRelativeUrl())
reference="TESTREGREQ-%s" % new_id, self.assertEqual(event.getSource(), self.expected_slapos_organisation)
resource='foo/bar', self.assertEqual(event.getDestination(), person.getRelativeUrl())
) self.assertEqual(event.getTextContent(), 'foo content')
self.assertEqual(event.getContentType(), 'text/plain')
def test_checkToSendUniqEvent_no_event(self): def test_checkToSendUniqEvent_notificationMessage(self):
project = self.addProject() project = self.addProject()
person = self.makePerson(project, index=0, user=0) person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
...@@ -298,8 +86,25 @@ class TestSlapOSRegularisationRequest_checkToSendUniqEvent(SlapOSTestCaseMixin): ...@@ -298,8 +86,25 @@ class TestSlapOSRegularisationRequest_checkToSendUniqEvent(SlapOSTestCaseMixin):
ticket.validate() ticket.validate()
ticket.suspend() ticket.suspend()
before_date = DateTime() before_date = DateTime()
notification_message_reference = 'test_checkToSendUniqEvent_notificationMessage%s' % self.generateNewId()
notification_message = self.portal.notification_message_module.newContent(
portal_type="Notification Message",
reference=notification_message_reference,
title='notification title ${foo}',
text_content_substitution_mapping_method_id='NotificationMessage_getSubstitutionMappingDictFromEvent',
text_content='notification content ${foo}',
content_type='text/html',
)
notification_message.validate()
self.tic()
event = ticket.RegularisationRequest_checkToSendUniqEvent( event = ticket.RegularisationRequest_checkToSendUniqEvent(
'service_module/slapos_crm_spam', 'foo title', 'foo content', 'foo comment') 'service_module/slapos_crm_spam', 'foo title', 'foo content',
'foo comment',
notification_message=notification_message_reference,
substitution_method_parameter_dict={'foo': 'bar'}
)
after_date = DateTime() after_date = DateTime()
self.assertEqual(ticket.getSimulationState(), 'suspended') self.assertEqual(ticket.getSimulationState(), 'suspended')
...@@ -309,14 +114,15 @@ class TestSlapOSRegularisationRequest_checkToSendUniqEvent(SlapOSTestCaseMixin): ...@@ -309,14 +114,15 @@ class TestSlapOSRegularisationRequest_checkToSendUniqEvent(SlapOSTestCaseMixin):
self.assertEqual(event.getSimulationState(), 'delivered') self.assertEqual(event.getSimulationState(), 'delivered')
self.assertTrue(event.getStartDate() >= before_date) self.assertTrue(event.getStartDate() >= before_date)
self.assertTrue(event.getStopDate() <= after_date) self.assertTrue(event.getStopDate() <= after_date)
self.assertEqual(event.getTitle(), "foo title") self.assertEqual(event.getTitle(), "notification title bar")
self.assertEqual(event.getResource(), 'service_module/slapos_crm_spam') self.assertEqual(event.getResource(), 'service_module/slapos_crm_spam')
self.assertEqual(event.getFollowUp(), ticket.getRelativeUrl()) self.assertEqual(event.getFollowUp(), ticket.getRelativeUrl())
self.assertEqual(event.getSource(), self.expected_slapos_organisation) self.assertEqual(event.getSource(), self.expected_slapos_organisation)
self.assertEqual(event.getDestination(), person.getRelativeUrl()) self.assertEqual(event.getDestination(), person.getRelativeUrl())
self.assertEqual(event.getTextContent(), 'foo content') self.assertEqual(event.getTextContent(), 'notification content bar')
self.assertEqual(event.getContentType(), 'text/html')
def test_checkToSendUniqEvent_service_required(self): def test_checkToSendUniqEvent_serviceRequired(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
self.assertRaises( self.assertRaises(
AssertionError, AssertionError,
...@@ -324,7 +130,7 @@ class TestSlapOSRegularisationRequest_checkToSendUniqEvent(SlapOSTestCaseMixin): ...@@ -324,7 +130,7 @@ class TestSlapOSRegularisationRequest_checkToSendUniqEvent(SlapOSTestCaseMixin):
ticket.getRelativeUrl(), '', '', '' ticket.getRelativeUrl(), '', '', ''
) )
def test_checkToSendUniqEvent_call_twice_with_tic(self): def test_checkToSendUniqEvent_callTwiceWithTic(self):
project = self.addProject() project = self.addProject()
person = self.makePerson(project, index=0, user=0) person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
...@@ -344,7 +150,7 @@ class TestSlapOSRegularisationRequest_checkToSendUniqEvent(SlapOSTestCaseMixin): ...@@ -344,7 +150,7 @@ class TestSlapOSRegularisationRequest_checkToSendUniqEvent(SlapOSTestCaseMixin):
self.assertEqual(event.getTextContent(), 'foo content') self.assertEqual(event.getTextContent(), 'foo content')
self.assertEqual(event.getRelativeUrl(), event2.getRelativeUrl()) self.assertEqual(event.getRelativeUrl(), event2.getRelativeUrl())
def test_checkToSendUniqEvent_manual_event(self): def test_checkToSendUniqEvent_manualEvent(self):
project = self.addProject() project = self.addProject()
person = self.makePerson(project, index=0, user=0) person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
...@@ -370,7 +176,7 @@ class TestSlapOSRegularisationRequest_checkToSendUniqEvent(SlapOSTestCaseMixin): ...@@ -370,7 +176,7 @@ class TestSlapOSRegularisationRequest_checkToSendUniqEvent(SlapOSTestCaseMixin):
self.assertEqual(event.getSimulationState(), 'draft') self.assertEqual(event.getSimulationState(), 'draft')
self.assertEqual(event.getRelativeUrl(), event2.getRelativeUrl()) self.assertEqual(event.getRelativeUrl(), event2.getRelativeUrl())
def test_checkToSendUniqEvent_not_suspended(self): def test_checkToSendUniqEvent_notSuspended(self):
project = self.addProject() project = self.addProject()
person = self.makePerson(project, index=0, user=0) person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
...@@ -384,7 +190,7 @@ class TestSlapOSRegularisationRequest_checkToSendUniqEvent(SlapOSTestCaseMixin): ...@@ -384,7 +190,7 @@ class TestSlapOSRegularisationRequest_checkToSendUniqEvent(SlapOSTestCaseMixin):
'service_module/slapos_crm_spam', 'foo2 title', 'foo2 content', 'foo2 comment') 'service_module/slapos_crm_spam', 'foo2 title', 'foo2 content', 'foo2 comment')
self.assertEqual(event, None) self.assertEqual(event, None)
def test_checkToSendUniqEvent_event_not_reindexed(self): def test_checkToSendUniqEvent_eventNotReindexed(self):
project = self.addProject() project = self.addProject()
person = self.makePerson(project, index=0, user=0) person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
...@@ -402,7 +208,7 @@ class TestSlapOSRegularisationRequest_checkToSendUniqEvent(SlapOSTestCaseMixin): ...@@ -402,7 +208,7 @@ class TestSlapOSRegularisationRequest_checkToSendUniqEvent(SlapOSTestCaseMixin):
self.assertNotEqual(event, event2) self.assertNotEqual(event, event2)
self.assertEqual(event2, None) self.assertEqual(event2, None)
def test_checkToSendUniqEvent_REQUEST_disallowed(self): def test_checkToSendUniqEvent_REQUESTdisallowed(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
self.assertRaises( self.assertRaises(
Unauthorized, Unauthorized,
...@@ -410,6 +216,7 @@ class TestSlapOSRegularisationRequest_checkToSendUniqEvent(SlapOSTestCaseMixin): ...@@ -410,6 +216,7 @@ class TestSlapOSRegularisationRequest_checkToSendUniqEvent(SlapOSTestCaseMixin):
'', '', '', '', '', '', '', '',
REQUEST={}) REQUEST={})
class TestSlapOSRegularisationRequest_checkToTriggerNextEscalationStep( class TestSlapOSRegularisationRequest_checkToTriggerNextEscalationStep(
SlapOSTestCaseMixinWithAbort): SlapOSTestCaseMixinWithAbort):
...@@ -430,18 +237,16 @@ class TestSlapOSRegularisationRequest_checkToTriggerNextEscalationStep( ...@@ -430,18 +237,16 @@ class TestSlapOSRegularisationRequest_checkToTriggerNextEscalationStep(
0, ticket.getRelativeUrl(), '', '', '', '' 0, ticket.getRelativeUrl(), '', '', '', ''
) )
@simulate('NotificationTool_getDocumentValue',
'reference=None, language="en"',
'assert reference == "slapos-crm.acknowledgment.escalation", reference\n' \
'return')
@simulate('RegularisationRequest_checkToSendUniqEvent', @simulate('RegularisationRequest_checkToSendUniqEvent',
'service_relative_url, title, text_content, comment, REQUEST=None', 'service_relative_url, title, text_content, comment, ' \
'notification_message=None, substitution_method_parameter_dict=None, ' \
'REQUEST=None',
'context.portal_workflow.doActionFor(' \ 'context.portal_workflow.doActionFor(' \
'context, action="edit_action", ' \ 'context, action="edit_action", ' \
'comment="Visited by RegularisationRequest_checkToSendUniqEvent ' \ 'comment="Visited by RegularisationRequest_checkToSendUniqEvent ' \
'%s %s %s %s" % (service_relative_url, title, text_content, comment))\n' \ '%s %s %s %s %s %s" % (service_relative_url, title, text_content, comment, notification_message, substitution_method_parameter_dict))\n' \
'return "fooevent"') 'return "fooevent"')
def test_checkToTriggerNextEscalationStep_matching_event(self): def test_checkToTriggerNextEscalationStep_matchingEvent(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_acknowledgement') ticket.edit(resource='service_module/slapos_crm_acknowledgement')
ticket.validate() ticket.validate()
...@@ -458,19 +263,21 @@ class TestSlapOSRegularisationRequest_checkToTriggerNextEscalationStep( ...@@ -458,19 +263,21 @@ class TestSlapOSRegularisationRequest_checkToTriggerNextEscalationStep(
event2 = ticket.RegularisationRequest_checkToTriggerNextEscalationStep( event2 = ticket.RegularisationRequest_checkToTriggerNextEscalationStep(
7, 'service_module/slapos_crm_acknowledgement', 7, 'service_module/slapos_crm_acknowledgement',
'service_module/slapos_crm_spam', 'service_module/slapos_crm_spam',
'foo2 title', 'foo2 content', 'foo2 comment') 'foo2 title', 'foo2 content', 'foo2 comment',
notification_message='slapos-crm.acknowledgment.escalation',
substitution_method_parameter_dict={'foo': 'bar'})
self.assertEqual(event2, event.getRelativeUrl()) self.assertEqual(event2, event.getRelativeUrl())
self.assertEqual( self.assertEqual(
'Visited by RegularisationRequest_checkToSendUniqEvent %s %s %s %s' % \ 'Visited by RegularisationRequest_checkToSendUniqEvent %s %s %s %s %s %s' % \
('service_module/slapos_crm_spam', 'foo2 title', 'foo2 content', ('service_module/slapos_crm_spam', 'foo2 title', 'foo2 content',
'foo2 comment'), 'foo2 comment', 'slapos-crm.acknowledgment.escalation', {'foo': 'bar'}),
ticket.workflow_history['edit_workflow'][-1]['comment']) ticket.workflow_history['edit_workflow'][-1]['comment'])
@simulate('RegularisationRequest_checkToSendUniqEvent', @simulate('RegularisationRequest_checkToSendUniqEvent',
'*args, **kwargs', '*args, **kwargs',
'raise NotImplementedError, "Should not have been called"') 'raise NotImplementedError, "Should not have been called"')
def test_checkToTriggerNextEscalationStep_recent_event(self): def test_checkToTriggerNextEscalationStep_recentEvent(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_acknowledgement') ticket.edit(resource='service_module/slapos_crm_acknowledgement')
ticket.validate() ticket.validate()
...@@ -494,7 +301,7 @@ class TestSlapOSRegularisationRequest_checkToTriggerNextEscalationStep( ...@@ -494,7 +301,7 @@ class TestSlapOSRegularisationRequest_checkToTriggerNextEscalationStep(
@simulate('RegularisationRequest_checkToSendUniqEvent', @simulate('RegularisationRequest_checkToSendUniqEvent',
'*args, **kwargs', '*args, **kwargs',
'raise NotImplementedError, "Should not have been called"') 'raise NotImplementedError, "Should not have been called"')
def test_checkToTriggerNextEscalationStep_other_ticket_event(self): def test_checkToTriggerNextEscalationStep_other_ticketEvent(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_acknowledgement') ticket.edit(resource='service_module/slapos_crm_acknowledgement')
ticket.validate() ticket.validate()
...@@ -517,7 +324,7 @@ class TestSlapOSRegularisationRequest_checkToTriggerNextEscalationStep( ...@@ -517,7 +324,7 @@ class TestSlapOSRegularisationRequest_checkToTriggerNextEscalationStep(
@simulate('RegularisationRequest_checkToSendUniqEvent', @simulate('RegularisationRequest_checkToSendUniqEvent',
'*args, **kwargs', '*args, **kwargs',
'raise NotImplementedError, "Should not have been called"') 'raise NotImplementedError, "Should not have been called"')
def test_checkToTriggerNextEscalationStep_other_resource_event(self): def test_checkToTriggerNextEscalationStep_otherResourceEvent(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_acknowledgement') ticket.edit(resource='service_module/slapos_crm_acknowledgement')
ticket.validate() ticket.validate()
...@@ -541,7 +348,7 @@ class TestSlapOSRegularisationRequest_checkToTriggerNextEscalationStep( ...@@ -541,7 +348,7 @@ class TestSlapOSRegularisationRequest_checkToTriggerNextEscalationStep(
@simulate('RegularisationRequest_checkToSendUniqEvent', @simulate('RegularisationRequest_checkToSendUniqEvent',
'*args, **kwargs', '*args, **kwargs',
'raise NotImplementedError, "Should not have been called"') 'raise NotImplementedError, "Should not have been called"')
def test_checkToTriggerNextEscalationStep_no_current_event(self): def test_checkToTriggerNextEscalationStep_noCurrentEvent(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_acknowledgement') ticket.edit(resource='service_module/slapos_crm_acknowledgement')
ticket.validate() ticket.validate()
...@@ -558,7 +365,7 @@ class TestSlapOSRegularisationRequest_checkToTriggerNextEscalationStep( ...@@ -558,7 +365,7 @@ class TestSlapOSRegularisationRequest_checkToTriggerNextEscalationStep(
@simulate('RegularisationRequest_checkToSendUniqEvent', @simulate('RegularisationRequest_checkToSendUniqEvent',
'*args, **kwargs', '*args, **kwargs',
'raise NotImplementedError, "Should not have been called"') 'raise NotImplementedError, "Should not have been called"')
def test_checkToTriggerNextEscalationStep_no_ticket_resource(self): def test_checkToTriggerNextEscalationStep_noTicketResource(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
ticket.validate() ticket.validate()
ticket.suspend() ticket.suspend()
...@@ -581,7 +388,7 @@ class TestSlapOSRegularisationRequest_checkToTriggerNextEscalationStep( ...@@ -581,7 +388,7 @@ class TestSlapOSRegularisationRequest_checkToTriggerNextEscalationStep(
@simulate('RegularisationRequest_checkToSendUniqEvent', @simulate('RegularisationRequest_checkToSendUniqEvent',
'*args, **kwargs', '*args, **kwargs',
'raise NotImplementedError, "Should not have been called"') 'raise NotImplementedError, "Should not have been called"')
def test_checkToTriggerNextEscalationStep_not_suspended(self): def test_checkToTriggerNextEscalationStep_notSuspended(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_acknowledgement') ticket.edit(resource='service_module/slapos_crm_acknowledgement')
ticket.validate() ticket.validate()
...@@ -601,7 +408,7 @@ class TestSlapOSRegularisationRequest_checkToTriggerNextEscalationStep( ...@@ -601,7 +408,7 @@ class TestSlapOSRegularisationRequest_checkToTriggerNextEscalationStep(
self.assertEqual(event2, None) self.assertEqual(event2, None)
def test_checkToTriggerNextEscalationStep_REQUEST_disallowed(self): def test_checkToTriggerNextEscalationStep_REQUESTdisallowed(self):
ticket = self.createRegularisationRequest() ticket = self.createRegularisationRequest()
self.assertRaises( self.assertRaises(
Unauthorized, Unauthorized,
...@@ -609,516 +416,40 @@ class TestSlapOSRegularisationRequest_checkToTriggerNextEscalationStep( ...@@ -609,516 +416,40 @@ class TestSlapOSRegularisationRequest_checkToTriggerNextEscalationStep(
'', '', '', '', '', '', '', '', '', '', '', '',
REQUEST={}) REQUEST={})
class TestSlapOSRegularisationRequest_triggerAcknowledgmentEscalation(
SlapOSTestCaseMixinWithAbort):
def test_triggerAcknowledgmentEscalation_REQUEST_disallowed(self):
ticket = self.createRegularisationRequest()
self.assertRaises(
Unauthorized,
ticket.RegularisationRequest_triggerAcknowledgmentEscalation,
REQUEST={})
@simulate('NotificationTool_getDocumentValue',
'reference=None, language="en"',
'assert reference == "slapos-crm.acknowledgment.escalation", reference\n' \
'return')
@simulate('RegularisationRequest_checkToTriggerNextEscalationStep',
'delay_period_in_days, current_service_relative_url, next_service_relative_url, title, text_content, comment, REQUEST=None',
'context.portal_workflow.doActionFor(' \
'context, action="edit_action", ' \
'comment="Visited by RegularisationRequest_checkToTriggerNextEscalationStep ' \
'%s %s %s %s %s %s" % (delay_period_in_days, current_service_relative_url, next_service_relative_url, title, text_content, comment))')
def test_checkToTriggerNextEscalationStep_matching_event(self):
ticket = self.createRegularisationRequest()
ticket.RegularisationRequest_triggerAcknowledgmentEscalation()
self.assertEqual(
'Visited by RegularisationRequest_checkToTriggerNextEscalationStep ' \
'%s %s %s %s %s %s' % \
(15,
'service_module/slapos_crm_acknowledgement',
'service_module/slapos_crm_stop_reminder',
'Reminder: invoice payment requested',
"""Dear user,
We would like to remind you the unpaid invoice you have on %s.
If no payment is done during the coming days, we will stop all your current instances to free some hardware resources.
Regards,
The slapos team
""" % self.portal.portal_preferences.getPreferredSlaposWebSiteUrl(),
'Stopping reminder.'),
ticket.workflow_history['edit_workflow'][-1]['comment'])
@simulate('NotificationTool_getDocumentValue',
'reference=None, language="en"',
'assert reference == "slapos-crm.acknowledgment.escalation"\n' \
'return context.restrictedTraverse(' \
'context.REQUEST["test_checkToTriggerNextEscalationStep_notification_message"])')
@simulate('RegularisationRequest_checkToTriggerNextEscalationStep',
'delay_period_in_days, current_service_relative_url, next_service_relative_url, title, text_content, comment, REQUEST=None',
'context.portal_workflow.doActionFor(' \
'context, action="edit_action", ' \
'comment="Visited by RegularisationRequest_checkToTriggerNextEscalationStep ' \
'%s %s %s %s %s %s" % (delay_period_in_days, current_service_relative_url, next_service_relative_url, title, text_content, comment))')
def test_checkToTriggerNextEscalationStep_notification_message(self):
ticket = self.createRegularisationRequest()
new_id = self.generateNewId()
notification_message = self.portal.notification_message_module.newContent(
portal_type="Notification Message",
title='Test NM title %s' % new_id,
text_content='Test NM content\n%s\n' % new_id,
content_type='text/plain',
)
self.portal.REQUEST\
['test_checkToTriggerNextEscalationStep_notification_message'] = \
notification_message.getRelativeUrl()
ticket.RegularisationRequest_triggerAcknowledgmentEscalation()
self.assertEqual(
'Visited by RegularisationRequest_checkToTriggerNextEscalationStep ' \
'%s %s %s %s %s %s' % \
(15,
'service_module/slapos_crm_acknowledgement',
'service_module/slapos_crm_stop_reminder',
'Test NM title %s' % new_id,
'Test NM content\n%s\n' % new_id,
'Stopping reminder.'),
ticket.workflow_history['edit_workflow'][-1]['comment'])
class TestSlapOSRegularisationRequest_triggerStopReminderEscalation(
SlapOSTestCaseMixinWithAbort):
def test_triggerStopReminderEscalation_REQUEST_disallowed(self):
ticket = self.createRegularisationRequest()
self.assertRaises(
Unauthorized,
ticket.RegularisationRequest_triggerStopReminderEscalation,
REQUEST={})
@simulate('NotificationTool_getDocumentValue',
'reference=None, language="en"',
'assert reference == "slapos-crm.stop.reminder.escalation", reference\n' \
'return')
@simulate('RegularisationRequest_checkToTriggerNextEscalationStep',
'delay_period_in_days, current_service_relative_url, next_service_relative_url, title, text_content, comment, REQUEST=None',
'context.portal_workflow.doActionFor(' \
'context, action="edit_action", ' \
'comment="Visited by RegularisationRequest_checkToTriggerNextEscalationStep ' \
'%s %s %s %s %s %s" % (delay_period_in_days, current_service_relative_url, next_service_relative_url, title, text_content, comment))')
def test_checkToTriggerNextEscalationStep_matching_event(self):
ticket = self.createRegularisationRequest()
ticket.RegularisationRequest_triggerStopReminderEscalation()
self.assertEqual(
'Visited by RegularisationRequest_checkToTriggerNextEscalationStep ' \
'%s %s %s %s %s %s' % \
(7,
'service_module/slapos_crm_stop_reminder',
'service_module/slapos_crm_stop_acknowledgement',
'Acknowledgment: instances stopped',
"""Dear user,
Despite our last reminder, you still have an unpaid invoice on %s.
We will now stop all your current instances to free some hardware resources.
Regards,
The slapos team
""" % self.portal.portal_preferences.getPreferredSlaposWebSiteUrl(),
'Stopping acknowledgment.'),
ticket.workflow_history['edit_workflow'][-1]['comment'])
@simulate('NotificationTool_getDocumentValue',
'reference=None, language="en"',
'assert reference == "slapos-crm.stop.reminder.escalation"\n' \
'return context.restrictedTraverse(' \
'context.REQUEST["test_checkToTriggerNextEscalationStep_notification_message"])')
@simulate('RegularisationRequest_checkToTriggerNextEscalationStep',
'delay_period_in_days, current_service_relative_url, next_service_relative_url, title, text_content, comment, REQUEST=None',
'context.portal_workflow.doActionFor(' \
'context, action="edit_action", ' \
'comment="Visited by RegularisationRequest_checkToTriggerNextEscalationStep ' \
'%s %s %s %s %s %s" % (delay_period_in_days, current_service_relative_url, next_service_relative_url, title, text_content, comment))')
def test_checkToTriggerNextEscalationStep_notification_message(self):
ticket = self.createRegularisationRequest()
new_id = self.generateNewId()
notification_message = self.portal.notification_message_module.newContent(
portal_type="Notification Message",
title='Test NM title %s' % new_id,
text_content='Test NM content\n%s\n' % new_id,
content_type='text/plain',
)
self.portal.REQUEST\
['test_checkToTriggerNextEscalationStep_notification_message'] = \
notification_message.getRelativeUrl()
ticket.RegularisationRequest_triggerStopReminderEscalation()
self.assertEqual(
'Visited by RegularisationRequest_checkToTriggerNextEscalationStep ' \
'%s %s %s %s %s %s' % \
(7,
'service_module/slapos_crm_stop_reminder',
'service_module/slapos_crm_stop_acknowledgement',
'Test NM title %s' % new_id,
'Test NM content\n%s\n' % new_id,
'Stopping acknowledgment.'),
ticket.workflow_history['edit_workflow'][-1]['comment'])
class TestSlapOSRegularisationRequest_triggerStopAcknowledgmentEscalation(
SlapOSTestCaseMixinWithAbort):
def test_triggerStopAcknowledgmentEscalation_REQUEST_disallowed(self):
ticket = self.createRegularisationRequest()
self.assertRaises(
Unauthorized,
ticket.RegularisationRequest_triggerStopAcknowledgmentEscalation,
REQUEST={})
@simulate('NotificationTool_getDocumentValue',
'reference=None, language="en"',
'assert reference == "slapos-crm.stop.acknowledgment.escalation", reference\n' \
'return')
@simulate('RegularisationRequest_checkToTriggerNextEscalationStep',
'delay_period_in_days, current_service_relative_url, next_service_relative_url, title, text_content, comment, REQUEST=None',
'context.portal_workflow.doActionFor(' \
'context, action="edit_action", ' \
'comment="Visited by RegularisationRequest_checkToTriggerNextEscalationStep ' \
'%s %s %s %s %s %s" % (delay_period_in_days, current_service_relative_url, next_service_relative_url, title, text_content, comment))')
def test_checkToTriggerNextEscalationStep_matching_event(self):
ticket = self.createRegularisationRequest()
ticket.RegularisationRequest_triggerStopAcknowledgmentEscalation()
self.assertEqual(
'Visited by RegularisationRequest_checkToTriggerNextEscalationStep ' \
'%s %s %s %s %s %s' % \
(7,
'service_module/slapos_crm_stop_acknowledgement',
'service_module/slapos_crm_delete_reminder',
'Last reminder: invoice payment requested',
"""Dear user,
We would like to remind you the unpaid invoice you have on %s.
If no payment is done during the coming days, we will delete all your instances.
Regards,
The slapos team
""" % self.portal.portal_preferences.getPreferredSlaposWebSiteUrl(),
'Deleting reminder.'),
ticket.workflow_history['edit_workflow'][-1]['comment'])
@simulate('NotificationTool_getDocumentValue',
'reference=None, language="en"',
'assert reference == "slapos-crm.stop.acknowledgment.escalation"\n' \
'return context.restrictedTraverse(' \
'context.REQUEST["test_checkToTriggerNextEscalationStep_notification_message"])')
@simulate('RegularisationRequest_checkToTriggerNextEscalationStep',
'delay_period_in_days, current_service_relative_url, next_service_relative_url, title, text_content, comment, REQUEST=None',
'context.portal_workflow.doActionFor(' \
'context, action="edit_action", ' \
'comment="Visited by RegularisationRequest_checkToTriggerNextEscalationStep ' \
'%s %s %s %s %s %s" % (delay_period_in_days, current_service_relative_url, next_service_relative_url, title, text_content, comment))')
def test_checkToTriggerNextEscalationStep_notification_message(self):
ticket = self.createRegularisationRequest()
new_id = self.generateNewId()
notification_message = self.portal.notification_message_module.newContent(
portal_type="Notification Message",
title='Test NM title %s' % new_id,
text_content='Test NM content\n%s\n' % new_id,
content_type='text/plain',
)
self.portal.REQUEST\
['test_checkToTriggerNextEscalationStep_notification_message'] = \
notification_message.getRelativeUrl()
ticket.RegularisationRequest_triggerStopAcknowledgmentEscalation()
self.assertEqual(
'Visited by RegularisationRequest_checkToTriggerNextEscalationStep ' \
'%s %s %s %s %s %s' % \
(7,
'service_module/slapos_crm_stop_acknowledgement',
'service_module/slapos_crm_delete_reminder',
'Test NM title %s' % new_id,
'Test NM content\n%s\n' % new_id,
'Deleting reminder.'),
ticket.workflow_history['edit_workflow'][-1]['comment'])
class TestSlapOSRegularisationRequest_triggerDeleteReminderEscalation(
SlapOSTestCaseMixinWithAbort):
def test_triggerDeleteReminderEscalation_REQUEST_disallowed(self):
ticket = self.createRegularisationRequest()
self.assertRaises(
Unauthorized,
ticket.RegularisationRequest_triggerDeleteReminderEscalation,
REQUEST={})
@simulate('NotificationTool_getDocumentValue',
'reference=None, language="en"',
'assert reference == "slapos-crm.delete.reminder.escalation", reference\n' \
'return')
@simulate('RegularisationRequest_checkToTriggerNextEscalationStep',
'delay_period_in_days, current_service_relative_url, next_service_relative_url, title, text_content, comment, REQUEST=None',
'context.portal_workflow.doActionFor(' \
'context, action="edit_action", ' \
'comment="Visited by RegularisationRequest_checkToTriggerNextEscalationStep ' \
'%s %s %s %s %s %s" % (delay_period_in_days, current_service_relative_url, next_service_relative_url, title, text_content, comment))')
def test_checkToTriggerNextEscalationStep_matching_event(self):
ticket = self.createRegularisationRequest()
ticket.RegularisationRequest_triggerDeleteReminderEscalation()
self.assertEqual(
'Visited by RegularisationRequest_checkToTriggerNextEscalationStep ' \
'%s %s %s %s %s %s' % \
(10,
'service_module/slapos_crm_delete_reminder',
'service_module/slapos_crm_delete_acknowledgement',
'Acknowledgment: instances deleted',
"""Dear user,
Despite our last reminder, you still have an unpaid invoice on %s.
We will now delete all your instances.
Regards,
The slapos team
""" % self.portal.portal_preferences.getPreferredSlaposWebSiteUrl(),
'Deleting acknowledgment.'),
ticket.workflow_history['edit_workflow'][-1]['comment'])
@simulate('NotificationTool_getDocumentValue',
'reference=None, language="en"',
'assert reference == "slapos-crm.delete.reminder.escalation"\n' \
'return context.restrictedTraverse(' \
'context.REQUEST["test_checkToTriggerNextEscalationStep_notification_message"])')
@simulate('RegularisationRequest_checkToTriggerNextEscalationStep',
'delay_period_in_days, current_service_relative_url, next_service_relative_url, title, text_content, comment, REQUEST=None',
'context.portal_workflow.doActionFor(' \
'context, action="edit_action", ' \
'comment="Visited by RegularisationRequest_checkToTriggerNextEscalationStep ' \
'%s %s %s %s %s %s" % (delay_period_in_days, current_service_relative_url, next_service_relative_url, title, text_content, comment))')
def test_checkToTriggerNextEscalationStep_notification_message(self):
ticket = self.createRegularisationRequest()
new_id = self.generateNewId()
notification_message = self.portal.notification_message_module.newContent(
portal_type="Notification Message",
title='Test NM title %s' % new_id,
text_content='Test NM content\n%s\n' % new_id,
content_type='text/plain',
)
self.portal.REQUEST\
['test_checkToTriggerNextEscalationStep_notification_message'] = \
notification_message.getRelativeUrl()
ticket.RegularisationRequest_triggerDeleteReminderEscalation()
self.assertEqual(
'Visited by RegularisationRequest_checkToTriggerNextEscalationStep ' \
'%s %s %s %s %s %s' % \
(10,
'service_module/slapos_crm_delete_reminder',
'service_module/slapos_crm_delete_acknowledgement',
'Test NM title %s' % new_id,
'Test NM content\n%s\n' % new_id,
'Deleting acknowledgment.'),
ticket.workflow_history['edit_workflow'][-1]['comment'])
class TestSlapOSRegularisationRequest_stopInstanceTreeList(
SlapOSTestCaseMixinWithAbort):
def createInstanceTree(self):
new_id = self.generateNewId()
instance_tree = self.portal.instance_tree_module\
.template_instance_tree.Base_createCloneDocument(batch_mode=1)
instance_tree.edit(
reference="TESTHS-%s" % new_id,
)
instance_tree.validate()
self.portal.portal_workflow._jumpToStateFor(
instance_tree, 'start_requested')
return instance_tree
def test_stopInstanceTreeList_REQUEST_disallowed(self):
ticket = self.createRegularisationRequest()
self.assertRaises(
Unauthorized,
ticket.RegularisationRequest_stopInstanceTreeList,
'footag',
REQUEST={})
@simulate('InstanceTree_stopFromRegularisationRequest',
'person, REQUEST=None',
'context.portal_workflow.doActionFor(' \
'context, action="edit_action", ' \
'comment="Visited by InstanceTree_stopFromRegularisationRequest ' \
'%s" % (person))')
def test_stopInstanceTreeList_matching_subscription(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest()
instance_tree = self.createInstanceTree()
ticket.edit(
source_project_value=person,
resource='service_module/slapos_crm_stop_acknowledgement',
)
ticket.validate()
ticket.suspend()
instance_tree.edit(
destination_section=person.getRelativeUrl(),
)
self.tic()
result = ticket.\
RegularisationRequest_stopInstanceTreeList('footag')
self.assertTrue(result)
self.tic()
self.assertEqual(
'Visited by InstanceTree_stopFromRegularisationRequest ' \
'%s' % person.getRelativeUrl(),
instance_tree.workflow_history['edit_workflow'][-1]['comment'])
@simulate('InstanceTree_stopFromRegularisationRequest',
'person, REQUEST=None',
'context.portal_workflow.doActionFor(' \
'context, action="edit_action", ' \
'comment="Visited by InstanceTree_stopFromRegularisationRequest ' \
'%s" % (person))')
def test_stopInstanceTreeList_matching_subscription_2(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest()
instance_tree = self.createInstanceTree()
ticket.edit(
source_project_value=person,
resource='service_module/slapos_crm_delete_reminder',
)
ticket.validate()
ticket.suspend()
instance_tree.edit(
destination_section=person.getRelativeUrl(),
)
self.tic()
result = ticket.\
RegularisationRequest_stopInstanceTreeList('footag')
self.assertTrue(result)
self.tic()
self.assertEqual(
'Visited by InstanceTree_stopFromRegularisationRequest ' \
'%s' % person.getRelativeUrl(),
instance_tree.workflow_history['edit_workflow'][-1]['comment'])
@simulate('InstanceTree_stopFromRegularisationRequest',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
def test_stopInstanceTreeList_other_subscription(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest()
self.createInstanceTree()
ticket.edit(
source_project_value=person,
resource='service_module/slapos_crm_stop_acknowledgement',
)
ticket.validate()
ticket.suspend()
self.tic()
result = ticket.\
RegularisationRequest_stopInstanceTreeList('footag')
self.assertTrue(result)
self.tic()
@simulate('InstanceTree_stopFromRegularisationRequest',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
def test_stopInstanceTreeList_no_person(self):
ticket = self.createRegularisationRequest()
ticket.edit(
resource='service_module/slapos_crm_stop_acknowledgement',
)
ticket.validate()
ticket.suspend()
self.tic()
result = ticket.\
RegularisationRequest_stopInstanceTreeList('footag')
self.assertFalse(result)
self.tic()
@simulate('InstanceTree_stopFromRegularisationRequest',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
def test_stopInstanceTreeList_not_suspended(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest()
self.createInstanceTree()
ticket.edit(
source_project_value=person,
resource='service_module/slapos_crm_stop_acknowledgement',
)
ticket.validate()
self.tic()
result = ticket.\
RegularisationRequest_stopInstanceTreeList('footag')
self.assertFalse(result)
self.tic()
@simulate('InstanceTree_stopFromRegularisationRequest',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
def test_stopInstanceTreeList_other_resource(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest()
self.createInstanceTree()
ticket.edit(
source_project_value=person,
resource='service_module/slapos_crm_acknowledgement',
)
ticket.validate()
ticket.suspend()
self.tic()
result = ticket.\
RegularisationRequest_stopInstanceTreeList('footag')
self.assertFalse(result)
self.tic()
class TestSlapOSInstanceTree_stopFromRegularisationRequest( class TestSlapOSInstanceTree_stopFromRegularisationRequest(
SlapOSTestCaseMixinWithAbort): SlapOSTestCaseMixinWithAbort):
def createInstanceTree(self): def createInstanceTree(self, project):
new_id = self.generateNewId() new_id = self.generateNewId()
instance_tree = self.portal.instance_tree_module\ instance_tree = self.portal.instance_tree_module\
.template_instance_tree.Base_createCloneDocument(batch_mode=1) .newContent(portal_type="Instance Tree")
instance_tree.edit( instance_tree.edit(
reference="TESTHS-%s" % new_id, reference="TESTHS-%s" % new_id,
follow_up_value=project,
url_string=self.generateNewSoftwareReleaseUrl(),
title=self.generateNewSoftwareTitle(),
source_reference=self.generateNewSoftwareType(),
text_content=self.generateSafeXml(),
sla_xml=self.generateSafeXml(),
root_slave=False
) )
instance_tree.validate() instance_tree.validate()
self.portal.portal_workflow._jumpToStateFor( self.portal.portal_workflow._jumpToStateFor(
instance_tree, 'start_requested') instance_tree, 'start_requested')
return instance_tree return instance_tree
def test_stopFromRegularisationRequest_REQUEST_disallowed(self): def test_stopFromRegularisationRequest_REQUESTdisallowed(self):
self.assertRaises( self.assertRaises(
Unauthorized, Unauthorized,
self.portal.InstanceTree_stopFromRegularisationRequest, self.portal.InstanceTree_stopFromRegularisationRequest,
'', '',
REQUEST={}) REQUEST={})
def test_stopFromRegularisationRequest_matching_subscription(self): def test_stopFromRegularisationRequest_matchingSubscription(self):
project = self.addProject() project = self.addProject()
person = self.makePerson(project, index=0, user=0) person = self.makePerson(project, index=0, user=0)
instance_tree = self.createInstanceTree() instance_tree = self.createInstanceTree(project)
instance_tree.edit( instance_tree.edit(
destination_section=person.getRelativeUrl(), destination_section=person.getRelativeUrl(),
) )
...@@ -1144,10 +475,10 @@ class TestSlapOSInstanceTree_stopFromRegularisationRequest( ...@@ -1144,10 +475,10 @@ class TestSlapOSInstanceTree_stopFromRegularisationRequest(
self.assertEqual(instance_tree.isRootSlave(), shared) self.assertEqual(instance_tree.isRootSlave(), shared)
self.assertEqual(instance_tree.getSlapState(), "stop_requested") self.assertEqual(instance_tree.getSlapState(), "stop_requested")
def test_stopFromRegularisationRequest_stopped_subscription(self): def test_stopFromRegularisationRequest_stoppedSubscription(self):
project = self.addProject() project = self.addProject()
person = self.makePerson(project, index=0, user=0) person = self.makePerson(project, index=0, user=0)
instance_tree = self.createInstanceTree() instance_tree = self.createInstanceTree(project)
instance_tree.edit( instance_tree.edit(
destination_section=person.getRelativeUrl(), destination_section=person.getRelativeUrl(),
) )
...@@ -1159,39 +490,48 @@ class TestSlapOSInstanceTree_stopFromRegularisationRequest( ...@@ -1159,39 +490,48 @@ class TestSlapOSInstanceTree_stopFromRegularisationRequest(
self.assertEqual(result, False) self.assertEqual(result, False)
def test_stopFromRegularisationRequest_non_matching_person(self): def test_stopFromRegularisationRequest_nonMatchingPerson(self):
instance_tree = self.createInstanceTree() project = self.addProject()
instance_tree = self.createInstanceTree(project)
self.assertRaises( self.assertRaises(
AssertionError, AssertionError,
instance_tree.InstanceTree_stopFromRegularisationRequest, instance_tree.InstanceTree_stopFromRegularisationRequest,
'foobar') 'foobar')
class TestSlapOSInstanceTree_deleteFromRegularisationRequest( class TestSlapOSInstanceTree_deleteFromRegularisationRequest(
SlapOSTestCaseMixinWithAbort): SlapOSTestCaseMixinWithAbort):
def createInstanceTree(self): def createInstanceTree(self, project):
new_id = self.generateNewId() new_id = self.generateNewId()
instance_tree = self.portal.instance_tree_module\ instance_tree = self.portal.instance_tree_module\
.template_instance_tree.Base_createCloneDocument(batch_mode=1) .newContent(portal_type="Instance Tree")
instance_tree.edit( instance_tree.edit(
reference="TESTHS-%s" % new_id, reference="TESTHS-%s" % new_id,
follow_up_value=project,
url_string=self.generateNewSoftwareReleaseUrl(),
title=self.generateNewSoftwareTitle(),
source_reference=self.generateNewSoftwareType(),
text_content=self.generateSafeXml(),
sla_xml=self.generateSafeXml(),
root_slave=False
) )
instance_tree.validate() instance_tree.validate()
self.portal.portal_workflow._jumpToStateFor( self.portal.portal_workflow._jumpToStateFor(
instance_tree, 'start_requested') instance_tree, 'start_requested')
return instance_tree return instance_tree
def test_deleteFromRegularisationRequest_REQUEST_disallowed(self): def test_deleteFromRegularisationRequest_REQUESTdisallowed(self):
self.assertRaises( self.assertRaises(
Unauthorized, Unauthorized,
self.portal.InstanceTree_deleteFromRegularisationRequest, self.portal.InstanceTree_deleteFromRegularisationRequest,
'', '',
REQUEST={}) REQUEST={})
def test_deleteFromRegularisationRequest_started_subscription(self): def test_deleteFromRegularisationRequest_startedSubscription(self):
project = self.addProject() project = self.addProject()
person = self.makePerson(project, index=0, user=0) person = self.makePerson(project, index=0, user=0)
instance_tree = self.createInstanceTree() instance_tree = self.createInstanceTree(project)
instance_tree.edit( instance_tree.edit(
destination_section=person.getRelativeUrl(), destination_section=person.getRelativeUrl(),
) )
...@@ -1204,6 +544,7 @@ class TestSlapOSInstanceTree_deleteFromRegularisationRequest( ...@@ -1204,6 +544,7 @@ class TestSlapOSInstanceTree_deleteFromRegularisationRequest(
sla_xml = instance_tree.getSlaXml() sla_xml = instance_tree.getSlaXml()
shared = instance_tree.isRootSlave() shared = instance_tree.isRootSlave()
self.assertEqual(instance_tree.getSlapState(), "start_requested") self.assertEqual(instance_tree.getSlapState(), "start_requested")
self.assertEqual(shared, False)
result = instance_tree.\ result = instance_tree.\
InstanceTree_deleteFromRegularisationRequest(person.getRelativeUrl()) InstanceTree_deleteFromRegularisationRequest(person.getRelativeUrl())
...@@ -1217,10 +558,10 @@ class TestSlapOSInstanceTree_deleteFromRegularisationRequest( ...@@ -1217,10 +558,10 @@ class TestSlapOSInstanceTree_deleteFromRegularisationRequest(
self.assertEqual(instance_tree.isRootSlave(), shared) self.assertEqual(instance_tree.isRootSlave(), shared)
self.assertEqual(instance_tree.getSlapState(), "destroy_requested") self.assertEqual(instance_tree.getSlapState(), "destroy_requested")
def test_deleteFromRegularisationRequest_stopped_subscription(self): def test_deleteFromRegularisationRequest_stoppedSubscription(self):
project = self.addProject() project = self.addProject()
person = self.makePerson(project, index=0, user=0) person = self.makePerson(project, index=0, user=0)
instance_tree = self.createInstanceTree() instance_tree = self.createInstanceTree(project)
instance_tree.edit( instance_tree.edit(
destination_section=person.getRelativeUrl(), destination_section=person.getRelativeUrl(),
) )
...@@ -1248,10 +589,10 @@ class TestSlapOSInstanceTree_deleteFromRegularisationRequest( ...@@ -1248,10 +589,10 @@ class TestSlapOSInstanceTree_deleteFromRegularisationRequest(
self.assertEqual(instance_tree.isRootSlave(), shared) self.assertEqual(instance_tree.isRootSlave(), shared)
self.assertEqual(instance_tree.getSlapState(), "destroy_requested") self.assertEqual(instance_tree.getSlapState(), "destroy_requested")
def test_deleteFromRegularisationRequest_destroyed_subscription(self): def test_deleteFromRegularisationRequest_destroyedSubscription(self):
project = self.addProject() project = self.addProject()
person = self.makePerson(project, index=0, user=0) person = self.makePerson(project, index=0, user=0)
instance_tree = self.createInstanceTree() instance_tree = self.createInstanceTree(project)
instance_tree.edit( instance_tree.edit(
destination_section=person.getRelativeUrl(), destination_section=person.getRelativeUrl(),
) )
...@@ -1263,165 +604,11 @@ class TestSlapOSInstanceTree_deleteFromRegularisationRequest( ...@@ -1263,165 +604,11 @@ class TestSlapOSInstanceTree_deleteFromRegularisationRequest(
self.assertEqual(result, False) self.assertEqual(result, False)
def test_deleteFromRegularisationRequest_non_matching_person(self): def test_deleteFromRegularisationRequest_nonMatchingPerson(self):
instance_tree = self.createInstanceTree() project = self.addProject()
instance_tree = self.createInstanceTree(project)
self.assertRaises( self.assertRaises(
AssertionError, AssertionError,
instance_tree.InstanceTree_deleteFromRegularisationRequest, instance_tree.InstanceTree_deleteFromRegularisationRequest,
'foobar') 'foobar')
class TestSlapOSRegularisationRequest_deleteInstanceTreeList(
SlapOSTestCaseMixinWithAbort):
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 createInstanceTree(self):
new_id = self.generateNewId()
instance_tree = self.portal.instance_tree_module\
.template_instance_tree.Base_createCloneDocument(batch_mode=1)
instance_tree.edit(
reference="TESTHS-%s" % new_id,
)
instance_tree.validate()
self.portal.portal_workflow._jumpToStateFor(
instance_tree, 'start_requested')
return instance_tree
def test_deleteInstanceTreeList_REQUEST_disallowed(self):
ticket = self.createRegularisationRequest()
self.assertRaises(
Unauthorized,
ticket.RegularisationRequest_deleteInstanceTreeList,
'footag',
REQUEST={})
@simulate('InstanceTree_deleteFromRegularisationRequest',
'person, REQUEST=None',
'context.portal_workflow.doActionFor(' \
'context, action="edit_action", ' \
'comment="Visited by InstanceTree_deleteFromRegularisationRequest ' \
'%s" % (person))')
def test_deleteInstanceTreeList_matching_subscription(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest()
instance_tree = self.createInstanceTree()
ticket.edit(
source_project_value=person,
resource='service_module/slapos_crm_delete_acknowledgement',
)
ticket.validate()
ticket.suspend()
instance_tree.edit(
destination_section=person.getRelativeUrl(),
)
self.tic()
result = ticket.\
RegularisationRequest_deleteInstanceTreeList('footag')
self.assertTrue(result)
self.tic()
self.assertEqual(
'Visited by InstanceTree_deleteFromRegularisationRequest ' \
'%s' % person.getRelativeUrl(),
instance_tree.workflow_history['edit_workflow'][-1]['comment'])
@simulate('InstanceTree_deleteFromRegularisationRequest',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
def test_deleteInstanceTreeList_other_subscription(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest()
self.createInstanceTree()
ticket.edit(
source_project_value=person,
resource='service_module/slapos_crm_delete_acknowledgement',
)
ticket.validate()
ticket.suspend()
self.tic()
result = ticket.\
RegularisationRequest_deleteInstanceTreeList('footag')
self.assertTrue(result)
self.tic()
@simulate('InstanceTree_deleteFromRegularisationRequest',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
def test_deleteInstanceTreeList_no_person(self):
ticket = self.createRegularisationRequest()
ticket.edit(
resource='service_module/slapos_crm_delete_acknowledgement',
)
ticket.validate()
ticket.suspend()
self.tic()
result = ticket.\
RegularisationRequest_deleteInstanceTreeList('footag')
self.assertFalse(result)
self.tic()
@simulate('InstanceTree_deleteFromRegularisationRequest',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
def test_deleteInstanceTreeList_not_suspended(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest()
self.createInstanceTree()
ticket.edit(
source_project_value=person,
resource='service_module/slapos_crm_delete_acknowledgement',
)
ticket.validate()
self.tic()
result = ticket.\
RegularisationRequest_deleteInstanceTreeList('footag')
self.assertFalse(result)
self.tic()
@simulate('InstanceTree_deleteFromRegularisationRequest',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
def test_deleteInstanceTreeList_other_resource(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest()
self.createInstanceTree()
ticket.edit(
source_project_value=person,
resource='service_module/slapos_crm_delete_reminder',
)
ticket.validate()
ticket.suspend()
self.tic()
result = ticket.\
RegularisationRequest_deleteInstanceTreeList('footag')
self.assertFalse(result)
self.tic()
...@@ -23,11 +23,11 @@ ...@@ -23,11 +23,11 @@
import transaction import transaction
from erp5.component.test.SlapOSTestCaseMixin import \ from erp5.component.test.SlapOSTestCaseMixin import \
SlapOSTestCaseMixin,SlapOSTestCaseMixinWithAbort, simulate SlapOSTestCaseMixin,SlapOSTestCaseMixinWithAbort, TemporaryAlarmScript
from DateTime import DateTime from DateTime import DateTime
from App.Common import rfc1123_date from App.Common import rfc1123_date
from Products.ERP5Type.Cache import DEFAULT_CACHE_SCOPE
import json
def getFakeSlapState(): def getFakeSlapState():
return "destroy_requested" return "destroy_requested"
...@@ -57,18 +57,19 @@ class TestCRMSkinsMixin(SlapOSTestCaseMixinWithAbort): ...@@ -57,18 +57,19 @@ class TestCRMSkinsMixin(SlapOSTestCaseMixinWithAbort):
assignment.open() assignment.open()
return assignment return assignment
def _makeInstanceTree(self): def _makeInstanceTree(self, project):
person = self.portal.person_module.template_member\ person = self.portal.person_module\
.Base_createCloneDocument(batch_mode=1) .newContent(portal_type="Person")
instance_tree = self.portal\ instance_tree = self.portal\
.instance_tree_module.template_instance_tree\ .instance_tree_module\
.Base_createCloneDocument(batch_mode=1) .newContent(portal_type="Instance Tree")
instance_tree.validate() instance_tree.validate()
new_id = self.generateNewId() new_id = self.generateNewId()
instance_tree.edit( instance_tree.edit(
title= "Test hosting sub ticket %s" % new_id, title= "Test hosting sub ticket %s" % new_id,
reference="TESTHST-%s" % new_id, reference="TESTHST-%s" % new_id,
destination_section_value=person destination_section_value=person,
follow_up_value=project
) )
return instance_tree return instance_tree
...@@ -91,8 +92,7 @@ class TestCRMSkinsMixin(SlapOSTestCaseMixinWithAbort): ...@@ -91,8 +92,7 @@ class TestCRMSkinsMixin(SlapOSTestCaseMixinWithAbort):
def _makeSoftwareInstallation(self): def _makeSoftwareInstallation(self):
self._makeComputeNode(self.project) self._makeComputeNode(self.project)
software_installation = self.portal\ software_installation = self.portal\
.software_installation_module.template_software_installation\ .software_installation_module.newContent(portal_type="Software Installation")
.Base_createCloneDocument(batch_mode=1)
software_installation.edit( software_installation.edit(
url_string=self.generateNewSoftwareReleaseUrl(), url_string=self.generateNewSoftwareReleaseUrl(),
aggregate=self.compute_node.getRelativeUrl(), aggregate=self.compute_node.getRelativeUrl(),
...@@ -111,7 +111,8 @@ class TestSlapOSSupportRequestModule_getMonitoringUrlList(TestCRMSkinsMixin): ...@@ -111,7 +111,8 @@ class TestSlapOSSupportRequestModule_getMonitoringUrlList(TestCRMSkinsMixin):
# We assume here that several objects created by others tests don't influentiate # We assume here that several objects created by others tests don't influentiate
# this test. # this test.
self.assertEqual(module.SupportRequestModule_getMonitoringUrlList(), []) self.assertEqual(module.SupportRequestModule_getMonitoringUrlList(), [])
instance_tree = self._makeInstanceTree() with TemporaryAlarmScript(self.portal, 'Item_getSubscriptionStatus', "'subscribed'"):
instance_tree = self._makeInstanceTree(self.project)
self._makeSoftwareInstance(instance_tree, "https://xxx/") self._makeSoftwareInstance(instance_tree, "https://xxx/")
support_request = module.newContent(portal_type="Support Request") support_request = module.newContent(portal_type="Support Request")
self.tic() self.tic()
...@@ -158,722 +159,53 @@ class TestSlapOSSupportRequestModule_getMonitoringUrlList(TestCRMSkinsMixin): ...@@ -158,722 +159,53 @@ class TestSlapOSSupportRequestModule_getMonitoringUrlList(TestCRMSkinsMixin):
self.tic() self.tic()
self.assertNotEqual(instance_tree.getSuccessorList(), []) self.assertNotEqual(instance_tree.getSuccessorList(), [])
class TestSlapOSComputeNode_getTicketRelatedList(TestCRMSkinsMixin):
def test_getTicketRelatedList_support_request_related_to_allocated_instance(self):
document = self._makeComputeNode(self.project)[0]
self._makeComplexComputeNode(self.project)
ticket = self.portal.support_request_module.newContent(\
title="Test Support Request %s" % self.new_id)
ticket.setAggregateValue(self.start_requested_software_instance.getSpecialiseValue())
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
# Not indexed yet
self.assertEqual(len(open_related_ticket_list), 0)
self.tic()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 0)
ticket.submit()
ticket.immediateReindexObject()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 1)
self.assertEqual(open_related_ticket_list[0].getUid(), ticket.getUid())
ticket.validate()
ticket.immediateReindexObject()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 1)
self.assertEqual(open_related_ticket_list[0].getUid(), ticket.getUid())
ticket.suspend()
ticket.immediateReindexObject()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 1)
self.assertEqual(open_related_ticket_list[0].getUid(), ticket.getUid())
ticket.invalidate()
ticket.immediateReindexObject()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 1)
self.assertEqual(open_related_ticket_list[0].getUid(), ticket.getUid())
def test_getTicketRelatedList_support_request_related_to_compute_node(self):
document = self._makeComputeNode(self.project)[0]
ticket = self.portal.support_request_module.newContent(\
title="Test Support Request %s" % self.new_id)
ticket.setAggregateValue(document)
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
# Not indexed yet
self.assertEqual(len(open_related_ticket_list), 0)
self.tic()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 0)
ticket.submit()
ticket.immediateReindexObject()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 1)
self.assertEqual(open_related_ticket_list[0].getUid(), ticket.getUid())
ticket.validate()
ticket.immediateReindexObject()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 1)
self.assertEqual(open_related_ticket_list[0].getUid(), ticket.getUid())
ticket.suspend()
ticket.immediateReindexObject()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 1)
self.assertEqual(open_related_ticket_list[0].getUid(), ticket.getUid())
ticket.invalidate()
ticket.immediateReindexObject()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 1)
self.assertEqual(open_related_ticket_list[0].getUid(), ticket.getUid())
def test_getTicketRelatedList_cancelled_support_request_related_to_allocated_instance(self):
document = self._makeComputeNode(self.project)[0]
self._makeComplexComputeNode(self.project)
ticket = self.portal.support_request_module.newContent(\
title="Test Support Request %s" % self.new_id)
ticket.setAggregateValue(self.start_requested_software_instance.getSpecialiseValue())
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
# Not indexed yet
self.assertEqual(len(open_related_ticket_list), 0)
self.tic()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 0)
ticket.submit()
ticket.immediateReindexObject()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 1)
self.assertEqual(open_related_ticket_list[0].getUid(), ticket.getUid())
ticket.cancel()
ticket.immediateReindexObject()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 0)
def test_getTicketRelatedList_cancelled_support_request_related_to_compute_node(self):
document = self._makeComputeNode(self.project)[0]
ticket = self.portal.support_request_module.newContent(\
title="Test Support Request %s" % self.new_id)
ticket.setAggregateValue(document)
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
# Not indexed yet
self.assertEqual(len(open_related_ticket_list), 0)
self.tic()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 0)
ticket.submit()
ticket.immediateReindexObject()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 1)
self.assertEqual(open_related_ticket_list[0].getUid(), ticket.getUid())
ticket.cancel()
ticket.immediateReindexObject()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 0)
def test_getTicketRelatedList_upgrade_decision_related_to_allocated_instance(self):
document = self._makeComputeNode(self.project)[0]
self._makeComplexComputeNode(self.project)
def newUpgradeDecision():
ticket = self.portal.upgrade_decision_module.newContent(
portal_type='Upgrade Decision',
title="Upgrade Decision Test %s" % self.new_id,
reference="TESTUD-%s" % self.new_id)
ticket.immediateReindexObject()
return ticket
ticket = newUpgradeDecision()
ticket.newContent(
portal_type="Upgrade Decision Line"
).setAggregateValue(
self.start_requested_software_instance.getSpecialiseValue())
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
# Not indexed yet
self.assertEqual(len(open_related_ticket_list), 0)
self.tic()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 0)
ticket.plan()
ticket.immediateReindexObject()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 0)
ticket.confirm()
ticket.immediateReindexObject()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 1)
self.assertEqual(open_related_ticket_list[0].getUid(), ticket.getUid())
ticket.start()
ticket.immediateReindexObject()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 1)
self.assertEqual(open_related_ticket_list[0].getUid(), ticket.getUid())
ticket.stop()
ticket.immediateReindexObject()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 1)
self.assertEqual(open_related_ticket_list[0].getUid(), ticket.getUid())
ticket.deliver()
ticket.immediateReindexObject()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 1)
self.assertEqual(open_related_ticket_list[0].getUid(), ticket.getUid())
def test_getTicketRelatedList_upgrade_decision_related_to_compute_node(self):
document = self._makeComputeNode(self.project)[0]
def newUpgradeDecision():
ticket = self.portal.upgrade_decision_module.newContent(
portal_type='Upgrade Decision',
title="Upgrade Decision Test %s" % self.new_id,
reference="TESTUD-%s" % self.new_id)
ticket.immediateReindexObject()
return ticket
ticket = newUpgradeDecision()
ticket.newContent(
portal_type="Upgrade Decision Line"
).setAggregateValue(document)
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
# Not indexed yet
self.assertEqual(len(open_related_ticket_list), 0)
self.tic()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 0)
ticket.plan()
ticket.immediateReindexObject()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 0)
ticket.confirm()
ticket.immediateReindexObject()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 1)
self.assertEqual(open_related_ticket_list[0].getUid(), ticket.getUid())
ticket.start()
ticket.immediateReindexObject()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 1)
self.assertEqual(open_related_ticket_list[0].getUid(), ticket.getUid())
ticket.stop()
ticket.immediateReindexObject()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 1)
self.assertEqual(open_related_ticket_list[0].getUid(), ticket.getUid())
ticket.deliver()
ticket.immediateReindexObject()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 1)
self.assertEqual(open_related_ticket_list[0].getUid(), ticket.getUid())
def test_getTicketRelatedList_cancelled_upgrade_decision_to_allocated_instance(self):
document = self._makeComputeNode(self.project)[0]
self._makeComplexComputeNode(self.project)
def newUpgradeDecision():
ticket = self.portal.upgrade_decision_module.newContent(
portal_type='Upgrade Decision',
title="Upgrade Decision Test %s" % self.new_id,
reference="TESTUD-%s" % self.new_id)
ticket.immediateReindexObject()
return ticket
ticket = newUpgradeDecision()
ticket.newContent(
portal_type="Upgrade Decision Line"
).setAggregateValue(
self.start_requested_software_instance.getSpecialiseValue())
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
# Not indexed yet
self.assertEqual(len(open_related_ticket_list), 0)
self.tic()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 0)
ticket.cancel()
ticket.immediateReindexObject()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 0)
def test_getTicketRelatedList_cancelled_upgrade_decision_to_computer_node(self):
document = self._makeComputeNode(self.project)[0]
def newUpgradeDecision():
ticket = self.portal.upgrade_decision_module.newContent(
portal_type='Upgrade Decision',
title="Upgrade Decision Test %s" % self.new_id,
reference="TESTUD-%s" % self.new_id)
ticket.immediateReindexObject()
return ticket
ticket = newUpgradeDecision()
ticket.newContent(
portal_type="Upgrade Decision Line"
).setAggregateValue(document)
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
# Not indexed yet
self.assertEqual(len(open_related_ticket_list), 0)
self.tic()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 0)
ticket.cancel()
ticket.immediateReindexObject()
open_related_ticket_list = document.ComputeNode_getTicketRelatedList()
self.assertEqual(len(open_related_ticket_list), 0)
class TestSlapOSBase_getOpenRelatedTicketList(TestCRMSkinsMixin):
def test_getOpenRelatedTicketList_support_request_related_to_compute_node(self):
self._test_getOpenRelatedTicketList_support_request_related(
self._makeComputeNode(self.project)[0])
def test_getOpenRelatedTicketList_support_request_related_to_instance_tree(self):
self._test_getOpenRelatedTicketList_support_request_related(
self._makeInstanceTree())
def _test_getOpenRelatedTicketList_support_request_related(self, document):
ticket = self.portal.support_request_module.newContent(\
title="Test Support Request %s" % self.new_id)
ticket.setAggregateValue(document)
open_related_ticket_list = document.Base_getOpenRelatedTicketList()
# Not indexed yet
self.assertEqual(len(open_related_ticket_list), 0)
self.tic()
open_related_ticket_list = document.Base_getOpenRelatedTicketList()
self.assertEqual(len(open_related_ticket_list), 0)
ticket.submit()
ticket.immediateReindexObject()
open_related_ticket_list = document.Base_getOpenRelatedTicketList()
self.assertEqual(len(open_related_ticket_list), 1)
self.assertEqual(open_related_ticket_list[0].getUid(), ticket.getUid())
ticket.validate()
ticket.immediateReindexObject()
open_related_ticket_list = document.Base_getOpenRelatedTicketList()
self.assertEqual(len(open_related_ticket_list), 1)
self.assertEqual(open_related_ticket_list[0].getUid(), ticket.getUid())
ticket.suspend()
ticket.immediateReindexObject()
open_related_ticket_list = document.Base_getOpenRelatedTicketList()
self.assertEqual(len(open_related_ticket_list), 1)
self.assertEqual(open_related_ticket_list[0].getUid(), ticket.getUid())
ticket.invalidate()
ticket.immediateReindexObject()
open_related_ticket_list = document.Base_getOpenRelatedTicketList()
self.assertEqual(len(open_related_ticket_list), 1)
self.assertEqual(open_related_ticket_list[0].getUid(), ticket.getUid())
def test_getOpenRelatedTicketList_cancelled_support_request_related_to_compute_node(self):
self._test_getOpenRelatedTicketList_cancelled_support_request_related(
self._makeComputeNode(self.project)[0])
def test_getOpenRelatedTicketList_cancelled_support_request_related_to_instance_tree(self):
self._test_getOpenRelatedTicketList_cancelled_support_request_related(
self._makeInstanceTree())
def _test_getOpenRelatedTicketList_cancelled_support_request_related(self, document):
ticket = self.portal.support_request_module.newContent(\
title="Test Support Request %s" % self.new_id)
ticket.setAggregateValue(document)
open_related_ticket_list = document.Base_getOpenRelatedTicketList()
# Not indexed yet
self.assertEqual(len(open_related_ticket_list), 0)
self.tic()
open_related_ticket_list = document.Base_getOpenRelatedTicketList()
self.assertEqual(len(open_related_ticket_list), 0)
ticket.submit()
ticket.immediateReindexObject()
open_related_ticket_list = document.Base_getOpenRelatedTicketList()
self.assertEqual(len(open_related_ticket_list), 1)
self.assertEqual(open_related_ticket_list[0].getUid(), ticket.getUid())
ticket.cancel()
ticket.immediateReindexObject()
open_related_ticket_list = document.Base_getOpenRelatedTicketList()
self.assertEqual(len(open_related_ticket_list), 0)
def test_getOpenRelatedTicketList_upgrade_decision_related_to_compute_node(self):
self._test_getOpenRelatedTicketList_upgrade_decision_related(
self._makeComputeNode(self.project)[0])
def test_getOpenRelatedTicketList_upgrade_decision_related_to_instance_tree(self):
self._test_getOpenRelatedTicketList_upgrade_decision_related(
self._makeInstanceTree())
def _test_getOpenRelatedTicketList_upgrade_decision_related(self, document):
def newUpgradeDecision():
ticket = self.portal.upgrade_decision_module.newContent(
portal_type='Upgrade Decision',
title="Upgrade Decision Test %s" % self.new_id,
reference="TESTUD-%s" % self.new_id)
ticket.immediateReindexObject()
return ticket
ticket = newUpgradeDecision()
ticket.newContent(
portal_type="Upgrade Decision Line"
).setAggregateValue(document)
open_related_ticket_list = document.Base_getOpenRelatedTicketList()
# Not indexed yet
self.assertEqual(len(open_related_ticket_list), 0)
self.tic()
open_related_ticket_list = document.Base_getOpenRelatedTicketList()
self.assertEqual(len(open_related_ticket_list), 0)
ticket.plan()
ticket.immediateReindexObject()
open_related_ticket_list = document.Base_getOpenRelatedTicketList()
self.assertEqual(len(open_related_ticket_list), 0)
ticket.confirm()
ticket.immediateReindexObject()
open_related_ticket_list = document.Base_getOpenRelatedTicketList()
self.assertEqual(len(open_related_ticket_list), 1)
self.assertEqual(open_related_ticket_list[0].getUid(), ticket.getUid())
ticket.start()
ticket.immediateReindexObject()
open_related_ticket_list = document.Base_getOpenRelatedTicketList()
self.assertEqual(len(open_related_ticket_list), 1)
self.assertEqual(open_related_ticket_list[0].getUid(), ticket.getUid())
ticket.stop()
ticket.immediateReindexObject()
open_related_ticket_list = document.Base_getOpenRelatedTicketList()
self.assertEqual(len(open_related_ticket_list), 1)
self.assertEqual(open_related_ticket_list[0].getUid(), ticket.getUid())
ticket.deliver()
ticket.immediateReindexObject()
open_related_ticket_list = document.Base_getOpenRelatedTicketList()
self.assertEqual(len(open_related_ticket_list), 1)
self.assertEqual(open_related_ticket_list[0].getUid(), ticket.getUid())
def test_getOpenRelatedTicketList_cancelled_upgrade_decision_related_to_compute_node(self):
self._test_getOpenRelatedTicketList_cancelled_upgrade_decision_related(
self._makeComputeNode(self.project)[0])
def test_getOpenRelatedTicketList_cancelled_upgrade_decision_related_to_instance_tree(self):
self._test_getOpenRelatedTicketList_cancelled_upgrade_decision_related(
self._makeInstanceTree())
def _test_getOpenRelatedTicketList_cancelled_upgrade_decision_related(self, document):
def newUpgradeDecision():
ticket = self.portal.upgrade_decision_module.newContent(
portal_type='Upgrade Decision',
title="Upgrade Decision Test %s" % self.new_id,
reference="TESTUD-%s" % self.new_id)
ticket.immediateReindexObject()
return ticket
ticket = newUpgradeDecision()
ticket.newContent(
portal_type="Upgrade Decision Line"
).setAggregateValue(document)
open_related_ticket_list = document.Base_getOpenRelatedTicketList()
# Not indexed yet
self.assertEqual(len(open_related_ticket_list), 0)
self.tic()
open_related_ticket_list = document.Base_getOpenRelatedTicketList()
self.assertEqual(len(open_related_ticket_list), 0)
ticket.cancel()
ticket.immediateReindexObject()
open_related_ticket_list = document.Base_getOpenRelatedTicketList()
self.assertEqual(len(open_related_ticket_list), 0)
class TestSlapOSComputeNode_notifyWrongAllocationScope(TestCRMSkinsMixin):
def afterSetUp(self):
TestCRMSkinsMixin.afterSetUp(self)
self.project = self.addProject()
self._cancelTestSupportRequestList(title="%%TESTCOMPT-%")
def _getGeneratedSupportRequest(self, compute_node):
request_title = '%%We have changed allocation scope for %s' % \
compute_node.getReference()
support_request = self.portal.portal_catalog.getResultValue(
portal_type = 'Support Request',
title = request_title,
simulation_state = 'suspended',
default_aggregate_uid = compute_node.getUid()
)
return support_request
def _makeNotificationMessage(self, reference):
notification_message = self.portal.notification_message_module.newContent(
portal_type="Notification Message",
title='We have changed allocation scope for %s' % reference,
text_content='Test NM content<br/>%s<br/>' % reference,
content_type='text/html',
)
return notification_message.getRelativeUrl()
@simulate('ERP5Site_isSupportRequestCreationClosed', '*args, **kwargs','return 0')
@simulate('NotificationTool_getDocumentValue',
'reference=None',
'assert reference == "slapos-crm-compute_node_allocation_scope.notification"\n' \
'return context.restrictedTraverse(' \
'context.REQUEST["test_ComputeNodeNotAllowedAllocationScope_OpenPublic"])')
def test_ComputeNodeNotAllowedAllocationScope_OpenPublic(self):
compute_node = self._makeComputeNode(self.project)[0]#, owner=self.makePerson(self.project, user=0))[0]
person = compute_node.getSourceAdministrationValue()
self.portal.REQUEST['test_ComputeNodeNotAllowedAllocationScope_OpenPublic'] = \
self._makeNotificationMessage(compute_node.getReference())
compute_node.edit(allocation_scope='open/public')
ticket = compute_node.ComputeNode_checkAndUpdateAllocationScope()
self.tic()
self.assertEqual(compute_node.getAllocationScope(), 'open/personal')
#ticket = self._getGeneratedSupportRequest(compute_node)
self.assertNotEqual(None, ticket)
self.assertEqual(ticket.getSimulationState(), 'suspended')
event_list = ticket.getFollowUpRelatedValueList()
self.assertEqual(len(event_list), 1)
event = event_list[0]
self.assertEqual(event.getTitle(),
'Allocation scope of %s changed to %s' % (compute_node.getReference(), 'open/personal'))
self.assertIn(compute_node.getReference(), event.getTextContent())
self.assertEqual(event.getSource(), person.getRelativeUrl())
self.assertEqual(event.getDestination(), ticket.getSourceSection())
@simulate('ERP5Site_isSupportRequestCreationClosed', '*args, **kwargs','return 0')
@simulate('NotificationTool_getDocumentValue',
'reference=None',
'assert reference == "slapos-crm-compute_node_allocation_scope.notification"\n' \
'return context.restrictedTraverse(' \
'context.REQUEST["test_ComputeNodeNotAllowedAllocationScope_OpenFriend"])')
def test_ComputeNodeNotAllowedAllocationScope_OpenFriend(self):
compute_node = self._makeComputeNode(self.project)[0]#, owner=self.makePerson(self.project, user=0))[0]
person = compute_node.getSourceAdministrationValue()
self.portal.REQUEST['test_ComputeNodeNotAllowedAllocationScope_OpenFriend'] = \
self._makeNotificationMessage(compute_node.getReference())
friend_person = self.makePerson(self.project)
compute_node.edit(allocation_scope='open/friend',
destination_section=friend_person.getRelativeUrl())
ticket = compute_node.ComputeNode_checkAndUpdateAllocationScope()
self.tic()
self.assertEqual(compute_node.getAllocationScope(), 'open/personal')
self.assertEqual(ticket.getSimulationState(), 'suspended')
event_list = ticket.getFollowUpRelatedValueList()
self.assertEqual(len(event_list), 1)
event = event_list[0]
self.assertEqual(event.getTitle(),
'Allocation scope of %s changed to %s' % (compute_node.getReference(), 'open/personal'))
self.assertIn(compute_node.getReference(), event.getTextContent())
self.assertEqual(event.getSource(), person.getRelativeUrl())
self.assertEqual(event.getDestination(), ticket.getSourceSection())
@simulate('ERP5Site_isSupportRequestCreationClosed', '*args, **kwargs','return 0')
@simulate('ComputeNode_hasContactedRecently', '*args, **kwargs','return False')
@simulate('NotificationTool_getDocumentValue',
'reference=None',
'assert reference == "slapos-crm-compute-node-allocation-scope-closed.notification"\n' \
'return context.restrictedTraverse(' \
'context.REQUEST["test_ComputeNodeToCloseAllocationScope_OpenPersonal"])')
def test_ComputeNodeToCloseAllocationScope_OpenPersonal(self):
compute_node = self._makeComputeNode(self.project)[0]#, owner=self.makePerson(self.project, user=0))[0]
person = compute_node.getSourceAdministrationValue()
target_allocation_scope = 'close/outdated'
self.portal.REQUEST['test_ComputeNodeToCloseAllocationScope_OpenPersonal'] = \
self._makeNotificationMessage(compute_node.getReference())
compute_node.edit(allocation_scope='open/personal')
support_request = compute_node.ComputeNode_checkAndUpdatePersonalAllocationScope()
self.tic()
self.assertEqual('suspended', support_request.getSimulationState())
self.assertEqual(compute_node.getAllocationScope(), target_allocation_scope)
event_list = support_request.getFollowUpRelatedValueList()
self.assertEqual(len(event_list), 1)
event = event_list[0]
self.assertEqual(event.getTitle(),
'Allocation scope of %s changed to %s' % \
(compute_node.getReference(), target_allocation_scope))
self.assertIn(compute_node.getReference(), event.getTextContent())
self.assertEqual(event.getSource(), person.getRelativeUrl())
self.assertEqual(event.getDestination(), support_request.getSourceSection())
def test_ComputeNodeNormalAllocationScope_OpenPersonal(self):
compute_node = self._makeComputeNode(self.project)[0]#, owner=self.makePerson(self.project, user=0))[0]
person = compute_node.getSourceAdministrationValue()
self._updatePersonAssignment(person, 'role/service_provider')
compute_node.edit(allocation_scope='open/personal')
compute_node.ComputeNode_checkAndUpdateAllocationScope()
self.tic()
self.assertEqual(compute_node.getAllocationScope(), 'open/personal')
def test_ComputeNodeAllowedAllocationScope_OpenPublic(self):
compute_node = self._makeComputeNode(self.project)[0]#, owner=self.makePerson(self.project, user=0))[0]
person = compute_node.getSourceAdministrationValue()
self._updatePersonAssignment(person, 'role/service_provider')
compute_node.edit(allocation_scope='open/public')
compute_node.ComputeNode_checkAndUpdateAllocationScope()
self.tic()
self.assertEqual(compute_node.getAllocationScope(), 'open/public')
def test_ComputeNodeAllowedAllocationScope_OpenFriend(self):
compute_node = self._makeComputeNode(self.project)[0]#, owner=self.makePerson(self.project, user=0))[0]
friend_person = self.makePerson(self.project)
person = compute_node.getSourceAdministrationValue()
self._updatePersonAssignment(person, 'role/service_provider')
compute_node.edit(allocation_scope='open/friend',
destination_section=friend_person.getRelativeUrl())
compute_node.ComputeNode_checkAndUpdateAllocationScope()
self.tic()
self.assertEqual(compute_node.getAllocationScope(), 'open/friend')
class TestComputeNode_hasContactedRecently(SlapOSTestCaseMixinWithAbort): class TestComputeNode_hasContactedRecently(SlapOSTestCaseMixinWithAbort):
def createSPL(self, compute_node):
delivery_template = self.portal.restrictedTraverse(
self.portal.portal_preferences.getPreferredInstanceDeliveryTemplate())
delivery = delivery_template.Base_createCloneDocument(batch_mode=1)
delivery.edit(
title="TEST SPL COMP %s" % compute_node.getReference(),
start_date=compute_node.getCreationDate(),
)
delivery.newContent(
portal_type="Sale Packing List Line",
title="SPL Line for %s" % compute_node.getReference(),
quantity=1,
aggregate_value_list=compute_node,
)
delivery.confirm(comment="Created from %s" % compute_node.getRelativeUrl())
delivery.start()
delivery.stop()
delivery.deliver()
return delivery
def test_ComputeNode_hasContactedRecently_newly_created(self): def test_ComputeNode_hasContactedRecently_newly_created(self):
compute_node = self._makeComputeNode(self.project)[0] compute_node, _ = self._makeComputeNode(self.addProject())
self.tic() self.tic()
has_contacted = compute_node.ComputeNode_hasContactedRecently() has_contacted = compute_node.ComputeNode_hasContactedRecently()
self.assertTrue(has_contacted) self.assertTrue(has_contacted)
@simulate('ComputeNode_getCreationDate', '*args, **kwargs','return DateTime() - 32')
def test_ComputeNode_hasContactedRecently_no_data(self): def test_ComputeNode_hasContactedRecently_no_data(self):
compute_node = self._makeComputeNode(self.project)[0] try:
self.pinDateTime(DateTime()-32)
compute_node, _ = self._makeComputeNode(self.addProject())
finally:
self.unpinDateTime()
self.tic() self.tic()
compute_node.getCreationDate = self.portal.ComputeNode_getCreationDate
has_contacted = compute_node.ComputeNode_hasContactedRecently() has_contacted = compute_node.ComputeNode_hasContactedRecently()
self.assertFalse(has_contacted) self.assertFalse(has_contacted)
@simulate('ComputeNode_getCreationDate', '*args, **kwargs','return DateTime() - 32')
def test_ComputeNode_hasContactedRecently_memcached(self): def test_ComputeNode_hasContactedRecently_memcached(self):
compute_node = self._makeComputeNode(self.project)[0]
compute_node.setAccessStatus("")
self.tic()
compute_node.getCreationDate = self.portal.ComputeNode_getCreationDate
has_contacted = compute_node.ComputeNode_hasContactedRecently()
self.assertTrue(has_contacted)
@simulate('ComputeNode_getCreationDate', '*args, **kwargs','return DateTime() - 32')
def test_ComputeNode_hasContactedRecently_memcached_oudated_no_spl(self):
compute_node = self._makeComputeNode(self.project)[0]
try: try:
self.pinDateTime(DateTime()-32) self.pinDateTime(DateTime()-32)
compute_node.setAccessStatus("") compute_node, _ = self._makeComputeNode(self.addProject())
finally: finally:
self.unpinDateTime() self.unpinDateTime()
compute_node.setAccessStatus("")
self.tic() self.tic()
compute_node.getCreationDate = self.portal.ComputeNode_getCreationDate
has_contacted = compute_node.ComputeNode_hasContactedRecently() has_contacted = compute_node.ComputeNode_hasContactedRecently()
self.assertFalse(has_contacted) self.assertTrue(has_contacted)
@simulate('ComputeNode_getCreationDate', '*args, **kwargs','return DateTime() - 32') def test_ComputeNode_hasContactedRecently_memcached_oudated_no_spl(self):
def test_ComputeNode_hasContactedRecently_memcached_oudated_with_spl(self):
compute_node = self._makeComputeNode(self.project)[0]
try: try:
self.pinDateTime(DateTime()-32) self.pinDateTime(DateTime()-32)
compute_node, _ = self._makeComputeNode(self.addProject())
compute_node.setAccessStatus("") compute_node.setAccessStatus("")
finally: finally:
self.unpinDateTime() self.unpinDateTime()
self.createSPL(compute_node)
self.tic() self.tic()
compute_node.getCreationDate = self.portal.ComputeNode_getCreationDate
has_contacted = compute_node.ComputeNode_hasContactedRecently() has_contacted = compute_node.ComputeNode_hasContactedRecently()
self.assertFalse(has_contacted) self.assertFalse(has_contacted)
class TestSlapOSisSupportRequestCreationClosed(TestCRMSkinsMixin): class TestSlapOSisSupportRequestCreationClosed(TestCRMSkinsMixin):
def afterSetUp(self): def afterSetUp(self):
...@@ -967,440 +299,25 @@ class TestSlapOSisSupportRequestCreationClosed(TestCRMSkinsMixin): ...@@ -967,440 +299,25 @@ class TestSlapOSisSupportRequestCreationClosed(TestCRMSkinsMixin):
self.assertFalse(self.portal.ERP5Site_isSupportRequestCreationClosed()) self.assertFalse(self.portal.ERP5Site_isSupportRequestCreationClosed())
class TestSlapOSComputeNode_CheckState(TestCRMSkinsMixin): class TestSlapOSHasError(SlapOSTestCaseMixin):
def beforeTearDown(self):
self._cancelTestSupportRequestList()
transaction.abort()
def afterSetUp(self):
TestCRMSkinsMixin.afterSetUp(self)
self.project = self.addProject()
self._cancelTestSupportRequestList("% TESTCOMPT-%")
def _makeNotificationMessage(self, reference):
notification_message = self.portal.notification_message_module.newContent(
portal_type="Notification Message",
title='The Compute Node %s has not contacted the server for more than 24 hours' % reference,
text_content='Test NM content<br/>%s<br/>' % reference,
content_type='text/html',
)
return notification_message.getRelativeUrl()
def _getGeneratedSupportRequest(self, compute_node_uid, request_title): def test_SoftwareInstance_hasReportedError(self):
support_request = self.portal.portal_catalog.getResultValue( instance = self.portal.software_instance_module.newContent(
portal_type = 'Support Request', portal_type="Software Instance",
title = request_title, reference=self.generateNewId()
simulation_state = 'validated',
default_aggregate_uid = compute_node_uid
) )
return support_request _, partition = self._makeComputeNode(self.addProject())
@simulate('ERP5Site_isSupportRequestCreationClosed', '*args, **kwargs','return 0')
def test_ComputeNode_checkState_call_support_request(self):
compute_node = self._makeComputeNode(self.project)[0]#, owner=self.makePerson(user=0))[0]
try:
d = DateTime() - 1.1
self.pinDateTime(d)
compute_node.setAccessStatus("")
finally:
self.unpinDateTime()
compute_node_support_request = compute_node.ComputeNode_checkState()
self.assertNotEqual(compute_node_support_request, None)
self.assertIn("[MONITORING] Lost contact with compute_node",
compute_node_support_request.getTitle())
self.assertIn("has not contacted the server for more than 30 minutes",
compute_node_support_request.getDescription())
self.assertIn(d.strftime("%Y/%m/%d %H:%M:%S"),
compute_node_support_request.getDescription())
@simulate('ERP5Site_isSupportRequestCreationClosed', '*args, **kwargs','return 0')
def test_ComputeNode_checkState_empty_cache(self):
compute_node = self._makeComputeNode(self.project)[0]#, owner=self.makePerson(user=0))[0]
compute_node_support_request = compute_node.ComputeNode_checkState()
compute_node_support_request = compute_node.ComputeNode_checkState()
self.assertNotEqual(compute_node_support_request, None)
self.assertIn("[MONITORING] Lost contact with compute_node",
compute_node_support_request.getTitle())
self.assertIn("has not contacted the server (No Contact Information)",
compute_node_support_request.getDescription())
@simulate('ERP5Site_isSupportRequestCreationClosed', '*args, **kwargs','return 0')
@simulate('NotificationTool_getDocumentValue',
'reference=None',
'assert reference == "slapos-crm-compute_node_check_state.notification"\n' \
'return context.restrictedTraverse(' \
'context.REQUEST["test_ComputeNode_checkState_notify"])')
def test_ComputeNode_checkState_notify(self):
compute_node = self._makeComputeNode(self.project)[0]#, owner=self.makePerson(user=0))[0]
person = compute_node.getSourceAdministrationValue()
try:
self.pinDateTime(DateTime()-1.1)
compute_node.setAccessStatus("")
finally:
self.unpinDateTime()
self.portal.REQUEST['test_ComputeNode_checkState_notify'] = \
self._makeNotificationMessage(compute_node.getReference())
compute_node.ComputeNode_checkState()
self.tic()
ticket_title = "[MONITORING] Lost contact with compute_node %s" % compute_node.getReference()
ticket = self._getGeneratedSupportRequest(compute_node.getUid(), ticket_title)
self.assertNotEqual(ticket, None)
event_list = ticket.getFollowUpRelatedValueList()
self.assertEqual(len(event_list), 1)
event = event_list[0]
self.assertEqual(event.getTitle(), ticket.getTitle())
self.assertIn(compute_node.getReference(), event.getTextContent())
self.assertEqual(event.getSource(), person.getRelativeUrl())
self.assertEqual(event.getDestination(), ticket.getSourceSection())
@simulate('ERP5Site_isSupportRequestCreationClosed', '*args, **kwargs','return 0')
@simulate('NotificationTool_getDocumentValue',
'reference=None',
'assert reference == "slapos-crm-compute_node_check_state.notification"\n' \
'return context.restrictedTraverse(' \
'context.REQUEST["test_ComputeNode_checkState_empty_cache_notify"])')
def test_ComputeNode_checkState_empty_cache_notify(self):
compute_node = self._makeComputeNode(self.project)[0]#, owner=self.makePerson(user=0))[0]
person = compute_node.getSourceAdministrationValue()
self.portal.REQUEST['test_ComputeNode_checkState_empty_cache_notify'] = \
self._makeNotificationMessage(compute_node.getReference())
compute_node.ComputeNode_checkState()
self.tic()
ticket_title = "[MONITORING] Lost contact with compute_node %s" % compute_node.getReference()
ticket = self._getGeneratedSupportRequest(compute_node.getUid(), ticket_title)
self.assertNotEqual(ticket, None)
event_list = ticket.getFollowUpRelatedValueList()
self.assertEqual(len(event_list), 1)
event = event_list[0]
self.assertEqual(event.getTitle(), ticket.getTitle())
self.assertIn(compute_node.getReference(), event.getTextContent())
self.assertEqual(event.getDestination(), ticket.getSourceSection())
self.assertEqual(event.getSource(), person.getRelativeUrl())
@simulate('ERP5Site_isSupportRequestCreationClosed', '*args, **kwargs','return 0')
@simulate('NotificationTool_getDocumentValue',
'reference=None',
'assert reference == "slapos-crm-compute_node_check_stalled_instance_state.notification", reference\n' \
'return context.restrictedTraverse(' \
'context.REQUEST["test_ComputeNode_checkState_stalled_instance"])')
def test_ComputeNode_checkState_stalled_instance(self):
compute_node = self._makeComputeNode(self.project)[0]#, owner=self.makePerson(user=0))[0]
self._makeComplexComputeNode(self.project)
person = compute_node.getSourceAdministrationValue()
self.portal.REQUEST['test_ComputeNode_checkState_stalled_instance'] = \
self._makeNotificationMessage(compute_node.getReference())
# Computer is getting access
compute_node.setAccessStatus("")
try:
self.pinDateTime(DateTime()-1.1)
self.start_requested_software_instance.setAccessStatus("")
finally:
self.unpinDateTime()
compute_node.ComputeNode_checkState()
self.tic()
ticket_title = "[MONITORING] Compute Node %s has a stalled instance process" % compute_node.getReference()
ticket = self._getGeneratedSupportRequest(compute_node.getUid(), ticket_title)
self.assertNotEqual(ticket, None)
event_list = ticket.getFollowUpRelatedValueList()
self.assertEqual(len(event_list), 1)
event = event_list[0]
self.assertEqual(event.getTitle(), ticket.getTitle())
self.assertIn(compute_node.getReference(), event.getTextContent())
self.assertEqual(event.getDestination(), ticket.getSourceSection())
self.assertEqual(event.getSource(), person.getRelativeUrl())
@simulate('ERP5Site_isSupportRequestCreationClosed', '*args, **kwargs','return 0')
@simulate('NotificationTool_getDocumentValue',
'reference=None',
'assert reference == "slapos-crm-compute_node_check_stalled_software_state.notification", reference\n' \
'return context.restrictedTraverse(' \
'context.REQUEST["test_ComputeNode_checkState_stalled_software"])')
def test_ComputeNode_checkState_stalled_software(self):
compute_node = self._makeComputeNode(self.project)[0]#, owner=self.makePerson(user=0))[0]
self._makeComplexComputeNode(self.project)
person = compute_node.getSourceAdministrationValue()
self.portal.REQUEST['test_ComputeNode_checkState_stalled_software'] = \
self._makeNotificationMessage(compute_node.getReference())
# Computer is getting access, also internal instance
compute_node.setAccessStatus("")
self.start_requested_software_instance.setAccessStatus("")
try:
self.pinDateTime(DateTime()-1.1)
self.start_requested_software_installation.setAccessStatus("")
finally:
self.unpinDateTime()
compute_node.ComputeNode_checkState()
self.tic()
ticket_title = "[MONITORING] Compute Node %s has a stalled software process" % compute_node.getReference()
ticket = self._getGeneratedSupportRequest(compute_node.getUid(), ticket_title)
self.assertNotEqual(ticket, None)
event_list = ticket.getFollowUpRelatedValueList()
self.assertEqual(len(event_list), 1)
event = event_list[0]
self.assertEqual(event.getTitle(), ticket.getTitle())
self.assertIn(compute_node.getReference(), event.getTextContent())
self.assertEqual(event.getDestination(), ticket.getSourceSection())
self.assertEqual(event.getSource(), person.getRelativeUrl())
@simulate('ERP5Site_isSupportRequestCreationClosed', '*args, **kwargs','return 0')
@simulate('NotificationTool_getDocumentValue',
'reference=None',
'assert reference == "slapos-crm-compute_node_check_stalled_instance_state.notification", reference\n' \
'return context.restrictedTraverse(' \
'context.REQUEST["test_ComputeNode_checkState_stalled_instance"])')
def test_ComputeNode_checkState_stalled_instance_single(self):
compute_node = self._makeComputeNode(self.project)[0]#, owner=self.makePerson(user=0))[0]
self._makeComplexComputeNode(self.project)
person = compute_node.getSourceAdministrationValue()
self.portal.REQUEST['test_ComputeNode_checkState_stalled_instance'] = \
self._makeNotificationMessage(compute_node.getReference())
# Computer is getting access
compute_node.setAccessStatus("")
error_date = DateTime()
try: try:
self.pinDateTime(DateTime()-1.1) self.pinDateTime(error_date)
self.start_requested_software_instance.setAccessStatus("") instance.setErrorStatus("")
self.start_requested_software_installation.setAccessStatus("")
finally: finally:
self.unpinDateTime() self.unpinDateTime()
compute_node.ComputeNode_checkState()
self.tic()
ticket_title = "[MONITORING] Compute Node %s has a stalled instance process" % compute_node.getReference()
ticket = self._getGeneratedSupportRequest(compute_node.getUid(), ticket_title)
self.assertNotEqual(ticket, None)
event_list = ticket.getFollowUpRelatedValueList()
self.assertEqual(len(event_list), 1)
event = event_list[0]
self.assertEqual(event.getTitle(), ticket.getTitle())
self.assertIn(compute_node.getReference(), event.getTextContent())
self.assertEqual(event.getDestination(), ticket.getSourceSection())
self.assertEqual(event.getSource(), person.getRelativeUrl())
class TestSlapOSInstanceTree_createSupportRequestEvent(SlapOSTestCaseMixin):
def _makeNotificationMessage(self, reference):
notification_message = self.portal.notification_message_module.newContent(
portal_type="Notification Message",
title='%s created an event' % reference,
text_content='Test NM content<br/>%s<br/>' % reference,
content_type='text/html',
)
return notification_message.getRelativeUrl()
def _makeInstanceTree(self):
person = self.makePerson(self.project, user=1)
instance_tree = self.portal\
.instance_tree_module.template_instance_tree\
.Base_createCloneDocument(batch_mode=1)
instance_tree.validate()
new_id = self.generateNewId()
instance_tree.edit(
title= "Test hosting sub ticket %s" % new_id,
reference="TESTHST-%s" % new_id,
destination_section_value=person
)
return instance_tree
def _getGeneratedSupportRequest(self, instance_tree_uid):
support_request = self.portal.portal_catalog.getResultValue(
portal_type = 'Support Request',
simulation_state = "validated",
default_aggregate_uid = instance_tree_uid
)
return support_request
@simulate('ERP5Site_isSupportRequestCreationClosed', '*args, **kwargs','return 0')
@simulate('SoftwareInstance_hasReportedError', '*args, **kwargs','return "MSG"')
@simulate('NotificationTool_getDocumentValue',
'reference=None',
'assert reference == "test-slapos-crm-check.notification"\n' \
'return context.restrictedTraverse(' \
'context.REQUEST["testInstanceTree_createSupportRequestEvent"])')
def testInstanceTree_createSupportRequestEvent(self):
instance_tree = self._makeInstanceTree()
person = instance_tree.getDestinationSectionValue()
self.portal.REQUEST['testInstanceTree_createSupportRequestEvent'] = \
self._makeNotificationMessage(instance_tree.getReference())
instance_tree.InstanceTree_createSupportRequestEvent(
instance_tree, "test-slapos-crm-check.notification")
self.tic()
ticket_title = "Instance Tree %s is failing." % instance_tree.getTitle()
ticket = self._getGeneratedSupportRequest(
instance_tree.getUid())
self.assertNotEqual(ticket, None)
self.assertEqual(ticket.getSimulationState(), "validated")
self.assertNotEqual(ticket, None)
event_list = ticket.getFollowUpRelatedValueList()
self.assertEqual(len(event_list), 1)
event = event_list[0]
self.assertEqual(event.getTitle(), ticket_title)
self.assertIn(instance_tree.getReference(), event.getTextContent())
self.assertEqual(event.getSource(), person.getRelativeUrl())
self.assertEqual(event.getDestination(), ticket.getSourceSection())
ticket.suspend()
self.tic()
self.assertEqual(None, self._getGeneratedSupportRequest(
instance_tree.getUid()))
instance_tree.InstanceTree_createSupportRequestEvent(
instance_tree, "test-slapos-crm-check.notification")
self.tic()
ticket = self._getGeneratedSupportRequest(
instance_tree.getUid())
# Do not reopen the ticket if it is suspended
self.assertEqual(None, ticket)
@simulate('ERP5Site_isSupportRequestCreationClosed', '*args, **kwargs','return 1')
@simulate('SoftwareInstance_hasReportedError', '*args, **kwargs','return "MSG"')
def testInstanceTree_createSupportRequestEvent_closed(self):
instance_tree = self._makeInstanceTree()
self.assertEqual(None,
instance_tree.InstanceTree_createSupportRequestEvent(
instance_tree, "test-slapos-crm-check.notification"))
@simulate('ERP5Site_isSupportRequestCreationClosed', '*args, **kwargs','return 0')
@simulate('SoftwareInstance_hasReportedError', '*args, **kwargs','return "MSG"')
def testInstanceTree_createSupportRequestEvent_no_person(self):
instance_tree = self._makeInstanceTree()
instance_tree.setDestinationSectionValue(None)
self.assertEqual(None,
instance_tree.InstanceTree_createSupportRequestEvent(
instance_tree, "test-slapos-crm-check.notification"))
class TestSlapOSHasError(SlapOSTestCaseMixin):
def makeSoftwareRelease(self, software_release_url=None):
software_release = self.portal.software_release_module\
.template_software_release.Base_createCloneDocument(batch_mode=1)
new_id = self.generateNewId()
software_release.edit(
url_string=software_release_url or self.generateNewSoftwareReleaseUrl(),
reference='TESTSOFTRELS-%s' % new_id,
title='Start requested for %s' % new_id
)
software_release.release()
return software_release
def _makeSoftwareInstallation(self, software_release_url):
software_installation = self.portal\
.software_installation_module.template_software_installation\
.Base_createCloneDocument(batch_mode=1)
new_id = self.generateNewId()
software_installation.edit(
url_string=software_release_url,
aggregate=self.compute_node.getRelativeUrl(),
reference='TESTSOFTINSTS-%s' % new_id,
title='Start requested for %s' % self.compute_node.getUid()
)
software_installation.validate()
software_installation.requestStart()
return software_installation
def _makeSoftwareInstance(self, instance_tree, software_url):
kw = dict(
software_release=software_url,
software_type=self.generateNewSoftwareType(),
instance_xml=self.generateSafeXml(),
sla_xml=self.generateSafeXml(),
shared=False,
software_title=instance_tree.getTitle(),
state='started'
)
instance_tree.requestStart(**kw)
instance_tree.requestInstance(**kw)
def _makeInstanceTree(self):
person = self.portal.person_module.template_member\
.Base_createCloneDocument(batch_mode=1)
instance_tree = self.portal\
.instance_tree_module.template_instance_tree\
.Base_createCloneDocument(batch_mode=1)
instance_tree.validate()
new_id = self.generateNewId()
instance_tree.edit(
title= "Test hosting sub ticket %s" % new_id,
reference="TESTHST-%s" % new_id,
destination_section_value=person
)
return instance_tree
def _makeComputePartitionList(self):
for i in range(1, 5):
id_ = 'partition%s' % (i, )
p = self.compute_node.newContent(portal_type='Compute Partition',
id=id_,
title=id_,
reference=id_,
default_network_address_ip_address='ip_address_%s' % i,
default_network_address_netmask='netmask_%s' % i)
p.markFree()
p.validate()
def test_SoftwareInstance_hasReportedError(self):
instance_tree = self._makeInstanceTree()
self._makeSoftwareInstance(instance_tree,
self.generateNewSoftwareReleaseUrl())
instance = instance_tree.getSuccessorValue()
self._makeComputeNode(self.project)
self._makeComputePartitionList()
instance.setErrorStatus("")
self.assertEqual(instance.SoftwareInstance_hasReportedError(), None) self.assertEqual(instance.SoftwareInstance_hasReportedError(), None)
instance.setAggregateValue(self.compute_node.partition1) instance.setAggregateValue(partition)
self.assertEqual(str(instance.SoftwareInstance_hasReportedError()), '#error ') self.assertEqual(str(instance.SoftwareInstance_hasReportedError()), '#error ')
...@@ -1408,11 +325,7 @@ class TestSlapOSHasError(SlapOSTestCaseMixin): ...@@ -1408,11 +325,7 @@ class TestSlapOSHasError(SlapOSTestCaseMixin):
self.assertEqual(instance.SoftwareInstance_hasReportedError(), None) self.assertEqual(instance.SoftwareInstance_hasReportedError(), None)
def test_SoftwareInstallation_hasReportedError(self): def test_SoftwareInstallation_hasReportedError(self):
software_release = self.makeSoftwareRelease() installation = self.portal.software_installation_module.newContent()
self._makeComputeNode(self.project)
installation = self._makeSoftwareInstallation(
software_release.getUrlString()
)
self.assertEqual(installation.SoftwareInstallation_hasReportedError(), None) self.assertEqual(installation.SoftwareInstallation_hasReportedError(), None)
...@@ -1430,192 +343,6 @@ class TestSlapOSHasError(SlapOSTestCaseMixin): ...@@ -1430,192 +343,6 @@ class TestSlapOSHasError(SlapOSTestCaseMixin):
self.assertEqual(installation.SoftwareInstallation_hasReportedError(), None) self.assertEqual(installation.SoftwareInstallation_hasReportedError(), None)
@simulate('ERP5Site_isSupportRequestCreationClosed', '','return 0')
@simulate('InstanceTree_createSupportRequestEvent',
'instance, notification_message_reference',
'return "Visited by InstanceTree_createSupportRequestEvent ' \
'%s %s" % (instance.getUid(), notification_message_reference)')
def testInstanceTree_checkSoftwareInstanceState(self):
date = DateTime()
def getCreationDate(*args, **kwargs):
return date - 2
from Products.ERP5Type.Base import Base
original_get_creation = Base.getCreationDate
Base.getCreationDate = getCreationDate
try:
instance_tree = self._makeInstanceTree()
self.assertEqual(instance_tree.getCreationDate(), date - 2)
self._makeSoftwareInstance(instance_tree,
self.generateNewSoftwareReleaseUrl())
instance = instance_tree.getSuccessorValue()
self.assertEqual(instance.getCreationDate(), date - 2)
self._makeComputeNode(self.project)
self._makeComputePartitionList()
instance.setAggregateValue(self.compute_node.partition1)
error_date = DateTime()
value = json.dumps(
{"created_at":"%s" % error_date, "text": "#error ", "since": "%s" % (error_date - 2)}
)
cache_duration = instance._getAccessStatusCacheFactory().cache_duration
instance._getAccessStatusPlugin().set(instance._getAccessStatusCacheKey(),
DEFAULT_CACHE_SCOPE, value, cache_duration=cache_duration)
self.assertEqual(
'Visited by InstanceTree_createSupportRequestEvent %s %s' % \
(instance.getUid(),
"slapos-crm-instance-tree-instance-state.notification"),
instance_tree.InstanceTree_checkSoftwareInstanceState())
instance.setAccessStatus("")
self.assertEqual(None,
instance_tree.InstanceTree_checkSoftwareInstanceState())
finally:
Base.getCreationDate = original_get_creation
self.portal.portal_types.resetDynamicDocumentsOnceAtTransactionBoundary()
transaction.commit()
@simulate('ERP5Site_isSupportRequestCreationClosed', '','return 0')
@simulate('InstanceTree_createSupportRequestEvent',
'instance, notification_message_reference',
'return "Visited by InstanceTree_createSupportRequestEvent ' \
'%s %s" % (instance.getUid(), notification_message_reference)')
def testInstanceTree_checkSoftwareInstanceState_tolerance(self):
date = DateTime()
def getCreationDate(*args, **kwargs):
return date - 2
from Products.ERP5Type.Base import Base
original_get_creation = Base.getCreationDate
Base.getCreationDate = getCreationDate
try:
instance_tree = self._makeInstanceTree()
self.assertEqual(instance_tree.getCreationDate(), date - 2)
self._makeSoftwareInstance(instance_tree,
self.generateNewSoftwareReleaseUrl())
instance = instance_tree.getSuccessorValue()
self.assertEqual(instance.getCreationDate(), date - 2)
self._makeComputeNode(self.project)
self._makeComputePartitionList()
instance.setAggregateValue(self.compute_node.partition1)
memcached_dict = self.portal.portal_memcached.getMemcachedDict(
key_prefix='slap_tool',
plugin_path='portal_memcached/default_memcached_plugin')
error_date = DateTime()
memcached_dict[instance.getReference()] = json.dumps(
{"created_at":"%s" % error_date, "text": "#error ", "since": "%s" % error_date}
)
# With tolerance of 30 min this should create SupportRequests immediately
self.assertEqual(None,
instance_tree.InstanceTree_checkSoftwareInstanceState())
finally:
Base.getCreationDate = original_get_creation
self.portal.portal_types.resetDynamicDocumentsOnceAtTransactionBoundary()
transaction.commit()
@simulate('ERP5Site_isSupportRequestCreationClosed', '','return 0')
@simulate('InstanceTree_createSupportRequestEvent',
'instance, notification_message_reference',
'return "Visited by InstanceTree_createSupportRequestEvent ' \
'%s %s" % (instance.getRelativeUrl(), notification_message_reference)')
def testInstanceTree_checkSoftwareInstanceState_partially_allocation(self):
date = DateTime()
def getCreationDate(*args, **kwargs):
return date - 2
from Products.ERP5Type.Base import Base
original_get_creation = Base.getCreationDate
Base.getCreationDate = getCreationDate
try:
instance_tree = self._makeInstanceTree()
self.assertEqual(instance_tree.getCreationDate(), date - 2)
self._makeSoftwareInstance(instance_tree,
self.generateNewSoftwareReleaseUrl())
instance = instance_tree.getSuccessorValue()
self.assertEqual(instance.getCreationDate(), date - 2)
self._makeComputeNode(self.project)
self._makeComputePartitionList()
instance.setAggregateValue(self.compute_node.partition1)
kw = dict(
software_release=instance_tree.getUrlString(),
software_type=self.generateNewSoftwareType(),
instance_xml=self.generateSafeXml(),
sla_xml=self.generateSafeXml(),
shared=False,
software_title="Another INstance %s" % self.generateNewId(),
state='started'
)
instance.requestInstance(**kw)
self.tic()
instance.setAccessStatus("")
self.assertEqual(
'Visited by InstanceTree_createSupportRequestEvent %s %s' % \
(instance.getSuccessor(portal_type="Software Instance"),
"slapos-crm-instance-tree-instance-allocation.notification"),
instance_tree.InstanceTree_checkSoftwareInstanceState())
kw["state"] = "destroyed"
instance.requestInstance(**kw)
self.tic()
self.assertEqual(
None,
instance_tree.InstanceTree_checkSoftwareInstanceState())
finally:
Base.getCreationDate = original_get_creation
self.portal.portal_types.resetDynamicDocumentsOnceAtTransactionBoundary()
transaction.commit()
@simulate('ERP5Site_isSupportRequestCreationClosed', '','return 0')
def testInstanceTree_checkSoftwareInstanceState_too_early(self):
instance_tree = self._makeInstanceTree()
self._makeSoftwareInstance(instance_tree,
self.generateNewSoftwareReleaseUrl())
instance = instance_tree.getSuccessorValue()
self._makeComputeNode(self.project)
self._makeComputePartitionList()
instance.setAggregateValue(self.compute_node.partition1)
instance.setErrorStatus("")
self.assertEqual(
None,
instance_tree.InstanceTree_checkSoftwareInstanceState())
class TestCRMPropertySheetConstraint(SlapOSTestCaseMixin): class TestCRMPropertySheetConstraint(SlapOSTestCaseMixin):
...@@ -1624,8 +351,6 @@ class TestCRMPropertySheetConstraint(SlapOSTestCaseMixin): ...@@ -1624,8 +351,6 @@ class TestCRMPropertySheetConstraint(SlapOSTestCaseMixin):
portal = self.getPortalObject() portal = self.getPortalObject()
self.project = self.addProject() self.project = self.addProject()
self.ticket_trade_condition = portal.sale_trade_condition_module.slapos_ticket_trade_condition
person_user = self.makePerson(self.project) person_user = self.makePerson(self.project)
self.tic() self.tic()
...@@ -1637,8 +362,9 @@ class TestCRMPropertySheetConstraint(SlapOSTestCaseMixin): ...@@ -1637,8 +362,9 @@ class TestCRMPropertySheetConstraint(SlapOSTestCaseMixin):
self.support_request = portal.support_request_module.newContent( self.support_request = portal.support_request_module.newContent(
portal_type="Support Request", portal_type="Support Request",
destination_decision=person_user.getRelativeUrl(), destination_value=person_user,
specialise=self.ticket_trade_condition.getRelativeUrl() destination_decision_value=person_user,
#specialise=
) )
# Value set by the init # Value set by the init
...@@ -1651,13 +377,17 @@ class TestCRMPropertySheetConstraint(SlapOSTestCaseMixin): ...@@ -1651,13 +377,17 @@ class TestCRMPropertySheetConstraint(SlapOSTestCaseMixin):
def testCheckCausalitySourceDestinationConsistency(self): def testCheckCausalitySourceDestinationConsistency(self):
person = self.portal.portal_membership.getAuthenticatedMember().getUserValue() person = self.portal.portal_membership.getAuthenticatedMember().getUserValue()
self.support_request.approveRegistration() self.support_request.Ticket_createProjectEvent(
"foo", "incoming", "Web Message",
self.portal.service_module.slapos_crm_information.getRelativeUrl(),
"bar", "text/plain"
)
self.tic() self.tic()
self.logout() self.logout()
self.login() self.login()
event = self.support_request.getCausalityValue() event = self.support_request.getFollowUpRelatedValue()
self.assertNotEqual(event, None) self.assertNotEqual(event, None)
self.assertFalse(event.checkConsistency()) self.assertFalse(event.checkConsistency())
...@@ -1680,13 +410,17 @@ class TestCRMPropertySheetConstraint(SlapOSTestCaseMixin): ...@@ -1680,13 +410,17 @@ class TestCRMPropertySheetConstraint(SlapOSTestCaseMixin):
def testCheckCustomerAsSourceOrDestinationConsistency(self): def testCheckCustomerAsSourceOrDestinationConsistency(self):
person = self.portal.portal_membership.getAuthenticatedMember().getUserValue() person = self.portal.portal_membership.getAuthenticatedMember().getUserValue()
self.support_request.approveRegistration() self.support_request.Ticket_createProjectEvent(
"foo", "incoming", "Web Message",
self.portal.service_module.slapos_crm_information.getRelativeUrl(),
"bar", "text/plain"
)
self.tic() self.tic()
self.logout() self.logout()
self.login() self.login()
event = self.support_request.getCausalityValue() event = self.support_request.getFollowUpRelatedValue()
self.assertNotEqual(event, None) self.assertNotEqual(event, None)
self.assertFalse(event.checkConsistency()) self.assertFalse(event.checkConsistency())
...@@ -1705,99 +439,13 @@ class TestCRMPropertySheetConstraint(SlapOSTestCaseMixin): ...@@ -1705,99 +439,13 @@ class TestCRMPropertySheetConstraint(SlapOSTestCaseMixin):
event.setDestination(person.getRelativeUrl()) event.setDestination(person.getRelativeUrl())
self.assertFalse(event.checkConsistency()) self.assertFalse(event.checkConsistency())
class TestSupportRequestUpdateMonitoringState(SlapOSTestCaseMixin):
def _makeInstanceTree(self):
person = self.portal.person_module.template_member\
.Base_createCloneDocument(batch_mode=1)
instance_tree = self.portal\
.instance_tree_module.template_instance_tree\
.Base_createCloneDocument(batch_mode=1)
instance_tree.validate()
new_id = self.generateNewId()
instance_tree.edit(
title= "Test hosting sub ticket %s" % new_id,
reference="TESTHST-%s" % new_id,
destination_section_value=person
)
return instance_tree
def _makeSupportRequest(self):
return self.portal.restrictedTraverse(
self.portal.portal_preferences.getPreferredSupportRequestTemplate()).\
Base_createCloneDocument(batch_mode=1)
@simulate('ERP5Site_isSupportRequestCreationClosed', '','return 0')
@simulate('SupportRequest_updateMonitoringDestroyRequestedState',
"",
'return "Visited by SupportRequest_updateMonitoringDestroyRequestedState '\
'%s" % (context.getRelativeUrl(),)')
def testSupportRequest_updateMonitoringState(self):
support_request = self._makeSupportRequest()
self.assertEqual(None,
support_request.SupportRequest_updateMonitoringState())
support_request.validate()
self.assertEqual(None,
support_request.SupportRequest_updateMonitoringState())
hs = self._makeInstanceTree()
support_request.setAggregateValue(hs)
hs.getSlapState = getFakeSlapState
self.assertEqual(
"Visited by SupportRequest_updateMonitoringDestroyRequestedState %s" %\
support_request.getRelativeUrl(),
support_request.SupportRequest_updateMonitoringState())
support_request.invalidate()
self.assertEqual(None,
support_request.SupportRequest_updateMonitoringState())
@simulate('ERP5Site_isSupportRequestCreationClosed', '','return 0')
def testSupportRequest_updateMonitoringDestroyRequestedState(self):
support_request = self._makeSupportRequest()
self.assertEqual(None,
support_request.SupportRequest_updateMonitoringDestroyRequestedState())
support_request.validate()
self.assertEqual(None,
support_request.SupportRequest_updateMonitoringDestroyRequestedState())
support_request.setAggregateValue(
self._makeComputeNode(self.project)[0])#, owner=self.makePerson(user=0))[0])
support_request.setDestinationDecisionValue(self.makePerson(self.project, user=0))
self.assertEqual(None,
support_request.SupportRequest_updateMonitoringDestroyRequestedState())
hs = self._makeInstanceTree()
support_request.setAggregateValue(hs)
self.tic()
hs.getSlapState = getFakeSlapState
self.commit()
self.assertNotEqual(None,
support_request.SupportRequest_updateMonitoringDestroyRequestedState())
self.tic()
event_list = support_request.getFollowUpRelatedValueList()
self.assertEqual(len(event_list), 1)
event = event_list[0]
self.assertEqual(event.getTitle(), 'Instance Tree was destroyed was destroyed by the user')
self.assertEqual(event.getSource(), support_request.getDestinationDecision())
self.assertEqual(event.getDestination(), support_request.getSourceSection())
self.assertEqual("invalidated",
support_request.getSimulationState())
class TestSlapOSFolder_getTicketFeedUrl(TestCRMSkinsMixin): class TestSlapOSFolder_getTicketFeedUrl(TestCRMSkinsMixin):
def _test(self, module): def _test(self, module):
self.assertRaises(ValueError, module.Folder_getTicketFeedUrl) self.assertRaises(ValueError, module.Folder_getTicketFeedUrl)
person = self.makePerson(self.project, user=1) person = self.makePerson(self.project, user=1)
self.addProjectProductionManagerAssignment(person, self.project)
self.tic() self.tic()
self.login(person.getUserId()) self.login(person.getUserId())
...@@ -1821,235 +469,3 @@ class TestSlapOSFolder_getTicketFeedUrl(TestCRMSkinsMixin): ...@@ -1821,235 +469,3 @@ class TestSlapOSFolder_getTicketFeedUrl(TestCRMSkinsMixin):
def test_Folder_getTicketFeedUrl_incident_response_module(self): def test_Folder_getTicketFeedUrl_incident_response_module(self):
self._test(self.portal.incident_response_module) self._test(self.portal.incident_response_module)
class TestSlapOSPerson_getSlapOSPendingTicket(TestCRMSkinsMixin):
def test_getSlapOSPendingTicket_support_request(self):
person = self.makePerson(self.project)
ticket = self.portal.support_request_module.newContent(\
title="Test Support Request %s" % self.new_id,
destination_decision=person.getRelativeUrl())
pending_ticket_list = person.Person_getSlapOSPendingTicket()
# Not indexed yet
self.assertEqual(len(pending_ticket_list), 0)
self.tic()
pending_ticket_list = person.Person_getSlapOSPendingTicket()
self.assertEqual(len(pending_ticket_list), 0)
ticket.submit()
ticket.immediateReindexObject()
pending_ticket_list = person.Person_getSlapOSPendingTicket()
self.assertEqual(len(pending_ticket_list), 0)
ticket.validate()
ticket.immediateReindexObject()
pending_ticket_list = person.Person_getSlapOSPendingTicket()
self.assertEqual(len(pending_ticket_list), 0)
ticket.suspend()
ticket.immediateReindexObject()
pending_ticket_list = person.Person_getSlapOSPendingTicket()
self.assertEqual(len(pending_ticket_list), 1)
self.assertEqual(pending_ticket_list[0].getUid(), ticket.getUid())
ticket.invalidate()
ticket.immediateReindexObject()
pending_ticket_list = person.Person_getSlapOSPendingTicket()
self.assertEqual(len(pending_ticket_list), 0)
def test_getSlapOSPendingTicket_support_request_cancelled(self):
person = self.makePerson(self.project)
ticket = self.portal.support_request_module.newContent(\
title="Test Support Request %s" % self.new_id,
destination_decision=person.getRelativeUrl())
pending_ticket_list = person.Person_getSlapOSPendingTicket()
# Not indexed yet
self.assertEqual(len(pending_ticket_list), 0)
self.tic()
pending_ticket_list = person.Person_getSlapOSPendingTicket()
self.assertEqual(len(pending_ticket_list), 0)
ticket.submit()
ticket.immediateReindexObject()
pending_ticket_list = person.Person_getSlapOSPendingTicket()
self.assertEqual(len(pending_ticket_list), 0)
ticket.cancel()
ticket.immediateReindexObject()
pending_ticket_list = person.Person_getSlapOSPendingTicket()
self.assertEqual(len(pending_ticket_list), 0)
def test_getSlapOSPendingTicket_upgrade_decision(self):
def newUpgradeDecision():
ticket = self.portal.upgrade_decision_module.newContent(
portal_type='Upgrade Decision',
title="Upgrade Decision Test %s" % self.new_id,
reference="TESTUD-%s" % self.new_id)
ticket.immediateReindexObject()
return ticket
person = self.makePerson(self.project)
ticket = newUpgradeDecision()
ticket.setDestinationDecisionValue(person)
ticket.newContent(
portal_type="Upgrade Decision Line"
)
pending_ticket_list = person.Person_getSlapOSPendingTicket()
# Not indexed yet
self.assertEqual(len(pending_ticket_list), 0)
self.tic()
pending_ticket_list = person.Person_getSlapOSPendingTicket()
self.assertEqual(len(pending_ticket_list), 0)
ticket.plan()
ticket.immediateReindexObject()
pending_ticket_list = person.Person_getSlapOSPendingTicket()
self.assertEqual(len(pending_ticket_list), 0)
ticket.confirm()
ticket.immediateReindexObject()
pending_ticket_list = person.Person_getSlapOSPendingTicket()
self.assertEqual(len(pending_ticket_list), 1)
self.assertEqual(pending_ticket_list[0].getUid(), ticket.getUid())
ticket.start()
ticket.immediateReindexObject()
pending_ticket_list = person.Person_getSlapOSPendingTicket()
self.assertEqual(len(pending_ticket_list), 0)
ticket.stop()
ticket.immediateReindexObject()
pending_ticket_list = person.Person_getSlapOSPendingTicket()
self.assertEqual(len(pending_ticket_list), 0)
ticket.deliver()
ticket.immediateReindexObject()
pending_ticket_list = person.Person_getSlapOSPendingTicket()
self.assertEqual(len(pending_ticket_list), 0)
def test_getSlapOSPendingTicket_upgrade_decision_cancel(self):
def newUpgradeDecision():
ticket = self.portal.upgrade_decision_module.newContent(
portal_type='Upgrade Decision',
title="Upgrade Decision Test %s" % self.new_id,
reference="TESTUD-%s" % self.new_id)
ticket.immediateReindexObject()
return ticket
person = self.makePerson(self.project)
ticket = newUpgradeDecision()
ticket.setDestinationDecisionValue(person)
ticket.newContent(
portal_type="Upgrade Decision Line"
)
pending_ticket_list = person.Person_getSlapOSPendingTicket()
# Not indexed yet
self.assertEqual(len(pending_ticket_list), 0)
self.tic()
pending_ticket_list = person.Person_getSlapOSPendingTicket()
self.assertEqual(len(pending_ticket_list), 0)
ticket.plan()
ticket.immediateReindexObject()
pending_ticket_list = person.Person_getSlapOSPendingTicket()
self.assertEqual(len(pending_ticket_list), 0)
ticket.cancel()
ticket.immediateReindexObject()
pending_ticket_list = person.Person_getSlapOSPendingTicket()
self.assertEqual(len(pending_ticket_list), 0)
class TestSlapOSPerson_getSlapOSPendingTicketMessageTemplate(TestCRMSkinsMixin):
@simulate('NotificationTool_getDocumentValue',
'reference=None',
'assert reference == "slapos-crm-person-pending-ticket-notification"\n' \
'return None')
@simulate('Person_getSlapOSPendingTicket', '*args, **kwargs','return range(99)')
def test_getSlapOSPendingTicketMessageTemplate(self):
person = self.makePerson(self.project)
# Test without notification message
title, message = person.Person_getSlapOSPendingTicketMessageTemplate()
self.assertEqual(""" You have 99 pending tickets """, title)
self.assertEqual(""" You have 99 pending tickets """, message)
def _makeNotificationMessage(self):
notification_message = self.portal.notification_message_module.newContent(
portal_type="Notification Message",
title='Pending ticket',
text_content_substitution_mapping_method_id='NotificationMessage_getSubstitutionMappingDictFromArgument',
text_content='Test NM content ${username} AMOUNT (${amount}) WEBSITE(${website})',
content_type='text/plain',
)
return notification_message.getRelativeUrl()
@simulate('Person_getSlapOSPendingTicket', '*args, **kwargs','return range(99)')
@simulate('NotificationTool_getDocumentValue',
'reference=None',
'assert reference == "slapos-crm-person-pending-ticket-notification"\n' \
'return context.restrictedTraverse(' \
'context.REQUEST["test_getSlapOSPendingTicketMessageTemplate"])')
def test_getSlapOSPendingTicketMessageTemplate_with_notification_message(self):
person = self.makePerson(self.project)
self.portal.REQUEST['test_getSlapOSPendingTicketMessageTemplate'] = \
self._makeNotificationMessage()
title, message = person.Person_getSlapOSPendingTicketMessageTemplate()
self.assertEqual('Pending ticket', title)
web_site_url = self.portal.portal_preferences.getPreferredSlaposWebSiteUrl()
self.assertEqual(message,
'Test NM content Member Template AMOUNT (99) WEBSITE(%s)' % web_site_url)
class TestSlapOSPerson_sendPendingTicketReminder(TestCRMSkinsMixin):
@simulate('Person_getSlapOSPendingTicket', '*args, **kwargs','return []')
@simulate('Person_sendSlapOSPendingTicketNotification', '*args, **kwargs','assert False')
def test_sendPendingTicketReminder(self):
person = self.makePerson(self.project)
# Script Person_sendSlapOSPendingTicketNotification not called
person.Person_sendPendingTicketReminder()
@simulate('Person_getSlapOSPendingTicket', '*args, **kwargs','return [1]')
@simulate('Person_sendSlapOSPendingTicketNotification', '*args, **kwargs',
'context.REQUEST.set("test_getSlapOSPendingTicketMessageTemplate", "called")')
def test_sendPendingTicketReminder_positive_amount(self):
person = self.makePerson(self.project)
person.Person_sendPendingTicketReminder()
self.assertEqual(self.portal.REQUEST["test_getSlapOSPendingTicketMessageTemplate"],
"called")
class TestSlapOSPerson_sendSlapOSPendingTicketNotification(TestCRMSkinsMixin):
def test_sendSlapOSPendingTicketNotification(self):
person = self.makePerson(self.project)
event = person.Person_sendSlapOSPendingTicketNotification(
"TEST TITLE",
"TEST CONTENT",
batch_mode=1
)
self.tic()
self.assertEqual(event.getTitle(), "TEST TITLE")
self.assertEqual(event.getTextContent(), "TEST CONTENT")
self.assertEqual(event.getSimulationState(), "started")
self.assertEqual(event.getPortalType(), "Mail Message")
self.assertEqual(event.getDestination(), person.getRelativeUrl())
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2002-2012 Nexedi SA and Contributors. All Rights Reserved.
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from erp5.component.test.SlapOSTestCaseMixin import SlapOSTestCaseMixin #, simulate
import transaction
class TestSlapOSCoreTicketSlapInterfaceWorkflow(SlapOSTestCaseMixin):
def afterSetUp(self):
SlapOSTestCaseMixin.afterSetUp(self)
portal = self.getPortalObject()
self.ticket_trade_condition = portal.sale_trade_condition_module.slapos_ticket_trade_condition
person_user = self.makePerson()
self.tic()
# Login as new user
self.login(person_user.getUserId())
new_person = self.portal.portal_membership.getAuthenticatedMember().getUserValue()
self.assertEqual(person_user.getRelativeUrl(), new_person.getRelativeUrl())
self.support_request = portal.support_request_module.newContent(
portal_type="Support Request",
destination_decision=person_user.getRelativeUrl(),
specialise=self.ticket_trade_condition.getRelativeUrl()
)
# Value set by the init
self.assertTrue(self.support_request.getReference().startswith("SR-"),
"Reference don't start with SR- : %s" % self.support_request.getReference())
def beforeTearDown(self):
transaction.abort()
def test_SupportRequest_approveRegistration_no_reference(self):
self.support_request.setReference(None)
self.assertRaises(ValueError, self.support_request.approveRegistration)
def test_SupportRequest_approveRegistration_already_validated(self):
# Login as admin since user cannot re-approve a validated project
self.login()
self.support_request.validate()
# Don't raise if support request is validated
self.assertEqual(self.support_request.approveRegistration(), None)
def test_SupportRequest_approveRegistration(self):
person = self.portal.portal_membership.getAuthenticatedMember().getUserValue()
self.support_request.approveRegistration()
self.tic()
self.logout()
self.login(person.getUserId())
self.assertEqual(self.support_request.getSimulationState(),
'validated')
self.assertEqual(self.support_request.getSourceSection(),
self.ticket_trade_condition.getSourceSection())
self.assertEqual(self.support_request.getSourceTrade(),
self.ticket_trade_condition.getSourceSection())
self.assertEqual(self.support_request.getSource(),
self.ticket_trade_condition.getSource())
self.assertNotEqual(self.support_request.getStartDate(),
None)
event = self.support_request.getCausalityValue()
self.assertNotEqual(event, None)
event_relative_url = self.support_request.REQUEST.get("event_relative_url")
self.assertEqual(event.getRelativeUrl(), event_relative_url)
self.assertEqual(event.getTitle(), self.support_request.getTitle())
def test_SupportRequest_requestEvent_noParameter(self):
self.assertRaises(TypeError, self.support_request.requestEvent)
self.assertRaises(TypeError, self.support_request.requestEvent, event_title="A")
self.assertRaises(TypeError, self.support_request.requestEvent, event_content="A")
self.assertRaises(TypeError, self.support_request.requestEvent, event_source="A")
def test_SupportRequest_requestEvent(self):
person = self.portal.portal_membership.getAuthenticatedMember().getUserValue()
self.support_request.approveRegistration()
self.tic()
self.logout()
self.login(person.getUserId())
self.support_request.requestEvent(
event_title="A",
event_content="B",
event_source=person.getRelativeUrl())
self.tic()
event_relative_url = self.support_request.REQUEST.get("event_relative_url")
event = self.portal.restrictedTraverse(event_relative_url)
self.assertEqual(event.getSimulationState(), "stopped")
self.assertEqual(self.support_request.getSimulationState(),
'validated')
self.assertEqual(self.support_request.getDestinationDecision(),
event.getSource())
self.assertEqual(person, event.getSourceValue())
self.assertEqual(self.support_request.getResource(),
event.getResource())
self.assertEqual(self.support_request,
event.getFollowUpValue())
self.assertEqual(event.getTitle(), "A")
self.assertEqual(event.getTextContent(), "B")
self.assertEqual(event.getContentType(), "text/plain")
self.assertEqual(event.getPortalType(), "Web Message")
self.assertEqual(event.getDestination(),
self.support_request.getSource())
self.assertNotEqual(event.getStartDate(),
None)
def test_SupportRequest_notify_noParameter(self):
self.assertRaises(TypeError, self.support_request.notify)
self.assertRaises(TypeError, self.support_request.notify, message_title="A")
self.assertRaises(TypeError, self.support_request.notify, message="A")
self.assertRaises(TypeError, self.support_request.notify, destination_relative_url="A")
def test_SupportRequest_notify(self):
person = self.portal.portal_membership.getAuthenticatedMember().getUserValue()
self.support_request.approveRegistration()
self.tic()
self.logout()
self.login()
self.support_request.notify(
message_title="A",
message="B")
event = self.support_request.REQUEST.get("ticket_notified_item")
self.assertEqual(event.getSimulationState(), "delivered")
self.assertEqual(self.support_request.getSimulationState(),
'validated')
self.assertEqual(self.support_request.getSourceSection(),
event.getDestination())
self.assertEqual(person, event.getSourceValue())
self.assertEqual("service_module/slapos_crm_information",
event.getResource())
self.assertEqual(self.support_request,
event.getFollowUpValue())
self.assertEqual(event.getTitle(), "A")
self.assertEqual(event.getTextContent(), "B")
self.assertEqual(event.getContentType(), "text/html")
self.assertEqual(event.getPortalType(), "Web Message")
self.assertEqual(event.getSource(),
self.support_request.getDestinationDecision())
self.assertEqual(event.getDestination(),
self.support_request.getSourceSection())
self.assertNotEqual(event.getStartDate(),
None)
# Retry now to see if doesn't create a new message
self.support_request.notify(
message_title="A",
message="B")
self.tic()
self.assertEqual(event,
self.support_request.REQUEST.get("ticket_notified_item"))
# Retry, now it must create a new one
self.support_request.notify(
message_title="C",
message="B")
self.tic()
self.assertNotEqual(event,
self.support_request.REQUEST.get("ticket_notified_item"))
# Remove completly the ticket_notified_item and try to create a new one
# It should find it anyway from catalog.
self.support_request.REQUEST.set("ticket_notified_item", None)
self.commit()
# Retry, now it must create a new one
self.support_request.notify(
message_title="A",
message="B")
self.tic()
self.assertEqual(event,
self.support_request.REQUEST.get("ticket_notified_item"))
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Test Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>testSlapOSCloudTicketSlapInterfaceWorkflow</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>test.erp5.testSlapOSCloudTicketSlapInterfaceWorkflow</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Test Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</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>component_validation_workflow</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="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<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>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Workflow" 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>categories</string> </key>
<value>
<tuple>
<string>source/portal_workflow/ticket_slap_interface_workflow/state_draft</string>
</tuple>
</value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>person_slap_interface_workflow</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>ticket_slap_interface_workflow</string> </value>
</item>
<item>
<key> <string>language</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>manager_bypass</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Workflow</string> </value>
</item>
<item>
<key> <string>state_variable</string> </key>
<value> <string>slap_state</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Ticket Slap Interface Workflow</string> </value>
</item>
<item>
<key> <string>workflow_managed_permission</string> </key>
<value>
<tuple/>
</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>
ticket = state_change["object"]
from DateTime import DateTime
portal = context.getPortalObject()
if ticket.getSimulationState() != "draft":
return
if ticket.getReference() in [None, ""]:
raise ValueError("Reference is missing on the Ticket")
# Get the user id of the context owner.
local_role_list = ticket.get_local_roles()
for group, role_list in local_role_list:
if 'Owner' in role_list:
user_id = group
break
person = portal.portal_catalog.getResultValue(user_id=user_id)
if person is None:
# Value was created by super user, so there isn't a point on continue
return
# XXX unhardcode the trade condition, by adding a preference
if ticket.getSpecialise() != "sale_trade_condition_module/slapos_ticket_trade_condition":
return
trade_condition = portal.sale_trade_condition_module.slapos_ticket_trade_condition
ticket.edit(
source_section=trade_condition.getSourceSection(),
source_trade=trade_condition.getSourceSection(),
source=trade_condition.getSource())
ticket.setStartDate(DateTime())
ticket.requestEvent(
event_title=ticket.getTitle(),
event_content=ticket.getDescription(),
event_source=ticket.getDestinationDecision()
)
event_relative_url = context.REQUEST.get("event_relative_url")
ticket.setCausality(event_relative_url)
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Workflow Script" module="erp5.portal_type"/>
</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>state_change</string> </value>
</item>
<item>
<key> <string>_proxy_roles</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>script_Ticket_approveRegistration</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Workflow Script</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Ticket_approveRegistration</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Workflow Script" module="erp5.portal_type"/>
</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>state_change</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>script_Ticket_checkConsistency</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Workflow Script</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<none/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
ticket = state_change["object"]
from DateTime import DateTime
portal = ticket.getPortalObject()
# Get required arguments
kwargs = state_change.kwargs
# Required args
# Raise TypeError if all parameters are not provided
try:
message_title = kwargs['message_title']
message = kwargs['message']
except KeyError:
raise TypeError("Ticket_notify takes exactly 2 arguments")
resource = portal.service_module.slapos_crm_information.getRelativeUrl()
# create Web message if needed for this ticket
last_event = ticket.SupportRequest_getLastEvent(message_title)
if last_event:
# User has already been notified for this problem.
ticket.REQUEST.set("ticket_notified_item", last_event)
return
transactional_event = ticket.REQUEST.get("ticket_notified_item", None)
if transactional_event is not None:
if (transactional_event.getFollowUpUid() == ticket.getUid()) and \
(transactional_event.getTitle() == message_title):
ticket.REQUEST.set("ticket_notified_item", transactional_event)
return
template = portal.restrictedTraverse(
portal.portal_preferences.getPreferredWebMessageTemplate())
event = template.Base_createCloneDocument(batch_mode=1)
event.edit(
title=message_title,
text_content=message,
start_date = DateTime(),
resource = resource,
source=ticket.getDestinationDecision(),
destination=ticket.getSource(),
follow_up=ticket.getRelativeUrl(),
)
event.stop()
event.deliver()
ticket.serialize()
ticket.REQUEST.set("ticket_notified_item", event)
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Workflow Script" module="erp5.portal_type"/>
</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>state_change</string> </value>
</item>
<item>
<key> <string>_proxy_roles</string> </key>
<value>
<tuple>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>script_Ticket_notify</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Workflow Script</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Ticket_notify</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
ticket = state_change["object"]
from DateTime import DateTime
portal = context.getPortalObject()
# Get required arguments
kwargs = state_change.kwargs
# Required args
# Raise TypeError if all parameters are not provided
try:
title = kwargs['event_title']
text_content = kwargs['event_content']
source = kwargs['event_source']
except KeyError:
raise TypeError, "Ticket_requestEvent takes at exactly 3 argument"
web_message = portal.event_module.newContent(
portal_type="Web Message",
start_date = DateTime(),
title=title,
text_content=text_content,
source=source,
content_type="text/plain",
destination=ticket.getSource(),
destination_project=ticket.getDestinationProject(),
resource=ticket.getResource(),
follow_up=ticket.getRelativeUrl()
)
web_message.stop(comment="Submitted from the renderjs app")
if portal.portal_workflow.isTransitionPossible(ticket, "validate"):
ticket.validate(comment="See %s" % web_message.getRelativeUrl())
ticket.REQUEST.set("event_relative_url", web_message.getRelativeUrl())
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Workflow Script" module="erp5.portal_type"/>
</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>state_change</string> </value>
</item>
<item>
<key> <string>_proxy_roles</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>script_Ticket_requestEvent</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Workflow Script</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Ticket_requestEvent</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Workflow State" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>acquire_permission</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>destination/portal_workflow/ticket_slap_interface_workflow/transition_approve_registration</string>
<string>destination/portal_workflow/ticket_slap_interface_workflow/transition_notify</string>
<string>destination/portal_workflow/ticket_slap_interface_workflow/transition_request_event</string>
</tuple>
</value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>state_draft</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Workflow State</string> </value>
</item>
<item>
<key> <string>state_permission_role_list_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>state_type</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Draft</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/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Workflow Transition" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>action_name</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/workflow</string>
<string>before_script/portal_workflow/ticket_slap_interface_workflow/script_Ticket_checkConsistency</string>
<string>after_script/portal_workflow/ticket_slap_interface_workflow/script_Ticket_approveRegistration</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>guard_permission</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>transition_approve_registration</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Workflow Transition</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Approve Registration</string> </value>
</item>
<item>
<key> <string>trigger_type</string> </key>
<value> <int>2</int> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Workflow Transition" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>action_name</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/workflow</string>
<string>before_script/portal_workflow/ticket_slap_interface_workflow/script_Ticket_checkConsistency</string>
<string>after_script/portal_workflow/ticket_slap_interface_workflow/script_Ticket_notify</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>guard_permission</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>transition_notify</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Workflow Transition</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Notify</string> </value>
</item>
<item>
<key> <string>trigger_type</string> </key>
<value> <int>2</int> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Workflow Transition" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>action_name</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/workflow</string>
<string>before_script/portal_workflow/ticket_slap_interface_workflow/script_Ticket_checkConsistency</string>
<string>after_script/portal_workflow/ticket_slap_interface_workflow/script_Ticket_requestEvent</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>guard_permission</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>transition_request_event</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Workflow Transition</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Request Event</string> </value>
</item>
<item>
<key> <string>trigger_type</string> </key>
<value> <int>2</int> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Workflow Variable" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>automatic_update</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>The last transition</string> </value>
</item>
<item>
<key> <string>for_catalog</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>variable_action</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Workflow Variable</string> </value>
</item>
<item>
<key> <string>status_included</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>variable_default_expression</string> </key>
<value> <string>transition/getReference|nothing</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Workflow Variable" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>automatic_update</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>The name of the user who performed the last transition</string> </value>
</item>
<item>
<key> <string>for_catalog</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>variable_actor</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Workflow Variable</string> </value>
</item>
<item>
<key> <string>status_included</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>variable_default_expression</string> </key>
<value> <string>user/getUserName</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Workflow Variable" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>automatic_update</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>Comments about the last transition</string> </value>
</item>
<item>
<key> <string>for_catalog</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>variable_comment</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Workflow Variable</string> </value>
</item>
<item>
<key> <string>status_included</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>variable_default_expression</string> </key>
<value> <string>python:state_change.kwargs.get(\'comment\', \'\')</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Workflow Variable" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>automatic_update</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>Error message if validation failed</string> </value>
</item>
<item>
<key> <string>for_catalog</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>variable_error_message</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Workflow Variable</string> </value>
</item>
<item>
<key> <string>status_included</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<none/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Workflow Variable" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>automatic_update</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>Provides access to workflow history</string> </value>
</item>
<item>
<key> <string>for_catalog</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>variable_history</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Workflow Variable</string> </value>
</item>
<item>
<key> <string>status_included</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>variable_default_expression</string> </key>
<value> <string>state_change/getHistory</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Workflow Variable" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>automatic_update</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>portal type (use as filter for worklists)</string> </value>
</item>
<item>
<key> <string>for_catalog</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>variable_portal_type</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Workflow Variable</string> </value>
</item>
<item>
<key> <string>status_included</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<none/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Workflow Variable" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>automatic_update</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>Time of the last transition</string> </value>
</item>
<item>
<key> <string>for_catalog</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>variable_time</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Workflow Variable</string> </value>
</item>
<item>
<key> <string>status_included</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>variable_default_expression</string> </key>
<value> <string>state_change/getDateTime</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -2,10 +2,9 @@ Compute Node | view_related_support_request ...@@ -2,10 +2,9 @@ Compute Node | view_related_support_request
Incident Response Module | rss_view Incident Response Module | rss_view
Incident Response Module | view Incident Response Module | view
Incident Response | view Incident Response | view
Instance Tree Module | slapos_resilience_usage_report
Instance Tree | jump_to_related_upgrade_decision Instance Tree | jump_to_related_upgrade_decision
Instance Tree | view_status
Instance Tree | view_ticket Instance Tree | view_ticket
Person | slapos_user_pending_ticket_report
Regularisation Request Module | rss_view Regularisation Request Module | rss_view
Regularisation Request Module | view Regularisation Request Module | view
Regularisation Request | clone_ticket_and_event_list Regularisation Request | clone_ticket_and_event_list
...@@ -13,7 +12,6 @@ Regularisation Request | create_new_file ...@@ -13,7 +12,6 @@ Regularisation Request | create_new_file
Regularisation Request | document_list Regularisation Request | document_list
Regularisation Request | new_event Regularisation Request | new_event
Regularisation Request | view Regularisation Request | view
Site Message | update_destination_for_slapos
Support Request Module | rss_view Support Request Module | rss_view
Support Request Module | slapos_support_request_instance_message_report Support Request Module | slapos_support_request_instance_message_report
Support Request Module | support_request_monitor_link Support Request Module | support_request_monitor_link
......
portal_types/Support Request Module/6
sale_trade_condition_module/slapos_ticket_trade_condition
sale_trade_condition_module/slapos_ticket_trade_condition/**
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_spam
service_module/slapos_crm_invoice_cancellation
service_module/slapos_crm_stop_reminder
service_module/slapos_crm_stop_acknowledgement
service_module/slapos_crm_delete_acknowledgement service_module/slapos_crm_delete_acknowledgement
service_module/slapos_crm_delete_reminder service_module/slapos_crm_delete_reminder
service_module/slapos_crm_information
service_module/slapos_crm_invoice_cancellation
service_module/slapos_crm_monitoring service_module/slapos_crm_monitoring
service_module/slapos_crm_spam
service_module/slapos_crm_stop_acknowledgement
service_module/slapos_crm_stop_reminder
service_module/slapos_crm_upgrade service_module/slapos_crm_upgrade
\ No newline at end of file
portal_types/Support Request Module/6
sale_trade_condition_module/slapos_ticket_trade_condition
sale_trade_condition_module/slapos_ticket_trade_condition/**
\ 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_spam
service_module/slapos_crm_invoice_cancellation
service_module/slapos_crm_stop_reminder
service_module/slapos_crm_stop_acknowledgement
service_module/slapos_crm_delete_acknowledgement service_module/slapos_crm_delete_acknowledgement
service_module/slapos_crm_delete_reminder service_module/slapos_crm_delete_reminder
service_module/slapos_crm_information
service_module/slapos_crm_invoice_cancellation
service_module/slapos_crm_monitoring service_module/slapos_crm_monitoring
service_module/slapos_crm_spam
service_module/slapos_crm_stop_acknowledgement
service_module/slapos_crm_stop_reminder
service_module/slapos_crm_upgrade service_module/slapos_crm_upgrade
\ No newline at end of file
support_request_module/slapos_crm_support_request_template
regularisation_request_module/slapos_crm_regularisation_request_template
event_module/slapos_crm_web_message_template
sale_trade_condition_module/slapos_ticket_trade_condition
sale_trade_condition_module/slapos_ticket_trade_condition/**
\ No newline at end of file
event_module/slapos_crm_web_message_template
person_module/allocation_tester
portal_alarms/slapos_crm_* portal_alarms/slapos_crm_*
portal_categories/monitor_scope/** portal_categories/monitor_scope/**
portal_categories/upgrade_scope/** portal_categories/upgrade_scope/**
regularisation_request_module/slapos_crm_regularisation_request_template
sale_trade_condition_module/slapos_ticket_trade_condition
sale_trade_condition_module/slapos_ticket_trade_condition/**
service_module/slapos_crm_* service_module/slapos_crm_*
\ No newline at end of file
support_request_module/slapos_crm_support_request_template
\ No newline at end of file
...@@ -3,6 +3,4 @@ Incident Response | ticket_workflow ...@@ -3,6 +3,4 @@ Incident Response | ticket_workflow
Regularisation Request | edit_workflow Regularisation Request | edit_workflow
Regularisation Request | pricing_interaction_workflow Regularisation Request | pricing_interaction_workflow
Regularisation Request | ticket_interaction_workflow Regularisation Request | ticket_interaction_workflow
Regularisation Request | ticket_slap_interface_workflow
Regularisation Request | ticket_workflow Regularisation Request | ticket_workflow
\ No newline at end of file
Support Request | ticket_slap_interface_workflow
\ No newline at end of file
test.erp5.testSlapOSCRMSkins
test.erp5.testSlapOSCRMRegularisationRequestSkins
test.erp5.testSlapOSCRMAlarm test.erp5.testSlapOSCRMAlarm
test.erp5.testSlapOSCloudTicketSlapInterfaceWorkflow test.erp5.testSlapOSCRMRegularisationRequestSkins
\ No newline at end of file test.erp5.testSlapOSCRMSkins
\ No newline at end of file
ticket_slap_interface_workflow
ticket_workflow ticket_workflow
\ 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