slapos_erp5: Add Scenario test for Subscription Cancellation
Showing
# -*- coding: utf8 -*- | ||
############################################################################## | ||
# | ||
# Copyright (c) 2012 Nexedi SA and Contributors. All Rights Reserved. | ||
# | ||
# WARNING: This program as such is intended to be used by professional | ||
# programmers who take the whole responsibility of assessing all potential | ||
# consequences resulting from its eventual inadequacies and bugs | ||
# End users who are looking for a ready-to-use solution with commercial | ||
# guarantees and support are strongly adviced to contract a Free Software | ||
# Service Company | ||
# | ||
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
# | ||
############################################################################## | ||
from erp5.component.test.testSlapOSERP5VirtualMasterScenario import TestSlapOSVirtualMasterScenarioMixin | ||
from erp5.component.test.SlapOSTestCaseMixin import PinnedDateTime | ||
from DateTime import DateTime | ||
class TestSlapOSSubscriptionScenarioMixin(TestSlapOSVirtualMasterScenarioMixin): | ||
pass | ||
class TestSlapOSSubscriptionScenario(TestSlapOSSubscriptionScenarioMixin): | ||
def test_subscription_request_cancel_after_instance_is_archived(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() | ||
# 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()) | ||
Please
register
or
sign in
to reply
|
||
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.login(project_owner_person.getUserId()) | ||
# Pay deposit to validate virtual master + one computer | ||
deposit_amount = 42.0 + 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) | ||
# 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() | ||
# join as the another visitor and request software instance on public | ||
# compute_node | ||
self.logout() | ||
public_reference = 'public-%s' % self.generateNewId() | ||
self.joinSlapOS(self.web_site, public_reference) | ||
self.login() | ||
public_person = self.portal.portal_catalog.getResultValue( | ||
portal_type="ERP5 Login", | ||
reference=public_reference).getParentValue() | ||
with PinnedDateTime(self, DateTime('2024/02/17 01:01')): | ||
public_instance_title = 'Public title %s' % self.generateNewId() | ||
self.login(public_person.getUserId()) | ||
self.personRequestInstanceNotReady( | ||
software_release=public_server_software, | ||
software_type=public_instance_type, | ||
partition_reference=public_instance_title, | ||
project_reference=project.getReference() | ||
) | ||
self.tic() | ||
instance_tree = self.portal.portal_catalog.getResultValue( | ||
portal_type="Instance Tree", | ||
title=public_instance_title, | ||
follow_up__reference=project.getReference() | ||
) | ||
person = instance_tree.getDestinationSectionValue() | ||
self.assertEqual(person.getUserId(), public_person.getUserId()) | ||
subscription_request = self.checkServiceSubscriptionRequest(instance_tree, 'submitted') | ||
expected_deposit_amount = 9.0 | ||
self.assertEqual(subscription_request.getTotalPrice(), | ||
expected_deposit_amount) | ||
self.tic() | ||
outstanding_amount_list = person.Entity_getOutstandingDepositAmountList( | ||
currency.getUid(), ledger_uid=subscription_request.getLedgerUid()) | ||
self.assertEqual(sum([i.total_price for i in outstanding_amount_list]), | ||
expected_deposit_amount) | ||
self.login(public_person.getUserId()) | ||
self.personRequestInstanceNotReady( | ||
software_release=public_server_software, | ||
software_type=public_instance_type, | ||
partition_reference=public_instance_title, | ||
state='<marshal><string>destroyed</string></marshal>', | ||
project_reference=project.getReference() | ||
) | ||
# let's find instances of user and check connection strings | ||
instance_tree_list = [q.getObject() for q in | ||
self._getCurrentInstanceTreeList() | ||
if q.getTitle() == public_instance_title] | ||
self.assertEqual(0, len(instance_tree_list)) | ||
self.tic() | ||
subscription_request = self.checkServiceSubscriptionRequest(instance_tree, 'cancelled') | ||
# and uninstall some software on them | ||
self.logout() | ||
self.login(owner_person.getUserId()) | ||
self.supplySoftware(public_server, public_server_software, | ||
state='destroyed') | ||
self.logout() | ||
# Uninstall from compute_node | ||
self.login() | ||
self.simulateSlapgridSR(public_server) | ||
self.tic() | ||
# Check stock | ||
# Instance was celled before generate simulation | ||
inventory_list = self.portal.portal_simulation.getCurrentInventoryList(**{ | ||
'group_by_section': False, | ||
'group_by_node': True, | ||
'group_by_variation': True, | ||
'resource_uid': software_product.getUid(), | ||
'node_uid': public_person.getUid(), | ||
'project_uid': None, | ||
'ledger_uid': self.portal.portal_categories.ledger.automated.getUid() | ||
}) | ||
assert len(inventory_list) == 0, len(inventory_list) | ||
# Check accounting | ||
transaction_list = self.portal.account_module.receivable.Account_getAccountingTransactionList( | ||
mirror_section_uid=public_person.getUid()) | ||
assert len(transaction_list) == 0, len(transaction_list) | ||
self.login() | ||
# Ensure no unexpected object has been created | ||
# 2 accounting transaction / line | ||
# 3 allocation supply / line / cell | ||
# 1 compute node | ||
# 2 credential request | ||
# 2 event | ||
# 1 instance tree | ||
# 3 open sale order / line | ||
# 5 (can reduce to 2) assignment | ||
# 16 simulation mvt | ||
# 3 packing list / line | ||
# 3 sale supply / line | ||
# 2 sale trade condition | ||
# 1 software installation | ||
# 1 software instance | ||
# 1 software product | ||
# 3 subscription requests | ||
self.assertRelatedObjectCount(project, 48) | ||
self.checkERP5StateBeforeExit() |