Commit 686edc8d authored by Romain Courteaud's avatar Romain Courteaud

slapos_crm:

* source_administration is not used anymore on Compute Node
* add virtual master contraint to tickets and events portal types
* propagate project from Regularisation Request to event
* delivery/movement must use source_project instead of follow_up
* set source_project on event
* stop setting person as source_project
* copy project from ticket to the new event
* utf-8 encoding issue
* XXX disable regularisation request alarm
* Regularisation Request Module acquires local roles
  See other modules
* drop upgrade_scope
  Upgrade is managed by Allocation Supply.
* drip upgrade_scope usage
* drop Upgrade Decision Line usage
* lint test
* fix slapos_crm_check_software_installation_state alarm test
* fixup slapos_crm_check_compute_node_state tests
* fixup slapos_crm_check_instance_in_error test
* fixup slapos_crm_update_support_request_state tests
* fixup slapos_crm_send_pending_ticket_reminder test
* fixup slapos_crm_trigger_stop_reminder_escalation tests
* fixup slapos_crm_trigger_stop_acknowledgment_escalation test
* fixup slapos_crm_trigger_delete_reminder_escalation test
* fix slapos_crm_trigger_acknowledgment_escalation test
* fix slapos_crm_stop_instance_tree test
* fix slapos_crm_invalidate_suspended_regularisation_request test
* fix slapos_crm_delete_instance_tree test
* fix slapos_crm_create_regularisation_request test
* drop slapos_crm_check_update_allocation_scope tests
* do not require source_project on crm
* fixup rebase: drop Instance Tree Module | slapos_resilience_usage_report
* 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
* drop preferred_cloud_contract_enabled_property
* only submit the newlu created Support Request
  end user can not validate their submitted ticket
* drop jump_related_slapos_item
* drop outdated SlapOSSupportRequestConstraint
* submit created event
  This allow to separate new ticket from the one currently handled
* constraint was dropped
* test: create test ticket in submitted state
* support request are created in submitted state
parent edef0dde
......@@ -42,7 +42,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>jump_to_related_upgrade_decision_line</string> </value>
<value> <string>jump_to_related_upgrade_decision</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
......@@ -62,7 +62,7 @@
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Related Upgrade Decision Line</string> </value>
<value> <string>Related Upgrade Decision</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
......@@ -81,7 +81,7 @@
<key> <string>text</string> </key>
<value> <string encoding="cdata"><![CDATA[
string:${object_url}/Base_jumpToRelatedObjectList?base_category=aggregate&portal_type=Upgrade%20Decision%20%Line&simulation_state=confirmed
string:${object_url}/Base_jumpToRelatedObjectList?base_category=aggregate&portal_type=Upgrade%20Decision&simulation_state=confirmed
]]></string> </value>
</item>
......@@ -96,7 +96,7 @@ string:${object_url}/Base_jumpToRelatedObjectList?base_category=aggregate&portal
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>python: portal.Base_checkPermission(\'subscription_request_module\', \'View\')</string> </value>
<value> <string>python: portal.Base_checkPermission(\'upgrade_decision_module\', \'View\')</string> </value>
</item>
</dictionary>
</pickle>
......
<?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="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_jump</string>
</tuple>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_jio_jump</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>jump_related_slapos_item</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>14.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Related Instance Tree, Compute Node or Software Installation</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 encoding="cdata"><![CDATA[
string:${object_url}/Base_jumpToRelationObject?base_category=aggregate&portal_type:list=Instance%20Tree&portal_type:list=Compute%20Node&portal_type:list=Software%20Installation
]]></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<module>
<category_list>
<category>business_application/crm</category>
</category_list>
<id>incident_response_module</id>
<permission_list>
<permission type='tuple'>
......
<?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 @@
<key> <string>active_sense_method_id</string> </key>
<value> <string>Alarm_checkComputeNodeState</string> </value>
</item>
<item>
<key> <string>automatic_solve</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<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>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>0</int> </value>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>id</string> </key>
......
......@@ -22,7 +22,7 @@
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>0</int> </value>
<value> <int>1</int> </value>
</item>
<item>
<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>
<base_category_list>
<portal_type id="Compute Node">
<item>monitor_scope</item>
<item>upgrade_scope</item>
</portal_type>
<portal_type id="Incident Response">
<item>aggregate</item>
......@@ -12,7 +11,6 @@
</portal_type>
<portal_type id="Instance Tree">
<item>monitor_scope</item>
<item>upgrade_scope</item>
</portal_type>
<portal_type id="Regularisation Request">
<item>specialise</item>
......
......@@ -8,9 +8,6 @@
<portal_type id="Site Message">
<item>SlapOSEventConstraint</item>
</portal_type>
<portal_type id="Support Request">
<item>SlapOSSupportRequestConstraint</item>
</portal_type>
<portal_type id="Web Message">
<item>SlapOSEventConstraint</item>
</portal_type>
......
......@@ -12,10 +12,20 @@
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>acquire_local_roles</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>content_icon</string> </key>
<value> <string>folder_icon.gif</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>factory</string> </key>
<value> <string>addFolder</string> </value>
......@@ -32,6 +42,18 @@
<key> <string>id</string> </key>
<value> <string>Regularisation Request Module</string> </value>
</item>
<item>
<key> <string>init_script</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>permission</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Base Type</string> </value>
......@@ -40,6 +62,12 @@
<key> <string>type_class</string> </key>
<value> <string>Folder</string> </value>
</item>
<item>
<key> <string>type_interface</string> </key>
<value>
<tuple/>
</value>
</item>
</dictionary>
</pickle>
</record>
......
......@@ -5,10 +5,6 @@
</chain>
<chain>
<type>Regularisation Request</type>
<workflow>edit_workflow, pricing_interaction_workflow, ticket_interaction_workflow, ticket_slap_interface_workflow, ticket_workflow</workflow>
</chain>
<chain>
<type>Support Request</type>
<workflow>ticket_slap_interface_workflow</workflow>
<workflow>edit_workflow, pricing_interaction_workflow, ticket_interaction_workflow, ticket_workflow</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>categories</string> </key>
<value>
<tuple>
<string>elementary_type/boolean</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>preferred_cloud_contract_enabled_property</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Standard Property</string> </value>
</item>
<item>
<key> <string>preference</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>property_default</string> </key>
<value> <string>python: False</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_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>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Property Sheet" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_count</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_mt_index</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>_tree</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>SlapOSSupportRequestConstraint</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Property Sheet</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Length" module="BTrees.Length"/>
</pickle>
<pickle> <int>0</int> </pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="OOBTree" module="BTrees.OOBTree"/>
</pickle>
<pickle>
<none/>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="OOBTree" module="BTrees.OOBTree"/>
</pickle>
<pickle>
<none/>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Script Constraint" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<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>constraint_type/default</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>causality_source_destination_constraint_constraint</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Script Constraint</string> </value>
</item>
<item>
<key> <string>script_id</string> </key>
<value> <string>SupportRequest_checkCausalitySourceDestinationConsistency</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>
......@@ -3,28 +3,23 @@ portal = context.getPortalObject()
person_uid_list = []
for (_, brain) in enumerate(portal.portal_simulation.getInventoryList(
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,
portal_type=portal.getPortalAccountingMovementTypeList(),
node_uid=[x.uid for x in context.Base_getReceivableAccountList()],
grouping_reference=None)):
node_uid=[x.uid for x in context.Base_getReceivableAccountList()] or -1,
parent__ledger__uid=portal.portal_categories.ledger.automated.getUid(),
grouping_reference=None
)):
payment_request_uid = brain.payment_request_uid
if not payment_request_uid:
payment_request_uid = brain.getObject().getExplanationUid()
payment_request = portal.portal_catalog.getObject(uid=payment_request_uid)
section_uid = payment_request.getDestinationSectionUid(portal_type="Person")
section_uid = brain.getDestinationSectionUid(portal_type="Person")
if section_uid is not None:
person_uid_list.append(section_uid)
portal.portal_catalog.searchAndActivate(
portal_type="Person",
validation_state="validated",
uid=person_uid_list,
method_id='Person_checkToCreateRegularisationRequest',
activate_kw={'tag': tag}
)
if person_uid_list:
portal.portal_catalog.searchAndActivate(
portal_type="Person",
validation_state="validated",
uid=person_uid_list,
method_id='Person_checkToCreateRegularisationRequest',
activate_kw={'tag': tag}
)
context.activate(after_tag=tag).getId()
portal = context.getPortalObject()
sub_tag = "RegularisationRequest_stopInstanceTreeList"
portal.portal_catalog.searchAndActivate(
portal_type="Regularisation Request",
portal_type="Regularisation Request",
simulation_state=["suspended"],
default_resource_uid=[
resource__uid=[
portal.service_module.slapos_crm_stop_acknowledgement.getUid(),
portal.service_module.slapos_crm_delete_reminder.getUid(),
portal.service_module.slapos_crm_delete_acknowledgement.getUid(),
......
portal = context.getPortalObject()
portal.portal_catalog.searchAndActivate(
portal_type="Regularisation Request",
portal_type="Regularisation Request",
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',
activate_kw={'tag': tag}
)
......
portal = context.getPortalObject()
portal.portal_catalog.searchAndActivate(
portal_type="Regularisation Request",
portal_type="Regularisation Request",
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',
activate_kw={'tag': tag}
)
......
......@@ -15,7 +15,8 @@ if (slap_state in ['start_requested', 'stop_requested']):
software_type=instance_tree.getSourceReference(),
instance_xml=instance_tree.getTextContent(),
sla_xml=instance_tree.getSlaXml(),
shared=instance_tree.isRootSlave()
shared=instance_tree.isRootSlave(),
project_reference=instance_tree.getFollowUpReference()
)
return True
return False
......@@ -15,7 +15,8 @@ if (slap_state == 'start_requested'):
software_type=instance_tree.getSourceReference(),
instance_xml=instance_tree.getTextContent(),
sla_xml=instance_tree.getSlaXml(),
shared=instance_tree.isRootSlave()
shared=instance_tree.isRootSlave(),
project_reference=instance_tree.getFollowUpReference()
)
return True
return False
......@@ -16,27 +16,15 @@ ticket_portal_type = "Regularisation Request"
ticket = portal.portal_catalog.getResultValue(
portal_type=ticket_portal_type,
default_source_project_uid=person.getUid(),
destination__uid=person.getUid(),
simulation_state=['suspended', 'validated'],
)
if ticket is not None:
return ticket, None
outstanding_amount = person.Entity_statSlapOSOutstandingAmount()
# 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:
mail_message = None
if person.Entity_hasOutstandingAmount():
tag = "%s_addRegularisationRequest_inProgress" % person.getUid()
if (portal.portal_activities.countMessageWithTag(tag) > 0):
# The regularisation request is already under creation but can not be fetched from catalog
......@@ -47,59 +35,39 @@ if int(outstanding_amount) > 0:
person.serialize()
# Time to create the ticket
regularisation_request_template = portal.restrictedTraverse(
portal.portal_preferences.getPreferredRegularisationRequestTemplate())
ticket = regularisation_request_template.Base_createCloneDocument(batch_mode=1)
ticket.edit(
source_project_value=context,
title='Account regularisation expected for "%s"' % context.getTitle(),
destination_decision_value=context,
destination_value=context,
start_date=DateTime(),
resource=portal.portal_preferences.getPreferredRegularisationRequestResource(),
comment = 'New automatic ticket for %s' % context.getTitle()
ticket = context.Entity_createTicketFromTradeCondition(
portal.service_module.slapos_crm_monitoring.getRelativeUrl(),
'Account regularisation expected for "%s"' % context.getTitle(),
'',
portal_type='Regularisation Request',
comment=comment
)
ticket.validate(comment='New automatic ticket for %s' % context.getTitle())
ticket.suspend(comment='New automatic ticket for %s' % context.getTitle())
ticket.validate(comment=comment)
ticket.suspend(comment=comment)
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'
body = """Dear %s,
subject = 'Invoice payment requested'
body = """Dear %s,
A new invoice has been generated.
A new invoice has been generated.
You can access it in your invoice section at %s.
Regards,
The slapos team
""" % (context.getTitle(), portal.portal_preferences.getPreferredSlaposWebSiteUrl())
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})
notification_message_reference = "slapos-crm.create.regularisation.request"
mail_message = ticket.RegularisationRequest_checkToSendUniqEvent(
portal.portal_preferences.getPreferredRegularisationRequestResource(),
subject,
body,
'Requested manual payment.')
return ticket, mail_message
'Requested manual payment.',
notification_message=notification_message_reference,
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"
event = portal.portal_catalog.getResultValue(
portal_type=event_portal_type,
default_resource_uid=service.getUid(),
default_follow_up_uid=ticket.getUid(),
resource__uid=service.getUid(),
follow_up__uid=ticket.getUid(),
)
if (event is None) and (ticket.getSimulationState() == 'suspended'):
......@@ -31,20 +31,15 @@ if (event is None) and (ticket.getSimulationState() == 'suspended'):
# Prevent concurrent transaction to create 2 events for the same ticket
ticket.edit(resource=service_relative_url)
event = portal.event_module.newContent(
portal_type=event_portal_type,
start_date=DateTime(),
destination=ticket.getDestination(),
follow_up=ticket.getRelativeUrl(),
source=context.getSource(),
title=title,
resource=service_relative_url,
event = ticket.Ticket_createProjectEvent(
title, 'outgoing', 'Mail Message',
service_relative_url,
text_content=text_content,
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})
return event
......@@ -50,7 +50,7 @@
</item>
<item>
<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>
<key> <string>id</string> </key>
......
......@@ -11,14 +11,16 @@ event_portal_type = "Mail Message"
event = portal.portal_catalog.getResultValue(
portal_type=event_portal_type,
default_resource_uid=current_service.getUid(),
default_follow_up_uid=ticket.getUid(),
resource__uid=current_service.getUid(),
follow_up__uid=ticket.getUid(),
simulation_state="delivered",
)
if (ticket.getSimulationState() == 'suspended') and (event is not None) and (ticket.getResource() == current_service_relative_url):
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 None
......@@ -50,7 +50,7 @@
</item>
<item>
<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>
<key> <string>id</string> </key>
......
......@@ -4,16 +4,16 @@ if REQUEST is not None:
ticket = context
state = ticket.getSimulationState()
person = ticket.getSourceProjectValue(portal_type="Person")
person = ticket.getDestinationDecisionValue(portal_type="Person")
if (state == 'suspended') and \
(person is not None) and \
(ticket.getResource() == 'service_module/slapos_crm_delete_acknowledgement'):
portal = context.getPortalObject()
portal.portal_catalog.searchAndActivate(
portal_type="Instance Tree",
validation_state=["validated"],
default_destination_section_uid=person.getUid(),
destination_section__uid=person.getUid(),
method_id='InstanceTree_deleteFromRegularisationRequest',
method_args=(person.getRelativeUrl(),),
activate_kw={'tag': tag}
......
......@@ -3,26 +3,10 @@ if REQUEST is not None:
raise Unauthorized
state = context.getSimulationState()
person = context.getSourceProjectValue(portal_type="Person")
person = context.getDestinationDecisionValue(portal_type="Person")
if (state not in ('suspended', 'validated')) or \
(person is None):
return
outstanding_amount = person.Entity_statSlapOSOutstandingAmount()
# 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)
if not person.Entity_hasOutstandingAmount():
context.invalidate(comment="Automatically disabled as balance is ok")
......@@ -4,16 +4,16 @@ if REQUEST is not None:
ticket = context
state = ticket.getSimulationState()
person = ticket.getSourceProjectValue(portal_type="Person")
person = ticket.getDestinationDecisionValue(portal_type="Person")
if (state == 'suspended') and \
(person is not None) and \
(ticket.getResource() in ['service_module/slapos_crm_stop_acknowledgement', 'service_module/slapos_crm_delete_reminder', 'service_module/slapos_crm_delete_acknowledgement']):
portal = context.getPortalObject()
portal.portal_catalog.searchAndActivate(
portal_type="Instance Tree",
validation_state=["validated"],
default_destination_section_uid=person.getUid(),
destination_section__uid=person.getUid(),
method_id='InstanceTree_stopFromRegularisationRequest',
method_args=(person.getRelativeUrl(),),
activate_kw={'tag': tag}
......
......@@ -2,19 +2,10 @@ from zExceptions import Unauthorized
if REQUEST is not None:
raise Unauthorized
portal = context.getPortalObject()
ndays = 15
language = "en"
recipient = context.getDestinationSectionValue()
if recipient is not None:
language = recipient.getLanguage("en")
notification_message = portal.portal_notifications.getDocumentValue(
language=language, reference="slapos-crm.acknowledgment.escalation")
if notification_message is None:
subject = 'Reminder: invoice payment requested'
body = """Dear user,
subject = 'Reminder: invoice payment requested'
body = """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.
......@@ -23,21 +14,6 @@ Regards,
The slapos team
""" % 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(
delay_period_in_days=ndays,
current_service_relative_url='service_module/slapos_crm_acknowledgement',
......@@ -45,4 +21,9 @@ return context.RegularisationRequest_checkToTriggerNextEscalationStep(
title=subject,
text_content=body,
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
if REQUEST is not None:
raise Unauthorized
portal = context.getPortalObject()
ndays = 10
language = "en"
recipient = context.getDestinationSectionValue()
if recipient is not None:
language = recipient.getLanguage("en")
notification_message = portal.portal_notifications.getDocumentValue(
language=language, reference="slapos-crm.delete.reminder.escalation")
if notification_message is None:
subject = 'Acknowledgment: instances deleted'
body = """Dear user,
subject = 'Acknowledgment: instances deleted'
body = """Dear user,
Despite our last reminder, you still have an unpaid invoice on %s.
We will now delete all your instances.
......@@ -22,20 +13,6 @@ We will now delete all your instances.
Regards,
The slapos team
""" % 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(
delay_period_in_days=ndays,
......@@ -44,4 +21,9 @@ return context.RegularisationRequest_checkToTriggerNextEscalationStep(
title=subject,
text_content=body,
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
if REQUEST is not None:
raise Unauthorized
portal = context.getPortalObject()
ndays = 7
language = "en"
recipient = context.getDestinationSectionValue()
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,
subject = 'Last reminder: invoice payment requested'
body = """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.
......@@ -22,20 +12,6 @@ If no payment is done during the coming days, we will delete all your instances.
Regards,
The slapos team
""" % 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(
delay_period_in_days=ndays,
......@@ -44,4 +20,9 @@ return context.RegularisationRequest_checkToTriggerNextEscalationStep(
title=subject,
text_content=body,
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
if REQUEST is not None:
raise Unauthorized
portal = context.getPortalObject()
ndays = 7
language = "en"
recipient = context.getDestinationSectionValue()
if recipient is not None:
language = recipient.getLanguage("en")
notification_message = portal.portal_notifications.getDocumentValue(
language=language, reference="slapos-crm.stop.reminder.escalation")
if notification_message is None:
subject = 'Acknowledgment: instances stopped'
body = """Dear user,
subject = 'Acknowledgment: instances stopped'
body = """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.
......@@ -22,20 +13,6 @@ We will now stop all your current instances to free some hardware resources.
Regards,
The slapos team
""" % 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(
delay_period_in_days=ndays,
......@@ -44,4 +21,9 @@ return context.RegularisationRequest_checkToTriggerNextEscalationStep(
title=subject,
text_content=body,
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(
if monitor_enabled_category is not None:
portal.portal_catalog.searchAndActivate(
portal_type = 'Compute Node',
validation_state = 'validated',
default_monitor_scope_uid = monitor_enabled_category.getUid(),
method_id = 'ComputeNode_checkState',
activate_kw = {'tag':tag}
portal_type='Compute Node',
validation_state='validated',
monitor_scope__uid=monitor_enabled_category.getUid(),
method_id='ComputeNode_checkState',
activate_kw={'tag':tag}
)
context.activate(after_tag=tag).getId()
......@@ -9,11 +9,11 @@ monitor_enabled_category = portal.restrictedTraverse(
if monitor_enabled_category is not None:
portal.portal_catalog.searchAndActivate(
portal_type = 'Compute Node',
validation_state = 'validated',
default_monitor_scope_uid = monitor_enabled_category.getUid(),
method_id = 'ComputeNode_checkSoftwareInstallationState',
activate_kw = {'tag':tag}
portal_type='Compute Node',
validation_state='validated',
monitor_scope__uid=monitor_enabled_category.getUid(),
method_id='ComputeNode_checkSoftwareInstallationState',
activate_kw={'tag':tag}
)
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>
......@@ -3,11 +3,11 @@ portal = context.getPortalObject()
default_resource_uid = portal.restrictedTraverse("service_module/slapos_crm_monitoring", None).getUid()
portal.portal_catalog.searchAndActivate(
portal_type='Support Request',
simulation_state=['validated', 'suspended'],
default_resource_uid=default_resource_uid,
default_aggregate_portal_type=["Instance Tree"],
simulation_state=['submitted', 'validated', 'suspended'],
resource__uid=default_resource_uid,
aggregate__portal_type=["Instance Tree"],
method_id='SupportRequest_updateMonitoringState',
activate_kw = {'tag':tag}
activate_kw={'tag':tag}
)
context.activate(after_tag=tag).getId()
from DateTime import DateTime
portal = context.getPortalObject()
person = context.getSourceAdministrationValue(portal_type="Person")
if not person or \
context.getMonitorScope() == "disabled" or \
if (context.getMonitorScope() == "disabled") or \
portal.ERP5Site_isSupportRequestCreationClosed():
return
return
software_installation_list = portal.portal_catalog(
portal_type='Software Installation',
default_aggregate_uid=context.getUid(),
aggregate__uid=context.getUid(),
validation_state='validated',
sort_on=(('creation_date', 'DESC'),)
)
......@@ -26,15 +24,20 @@ for software_installation in software_installation_list:
# Give it 12 hours to deploy.
continue
if software_installation.getSlapState() != 'start_requested':
continue
reference = software_installation.getReference()
d = software_installation.getAccessStatus()
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)
description = "The software release %s did not started to build on %s since %s" % \
(software_installation.getUrlString(), compute_node_title, software_installation.getCreationDate())
else:
last_contact = DateTime(d.get('created_at'))
if d.get("text").startswith("building"):
if d.get("text").startswith("#building"):
should_notify = True
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" % \
......@@ -49,42 +52,34 @@ for software_installation in software_installation_list:
(software_installation.getUrlString(), compute_node_title, software_installation.getCreationDate())
if should_notify:
support_request = person.Base_getSupportRequestInProgress(
title=ticket_title,
aggregate=software_installation.getRelativeUrl())
if support_request is None:
person.notify(support_request_title=ticket_title,
support_request_description=description,
aggregate=software_installation.getRelativeUrl())
support_request_relative_url = context.REQUEST.get("support_request_relative_url")
if support_request_relative_url is None:
return
project = context.getFollowUpValue()
support_request = project.Project_createSupportRequestWithCausality(
ticket_title,
description,
causality=context.getRelativeUrl(),
destination_decision=project.getDestination()
)
support_request = portal.restrictedTraverse(support_request_relative_url)
if support_request is None:
return
# Send Notification message
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})
notification_message_reference = 'slapos-crm-compute_node_software_installation_state.notification'
event = support_request.SupportRequest_getLastEvent(ticket_title)
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)
......
from DateTime import DateTime
portal = context.getPortalObject()
person = context.getSourceAdministrationValue(portal_type="Person")
if not person or \
context.getMonitorScope() == "disabled" or \
if (context.getMonitorScope() == "disabled") or \
portal.ERP5Site_isSupportRequestCreationClosed():
return
......@@ -56,7 +54,7 @@ if not should_notify:
if compute_partition_uid_list:
instance_list = portal.portal_catalog(
portal_type='Software Instance',
default_aggregate_uid=compute_partition_uid_list)
aggregate__uid=compute_partition_uid_list)
if instance_list:
should_notify = True
......@@ -78,45 +76,36 @@ if not should_notify:
context.getTitle(), context.getReference(), last_contact)
if should_notify:
support_request = person.Base_getSupportRequestInProgress(
title=node_ticket_title,
aggregate=context.getRelativeUrl())
support_request = context.Base_getSupportRequestInProgress(
title=node_ticket_title)
if support_request is None:
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)
project = context.getFollowUpValue()
support_request = project.Project_createSupportRequestWithCausality(
ticket_title,
description,
causality=context.getRelativeUrl(),
destination_decision=project.getDestination()
)
if support_request is None:
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)
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
portal = context.getPortalObject()
compute_node = context
now_date = DateTime()
......@@ -15,13 +14,4 @@ if message_dict.has_key('created_at'):
contact_date = DateTime(message_dict.get('created_at').encode('utf-8'))
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
......@@ -96,8 +96,8 @@
<key> <string>left</string> </key>
<value>
<list>
<string>my_reference</string>
<string>my_title</string>
<string>my_reference</string>
</list>
</value>
</item>
......
......@@ -2,19 +2,20 @@ from Products.ERP5Type.Cache import CachingMethod
portal = context.getPortalObject()
def isSupportRequestCreationClosed(destination_decision=None):
limit = portal.portal_preferences.getPreferredSupportRequestCreationLimit(5)
limit = int(portal.portal_preferences.getPreferredSupportRequestCreationLimit(5))
kw = {}
kw['limit'] = limit
kw['portal_type'] = 'Support Request'
kw['simulation_state'] = ["validated","submitted"]
kw['default_resource_uid'] = portal.service_module.slapos_crm_monitoring.getUid()
kw = {
'limit': limit,
'portal_type': 'Support Request',
'simulation_state': ["validated", "submitted"],
'resource__uid': portal.service_module.slapos_crm_monitoring.getUid()
}
if destination_decision:
kw['default_destination_decision_uid'] = context.restrictedTraverse(
kw['destination_decision__uid'] = context.restrictedTraverse(
destination_decision).getUid()
support_request_amount = context.portal_catalog.countResults(**kw)[0][0]
return support_request_amount >= int(limit)
support_request_amount_list = context.portal_catalog(**kw)
return limit <= len(support_request_amount_list)
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.submit(comment=comment)
return ticket
......@@ -50,11 +50,11 @@
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>instance, notification_message_reference</string> </value>
<value> <string>resource, title, text_content, portal_type=\'Support Request\', source_project=None, causality=None, comment=None</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>InstanceTree_createSupportRequestEvent</string> </value>
<value> <string>Entity_createTicketFromTradeCondition</string> </value>
</item>
</dictionary>
</pickle>
......
......@@ -4,10 +4,6 @@ from erp5.component.module.DateUtils import addToDate
instance_tree = context
portal = context.getPortalObject()
if instance_tree.getMonitorScope() == "disabled":
# Don't generate ticket if Monitor Scope is marked to disable
return
if portal.ERP5Site_isSupportRequestCreationClosed():
# Stop ticket creation
return
......@@ -20,14 +16,11 @@ if (date_check_limit - instance_tree.getCreationDate()) < 0:
software_instance_list = context.portal_catalog(
portal_type=["Software Instance", "Slave Instance"],
specialise_uid=instance_tree.getUid(),
specialise__uid=instance_tree.getUid(),
**{"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
notification_message_reference = None
for instance in software_instance_list:
if (date_check_limit - instance.getCreationDate()) < 0:
continue
......@@ -36,19 +29,48 @@ for instance in software_instance_list:
continue
compute_partition = instance.getAggregateValue()
if compute_partition is not None:
has_newest_allocated_instance = True
if instance.getPortalType() == "Software Instance" and \
compute_partition.getParentValue().getMonitorScope() == "enabled" and \
instance.SoftwareInstance_hasReportedError(tolerance=30):
return context.InstanceTree_createSupportRequestEvent(
instance, 'slapos-crm-instance-tree-instance-state.notification')
else:
has_unallocated_instance = True
failing_instance = instance
if has_unallocated_instance and has_newest_allocated_instance:
return context.InstanceTree_createSupportRequestEvent(
failing_instance, 'slapos-crm-instance-tree-instance-allocation.notification')
return
if compute_partition is None:
notification_message_reference = 'slapos-crm-instance-tree-instance-allocation.notification'
elif (instance.getPortalType() == "Software Instance") and \
(compute_partition.getParentValue().getMonitorScope() == "enabled") and \
instance.SoftwareInstance_hasReportedError(tolerance=30):
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:
error_message = "No message!"
project = context.getFollowUpValue()
support_request = project.Project_createSupportRequestWithCausality(
ticket_title,
description,
causality=context.getRelativeUrl(),
destination_decision=context.getDestinationSection()
)
if support_request is None:
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 @@
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>**kw</string> </value>
<value> <string>title, text_content, causality, destination_decision</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Person_getSlapOSPendingTicket</string> </value>
<value> <string>Project_createSupportRequestWithCausality</string> </value>
</item>
</dictionary>
</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>
event = context.Ticket_getCausalityValue()
error_list = []
if event:
if event.getSource() != context.getDestinationDecision():
error_list.append(
'Sender of the related event should be the customer')
if event.getDestination() != context.getSourceSection():
error_list.append(
'Destination of the related event should be the slapos organisation')
return error_list
<?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>fixit=False</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>SupportRequest_checkCausalitySourceDestinationConsistency</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
portal = context.getPortalObject()
return portal.portal_catalog.getResultValue(
title=title,
follow_up_uid=context.getUid(),
title={'query': title, 'key': 'ExactMatch'},
follow_up__uid=context.getUid(),
portal_type=portal.getPortalEventTypeList(),
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. """
from Products.ERP5Type.Errors import UnsupportedWorkflowMethod
portal = context.getPortalObject()
if context.getSimulationState() == "invalidated":
return
document = context.getAggregateValue(portal_type="Instance Tree")
document = context.getCausalityValue(portal_type="Instance Tree")
if document is None:
return
return
if document.getSlapState() == "destroy_requested":
# 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()
}
)
if document.getPortalType() == "Instance Tree":
if document.getSlapState() == "destroy_requested":
return context.SupportRequest_updateMonitoringDestroyRequestedState()
try:
context.validate()
except UnsupportedWorkflowMethod:
pass
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 @@
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></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>
<key> <string>id</string> </key>
<value> <string>Person_getSubscriptionRequestFirstUnpaidInvoiceList</string> </value>
<value> <string>Ticket_createProjectEvent</string> </value>
</item>
</dictionary>
</pickle>
......
......@@ -21,149 +21,344 @@
#
##############################################################################
from erp5.component.test.SlapOSTestCaseMixin import \
SlapOSTestCaseMixin, SlapOSTestCaseMixinWithAbort
SlapOSTestCaseMixin,SlapOSTestCaseMixinWithAbort, simulate
from DateTime import DateTime
import difflib
import transaction
from zExceptions import Unauthorized
class TestSlapOSCRMCreateRegularisationRequest(SlapOSTestCaseMixin):
def createFinalInvoice(self, person):
template = self.portal.restrictedTraverse(
self.portal.portal_preferences.getPreferredDefaultPrePaymentSubscriptionInvoiceTemplate())
current_invoice = template.Base_createCloneDocument(batch_mode=1)
class TestSlapOSCRMCreateRegularisationRequestAlarm(SlapOSTestCaseMixin):
def createFinalInvoice(self, person, grouping_reference=None,
ledger="automated",
source="account_module/receivable",
is_stopped=True):
current_invoice.edit(
destination_value=person,
current_invoice = self.portal.accounting_module.newContent(
portal_type="Sale Invoice Transaction",
destination_section_value=person,
destination_decision_value=person,
start_date=DateTime('2019/10/20'),
stop_date=DateTime('2019/10/20'),
title='Fake Invoice for Demo User Functional',
price_currency="currency_module/EUR",
reference='1')
cell = current_invoice["1"]["movement_0"]
cell.edit(quantity=1)
cell.setPrice(1)
resource="currency_module/EUR",
reference='1',
ledger=ledger)
current_invoice.receivable.edit(
source=source,
quantity=1,
price=1,
grouping_reference=grouping_reference
)
current_invoice.plan()
current_invoice.confirm()
current_invoice.startBuilding()
current_invoice.reindexObject()
current_invoice.stop()
if is_stopped:
current_invoice.stop()
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
def test_alarm_expected_person(self):
#################################################################
# slapos_crm_create_regularisation_request
#################################################################
def test_Person_checkToCreateRegularisationRequest_alarm_expectedPerson(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)
self.tic()
alarm = self.portal.portal_alarms.\
slapos_crm_create_regularisation_request
self._test_alarm(alarm, person, "Person_checkToCreateRegularisationRequest")
self._test_alarm(
self.portal.portal_alarms.slapos_crm_create_regularisation_request,
person,
'Person_checkToCreateRegularisationRequest'
)
def test_alarm_not_validated(self):
def test_Person_checkToCreateRegularisationRequest_alarm_started(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)
person.invalidate()
self.createFinalInvoice(person, is_stopped=False)
self.tic()
alarm = self.portal.portal_alarms.\
slapos_crm_create_regularisation_request
self._test_alarm_not_visited(alarm, person, "Person_checkToCreateRegularisationRequest")
self._test_alarm_not_visited(
self.portal.portal_alarms.slapos_crm_create_regularisation_request,
person,
'Person_checkToCreateRegularisationRequest'
)
def test_alarm_payment_stopped(self):
def test_Person_checkToCreateRegularisationRequest_alarm_lettered(self):
new_id = self.generateNewId()
person = self.portal.person_module.newContent(
portal_type='Person',
title="Test person %s" % new_id
)
person.validate()
current_invoice = self.createFinalInvoice(person)
payment_template = self.portal.restrictedTraverse(
self.portal.portal_preferences.getPreferredDefaultPrePaymentTemplate())
payment = payment_template.Base_createCloneDocument(batch_mode=1)
self.createFinalInvoice(person, grouping_reference="foobar")
self.tic()
self._test_alarm_not_visited(
self.portal.portal_alarms.slapos_crm_create_regularisation_request,
person,
'Person_checkToCreateRegularisationRequest'
)
for line in payment.contentValues():
if line.getSource() == "account_module/payment_to_encash":
line.setQuantity(-1)
elif line.getSource() == "account_module/receivable":
line.setQuantity(1)
def test_Person_checkToCreateRegularisationRequest_alarm_noLedger(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, ledger=None)
self.tic()
self._test_alarm_not_visited(
self.portal.portal_alarms.slapos_crm_create_regularisation_request,
person,
'Person_checkToCreateRegularisationRequest'
)
payment.confirm()
payment.start()
payment.setCausalityValue(current_invoice)
payment.setDestinationSectionValue(person)
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._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()
alarm = self.portal.portal_alarms.\
slapos_crm_create_regularisation_request
self._test_alarm_not_visited(alarm, person, "Person_checkToCreateRegularisationRequest")
self._test_alarm_not_visited(
self.portal.portal_alarms.slapos_crm_create_regularisation_request,
person,
'Person_checkToCreateRegularisationRequest'
)
def test_alarm_payment_started(self):
def test_Person_checkToCreateRegularisationRequest_alarm_noInvoice(self):
new_id = self.generateNewId()
person = self.portal.person_module.newContent(
portal_type='Person',
title="Test person %s" % new_id
)
person.validate()
self.tic()
self._test_alarm_not_visited(
self.portal.portal_alarms.slapos_crm_create_regularisation_request,
person,
'Person_checkToCreateRegularisationRequest'
)
current_invoice = self.createFinalInvoice(person)
payment_template = self.portal.restrictedTraverse(
self.portal.portal_preferences.getPreferredDefaultPrePaymentTemplate())
payment = payment_template.Base_createCloneDocument(batch_mode=1)
@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)
for line in payment.contentValues():
if line.getSource() == "account_module/payment_to_encash":
line.setQuantity(-1)
elif line.getSource() == "account_module/receivable":
line.setQuantity(1)
self.createFinalInvoice(person)
self.tic()
payment.confirm()
payment.start()
payment.setCausalityValue(current_invoice)
payment.setDestinationSectionValue(person)
before_date = DateTime()
ticket, event = person.Person_checkToCreateRegularisationRequest()
after_date = DateTime()
self.tic()
alarm = self.portal.portal_alarms.\
slapos_crm_create_regularisation_request
self._test_alarm(alarm, person, "Person_checkToCreateRegularisationRequest")
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()
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_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):
new_id = self.generateNewId()
......@@ -173,7 +368,10 @@ class TestSlapOSCrmInvalidateSuspendedRegularisationRequest(SlapOSTestCaseMixinW
reference="TESTREGREQ-%s" % new_id,
)
def test_alarm_validated_regularisation_request(self):
#################################################################
# slapos_crm_invalidate_suspended_regularisation_request
#################################################################
def test_RegularisationRequest_invalidateIfPersonBalanceIsOk_alarm_validatedRegularisationRequest(self):
ticket = self.createRegularisationRequest()
ticket.validate()
self.tic()
......@@ -181,7 +379,7 @@ class TestSlapOSCrmInvalidateSuspendedRegularisationRequest(SlapOSTestCaseMixinW
slapos_crm_invalidate_suspended_regularisation_request
self._test_alarm(alarm, ticket, "RegularisationRequest_invalidateIfPersonBalanceIsOk")
def test_alarm_suspended_regularisation_request(self):
def test_RegularisationRequest_invalidateIfPersonBalanceIsOk_alarm_suspendedRegularisationRequest(self):
ticket = self.createRegularisationRequest()
ticket.validate()
ticket.suspend()
......@@ -190,7 +388,7 @@ class TestSlapOSCrmInvalidateSuspendedRegularisationRequest(SlapOSTestCaseMixinW
slapos_crm_invalidate_suspended_regularisation_request
self._test_alarm(alarm, ticket, "RegularisationRequest_invalidateIfPersonBalanceIsOk")
def test_alarm_invalidated_regularisation_request(self):
def test_RegularisationRequest_invalidateIfPersonBalanceIsOk_alarm_invalidatedRegularisationRequest(self):
ticket = self.createRegularisationRequest()
ticket.validate()
ticket.invalidate()
......@@ -199,6 +397,53 @@ class TestSlapOSCrmInvalidateSuspendedRegularisationRequest(SlapOSTestCaseMixinW
slapos_crm_invalidate_suspended_regularisation_request
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):
......@@ -210,7 +455,10 @@ class TestSlapOSCrmTriggerEscalationOnAcknowledgmentRegularisationRequest(SlapOS
reference="TESTREGREQ-%s" % new_id,
)
def test_alarm_matching_regularisation_request(self):
#################################################################
# slapos_crm_trigger_acknowledgment_escalation
#################################################################
def test_RegularisationRequest_triggerAcknowledgmentEscalation_alarm_matchingRegularisationRequest(self):
ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_acknowledgement')
ticket.validate()
......@@ -222,7 +470,7 @@ class TestSlapOSCrmTriggerEscalationOnAcknowledgmentRegularisationRequest(SlapOS
self._test_alarm(alarm, ticket,
"RegularisationRequest_triggerAcknowledgmentEscalation")
def test_alarm_not_suspended(self):
def test_RegularisationRequest_triggerAcknowledgmentEscalation_alarm_notSuspendedRegularisationRequest(self):
ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_acknowledgement')
ticket.validate()
......@@ -234,7 +482,7 @@ class TestSlapOSCrmTriggerEscalationOnAcknowledgmentRegularisationRequest(SlapOS
"RegularisationRequest_triggerAcknowledgmentEscalation")
def test_alarm_not_expected_resource(self):
def test_RegularisationRequest_triggerAcknowledgmentEscalation_alarm_notExpectedResource(self):
ticket = self.createRegularisationRequest()
ticket.validate()
ticket.suspend()
......@@ -245,6 +493,46 @@ class TestSlapOSCrmTriggerEscalationOnAcknowledgmentRegularisationRequest(SlapOS
self._test_alarm_not_visited(alarm, ticket,
"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):
def createRegularisationRequest(self):
......@@ -255,7 +543,10 @@ class TestSlapOSCrmTriggerEscalationOnStopReminderRegularisationRequest(SlapOSTe
reference="TESTREGREQ-%s" % new_id,
)
def test_alarm_matching_regularisation_request(self):
#################################################################
# slapos_crm_trigger_stop_reminder_escalation
#################################################################
def test_RegularisationRequest_triggerStopReminderEscalation_alarm_matchingRegularisationRequest(self):
ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_stop_reminder')
ticket.validate()
......@@ -267,7 +558,7 @@ class TestSlapOSCrmTriggerEscalationOnStopReminderRegularisationRequest(SlapOSTe
self._test_alarm(alarm, ticket,
"RegularisationRequest_triggerStopReminderEscalation")
def test_alarm_not_suspended(self):
def test_RegularisationRequest_triggerStopReminderEscalation_alarm_notSuspended(self):
ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_stop_reminder')
ticket.validate()
......@@ -278,7 +569,7 @@ class TestSlapOSCrmTriggerEscalationOnStopReminderRegularisationRequest(SlapOSTe
self._test_alarm_not_visited(alarm, ticket,
"RegularisationRequest_triggerStopReminderEscalation")
def test_alarm_not_expected_resource(self):
def test_RegularisationRequest_triggerStopReminderEscalation_alarm_notExpectedResource(self):
ticket = self.createRegularisationRequest()
ticket.validate()
ticket.suspend()
......@@ -289,6 +580,46 @@ class TestSlapOSCrmTriggerEscalationOnStopReminderRegularisationRequest(SlapOSTe
self._test_alarm_not_visited(alarm, ticket,
"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):
def createRegularisationRequest(self):
......@@ -299,7 +630,10 @@ class TestSlapOSCrmTriggerEscalationOnStopAcknowledgmentRegularisationRequest(Sl
reference="TESTREGREQ-%s" % new_id,
)
def test_alarm_matching_regularisation_request(self):
#################################################################
# slapos_crm_trigger_stop_acknowledgment_escalation
#################################################################
def test_RegularisationRequest_triggerStopAcknowledgmentEscalation_alarm_matchingRegularisationRequest(self):
ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_stop_acknowledgement')
ticket.validate()
......@@ -311,7 +645,7 @@ class TestSlapOSCrmTriggerEscalationOnStopAcknowledgmentRegularisationRequest(Sl
self._test_alarm(alarm, ticket,
"RegularisationRequest_triggerStopAcknowledgmentEscalation")
def test_alarm_not_suspended(self):
def test_RegularisationRequest_triggerStopAcknowledgmentEscalation_alarm_notSuspended(self):
ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_stop_acknowledgement')
ticket.validate()
......@@ -322,7 +656,7 @@ class TestSlapOSCrmTriggerEscalationOnStopAcknowledgmentRegularisationRequest(Sl
self._test_alarm_not_visited(alarm, ticket,
"RegularisationRequest_triggerStopAcknowledgmentEscalation")
def test_alarm_not_expected_resource(self):
def test_RegularisationRequest_triggerStopAcknowledgmentEscalation_alarm_notExpectedResource(self):
ticket = self.createRegularisationRequest()
ticket.validate()
ticket.suspend()
......@@ -333,6 +667,46 @@ class TestSlapOSCrmTriggerEscalationOnStopAcknowledgmentRegularisationRequest(Sl
self._test_alarm_not_visited(alarm, ticket,
"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):
def createRegularisationRequest(self):
......@@ -343,7 +717,10 @@ class TestSlapOSCrmTriggerEscalationOnDeleteReminderRegularisationRequest(SlapOS
reference="TESTREGREQ-%s" % new_id,
)
def test_alarm_matching_regularisation_request(self):
#################################################################
# slapos_crm_trigger_delete_reminder_escalation
#################################################################
def test_RegularisationRequest_triggerDeleteReminderEscalation_alarm_matchingRegularisationRequest(self):
ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_delete_reminder')
ticket.validate()
......@@ -354,18 +731,17 @@ class TestSlapOSCrmTriggerEscalationOnDeleteReminderRegularisationRequest(SlapOS
slapos_crm_trigger_delete_reminder_escalation
self._test_alarm(alarm, ticket, "RegularisationRequest_triggerDeleteReminderEscalation")
def test_alarm_not_suspended(self):
def test_RegularisationRequest_triggerDeleteReminderEscalation_alarm_notSuspended(self):
ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_delete_reminder')
ticket.validate()
self.tic()
self.tic()
alarm = self.portal.portal_alarms.\
slapos_crm_trigger_delete_reminder_escalation
self._test_alarm_not_visited(alarm, ticket, "RegularisationRequest_triggerDeleteReminderEscalation")
def test_alarm_not_expected_resource(self):
def test_RegularisationRequest_triggerDeleteReminderEscalation_alarm_notExpectedResource(self):
ticket = self.createRegularisationRequest()
ticket.validate()
ticket.suspend()
......@@ -375,6 +751,46 @@ class TestSlapOSCrmTriggerEscalationOnDeleteReminderRegularisationRequest(SlapOS
slapos_crm_trigger_delete_reminder_escalation
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):
def createRegularisationRequest(self):
......@@ -385,7 +801,10 @@ class TestSlapOSCrmStopInstanceTree(SlapOSTestCaseMixinWithAbort):
reference="TESTREGREQ-%s" % new_id,
)
def test_alarm_matching_regularisation_request(self):
#################################################################
# slapos_crm_trigger_delete_reminder_escalation
#################################################################
def test_RegularisationRequest_stopInstanceTreeList_alarm_matchingRegularisationRequest(self):
ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_delete_reminder')
ticket.validate()
......@@ -396,7 +815,7 @@ class TestSlapOSCrmStopInstanceTree(SlapOSTestCaseMixinWithAbort):
slapos_crm_stop_instance_tree
self._test_alarm(alarm, ticket, "RegularisationRequest_stopInstanceTreeList")
def test_alarm_matching_regularisation_request_2(self):
def test_RegularisationRequest_stopInstanceTreeList_alarm_matchingRegularisationRequest2(self):
ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_stop_acknowledgement')
ticket.validate()
......@@ -407,7 +826,7 @@ class TestSlapOSCrmStopInstanceTree(SlapOSTestCaseMixinWithAbort):
slapos_crm_stop_instance_tree
self._test_alarm(alarm, ticket, "RegularisationRequest_stopInstanceTreeList")
def test_alarm_not_suspended(self):
def test_RegularisationRequest_stopInstanceTreeList_alarm_notSuspended(self):
ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_stop_acknowledgement')
ticket.validate()
......@@ -417,8 +836,7 @@ class TestSlapOSCrmStopInstanceTree(SlapOSTestCaseMixinWithAbort):
slapos_crm_stop_instance_tree
self._test_alarm_not_visited(alarm, ticket, "RegularisationRequest_stopInstanceTreeList")
def test_alarm_other_resource(self):
def test_RegularisationRequest_stopInstanceTreeList_alarm_otherResource(self):
ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_acknowledgement')
ticket.validate()
......@@ -429,6 +847,183 @@ class TestSlapOSCrmStopInstanceTree(SlapOSTestCaseMixinWithAbort):
slapos_crm_stop_instance_tree
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):
......@@ -438,9 +1033,13 @@ class TestSlapOSCrmDeleteInstanceTree(SlapOSTestCaseMixinWithAbort):
portal_type='Regularisation Request',
title="Test Reg. Req.%s" % new_id,
reference="TESTREGREQ-%s" % new_id,
resource='foo/bar',
)
def test_alarm_matching_regularisation_request(self):
#################################################################
# slapos_crm_delete_instance_tree
#################################################################
def test_RegularisationRequest_deleteInstanceTreeList_alarm_matchingRegularisationRequest(self):
ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_delete_acknowledgement')
ticket.validate()
......@@ -451,7 +1050,7 @@ class TestSlapOSCrmDeleteInstanceTree(SlapOSTestCaseMixinWithAbort):
slapos_crm_delete_instance_tree
self._test_alarm(alarm, ticket, "RegularisationRequest_deleteInstanceTreeList")
def test_alarm_not_suspended(self):
def test_RegularisationRequest_deleteInstanceTreeList_alarm_notSuspended(self):
ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_delete_acknowledgement')
ticket.validate()
......@@ -461,8 +1060,7 @@ class TestSlapOSCrmDeleteInstanceTree(SlapOSTestCaseMixinWithAbort):
slapos_crm_delete_instance_tree
self._test_alarm_not_visited(alarm, ticket, "RegularisationRequest_deleteInstanceTreeList")
def test_alarm_other_resource(self):
def test_RegularisationRequest_deleteInstanceTreeList_alarm_otherResource(self):
ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_delete_reminder')
ticket.validate()
......@@ -473,30 +1071,167 @@ class TestSlapOSCrmDeleteInstanceTree(SlapOSTestCaseMixinWithAbort):
slapos_crm_delete_instance_tree
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
class TestSlapOSCrmMonitoringCheckComputeNodeState(SlapOSTestCaseMixinWithAbort):
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()
def test_alarm_check_public_compute_node_state(self):
self._makeComputeNode()
self.compute_node.edit(allocation_scope='open/public')
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()
self.assertEqual(self.compute_node.getMonitorScope(), "enabled")
result = ticket.\
RegularisationRequest_deleteInstanceTreeList('footag')
self.assertTrue(result)
self.tic()
alarm = self.portal.portal_alarms.\
slapos_crm_check_compute_node_state
self._test_alarm(alarm, self.compute_node, "ComputeNode_checkState")
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()
def test_alarm_check_personal_compute_node_state(self):
self._makeComputeNode()
self.compute_node.edit(allocation_scope='open/personal')
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):
#################################################################
# slapos_crm_check_compute_node_state
#################################################################
def test_ComputeNode_checkState_alarm_monitoredComputeNodeState(self):
self._makeComputeNode(self.addProject())
self.tic()
self.assertEqual(self.compute_node.getMonitorScope(), "enabled")
alarm = self.portal.portal_alarms.\
slapos_crm_check_compute_node_state
self._test_alarm(alarm, self.compute_node, "ComputeNode_checkState")
def _test_alarm_check_compute_node_state_selected(self, allocation_scope,
monitor_scope=None):
self._makeComputeNode()
self._makeComputeNode(self.addProject())
self.compute_node.edit(allocation_scope=allocation_scope)
self.tic()
if monitor_scope is not None:
......@@ -507,9 +1242,9 @@ class TestSlapOSCrmMonitoringCheckComputeNodeState(SlapOSTestCaseMixinWithAbort)
slapos_crm_check_compute_node_state
self._test_alarm(alarm, self.compute_node, "ComputeNode_checkState")
def _test_alarm_check_compute_node_state_not_selected(self, allocation_scope,
def _test_checkComputeNodeState_compute_node_state_not_selected(self, allocation_scope,
monitor_scope=None):
self._makeComputeNode()
self._makeComputeNode(self.addProject())
self.compute_node.edit(allocation_scope=allocation_scope)
self.tic()
if monitor_scope is not None:
......@@ -520,129 +1255,517 @@ class TestSlapOSCrmMonitoringCheckComputeNodeState(SlapOSTestCaseMixinWithAbort)
slapos_crm_check_compute_node_state
self._test_alarm_not_visited(alarm, self.compute_node, "ComputeNode_checkState")
def test_alarm_check_compute_node_state_on_public_compute_node_with_monitor_scope_disabled(self):
self._test_alarm_check_compute_node_state_not_selected(
allocation_scope='open/public',
monitor_scope="disabled")
def test_alarm_check_compute_node_state_on_personal_compute_node_with_monitor_scope_disabled(self):
self._test_alarm_check_compute_node_state_not_selected(
allocation_scope='open/personal',
def test_ComputeNode_checkState_alarm_openAllocationAndDisabledMonitor(self):
self._test_checkComputeNodeState_compute_node_state_not_selected(
allocation_scope='open',
monitor_scope="disabled")
def test_alarm_check_compute_node_state_closed_forever_compute_node(self):
self._test_alarm_check_compute_node_state_not_selected(
def test_ComputeNode_checkState_alarm_closedForeverAllocation(self):
self._test_checkComputeNodeState_compute_node_state_not_selected(
allocation_scope='close/forever')
def test_alarm_check_compute_node_state_closed_mantainence_compute_node(self):
def test_ComputeNode_checkState_alarm_closedMaintainanceAllocation(self):
self._test_alarm_check_compute_node_state_selected(
allocation_scope='close/maintenance')
def test_alarm_check_compute_node_state_closed_termination_compute_node(self):
def test_ComputeNode_checkState_alarm_closedTerminationAllocation(self):
self._test_alarm_check_compute_node_state_selected(
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(
allocation_scope='close/noallocation')
class TestSlapOSCrmMonitoringCheckComputeNodeSoftwareInstallation(SlapOSTestCaseMixinWithAbort):
@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='submitted',
causality__uid=compute_node_uid
)
return support_request
def test_alarm_run_on_open_public(self):
self._makeComputeNode()
self.compute_node.edit(allocation_scope = 'open/public')
@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()
alarm = self.portal.portal_alarms.\
slapos_crm_check_software_installation_state
self._test_alarm(alarm, self.compute_node, "ComputeNode_checkSoftwareInstallationState")
def test_alarm_run_on_open_personal(self):
self._makeComputeNode()
self.compute_node.edit(allocation_scope = 'open/personal',
monitor_scope="enabled")
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(), "submitted")
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(), "submitted")
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()
alarm = self.portal.portal_alarms.\
slapos_crm_check_software_installation_state
self._test_alarm(alarm, self.compute_node, "ComputeNode_checkSoftwareInstallationState")
def test_alarm_dont_run_on_open_public_with_monitor_scope_disabled(self):
self._makeComputeNode()
self.compute_node.edit(allocation_scope = 'open/public')
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(), "submitted")
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()
self.compute_node.edit(monitor_scope = 'disabled')
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(), "submitted")
self.assertEqual(event.getSimulationState(), "delivered")
self.assertEqual(event.getPortalType(), "Web Message")
class TestSlapOSCrmMonitoringCheckComputeNodeSoftwareInstallation(SlapOSTestCaseMixinWithAbort):
#################################################################
# slapos_crm_check_software_installation_state
#################################################################
def test_ComputeNode_checkSoftwareInstallationState_alarm_monitorEnabled(self):
self._makeComputeNode(self.addProject())
self.compute_node.edit(monitor_scope="enabled")
self.tic()
alarm = self.portal.portal_alarms.\
slapos_crm_check_software_installation_state
self._test_alarm_not_visited(alarm, self.compute_node, "ComputeNode_checkSoftwareInstallationState")
self._test_alarm(alarm, self.compute_node, "ComputeNode_checkSoftwareInstallationState")
def test_alarm_dont_run_on_open_personal_with_monitor_scope_disabled(self):
self._makeComputeNode()
self.compute_node.edit(allocation_scope = 'open/personal',
monitor_scope="enabled")
self.tic()
self.compute_node.edit(monitor_scope = 'disabled')
def test_ComputeNode_checkSoftwareInstallationState_alarm_invalidated(self):
self._makeComputeNode(self.addProject())
self.compute_node.edit(monitor_scope="enabled")
self.compute_node.invalidate()
self.tic()
alarm = self.portal.portal_alarms.\
slapos_crm_check_software_installation_state
self._test_alarm_not_visited(alarm, self.compute_node, "ComputeNode_checkSoftwareInstallationState")
def _test_alarm_not_run_on_close(self, allocation_scope, monitor_scope=None):
self._makeComputeNode()
self.compute_node.edit(allocation_scope=allocation_scope)
def test_ComputeNode_checkSoftwareInstallationState_alarm_monitorDisabled(self):
self._makeComputeNode(self.addProject())
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()
alarm = self.portal.portal_alarms.\
slapos_crm_check_software_installation_state
self._test_alarm_not_visited(alarm, self.compute_node, "ComputeNode_checkSoftwareInstallationState")
def _test_alarm_run_on_close(self, allocation_scope,):
self._makeComputeNode()
self.compute_node.edit(allocation_scope=allocation_scope)
def _makeNotificationMessage(self, reference):
notification_message = self.portal.notification_message_module.newContent(
portal_type="Notification Message",
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='submitted',
causality__uid=compute_node_uid
)
@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_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()
self.tic()
self.portal.REQUEST['test_ComputeNode_checkSoftwareInstallationState_notify'] = \
self._makeNotificationMessage(compute_node.getReference())
alarm = self.portal.portal_alarms.\
slapos_crm_check_software_installation_state
self._test_alarm(alarm, self.compute_node, "ComputeNode_checkSoftwareInstallationState")
compute_node.ComputeNode_checkSoftwareInstallationState()
self.tic()
ticket_title = "[MONITORING] No information for %s on %s" % (
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(), "submitted")
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_forever(self):
self._test_alarm_not_run_on_close('close/forever')
compute_node.ComputeNode_checkSoftwareInstallationState()
self.tic()
def test_alarm_not_run_on_close_maintainence(self):
self._test_alarm_not_run_on_close('close/maintenence', monitor_scope="disabled")
ticket_title = "[MONITORING] %s is building for too long on %s" % (
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(), "submitted")
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_not_run_on_close_outdated(self):
self._test_alarm_not_run_on_close('close/outdated', monitor_scope="disabled")
compute_node.ComputeNode_checkSoftwareInstallationState()
self.tic()
def test_alarm_not_run_on_close_termination(self):
self._test_alarm_not_run_on_close('close/termination', monitor_scope="disabled")
ticket_title = "[MONITORING] %s is building for too long on %s" % (
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_not_run_on_close_noallocation(self):
self._test_alarm_not_run_on_close('close/noallocation', monitor_scope="disabled")
compute_node.ComputeNode_checkSoftwareInstallationState()
self.tic()
def test_alarm_run_on_close_maintainence(self):
self._test_alarm_run_on_close('close/maintenence')
ticket_title = "[MONITORING] %s is failing to build on %s" % (
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(), "submitted")
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_alarm_run_on_close_outdated(self):
self._test_alarm_run_on_close('close/outdated')
compute_node.ComputeNode_checkSoftwareInstallationState()
self.tic()
def test_alarm_run_on_close_termination(self):
self._test_alarm_run_on_close('close/termination')
ticket_title = "[MONITORING] %s is failing to build on %s" % (
self.start_requested_software_installation.getReference(),
compute_node.getReference()
)
ticket = self._getGeneratedSupportRequest(compute_node.getUid(), ticket_title)
def test_alarm_run_on_close_noallocation(self):
self._test_alarm_run_on_close('close/noallocation')
self.assertEqual(ticket, None)
class TestSlapOSCrmMonitoringCheckInstanceInError(SlapOSTestCaseMixinWithAbort):
def _makeInstanceTree(self):
person = self.portal.person_module.template_member\
.Base_createCloneDocument(batch_mode=1)
person = self.portal.person_module\
.newContent(portal_type="Person")
instance_tree = self.portal\
.instance_tree_module.template_instance_tree\
.Base_createCloneDocument(batch_mode=1)
.instance_tree_module\
.newContent(portal_type="Instance Tree")
instance_tree.validate()
new_id = self.generateNewId()
instance_tree.edit(
......@@ -654,58 +1777,236 @@ class TestSlapOSCrmMonitoringCheckInstanceInError(SlapOSTestCaseMixinWithAbort):
return instance_tree
def _makeSoftwareInstance(self, instance_tree):
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_alarm_check_instance_in_error_validated_instance_tree(self):
@simulate('ERP5Site_isSupportRequestCreationClosed', '','return 0')
def test_InstanceTree_checkSoftwareInstanceState_alarm_validated(self):
host_sub = self._makeInstanceTree()
self.tic()
alarm = self.portal.portal_alarms.\
slapos_crm_check_instance_in_error
self._test_alarm(alarm, host_sub, "InstanceTree_checkSoftwareInstanceState")
def test_alarm_check_instance_in_error_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.edit(monitor_scope="disabled")
host_sub.archive()
self.tic()
alarm = self.portal.portal_alarms.\
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
# on the searchAndActivate, so we end up callind the script in any situation.
self.assertEqual('Visited by InstanceTree_checkSoftwareInstanceState',
host_sub.workflow_history['edit_workflow'][-1]['comment'])
def _makeNotificationMessage(self, reference):
notification_message = self.portal.notification_message_module.newContent(
portal_type="Notification Message",
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='submitted',
causality__uid=compute_node_uid
)
def test_alarm_check_instance_in_error_archived_instance_tree(self):
host_sub = self._makeInstanceTree()
host_sub.archive()
@simulate('ERP5Site_isSupportRequestCreationClosed', '','return 0')
@simulate('NotificationTool_getDocumentValue',
'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()
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(), "submitted")
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()
alarm = self.portal.portal_alarms.\
slapos_crm_check_instance_in_error
self._test_alarm_not_visited(alarm, host_sub, "InstanceTree_checkSoftwareInstanceState")
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(), "submitted")
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):
def _makeSupportRequest(self):
person = self.portal.person_module.template_member\
.Base_createCloneDocument(batch_mode=1)
person = self.portal.person_module\
.newContent(portal_type="Person")
"""
support_request = self.portal.restrictedTraverse(
self.portal.portal_preferences.getPreferredSupportRequestTemplate()).\
Base_createCloneDocument(batch_mode=1)
support_request.validate()
Base_createCloneDocument(batch_mode=1)"""
support_request = self.portal.support_request_module.newContent(
portal_type="Support Request"
)
support_request.submit()
new_id = self.generateNewId()
support_request.edit(
title= "Support Request éçà %s" % new_id, #pylint: disable=invalid-encoded-data
......@@ -716,11 +2017,11 @@ class TestSlaposCrmUpdateSupportRequestState(SlapOSTestCaseMixinWithAbort):
return support_request
def _makeInstanceTree(self):
person = self.portal.person_module.template_member\
.Base_createCloneDocument(batch_mode=1)
person = self.portal.person_module\
.newContent(portal_type="Person")
instance_tree = self.portal\
.instance_tree_module.template_instance_tree\
.Base_createCloneDocument(batch_mode=1)
.instance_tree_module\
.newContent(portal_type="Instance Tree")
instance_tree.validate()
new_id = self.generateNewId()
instance_tree.edit(
......@@ -732,7 +2033,7 @@ class TestSlaposCrmUpdateSupportRequestState(SlapOSTestCaseMixinWithAbort):
return instance_tree
def test_alarm_update_support_request_state(self):
def test_SupportRequest_updateMonitoringState_alarm_monitoring(self):
support_request = self._makeSupportRequest()
support_request.setResource("service_module/slapos_crm_monitoring")
hs = self._makeInstanceTree()
......@@ -742,11 +2043,128 @@ class TestSlaposCrmUpdateSupportRequestState(SlapOSTestCaseMixinWithAbort):
slapos_crm_update_support_request_state
self._test_alarm(alarm, support_request, "SupportRequest_updateMonitoringState")
def test_SupportRequest_updateMonitoringState_alarm_notResource(self):
support_request = self._makeSupportRequest()
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_notValidated(self):
support_request = self._makeSupportRequest()
support_request.setResource("service_module/slapos_crm_monitoring")
support_request.validate()
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")
def test_alarm_send_pending_ticket_reminder(self):
person = self.makePerson()
def test_SupportRequest_updateMonitoringState_alarm_noInstanceTree(self):
support_request = self._makeSupportRequest()
support_request.setResource("service_module/slapos_crm_monitoring")
self.tic()
alarm = self.portal.portal_alarms.\
slapos_crm_send_pending_ticket_reminder
self._test_alarm(alarm, person, "Person_sendPendingTicketReminder")
slapos_crm_update_support_request_state
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()
self.assertEqual(support_request.getSimulationState(), "submitted")
support_request.SupportRequest_updateMonitoringState()
self.tic()
ticket = support_request
event_list = ticket.getFollowUpRelatedValueList()
self.assertEqual(len(event_list), 0)
self.assertEqual(ticket.getSimulationState(), "submitted")
@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.validate()
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,192 +26,15 @@ from erp5.component.test.SlapOSTestCaseMixin import \
SlapOSTestCaseMixin,SlapOSTestCaseMixinWithAbort, simulate
from zExceptions import Unauthorized
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/')
person = self.makePerson(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',
'reference=None, language="en"',
'assert reference == "slapos-crm.create.regularisation.request"\n' \
'return context.restrictedTraverse(' \
'context.REQUEST["test_addRegularisationRequest_notification_message"])')
@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/')
person = self.makePerson(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(), 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):
person = self.makePerson(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):
person = self.makePerson(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):
person = self.makePerson(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):
person = self.makePerson(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):
person = self.makePerson(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):
person = self.makePerson(index=0, user=0)
self.assertRaises(
Unauthorized,
person.Person_checkToCreateRegularisationRequest,
REQUEST={})
class TestSlapOSRegularisationRequest_invalidateIfPersonBalanceIsOk(
SlapOSTestCaseMixinWithAbort):
class TestSlapOSRegularisationRequest_checkToSendUniqEvent(SlapOSTestCaseMixin):
def afterSetUp(self):
SlapOSTestCaseMixin.afterSetUp(self)
expected_slapos_organisation = self.portal.organisation_module.newContent(
default_email_coordinate_text="foo@example.org"
)
self.expected_slapos_organisation = expected_slapos_organisation.getRelativeUrl()
def createRegularisationRequest(self):
new_id = self.generateNewId()
......@@ -219,65 +42,42 @@ class TestSlapOSRegularisationRequest_invalidateIfPersonBalanceIsOk(
portal_type='Regularisation Request',
title="Test Reg. Req.%s" % new_id,
reference="TESTREGREQ-%s" % new_id,
resource='foo/bar',
)
def test_invalidateIfPersonBalanceIsOk_REQUEST_disallowed(self):
ticket = self.createRegularisationRequest()
self.assertRaises(
Unauthorized,
ticket.RegularisationRequest_invalidateIfPersonBalanceIsOk,
REQUEST={})
@simulate('Entity_statOutstandingAmount', '*args, **kwargs', 'return "0"')
def test_invalidateIfPersonBalanceIsOk_matching_case(self):
person = self.makePerson(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):
person = self.makePerson(index=0, user=0)
ticket = self.createRegularisationRequest()
ticket.edit(source_project_value=person)
ticket.validate()
ticket.RegularisationRequest_invalidateIfPersonBalanceIsOk()
self.assertEqual(ticket.getSimulationState(), 'invalidated')
@simulate('Entity_statOutstandingAmount', '*args, **kwargs', 'return "0"')
def test_invalidateIfPersonBalanceIsOk_no_person(self):
def test_checkToSendUniqEvent_noEvent(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest()
ticket.edit(
source=self.expected_slapos_organisation,
destination_value=person,
source_project_value=person)
ticket.validate()
ticket.suspend()
ticket.RegularisationRequest_invalidateIfPersonBalanceIsOk()
self.assertEqual(ticket.getSimulationState(), 'suspended')
before_date = DateTime()
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):
person = self.makePerson(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.getResource(), 'service_module/slapos_crm_spam')
class TestSlapOSRegularisationRequest_checkToSendUniqEvent(SlapOSTestCaseMixin):
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',
)
self.assertEqual(event.getPortalType(), 'Mail Message')
self.assertEqual(event.getSimulationState(), 'delivered')
self.assertTrue(event.getStartDate() >= before_date)
self.assertTrue(event.getStopDate() <= after_date)
self.assertEqual(event.getTitle(), "foo title")
self.assertEqual(event.getResource(), 'service_module/slapos_crm_spam')
self.assertEqual(event.getFollowUp(), ticket.getRelativeUrl())
self.assertEqual(event.getSource(), self.expected_slapos_organisation)
self.assertEqual(event.getDestination(), person.getRelativeUrl())
self.assertEqual(event.getTextContent(), 'foo content')
self.assertEqual(event.getContentType(), 'text/plain')
def test_checkToSendUniqEvent_no_event(self):
person = self.makePerson(index=0, user=0)
def test_checkToSendUniqEvent_notificationMessage(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest()
ticket.edit(
source=self.expected_slapos_organisation,
......@@ -286,8 +86,25 @@ class TestSlapOSRegularisationRequest_checkToSendUniqEvent(SlapOSTestCaseMixin):
ticket.validate()
ticket.suspend()
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(
'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()
self.assertEqual(ticket.getSimulationState(), 'suspended')
......@@ -297,14 +114,15 @@ class TestSlapOSRegularisationRequest_checkToSendUniqEvent(SlapOSTestCaseMixin):
self.assertEqual(event.getSimulationState(), 'delivered')
self.assertTrue(event.getStartDate() >= before_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.getFollowUp(), ticket.getRelativeUrl())
self.assertEqual(event.getSource(), self.expected_slapos_organisation)
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()
self.assertRaises(
AssertionError,
......@@ -312,8 +130,9 @@ class TestSlapOSRegularisationRequest_checkToSendUniqEvent(SlapOSTestCaseMixin):
ticket.getRelativeUrl(), '', '', ''
)
def test_checkToSendUniqEvent_call_twice_with_tic(self):
person = self.makePerson(index=0, user=0)
def test_checkToSendUniqEvent_callTwiceWithTic(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest()
ticket.edit(
source=self.expected_slapos_organisation,
......@@ -331,8 +150,9 @@ class TestSlapOSRegularisationRequest_checkToSendUniqEvent(SlapOSTestCaseMixin):
self.assertEqual(event.getTextContent(), 'foo content')
self.assertEqual(event.getRelativeUrl(), event2.getRelativeUrl())
def test_checkToSendUniqEvent_manual_event(self):
person = self.makePerson(index=0, user=0)
def test_checkToSendUniqEvent_manualEvent(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest()
ticket.edit(
source=self.expected_slapos_organisation,
......@@ -356,8 +176,9 @@ class TestSlapOSRegularisationRequest_checkToSendUniqEvent(SlapOSTestCaseMixin):
self.assertEqual(event.getSimulationState(), 'draft')
self.assertEqual(event.getRelativeUrl(), event2.getRelativeUrl())
def test_checkToSendUniqEvent_not_suspended(self):
person = self.makePerson(index=0, user=0)
def test_checkToSendUniqEvent_notSuspended(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest()
ticket.edit(
source=self.expected_slapos_organisation,
......@@ -369,8 +190,9 @@ class TestSlapOSRegularisationRequest_checkToSendUniqEvent(SlapOSTestCaseMixin):
'service_module/slapos_crm_spam', 'foo2 title', 'foo2 content', 'foo2 comment')
self.assertEqual(event, None)
def test_checkToSendUniqEvent_event_not_reindexed(self):
person = self.makePerson(index=0, user=0)
def test_checkToSendUniqEvent_eventNotReindexed(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
ticket = self.createRegularisationRequest()
ticket.edit(
source=self.expected_slapos_organisation,
......@@ -386,7 +208,7 @@ class TestSlapOSRegularisationRequest_checkToSendUniqEvent(SlapOSTestCaseMixin):
self.assertNotEqual(event, event2)
self.assertEqual(event2, None)
def test_checkToSendUniqEvent_REQUEST_disallowed(self):
def test_checkToSendUniqEvent_REQUESTdisallowed(self):
ticket = self.createRegularisationRequest()
self.assertRaises(
Unauthorized,
......@@ -394,6 +216,7 @@ class TestSlapOSRegularisationRequest_checkToSendUniqEvent(SlapOSTestCaseMixin):
'', '', '', '',
REQUEST={})
class TestSlapOSRegularisationRequest_checkToTriggerNextEscalationStep(
SlapOSTestCaseMixinWithAbort):
......@@ -414,18 +237,16 @@ class TestSlapOSRegularisationRequest_checkToTriggerNextEscalationStep(
0, ticket.getRelativeUrl(), '', '', '', ''
)
@simulate('NotificationTool_getDocumentValue',
'reference=None, language="en"',
'assert reference == "slapos-crm.acknowledgment.escalation", reference\n' \
'return')
@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, action="edit_action", ' \
'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"')
def test_checkToTriggerNextEscalationStep_matching_event(self):
def test_checkToTriggerNextEscalationStep_matchingEvent(self):
ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_acknowledgement')
ticket.validate()
......@@ -442,19 +263,21 @@ class TestSlapOSRegularisationRequest_checkToTriggerNextEscalationStep(
event2 = ticket.RegularisationRequest_checkToTriggerNextEscalationStep(
7, 'service_module/slapos_crm_acknowledgement',
'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(
'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',
'foo2 comment'),
'foo2 comment', 'slapos-crm.acknowledgment.escalation', {'foo': 'bar'}),
ticket.workflow_history['edit_workflow'][-1]['comment'])
@simulate('RegularisationRequest_checkToSendUniqEvent',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
def test_checkToTriggerNextEscalationStep_recent_event(self):
def test_checkToTriggerNextEscalationStep_recentEvent(self):
ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_acknowledgement')
ticket.validate()
......@@ -478,7 +301,7 @@ class TestSlapOSRegularisationRequest_checkToTriggerNextEscalationStep(
@simulate('RegularisationRequest_checkToSendUniqEvent',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
def test_checkToTriggerNextEscalationStep_other_ticket_event(self):
def test_checkToTriggerNextEscalationStep_other_ticketEvent(self):
ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_acknowledgement')
ticket.validate()
......@@ -501,7 +324,7 @@ class TestSlapOSRegularisationRequest_checkToTriggerNextEscalationStep(
@simulate('RegularisationRequest_checkToSendUniqEvent',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
def test_checkToTriggerNextEscalationStep_other_resource_event(self):
def test_checkToTriggerNextEscalationStep_otherResourceEvent(self):
ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_acknowledgement')
ticket.validate()
......@@ -525,7 +348,7 @@ class TestSlapOSRegularisationRequest_checkToTriggerNextEscalationStep(
@simulate('RegularisationRequest_checkToSendUniqEvent',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
def test_checkToTriggerNextEscalationStep_no_current_event(self):
def test_checkToTriggerNextEscalationStep_noCurrentEvent(self):
ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_acknowledgement')
ticket.validate()
......@@ -542,7 +365,7 @@ class TestSlapOSRegularisationRequest_checkToTriggerNextEscalationStep(
@simulate('RegularisationRequest_checkToSendUniqEvent',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
def test_checkToTriggerNextEscalationStep_no_ticket_resource(self):
def test_checkToTriggerNextEscalationStep_noTicketResource(self):
ticket = self.createRegularisationRequest()
ticket.validate()
ticket.suspend()
......@@ -565,7 +388,7 @@ class TestSlapOSRegularisationRequest_checkToTriggerNextEscalationStep(
@simulate('RegularisationRequest_checkToSendUniqEvent',
'*args, **kwargs',
'raise NotImplementedError, "Should not have been called"')
def test_checkToTriggerNextEscalationStep_not_suspended(self):
def test_checkToTriggerNextEscalationStep_notSuspended(self):
ticket = self.createRegularisationRequest()
ticket.edit(resource='service_module/slapos_crm_acknowledgement')
ticket.validate()
......@@ -585,7 +408,7 @@ class TestSlapOSRegularisationRequest_checkToTriggerNextEscalationStep(
self.assertEqual(event2, None)
def test_checkToTriggerNextEscalationStep_REQUEST_disallowed(self):
def test_checkToTriggerNextEscalationStep_REQUESTdisallowed(self):
ticket = self.createRegularisationRequest()
self.assertRaises(
Unauthorized,
......@@ -593,510 +416,40 @@ class TestSlapOSRegularisationRequest_checkToTriggerNextEscalationStep(
'', '', '', '', '', '',
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):
person = self.makePerson(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):
person = self.makePerson(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):
person = self.makePerson(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):
person = self.makePerson(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):
person = self.makePerson(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(
SlapOSTestCaseMixinWithAbort):
def createInstanceTree(self):
def createInstanceTree(self, project):
new_id = self.generateNewId()
instance_tree = self.portal.instance_tree_module\
.template_instance_tree.Base_createCloneDocument(batch_mode=1)
.newContent(portal_type="Instance Tree")
instance_tree.edit(
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()
self.portal.portal_workflow._jumpToStateFor(
instance_tree, 'start_requested')
return instance_tree
def test_stopFromRegularisationRequest_REQUEST_disallowed(self):
def test_stopFromRegularisationRequest_REQUESTdisallowed(self):
self.assertRaises(
Unauthorized,
self.portal.InstanceTree_stopFromRegularisationRequest,
'',
REQUEST={})
def test_stopFromRegularisationRequest_matching_subscription(self):
person = self.makePerson(index=0, user=0)
instance_tree = self.createInstanceTree()
def test_stopFromRegularisationRequest_matchingSubscription(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
instance_tree = self.createInstanceTree(project)
instance_tree.edit(
destination_section=person.getRelativeUrl(),
)
......@@ -1122,9 +475,10 @@ class TestSlapOSInstanceTree_stopFromRegularisationRequest(
self.assertEqual(instance_tree.isRootSlave(), shared)
self.assertEqual(instance_tree.getSlapState(), "stop_requested")
def test_stopFromRegularisationRequest_stopped_subscription(self):
person = self.makePerson(index=0, user=0)
instance_tree = self.createInstanceTree()
def test_stopFromRegularisationRequest_stoppedSubscription(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
instance_tree = self.createInstanceTree(project)
instance_tree.edit(
destination_section=person.getRelativeUrl(),
)
......@@ -1136,38 +490,48 @@ class TestSlapOSInstanceTree_stopFromRegularisationRequest(
self.assertEqual(result, False)
def test_stopFromRegularisationRequest_non_matching_person(self):
instance_tree = self.createInstanceTree()
def test_stopFromRegularisationRequest_nonMatchingPerson(self):
project = self.addProject()
instance_tree = self.createInstanceTree(project)
self.assertRaises(
AssertionError,
instance_tree.InstanceTree_stopFromRegularisationRequest,
'foobar')
class TestSlapOSInstanceTree_deleteFromRegularisationRequest(
SlapOSTestCaseMixinWithAbort):
def createInstanceTree(self):
def createInstanceTree(self, project):
new_id = self.generateNewId()
instance_tree = self.portal.instance_tree_module\
.template_instance_tree.Base_createCloneDocument(batch_mode=1)
.newContent(portal_type="Instance Tree")
instance_tree.edit(
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()
self.portal.portal_workflow._jumpToStateFor(
instance_tree, 'start_requested')
return instance_tree
def test_deleteFromRegularisationRequest_REQUEST_disallowed(self):
def test_deleteFromRegularisationRequest_REQUESTdisallowed(self):
self.assertRaises(
Unauthorized,
self.portal.InstanceTree_deleteFromRegularisationRequest,
'',
REQUEST={})
def test_deleteFromRegularisationRequest_started_subscription(self):
person = self.makePerson(index=0, user=0)
instance_tree = self.createInstanceTree()
def test_deleteFromRegularisationRequest_startedSubscription(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
instance_tree = self.createInstanceTree(project)
instance_tree.edit(
destination_section=person.getRelativeUrl(),
)
......@@ -1180,6 +544,7 @@ class TestSlapOSInstanceTree_deleteFromRegularisationRequest(
sla_xml = instance_tree.getSlaXml()
shared = instance_tree.isRootSlave()
self.assertEqual(instance_tree.getSlapState(), "start_requested")
self.assertEqual(shared, False)
result = instance_tree.\
InstanceTree_deleteFromRegularisationRequest(person.getRelativeUrl())
......@@ -1193,9 +558,10 @@ class TestSlapOSInstanceTree_deleteFromRegularisationRequest(
self.assertEqual(instance_tree.isRootSlave(), shared)
self.assertEqual(instance_tree.getSlapState(), "destroy_requested")
def test_deleteFromRegularisationRequest_stopped_subscription(self):
person = self.makePerson(index=0, user=0)
instance_tree = self.createInstanceTree()
def test_deleteFromRegularisationRequest_stoppedSubscription(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
instance_tree = self.createInstanceTree(project)
instance_tree.edit(
destination_section=person.getRelativeUrl(),
)
......@@ -1223,9 +589,10 @@ class TestSlapOSInstanceTree_deleteFromRegularisationRequest(
self.assertEqual(instance_tree.isRootSlave(), shared)
self.assertEqual(instance_tree.getSlapState(), "destroy_requested")
def test_deleteFromRegularisationRequest_destroyed_subscription(self):
person = self.makePerson(index=0, user=0)
instance_tree = self.createInstanceTree()
def test_deleteFromRegularisationRequest_destroyedSubscription(self):
project = self.addProject()
person = self.makePerson(project, index=0, user=0)
instance_tree = self.createInstanceTree(project)
instance_tree.edit(
destination_section=person.getRelativeUrl(),
)
......@@ -1237,161 +604,11 @@ class TestSlapOSInstanceTree_deleteFromRegularisationRequest(
self.assertEqual(result, False)
def test_deleteFromRegularisationRequest_non_matching_person(self):
instance_tree = self.createInstanceTree()
def test_deleteFromRegularisationRequest_nonMatchingPerson(self):
project = self.addProject()
instance_tree = self.createInstanceTree(project)
self.assertRaises(
AssertionError,
instance_tree.InstanceTree_deleteFromRegularisationRequest,
'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):
person = self.makePerson(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):
person = self.makePerson(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):
person = self.makePerson(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):
person = self.makePerson(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 @@
import transaction
from erp5.component.test.SlapOSTestCaseMixin import \
SlapOSTestCaseMixin,SlapOSTestCaseMixinWithAbort, simulate
SlapOSTestCaseMixin,SlapOSTestCaseMixinWithAbort, TemporaryAlarmScript
from DateTime import DateTime
from App.Common import rfc1123_date
from Products.ERP5Type.Cache import DEFAULT_CACHE_SCOPE
import json
def getFakeSlapState():
return "destroy_requested"
......@@ -36,7 +36,9 @@ class TestCRMSkinsMixin(SlapOSTestCaseMixinWithAbort):
def afterSetUp(self):
SlapOSTestCaseMixinWithAbort.afterSetUp(self)
self.person = self.makePerson(new_id=self.new_id, index=0, user=0)
self.project = self.addProject()
self.person = self.makePerson(self.project, new_id=self.new_id,
index=0, user=0)
def _cancelTestSupportRequestList(self, title="%"):
for support_request in self.portal.portal_catalog(
......@@ -55,18 +57,19 @@ class TestCRMSkinsMixin(SlapOSTestCaseMixinWithAbort):
assignment.open()
return assignment
def _makeInstanceTree(self):
person = self.portal.person_module.template_member\
.Base_createCloneDocument(batch_mode=1)
def _makeInstanceTree(self, project):
person = self.portal.person_module\
.newContent(portal_type="Person")
instance_tree = self.portal\
.instance_tree_module.template_instance_tree\
.Base_createCloneDocument(batch_mode=1)
.instance_tree_module\
.newContent(portal_type="Instance Tree")
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
destination_section_value=person,
follow_up_value=project
)
return instance_tree
......@@ -87,10 +90,9 @@ class TestCRMSkinsMixin(SlapOSTestCaseMixinWithAbort):
def _makeSoftwareInstallation(self):
self._makeComputeNode()
self._makeComputeNode(self.project)
software_installation = self.portal\
.software_installation_module.template_software_installation\
.Base_createCloneDocument(batch_mode=1)
.software_installation_module.newContent(portal_type="Software Installation")
software_installation.edit(
url_string=self.generateNewSoftwareReleaseUrl(),
aggregate=self.compute_node.getRelativeUrl(),
......@@ -109,8 +111,9 @@ class TestSlapOSSupportRequestModule_getMonitoringUrlList(TestCRMSkinsMixin):
# We assume here that several objects created by others tests don't influentiate
# this test.
self.assertEqual(module.SupportRequestModule_getMonitoringUrlList(), [])
instance_tree = self._makeInstanceTree()
self._makeSoftwareInstance(instance_tree, "https://xxx/")
with TemporaryAlarmScript(self.portal, 'Item_getSubscriptionStatus', "'subscribed'"):
instance_tree = self._makeInstanceTree(self.project)
self._makeSoftwareInstance(instance_tree, "https://xxx/")
support_request = module.newContent(portal_type="Support Request")
self.tic()
......@@ -156,100 +159,65 @@ class TestSlapOSSupportRequestModule_getMonitoringUrlList(TestCRMSkinsMixin):
self.tic()
self.assertNotEqual(instance_tree.getSuccessorList(), [])
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
class TestComputeNode_hasContactedRecently(SlapOSTestCaseMixinWithAbort):
def test_ComputeNode_hasContactedRecently_newly_created(self):
compute_node = self._makeComputeNode()[0]
compute_node, _ = self._makeComputeNode(self.addProject())
self.tic()
has_contacted = compute_node.ComputeNode_hasContactedRecently()
self.assertTrue(has_contacted)
@simulate('ComputeNode_getCreationDate', '*args, **kwargs','return DateTime() - 32')
def test_ComputeNode_hasContactedRecently_no_data(self):
compute_node = self._makeComputeNode()[0]
try:
self.pinDateTime(DateTime()-32)
compute_node, _ = self._makeComputeNode(self.addProject())
finally:
self.unpinDateTime()
self.tic()
compute_node.getCreationDate = self.portal.ComputeNode_getCreationDate
has_contacted = compute_node.ComputeNode_hasContactedRecently()
self.assertFalse(has_contacted)
@simulate('ComputeNode_getCreationDate', '*args, **kwargs','return DateTime() - 32')
def test_ComputeNode_hasContactedRecently_memcached(self):
compute_node = self._makeComputeNode()[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()[0]
try:
self.pinDateTime(DateTime()-32)
compute_node.setAccessStatus("")
compute_node, _ = self._makeComputeNode(self.addProject())
finally:
self.unpinDateTime()
compute_node.setAccessStatus("")
self.tic()
compute_node.getCreationDate = self.portal.ComputeNode_getCreationDate
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_with_spl(self):
compute_node = self._makeComputeNode()[0]
def test_ComputeNode_hasContactedRecently_memcached_oudated_no_spl(self):
try:
self.pinDateTime(DateTime()-32)
compute_node, _ = self._makeComputeNode(self.addProject())
compute_node.setAccessStatus("")
finally:
self.unpinDateTime()
self.createSPL(compute_node)
self.tic()
compute_node.getCreationDate = self.portal.ComputeNode_getCreationDate
has_contacted = compute_node.ComputeNode_hasContactedRecently()
self.assertFalse(has_contacted)
class TestSlapOSisSupportRequestCreationClosed(TestCRMSkinsMixin):
def afterSetUp(self):
TestCRMSkinsMixin.afterSetUp(self)
self.project = self.addProject()
self._cancelTestSupportRequestList()
self.clearCache()
def test_ERP5Site_isSupportRequestCreationClosed(self):
person = self.makePerson(user=0)
other_person = self.makePerson(user=0)
person = self.makePerson(self.project, user=0)
other_person = self.makePerson(self.project, user=0)
url = person.getRelativeUrl()
self.assertFalse(self.portal.ERP5Site_isSupportRequestCreationClosed(url))
self.assertFalse(self.portal.ERP5Site_isSupportRequestCreationClosed())
......@@ -284,7 +252,7 @@ class TestSlapOSisSupportRequestCreationClosed(TestCRMSkinsMixin):
other_person.getRelativeUrl()))
def test_ERP5Site_isSupportRequestCreationClosed_suspended_state(self):
person = self.makePerson(user=0)
person = self.makePerson(self.project, user=0)
url = person.getRelativeUrl()
self.assertFalse(self.portal.ERP5Site_isSupportRequestCreationClosed(url))
self.assertFalse(self.portal.ERP5Site_isSupportRequestCreationClosed())
......@@ -308,7 +276,7 @@ class TestSlapOSisSupportRequestCreationClosed(TestCRMSkinsMixin):
def test_ERP5Site_isSupportRequestCreationClosed_nonmonitoring(self):
person = self.makePerson(user=0)
person = self.makePerson(self.project, user=0)
url = person.getRelativeUrl()
self.assertFalse(self.portal.ERP5Site_isSupportRequestCreationClosed(url))
self.assertFalse(self.portal.ERP5Site_isSupportRequestCreationClosed())
......@@ -331,397 +299,25 @@ class TestSlapOSisSupportRequestCreationClosed(TestCRMSkinsMixin):
self.assertFalse(self.portal.ERP5Site_isSupportRequestCreationClosed())
class TestSlapOSComputeNode_CheckState(TestCRMSkinsMixin):
def beforeTearDown(self):
self._cancelTestSupportRequestList()
transaction.abort()
class TestSlapOSHasError(SlapOSTestCaseMixin):
def afterSetUp(self):
TestCRMSkinsMixin.afterSetUp(self)
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):
support_request = self.portal.portal_catalog.getResultValue(
portal_type = 'Support Request',
title = request_title,
simulation_state = 'validated',
default_aggregate_uid = compute_node_uid
def test_SoftwareInstance_hasReportedError(self):
instance = self.portal.software_instance_module.newContent(
portal_type="Software Instance",
reference=self.generateNewId()
)
return support_request
@simulate('ERP5Site_isSupportRequestCreationClosed', '*args, **kwargs','return 0')
def test_ComputeNode_checkState_call_support_request(self):
compute_node = self._makeComputeNode(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(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(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(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(owner=self.makePerson(user=0))[0]
self._makeComplexComputeNode()
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_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(owner=self.makePerson(user=0))[0]
self._makeComplexComputeNode()
person = compute_node.getSourceAdministrationValue()
self.portal.REQUEST['test_ComputeNode_checkState_stalled_instance'] = \
self._makeNotificationMessage(compute_node.getReference())
# Computer is getting access
compute_node.setAccessStatus("")
_, partition = self._makeComputeNode(self.addProject())
error_date = DateTime()
try:
self.pinDateTime(DateTime()-1.1)
self.start_requested_software_instance.setAccessStatus("")
self.start_requested_software_installation.setAccessStatus("")
self.pinDateTime(error_date)
instance.setErrorStatus("")
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())
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(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._makeComputePartitionList()
instance.setErrorStatus("")
self.assertEqual(instance.SoftwareInstance_hasReportedError(), None)
instance.setAggregateValue(self.compute_node.partition1)
instance.setAggregateValue(partition)
self.assertEqual(str(instance.SoftwareInstance_hasReportedError()), '#error ')
......@@ -729,11 +325,7 @@ class TestSlapOSHasError(SlapOSTestCaseMixin):
self.assertEqual(instance.SoftwareInstance_hasReportedError(), None)
def test_SoftwareInstallation_hasReportedError(self):
software_release = self._makeSoftwareRelease()
self._makeComputeNode()
installation = self._makeSoftwareInstallation(
software_release.getUrlString()
)
installation = self.portal.software_installation_module.newContent()
self.assertEqual(installation.SoftwareInstallation_hasReportedError(), None)
......@@ -751,202 +343,15 @@ class TestSlapOSHasError(SlapOSTestCaseMixin):
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._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._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._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._makeComputePartitionList()
instance.setAggregateValue(self.compute_node.partition1)
instance.setErrorStatus("")
self.assertEqual(
None,
instance_tree.InstanceTree_checkSoftwareInstanceState())
class TestCRMPropertySheetConstraint(SlapOSTestCaseMixin):
def afterSetUp(self):
SlapOSTestCaseMixin.afterSetUp(self)
portal = self.getPortalObject()
self.project = self.addProject()
self.ticket_trade_condition = portal.sale_trade_condition_module.slapos_ticket_trade_condition
person_user = self.makePerson()
person_user = self.makePerson(self.project)
self.tic()
# Login as new user
......@@ -957,8 +362,9 @@ class TestCRMPropertySheetConstraint(SlapOSTestCaseMixin):
self.support_request = portal.support_request_module.newContent(
portal_type="Support Request",
destination_decision=person_user.getRelativeUrl(),
specialise=self.ticket_trade_condition.getRelativeUrl()
destination_value=person_user,
destination_decision_value=person_user,
#specialise=
)
# Value set by the init
......@@ -968,51 +374,26 @@ class TestCRMPropertySheetConstraint(SlapOSTestCaseMixin):
def beforeTearDown(self):
transaction.abort()
def testCheckCausalitySourceDestinationConsistency(self):
person = self.portal.portal_membership.getAuthenticatedMember().getUserValue()
self.support_request.approveRegistration()
self.tic()
self.logout()
self.login()
event = self.support_request.getCausalityValue()
self.assertNotEqual(event, None)
self.assertFalse(event.checkConsistency())
self.assertFalse(self.support_request.checkConsistency())
source = event.getDestination()
event.setDestination(person.getRelativeUrl())
non_consistency_list = [str(i.getTranslatedMessage()) for i in self.support_request.checkConsistency()]
self.assertEqual(non_consistency_list,
['Destination of the related event should be the slapos organisation'])
event.setSource(source)
non_consistency_list = [str(i.getTranslatedMessage()) for i in self.support_request.checkConsistency()]
self.assertEqual(non_consistency_list,
['Sender of the related event should be the customer',
'Destination of the related event should be the slapos organisation'])
def testCheckCustomerAsSourceOrDestinationConsistency(self):
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.logout()
self.login()
event = self.support_request.getCausalityValue()
event = self.support_request.getFollowUpRelatedValue()
self.assertNotEqual(event, None)
self.assertFalse(event.checkConsistency())
self.assertFalse(self.support_request.checkConsistency())
person_user = self.makePerson()
person_user = self.makePerson(self.project)
self.tic()
event.setSource(person_user.getRelativeUrl())
......@@ -1025,101 +406,15 @@ class TestCRMPropertySheetConstraint(SlapOSTestCaseMixin):
event.setDestination(person.getRelativeUrl())
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(owner=self.makePerson(user=0))[0])
support_request.setDestinationDecisionValue(self.makePerson(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):
def _test(self, module):
self.assertRaises(ValueError, module.Folder_getTicketFeedUrl)
person = self.makePerson(user=1)
person = self.makePerson(self.project, user=1)
self.addProjectProductionManagerAssignment(person, self.project)
self.tic()
self.login(person.getUserId())
url = module.Folder_getTicketFeedUrl()
......@@ -1141,235 +436,3 @@ class TestSlapOSFolder_getTicketFeedUrl(TestCRMSkinsMixin):
def test_Folder_getTicketFeedUrl_incident_response_module(self):
self._test(self.portal.incident_response_module)
class TestSlapOSPerson_getSlapOSPendingTicket(TestCRMSkinsMixin):
def test_getSlapOSPendingTicket_support_request(self):
person = self.makePerson()
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()
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()
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()
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()
# 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.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()
# 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()
person.Person_sendPendingTicketReminder()
self.assertEqual(self.portal.REQUEST["test_getSlapOSPendingTicketMessageTemplate"],
"called")
class TestSlapOSPerson_sendSlapOSPendingTicketNotification(TestCRMSkinsMixin):
def test_sendSlapOSPendingTicketNotification(self):
person = self.makePerson()
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(),
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
Incident Response Module | rss_view
Incident Response Module | view
Incident Response | view
Instance Tree | jump_to_related_upgrade_decision_line
Instance Tree | jump_to_related_upgrade_decision
Instance Tree | view_status
Instance Tree | view_ticket
Person | slapos_user_pending_ticket_report
Regularisation Request Module | rss_view
Regularisation Request Module | view
Regularisation Request | clone_ticket_and_event_list
......@@ -13,10 +12,8 @@ Regularisation Request | create_new_file
Regularisation Request | document_list
Regularisation Request | new_event
Regularisation Request | view
Site Message | update_destination_for_slapos
Support Request Module | rss_view
Support Request Module | slapos_support_request_instance_message_report
Support Request Module | support_request_monitor_link
Support Request Module | support_request_monitor_opml_description_list
Support Request | jump_related_slapos_item
Support Request | view_monitoring
\ 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/**
service_module/slapos_crm_acknowledgement
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_reminder
service_module/slapos_crm_information
service_module/slapos_crm_invoice_cancellation
service_module/slapos_crm_monitoring
service_module/slapos_crm_upgrade
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_spam
service_module/slapos_crm_stop_acknowledgement
service_module/slapos_crm_stop_reminder
service_module/slapos_crm_upgrade
\ No newline at end of file
service_module/slapos_crm_acknowledgement
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_reminder
service_module/slapos_crm_information
service_module/slapos_crm_invoice_cancellation
service_module/slapos_crm_monitoring
service_module/slapos_crm_upgrade
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
service_module/slapos_crm_spam
service_module/slapos_crm_stop_acknowledgement
service_module/slapos_crm_stop_reminder
service_module/slapos_crm_upgrade
\ No newline at end of file
event_module/slapos_crm_web_message_template
person_module/allocation_tester
portal_alarms/slapos_crm_*
portal_categories/monitor_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_*
support_request_module/slapos_crm_support_request_template
\ No newline at end of file
service_module/slapos_crm_*
\ No newline at end of file
Compute Node | monitor_scope
Compute Node | upgrade_scope
Incident Response Module | business_application
Incident Response | aggregate
Incident Response | specialise
Instance Tree | monitor_scope
Instance Tree | upgrade_scope
Regularisation Request Module | business_application
Regularisation Request | specialise
Support Request | aggregate
......
Mail Message | SlapOSEventConstraint
Regularisation Request | Codification
Site Message | SlapOSEventConstraint
Support Request | SlapOSSupportRequestConstraint
Web Message | SlapOSEventConstraint
\ No newline at end of file
......@@ -3,6 +3,4 @@ Incident Response | ticket_workflow
Regularisation Request | edit_workflow
Regularisation Request | pricing_interaction_workflow
Regularisation Request | ticket_interaction_workflow
Regularisation Request | ticket_slap_interface_workflow
Regularisation Request | ticket_workflow
Support Request | ticket_slap_interface_workflow
\ No newline at end of file
Regularisation Request | ticket_workflow
\ No newline at end of file
SlapOSCRMSystemPreference
SlapOSEventConstraint
SlapOSSupportRequestConstraint
\ No newline at end of file
SlapOSEventConstraint
\ No newline at end of file
test.erp5.testSlapOSCRMSkins
test.erp5.testSlapOSCRMRegularisationRequestSkins
test.erp5.testSlapOSCRMAlarm
test.erp5.testSlapOSCloudTicketSlapInterfaceWorkflow
\ No newline at end of file
test.erp5.testSlapOSCRMRegularisationRequestSkins
test.erp5.testSlapOSCRMSkins
\ No newline at end of file
ticket_slap_interface_workflow
ticket_workflow
\ No newline at end of file
<?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>items</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_upgrade_scope</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>items</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</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_dialog_mode_category</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Upgrade Scope</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.getUpgradeScope()</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: getattr(here.portal_categories[field.getId().replace(\'my_\', \'\', 1)], preferences.getPreference(\'preferred_category_child_item_list_method_id\', \'getCategoryChildCompactLogicalPathItemList\'))(local_sort_id=(\'int_index\', \'translated_title\'), checked_permission=\'View\')</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
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