Commit 000ec3e1 authored by Romain Courteaud's avatar Romain Courteaud

slapos_panel: add an action to pay a Subscription Request by an Organisation

parent 6893bc65
......@@ -184,3 +184,103 @@ class TestSlapOSSubscriptionChangeRequestScenario(TestSlapOSSubscriptionChangeRe
with PinnedDateTime(self, DateTime('2024/02/15')):
self.checkERP5StateBeforeExit()
def test_subscription_change_request_change_project_destination_section_scenario(self):
currency, _, _, sale_person = self.bootstrapVirtualMasterTest(is_virtual_master_accountable=True)
self.tic()
self.logout()
with PinnedDateTime(self, DateTime('2024/01/25')):
# lets join as slapos administrator, which will own few compute_nodes
owner_reference = 'owner-%s' % self.generateNewId()
self.joinSlapOS(self.web_site, owner_reference)
self.login()
owner_person = self.portal.portal_catalog.getResultValue(
portal_type="ERP5 Login",
reference=owner_reference).getParentValue()
#owner_person.setCareerSubordinationValue(seller_organisation)
self.tic()
# hooray, now it is time to create compute_nodes
self.logout()
self.login(sale_person.getUserId())
# create a default project
project_relative_url = self.addProject(person=owner_person, currency=currency)
self.logout()
self.login()
project = self.portal.restrictedTraverse(project_relative_url)
preference = self.portal.portal_preferences.slapos_default_system_preference
preference.edit(
preferred_subscription_assignment_category_list=[
'function/customer',
'role/client',
'destination_project/%s' % project.getRelativeUrl()
]
)
self.tic()
self.logout()
self.login(owner_person.getUserId())
with PinnedDateTime(self, DateTime('2024/02/25')):
self.login(sale_person.getUserId())
subscription_request = self.portal.portal_catalog.getResultValue(
portal_type='Subscription Request',
aggregate__uid=project.getUid()
)
owner_organisation = self.portal.organisation_module.newContent(
title='Test Owner Organisation',
vat_code='1234567890'
)
owner_organisation.validate()
new_trade_condition = owner_organisation.Organisation_claimSlaposSubscriptionRequest(
subscription_request.getReference(),
None
)
self.tic()
self.logout()
self.login()
self.assertEquals(new_trade_condition.getDestination(),
owner_person.getRelativeUrl())
self.assertEquals(new_trade_condition.getDestinationSection(),
owner_organisation.getRelativeUrl())
self.assertEquals(new_trade_condition.getPortalType(),
'Sale Trade Condition')
self.assertEquals(subscription_request.getSimulationState(),
'cancelled')
new_subscription_request = self.portal.portal_catalog.getResultValue(
portal_type='Subscription Request',
aggregate__uid=project.getUid()
)
self.assertEquals(new_subscription_request.getDestination(),
owner_person.getRelativeUrl())
self.assertEquals(new_subscription_request.getDestinationSection(),
owner_organisation.getRelativeUrl())
self.assertEquals(new_subscription_request.getSimulationState(),
'submitted')
# If the script is called a second time,
# it should return the existing submitted Subscription Request
self.login(sale_person.getUserId())
new_subscription_request_2 = owner_organisation.Organisation_claimSlaposSubscriptionRequest(
new_subscription_request.getReference(),
None
)
self.assertEquals(new_subscription_request.getRelativeUrl(),
new_subscription_request_2.getRelativeUrl())
# Ensure no unexpected object has been created
# 2 assignment
# 2 sale trade condition
# 2 subscription request
self.assertRelatedObjectCount(project, 6)
with PinnedDateTime(self, DateTime('2024/02/15')):
self.checkERP5StateBeforeExit()
<?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>claim_slapos_subscription_request</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>60.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Claim Subscription Request</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}/Organisation_claimSlaposSubscriptionRequestDialog</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: portal.Base_checkPermission(\'subscription_request_module\', \'Add portal content\') and (context.getValidationState() == \'validated\')</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
portal = context.getPortalObject()
Base_translateString = portal.Base_translateString
organisation = context
from zExceptions import Unauthorized
if REQUEST is not None:
raise Unauthorized
batch = (dialog_id is None)
# Search for the matching item
sql_subscription_request_list = portal.portal_catalog(
reference=reference,
# Project are not handled yet, as it must also move all compute node subscription at the same time
portal_type=['Subscription Request'],
simulation_state='submitted',
limit=2
)
if len(sql_subscription_request_list) != 1:
keep_items = {
'your_reference': reference,
'portal_status_level': 'warning',
'portal_status_message': Base_translateString('Unknown reference')
}
if batch:
raise ValueError(keep_items['portal_status_message'] + str(len(sql_subscription_request_list)))
return context.Base_renderForm(dialog_id, keep_items=keep_items)
subscription_request = sql_subscription_request_list[0].getObject()
tag = "%s-%s" % (script.id, subscription_request.getRelativeUrl())
if subscription_request.getDestinationSection() == organisation.getRelativeUrl():
keep_items = {
'your_reference': reference,
'portal_status_level': 'warning',
'portal_status_message': Base_translateString('The Subscription Request is already paid by this organisation')
}
if batch:
return subscription_request
return context.Base_renderForm(dialog_id, keep_items=keep_items)
# Create the Subscription Change Request
item = subscription_request.getAggregateValue()
if item.getPortalType() == 'Project':
project = item
else:
project = subscription_request.getSourceProjectValue()
subscription_change_request = subscription_request.getResourceValue().Resource_createSubscriptionRequest(
subscription_request.getDestinationValue(),
# [software_type, software_release],
subscription_request.getVariationCategoryList(),
project,
currency_value=subscription_request.getPriceCurrencyValue(),
temp_object=True,
item_value=item,
causality_value=subscription_request.getCausalityValue()
)
current_trade_condition = subscription_change_request.getSpecialiseValue()
if (current_trade_condition.getDestination() is None):
# Create a dedicated trade condition for the customer
# to define the payment by this organisation
customer = subscription_request.getDestinationValue()
new_sale_trade_condition = portal.sale_trade_condition_module.newContent(
portal_type='Sale Trade Condition',
specialise_value=current_trade_condition,
title='%s for %s' % (current_trade_condition.getTitle(), customer.getTitle()),
destination_value=customer,
destination_section_value=organisation,
# source_project=current_trade_condition.getSourceProject(),
price_currency=current_trade_condition.getPriceCurrency(),
trade_condition_type=current_trade_condition.getTradeConditionType(),
)
new_sale_trade_condition.validate()
new_sale_trade_condition.reindexObject(activate_kw={'tag': tag})
organisation.activate(after_tag=tag).Organisation_claimSlaposSubscriptionRequest(reference, None)
keep_items = {
'portal_status_message': Base_translateString('Creating a dedicated Trade Condition for the customer')
}
if batch:
return new_sale_trade_condition
return new_sale_trade_condition.Base_redirect(keep_items=keep_items)
elif ((current_trade_condition.getDestination() == subscription_request.getDestination()) and
(current_trade_condition.getDestinationSection() == organisation.getRelativeUrl())):
# We have a matching Trade Condition.
# We can recreate the Subscription Request
subscription_change_request = subscription_request.getResourceValue().Resource_createSubscriptionRequest(
subscription_request.getDestinationValue(),
# [software_type, software_release],
subscription_request.getVariationCategoryList(),
project,
currency_value=subscription_request.getPriceCurrencyValue(),
item_value=item,
causality_value=subscription_request.getCausalityValue()
)
assert subscription_change_request.getDestinationSection() == organisation.getRelativeUrl()
subscription_request.cancel(comment='Replaced by %s' % subscription_change_request.getReference())
if batch:
return subscription_change_request
return subscription_change_request.Base_redirect()
else:
keep_items = {
'your_reference': reference,
'portal_status_level': 'error',
'portal_status_message': Base_translateString('This customer already has a dedicated incompatible Trade Condition')
}
if batch:
raise ValueError(keep_items['portal_status_message'])
return current_trade_condition.Base_redirect(keep_items=keep_items)
<?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>reference, dialog_id, activate_kw=None, REQUEST=None, **kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Organisation_claimSlaposSubscriptionRequest</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>Organisation_claimSlaposSubscriptionRequest</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/>
</value>
</item>
<item>
<key> <string>center</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>hidden</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>left</string> </key>
<value>
<list>
<string>your_reference</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>Organisation_claimSlaposSubscriptionRequestDialog</string> </value>
</item>
<item>
<key> <string>method</string> </key>
<value> <string>POST</string> </value>
</item>
<item>
<key> <string>name</string> </key>
<value> <string>Organisation_claimSlaposSubscriptionRequestDialog</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>Claim Subscription</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>required</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>your_reference</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_dialog_mode_reference</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -35,6 +35,7 @@ Instance Tree | slapos_request_hs_stop
Instance Tree | slapos_view_request_destroy
Instance Tree | update_slapos_parameter
Mail Message | slapos_panel_view
Organisation | claim_slapos_subscription_request
Person | claim_slapos_item_subscription
Person | create_slapos_project
Person | slapos_panel_view
......
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