Commit a333fbb0 authored by Rafael Monnerat's avatar Rafael Monnerat

slapos_subscription_request: Trigger alarm when invalidate Compute Node and Project

  The alarm should update the state of Subscription Request whenever Compute Node and Project are invalidated, to proper cancel it as soon as possible.
parent d93e3539
Pipeline #35898 failed with stage
in 0 seconds
......@@ -97,11 +97,6 @@ class TestSlapOSSubscriptionScenario(TestSlapOSSubscriptionScenarioMixin):
base_price=9,
resource_value=software_product
)
sale_supply.newContent(
portal_type="Sale Supply Line",
base_price=99,
resource="service_module/slapos_compute_node_subscription"
)
sale_supply.validate()
self.tic()
......@@ -172,7 +167,6 @@ class TestSlapOSSubscriptionScenario(TestSlapOSSubscriptionScenarioMixin):
with PinnedDateTime(self, DateTime('2024/02/17 01:01')):
public_instance_title = 'Public title %s' % self.generateNewId()
self.login(public_person.getUserId())
self.personRequestInstanceNotReady(
......@@ -255,11 +249,307 @@ class TestSlapOSSubscriptionScenario(TestSlapOSSubscriptionScenarioMixin):
# 5 (can reduce to 2) assignment
# 2 simulation mvt
# 1 packing list / line
# 3 sale supply / line
# 2 sale supply / line
# 2 sale trade condition
# 1 software installation
# 1 software product
# 2 subscription requests
self.assertRelatedObjectCount(project, 22)
self.assertRelatedObjectCount(project, 21)
self.checkERP5StateBeforeExit()
def test_subscription_request_cancel_after_project_is_invalidated(self):
""" It is only tested with is_virtual_master_accountable enabled since the
subscription request is automatically validated/invalidated if price is 0.
"""
with PinnedDateTime(self, DateTime('2024/01/31')):
currency, _, _, sale_person = self.bootstrapVirtualMasterTest()
self.logout()
# lets join as slapos administrator, which will manager the project
project_owner_reference = 'project-%s' % self.generateNewId()
self.joinSlapOS(self.web_site, project_owner_reference)
self.login()
project_owner_person = self.portal.portal_catalog.getResultValue(
portal_type="ERP5 Login",
reference=project_owner_reference).getParentValue()
# owner_person.setCareerSubordinationValue(seller_organisation)
self.tic()
self.logout()
self.login(sale_person.getUserId())
project_relative_url = self.addProject(
is_accountable=True, person=project_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.logout()
# 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()
# first slapos administrator assignment can only be created by
# the erp5 manager
self.addProjectProductionManagerAssignment(owner_person, project)
self.tic()
self.login(project_owner_person.getUserId())
# Pay deposit to validate virtual master
deposit_amount = 42.0
ledger = self.portal.portal_categories.ledger.automated
outstanding_amount_list = project_owner_person.Entity_getOutstandingDepositAmountList(
currency.getUid(), ledger_uid=ledger.getUid())
amount = sum([i.total_price for i in outstanding_amount_list])
self.assertEqual(amount, deposit_amount)
self.login()
# Invalidate Project to cancel subscription, there isnt a use case except
# by Manager, but we would like to ensure it works, once the action is
# implemented.
project.invalidate()
self.tic()
self.login()
self.checkServiceSubscriptionRequest(project, 'cancelled')
self.login(project_owner_person.getUserId())
amount = sum([i.total_price for i in project_owner_person.Entity_getOutstandingDepositAmountList(
currency.getUid(), ledger_uid=ledger.getUid())])
self.assertEqual(0, amount)
self.logout()
self.login()
# Check accounting
transaction_list = self.portal.account_module.receivable.Account_getAccountingTransactionList(
mirror_section_uid=project_owner_person.getUid())
assert len(transaction_list) == 0, len(transaction_list)
# Ensure no unexpected object has been created
# 1 credential request
# 4 assignment
# 2 Sale Trade condition
# 1 subscription request
self.assertRelatedObjectCount(project, 8)
self.checkERP5StateBeforeExit()
def test_subscription_request_cancel_after_compute_node_is_invalidated(self):
""" It is only tested with is_virtual_master_accountable enabled since the
subscription request is automatically validated/invalidated if price is 0.
"""
with PinnedDateTime(self, DateTime('2024/01/31')):
currency, _, _, sale_person = self.bootstrapVirtualMasterTest()
self.logout()
# lets join as slapos administrator, which will manager the project
project_owner_reference = 'project-%s' % self.generateNewId()
self.joinSlapOS(self.web_site, project_owner_reference)
self.login()
project_owner_person = self.portal.portal_catalog.getResultValue(
portal_type="ERP5 Login",
reference=project_owner_reference).getParentValue()
# owner_person.setCareerSubordinationValue(seller_organisation)
self.tic()
self.logout()
self.login(sale_person.getUserId())
project_relative_url = self.addProject(
is_accountable=True, person=project_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()
]
)
public_server_software = self.generateNewSoftwareReleaseUrl()
public_instance_type = 'public type'
software_product, release_variation, type_variation = self.addSoftwareProduct(
"instance product", project, public_server_software, public_instance_type
)
self.logout()
self.login(sale_person.getUserId())
sale_supply = self.portal.sale_supply_module.newContent(
portal_type="Sale Supply",
title="price for %s" % project.getRelativeUrl(),
source_project_value=project,
price_currency_value=currency
)
sale_supply.newContent(
portal_type="Sale Supply Line",
base_price=9,
resource_value=software_product
)
sale_supply.newContent(
portal_type="Sale Supply Line",
base_price=99,
resource="service_module/slapos_compute_node_subscription"
)
sale_supply.validate()
self.tic()
# some preparation
self.logout()
# 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()
# first slapos administrator assignment can only be created by
# the erp5 manager
self.addProjectProductionManagerAssignment(owner_person, project)
self.tic()
self.login(project_owner_person.getUserId())
# Pay deposit to validate virtual master
deposit_amount = 42.0
ledger = self.portal.portal_categories.ledger.automated
outstanding_amount_list = project_owner_person.Entity_getOutstandingDepositAmountList(
currency.getUid(), ledger_uid=ledger.getUid())
amount = sum([i.total_price for i in outstanding_amount_list])
self.assertEqual(amount, deposit_amount)
# Ensure to pay from the website
outstanding_amount = self.web_site.restrictedTraverse(outstanding_amount_list[0].getRelativeUrl())
outstanding_amount.Base_createExternalPaymentTransactionFromOutstandingAmountAndRedirect()
self.tic()
self.logout()
self.login()
payment_transaction = self.portal.portal_catalog.getResultValue(
portal_type="Payment Transaction",
destination_section_uid=project_owner_person.getUid(),
simulation_state="started"
)
self.assertEqual(payment_transaction.getSpecialiseValue().getTradeConditionType(), "deposit")
# payzen/wechat or accountant will only stop the payment
payment_transaction.stop()
self.tic()
assert payment_transaction.receivable.getGroupingReference(None) is not None
self.login(project_owner_person.getUserId())
amount = sum([i.total_price for i in project_owner_person.Entity_getOutstandingDepositAmountList(
currency.getUid(), ledger_uid=ledger.getUid())])
self.assertEqual(0, amount)
self.logout()
# hooray, now it is time to create compute_nodes
self.login(owner_person.getUserId())
public_server_title = 'Public Server for %s' % owner_reference
public_server_id = self.requestComputeNode(public_server_title, project.getReference())
public_server = self.portal.portal_catalog.getResultValue(
portal_type='Compute Node', reference=public_server_id)
self.setAccessToMemcached(public_server)
self.assertNotEqual(None, public_server)
self.setServerOpenPublic(public_server)
public_server.generateCertificate()
self.addAllocationSupply("for compute node", public_server, software_product,
release_variation, type_variation)
# and install some software on them
self.supplySoftware(public_server, public_server_software)
# format the compute_nodes
self.formatComputeNode(public_server)
self.logout()
self.tic()
self.login(project_owner_person.getUserId())
# Pay deposit to validate virtual master
deposit_amount = 99.0
ledger = self.portal.portal_categories.ledger.automated
outstanding_amount_list = project_owner_person.Entity_getOutstandingDepositAmountList(
currency.getUid(), ledger_uid=ledger.getUid())
amount = sum([i.total_price for i in outstanding_amount_list])
self.assertEqual(amount, deposit_amount)
self.login()
# Invalidate Public Computer to cancel subscription we would like to ensure
# it works, once the action is implemented.
public_server.invalidate()
self.tic()
self.login()
self.checkServiceSubscriptionRequest(public_server, 'cancelled')
self.login(project_owner_person.getUserId())
amount = sum([i.total_price for i in project_owner_person.Entity_getOutstandingDepositAmountList(
currency.getUid(), ledger_uid=ledger.getUid())])
self.assertEqual(0, amount)
self.logout()
self.login()
# Check accounting
transaction_list = self.portal.account_module.receivable.Account_getAccountingTransactionList(
mirror_section_uid=project_owner_person.getUid())
assert len(transaction_list) == 2, len(transaction_list)
# Ensure no unexpected object has been created
# 1 accounting transaction / line
# 3 allocation supply / Line / Cell
# 1 compute node
# 1 credential request
# 1 event
# 1 open sale order / line
# 4 assignment
# 2 simulation mvt
# 1 packing list / line
# 3 sale supply / line
# 2 sale trade condition
# 1 software installation
# 1 software product
# 2 subscription requests
self.assertRelatedObjectCount(project, 24)
self.checkERP5StateBeforeExit()
......@@ -15,6 +15,10 @@
<type>Open Sale Order</type>
<workflow>slapos_subscription_request_interaction_workflow</workflow>
</chain>
<chain>
<type>Project</type>
<workflow>slapos_subscription_request_interaction_workflow</workflow>
</chain>
<chain>
<type>Sale Invoice Transaction Line</type>
<workflow>slapos_subscription_request_interaction_workflow</workflow>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Interaction Workflow Interaction" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>after_script/portal_workflow/slapos_subscription_request_interaction_workflow/script_Base_triggerValidationAlarm</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>interaction_ComputeNode_invalidate</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Interaction Workflow Interaction</string> </value>
</item>
<item>
<key> <string>portal_type_filter</string> </key>
<value>
<tuple>
<string>Compute Node</string>
<string>Project</string>
</tuple>
</value>
</item>
<item>
<key> <string>portal_type_group_filter</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>temporary_document_disallowed</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>ComputeNode_invalidate</string> </value>
</item>
<item>
<key> <string>trigger_method_id</string> </key>
<value>
<tuple>
<string>invalidate</string>
</tuple>
</value>
</item>
<item>
<key> <string>trigger_once_per_transaction</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>trigger_type</string> </key>
<value> <int>2</int> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -2,6 +2,7 @@ Compute Node | slapos_subscription_request_interaction_workflow
Email | -coordinate_interaction_workflow
Instance Tree | slapos_subscription_request_interaction_workflow
Open Sale Order | slapos_subscription_request_interaction_workflow
Project | slapos_subscription_request_interaction_workflow
Sale Invoice Transaction Line | slapos_subscription_request_interaction_workflow
Sale Trade Condition | slapos_subscription_request_interaction_workflow
Software Product | slapos_subscription_request_interaction_workflow
......
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