Commit 276c46f8 authored by Romain Courteaud's avatar Romain Courteaud

slapos_subscription_request: drop outdated subscription scenarios

parent 371645ab
# -*- coding:utf-8 -*-
##############################################################################
#
# Copyright (c) 2019 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
from erp5.component.test.testSlapOSSubscriptionCDNScenario import TestSlapOSSubscriptionCDNScenarioMixin
from erp5.component.test.SlapOSTestCaseMixin import changeSkin
class TestSlapOSSubscriptionChineseCDNScenarioMixin(TestSlapOSSubscriptionCDNScenarioMixin):
def afterSetUp(self):
self.expected_slapos_organisation = self.expected_zh_slapos_organisation
TestSlapOSSubscriptionCDNScenarioMixin.afterSetUp(self)
self.expected_price_currency = "currency_module/CNY"
self.normal_user = None
self.expected_notification_language = "zh"
self.login()
@changeSkin('Hal')
def _requestSubscription(self, **kw):
return self._requestSubscriptionViaChineseWebsite(**kw)
def createSubscriptionCondition(self, slave=False):
self.subscription_condition = self.createChineseSubscriptionCondition(
slave=slave)
class TestSlapOSSubscriptionCDNChineseScenario(TestSlapOSSubscriptionChineseCDNScenarioMixin):
def test_subscription_scenario_with_single_vm(self):
self._test_subscription_scenario(amount=1)
def test_subscription_with_3_vms_scenario(self):
self._test_subscription_scenario(amount=3)
def test_subscription_scenario_with_reversal_transaction(self):
self._test_subscription_scenario_with_reversal_transaction(amount=1)
def test_two_subscription_scenario(self):
self._test_two_subscription_scenario(amount=1)
def test_subscription_scenario_with_existing_user(self):
self._test_subscription_scenario_with_existing_user(amount=1, language="zh")
def test_subscription_scenario_with_existing_user_with_non_subscription_request(self):
self._test_subscription_scenario_with_existing_user_with_non_subscription_request(amount=1, language="en")
def test_subscription_scenario_with_existing_english_user(self):
# Messages are in chinese, when subscribed via chinese website. Even if the english language is
# english
self._test_subscription_scenario_with_existing_user(amount=1, language="en")
<?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>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>testSlapOSSubscriptionCDNChineseScenario</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.testSlapOSSubscriptionCDNChineseScenario</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">AAAAAAAAAAM=</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/>
</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>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<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>
# -*- coding:utf-8 -*-
##############################################################################
#
# Copyright (c) 2019 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
from erp5.component.test.testSlapOSSubscriptionScenario import TestSlapOSSubscriptionScenarioMixin
class TestSlapOSSubscriptionCDNScenarioMixin(TestSlapOSSubscriptionScenarioMixin):
def afterSetUp(self):
TestSlapOSSubscriptionScenarioMixin.afterSetUp(self)
self.expected_individual_price_without_tax = 5
self.expected_individual_price_with_tax = 6.0
self.expected_reservation_fee = 1.2
self.expected_reservation_fee_without_tax = 1
self.expected_reservation_quantity_tax = 1.0
self.expected_reservation_tax = 0.2
self.expected_price_currency = "currency_module/EUR"
self.expected_zh_individual_price_without_tax = 40
self.expected_zh_individual_price_with_tax = 40
self.expected_zh_reservation_fee = 8.0
self.expected_zh_reservation_fee_without_tax = 8.0
self.expected_zh_reservation_quantity_tax = 8.0
self.expected_zh_reservation_tax = 0
self.resource_variation_reference = "CDN"
self.login()
# Overwrite default Subscription Condition.
self.createSubscriptionCondition(slave=True)
# some preparation
self.logout()
def createPublicServerForAdminUser(self):
subscription_server = TestSlapOSSubscriptionScenarioMixin.createPublicServerForAdminUser(self)
self.login()
contract = self.admin_user.Person_generateCloudContract(batch=True)
if contract.getValidationState() in ["draft", "invalidated"]:
contract.validate()
self.tic()
# now instantiate it on compute_node and set some nice connection dict
self.setServerOpenPublic(subscription_server)
self.login(self.admin_user.getUserId())
self.personRequestInstanceNotReady(
software_release=self.subscription_condition.getUrlString(),
software_type=self.subscription_condition.getSourceReference(),
partition_reference="InstanceForSlave%s" % self.new_id,
project_reference=self.subscription_project.getReference()
)
self.stepCallSlaposAllocateInstanceAlarm()
self.tic()
self.personRequestInstance(
software_release=self.subscription_condition.getUrlString(),
software_type=self.subscription_condition.getSourceReference(),
partition_reference="InstanceForSlave%s" % self.new_id,
project_reference=self.subscription_project.getReference()
)
# now instantiate it on compute_node and set some nice connection dict
self.simulateSlapgridCP(subscription_server)
self.tic()
self.login()
#self.setServerOpenSubscription(subscription_server)
self.setAccessToMemcached(subscription_server)
self.tic()
self.simulateSlapgridCP(subscription_server)
self.logout()
return subscription_server
class TestSlapOSSubscriptionCDNScenario(TestSlapOSSubscriptionCDNScenarioMixin):
def test_subscription_scenario_with_single_vm(self):
self._test_subscription_scenario(amount=1)
def test_subscription_with_3_vms_scenario(self):
self._test_subscription_scenario(amount=3)
def test_subscription_scenario_with_reversal_transaction(self):
self._test_subscription_scenario_with_reversal_transaction(amount=1)
def test_two_subscription_scenario(self):
self._test_two_subscription_scenario(amount=1)
def test_subscription_scenario_with_existing_user(self):
self._test_subscription_scenario_with_existing_user(amount=1, language="zh")
def test_subscription_scenario_with_existing_user_with_non_subscription_request(self):
self._test_subscription_scenario_with_existing_user_with_non_subscription_request(amount=1, language="en")
def test_subscription_scenario_with_existing_chinese_user(self):
# Messages are in chinese, when subscribed via chinese website. Even if the english language is
# english
self._test_subscription_scenario_with_existing_user(amount=1, language="zh")
<?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>testSlapOSSubscriptionCDNScenario</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.testSlapOSSubscriptionCDNScenario</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>
# -*- coding:utf-8 -*-
##############################################################################
#
# Copyright (c) 2019 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
from erp5.component.test.testSlapOSSubscriptionScenario import TestSlapOSSubscriptionScenarioMixin
#from erp5.component.test.SlapOSTestCaseMixin import changeSkin
class TestSlapOSSubscriptionCancellationScenario(TestSlapOSSubscriptionScenarioMixin):
def invokeBasicSimulationAlarmList(self):
# stabilise aggregated invoices and expand them
self.stepCallSlaposManageBuildingCalculatingDeliveryAlarm()
self.tic()
# update invoices with their tax & discount
self.stepCallSlaposTriggerBuildAlarm()
self.tic()
self.stepCallSlaposManageBuildingCalculatingDeliveryAlarm()
self.tic()
# update invoices with their tax & discount transaction lines
self.stepCallSlaposTriggerBuildAlarm()
self.tic()
self.stepCallSlaposManageBuildingCalculatingDeliveryAlarm()
self.tic()
# stop the invoices and solve them again
self.stepCallSlaposStopConfirmedAggregatedSaleInvoiceTransactionAlarm()
self.tic()
self.stepCallSlaposManageBuildingCalculatingDeliveryAlarm()
self.tic()
def test_subscription_scenario_reservation_cancellation_scenario(self):
self.subscription_server = self.createPublicServerForAdminUser()
# Call as anonymous... check response?
default_email_text = "abc%s@nexedi.com" % self.new_id
name="ABC %s" % self.new_id
amount = 1
self.logout()
user_input_dict = {
"name": name,
"amount" : amount}
self._requestSubscription(
subscription_reference=self.subscription_condition.getReference(),
user_input_dict=user_input_dict,
email=default_email_text,
confirmation_required=False)
self.login()
# I'm not sure if this is realistic
self.tic()
subscription_request = self.getSubscriptionRequest(
default_email_text, self.subscription_condition)
self.checkDraftSubscriptionRequest(subscription_request,
default_email_text, self.subscription_condition, amount=amount)
### Here all fine, Now let's consider the user never payed.
invoice = subscription_request.getCausalityValue(
portal_type="Sale Invoice Transaction")
self.assertEqual(invoice.getSimulationState(), "confirmed")
self.assertEqual(invoice.getCausalityState(), "building")
# Invoices are not payed!
payment_list = invoice.getCausalityRelatedValueList(portal_type="Payment Transaction")
self.assertEqual(len(payment_list), 1)
payment = payment_list[0]
self.assertEqual(payment.getSimulationState(), "started")
self.assertEqual(subscription_request.getSimulationState(), "draft")
self.invokeBasicSimulationAlarmList()
payment.cancel()
self.invokeBasicSimulationAlarmList()
# Call alarm to check payment and invoice and move foward to planned.
self.stepCallSlaposSubscriptionRequestProcessDraftAlarm()
self.tic()
payment_list = invoice.getCausalityRelatedValueList(portal_type="Payment Transaction")
self.assertEqual(len(payment_list), 1)
payment = payment_list[0]
self.assertEqual(payment.getSimulationState(), "cancelled")
# Alarm is conflicting
self.assertEqual(subscription_request.getSimulationState(), "cancelled")
def test_subscription_scenario_reservation_cancellation_late_alarm_scenario(self):
self.subscription_server = self.createPublicServerForAdminUser()
# Call as anonymous... check response?
default_email_text = "abc%s@nexedi.com" % self.new_id
name="ABC %s" % self.new_id
amount = 1
self.logout()
user_input_dict = {
"name": name,
"amount" : amount}
self._requestSubscription(
subscription_reference=self.subscription_condition.getReference(),
user_input_dict=user_input_dict,
email=default_email_text,
confirmation_required=False)
self.login()
# I'm not sure if this is realistic
self.tic()
subscription_request = self.getSubscriptionRequest(
default_email_text, self.subscription_condition)
self.checkDraftSubscriptionRequest(subscription_request,
default_email_text, self.subscription_condition, amount=amount)
### Here all fine, Now let's consider the user never payed.
invoice = subscription_request.getCausalityValue(
portal_type="Sale Invoice Transaction")
self.assertEqual(invoice.getSimulationState(), "confirmed")
self.assertEqual(invoice.getCausalityState(), "building")
# Invoices are not payed!
payment_list = invoice.getCausalityRelatedValueList(portal_type="Payment Transaction")
self.assertEqual(len(payment_list), 1)
payment = payment_list[0]
self.assertEqual(payment.getSimulationState(), "started")
self.assertEqual(subscription_request.getSimulationState(), "draft")
self.invokeBasicSimulationAlarmList()
# stop the invoices and solve them again
self.stepCallSlaposStopConfirmedAggregatedSaleInvoiceTransactionAlarm()
self.tic()
self.stepCallSlaposManageBuildingCalculatingDeliveryAlarm()
self.tic()
self.invokeBasicSimulationAlarmList()
self.assertEqual(invoice.getSimulationState(), "stopped")
self.assertEqual(invoice.getCausalityState(), "solved")
self.assertEqual(payment.getSimulationState(), "started")
# Cancel Payment and ensure all is cancelled along
payment.cancel()
self.assertEqual(payment.getSimulationState(), "cancelled")
self.tic()
self.assertEqual(invoice.getSimulationState(), "stopped")
self.assertEqual(invoice.getCausalityState(), "solved")
self.invokeBasicSimulationAlarmList()
# Call alarm to check payment and invoice and move foward to planned.
self.stepCallSlaposSubscriptionRequestProcessDraftAlarm()
self.tic()
payment_list = invoice.getCausalityRelatedValueList(portal_type="Payment Transaction")
self.assertEqual(len(payment_list), 1)
payment = payment_list[0]
self.assertEqual(payment.getSimulationState(), "cancelled")
self.assertEqual(invoice.getSimulationState(), "cancelled")
# Alarm is conflicting
self.assertEqual(subscription_request.getSimulationState(), "cancelled")
<?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>testSlapOSSubscriptionCancellationScenario</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.testSlapOSSubscriptionCancellationScenario</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>
# -*- coding:utf-8 -*-
##############################################################################
#
# Copyright (c) 2019 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
from erp5.component.test.testSlapOSSubscriptionScenario import TestSlapOSSubscriptionScenarioMixin
from erp5.component.test.SlapOSTestCaseMixin import changeSkin
class TestSlapOSSubscriptionChineseScenarioMixin(TestSlapOSSubscriptionScenarioMixin):
def afterSetUp(self):
self.expected_slapos_organisation = self.expected_zh_slapos_organisation
TestSlapOSSubscriptionScenarioMixin.afterSetUp(self)
self.expected_price_currency = "currency_module/CNY"
self.normal_user = None
self.expected_notification_language = "zh"
self.login()
@changeSkin('Hal')
def _requestSubscription(self, **kw):
return self._requestSubscriptionViaChineseWebsite(**kw)
def createSubscriptionCondition(self, slave=False):
self.subscription_condition = self.createChineseSubscriptionCondition(
slave=slave)
class TestSlapOSSubscriptionChineseScenario(TestSlapOSSubscriptionChineseScenarioMixin):
def test_subscription_scenario_with_single_vm(self):
self._test_subscription_scenario(amount=1)
def test_subscription_with_3_vms_scenario(self):
self._test_subscription_scenario(amount=3)
def test_subscription_scenario_with_reversal_transaction(self):
self._test_subscription_scenario_with_reversal_transaction(amount=1)
def test_two_subscription_scenario(self):
self._test_two_subscription_scenario(amount=1)
def test_subscription_scenario_with_existing_user(self):
self._test_subscription_scenario_with_existing_user(amount=1, language="zh")
def test_subscription_scenario_with_existing_user_with_non_subscription_request(self):
self._test_subscription_scenario_with_existing_user_with_non_subscription_request(amount=1, language="en")
def test_subscription_scenario_with_existing_english_user(self):
# Messages are in chinese, when subscribed via chinese website. Even if the english language is
# english
self._test_subscription_scenario_with_existing_user(amount=1, language="en")
<?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>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>testSlapOSSubscriptionChineseScenario</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>test.erp5.testSlapOSSubscriptionChineseScenario</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">AAAAAAAAAAM=</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/>
</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>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<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>
# -*- coding:utf-8 -*-
##############################################################################
#
# Copyright (c) 2019 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
from erp5.component.test.testSlapOSSubscriptionScenario import TestSlapOSSubscriptionScenarioMixin
class testSlapOSSubscriptionDualOrganisationScenario(TestSlapOSSubscriptionScenarioMixin):
def afterSetUp(self):
TestSlapOSSubscriptionScenarioMixin.afterSetUp(self)
fr_organisation, zh_organisation = self.redefineAccountingTemplatesonPreferencesWithDualOrganisation()
self.expected_source = fr_organisation.getRelativeUrl()
self.expected_source_section = fr_organisation.getRelativeUrl()
self.expected_zh_reservation_fee = 188.00
self.subscription_condition.getSpecialiseValue().edit(
source=self.expected_source,
source_section=self.expected_source_section,
source_payment=self.expected_source_section + '/bank_account',
)
self.subscription_condition_zh = self.createChineseSubscriptionCondition()
self.expected_zh_source = zh_organisation.getRelativeUrl()
self.expected_zh_source_section = zh_organisation.getRelativeUrl()
self.subscription_condition_zh.getSpecialiseValue().edit(
source=self.expected_zh_source,
source_section=self.expected_zh_source_section,
source_payment=self.expected_zh_source_section + '/bank_account',
)
self.portal.portal_caches.clearAllCache()
self.tic()
def beforeTearDown(self):
TestSlapOSSubscriptionScenarioMixin.beforeTearDown(self)
self.restoreAccountingTemplatesOnPreferences()
self.portal.portal_caches.clearAllCache()
self.tic()
def requestAndCheckDualInstanceTree(self, amount, name,
default_email_text, language_list):
self.logout()
user_input_dict = {
"name": name,
"amount" : amount}
request_kw = dict(
subscription_reference=self.subscription_condition.getReference(),
user_input_dict=user_input_dict,
email=default_email_text,
confirmation_required=False)
all_subscription_requested_list = []
for language in language_list:
if language == "zh":
self._requestSubscriptionViaChineseWebsite(**request_kw)
subscription_condition = self.subscription_condition_zh
expected_price_currency = "currency_module/CNY"
expected_source_section = self.expected_zh_source_section
else:
self._requestSubscription(**request_kw)
subscription_condition = self.subscription_condition
expected_price_currency = "currency_module/EUR"
expected_source_section = self.expected_source_section
self.login()
# I'm not sure if this is realistic
self.tic()
subscription_request_list = self.getSubscriptionRequestList(
default_email_text, subscription_condition)
for subscription_request in subscription_request_list:
self.assertEqual(language,
subscription_request.getLanguage())
trade_condition = subscription_request.getSpecialiseValue().getSpecialiseValue()
self.assertEqual(expected_price_currency,
trade_condition.getPriceCurrency())
self.assertEqual(expected_source_section,
trade_condition.getSourceSection())
self.checkDraftSubscriptionRequest(subscription_request,
default_email_text,
subscription_request.getSpecialiseValue(),
amount=amount)
self.tic()
if subscription_request not in all_subscription_requested_list:
all_subscription_requested_list.append(subscription_request)
self.checkAndPaySubscriptionPayment(all_subscription_requested_list)
self.tic()
# Call alarm to check payment and invoice and move foward to planned.
self.stepCallSlaposSubscriptionRequestProcessDraftAlarm()
self.tic()
for subscription_request in all_subscription_requested_list:
self.checkPlannedSubscriptionRequest(subscription_request,
default_email_text,
subscription_request.getSpecialiseValue())
# Call alarm to mark subscription request as ordered, bootstrap the user
# and check if email is sent, once done move to ordered state.
self.stepCallSlaposSubscriptionRequestProcessPlannedAlarm()
self.tic()
for subscription_request in all_subscription_requested_list:
self.checkOrderedSubscriptionRequest(subscription_request,
default_email_text,
subscription_request.getSpecialiseValue())
# Call alarm to make the request of the instance?
self.stepCallSlaposSubscriptionRequestProcessOrderedAlarm()
self.tic()
# The alarms might be called multiple times for move each step
self.stepCallSlaposSubscriptionRequestProcessOrderedAlarm()
self.tic()
for subscription_request in all_subscription_requested_list:
sale_packing_list_list = self.portal.portal_catalog(
causality_uid = subscription_request.getUid(),
title="Reservation Deduction",
portal_type="Sale Packing List"
)
self.assertEqual(len(sale_packing_list_list), 1)
sale_packing_list = sale_packing_list_list[0]
trade_condition = subscription_request.getSpecialiseValue().getSpecialiseValue()
self.assertEqual(sale_packing_list.getPriceCurrency(),
trade_condition.getPriceCurrency())
self.assertEqual(sale_packing_list.getSpecialise(),
"sale_trade_condition_module/slapos_reservation_refund_trade_condition")
if trade_condition.getPriceCurrency() == "currency_module/CNY":
expected_reservation_fee = self.expected_zh_reservation_fee_without_tax
else:
expected_reservation_fee = self.expected_reservation_fee_without_tax
self.assertEqual(round(sale_packing_list.getTotalPrice(), 2),
-round(expected_reservation_fee*amount, 2))
return all_subscription_requested_list
def _test_subscription_scenario_with_dual_organisation(self, language_list, amount=1, language="en"):
# Call as anonymous... check response?
default_email_text = "abc%s@nexedi.com" % self.new_id
name="ABC %s" % self.new_id
self.login()
self.createNormalUser(default_email_text, name, language, self.subscription_project)
self.tic()
self.subscription_server = self.createPublicServerForAdminUser()
self.login()
# Extra software from zh version
subscription_server_software = self.subscription_condition_zh.getUrlString()
self.supplySoftware(self.subscription_server, subscription_server_software)
self.tic()
self.logout()
subscription_request_list = self.requestAndCheckDualInstanceTree(
amount, name, default_email_text, language_list=language_list)
self._checkSubscriptionDeploymentAndSimulation(
subscription_request_list, default_email_text,
self.subscription_server)
if not self.expected_free_reservation:
for subscription_request in subscription_request_list:
trade_condition = subscription_request.getSpecialiseValue().getSpecialiseValue()
if trade_condition.getPriceCurrency() == "currency_module/CNY":
self.checkAndPayFirstMonthViaWechat(subscription_request)
else:
self.checkAndPayFirstMonth(subscription_request)
self.tic()
self.stepCallSlaposSubscriptionRequestProcessConfirmedAlarm()
self.tic()
for subscription_request in subscription_request_list:
self.assertTrue(
subscription_request.SubscriptionRequest_testPaymentBalance())
self.assertEqual('start_requested',
subscription_request.getAggregateValue().getSlapState())
# On the second loop that email is send and state is moved to started
self.stepCallSlaposSubscriptionRequestProcessConfirmedAlarm()
self.tic()
for subscription_request in subscription_request_list:
self.assertTrue(
subscription_request.SubscriptionRequest_testPaymentBalance())
self.assertEqual('start_requested',
subscription_request.getAggregateValue().getSlapState())
self.checkStartedSubscriptionRequest(subscription_request,
default_email_text,
subscription_request.getSpecialiseValue())
for subscription_request in subscription_request_list:
self.assertEqual(self.normal_user,
subscription_request.getDestinationSectionValue())
if self.skip_destroy_and_check:
return
for subscription_request in subscription_request_list:
self.assertEqual('start_requested',
subscription_request.getAggregateValue().getSlapState())
# Destroy all instances and process
instance_tree = subscription_request.getAggregateValue()
instance_tree.InstanceTree_requestPerson('destroyed')
self.tic()
self.stepCallSlaposSubscriptionRequestProcessStartedAlarm()
self.tic()
self.checkStoppedSubscriptionRequest(subscription_request,
default_email_text,
subscription_request.getSpecialiseValue())
return default_email_text, name
def test_subscription_scenario_with_dual_organisation_en(self):
self._test_subscription_scenario_with_dual_organisation(["en", "zh", "en"], amount=1, language="en")
def test_subscription_scenario_with_dual_organisation_zh(self):
self._test_subscription_scenario_with_dual_organisation(["en", "zh", "zh"], amount=1, language="zh")
def test_subscription_scenario_with_dual_organisation_en_2(self):
self._test_subscription_scenario_with_dual_organisation(["en", "zh"], amount=2, language="en")
def test_subscription_scenario_with_dual_organisation_zh_2(self):
self._test_subscription_scenario_with_dual_organisation(["en", "zh"], amount=2, language="zh")
def test_subscription_scenario_with_dual_organisation_en_only(self):
self._test_subscription_scenario_with_dual_organisation(["en", "en", "en"], amount=1, language="en")
def test_subscription_scenario_with_dual_organisation_zh_only(self):
self._test_subscription_scenario_with_dual_organisation(["zh", "zh", "zh"], amount=1, language="zh")
<?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>testSlapOSSubscriptionDualOrganisationScenario</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.testSlapOSSubscriptionDualOrganisationScenario</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>
# -*- coding:utf-8 -*-
##############################################################################
#
# Copyright (c) 2019 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
from erp5.component.test.testSlapOSSubscriptionChineseScenario import TestSlapOSSubscriptionChineseScenarioMixin
class testSlapOSSubscriptionCloudInvitationTokenScenario(TestSlapOSSubscriptionChineseScenarioMixin):
def test_subscription_scenario_with_single_vm_and_empty_invitation(self):
self.cloud_invitation_token = self.makeCloudInvitationToken()
self._test_subscription_scenario(amount=1)
def test_subscription_with_3_vms_scenario_and_empty_invitation(self):
self.cloud_invitation_token = self.makeCloudInvitationToken()
self._test_subscription_scenario(amount=3)
def test_subscription_scenario_with_reversal_transaction_and_empty_invitation(self):
self.cloud_invitation_token = self.makeCloudInvitationToken()
self._test_subscription_scenario_with_reversal_transaction(amount=1)
def test_two_subscription_scenario_and_empty_invitation(self):
self._test_two_subscription_scenario(amount=1)
def test_subscription_scenario_with_existing_user_and_empty_invitation(self):
self.cloud_invitation_token = self.makeCloudInvitationToken()
self._test_subscription_scenario_with_existing_user(amount=1, language="zh")
def test_subscription_scenario_with_existing_user_with_non_subscription_request_with_empty_invitation(self):
self.cloud_invitation_token = self.makeCloudInvitationToken()
self._test_subscription_scenario_with_existing_user_with_non_subscription_request(amount=1, language="en")
def test_subscription_scenario_with_existing_english_user_and_empty_invitation(self):
self.cloud_invitation_token = self.makeCloudInvitationToken()
self._test_subscription_scenario_with_existing_user(amount=1, language="en")
def _init_test_with_valid_invitation(self):
self.expected_reservation_fee = 0.0
self.expected_reservation_fee_without_tax = 0.0
self.expected_reservation_quantity_tax = 0.0
self.expected_reservation_tax = 0.0
self.expected_free_reservation = 1
self.expected_zh_reservation_fee = 0.0
self.expected_zh_reservation_fee_without_tax = 0.0
self.expected_zh_reservation_quantity_tax = 0.0
self.expected_zh_reservation_tax = 0.0
self.expected_zh_free_reservation = 1
self.cloud_invitation_token = self.makeCloudInvitationToken(
max_invoice_delay=99,
max_invoice_credit_eur=900,
max_invoice_credit_cny=90000)
def test_subscription_scenario_with_single_vm_with_invitation(self):
self._init_test_with_valid_invitation()
self._test_subscription_scenario(amount=1)
def test_subscription_with_3_vms_scenario_with_invitation(self):
self._init_test_with_valid_invitation()
self._test_subscription_scenario(amount=3)
def test_subscription_scenario_with_reversal_transaction_with_invitation(self):
self._init_test_with_valid_invitation()
self._test_subscription_scenario_with_reversal_transaction(amount=1)
def test_two_subscription_scenario_with_invitation(self):
self.expected_reservation_fee = 0.0
self.expected_reservation_fee_without_tax = 0.0
self.expected_reservation_quantity_tax = 0.0
self.expected_reservation_tax = 0.0
self.expected_free_reservation = 1
self.expected_zh_reservation_fee = 0.0
self.expected_zh_reservation_fee_without_tax = 0.0
self.expected_zh_reservation_quantity_tax = 0.0
self.expected_zh_reservation_tax = 0.0
self.expected_zh_free_reservation = 1
self._test_two_subscription_scenario(amount=1,
create_invitation=True,
max_invoice_delay=99,
max_invoice_credit_eur=900,
max_invoice_credit_cny=90000
)
def test_subscription_scenario_with_existing_user_with_invitation(self):
self._init_test_with_valid_invitation()
self._test_subscription_scenario_with_existing_user(amount=1, language="zh")
def test_subscription_scenario_with_existing_english_user_with_invitation(self):
self._init_test_with_valid_invitation()
self._test_subscription_scenario_with_existing_user(amount=1, language="en")
def test_subscription_scenario_with_existing_user_with_non_subscription_request_with_token(self):
self._init_test_with_valid_invitation()
self._test_subscription_scenario_with_existing_user_with_non_subscription_request(amount=1, language="en")
<?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>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>testSlapOSSubscriptionInvitationTokenChineseScenario</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>test.erp5.testSlapOSSubscriptionInvitationTokenChineseScenario</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">AAAAAAAAAAM=</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/>
</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>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<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>
# -*- coding:utf-8 -*-
##############################################################################
#
# Copyright (c) 2019 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
from erp5.component.test.testSlapOSSubscriptionScenario import TestSlapOSSubscriptionScenarioMixin
class testSlapOSSubscriptionCloudInvitationTokenScenario(TestSlapOSSubscriptionScenarioMixin):
def test_subscription_scenario_with_single_vm_and_empty_invitation(self):
self.cloud_invitation_token = self.makeCloudInvitationToken()
self._test_subscription_scenario(amount=1)
def test_subscription_with_3_vms_scenario_and_empty_invitation(self):
self.cloud_invitation_token = self.makeCloudInvitationToken()
self._test_subscription_scenario(amount=3)
def test_subscription_scenario_with_reversal_transaction_and_empty_invitation(self):
self.cloud_invitation_token = self.makeCloudInvitationToken()
self._test_subscription_scenario_with_reversal_transaction(amount=1)
def test_two_subscription_scenario_and_empty_invitation(self):
self._test_two_subscription_scenario(amount=1)
def test_subscription_scenario_with_existing_user_and_empty_invitation(self):
self.cloud_invitation_token = self.makeCloudInvitationToken()
self._test_subscription_scenario_with_existing_user(amount=1, language="zh")
def test_subscription_scenario_with_existing_user_with_non_subscription_request_with_empty_invitation(self):
self.cloud_invitation_token = self.makeCloudInvitationToken()
self._test_subscription_scenario_with_existing_user_with_non_subscription_request(amount=1, language="en")
def test_subscription_scenario_with_existing_english_user_and_empty_invitation(self):
self.cloud_invitation_token = self.makeCloudInvitationToken()
self._test_subscription_scenario_with_existing_user(amount=1, language="en")
def _init_test_with_valid_invitation(self):
self.expected_reservation_fee_without_tax = 0.0
self.expected_reservation_fee = 0.0
self.expected_reservation_quantity_tax = 0.0
self.expected_reservation_tax = 0.0
self.expected_free_reservation = 1
self.cloud_invitation_token = self.makeCloudInvitationToken(
max_invoice_delay=99,
max_invoice_credit_eur=900,
max_invoice_credit_cny=900)
def test_subscription_scenario_with_single_vm_with_invitation(self):
self._init_test_with_valid_invitation()
self._test_subscription_scenario(amount=1)
def test_subscription_with_3_vms_scenario_with_invitation(self):
self._init_test_with_valid_invitation()
self._test_subscription_scenario(amount=3)
def test_subscription_scenario_with_reversal_transaction_with_invitation(self):
self._init_test_with_valid_invitation()
self._test_subscription_scenario_with_reversal_transaction(amount=1)
def test_two_subscription_scenario_with_invitation(self):
self.expected_reservation_fee_without_tax = 0.0
self.expected_reservation_fee = 0.0
self.expected_reservation_quantity_tax = 0.0
self.expected_reservation_tax = 0.0
self.expected_free_reservation = 1
self._test_two_subscription_scenario(amount=1,
create_invitation=True,
max_invoice_delay=99,
max_invoice_credit_eur=900,
max_invoice_credit_cny=900
)
def test_subscription_scenario_with_existing_user_with_invitation(self):
self._init_test_with_valid_invitation()
self._test_subscription_scenario_with_existing_user(amount=1, language="zh")
def test_subscription_scenario_with_existing_english_user_with_invitation(self):
self._init_test_with_valid_invitation()
self._test_subscription_scenario_with_existing_user(amount=1, language="en")
def test_subscription_scenario_with_existing_user_with_non_subscription_request_with_token(self):
self._init_test_with_valid_invitation()
self._test_subscription_scenario_with_existing_user_with_non_subscription_request(amount=1, language="en")
<?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>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>testSlapOSSubscriptionInvitationTokenScenario</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>test.erp5.testSlapOSSubscriptionInvitationTokenScenario</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">AAAAAAAAAAM=</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/>
</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>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<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>
# -*- coding:utf-8 -*-
##############################################################################
#
# Copyright (c) 2019 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
from erp5.component.test.testSlapOSSubscriptionChineseScenario import TestSlapOSSubscriptionChineseScenarioMixin
class testSlapOSSubscriptionNewTemplateChineseScenario(TestSlapOSSubscriptionChineseScenarioMixin):
def afterSetUp(self):
TestSlapOSSubscriptionChineseScenarioMixin.afterSetUp(self)
organisation = self.redefineAccountingTemplatesonPreferences(
price_currency="currency_module/CNY")
self.expected_source = organisation.getRelativeUrl()
self.expected_source_section = organisation.getRelativeUrl()
self.subscription_condition.getSpecialiseValue().edit(
source=self.expected_source,
source_section=self.expected_source_section,
source_payment=self.expected_source_section + '/bank_account',
)
self.portal.portal_caches.clearAllCache()
self.tic()
def beforeTearDown(self):
TestSlapOSSubscriptionChineseScenarioMixin.beforeTearDown(self)
self.restoreAccountingTemplatesOnPreferences()
self.portal.portal_caches.clearAllCache()
self.tic()
def test_subscription_scenario_with_single_vm(self):
self._test_subscription_scenario(amount=1)
def test_subscription_with_3_vms_scenario(self):
self._test_subscription_scenario(amount=3)
def test_subscription_scenario_with_reversal_transaction(self):
self._test_subscription_scenario_with_reversal_transaction(amount=1)
def test_two_subscription_scenario(self):
self._test_two_subscription_scenario(amount=1)
def test_subscription_scenario_with_existing_user(self):
self._test_subscription_scenario_with_existing_user(amount=1, language="zh")
def test_subscription_scenario_with_existing_user_with_non_subscription_request(self):
self._test_subscription_scenario_with_existing_user_with_non_subscription_request(amount=1, language="zh")
def test_subscription_scenario_with_existing_english_user(self):
# Messages are in chinese, when subscribed via chinese website. Even if the english language is
# english
self._test_subscription_scenario_with_existing_user(amount=1, language="en")
\ No newline at end of file
<?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>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>testSlapOSSubscriptionNewTemplateChineseScenario</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>test.erp5.testSlapOSSubscriptionNewTemplateChineseScenario</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">AAAAAAAAAAM=</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/>
</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>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<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>
# -*- coding:utf-8 -*-
##############################################################################
#
# Copyright (c) 2019 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
from erp5.component.test.testSlapOSSubscriptionScenario import TestSlapOSSubscriptionScenarioMixin
class testSlapOSSubscriptionNewTemplateScenario(TestSlapOSSubscriptionScenarioMixin):
def afterSetUp(self):
TestSlapOSSubscriptionScenarioMixin.afterSetUp(self)
organisation = self.redefineAccountingTemplatesonPreferences()
self.expected_source = organisation.getRelativeUrl()
self.expected_source_section = organisation.getRelativeUrl()
self.subscription_condition.getSpecialiseValue().edit(
source=self.expected_source,
source_section=self.expected_source_section,
source_payment=self.expected_source_section + '/bank_account',
)
self.portal.portal_caches.clearAllCache()
self.tic()
def beforeTearDown(self):
TestSlapOSSubscriptionScenarioMixin.beforeTearDown(self)
self.restoreAccountingTemplatesOnPreferences()
self.portal.portal_caches.clearAllCache()
self.tic()
def test_subscription_scenario_with_single_vm(self):
self._test_subscription_scenario(amount=1)
def test_subscription_with_3_vms_scenario(self):
self._test_subscription_scenario(amount=3)
def test_subscription_scenario_with_reversal_transaction(self):
self._test_subscription_scenario_with_reversal_transaction(amount=1)
def test_two_subscription_scenario(self):
self._test_two_subscription_scenario(amount=1)
def test_subscription_scenario_with_existing_user(self):
self._test_subscription_scenario_with_existing_user(amount=1, language="zh")
def test_subscription_scenario_with_existing_user_with_non_subscription_request(self):
self._test_subscription_scenario_with_existing_user_with_non_subscription_request(amount=1, language="zh")
def test_subscription_scenario_with_existing_english_user(self):
# Messages are in chinese, when subscribed via chinese website. Even if the english language is
# english
self._test_subscription_scenario_with_existing_user(amount=1, language="en")
<?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>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>testSlapOSSubscriptionNewTemplateScenario</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>test.erp5.testSlapOSSubscriptionNewTemplateScenario</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">AAAAAAAAAAM=</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/>
</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>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<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>
# -*- coding:utf-8 -*-
##############################################################################
#
# Copyright (c) 2019 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
from erp5.component.test.testSlapOSSubscriptionScenario import TestSlapOSSubscriptionScenarioMixin
class testSlapOSSubscriptionPerUserTradeConditionScenario(TestSlapOSSubscriptionScenarioMixin):
def createCustomUserSaleTradeCondition(self, person):
root_trade_condition = self.portal.portal_preferences.\
getPreferredAggregatedSubscriptionSaleTradeCondition()
root_trade_condition_value = self.portal.restrictedTraverse(
root_trade_condition)
user_trade_condition = root_trade_condition_value.\
Base_createCloneDocument(batch_mode=1)
user_trade_condition.manage_delObjects([x for x in
user_trade_condition.contentIds()])
user_trade_condition.edit(
title="TEST Trade Condition for %s" % person.getTitle(),
reference="%s_custom_%s" % (user_trade_condition.getReference(), user_trade_condition.getUid()),
destination_section_value=person,
specialise_value=self.subscription_condition.getSpecialiseValue(),
payment_mode='payzen',
price_currency_value=self.subscription_condition.getSpecialiseValue().getPriceCurrency(),
)
user_trade_condition.validate()
self.subscription_condition.edit(specialise_value=user_trade_condition)
return user_trade_condition
def _test_subscription_scenario_with_custom_condition(self, amount=1, language=None):
""" The admin creates an compute_node, user can request instances on it"""
# Call as anonymous... check response?
default_email_text = "abc%s@nexedi.com" % self.new_id
name="ABC %s" % self.new_id
self.login()
self.createNormalUser(default_email_text, name, language, self.subscription_project)
self.createCustomUserSaleTradeCondition(self.normal_user)
self.tic()
self.subscription_server = self.createPublicServerForAdminUser()
self.requestAndCheckInstanceTree(
amount, name, default_email_text)
self.checkSubscriptionDeploymentAndSimulation(
default_email_text, self.subscription_server)
subscription_request = self.getSubscriptionRequest(
default_email_text, self.subscription_condition)
self.assertEqual(self.normal_user,
subscription_request.getDestinationSectionValue())
self.destroyAndCheckSubscription(
default_email_text, self.subscription_server
)
return default_email_text, name
def test_custom_scenario(self):
self._test_subscription_scenario_with_custom_condition(amount=1, language="en")
class testSlapOSSubscriptionPerUserTradeConditionScenarioDetaxed(TestSlapOSSubscriptionScenarioMixin):
def afterSetUp(self):
TestSlapOSSubscriptionScenarioMixin.afterSetUp(self)
self.expected_individual_price_without_tax = 162.5
self.expected_individual_price_with_tax = 195
self.expected_reservation_fee = 25.00
self.expected_reservation_fee_without_tax = 20.83
self.expected_reservation_quantity_tax = 20.83
self.expected_reservation_tax = 4.17
def createDetaxedUserSaleTradeCondition(self, person):
root_trade_condition = self.portal.portal_preferences.\
getPreferredAggregatedSubscriptionSaleTradeCondition()
root_trade_condition_value = self.portal.restrictedTraverse(
root_trade_condition)
user_trade_condition = root_trade_condition_value.\
Base_createCloneDocument(batch_mode=1)
user_trade_condition.edit(
title="TEST Trade Condition for %s" % person.getTitle(),
reference="%s_detaxed_%s" % (user_trade_condition.getReference(), user_trade_condition.getUid()),
destination_section_value=person,
specialise_value=self.subscription_condition.getSpecialiseValue(),
payment_mode='payzen',
price_currency_value=self.subscription_condition.getSpecialiseValue().getPriceCurrency(),
)
user_trade_condition.manage_delObjects([x for x in
user_trade_condition.contentIds()])
user_trade_condition.newContent(
portal_type="Sale Supply Line",
base_price=self.expected_reservation_fee_without_tax,
resource='service_module/slapos_reservation_fee_2',
)
user_trade_condition.newContent(
portal_type="Sale Supply Line",
base_price=self.expected_individual_price_without_tax,
resource='service_module/slapos_instance_subscription',
)
user_trade_condition.validate()
self.subscription_condition.edit(specialise_value=user_trade_condition)
return user_trade_condition
def _test_subscription_scenario_with_detaxed_condition(self, amount=1, language=None):
""" The admin creates an compute_node, user can request instances on it"""
# Call as anonymous... check response?
default_email_text = "abc%s@nexedi.com" % self.new_id
name="ABC %s" % self.new_id
self.login()
self.createNormalUser(default_email_text, name, language, self.subscription_project)
self.createDetaxedUserSaleTradeCondition(self.normal_user)
self.tic()
self.subscription_server = self.createPublicServerForAdminUser()
self.requestAndCheckInstanceTree(
amount, name, default_email_text)
self.checkSubscriptionDeploymentAndSimulation(
default_email_text, self.subscription_server)
subscription_request = self.getSubscriptionRequest(
default_email_text, self.subscription_condition)
self.assertEqual(self.normal_user,
subscription_request.getDestinationSectionValue())
self.destroyAndCheckSubscription(
default_email_text, self.subscription_server
)
return default_email_text, name
def test_detaxed_scenario(self):
self._test_subscription_scenario_with_detaxed_condition(amount=1, language="en")
<?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>testSlapOSSubscriptionPerUserTradeConditionScenario</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.testSlapOSSubscriptionPerUserTradeConditionScenario</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>
# -*- coding:utf-8 -*-
##############################################################################
#
# Copyright (c) 2019 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
from erp5.component.test.SlapOSTestCaseDefaultScenarioMixin import DefaultScenarioMixin
from erp5.component.test.SlapOSTestCaseMixin import changeSkin
from Products.ERP5Type.tests.utils import createZODBPythonScript
from DateTime import DateTime
import datetime
class TestSlapOSSubscriptionScenarioMixin(DefaultScenarioMixin):
def afterSetUp(self):
self.unpinDateTime()
self.normal_user = None
# XXX TODO change price to ensure nothing is hardcoded
self.expected_individual_price_without_tax = 195
self.expected_individual_price_with_tax = 234
self.expected_reservation_fee = 30.00
self.expected_reservation_fee_without_tax = 25
self.expected_reservation_quantity_tax = 25
self.expected_reservation_tax = 5.0
self.expected_price_currency = "currency_module/EUR"
self.expected_zh_individual_price_without_tax = 1888
self.expected_zh_individual_price_with_tax = 1888
self.expected_zh_reservation_fee = 188.00
self.expected_zh_reservation_fee_without_tax = 188
self.expected_zh_reservation_quantity_tax = 188
self.expected_zh_reservation_tax = 1.88
# XXX TODO change source to ensure nothing is hardcoded
self.expected_notification_language = "en"
self.expected_source = self.expected_slapos_organisation
self.expected_source_section = self.expected_slapos_organisation
self.cloud_invitation_token = None
self.resource_variation_reference = None
self.expected_free_reservation = 0
self.non_subscription_related_instance_amount = 0
self.skip_destroy_and_check = 0
self.login()
self.portal.portal_alarms.slapos_subscription_request_process_draft.setEnabled(True)
self.portal.portal_alarms.slapos_subscription_request_process_ordered.setEnabled(True)
self.portal.portal_alarms.slapos_subscription_request_process_planned.setEnabled(True)
self.portal.portal_alarms.slapos_subscription_request_process_confirmed.setEnabled(True)
self.portal.portal_alarms.slapos_subscription_request_process_started.setEnabled(True)
DefaultScenarioMixin.afterSetUp(self)
self.portal.accounting_module.\
template_pre_payment_subscription_sale_invoice_transaction.\
updateLocalRolesOnSecurityGroups()
self.portal.accounting_module.\
slapos_pre_payment_template.\
updateLocalRolesOnSecurityGroups()
self.subscription_project = self.createProject()
# One user to create compute_nodes to deploy the subscription
self.createAdminUser(self.subscription_project)
self.cleanUpNotificationMessage()
self.portal.portal_catalog.searchAndActivate(
portal_type='Active Process',
method_id='ActiveProcess_deleteSelf')
self.tic()
self.createNotificationMessage("subscription_request-confirmation-with-password")
self.createNotificationMessage("subscription_request-confirmation-without-password",
text_content='${name} ${login_name}')
self.createNotificationMessage("subscription_request-instance-is-ready",
text_content='${name} ${subscription_title} ${instance_tree_relative_url}')
self.createNotificationMessage("subscription_request-payment-is-ready",
text_content='${name} ${subscription_title} ${payment_relative_relative_url}')
self.createNotificationMessage("subscription_request-confirmation-with-password", language="zh",
text_content='CHINESE! ${name} ${login_name} ${login_password}')
self.createNotificationMessage("subscription_request-confirmation-without-password", language="zh",
text_content='CHINESE! ${name} ${login_name}')
self.createNotificationMessage("subscription_request-instance-is-ready", language="zh",
text_content='CHINESE! ${name} ${subscription_title} ${instance_tree_relative_url}')
self.createNotificationMessage("subscription_request-payment-is-ready", language="zh",
text_content='CHINESE! ${name} ${subscription_title} ${payment_relative_relative_url}')
self.cleanUpSubscriptionRequest()
self.tic()
self.login()
self.createSubscriptionCondition()
# some preparation
self.logout()
self.web_site = self.portal.web_site_module.hostingjs
# The PaymentTransaction_getVADSUrlDict is required by the implementation
# wechat payments.
def _simulatePaymentTransaction_getVADSUrlDict(self):
script_name = 'PaymentTransaction_getVADSUrlDict'
if script_name in self.portal.portal_skins.custom.objectIds():
raise ValueError('Precondition failed: %s exists in custom' % script_name)
createZODBPythonScript(self.portal.portal_skins.custom,
script_name,
'*args, **kwargs',
'# Script body\n'
"""payment_transaction_url = context.getRelativeUrl()
return dict(vads_url_already_registered="%s/already_registered" % (payment_transaction_url),
vads_url_cancel="%s/cancel" % (payment_transaction_url),
vads_url_error="%s/error" % (payment_transaction_url),
vads_url_referral="%s/referral" % (payment_transaction_url),
vads_url_refused="%s/refused" % (payment_transaction_url),
vads_url_success="%s/success" % (payment_transaction_url),
vads_url_return="%s/return" % (payment_transaction_url),
)""")
def _dropPaymentTransaction_getVADSUrlDict(self):
script_name = 'PaymentTransaction_getVADSUrlDict'
if script_name in self.portal.portal_skins.custom.objectIds():
self.portal.portal_skins.custom.manage_delObjects(script_name)
def cleanUpSubscriptionRequest(self):
for subscription_request in self.portal.portal_catalog(
portal_type="Subscription Request",
simulation_state=["draft", "planned", "ordered", "confirmed"],
title="Test Subscription Request %"):
if subscription_request.getSimulationState() == "draft":
subscription_request.cancel()
if subscription_request.getSimulationState() == "planned":
subscription_request.order()
if subscription_request.getSimulationState() == "ordered":
subscription_request.confirm()
if subscription_request.getSimulationState() == "confirmed":
subscription_request.start()
if subscription_request.getSimulationState() == "started":
subscription_request.stop()
def cleanUpNotificationMessage(self):
for notification_message in self.portal.portal_catalog(
portal_type="Notification Message",
validation_state=["validated"],
title="TestSubscriptionSkins %"):
if str(notification_message.getVersion("")) == "999":
notification_message.invalidate()
def createNotificationMessage(self, reference,
content_type='text/html', language="en", text_content='${name} ${login_name} ${login_password}'):
notification_message = self.portal.notification_message_module.newContent(
portal_type="Notification Message",
text_content_substitution_mapping_method_id='NotificationMessage_getSubstitutionMappingDictFromArgument',
title='TestSubscriptionSkins Notification Message %s %s' % (language, reference),
text_content=text_content,
content_type=content_type,
reference=reference,
version=999,
language=language
)
notification_message.validate()
return notification_message
def createNormalUser(self, email, name, language, project):
""" Create a Normal user """
normal_user_login = self.portal.portal_catalog.getResultValue(
portal_type="ERP5 Login",
reference=email,
validation_state="validated"
)
if normal_user_login is None:
normal_user = self.portal.person_module.template_member.\
Base_createCloneDocument(batch_mode=1)
normal_user.newContent(
portal_type="ERP5 Login",
reference=email).validate()
normal_user.edit(
first_name=name,
reference=email,
default_email_text=email,
)
for assignment in normal_user.contentValues(portal_type="Assignment"):
assignment.open()
normal_user.validate()
else:
normal_user = normal_user_login.getParentValue()
normal_user.newContent(
portal_type='Assignment',
destination_project_value=project,
function='customer'
).open()
self.normal_user = normal_user
self.normal_user.setLanguage(language)
def createChineseSubscriptionCondition(self, slave=False):
sale_trade_condition = self.portal.sale_trade_condition_module.newContent(
portal_type="Sale Trade Condition",
title="TestSubscriptionScenario",
source=self.expected_source,
source_section=self.expected_source_section,
source_payment=self.expected_source_section + "/bank_account",
price_currency="currency_module/CNY",
payment_mode='wechat',
specialise="sale_trade_condition_module/slapos_subscription_trade_condition"
)
sale_trade_condition.newContent(
portal_type="Sale Supply Line",
base_price=self.expected_zh_individual_price_without_tax,
resource='service_module/slapos_instance_subscription',
)
sale_trade_condition.newContent(
portal_type="Sale Supply Line",
base_price=self.expected_zh_reservation_fee_without_tax,
resource='service_module/slapos_reservation_fee_2',
)
sale_trade_condition.validate()
subscription_condition = self.portal.subscription_condition_module.newContent(
portal_type="Subscription Condition",
title="TestSubscriptionChineseScenario",
short_tile="Test Your Chinese Scenario",
description="This is a Chinese test",
url_string=self.generateNewSoftwareReleaseUrl(),
root_slave=slave,
default_source_reference="default",
reference="rapidvm%s_zh" % self.new_id,
# Aggregate and Follow up to web pages for product description and
# Terms of service
sla_xml='<?xml version="1.0" encoding="utf-8"?>\n<instance>\n</instance>',
text_content='<?xml version="1.0" encoding="utf-8"?>\n<instance>\n</instance>',
user_input={},
specialise_value=sale_trade_condition,
follow_up_value=self.subscription_project
)
subscription_condition.validate()
self.tic()
return subscription_condition
def createSubscriptionCondition(self, slave=False):
url_string = self.generateNewSoftwareReleaseUrl()
# Create Software Product/Release
software_product = self.portal.software_product_module.newContent(
portal_type="Software Product",
title="TestSoftwareProduct",
follow_up_value=self.subscription_project,
use='trade/sale',
quantity_unit='unit/piece',
product_line='cloud/subscription',
base_contribution_list=[
'base_amount/invoicing/discounted',
'base_amount/invoicing/taxable'
]
)
software_product.validate()
software_release = self.portal.software_release_module.newContent(
portal_type="Software Release",
title="TestSoftwareRelease",
url_string=url_string,
aggregate_value=software_product,
follow_up_value=self.subscription_project
)
software_release.share()
sale_trade_condition = self.portal.sale_trade_condition_module.newContent(
portal_type="Sale Trade Condition",
title="TestSubscriptionScenario",
source=self.expected_source,
source_section=self.expected_source_section,
source_payment=self.expected_source_section + "/bank_account",
price_currency="currency_module/EUR",
payment_mode='payzen',
specialise="sale_trade_condition_module/slapos_subscription_trade_condition",
source_project_value=self.subscription_project
)
# XXX TODO clarify the with / without tax
sale_trade_condition.newContent(
portal_type="Sale Supply Line",
base_price=self.expected_individual_price_without_tax,
resource_value=software_product,
)
sale_trade_condition.newContent(
portal_type="Sale Supply Line",
base_price=self.expected_reservation_fee_without_tax,
resource='service_module/slapos_reservation_fee_2',
)
sale_trade_condition.validate()
self.subscription_condition = self.portal.subscription_condition_module.newContent(
portal_type="Subscription Condition",
title="TestSubscriptionScenario",
short_tile="Test Your Scenario",
description="This is a test",
url_string=url_string,
root_slave=slave,
default_source_reference="default",
reference="rapidvm%s" % self.new_id,
# Aggregate and Follow up to web pages for product description and
# Terms of service
sla_xml='<?xml version="1.0" encoding="utf-8"?>\n<instance>\n</instance>',
text_content='<?xml version="1.0" encoding="utf-8"?>\n<instance>\n</instance>',
user_input={},
specialise_value=sale_trade_condition,
follow_up_value=self.subscription_project
)
self.subscription_condition.validate()
self.tic()
def getSubscriptionRequest(self, email, subscription_condition):
subscription_request_list = subscription_condition.getSpecialiseRelatedValueList(
portal_type='Subscription Request')
self.assertEqual(len(subscription_request_list), 1)
return subscription_request_list[0]
def getSubscriptionRequestList(self, email, subscription_condition):
subscription_request_list = subscription_condition.getSpecialiseRelatedValueList(
portal_type='Subscription Request')
return subscription_request_list
def checkSubscriptionRequest(self, subscription_request, email, subscription_condition):
self.assertNotEqual(subscription_request, None)
self.assertEqual(subscription_request.getDefaultEmailText(), email)
#self.assertEqual(subscription_request.getUrlString(), subscription_condition.getUrlString())
#self.assertEqual(subscription_request.getRootSlave(), subscription_condition.getRootSlave())
#self.assertEqual(subscription_request.getTextContent(),
# '<?xml version="1.0" encoding="utf-8"?>\n<instance>\n</instance>')
#self.assertEqual(trial_request.getSlaXml(), '<?xml version="1.0" encoding="utf-8"?>\n<instance>\n</instance>')
#self.assertEqual(subscription_request.getSourceReference(), "default")
def checkDraftSubscriptionRequest(self, subscription_request, email, subscription_condition,
amount=1):
self.checkSubscriptionRequest(subscription_request, email, subscription_condition)
# XXX This might be diferent
self.assertEqual(subscription_request.getQuantity(), amount)
self.assertEqual(subscription_request.getAggregate(), None)
invoice = subscription_request.getCausalityValue(portal_type="Sale Invoice Transaction")
self.assertNotEqual(invoice, None)
payment = invoice.getCausalityRelatedValue(portal_type="Payment Transaction")
self.assertNotEqual(payment, None)
def checkPlannedSubscriptionRequest(self, subscription_request, email,
subscription_condition):
self.checkSubscriptionRequest(subscription_request, email,
subscription_condition)
self.assertEqual(subscription_request.getSimulationState(), "planned")
def checkOrderedSubscriptionRequest(self, subscription_request, email,
subscription_condition,
notification_message="subscription_request-confirmation-with-password"):
self.checkSubscriptionRequest(subscription_request, email,
subscription_condition)
self.assertEqual(subscription_request.getSimulationState(), "ordered")
self.checkBootstrapUser(subscription_request)
self.checkEmailNotification(subscription_request, notification_message)
def checkConfirmedSubscriptionRequest(self, subscription_request, email,
subscription_condition,
notification_message="subscription_request-payment-is-ready"):
self.checkSubscriptionRequest(subscription_request, email,
subscription_condition)
invoice = subscription_request.SubscriptionRequest_verifyPaymentBalanceIsReady()
self.assertNotEqual(invoice, None)
self.assertEqual(invoice.getSimulationState(), 'stopped')
# Assert instance is allocated and without error
self.assertEqual(True,
subscription_request.SubscriptionRequest_verifyInstanceIsAllocated(verbose=True))
self.assertEqual(subscription_request.getSimulationState(), "confirmed",
"%s != confirmed (%s)" % (subscription_request.getSimulationState(),
subscription_request.SubscriptionRequest_processOrdered()))
self.checkEmailPaymentNotification(subscription_request, notification_message)
def checkStartedSubscriptionRequest(self, subscription_request, email,
subscription_condition,
notification_message="subscription_request-instance-is-ready"):
self.checkSubscriptionRequest(subscription_request, email,
subscription_condition)
self.assertEqual(subscription_request.getSimulationState(), "started")
self.checkEmailInstanceNotification(subscription_request, notification_message)
def checkStoppedSubscriptionRequest(self, subscription_request, email,
subscription_condition):
self.checkSubscriptionRequest(subscription_request, email,
subscription_condition)
self.assertEqual(subscription_request.getSimulationState(), "stopped")
def _getRelatedPaymentValue(self, subscription_request):
invoice = subscription_request.getCausalityValue(portal_type="Sale Invoice Transaction")
return invoice.getCausalityRelatedValue(portal_type="Payment Transaction")
def createReversalInvoiceAndCancelPayment(self, subscription_request):
self.login()
person = subscription_request.getDestinationSectionValue()
self.login(person.getUserId())
invoice_list = person.Entity_getOutstandingAmountList()
self.assertEqual(len(invoice_list), 1)
sale_transaction_invoice = invoice_list[0].getObject()
self.logout()
self.login()
sale_transaction_invoice.SaleInvoiceTransaction_createReversalSaleInvoiceTransaction(batch_mode=1)
def checkSubscriptionRequestPayment(self, subscription_request, authAmount):
self.assertEqual(subscription_request.getSourceSection(), None)
self.assertEqual(subscription_request.getSource(), None)
trade_condition = subscription_request.getSpecialiseValue().getSpecialiseValue()
if trade_condition.getSource() is not None:
#expected_source = subscription_request.getSource()
expected_source_section = trade_condition.getSourceSection()
else:
#expected_source = self.expected_source
expected_source_section = self.expected_source_section
# Be accurate when select the payment
payment = self.portal.portal_catalog.getResultValue(
portal_type="Payment Transaction",
destination_section_uid=subscription_request.getDestinationSectionUid(),
source_section_uid=self.portal.restrictedTraverse(expected_source_section).getUid(),
simulation_state="started")
self.assertEqual(payment.getSourceSection(),
expected_source_section)
self.assertEqual(payment.getSourcePayment(),
"%s/bank_account" % expected_source_section)
self.assertEqual(int(round(payment.PaymentTransaction_getTotalPayablePrice(), 2)*100),
-authAmount)
subscription_condition = subscription_request.getSpecialiseValue(portal_type='Subscription Condition')
sale_trade_condition = subscription_condition.getSpecialiseValue(portal_type='Sale Trade Condition')
self.assertEqual(payment.getPriceCurrency(),
sale_trade_condition.getPriceCurrency())
# Check related invoice Data
invoice_list = payment.getCausalityValueList()
self.assertEqual(len(invoice_list), 1)
invoice = invoice_list[0]
delivery_list = invoice.getCausalityValueList()
# Invoices related to Subscription Request don't merge
self.assertEqual(len(delivery_list), 1)
sale_packing_list = delivery_list[0]
instance_tree = subscription_request.getAggregateValue()
subscription_delivery_line_list = self.portal.portal_catalog(
portal_type="Sale Packing List Line",
resource__uid=instance_tree.InstanceTree_getSoftwareProduct().getUid(),
grouping_reference=sale_packing_list.getReference()
)
self.assertEqual(len(subscription_delivery_line_list), 1,
"len(%s) is not 1" % [i.getObject() for i in subscription_delivery_line_list])
# Check more :)
return payment
def checkAndPayFirstMonth(self, subscription_request):
self.login()
person = subscription_request.getDestinationSectionValue()
quantity = subscription_request.getQuantity()
self.login(person.getUserId())
self.usePaymentManually(
self.web_site,
person.getUserId(),
is_email_expected=False,
subscription_request=subscription_request)
self.logout()
self.login()
# 195 is the month payment
# 195*1 is the 1 months to pay upfront to use.
# 25 is the reservation fee deduction.
authAmount = (int(self.expected_individual_price_with_tax*100)*1-int(self.expected_reservation_fee*100))*quantity
payment = self.checkSubscriptionRequestPayment(subscription_request, authAmount)
data_kw = {
"status": "SUCCESS",
"answer": {
"transactions": [
{
"detailedStatus": "AUTHORISED",
"transactionDetails": {
"cardDetails": {
"authorizationResponse": {
"amount": authAmount,
"currency": "EUR",
},
},
},
}
],
},
}
payment.PaymentTransaction_createPayzenEvent().PayzenEvent_processUpdate(data_kw)
def checkAndPaySecondMonth(self, subscription_request):
self.login()
person = subscription_request.getDestinationSectionValue()
quantity = subscription_request.getQuantity()
self.login(person.getUserId())
self.usePaymentManually(
self.web_site,
person.getUserId(),
subscription_request=subscription_request)
self.logout()
self.login()
authAmount = int(self.expected_individual_price_with_tax*100)*quantity
payment = self.checkSubscriptionRequestPayment(subscription_request, authAmount)
data_kw = {
"status": "SUCCESS",
"answer": {
"transactions": [
{
"detailedStatus": "AUTHORISED",
"transactionDetails": {
"cardDetails": {
"authorizationResponse": {
"amount": authAmount,
"currency": "EUR",
},
},
},
}
],
},
}
payment.PaymentTransaction_createPayzenEvent().PayzenEvent_processUpdate(data_kw)
def checkAndPayFirstMonthViaWechat(self, subscription_request):
self.login()
original_mode = self.portal.portal_secure_payments.slapos_wechat_test.getWechatMode()
self._simulatePaymentTransaction_getVADSUrlDict()
try:
person = subscription_request.getDestinationSectionValue()
quantity = subscription_request.getQuantity()
self.portal.portal_secure_payments.slapos_wechat_test.setWechatMode("UNITTEST")
self.login(person.getUserId())
self.usePaymentManually(
self.web_site,
person.getUserId(),
is_email_expected=False,
subscription_request=subscription_request)
self.logout()
self.login()
authAmount = (int(self.expected_zh_individual_price_with_tax*100)*1-int(self.expected_zh_reservation_fee*100))*quantity
payment = self.checkSubscriptionRequestPayment(subscription_request, authAmount)
data_kw = {
'result_code': 'SUCCESS',
'trade_state': 'SUCCESS',
'total_fee': authAmount,
'fee_type': 'CNY',
}
# Wechat_processUpdate will mark payment as payed by stopping it.
payment.PaymentTransaction_createWechatEvent().WechatEvent_processUpdate(data_kw)
finally:
self._dropPaymentTransaction_getVADSUrlDict()
self.portal.portal_secure_payments.slapos_wechat_test.setWechatMode(original_mode)
def checkAndPaySecondMonthViaWechat(self, subscription_request):
self.login()
original_mode = self.portal.portal_secure_payments.slapos_wechat_test.getWechatMode()
self._simulatePaymentTransaction_getVADSUrlDict()
try:
person = subscription_request.getDestinationSectionValue()
quantity = subscription_request.getQuantity()
self.portal.portal_secure_payments.slapos_wechat_test.setWechatMode("UNITTEST")
self.login(person.getUserId())
self.usePaymentManually(
self.web_site,
person.getUserId(),
subscription_request=subscription_request)
self.logout()
self.login()
authAmount = int(self.expected_zh_individual_price_with_tax*100)*quantity
payment = self.checkSubscriptionRequestPayment(subscription_request, authAmount)
data_kw = {
'result_code': 'SUCCESS',
'trade_state': 'SUCCESS',
'total_fee': authAmount,
'fee_type': 'CNY',
}
# Wechat_processUpdate will mark payment as payed by stopping it.
payment.PaymentTransaction_createWechatEvent().WechatEvent_processUpdate(data_kw)
finally:
self._dropPaymentTransaction_getVADSUrlDict()
self.portal.portal_secure_payments.slapos_wechat_test.setWechatMode(original_mode)
def _checkFreeReservationPayment(self, subscription_request):
quantity = subscription_request.getQuantity()
# Check Payment
payment = self._getRelatedPaymentValue(subscription_request)
subscription_condition = subscription_request.getSpecialiseValue(portal_type='Subscription Condition')
sale_trade_condition = subscription_condition.getSpecialiseValue(portal_type='Sale Trade Condition')
self.assertEqual(sale_trade_condition.getPriceCurrency(),
payment.getPriceCurrency())
self.assertEqual(-self.expected_reservation_fee*quantity,
payment.PaymentTransaction_getTotalPayablePrice())
self.assertEqual(payment.getSimulationState(), "stopped")
return payment
def _payPayment(self, subscription_request):
quantity = subscription_request.getQuantity()
# Check Payment
payment = self._getRelatedPaymentValue(subscription_request)
subscription_condition = subscription_request.getSpecialiseValue(portal_type='Subscription Condition')
sale_trade_condition = subscription_condition.getSpecialiseValue(portal_type='Sale Trade Condition')
#sale_supply_line = sale_trade_condition.contentValues(portal_type='Sale Supply Line')[0]
self.assertEqual(sale_trade_condition.getPriceCurrency(),
payment.getPriceCurrency())
self.assertEqual(payment.getSimulationState(), "started")
# Pay with appropriate mode depending of the currency.
if payment.getPriceCurrency() == "currency_module/CNY":
self.assertEqual(-round(self.expected_zh_reservation_fee*quantity, 2),
round(payment.PaymentTransaction_getTotalPayablePrice(), 2))
# Pay 188 CNY per VM
data_kw = {
'result_code': 'SUCCESS',
'trade_state': 'SUCCESS',
'total_fee': self.expected_zh_reservation_fee*100*quantity,
'fee_type': 'CNY',
}
# Wechat_processUpdate will mark payment as payed by stopping it.
payment.PaymentTransaction_createWechatEvent().WechatEvent_processUpdate(data_kw)
else:
self.assertEqual(-round(self.expected_reservation_fee*quantity, 2),
round(payment.PaymentTransaction_getTotalPayablePrice(), 2))
# Pay 25 euros per VM
data_kw = {
"status": "SUCCESS",
"answer": {
"transactions": [
{
"detailedStatus": "AUTHORISED",
"transactionDetails": {
"cardDetails": {
"authorizationResponse": {
"amount": self.expected_reservation_fee*100*quantity,
"currency": "EUR",
},
},
},
}
],
},
}
# Payzen_processUpdate will mark payment as payed by stopping it.
payment.PaymentTransaction_createPayzenEvent().PayzenEvent_processUpdate(data_kw)
return payment
def checkAndPaySubscriptionPayment(self, subscription_request_list):
for subscription_request in subscription_request_list:
quantity = subscription_request.getQuantity()
invoice = subscription_request.getCausalityValue(
portal_type="Sale Invoice Transaction")
self.assertEqual(invoice.getSimulationState(), "confirmed")
self.assertEqual(invoice.getCausalityState(), "building")
self.assertEqual(subscription_request.getSourceSection(), None)
self.assertEqual(subscription_request.getSource(), None)
self.assertEqual(subscription_request.getSpecialiseValue().getSourceSection(), None)
self.assertEqual(subscription_request.getSpecialiseValue().getSource(), None)
trade_condition = subscription_request.getSpecialiseValue().getSpecialiseValue()
if trade_condition.getSource() is not None:
expected_source = trade_condition.getSource()
expected_source_section = trade_condition.getSourceSection()
else:
expected_source = self.expected_source
expected_source_section = self.expected_source_section
self.assertEqual(invoice.getSource(), expected_source)
self.assertEqual(invoice.getSourceSection(), expected_source_section)
# Pay Invoice if it is not Free
if not self.expected_free_reservation:
payment = self._payPayment(subscription_request)
else:
payment = self._checkFreeReservationPayment(subscription_request)
# Check Payment
self.assertEqual(payment.getSourceSection(), expected_source_section)
self.assertEqual(payment.getSourcePayment(),
"%s/bank_account" % expected_source_section)
self.tic()
self.assertEqual(payment.getSimulationState(), "stopped")
# stabilise aggregated invoices and expand them
self.stepCallSlaposManageBuildingCalculatingDeliveryAlarm()
self.tic()
# update invoices with their tax & discount
self.stepCallSlaposTriggerBuildAlarm()
self.tic()
self.stepCallSlaposManageBuildingCalculatingDeliveryAlarm()
self.tic()
# update invoices with their tax & discount transaction lines
self.stepCallSlaposTriggerBuildAlarm()
self.tic()
self.stepCallSlaposManageBuildingCalculatingDeliveryAlarm()
self.tic()
# stop the invoices and solve them again
self.stepCallSlaposStopConfirmedAggregatedSaleInvoiceTransactionAlarm()
self.tic()
self.stepCallSlaposManageBuildingCalculatingDeliveryAlarm()
self.tic()
for subscription_request in subscription_request_list:
invoice = subscription_request.getCausalityValue(
portal_type="Sale Invoice Transaction")
subscription_condition = subscription_request.getSpecialiseValue(portal_type='Subscription Condition')
sale_trade_condition = subscription_condition.getSpecialiseValue(portal_type='Sale Trade Condition')
#sale_supply_line = sale_trade_condition.contentValues(portal_type='Sale Supply Line')[0]
if sale_trade_condition.getPriceCurrency() == "currency_module/CNY":
expected_reservation_fee_without_tax = self.expected_zh_reservation_fee_without_tax
expected_reservation_quantity_tax = self.expected_zh_reservation_quantity_tax
expected_reservation_tax = self.expected_zh_reservation_tax
expected_reservation_fee = self.expected_zh_reservation_fee
else:
expected_reservation_fee_without_tax = self.expected_reservation_fee_without_tax
expected_reservation_quantity_tax = self.expected_reservation_quantity_tax
expected_reservation_tax = self.expected_reservation_tax
expected_reservation_fee = self.expected_reservation_fee
self.assertEqual(invoice.getSimulationState(), "stopped", invoice.getRelativeUrl())
self.assertEqual(invoice.getCausalityState(), "solved")
self.assertEqual(invoice.getPriceCurrency(),
sale_trade_condition.getPriceCurrency())
for line in invoice.objectValues():
if line.getResource() == "service_module/slapos_reservation_fee_2":
self.assertEqual(line.getTotalQuantity(), quantity)
if self.expected_free_reservation:
self.assertEqual(round(line.getTotalPrice(), 2), 0.0)
else:
self.assertEqual(round(line.getTotalPrice(), 2),
round(expected_reservation_fee_without_tax*quantity, 2))
if line.getResource() == "service_module/slapos_tax":
self.assertEqual(round(line.getTotalQuantity(), 2),
round(expected_reservation_quantity_tax*quantity, 2))
self.assertEqual(round(line.getTotalPrice(), 2),
round(expected_reservation_tax*quantity, 2))
self.assertEqual(round(invoice.getTotalPrice(), 2),
round(expected_reservation_fee*quantity, 2))
def checkSecondMonthAggregatedSalePackingList(self, subscription_request, sale_packing_list):
sale_packing_list_line = [ i for i in sale_packing_list.objectValues()
if i.getResource() == "service_module/slapos_instance_subscription"][0]
quantity = subscription_request.getQuantity()
subscription_condition = subscription_request.getSpecialiseValue(portal_type='Subscription Condition')
sale_trade_condition = subscription_condition.getSpecialiseValue(portal_type='Sale Trade Condition')
# The values are without tax
if sale_trade_condition.getPriceCurrency() == "currency_module/CNY":
expected_individual_price_without_tax = self.expected_zh_individual_price_without_tax
else:
expected_individual_price_without_tax = self.expected_individual_price_without_tax
self.assertEqual(sale_packing_list_line.getQuantity(), 1*quantity)
self.assertEqual(round(sale_packing_list_line.getPrice(), 2),
round(expected_individual_price_without_tax, 2))
self.assertEqual(round(sale_packing_list_line.getTotalPrice(), 2),
round(1*expected_individual_price_without_tax*quantity, 2))
self.assertEqual(sale_packing_list.getCausality(),
subscription_request.getRelativeUrl())
self.assertEqual(sale_packing_list.getCausality(),
subscription_request.getRelativeUrl())
self.assertEqual(sale_packing_list.getPriceCurrency(),
sale_trade_condition.getPriceCurrency())
def _checkSecondMonthSimulation(self, subscription_request_list,
default_email_text, subscription_server):
# Needed?
self.simulateSlapgridCP(subscription_server)
self.tic()
self.stepCallSlaposUpdateOpenSaleOrderPeriodAlarm()
self.tic()
for subscription_request in subscription_request_list:
self.checkAllocationOnRelatedInstance(subscription_request)
# Needed?
self.simulateSlapgridCP(subscription_server)
self.tic()
# generate simulation for open order
self.stepCallUpdateOpenOrderSimulationAlarm(full=1)
self.tic()
# build subscription packing list
self.stepCallSlaposTriggerBuildAlarm()
self.tic()
# stabilise build deliveries and expand them
self.stepCallSlaposManageBuildingCalculatingDeliveryAlarm()
self.tic()
# build aggregated packing list
self.stepCallSlaposTriggerAggregatedDeliveryOrderBuilderAlarm()
self.tic()
# stabilise aggregated deliveries and expand them
self.stepCallSlaposManageBuildingCalculatingDeliveryAlarm()
self.tic()
# check if Packing list is generated with the right trade condition
preference_tool = self.portal.portal_preferences
aggregate_subscription_condition = \
preference_tool.getPreferredAggregatedSubscriptionSaleTradeCondition()
trade_condition = preference_tool.getPreferredAggregatedSaleTradeCondition()
for subscription_request in subscription_request_list:
sale_packing_list_list = self.getAggregatedSalePackingList(
subscription_request, aggregate_subscription_condition)
if not len(sale_packing_list_list):
diverged_sale_packing_list_list = self.getDivergedAggregatedSalePackingList(
subscription_request, aggregate_subscription_condition)
self.assertEqual(0, len(diverged_sale_packing_list_list))
self.assertEqual(1, len(sale_packing_list_list))
self.checkSecondMonthAggregatedSalePackingList(subscription_request, sale_packing_list_list[0])
expected_sale_packing_list_amount = (len(subscription_request_list) * 2)+\
self.non_subscription_related_instance_amount
self.assertEqual(expected_sale_packing_list_amount,
len(self.getSubscriptionSalePackingList(subscription_request)))
self.assertEqual(0, len(self.getAggregatedSalePackingList(
subscription_request, trade_condition)))
# Call this alarm shouldn't affect the delivery
self.stepCallSlaposStartConfirmedAggregatedSalePackingListAlarm(
accounting_date=DateTime('2222/01/01'))
self.tic()
for subscription_request in subscription_request_list:
self.assertEqual(1, len(self.getAggregatedSalePackingList(
subscription_request, aggregate_subscription_condition)))
# Call this alarm shouldn't affect the delivery
self.stepCallSlaposStartConfirmedAggregatedSubscriptionSalePackingListAlarm()
self.tic()
for subscription_request in subscription_request_list:
self.assertEqual(0, len(self.getAggregatedSalePackingList(
subscription_request, trade_condition)))
# stabilise aggregated deliveries and expand them
self.stepCallSlaposManageBuildingCalculatingDeliveryAlarm()
self.tic()
# deliver aggregated deliveries
self.stepCallSlaposDeliverStartedAggregatedSalePackingListAlarm()
self.tic()
# stabilise aggregated deliveries and expand them
self.stepCallSlaposManageBuildingCalculatingDeliveryAlarm()
self.tic()
# build aggregated invoices
self.stepCallSlaposTriggerBuildAlarm()
self.tic()
# stabilise aggregated invoices and expand them
self.stepCallSlaposManageBuildingCalculatingDeliveryAlarm()
self.tic()
# update invoices with their tax & discount
self.stepCallSlaposTriggerBuildAlarm()
self.tic()
self.stepCallSlaposManageBuildingCalculatingDeliveryAlarm()
self.tic()
# update invoices with their tax & discount transaction lines
self.stepCallSlaposTriggerBuildAlarm()
self.tic()
self.stepCallSlaposManageBuildingCalculatingDeliveryAlarm()
self.tic()
# stop the invoices and solve them again
self.stepCallSlaposStopConfirmedAggregatedSaleInvoiceTransactionAlarm()
self.tic()
self.stepCallSlaposManageBuildingCalculatingDeliveryAlarm()
self.tic()
# trigger the CRM interaction
self.stepCallSlaposCrmCreateRegularisationRequestAlarm()
self.tic()
# Test if balance is bad now
subscriber = subscription_request.getDestinationSectionValue()
self.assertEqual(subscriber.Entity_statOutstandingAmount(at_date=DateTime()),
0.0)
trade_condition = subscription_request.getSpecialiseValue().getSpecialiseValue()
if trade_condition.getPriceCurrency() == "currency_module/CNY":
expected_individual_price_with_tax = self.expected_zh_individual_price_with_tax
else:
expected_individual_price_with_tax = self.expected_individual_price_with_tax
expected_amount = round(expected_individual_price_with_tax*sum([i.getQuantity(0)
for i in subscription_request_list]),2)
self.assertEqual(round(subscriber.Entity_statOutstandingAmount(), 2), expected_amount)
# Invoice to Pay
self.assertEqual(
round(subscriber.Entity_statSlapOSOutstandingAmount(at_date=DateTime()+20), 2),
expected_amount)
# Pay this new invoice
for subscription_request in subscription_request_list:
trade_condition = subscription_request.getSpecialiseValue().getSpecialiseValue()
if trade_condition.getPriceCurrency() == "currency_module/CNY":
self.checkAndPaySecondMonthViaWechat(subscription_request)
else:
self.checkAndPaySecondMonth(subscription_request)
self.tic()
# Here the invoice was payed before the date, so value is negative.
self.assertEqual(round(subscriber.Entity_statOutstandingAmount(at_date=DateTime()), 2),
0.0)
self.assertEqual(round(subscriber.Entity_statOutstandingAmount(), 2), 0.0)
# All payed
self.assertEqual(
round(subscriber.Entity_statSlapOSOutstandingAmount(at_date=DateTime()+20), 2),
0.0)
def checkBootstrapUser(self, subscription_request):
person = subscription_request.getDestinationSectionValue(portal_type="Person")
self.assertEqual(person.getDefaultEmailText(),
subscription_request.getDefaultEmailText())
self.assertEqual(person.getValidationState(), "validated")
login_list = [x for x in person.objectValues(portal_type='ERP5 Login') \
if x.getValidationState() == 'validated']
self.assertEqual(len(login_list), 1)
self.assertEqual(login_list[0].getReference(), person.getDefaultEmailText())
def checkEmailNotification(self, subscription_request,
notification_message="subscription_request-confirmation-with-password"):
expected_amount = 1
if self.normal_user is not None:
# If user already exists we do not expect to send an email
expected_amount = 0
mail_message_list = [i for i in subscription_request.getFollowUpRelatedValueList(
portal_type="Mail Message") if notification_message in i.getTitle()]
self.assertEqual(len(mail_message_list), expected_amount)
if not expected_amount:
return
mail_message = mail_message_list[0]
self.assertEqual(
"TestSubscriptionSkins Notification Message %s %s" % (
subscription_request.getLanguage(), notification_message),
mail_message.getTitle())
self.assertTrue(subscription_request.getDefaultEmailText() in \
mail_message.getTextContent())
self.assertTrue(subscription_request.getDestinationSectionTitle() in \
mail_message.getTextContent())
def checkEmailPaymentNotification(self, subscription_request,
notification_message="subscription_request-payment-is-ready"):
mail_message_list = [i for i in subscription_request.getFollowUpRelatedValueList(
portal_type="Mail Message") if notification_message in i.getTitle()]
self.assertEqual(len(mail_message_list), 1)
mail_message = mail_message_list[0]
self.assertEqual(
"TestSubscriptionSkins Notification Message %s %s" % (
subscription_request.getLanguage(), notification_message),
mail_message.getTitle())
invoice = subscription_request.SubscriptionRequest_verifyPaymentBalanceIsReady()
self.assertEqual(invoice.getSimulationState(), 'stopped')
self.assertTrue(invoice.getRelativeUrl() in \
mail_message.getTextContent())
self.assertTrue(subscription_request.getDestinationSectionTitle() in \
mail_message.getTextContent())
def checkEmailInstanceNotification(self, subscription_request,
notification_message="subscription_request-instance-is-ready"):
mail_message_list = [i for i in subscription_request.getFollowUpRelatedValueList(
portal_type="Mail Message") if notification_message in i.getTitle()]
self.assertEqual(len(mail_message_list), 1)
mail_message = mail_message_list[0]
self.assertEqual(
"TestSubscriptionSkins Notification Message %s %s" % (
subscription_request.getLanguage(), notification_message),
mail_message.getTitle())
instance_tree = subscription_request.getAggregateValue()
self.assertEqual(instance_tree.getSlapState(), 'start_requested')
self.assertTrue(instance_tree.getRelativeUrl() in \
mail_message.getTextContent())
self.assertTrue(subscription_request.getDestinationSectionTitle() in \
mail_message.getTextContent())
def checkRelatedInstance(self, subscription_request):
instance = self._checkRelatedInstance(subscription_request)
self.assertEqual(instance.getAggregate(), None)
def _checkRelatedInstance(self, subscription_request):
instance_tree = subscription_request.getAggregateValue()
self.assertNotEqual(instance_tree, None)
subscription_condition = subscription_request.getSpecialiseValue(portal_type='Subscription Condition')
self.assertEqual(subscription_condition.getUrlString(),
instance_tree.getUrlString())
self.assertEqual(subscription_condition.getRootSlave(),
instance_tree.getRootSlave())
self.assertEqual(instance_tree.getTextContent(),
'<?xml version="1.0" encoding="utf-8"?>\n<instance>\n</instance>')
#self.assertEqual(trial_request.getSlaXml(), '<?xml version="1.0" encoding="utf-8"?>\n<instance>\n</instance>')
self.assertEqual(instance_tree.getSourceReference(), "default")
instance_list = instance_tree.getSpecialiseRelatedValueList(
portal_type=["Software Instance", "Slave Instance"])
self.assertEqual(1,len(instance_list))
return instance_list[0]
def checkAllocationOnRelatedInstance(self, subscription_request):
instance = self._checkRelatedInstance(subscription_request)
self.assertNotEqual(instance.getAggregate(), None)
def checkAggregatedSalePackingList(self, subscription_request, sale_packing_list):
subscription_condition = subscription_request.getSpecialiseValue(portal_type='Subscription Condition')
sale_trade_condition = subscription_condition.getSpecialiseValue(portal_type='Sale Trade Condition')
#sale_supply_line = sale_trade_condition.contentValues(portal_type='Sale Supply Line')[0]
self.assertEqual(len(sale_packing_list.objectValues()), 2)
sale_packing_list_line = [ i for i in sale_packing_list.objectValues()
if i.getResourceValue().getPortalType() == "Software Product"][0]
quantity = subscription_request.getQuantity()
if sale_trade_condition.getPriceCurrency() == "currency_module/CNY":
expected_individual_price_without_tax = self.expected_zh_individual_price_without_tax
expected_reservation_fee = self.expected_zh_reservation_fee_without_tax
else:
expected_individual_price_without_tax = self.expected_individual_price_without_tax
expected_reservation_fee = self.expected_reservation_fee_without_tax
# The values are without tax
self.assertEqual(sale_packing_list_line.getQuantity(), 1*quantity)
self.assertEqual(round(sale_packing_list_line.getPrice(), 2),
round(expected_individual_price_without_tax, 2))
self.assertEqual(round(sale_packing_list_line.getTotalPrice(), 2),
round(1*expected_individual_price_without_tax*quantity, 2))
self.assertEqual(sale_packing_list.getCausality(),
subscription_request.getRelativeUrl())
sale_packing_list_line = [ i for i in sale_packing_list.objectValues()
if i.getResource() == "service_module/slapos_reservation_refund"][0]
quantity = subscription_request.getQuantity()
# The values are without tax
self.assertEqual(sale_packing_list_line.getQuantity(), 1)
self.assertEqual(round(sale_packing_list_line.getPrice(), 2),
-round(expected_reservation_fee*quantity, 2))
self.assertEqual(round(sale_packing_list_line.getTotalPrice(), 2),
-round(expected_reservation_fee*quantity, 2))
self.assertEqual(sale_packing_list.getCausality(),
subscription_request.getRelativeUrl())
self.assertEqual(sale_packing_list.getPriceCurrency(),
sale_trade_condition.getPriceCurrency())
def makeCloudInvitationToken(self, max_invoice_delay=0, max_invoice_credit_eur=0.0,
max_invoice_credit_cny=0.0):
self.login()
contract_invitation_token = self.portal.invitation_token_module.newContent(
portal_type="Contract Invitation Token",
maximum_invoice_delay=max_invoice_delay
)
if max_invoice_credit_eur > 0:
contract_invitation_token.newContent(
maximum_invoice_credit=max_invoice_credit_eur,
price_currency="currency_module/EUR")
if max_invoice_credit_cny > 0:
contract_invitation_token.newContent(
maximum_invoice_credit=max_invoice_credit_cny,
price_currency="currency_module/CNY")
contract_invitation_token.validate()
self.logout()
return contract_invitation_token
@changeSkin('Hal')
def _requestSubscription(self, **kw):
if self.cloud_invitation_token is not None:
kw["token"] = self.cloud_invitation_token.getId()
if self.resource_variation_reference is not None:
kw["variation_reference"] = self.resource_variation_reference
return self.web_site.hateoas.SubscriptionRequestModule_requestSubscriptionProxy(**kw)
@changeSkin('Hal')
def _requestSubscriptionViaChineseWebsite(self, **kw):
if self.cloud_invitation_token is not None:
kw["token"] = self.cloud_invitation_token.getId()
if 'target_language' not in kw:
kw["target_language"] = "zh"
if self.resource_variation_reference is not None:
kw["variation_reference"] = self.resource_variation_reference
kw["subscription_reference"] = self.subscription_condition.getReference().replace("_zh", "")
original_mode = self.portal.portal_secure_payments.slapos_wechat_test.getWechatMode()
self._simulatePaymentTransaction_getVADSUrlDict()
try:
self.portal.portal_secure_payments.slapos_wechat_test.setWechatMode("UNITTEST")
self.logout()
self.changeSkin('Hal')
return self.web_site.hateoas.SubscriptionRequestModule_requestSubscriptionProxy(**kw)
finally:
self._dropPaymentTransaction_getVADSUrlDict()
self.portal.portal_secure_payments.slapos_wechat_test.setWechatMode(original_mode)
def getAggregatedSalePackingList(self, subscription_request, specialise):
person = subscription_request.getDestinationSectionValue()
person_uid = person.getUid()
specialise_uid = self.portal.restrictedTraverse(specialise).getUid()
return self.portal.portal_catalog(
portal_type='Sale Packing List',
simulation_state='confirmed',
causality_state='solved',
causality_uid=subscription_request.getUid(),
destination_decision_uid=person_uid,
specialise_uid=specialise_uid)
def getDivergedAggregatedSalePackingList(self, subscription_request, specialise):
person_uid = subscription_request.getDestinationSectionValue().getUid()
specialise_uid = self.portal.restrictedTraverse(specialise).getUid()
return self.portal.portal_catalog(
portal_type='Sale Packing List',
simulation_state='confirmed',
causality_state='diverged',
causality_uid=subscription_request.getUid(),
destination_decision_uid=person_uid,
specialise_uid=specialise_uid)
def getSubscriptionSalePackingList(self, subscription_request):
person_uid = subscription_request.getDestinationSectionValue().getUid()
specialise_uid = self.portal.restrictedTraverse(
"sale_trade_condition_module/slapos_subscription_trade_condition").getUid()
specialise_uid = [specialise_uid] + [
i.uid for i in self.portal.ERP5Site_searchRelatedInheritedSpecialiseList(
specialise_uid=specialise_uid)
]
return self.portal.portal_catalog(
portal_type='Sale Packing List',
simulation_state='delivered',
causality_state='solved',
destination_decision_uid=person_uid,
specialise_uid=specialise_uid)
def createPublicServerForAdminUser(self):
# hooray, now it is time to create compute_nodes
self.login(self.admin_user.getUserId())
# Create a Public Server for admin user, and allow
subscription_server_title = 'Trial Public Server for Admin User %s' % self.new_id
subscription_server_id = self.requestComputeNode(subscription_server_title,
self.subscription_project.getReference())
subscription_server = self.portal.portal_catalog.getResultValue(
portal_type='Compute Node', reference=subscription_server_id)
self.setAccessToMemcached(subscription_server)
self.assertNotEqual(None, subscription_server)
self.setServerOpenPublic(subscription_server)
self.assertEqual('open', subscription_server.getCapacityScope())
# and install some software on them
subscription_server_software = self.subscription_condition.getUrlString()
self.supplySoftware(subscription_server, subscription_server_software)
# format the compute_nodes
self.formatComputeNode(subscription_server)
self.tic()
self.logout()
return subscription_server
def requestAndCheckInstanceTree(self, amount, name,
default_email_text):
self.logout()
user_input_dict = {
"name": name,
"amount" : amount}
self._requestSubscription(
subscription_reference=self.subscription_condition.getReference(),
user_input_dict=user_input_dict,
email=default_email_text,
confirmation_required=False)
self.login()
# I'm not sure if this is realistic
self.tic()
subscription_request = self.getSubscriptionRequest(
default_email_text, self.subscription_condition)
sale_trade_condition = self.subscription_condition.getSpecialiseValue(
portal_type="Sale Trade Condition",
)
self.assertEqual(self.expected_price_currency,
sale_trade_condition.getPriceCurrency())
self.assertEqual(self.expected_notification_language,
subscription_request.getLanguage())
self.checkDraftSubscriptionRequest(subscription_request,
default_email_text, self.subscription_condition,
amount=amount)
# Check Payment and pay it.
self.checkAndPaySubscriptionPayment([subscription_request])
self.tic()
# Call alarm to check payment and invoice and move foward to planned.
self.stepCallSlaposSubscriptionRequestProcessDraftAlarm()
self.tic()
self.checkPlannedSubscriptionRequest(subscription_request,
default_email_text, self.subscription_condition)
# Call alarm to mark subscription request as ordered, bootstrap the user
# and check if email is sent, once done move to ordered state.
self.stepCallSlaposSubscriptionRequestProcessPlannedAlarm()
self.tic()
self.checkOrderedSubscriptionRequest(subscription_request,
default_email_text, self.subscription_condition)
# Call alarm to make the request of the instance?
self.stepCallSlaposSubscriptionRequestProcessOrderedAlarm()
self.tic()
# The alarms might be called multiple times for move each step
self.stepCallSlaposSubscriptionRequestProcessOrderedAlarm()
self.tic()
sale_packing_list_list = self.portal.portal_catalog(
causality_uid = subscription_request.getUid(),
title="Reservation Deduction",
portal_type="Sale Packing List"
)
self.assertEqual(len(sale_packing_list_list), 1)
sale_packing_list = sale_packing_list_list[0]
subscription_condition = subscription_request.getSpecialiseValue(portal_type='Subscription Condition')
sale_trade_condition = subscription_condition.getSpecialiseValue(portal_type='Sale Trade Condition')
#sale_supply_line = sale_trade_condition.contentValues(portal_type='Sale Supply Line')[0]
self.assertEqual(sale_packing_list.getPriceCurrency(),
sale_trade_condition.getPriceCurrency())
self.assertEqual(sale_packing_list.getSpecialise(),
"sale_trade_condition_module/slapos_reservation_refund_trade_condition")
if sale_trade_condition.getPriceCurrency() == "currency_module/CNY":
self.assertEqual(round(sale_packing_list.getTotalPrice(), 2),
-round(self.expected_zh_reservation_fee_without_tax*amount, 2))
else:
self.assertEqual(round(sale_packing_list.getTotalPrice(), 2),
-round(self.expected_reservation_fee_without_tax*amount, 2))
return subscription_request
def _checkSubscriptionDeploymentAndSimulation(self, subscription_request_list,
default_email_text, subscription_server):
for subscription_request in subscription_request_list:
# Check if instance was requested
self.checkRelatedInstance(subscription_request)
self.simulateSlapgridCP(subscription_server)
self.tic()
self.stepCallSlaposAllocateInstanceAlarm()
self.tic()
# now instantiate it on compute_node and set some nice connection dict
self.simulateSlapgridCP(subscription_server)
self.tic()
for subscription_request in subscription_request_list:
# Re-check, as instance shouldn't be allocated until
# the confirmation of the new Payment.
self.checkAllocationOnRelatedInstance(subscription_request)
# generate simulation for open order
self.stepCallUpdateOpenOrderSimulationAlarm()
self.tic()
# build subscription packing list
self.stepCallSlaposTriggerBuildAlarm()
self.tic()
# stabilise build deliveries and expand them
self.stepCallSlaposManageBuildingCalculatingDeliveryAlarm()
self.tic()
# build aggregated packing list
self.stepCallSlaposTriggerAggregatedDeliveryOrderBuilderAlarm()
self.tic()
# stabilise aggregated deliveries and expand them
self.stepCallSlaposManageBuildingCalculatingDeliveryAlarm()
self.tic()
# check if Packing list is generated with the right trade condition
preference_tool = self.portal.portal_preferences
aggregate_subscription_condition = \
preference_tool.getPreferredAggregatedSubscriptionSaleTradeCondition()
trade_condition = preference_tool.getPreferredAggregatedSaleTradeCondition()
for subscription_request in subscription_request_list:
instance_tree = subscription_request.getAggregateValue()
self.assertEqual(instance_tree.getCausalityState(), "solved")
sale_packing_list_list = self.getAggregatedSalePackingList(
subscription_request, aggregate_subscription_condition)
self.assertEqual(1, len(sale_packing_list_list))
self.checkAggregatedSalePackingList(subscription_request, sale_packing_list_list[0])
expected_sale_packing_list_amount = len(subscription_request_list) +\
self.non_subscription_related_instance_amount
self.assertEqual(expected_sale_packing_list_amount,
len(self.getSubscriptionSalePackingList(subscription_request)))
self.assertEqual(0, len(self.getAggregatedSalePackingList(
subscription_request, trade_condition)))
# Call this alarm shouldn't affect the delivery
self.stepCallSlaposStartConfirmedAggregatedSalePackingListAlarm(
accounting_date=DateTime('2222/01/01'))
self.tic()
for subscription_request in subscription_request_list:
self.assertEqual(1, len(self.getAggregatedSalePackingList(
subscription_request, aggregate_subscription_condition)))
# Call this alarm shouldn't affect the delivery
self.stepCallSlaposStartConfirmedAggregatedSubscriptionSalePackingListAlarm()
self.tic()
for subscription_request in subscription_request_list:
self.assertEqual(0, len(self.getAggregatedSalePackingList(
subscription_request, trade_condition)))
# stabilise aggregated deliveries and expand them
self.stepCallSlaposManageBuildingCalculatingDeliveryAlarm()
self.tic()
# deliver aggregated deliveries
self.stepCallSlaposDeliverStartedAggregatedSalePackingListAlarm()
self.tic()
# stabilise aggregated deliveries and expand them
self.stepCallSlaposManageBuildingCalculatingDeliveryAlarm()
self.tic()
# build aggregated invoices
self.stepCallSlaposTriggerBuildAlarm()
self.tic()
# stabilise aggregated invoices and expand them
self.stepCallSlaposManageBuildingCalculatingDeliveryAlarm()
self.tic()
# update invoices with their tax & discount
self.stepCallSlaposTriggerBuildAlarm()
self.tic()
self.stepCallSlaposManageBuildingCalculatingDeliveryAlarm()
self.tic()
# update invoices with their tax & discount transaction lines
self.stepCallSlaposTriggerBuildAlarm()
self.tic()
self.stepCallSlaposManageBuildingCalculatingDeliveryAlarm()
self.tic()
# stop the invoices and solve them again
self.stepCallSlaposStopConfirmedAggregatedSaleInvoiceTransactionAlarm()
self.tic()
self.stepCallSlaposManageBuildingCalculatingDeliveryAlarm()
self.tic()
# trigger the CRM interaction
self.stepCallSlaposCrmCreateRegularisationRequestAlarm()
self.tic()
# After the payment re-call the Alarm in order to confirm the subscription
# Request.
self.stepCallSlaposSubscriptionRequestProcessOrderedAlarm()
self.tic()
# The alarms might be called multiple times for move each step
self.stepCallSlaposSubscriptionRequestProcessOrderedAlarm()
self.tic()
for subscription_request in subscription_request_list:
# Instances should be allocated
self.checkAllocationOnRelatedInstance(subscription_request)
if not self.expected_free_reservation:
# In a scenario where invitation token is used, we expect
# that this script outputs True as user is below the maximum limit.
expected_test_payment_balance = False
expected_slap_state_after_subscription_is_confirmed = 'stop_requested'
else:
expected_test_payment_balance = True
expected_slap_state_after_subscription_is_confirmed = 'start_requested'
# Check if instance is on confirmed state
for subscription_request in subscription_request_list:
self.checkConfirmedSubscriptionRequest(subscription_request,
default_email_text,
subscription_request.getSpecialiseValue())
self.assertEqual(expected_test_payment_balance,
subscription_request.SubscriptionRequest_testPaymentBalance())
self.assertEqual('start_requested',
subscription_request.getAggregateValue().getSlapState())
# The alarms might be called multiple times for move each step
self.stepCallSlaposSubscriptionRequestProcessConfirmedAlarm()
self.tic()
for subscription_request in subscription_request_list:
self.assertEqual(expected_test_payment_balance,
subscription_request.SubscriptionRequest_testPaymentBalance())
self.assertEqual(expected_slap_state_after_subscription_is_confirmed,
subscription_request.getAggregateValue().getSlapState())
def checkSubscriptionDeploymentAndSimulationWithReversalTransaction(self, default_email_text, subscription_server):
subscription_request_list = self.getSubscriptionRequestList(
default_email_text, self.subscription_condition)
self._checkSubscriptionDeploymentAndSimulation(
subscription_request_list, default_email_text, subscription_server)
# Make payments and reinvoke alarm
for subscription_request in subscription_request_list:
self.createReversalInvoiceAndCancelPayment(subscription_request)
self.tic()
self.stepCallSlaposSubscriptionRequestProcessConfirmedAlarm()
self.tic()
for subscription_request in subscription_request_list:
self.assertTrue(
subscription_request.SubscriptionRequest_testPaymentBalance())
self.assertEqual('start_requested',
subscription_request.getAggregateValue().getSlapState())
# On the second loop that email is send and state is moved to started
self.stepCallSlaposSubscriptionRequestProcessConfirmedAlarm()
self.tic()
for subscription_request in subscription_request_list:
self.assertTrue(
subscription_request.SubscriptionRequest_testPaymentBalance())
self.assertEqual('start_requested',
subscription_request.getAggregateValue().getSlapState())
self.checkStartedSubscriptionRequest(subscription_request,
default_email_text, self.subscription_condition)
def checkSubscriptionDeploymentAndSimulation(self, default_email_text, subscription_server):
subscription_request_list = self.getSubscriptionRequestList(
default_email_text, self.subscription_condition)
self._checkSubscriptionDeploymentAndSimulation(
subscription_request_list, default_email_text, subscription_server)
if not self.expected_free_reservation:
for subscription_request in subscription_request_list:
subscription_condition = subscription_request.getSpecialiseValue(portal_type='Subscription Condition')
sale_trade_condition = subscription_condition.getSpecialiseValue(portal_type='Sale Trade Condition')
if sale_trade_condition.getPriceCurrency() == "currency_module/CNY":
self.checkAndPayFirstMonthViaWechat(subscription_request)
else:
self.checkAndPayFirstMonth(subscription_request)
self.tic()
self.stepCallSlaposSubscriptionRequestProcessConfirmedAlarm()
self.tic()
for subscription_request in subscription_request_list:
self.assertTrue(
subscription_request.SubscriptionRequest_testPaymentBalance())
self.assertEqual('start_requested',
subscription_request.getAggregateValue().getSlapState())
# On the second loop that email is send and state is moved to started
self.stepCallSlaposSubscriptionRequestProcessConfirmedAlarm()
self.tic()
for subscription_request in subscription_request_list:
self.assertTrue(
subscription_request.SubscriptionRequest_testPaymentBalance())
self.assertEqual('start_requested',
subscription_request.getAggregateValue().getSlapState())
self.checkStartedSubscriptionRequest(subscription_request,
default_email_text, self.subscription_condition)
def destroyAndCheckSubscription(self, default_email_text, subscription_server):
if self.skip_destroy_and_check:
return
subscription_request_list = self.getSubscriptionRequestList(
default_email_text, self.subscription_condition)
for subscription_request in subscription_request_list:
self.assertEqual('start_requested',
subscription_request.getAggregateValue().getSlapState())
# Destroy all instances and process
instance_tree = subscription_request.getAggregateValue()
instance_tree.InstanceTree_requestPerson('destroyed')
self.tic()
self.stepCallSlaposSubscriptionRequestProcessStartedAlarm()
self.tic()
self.checkStoppedSubscriptionRequest(subscription_request,
default_email_text, self.subscription_condition)
def _test_subscription_scenario(self, amount=1):
""" The admin creates an compute_node, user can request instances on it"""
self.subscription_server = self.createPublicServerForAdminUser()
# Call as anonymous... check response?
default_email_text = "abc%s@nexedi.com" % self.new_id
name="ABC %s" % self.new_id
self.requestAndCheckInstanceTree(
amount, name, default_email_text)
self.checkSubscriptionDeploymentAndSimulation(
default_email_text, self.subscription_server)
self.destroyAndCheckSubscription(
default_email_text, self.subscription_server
)
return default_email_text, name
def _test_subscription_scenario_with_existing_user(self, amount=1, language=None):
""" The admin creates an compute_node, user can request instances on it"""
# Call as anonymous... check response?
default_email_text = "abc%s@nexedi.com" % self.new_id
name="ABC %s" % self.new_id
project_reference = self.subscription_project.getReference()
self.login()
self.createNormalUser(default_email_text, name, language, self.subscription_project)
self.tic()
self.subscription_server = self.createPublicServerForAdminUser()
self.requestAndCheckInstanceTree(
amount, name, default_email_text)
self.checkSubscriptionDeploymentAndSimulation(
default_email_text, self.subscription_server)
subscription_request = self.getSubscriptionRequest(
default_email_text, self.subscription_condition)
self.assertEqual(self.normal_user,
subscription_request.getDestinationSectionValue())
self.destroyAndCheckSubscription(
default_email_text, self.subscription_server
)
return default_email_text, name
def _test_subscription_scenario_with_existing_user_with_non_subscription_request(self, amount=1, language=None):
# Call as anonymous... check response?
default_email_text = "abc%s@nexedi.com" % self.new_id
name="ABC %s" % self.new_id
self.login()
self.createNormalUser(default_email_text, name, language, self.subscription_project)
self.tic()
self.subscription_server = self.createPublicServerForAdminUser()
# Disable on this test the pricing on the template to not generate debt before
# them expected
supply_line = self.portal.sale_trade_condition_module.\
default_subscription_trade_condition.\
subscription_price_eur
previous_price = supply_line.getBasePrice()
supply_line.setBasePrice(0.0)
try:
self.login(self.normal_user.getUserId())
self.personRequestInstanceNotReady(
software_release=self.subscription_condition.getUrlString(),
software_type="default",
partition_reference="_test_subscription_scenario_with_existing_user_extra_instance",
project_reference=project_reference
)
self.non_subscription_related_instance_amount = 1
# Trigger open order creation
self.portal.portal_alarms.slapos_request_update_instance_tree_open_sale_order.activeSense()
self.tic()
self.login()
self.requestAndCheckInstanceTree(
amount, name, default_email_text)
self.checkSubscriptionDeploymentAndSimulation(
default_email_text, self.subscription_server)
subscription_request = self.getSubscriptionRequest(
default_email_text, self.subscription_condition)
self.assertEqual(self.normal_user,
subscription_request.getDestinationSectionValue())
self.destroyAndCheckSubscription(
default_email_text, self.subscription_server
)
finally:
supply_line.setPrice(previous_price)
return default_email_text, name
def _test_two_subscription_scenario(self, amount=1, create_invitation=False,
max_invoice_delay=0, max_invoice_credit_eur=0.0, max_invoice_credit_cny=0.0):
""" The admin creates an compute_node, user can request instances on it"""
self.subscription_server = self.createPublicServerForAdminUser()
# Call as anonymous... check response?
default_email_text = "abc%s@nexedi.com" % self.new_id
name="ABC %s" % self.new_id
if create_invitation:
self.login()
self.cloud_invitation_token = self.makeCloudInvitationToken(
max_invoice_delay=max_invoice_delay,
max_invoice_credit_eur=max_invoice_credit_eur,
max_invoice_credit_cny=max_invoice_credit_cny
)
self.logout()
user_input_dict = {
"name": name,
"amount" : amount}
self._requestSubscription(
subscription_reference=self.subscription_condition.getReference(),
user_input_dict=user_input_dict,
email=default_email_text,
confirmation_required=False)
self.login()
# I'm not sure if this is realistic
self.tic()
first_subscription_request = self.getSubscriptionRequest(
default_email_text, self.subscription_condition)
self.checkDraftSubscriptionRequest(first_subscription_request,
default_email_text, self.subscription_condition, amount=amount)
# Check Payment and pay it.
self.checkAndPaySubscriptionPayment([first_subscription_request])
self.tic()
# Call alarm to check payment and invoice and move foward to planned.
self.stepCallSlaposSubscriptionRequestProcessDraftAlarm()
self.tic()
self.checkPlannedSubscriptionRequest(first_subscription_request,
default_email_text, self.subscription_condition)
# Call alarm to mark subscription request as ordered, bootstrap the user
# and check if email is sent, once done move to ordered state.
self.stepCallSlaposSubscriptionRequestProcessPlannedAlarm()
self.tic()
self.checkOrderedSubscriptionRequest(first_subscription_request,
default_email_text, self.subscription_condition)
if create_invitation:
self.login()
self.cloud_invitation_token = self.makeCloudInvitationToken(
max_invoice_delay=max_invoice_delay,
max_invoice_credit_eur=max_invoice_credit_eur,
max_invoice_credit_cny=max_invoice_credit_cny
)
self.logout()
# Request a second one, without require confirmation and verifing
# the second subscription request
user_input_dict = {
"name": name,
"amount" : amount}
self._requestSubscription(
subscription_reference=self.subscription_condition.getReference(),
user_input_dict=user_input_dict,
email=default_email_text,
confirmation_required=False)
self.login()
self.tic()
second_subscription_request = [ i for i in self.getSubscriptionRequestList(
default_email_text, self.subscription_condition) if i.getSimulationState() == "draft"][0]
self.checkDraftSubscriptionRequest(second_subscription_request,
default_email_text, self.subscription_condition)
# Check Payment and pay it.
self.checkAndPaySubscriptionPayment([second_subscription_request])
self.tic()
# Call alarm to check payment and invoice and move foward to planned.
self.stepCallSlaposSubscriptionRequestProcessDraftAlarm()
self.tic()
self.checkPlannedSubscriptionRequest(second_subscription_request,
default_email_text, self.subscription_condition)
# Call alarm to mark subscription request as ordered, bootstrap the user
# and check if email is sent, once done move to ordered state.
self.stepCallSlaposSubscriptionRequestProcessPlannedAlarm()
self.tic()
self.checkOrderedSubscriptionRequest(second_subscription_request,
default_email_text, self.subscription_condition,
notification_message="subscription_request-confirmation-without-password")
# Call alarm to make the request of the instance?
self.stepCallSlaposSubscriptionRequestProcessOrderedAlarm()
self.tic()
# The alarms might be called multiple times for move each step
self.stepCallSlaposSubscriptionRequestProcessOrderedAlarm()
self.tic()
self.checkSubscriptionDeploymentAndSimulation(
default_email_text, self.subscription_server)
self.destroyAndCheckSubscription(
default_email_text, self.subscription_server
)
return default_email_text, name
def _test_subscription_scenario_with_reversal_transaction(self, amount=1):
""" The admin creates an compute_node, user can request instances on it"""
self.subscription_server = self.createPublicServerForAdminUser()
# Call as anonymous... check response?
default_email_text = "abc%s@nexedi.com" % self.new_id
name="ABC %s" % self.new_id
self.requestAndCheckInstanceTree(amount, name, default_email_text)
self.checkSubscriptionDeploymentAndSimulationWithReversalTransaction(
default_email_text, self.subscription_server)
self.destroyAndCheckSubscription(
default_email_text, self.subscription_server
)
return default_email_text, name
def _test_second_month_scenario(self, default_email_text):
subscription_request_list = self.getSubscriptionRequestList(
default_email_text, self.subscription_condition)
# Ensure periodicity is correct
for subscription_request in subscription_request_list:
instance_tree = subscription_request.getAggregateValue()
open_order_line = instance_tree.getAggregateRelatedValue(portal_type="Open Sale Order Line")
hosting_subscription = open_order_line.getAggregateValue(portal_type="Hosting Subscription")
self.assertEqual(hosting_subscription.getPeriodicityMonthDay(),
min(DateTime().day(), 28))
self.pinDateTime(DateTime(DateTime().asdatetime() + datetime.timedelta(days=17)))
self.addCleanup(self.unpinDateTime)
self._checkSecondMonthSimulation(subscription_request_list,
default_email_text, self.subscription_server)
self.skip_destroy_and_check = 0
self.destroyAndCheckSubscription(
default_email_text, self.subscription_server
)
class TestSlapOSSubscriptionScenario(TestSlapOSSubscriptionScenarioMixin):
def test_new_subscription_scenario_with_single_vm(self):
self._test_subscription_scenario(amount=1)
def test_subscription_scenario_with_single_vm(self):
self._test_subscription_scenario(amount=1)
def test_subscription_scenario_with_reversal_transaction(self):
self._test_subscription_scenario_with_reversal_transaction(amount=1)
def test_subscription_with_3_vms_scenario(self):
self._test_subscription_scenario(amount=3)
def test_two_subscription_scenario(self):
self._test_two_subscription_scenario(amount=1)
def test_subscription_scenario_with_existing_user(self):
self._test_subscription_scenario_with_existing_user(amount=1, language="en")
def test_subscription_scenario_with_existing_user_with_non_subscription_request(self):
self._test_subscription_scenario_with_existing_user_with_non_subscription_request(amount=1, language="en")
def test_subscription_scenario_with_existing_chinese_user(self):
# Messages are in english, when subscribed via english website. Even if the chinese language is
# defined at user level.
self._test_subscription_scenario_with_existing_user(amount=1, language="zh")
<?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>testSlapOSSubscriptionScenario</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>test.erp5.testSlapOSSubscriptionScenario</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>
# -*- coding:utf-8 -*-
##############################################################################
#
# Copyright (c) 2019 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
from erp5.component.test.testSlapOSSubscriptionChineseScenario import TestSlapOSSubscriptionChineseScenarioMixin
class testSlapOSSubscriptionSecondMonthPaymentScenario(TestSlapOSSubscriptionChineseScenarioMixin):
def test_subscription_scenario_with_single_vm(self):
self.skip_destroy_and_check = 1
default_email_text, _ = self._test_subscription_scenario(amount=1)
self._test_second_month_scenario(default_email_text)
def test_subscription_with_3_vms_scenario(self):
self.skip_destroy_and_check = 1
default_email_text, _ = self._test_subscription_scenario(amount=3)
self._test_second_month_scenario(default_email_text)
def test_subscription_scenario_with_reversal_transaction(self):
self.skip_destroy_and_check = 1
default_email_text, _ = self._test_subscription_scenario_with_reversal_transaction(amount=1)
self._test_second_month_scenario(default_email_text)
def test_two_subscription_scenario(self):
self.skip_destroy_and_check = 1
default_email_text, _ = self._test_two_subscription_scenario(amount=1)
self._test_second_month_scenario(default_email_text)
def test_subscription_scenario_with_existing_chienese_user(self):
self.skip_destroy_and_check = 1
default_email_text, _ = self._test_subscription_scenario_with_existing_user(amount=1, language="zh")
self._test_second_month_scenario(default_email_text)
def test_subscription_scenario_with_existing_english_user(self):
self.skip_destroy_and_check = 1
default_email_text, _ = self._test_subscription_scenario_with_existing_user(amount=1, language="en")
self._test_second_month_scenario(default_email_text)
def test_subscription_scenario_with_existing_user_with_non_subscription_request(self):
self.skip_destroy_and_check = 1
default_email_text, _ = \
self._test_subscription_scenario_with_existing_user_with_non_subscription_request(amount=1, language="zh")
self._test_second_month_scenario(default_email_text)
<?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>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>testSlapOSSubscriptionSecondMonthPaymentChineseScenario</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>test.erp5.testSlapOSSubscriptionSecondMonthPaymentChineseScenario</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">AAAAAAAAAAM=</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/>
</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>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<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>
# -*- coding:utf-8 -*-
##############################################################################
#
# Copyright (c) 2019 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
from erp5.component.test.testSlapOSSubscriptionScenario import TestSlapOSSubscriptionScenarioMixin
class testSlapOSSubscriptionSecondMonthPaymentScenario(TestSlapOSSubscriptionScenarioMixin):
def test_subscription_scenario_with_single_vm(self):
self.skip_destroy_and_check = 1
default_email_text, _ = self._test_subscription_scenario(amount=1)
self._test_second_month_scenario(default_email_text)
def test_subscription_with_3_vms_scenario(self):
self.skip_destroy_and_check = 1
default_email_text, _ = self._test_subscription_scenario(amount=3)
self._test_second_month_scenario(default_email_text)
def test_subscription_scenario_with_reversal_transaction(self):
self.skip_destroy_and_check = 1
default_email_text, _ = self._test_subscription_scenario_with_reversal_transaction(amount=1)
self._test_second_month_scenario(default_email_text)
def test_two_subscription_scenario(self):
self.skip_destroy_and_check = 1
default_email_text, _ = self._test_two_subscription_scenario(amount=1)
self._test_second_month_scenario(default_email_text)
def test_subscription_scenario_with_existing_chienese_user(self):
self.skip_destroy_and_check = 1
default_email_text, _ = self._test_subscription_scenario_with_existing_user(amount=1, language="zh")
self._test_second_month_scenario(default_email_text)
def test_subscription_scenario_with_existing_english_user(self):
self.skip_destroy_and_check = 1
default_email_text, _ = self._test_subscription_scenario_with_existing_user(amount=1, language="en")
self._test_second_month_scenario(default_email_text)
def test_subscription_scenario_with_existing_user_with_non_subscription_request(self):
self.skip_destroy_and_check = 1
default_email_text, _ = \
self._test_subscription_scenario_with_existing_user_with_non_subscription_request(amount=1, language="en")
self._test_second_month_scenario(default_email_text)
<?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>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>testSlapOSSubscriptionSecondMonthPaymentScenario</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>test.erp5.testSlapOSSubscriptionSecondMonthPaymentScenario</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">AAAAAAAAAAM=</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/>
</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>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<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>
test.erp5.testSlapOSERP5VirtualMasterSubscriptionRequestScenario
test.erp5.testSlapOSSubscriptionAlarm
test.erp5.testSlapOSSubscriptionCDNChineseScenario
test.erp5.testSlapOSSubscriptionCDNScenario
test.erp5.testSlapOSSubscriptionCancellationScenario
test.erp5.testSlapOSSubscriptionChineseScenario
test.erp5.testSlapOSSubscriptionDualOrganisationScenario
test.erp5.testSlapOSSubscriptionInvitationTokenChineseScenario
test.erp5.testSlapOSSubscriptionInvitationTokenScenario
test.erp5.testSlapOSSubscriptionNewTemplateChineseScenario
test.erp5.testSlapOSSubscriptionNewTemplateScenario
test.erp5.testSlapOSSubscriptionPerUserTradeConditionScenario
test.erp5.testSlapOSSubscriptionScenario
test.erp5.testSlapOSSubscriptionSecondMonthPaymentChineseScenario
test.erp5.testSlapOSSubscriptionSecondMonthPaymentScenario
test.erp5.testSlapOSSubscriptionSkins
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment