Commit 371645ab authored by Romain Courteaud's avatar Romain Courteaud

slapos_subscription_request: add testSlapOSERP5VirtualMasterSubscriptionRequestScenario

parent 41b77d45
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2022 Nexedi SA and Contributors. All Rights Reserved.
#
##############################################################################
from erp5.component.test.testSlapOSERP5VirtualMasterScenario import TestSlapOSVirtualMasterScenarioMixin
from DateTime import DateTime
class TestSlapOSVirtualMasterSubscriptionRequestScenario(TestSlapOSVirtualMasterScenarioMixin):
"""
def createAccountableProject(self):
# create a default project
project = self.addProject(is_accountable=True)
self.web_site = self.portal.web_site_module.slapos_master_panel
preference = self.portal.portal_preferences.slapos_default_system_preference
preference.edit(
preferred_subscription_assignment_category_list=[
'function/customer',
'role/client',
'destination_project/%s' % project.getRelativeUrl()
]
)
return project, self.web_site
"""
def createProjectAdministrator(self, project, web_site):
self.logout()
login = 'owner-%s' % self.generateNewId()
self.joinSlapOS(web_site, login)
self.login()
person = self.portal.portal_catalog.getResultValue(
portal_type="ERP5 Login",
reference=login).getParentValue()
# first slapos administrator assignment can only be created by
# the erp5 manager
self.addProjectProductionManagerAssignment(person, project)
self.tic()
return person
def createSoftwareProduct(self, project, person):
self.logout()
self.login(person.getUserId())
software_url = self.generateNewSoftwareReleaseUrl()
software_type = 'public type'
return self.addSoftwareProduct(
"instance product", project, software_url, software_type
)
def createPreparedComputeNode(self, project, person, software_product,
release_variation, type_variation):
self.logout()
self.login(person.getUserId())
server_title = 'Server for %s' % project.getReference()
server_id = self.requestComputeNode(server_title, project.getReference())
server = self.portal.portal_catalog.getResultValue(
portal_type='Compute Node', reference=server_id)
"""
self.setAccessToMemcached(server)
self.assertNotEqual(None, server)
self.setServerOpenPublic(server)"""
self.addAllocationSupply("for compute node", server, software_product,
release_variation, type_variation)
# and install some software on them
self.supplySoftware(server, release_variation.getUrlString())
# format the compute_nodes
self.formatComputeNode(server)
return server
def createSoftwareProductSaleSupply(self, software_product, price=9):
self.logout()
# XXX Use accountant account
self.login()
project = software_product.getFollowUpValue()
sale_supply = self.portal.sale_supply_module.newContent(
portal_type="Sale Supply",
destination_project_value=project,
price_currency_value=project.getSpecialiseValue().getPriceCurrencyValue()
)
# XXX Put price in sale supply module
sale_supply.newContent(
portal_type="Sale Supply Line",
base_price=price,
resource_value=software_product
)
sale_supply.validate()
def addSaleManagerAssignment(self, person):
person.newContent(
portal_type='Assignment',
function='function/sale/manager'
).open()
def createSaleAdministrator(self, web_site):
self.logout()
login = 'sale-%s' % self.generateNewId()
self.joinSlapOS(web_site, login)
self.login()
person = self.portal.portal_catalog.getResultValue(
portal_type="ERP5 Login",
reference=login).getParentValue()
# first slapos administrator assignment can only be created by
# the erp5 manager
self.addSaleManagerAssignment(person)
# Remove customer project assignment
#person.manage_delObjects(ids=[x.getId() for x in person.contentValues(portal_type="Assignment") if x.getFunction() == 'customer'])
self.tic()
return person
"""
def bootstrapInvoicingScenario(self):
# Done by ERP5 admin?
project, web_site = self.createAccountableProject()
# lets join as slapos administrator, which will own few compute_nodes
owner_person = self.createProjectAdministrator(project, web_site)
# create a software product
software_product, release_variation, type_variation = self.createSoftwareProduct(project, owner_person)
# create compute_nodes and prepare it
compute_node = self.createPreparedComputeNode(project, owner_person, software_product,
release_variation, type_variation)
# define price
self.createSoftwareProductSaleSupply(software_product)
return project, web_site, software_product, release_variation, type_variation, compute_node
"""
def createProjectCustomer(self, web_site):
# join as the another visitor and request software instance on public
# compute_node
self.logout()
login = 'customer-%s' % self.generateNewId()
self.joinSlapOS(web_site, login)
self.login()
person = self.portal.portal_catalog.getResultValue(
portal_type="ERP5 Login",
reference=login).getParentValue()
return person, login
def bootstrapSubscriptionRequestScenario(self):
# Done by ERP5 admin?
# XXX XXX to drop. First project is created on UI
self.web_site = self.portal.web_site_module.slapos_master_panel
web_site = self.web_site
sale_person = self.createSaleAdministrator(web_site)
currency = self.portal.currency_module.newContent(
portal_type='Currency',
title="fake currency"
)
currency.validate()
return web_site, currency, sale_person
def test_virtual_master_subscribe_to_project(self):
_, currency, sale_person = self.bootstrapSubscriptionRequestScenario()
self.tic()
#################################
# Prepare saling virtual master
#################################
self.logout()
self.login(sale_person.getUserId())
now = DateTime()
seller_organisation = self.portal.organisation_module.newContent(
portal_type="Organisation",
title="seller-orga"
)
seller_organisation.validate()
sale_person.setCareerSubordinationValue(seller_organisation)
internal_trade_condition = self.portal.sale_trade_condition_module.newContent(
portal_type="Sale Trade Condition",
reference='internal_for_%s' % seller_organisation.getTitle(),
# XXX hardcoded
specialise="business_process_module/slapos_ultimate_business_process",
source_value=seller_organisation,
source_section_value=seller_organisation,
destination_section_value=seller_organisation,
effective_date=now.earliestTime(),
price_currency_value=currency
)
internal_trade_condition.validate()
"""
virtual_master_sale_supply = self.portal.sale_supply_module.newContent(
portal_type="Sale Supply"
)
virtual_master_sale_supply.validate()
"""
self.tic()
#################################
# Buy the first project
#################################
# XXX How to list possible service to sell?
# Search product with `time` unit ?
service = self.portal.restrictedTraverse('service_module/slapos_virtual_master_subscription')
# XXX This is a script like: Product_submitSubscriptionRequest()
source_decision_value = self.portal.portal_membership.getAuthenticatedMember().getUserValue()
source_section_value = seller_organisation#source_decision_value#source_decision_value.getCareerSubordinationValue() or source_decision_value
source_section_value = source_decision_value.getCareerSubordinationValue(source_decision_value)
# Find trade condition / price
order_portal_type = 'Sale Order'
line_portal_type = 'Sale Order Line'
#cell_portal_type = 'Sale Order Cell'
#base_id = 'movement'
module = self.portal.sale_order_module
temp_order = 1
#aggregate_value_list = []
open_sale_order = module.newContent(
portal_type=order_portal_type,
temp_object=temp_order,
#effective_date=now+1,
start_date=now,
# Ensure stop date value is higher than start date
# it will be updated by OpenSaleOrder_updatePeriod
# stop_date=now + 2,
destination_value=source_decision_value,
destination_section_value=source_section_value,
#destination_decision_value=source_decision_value,
ledger_value=self.portal.portal_categories.ledger.automated,
# XXX XXX destination_project_value=instance_tree.getFollowUpValue(),
)
"""
resource_vcl = [
'software_release/%s' % software_release.getRelativeUrl(),
'software_type/%s' % software_type.getRelativeUrl()
]
resource_vcl.sort()
assert len(resource_vcl) == 2, service
"""
# Add lines
open_order_line = open_sale_order.newContent(
portal_type=line_portal_type,
temp_object=temp_order,
resource_value=service,
#variation_category_list=resource_vcl,
quantity_unit=service.getQuantityUnit(),
base_contribution_list=service.getBaseContributionList(),
use=service.getUse(),
# stop_date=calculateOpenOrderLineStopDate(open_sale_order_line,
# instance_tree, start_date_delta=start_date_delta),
#activate_kw=activate_kw
quantity=1
)
"""
subscription_request = instance_tree.getAggregateRelatedValue(portal_type="Subscription Request")
# Define the start date of the period, this can variates with the time.
# start_date_delta = 0
if subscription_request is not None:
# Quantity is double because the first invoice has to
# charge for 2 months
edit_kw['quantity'] = subscription_request.getQuantity()
"""
"""
cell_key = list(open_order_line.getCellKeyList(base_id=base_id))[0]
open_order_cell = open_order_line.newCell(
base_id=base_id,
portal_type=cell_portal_type,
temp_object=temp_order,
*cell_key
)
open_order_cell.edit(
mapped_value_property_list=['price','quantity'],
quantity=1,
predicate_category_list=cell_key,
variation_category_list=cell_key,
aggregate_value_list=aggregate_value_list,
activate_kw=activate_kw
)
"""
open_sale_order.SaleOrder_applySaleTradeCondition(batch_mode=1, force=1)
price = open_order_line.getPrice()
open_order_line.edit(
price=price
)
subscription_request = self.portal.subscription_request_module.newContent(
portal_type='Subscription Request',
source_value=source_decision_value,
source_section_value=source_section_value,
source_decision_value=source_decision_value,
start_date=now,
effective_date=now,
resource_value=service,
quantity_unit_value=open_order_line.getQuantityUnitValue(),
ledger="automated",
specialise_value=open_sale_order.getSpecialiseValue(),
destination_value=open_sale_order.getSourceValue(),
destination_section_value=open_sale_order.getSourceSectionValue(),
price_currency_value=open_sale_order.getPriceCurrencyValue()
)
"""
invoicing_type=invoicing_type,
number_tag=number_tag,
number_clip=number_clip,
insured_vehicle_count=insured_vehicle_count,
license_plate_number_list=license_plate_number_list,
free_subscription_dict_json=dumps(free_subscription_dict_json),
promotion_code=promotion_code,
member_reference=member_reference,
role=role,
company_title=company_title,
vat_code=vat_code,
social_title=social_title,
first_name=first_name,
last_name=last_name,
date_of_birth=date_of_birth,
default_email_text=default_email_text,
mobile_telephone_telephone_country=mobile_telephone_telephone_country,
mobile_telephone_telephone_number=mobile_telephone_text,
default_telephone_telephone_country=default_telephone_telephone_country,
default_address_zip_code=default_address_zip_code,
default_address_street_address='\n'.join((default_address_text2, default_address_text3, default_address_text1, default_address_text4)),
default_address_city=default_address_city,
default_address_region=default_address_region or None,
language=language,
client_address=request.getClientAddr(),
destination_reference=destination_reference,
accept_opteven_info=accept_opteven_info,
delivery_mode=delivery_mode,
price_list_json=dumps(price_list),
source_reference=tag_reference, # to lookup by catalog
pack_reference=pack_reference,
# Following fields are hidden and autocompleted by DQE result.
# So it is not passed in the parameters and we read it be REQUEST form
default_address_autocompleted=bool(int(request_form.get('field_your_default_address_autocompleted', "0"))),
delivery_address_autocompleted=has_delivery_address and bool(int(request_form.get('field_your_delivery_address_autocompleted', "0"))),
)
"""
subscription_request.submit()
self.tic()
#payment_transaction = None
self.logout()
self.login()
#################################
# Alarm / Sale Person validate the request
#################################
item = self.portal.project_module.newContent(
portal_type="Project",
title="new title",
)
item.validate()
subscription_request.getSourceDecisionValue().newContent(
portal_type="Assignment",
destination_project_value=item,
function='production/manager'
).open()
hosting_subscription = self.portal.hosting_subscription_module.newContent(
portal_type="Hosting Subscription",
title="hosting %s" % item.getTitle(),
#follow_up_value=instance_tree.getFollowUpValue(),
ledger_value=self.portal.portal_categories.ledger.automated,
)
hosting_subscription.validate()
start_date = hosting_subscription.HostingSubscription_calculateSubscriptionStartDate()
open_sale_order = self.portal.open_sale_order_module.newContent(
portal_type="Open Sale Order",
start_date=start_date,
# Ensure stop date value is higher than start date
# it will be updated by OpenSaleOrder_updatePeriod
stop_date=start_date + 1,
specialise_value=subscription_request.getSpecialiseValue(),
destination_value=subscription_request.getSourceValue(),
destination_section_value=subscription_request.getSourceSectionValue(),
destination_decision_value=subscription_request.getSourceDecisionValue(),
ledger_value=self.portal.portal_categories.ledger.automated,
causality_value=subscription_request
)
open_sale_order.SaleOrder_applySaleTradeCondition(batch_mode=1)
# Add lines
service = subscription_request.getResourceValue()
open_order_line = open_sale_order.newContent(
portal_type="Open Sale Order Line",
resource_value=service,
#variation_category_list=resource_vcl,
quantity_unit_value=subscription_request.getQuantityUnitValue(),
base_contribution_list=service.getBaseContributionList(),
use=service.getUse(),
# stop_date=calculateOpenOrderLineStopDate(open_sale_order_line,
# instance_tree, start_date_delta=start_date_delta),
#activate_kw=activate_kw
quantity=1,
price=subscription_request.getPrice(),
aggregate_value_list=[
hosting_subscription,
item
]
)
open_sale_order.plan()
open_sale_order.validate()
subscription_request.validate()
"""
payment_transaction = self.portal.accounting_module.newContent(
portal_type='Payment Transaction',
#start_date=context.getStopDate(),
#resource='currency_module/EUR',
#source_section=sanef_fr_relative_url,
#source_payment_value=bank_account,
causality_value=subscription_request,
#specialise_value=direct_debit_mandate,
# destination_section_value=customer,
#destination_payment=direct_debit_mandate.getSourcePayment(),
#payment_mode='direct_debit',
ledger="automated",
created_by_builder=1, # XXX this prevent init script from creating lines.
#activate_kw={'tag':'%s_init' % context.getDestinationReference()}
)
"""
"""
getAccountForUse = context.Base_getAccountForUse
# receivable
payment_transaction.newContent(
id='receivable',
portal_type='Accounting Transaction Line',
quantity=total_price,
source_value=getAccountForUse('asset_receivable_subscriber'),
)
# bank
payment_transaction.newContent(
id='bank',
portal_type='Accounting Transaction Line',
quantity=-total_price,
source_value=getAccountForUse('collection'),
aggregate_value=payment_transaction_group_value,
)
tag = '%s_update' % context.getDestinationReference()
payment_transaction.confirm(activate_kw={'tag': tag})
payment_transaction.activate(after_tag=tag).stop()
"""
#assert payment_transaction is not None
#################################
# And finally, allow customer to buy a virtual master
#################################
# virtual master subscription is NOT PUBLIC (too complex for anonymous?)
"""
customer, _ = self.createProjectCustomer(web_site)
self.logout()
self.login(customer.getUserId())
"""
self.logout()
for _ in range(20):
self.stepCallAlarmList()
self.tic()
self.login()
self.stepcheckERP5Consistency()
# after accept, an email is send containing the reset link
last_message = self.portal.MailHost._last_message
assert last_message is None, last_message
\ 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>default_reference</string> </key>
<value> <string>testSlapOSERP5VirtualMasterSubscriptionRequestScenario</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.testSlapOSERP5VirtualMasterSubscriptionRequestScenario</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>
test.erp5.testSlapOSERP5VirtualMasterSubscriptionRequestScenario
test.erp5.testSlapOSSubscriptionAlarm
test.erp5.testSlapOSSubscriptionSkins
test.erp5.testSlapOSSubscriptionScenario
test.erp5.testSlapOSSubscriptionCDNChineseScenario
test.erp5.testSlapOSSubscriptionCDNScenario
test.erp5.testSlapOSSubscriptionCancellationScenario
test.erp5.testSlapOSSubscriptionChineseScenario
test.erp5.testSlapOSSubscriptionNewTemplateScenario
test.erp5.testSlapOSSubscriptionNewTemplateChineseScenario
test.erp5.testSlapOSSubscriptionInvitationTokenScenario
test.erp5.testSlapOSSubscriptionInvitationTokenChineseScenario
test.erp5.testSlapOSSubscriptionSecondMonthPaymentScenario
test.erp5.testSlapOSSubscriptionSecondMonthPaymentChineseScenario
test.erp5.testSlapOSSubscriptionDualOrganisationScenario
test.erp5.testSlapOSSubscriptionCancellationScenario
test.erp5.testSlapOSSubscriptionCDNScenario
test.erp5.testSlapOSSubscriptionCDNChineseScenario
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