Commit 3aca11ec authored by Rafael Monnerat's avatar Rafael Monnerat

Pay deposity for payable subscription requests

See merge request !629
parents 0941e532 cb300deb
from zExceptions import Unauthorized
if REQUEST is not None:
raise Unauthorized
from DateTime import DateTime
from Products.ERP5Type.Message import translateString
portal = context.getPortalObject()
if not subscription_list:
raise ValueError('You need to provide at least one Subscription Request')
payment_tag = 'Entity_addDepositPayment_%s' % context.getUid()
if context.REQUEST.get(payment_tag, None) is not None:
raise ValueError('This script was already called twice on the same transaction ')
activate_kw = {
'tag': payment_tag
}
# Ensure all invoice use the same arrow and resource
first_subscription = subscription_list[0]
identical_dict = {
'getSource': first_subscription.getSource(),
'getSourceSection': first_subscription.getSourceSection(),
'getDestinationSection': first_subscription.getDestinationSection(),
'getPriceCurrency': first_subscription.getPriceCurrency(),
'getLedger': first_subscription.getLedger(),
}
price = 0
for subscription in subscription_list:
for method_id, method_value in identical_dict.items():
if getattr(subscription, method_id)() != method_value:
raise ValueError('Subscription Requests do not match on method: %s' % method_id)
if subscription.total_price:
price += subscription.total_price
# Simulation state
if not subscription.isTempObject() and subscription.getSimulationState() != "submitted":
raise ValueError('Not on submitted state')
if subscription.getPortalType() != "Subscription Request":
raise ValueError('Not an Subscription Request')
if not price:
raise ValueError("No price to to pay")
if first_subscription.getDestinationSection() != context.getRelativeUrl():
raise ValueError("Subscription not related to the context")
######################################################
# Find Sale Trade Condition
source_section = context
currency_relative_url = first_subscription.getPriceCurrency()
ledger_relative_url = first_subscription.getLedger()
# Create a temp Sale Order to calculate the real price and find the trade condition
now = DateTime()
module = portal.portal_trash
tmp_sale_order = module.newContent(
portal_type='Sale Order',
temp_object=True,
trade_condition_type="deposit",
start_date=now,
source=first_subscription.getSource(),
source_section=first_subscription.getSourceSection(),
destination_value=source_section,
destination_section_value=source_section,
destination_decision_value=source_section,
ledger_value=portal.portal_categories.ledger.automated,
ledger=ledger_relative_url,
price_currency=currency_relative_url
)
tmp_sale_order.SaleOrder_applySaleTradeCondition(batch_mode=1, force=1)
......@@ -36,14 +84,20 @@ if (tmp_sale_order.getSourceSection(None) == tmp_sale_order.getDestinationSectio
(tmp_sale_order.getSourceSection(None) is None):
raise AssertionError('The trade condition does not generate accounting: %s' % tmp_sale_order.getSpecialise())
#######################################################
payment_transaction = portal.accounting_module.newContent(
# The payment needs to be returned on web site context, to proper handle acquisition later on
# otherwise, payment redirections would fail on multiple occasions whenever website isn't in
# the context acquisition.
web_site = context.getWebSiteValue()
if web_site is None:
web_site = portal
# preserve the capability to call payment_transaction.getWebSiteValue() and get the current website back.
payment_transaction = web_site.accounting_module.newContent(
title="reservation payment",
portal_type="Payment Transaction",
start_date=now,
stop_date=now,
specialise_value=tmp_sale_order.getSpecialiseValue(),
source=tmp_sale_order.getSource(),
source_section=tmp_sale_order.getSourceSection(),
......@@ -53,11 +107,11 @@ payment_transaction = portal.accounting_module.newContent(
destination_section=tmp_sale_order.getDestinationSection(),
destination_decision=tmp_sale_order.getDestinationDecision(),
destination_project=tmp_sale_order.getDestinationProject(),
ledger_value=portal.portal_categories.ledger.automated,
payment_mode=payment_mode,
ledger_value=ledger_relative_url,
resource=tmp_sale_order.getPriceCurrency(),
created_by_builder=1, # XXX this prevent init script from creating lines.
activate_kw={'tag':'%s_init' % context.getRelativeUrl()}
activate_kw=activate_kw
)
getAccountForUse = context.Base_getAccountForUse
......@@ -68,7 +122,8 @@ payment_transaction.newContent(
portal_type='Accounting Transaction Line',
quantity=price,
source_value=getAccountForUse('asset_receivable_subscriber'),
destination_value=getAccountForUse('payable')
destination_value=getAccountForUse('payable'),
activate_kw=activate_kw
)
# bank
......@@ -78,15 +133,16 @@ payment_transaction.newContent(
portal_type='Accounting Transaction Line',
quantity=-price,
source_value=collection_account,
destination_value=collection_account
destination_value=collection_account,
activate_kw=activate_kw
)
if len(payment_transaction.checkConsistency()) != 0:
raise AssertionError(payment_transaction.checkConsistency()[0])
#tag = '%s_update' % context.getDestinationReference()
payment_transaction.start(comment=translateString("Deposit payment."))
comment = translateString("Deposit payment.")
payment_transaction.start(comment=comment)
# Set a flag on the request for prevent 2 calls on the same transaction
context.REQUEST.set(payment_tag, 1)
return payment_transaction
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>subscription_list, payment_mode=None, REQUEST=None</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Entity_createDepositPaymentTransaction</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -90,7 +90,8 @@ for index, line in enumerate(invoice_list):
activate_kw=activate_kw,
)
assert len(payment_transaction.checkConsistency()) == 0
if len(payment_transaction.checkConsistency()) != 0:
raise AssertionError(payment_transaction.checkConsistency()[0])
payment_transaction.start()
......
portal = context.getPortalObject()
# Ensure all invoice use the same arrow and resource
first_subscription = subscription_list[0]
identical_dict = {
'getSourceSection': first_subscription.getSourceSection(),
'getDestinationSection': first_subscription.getDestinationSection(),
'getPriceCurrency': first_subscription.getPriceCurrency(),
'getLedger': first_subscription.getLedger(),
}
for subscription in subscription_list:
for method_id, method_value in identical_dict.items():
if getattr(subscription, method_id)() != method_value:
raise ValueError('Subscription Requests do not match on method: %s' % method_id)
if subscription.getPortalType() != "Subscription Request":
raise ValueError('Not an Subscription Request')
assert_price_kw = {
'resource_uid': first_subscription.getPriceCurrencyUid(),
'portal_type': portal.getPortalAccountingMovementTypeList(),
'ledger_uid': first_subscription.getLedgerUid(),
}
if first_subscription.getDestinationSection() != context.getRelativeUrl():
raise ValueError("Subscription not related to the context")
# entity is the depositor
# mirror_section_uid is the payee/recipient
entity_uid = context.getUid()
mirror_section_uid = first_subscription.getSourceSectionUid()
# Total received
deposit_amount = portal.portal_simulation.getInventoryAssetPrice(
section_uid=entity_uid,
mirror_section_uid=mirror_section_uid,
mirror_node_uid=portal.restrictedTraverse('account_module/deposit_received').getUid(),
#node_category_strict_membership=['account_type/income'],
simulation_state= ('stopped', 'delivered'),
# Do not gather deposit reimburse
# when it does not yet have a grouping_reference
omit_asset_decrease=1,
grouping_reference=None,
**assert_price_kw
)
# Total reserved
payable_amount = portal.portal_simulation.getInventoryAssetPrice(
mirror_section_uid=entity_uid,
section_uid=mirror_section_uid,
# Do not gather deposit receivable
# when it does not yet have a grouping_reference
omit_asset_decrease=1,
node_category_strict_membership=['account_type/asset/receivable',
'account_type/liability/payable'],
simulation_state= ('planned', 'confirmed', 'started', 'stopped', 'delivered'),
grouping_reference=None,
**assert_price_kw
)
return deposit_amount - payable_amount
......@@ -50,11 +50,11 @@
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>price, currency_relative_url, batch=0</string> </value>
<value> <string>subscription_list, **kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Person_addDepositPayment</string> </value>
<value> <string>Entity_getDepositBalanceAmount</string> </value>
</item>
</dictionary>
</pickle>
......
portal = context.getPortalObject()
query_kw = {
"portal_type": "Subscription Request",
"simulation_state": "submitted"
}
if section_uid:
query_kw['source_section__uid'] = section_uid
if ledger_uid:
query_kw['ledger__uid'] = ledger_uid
if resource_uid is not None:
query_kw['price_currency__uid'] = resource_uid
object_dict = {}
for subscription_request_brain in portal.portal_catalog(
destination_section__uid=context.getUid(),
**query_kw):
subscription_request = subscription_request_brain.getObject()
subscription_request_total_price = subscription_request.getTotalPrice()
if 0 < subscription_request_total_price:
currency_uid = subscription_request.getPriceCurrencyUid()
# Future proof in case we implement B2B payment
object_index = "%s_%s_%s" % (
currency_uid,
subscription_request.getSourceSection(),
subscription_request.getLedger())
if object_index not in object_dict:
object_dict[object_index] = [subscription_request, subscription_request_total_price]
else:
subscription_request_total_price += object_dict[object_index][1]
object_dict[object_index] = [object_dict[object_index][0],
subscription_request_total_price]
return [s.asContext(total_price=price) for s, price in object_dict.values()]
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>resource_uid=None, section_uid=None, ledger_uid=None,**kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Entity_getOutstandingDepositAmountList</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -34,6 +34,34 @@ from zExceptions import Unauthorized
class TestSlapOSAccounting(SlapOSTestCaseMixin):
def createIntegrationSite(self):
# Include a simple Integration site, which is required for
# PaymentTransaction_generatePayzenId
integration_site = self.portal.portal_integrations.newContent(
title="Integration site for test_AccountingTransaction_getPaymentState_payzen_waiting_payment",
reference="payzen",
portal_type="Integration Site"
)
integration_site.newContent(
id="Causality",
portal_type="Integration Base Category Mapping",
default_source_reference="Causality",
default_destination_reference="causality"
)
resource_map = integration_site.newContent(
id="Resource",
portal_type="Integration Base Category Mapping",
default_source_reference="Resource",
default_destination_reference="resource"
)
resource_map.newContent(
id='978',
portal_type="Integration Category Mapping",
default_destination_reference='resource/currency_module/EUR',
default_source_reference='978'
)
return integration_site
def createHostingSubscription(self):
new_id = self.generateNewId()
return self.portal.hosting_subscription_module.newContent(
......@@ -153,16 +181,32 @@ class TestSlapOSAccounting(SlapOSTestCaseMixin):
causality_value=invoice,
destination=invoice.getDestination(),
destination_section=invoice.getDestinationSection(),
created_by_builder=1 # to prevent init script to create lines
created_by_builder=1 # to prevent init script to create lines
)
self.portal.portal_workflow._jumpToStateFor(payment, 'started')
self.tic()
payment.PaymentTransaction_generatePayzenId()
self.assertRaises(
ValueError,
invoice.SaleInvoiceTransaction_createReversalSaleInvoiceTransaction,
batch_mode=1)
system_preference = self.portal.portal_preferences.slapos_default_system_preference
older_integration_site = system_preference.getPreferredPayzenIntegrationSite()
integration_site = self.createIntegrationSite()
system_preference.setPreferredPayzenIntegrationSite(
integration_site.getRelativeUrl()
)
try:
self.tic()
payment.PaymentTransaction_generatePayzenId()
self.assertRaises(
ValueError,
invoice.SaleInvoiceTransaction_createReversalSaleInvoiceTransaction,
batch_mode=1)
finally:
self.portal.portal_integrations.manage_delObjects(
ids=[integration_site.getId()])
system_preference.setPreferredPayzenIntegrationSite(
older_integration_site
)
@withAbort
def test_createReversalSaleInvoiceTransaction_ok(self, payment_mode='payzen'):
......@@ -388,19 +432,35 @@ class TestSlapOSAccounting(SlapOSTestCaseMixin):
causality_value=invoice,
destination=invoice.getDestination(),
destination_section=invoice.getDestinationSection(),
created_by_builder=1 # to prevent init script to create lines
created_by_builder=1 # to prevent init script to create lines
)
self.portal.portal_workflow._jumpToStateFor(payment, 'started')
payment.PaymentTransaction_generatePayzenId()
self.tic()
self.login(person.getUserId())
self.assertEqual("Waiting for payment confirmation",
system_preference = self.portal.portal_preferences.slapos_default_system_preference
older_integration_site = system_preference.getPreferredPayzenIntegrationSite()
integration_site = self.createIntegrationSite()
system_preference.setPreferredPayzenIntegrationSite(
integration_site.getRelativeUrl()
)
try:
payment.PaymentTransaction_generatePayzenId()
self.tic()
self.login(person.getUserId())
self.assertEqual("Waiting for payment confirmation",
invoice.AccountingTransaction_getPaymentState())
finally:
self.portal.portal_integrations.manage_delObjects(
ids=[integration_site.getId()])
system_preference.setPreferredPayzenIntegrationSite(
older_integration_site
)
def test_AccountingTransaction_getPaymentState_wechat_waiting_payment(self):
project = self.addProject()
person = self.makePerson(project)
invoice = self.createStoppedSaleInvoiceTransaction(
invoice = self.createStoppedSaleInvoiceTransaction(
destination_section_value=person,
payment_mode='wechat')
......
......@@ -17,7 +17,7 @@ class TestSlapOSAccountingScenario(TestSlapOSVirtualMasterScenarioMixin):
User does not pay the subscription, which is cancelled after some time
"""
with PinnedDateTime(self, DateTime('2020/05/19')):
owner_person, currency, project = self.bootstrapAccountingTest()
owner_person, _, project = self.bootstrapAccountingTest()
# Ensure no unexpected object has been created
# 2 assignment
# 2 sale trade condition
......@@ -32,9 +32,14 @@ class TestSlapOSAccountingScenario(TestSlapOSVirtualMasterScenarioMixin):
aggregate__uid=project.getUid()
)
self.assertEqual(subscription_request.getSimulationState(), "submitted")
deposit_outstanding_amount_list = owner_person.Entity_getOutstandingDepositAmountList()
self.assertEqual(len(deposit_outstanding_amount_list), 1)
self.assertEqual(subscription_request.getUid(),
deposit_outstanding_amount_list[0].getUid())
with PinnedDateTime(self, DateTime('2021/04/04')):
payment_transaction = owner_person.Person_addDepositPayment(99*10, currency.getRelativeUrl(), 1)
payment_transaction = owner_person.Entity_createDepositPaymentTransaction(
deposit_outstanding_amount_list)
# payzen interface will only stop the payment
payment_transaction.stop()
self.tic()
......@@ -209,9 +214,24 @@ class TestSlapOSAccountingScenario(TestSlapOSVirtualMasterScenarioMixin):
# Add deposit
with PinnedDateTime(self, creation_date + 2):
for person in person_list:
payment_transaction = person.Person_addDepositPayment(99*100, currency.getRelativeUrl(), 1)
# Just add some large sum, so instances dont get blocked.
tmp_subscription_request = self.portal.portal_trash.newContent(
portal_type='Subscription Request',
temp_object=True,
start_date=DateTime(),
# source_section rely on default trade condition, like the rest.
destination_value=person,
destination_section_value=person,
ledger_value=self.portal.portal_categories.ledger.automated,
price_currency=currency.getRelativeUrl(),
total_price=99 * 10
)
payment_transaction = person.Entity_createDepositPaymentTransaction(
[tmp_subscription_request])
# payzen interface will only stop the payment
payment_transaction.stop()
self.tic()
##################################################
# Add first batch of service, and generate invoices
......@@ -299,7 +319,7 @@ class TestSlapOSAccountingScenario(TestSlapOSVirtualMasterScenarioMixin):
"""
creation_date = DateTime('2020/02/19')
with PinnedDateTime(self, creation_date):
owner_person, currency, project = self.bootstrapAccountingTest()
owner_person, _, project = self.bootstrapAccountingTest()
owner_person.edit(default_address_region='america/south/brazil')
# Ensure no unexpected object has been created
......@@ -310,10 +330,16 @@ class TestSlapOSAccountingScenario(TestSlapOSVirtualMasterScenarioMixin):
##################################################
# Add deposit (0.1 to prevent discount generation)
deposit_outstanding_amount_list = owner_person.Entity_getOutstandingDepositAmountList()
self.assertEqual(len(deposit_outstanding_amount_list), 1)
self.assertEqual(sum([i.total_price for i in deposit_outstanding_amount_list]), 42)
with PinnedDateTime(self, creation_date + 0.1):
payment_transaction = owner_person.Person_addDepositPayment(99*100, currency.getRelativeUrl(), 1)
payment_transaction = owner_person.Entity_createDepositPaymentTransaction(
deposit_outstanding_amount_list)
# payzen interface will only stop the payment
payment_transaction.stop()
self.tic()
self.logout()
self.login()
......
......@@ -245,14 +245,6 @@
<key> <string>preferred_password_lifetime_expire_warning_duration</string> </key>
<value> <int>336</int> </value>
</item>
<item>
<key> <string>preferred_payzen_integration_site</string> </key>
<value> <string>portal_integrations/slapos_payzen_test_integration</string> </value>
</item>
<item>
<key> <string>preferred_payzen_payment_service_reference</string> </key>
<value> <string>PSERV-Payzen-Test</string> </value>
</item>
<item>
<key> <string>preferred_registration_resource</string> </key>
<value> <string>service_module/vifib_registration</string> </value>
......
......@@ -581,15 +581,17 @@ class DefaultScenarioMixin(TestSlapOSSecurityMixin):
if q.getTitle() == instance_title]
self.assertEqual(0, len(instance_tree_list))
def checkServiceSubscriptionRequest(self, service):
def checkServiceSubscriptionRequest(self, service, simulation_state='invalidated'):
self.login()
subscription_request = self.portal.portal_catalog.getResultValue(
portal_type="Subscription Request",
aggregate__uid=service.getUid(),
simulation_state='invalidated'
simulation_state=simulation_state
)
self.assertNotEqual(subscription_request, None)
self.assertNotEqual(subscription_request, None,
"Not found subscription request for %s" % service.getRelativeUrl())
return subscription_request
def checkInstanceAllocation(self, person_user_id, person_reference,
instance_title, software_release, software_type, server,
......@@ -644,6 +646,96 @@ class DefaultScenarioMixin(TestSlapOSSecurityMixin):
partition.contentValues(portal_type='Internet Protocol Address')],
connection_dict.values())
def checkInstanceAllocationWithDeposit(self, person_user_id, person_reference,
instance_title, software_release, software_type, server,
project_reference, deposit_amount, currency):
self.login(person_user_id)
self.personRequestInstanceNotReady(
software_release=software_release,
software_type=software_type,
partition_reference=instance_title,
project_reference=project_reference
)
self.tic()
instance_tree = self.portal.portal_catalog.getResultValue(
portal_type="Instance Tree",
title=instance_title,
follow_up__reference=project_reference
)
person = instance_tree.getDestinationSectionValue()
self.assertEqual(person.getUserId(), person_user_id)
subscription_request = self.checkServiceSubscriptionRequest(instance_tree, 'submitted')
self.assertEqual(subscription_request.getTotalPrice(), deposit_amount)
self.tic()
outstanding_amount_list = person.Entity_getOutstandingDepositAmountList(
currency.getUid(), ledger_uid=subscription_request.getLedgerUid())
self.assertEqual(sum([i.total_price for i in outstanding_amount_list]), deposit_amount)
self.login(person.getUserId())
# Ensure to pay from the website
outstanding_amount = self.web_site.restrictedTraverse(outstanding_amount_list[0].getRelativeUrl())
outstanding_amount.Base_createExternalPaymentTransactionFromOutstandingAmountAndRedirect()
self.tic()
self.logout()
self.login()
payment_transaction = self.portal.portal_catalog.getResultValue(
portal_type="Payment Transaction",
destination_section_uid=person.getUid(),
simulation_state="started"
)
self.assertEqual(payment_transaction.getSpecialiseValue().getTradeConditionType(), "deposit")
# payzen interface will only stop the payment
payment_transaction.stop()
self.tic()
assert payment_transaction.receivable.getGroupingReference(None) is not None
self.login(person_user_id)
self.checkServiceSubscriptionRequest(instance_tree, 'invalidated')
amount = sum([i.total_price for i in person.Entity_getOutstandingDepositAmountList(
currency.getUid(), ledger_uid=subscription_request.getLedgerUid())])
self.assertEqual(0, amount)
self.login(person_user_id)
self.personRequestInstance(
software_release=software_release,
software_type=software_type,
partition_reference=instance_title,
project_reference=project_reference
)
# now instantiate it on compute_node and set some nice connection dict
self.simulateSlapgridCP(server)
# let's find instances of user and check connection strings
instance_tree_list = [q.getObject() for q in
self._getCurrentInstanceTreeList()
if q.getTitle() == instance_title]
self.assertEqual(1, len(instance_tree_list))
instance_tree = instance_tree_list[0]
software_instance = instance_tree.getSuccessorValue()
self.assertEqual(software_instance.getTitle(),
instance_tree.getTitle())
connection_dict = software_instance.getConnectionXmlAsDict()
self.assertSameSet(('url_1', 'url_2'), connection_dict.keys())
self.login()
partition = software_instance.getAggregateValue()
self.assertSameSet(
['http://%s/' % q.getIpAddress() for q in
partition.contentValues(portal_type='Internet Protocol Address')],
connection_dict.values())
def findMessage(self, email, body):
for candidate in reversed(self.portal.MailHost.getMessageList()):
if [q for q in candidate[1] if email in q] and body in candidate[2]:
......
......@@ -56,9 +56,38 @@ class TestSlapOSCRMScenario(TestSlapOSVirtualMasterScenarioMixin):
##################################################
# Add deposit
with PinnedDateTime(self, creation_date):
payment_transaction = owner_person.Person_addDepositPayment(99*100, currency.getRelativeUrl(), 1)
# payzen interface will only stop the payment
# Pay deposit to validate virtual master
self.login(owner_person.getUserId())
deposit_amount = 42.0
ledger = self.portal.portal_categories.ledger.automated
outstanding_amount_list = owner_person.Entity_getOutstandingDepositAmountList(
currency.getUid(), ledger_uid=ledger.getUid())
amount = sum([i.total_price for i in outstanding_amount_list])
self.assertEqual(amount, deposit_amount)
# Ensure to pay from the website
outstanding_amount = self.web_site.restrictedTraverse(outstanding_amount_list[0].getRelativeUrl())
outstanding_amount.Base_createExternalPaymentTransactionFromOutstandingAmountAndRedirect()
self.tic()
self.logout()
self.login()
payment_transaction = self.portal.portal_catalog.getResultValue(
portal_type="Payment Transaction",
destination_section_uid=owner_person.getUid(),
simulation_state="started"
)
self.assertEqual(payment_transaction.getSpecialiseValue().getTradeConditionType(), "deposit")
# payzen/wechat or accountant will only stop the payment
payment_transaction.stop()
self.tic()
assert payment_transaction.receivable.getGroupingReference(None) is not None
self.login(owner_person.getUserId())
amount = sum([i.total_price for i in owner_person.Entity_getOutstandingDepositAmountList(
currency.getUid(), ledger_uid=ledger.getUid())])
self.assertEqual(0, amount)
##################################################
# Add first batch of service, and generate invoices
......@@ -176,4 +205,4 @@ class TestSlapOSCRMScenario(TestSlapOSVirtualMasterScenarioMixin):
with PinnedDateTime(self, creation_date + 5):
self.checkERP5StateBeforeExit()
\ No newline at end of file
self.checkERP5StateBeforeExit()
......@@ -7,6 +7,13 @@
<multi_property id='categories'>local_role_group/user</multi_property>
<multi_property id='base_category'>destination_decision</multi_property>
</role>
<role id='Auditor'>
<property id='title'>Person Shadow</property>
<property id='condition'>python: context.getLedger("") == "automated"</property>
<multi_property id='categories'>local_role_group/shadow</multi_property>
<multi_property id='category'>role/shadow/person</multi_property>
<multi_property id='base_category'>role</multi_property>
</role>
<role id='Auditor'>
<property id='title'>Sale Agent</property>
<multi_property id='categories'>local_role_group/function</multi_property>
......
......@@ -36,10 +36,6 @@ if not [x for x in subscription_assignment_category_list if x.startswith('destin
preference_method_list = [
"getPreferredHateoasUrl",
"getPreferredPayzenPaymentServiceReference",
"getPreferredPayzenIntegrationSite",
"getPreferredWechatPaymentServiceReference",
"getPreferredWechatIntegrationSite"
]
for method_id in preference_method_list:
......
......@@ -227,6 +227,7 @@ def makeTestSlapOSCodingStyleTestCase(tested_business_template):
'slapos_panel/Base_addSlapOSSupportRequest',
'slapos_panel/Base_getAuthenticatedPersonUid',
'slapos_panel/Base_getNewsDictFromComputeNodeList',
'slapos_panel/Base_getPaymentModeForCurrency',
'slapos_panel/Base_getStatusMonitorUrl',
'slapos_panel/Base_hasSlapOSProjectUserGroup',
'slapos_panel/ComputeNode_getBusyComputePartitionList',
......@@ -249,6 +250,7 @@ def makeTestSlapOSCodingStyleTestCase(tested_business_template):
'slapos_panel/InstanceTree_requestStart',
'slapos_panel/InstanceTree_requestStop',
'slapos_panel/InstanceTree_updateParameter',
'slapos_panel/PaymentTransaction_redirectToManualPayment',
'slapos_panel/Project_addSlapOSAllocationSupply',
'slapos_panel/Project_addSlapOSComputeNode',
'slapos_panel/Project_addSlapOSComputeNodeToken',
......@@ -272,6 +274,7 @@ def makeTestSlapOSCodingStyleTestCase(tested_business_template):
'slapos_panel/SoftwareInstance_getNewsDict',
'slapos_panel/SoftwareProduct_addSlapOSSoftwareRelease',
'slapos_panel/SoftwareProduct_addSlapOSSoftwareType',
'slapos_panel/SubscriptionRequest_jumpToPaymentPage',
'slapos_panel/Ticket_addSlapOSEvent',
'slapos_panel/Ticket_closeSlapOS',
'slapos_panel/Ticket_suspendSlapOS',
......@@ -281,7 +284,6 @@ def makeTestSlapOSCodingStyleTestCase(tested_business_template):
'slapos_panel/InstanceTree_proposeUpgradeDecision',
'slapos_panel/InstanceTree_searchUpgradableSoftwareReleaseList',
'slapos_panel/PaymentTransaction_triggerPaymentCheckAlarmAndRedirectToPanel',
'slapos_panel/SaleInvoiceTransaction_createExternalPaymentTransactionFromAmountAndRedirect',
'slapos_panel_compatibility/Base_getComputerToken',
'slapos_parameter_editor/SoftwareProductModule_updateParameterEditorTestDialog',
'slapos_parameter_editor/SoftwareProductModule_validateParameterEditorTestDialog',
......
......@@ -1628,11 +1628,12 @@ class TestSubscriptionRequest(TestSlapOSGroupRoleSecurityMixin):
portal_type='Subscription Request')
delivery.edit(destination_decision_value=person, ledger="automated")
self.assertSecurityGroup(delivery,
['F-SALE*', self.user_id, person.getUserId()], False)
['F-SALE*', self.user_id, "R-SHADOW-PERSON",
person.getUserId()], False)
self.assertRoles(delivery, self.user_id, ['Owner'])
self.assertRoles(delivery, 'F-SALE*', ['Auditor'])
self.assertRoles(delivery, person.getUserId(), ['Associate'])
self.assertRoles(delivery, 'R-SHADOW-PERSON', ['Auditor'])
class TestOrganisationModule(TestSlapOSGroupRoleSecurityMixin):
def test_OrganisationModule(self):
......
......@@ -338,7 +338,7 @@ class TestSlapOSVirtualMasterScenario(TestSlapOSVirtualMasterScenarioMixin):
owner_person = self.portal.portal_catalog.getResultValue(
portal_type="ERP5 Login",
reference=owner_reference).getParentValue()
#owner_person.setCareerSubordinationValue(seller_organisation)
# owner_person.setCareerSubordinationValue(seller_organisation)
self.tic()
......@@ -459,7 +459,8 @@ class TestSlapOSVirtualMasterScenario(TestSlapOSVirtualMasterScenarioMixin):
def test_deposit_with_accounting_scenario(self):
currency, _, _, _ = self.bootstrapVirtualMasterTest(is_virtual_master_accountable=True)
currency, seller_organisation, _, _ = \
self.bootstrapVirtualMasterTest(is_virtual_master_accountable=True)
self.logout()
# lets join as slapos administrator, which will own few compute_nodes
......@@ -472,20 +473,40 @@ class TestSlapOSVirtualMasterScenario(TestSlapOSVirtualMasterScenarioMixin):
reference=owner_reference).getParentValue()
self.tic()
# hooray
self.logout()
self.login(owner_person.getUserId())
# XXX XXX do reservation payment for a huge amount, to check if other services are ok
# Pre-input a reservation payment for a huge amount, to have enough amount.
# to check if other services are ok
total_price = 1234
def createTempSubscription(person, source_section, total_price, currency):
return self.portal.portal_trash.newContent(
portal_type='Subscription Request',
temp_object=True,
start_date=DateTime(),
source_section=source_section,
destination_value=person,
destination_section_value=person,
ledger_value=self.portal.portal_categories.ledger.automated,
price_currency=currency,
total_price=total_price
)
# Action to submit project subscription
def wrapWithShadow(person, *arg):
return person.Person_addDepositPayment(*arg)
def wrapWithShadow(person, source_section, total_price, currency):
# pre-include a large amount of w/o any subscription request using a temp
# object. It requires to be created under shadow user for security reasons.
tmp_subscription_request = createTempSubscription(person, source_section, total_price, currency)
return person.Entity_createDepositPaymentTransaction([tmp_subscription_request])
payment_transaction = owner_person.Person_restrictMethodAsShadowUser(
shadow_document=owner_person,
callable_object=wrapWithShadow,
argument_list=[owner_person, total_price, currency.getRelativeUrl(), 1])
argument_list=[owner_person, seller_organisation.getRelativeUrl(),
total_price, currency.getRelativeUrl()])
self.tic()
self.logout()
self.login()
......@@ -495,6 +516,14 @@ class TestSlapOSVirtualMasterScenario(TestSlapOSVirtualMasterScenarioMixin):
assert payment_transaction.receivable.getGroupingReference(None) is not None
# Check if the Deposit lead to proper balance.
tmp_subscription_request = createTempSubscription(
owner_person, seller_organisation.getRelativeUrl(), total_price, currency.getRelativeUrl())
self.assertEqual(
owner_person.Entity_getDepositBalanceAmount([tmp_subscription_request]),
total_price)
self.checkERP5StateBeforeExit()
......@@ -561,12 +590,6 @@ class TestSlapOSVirtualMasterScenario(TestSlapOSVirtualMasterScenarioMixin):
self.login()
project = self.portal.restrictedTraverse(project_relative_url)
payment_transaction = customer_section_organisation.Person_addDepositPayment(99*10, currency.getRelativeUrl(), 1)
# payzen interface will only stop the payment
payment_transaction.stop()
self.tic()
self.portal.log('SubscriptionRequest_validateIfSubmitted %s' % payment_transaction.getSimulationState())
preference = self.portal.portal_preferences.slapos_default_system_preference
preference.edit(
preferred_subscription_assignment_category_list=[
......@@ -674,6 +697,30 @@ class TestSlapOSVirtualMasterScenario(TestSlapOSVirtualMasterScenarioMixin):
dedicated_trade_condition.validate()
self.tic()
# Pay deposit to validate virtual master + one computer, for the organisation
# For now we cannot rely on user payments
deposit_amount = 42.0 + 99.0
ledger = self.portal.portal_categories.ledger.automated
outstanding_amount_list = customer_section_organisation.Entity_getOutstandingDepositAmountList(
currency.getUid(), ledger_uid=ledger.getUid())
amount = sum([i.total_price for i in outstanding_amount_list])
self.assertEqual(amount, deposit_amount)
payment_transaction = customer_section_organisation.Entity_createDepositPaymentTransaction(
outstanding_amount_list)
self.tic()
self.assertEqual(payment_transaction.getSpecialiseValue().getTradeConditionType(), "deposit")
# payzen/wechat or accountant will only stop the payment
payment_transaction.stop()
self.tic()
assert payment_transaction.receivable.getGroupingReference(None) is not None
outstanding_amount_list = customer_section_organisation.Entity_getOutstandingDepositAmountList(
currency.getUid(), ledger_uid=ledger.getUid())
self.assertEqual(0, sum([i.total_price for i in outstanding_amount_list]))
with PinnedDateTime(self, DateTime('2024/02/17 01:01')):
public_instance_title = 'Public title %s' % self.generateNewId()
self.checkInstanceAllocation(public_person.getUserId(),
......@@ -718,7 +765,7 @@ class TestSlapOSVirtualMasterScenario(TestSlapOSVirtualMasterScenarioMixin):
assert len(inventory_list) == 1, len(inventory_list)
assert inventory_list[0].quantity == 1, inventory_list[0].quantity
resource_vcl = [
#'software_release/%s' % release_variation.getRelativeUrl(),
# 'software_release/%s' % release_variation.getRelativeUrl(),
'software_type/%s' % type_variation.getRelativeUrl()
]
resource_vcl.sort()
......@@ -727,8 +774,8 @@ class TestSlapOSVirtualMasterScenario(TestSlapOSVirtualMasterScenarioMixin):
# Check accounting
transaction_list = self.portal.account_module.receivable.Account_getAccountingTransactionList(mirror_section_uid=customer_section_organisation.getUid())
assert len(transaction_list) == 2, len(transaction_list)
assert transaction_list[0].total_price == 990.0, transaction_list[0].total_price
assert transaction_list[1].total_price == -990.0, transaction_list[1].total_price
assert transaction_list[0].total_price == 141.0, transaction_list[0].total_price
assert transaction_list[1].total_price == -141.0, transaction_list[1].total_price
self.login()
......@@ -737,6 +784,7 @@ class TestSlapOSVirtualMasterScenario(TestSlapOSVirtualMasterScenarioMixin):
# 3 allocation supply / line / cell
# 1 compute node
# 2 credential request
# 1 event
# 1 instance tree
# 6 open sale order / line
# 5 (can reduce to 2) assignment
......@@ -748,7 +796,7 @@ class TestSlapOSVirtualMasterScenario(TestSlapOSVirtualMasterScenarioMixin):
# 1 software instance
# 1 software product
# 3 subscription requests
self.assertRelatedObjectCount(project, 52)
self.assertRelatedObjectCount(project, 53)
self.checkERP5StateBeforeExit()
......@@ -759,32 +807,27 @@ class TestSlapOSVirtualMasterScenario(TestSlapOSVirtualMasterScenarioMixin):
self.logout()
# lets join as slapos administrator, which will manager the project
owner_reference = 'project-%s' % self.generateNewId()
self.joinSlapOS(self.web_site, owner_reference)
project_owner_reference = 'project-%s' % self.generateNewId()
self.joinSlapOS(self.web_site, project_owner_reference)
self.login()
owner_person = self.portal.portal_catalog.getResultValue(
project_owner_person = self.portal.portal_catalog.getResultValue(
portal_type="ERP5 Login",
reference=owner_reference).getParentValue()
#owner_person.setCareerSubordinationValue(seller_organisation)
reference=project_owner_reference).getParentValue()
# owner_person.setCareerSubordinationValue(seller_organisation)
self.tic()
# hooray, now it is time to create compute_nodes
self.logout()
self.login(sale_person.getUserId())
project_relative_url = self.addProject(is_accountable=True, person=owner_person, currency=currency)
project_relative_url = self.addProject(
is_accountable=True, person=project_owner_person, currency=currency)
self.logout()
self.login()
project = self.portal.restrictedTraverse(project_relative_url)
payment_transaction = owner_person.Person_addDepositPayment(99*10, currency.getRelativeUrl(), 1)
# payzen interface will only stop the payment
payment_transaction.stop()
preference = self.portal.portal_preferences.slapos_default_system_preference
preference.edit(
preferred_subscription_assignment_category_list=[
......@@ -822,6 +865,7 @@ class TestSlapOSVirtualMasterScenario(TestSlapOSVirtualMasterScenarioMixin):
)
sale_supply.validate()
self.tic()
# some preparation
self.logout()
......@@ -859,6 +903,42 @@ class TestSlapOSVirtualMasterScenario(TestSlapOSVirtualMasterScenarioMixin):
# format the compute_nodes
self.formatComputeNode(public_server)
self.logout()
self.login(project_owner_person.getUserId())
# Pay deposit to validate virtual master + one computer
deposit_amount = 42.0 + 99.0
ledger = self.portal.portal_categories.ledger.automated
outstanding_amount_list = project_owner_person.Entity_getOutstandingDepositAmountList(
currency.getUid(), ledger_uid=ledger.getUid())
amount = sum([i.total_price for i in outstanding_amount_list])
self.assertEqual(amount, deposit_amount)
# Ensure to pay from the website
outstanding_amount = self.web_site.restrictedTraverse(outstanding_amount_list[0].getRelativeUrl())
outstanding_amount.Base_createExternalPaymentTransactionFromOutstandingAmountAndRedirect()
self.tic()
self.logout()
self.login()
payment_transaction = self.portal.portal_catalog.getResultValue(
portal_type="Payment Transaction",
destination_section_uid=project_owner_person.getUid(),
simulation_state="started"
)
self.assertEqual(payment_transaction.getSpecialiseValue().getTradeConditionType(), "deposit")
# payzen/wechat or accountant will only stop the payment
payment_transaction.stop()
self.tic()
assert payment_transaction.receivable.getGroupingReference(None) is not None
self.login(project_owner_person.getUserId())
amount = sum([i.total_price for i in project_owner_person.Entity_getOutstandingDepositAmountList(
currency.getUid(), ledger_uid=ledger.getUid())])
self.assertEqual(0, amount)
self.logout()
# join as the another visitor and request software instance on public
# compute_node
......@@ -871,16 +951,13 @@ class TestSlapOSVirtualMasterScenario(TestSlapOSVirtualMasterScenarioMixin):
portal_type="ERP5 Login",
reference=public_reference).getParentValue()
payment_transaction = public_person.Person_addDepositPayment(99*10, currency.getRelativeUrl(), 1)
# payzen interface will only stop the payment
payment_transaction.stop()
with PinnedDateTime(self, DateTime('2024/02/17 01:01')):
public_instance_title = 'Public title %s' % self.generateNewId()
self.checkInstanceAllocation(public_person.getUserId(),
self.checkInstanceAllocationWithDeposit(public_person.getUserId(),
public_reference, public_instance_title,
public_server_software, public_instance_type,
public_server, project.getReference())
public_server, project.getReference(),
9.0, currency)
self.login()
public_person = self.portal.portal_catalog.getResultValue(
......@@ -919,7 +996,7 @@ class TestSlapOSVirtualMasterScenario(TestSlapOSVirtualMasterScenarioMixin):
assert len(inventory_list) == 1, len(inventory_list)
assert inventory_list[0].quantity == 1, inventory_list[0].quantity
resource_vcl = [
#'software_release/%s' % release_variation.getRelativeUrl(),
# 'software_release/%s' % release_variation.getRelativeUrl(),
'software_type/%s' % type_variation.getRelativeUrl()
]
resource_vcl.sort()
......@@ -930,7 +1007,7 @@ class TestSlapOSVirtualMasterScenario(TestSlapOSVirtualMasterScenarioMixin):
assert len(transaction_list) == 2, len(transaction_list)
self.assertSameSet(
[x.total_price for x in transaction_list],
[990.0, -990.0],
[9.0, -9.0],
[x.total_price for x in transaction_list]
)
......@@ -941,7 +1018,7 @@ class TestSlapOSVirtualMasterScenario(TestSlapOSVirtualMasterScenarioMixin):
# 3 allocation supply / line / cell
# 1 compute node
# 2 credential request
# 1 event
# 2 event
# 1 instance tree
# 6 open sale order / line
# 5 (can reduce to 2) assignment
......@@ -953,7 +1030,7 @@ class TestSlapOSVirtualMasterScenario(TestSlapOSVirtualMasterScenarioMixin):
# 1 software instance
# 1 software product
# 3 subscription requests
self.assertRelatedObjectCount(project, 52)
self.assertRelatedObjectCount(project, 53)
self.checkERP5StateBeforeExit()
......
......@@ -2,91 +2,99 @@
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Payzen Service" module="erp5.portal_type"/>
<global name="ActionInformation" module="Products.CMFCore.ActionInformation"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_count</string> </key>
<key> <string>action</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_mt_index</string> </key>
<key> <string>categories</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>_tree</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
<tuple>
<string>action_type/object_jio_jump</string>
</tuple>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>PSERV-Payzen-Test</string> </value>
<key> <string>category</string> </key>
<value> <string>object_jio_jump</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>slapos_payzen_test</string> </value>
<key> <string>condition</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>payzen_vads_action_mode</string> </key>
<value> <string>INTERACTIVE</string> </value>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>payzen_vads_ctx_mode</string> </key>
<value> <string>TEST</string> </value>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>payzen_vads_page_action</string> </key>
<value> <string>PAYMENT</string> </value>
<key> <string>id</string> </key>
<value> <string>jump_pay_my_slapos_sale_invoice_transaction</string> </value>
</item>
<item>
<key> <string>payzen_vads_version</string> </key>
<value> <string>V2</string> </value>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>View</string>
</tuple>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Payzen Service</string> </value>
<value> <string>Action Information</string> </value>
</item>
<item>
<key> <string>service_password</string> </key>
<value> <string>bar</string> </value>
<key> <string>priority</string> </key>
<value> <float>20.0</float> </value>
</item>
<item>
<key> <string>service_username</string> </key>
<value> <string>foo</string> </value>
<key> <string>title</string> </key>
<value> <string>Pay</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>PayZen</string> </value>
<key> <string>visible</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Length" module="BTrees.Length"/>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle> <int>0</int> </pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="OOBTree" module="BTrees.OOBTree"/>
</pickle>
<pickle>
<none/>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/SubscriptionRequest_jumpToPaymentPage</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="OOBTree" module="BTrees.OOBTree"/>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<none/>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>python: (context.getWebSiteValue() is not None) and (context.getSimulationState() == \'submitted\')</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -363,16 +363,6 @@
<value> <string>string</string> </value>
</item>
</dictionary>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>configuration_payment_url_template</string> </value>
</item>
<item>
<key> <string>type</string> </key>
<value> <string>string</string> </value>
</item>
</dictionary>
</tuple>
</value>
</item>
......@@ -467,12 +457,6 @@
<key> <string>configuration_panel_gadget_url</string> </key>
<value> <string>slapos_master_panel_panel.html</string> </value>
</item>
<item>
<key> <string>configuration_payment_url_template</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>configuration_precache_manifest_script_list</string> </key>
<value> <string>WebSection_getJsonEditorPrecacheManifestList\n
......
......@@ -14,31 +14,33 @@ ledger_uid = portal.portal_categories.ledger.automated.getUid()
html_content = ''
entity = portal.portal_membership.getAuthenticatedMember().getUserValue()
if entity is None:
return '<p>Nothing to pay</p>'
return '<p>Nothing to pay with your account</p>'
for currency_uid, secure_service_relative_url in [
(portal.currency_module.EUR.getUid(), portal.Base_getPayzenServiceRelativeUrl()),
# (portal.currency_module.CNY.getUid(), portal.Base_getWechatServiceRelativeUrl())
]:
if secure_service_relative_url is not None:
outstanding_amount_list = entity.Entity_getOutstandingAmountList(
ledger_uid=ledger_uid,
resource_uid=currency_uid
)
for outstanding_amount in outstanding_amount_list:
html_content += """
<p><a href="%(payment_url)s">%(total_price)s %(currency)s</a></p>
""" % {
'total_price': outstanding_amount.total_price,
'currency': outstanding_amount.getPriceCurrencyReference(),
'payment_url': '%s/SaleInvoiceTransaction_createExternalPaymentTransactionFromAmountAndRedirect' % outstanding_amount.absolute_url()
}
if html_content:
if web_site.getLayoutProperty("configuration_payment_url_template", None) is None:
html_content = '<p>Please contact us to handle your payment</p>'
else:
is_payment_configured = 1
if secure_service_relative_url is None:
is_payment_configured = 0
for method in [entity.Entity_getOutstandingAmountList,
entity.Entity_getOutstandingDepositAmountList]:
for outstanding_amount in method(
ledger_uid=ledger_uid, resource_uid=currency_uid):
if 0 < outstanding_amount.total_price:
if not is_payment_configured:
return '<p>Please contact us to handle your payment</p>'
html_content += """
<p><a href="%(payment_url)s">%(total_price)s %(currency)s</a></p>
""" % {
'total_price': outstanding_amount.total_price,
'currency': outstanding_amount.getPriceCurrencyReference(),
'payment_url': '%s/Base_createExternalPaymentTransactionFromOutstandingAmountAndRedirect' % outstanding_amount.absolute_url()
}
if not html_content:
html_content = '<p>Nothing to pay</p>'
return html_content
portal = context.getPortalObject()
# Get entity from context to preserve path
entity = portal.portal_membership.getAuthenticatedMember().getUserValue()
outstanding_amount = context
web_site = outstanding_amount.getWebSiteValue()
assert outstanding_amount.getLedgerUid() == portal.portal_categories.ledger.automated.getUid()
assert outstanding_amount.getDestinationSectionUid() == entity.getUid()
assert web_site is not None
payment_mode = outstanding_amount.Base_getPaymentModeForCurrency(outstanding_amount.getPriceCurrencyUid())
def wrapWithShadow(entity, outstanding_amount, payment_mode):
portal_type = outstanding_amount.getPortalType()
method_kw = dict(
section_uid=outstanding_amount.getSourceSectionUid(),
resource_uid=outstanding_amount.getPriceCurrencyUid(),
ledger_uid=outstanding_amount.getLedgerUid()
)
if portal_type == "Sale Invoice Transaction":
return entity.Entity_createPaymentTransaction(
entity.Entity_getOutstandingAmountList(
group_by_node=False,
**method_kw
),
payment_mode=payment_mode
)
elif portal_type == "Subscription Request":
# We include deposit for Subscription Requests.
return entity.Entity_createDepositPaymentTransaction(
entity.Entity_getOutstandingDepositAmountList(
**method_kw),
payment_mode=payment_mode
)
raise ValueError("Unsupported outstanding amount type: %s" % (portal_type))
# Ensure to re-take the entity under a proper acquisition context
entity = web_site.restrictedTraverse(entity.getRelativeUrl())
payment_transaction = entity.Person_restrictMethodAsShadowUser(
shadow_document=entity,
callable_object=wrapWithShadow,
argument_list=[entity, outstanding_amount, payment_mode])
return payment_transaction.PaymentTransaction_redirectToManualPayment()
......@@ -54,7 +54,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>SaleInvoiceTransaction_createExternalPaymentTransactionFromAmountAndRedirect</string> </value>
<value> <string>Base_createExternalPaymentTransactionFromOutstandingAmountAndRedirect</string> </value>
</item>
</dictionary>
</pickle>
......
""" XXX This script expects some re-implementation to
rely on panel configuration for handle payment.
"""
portal = context.getPortalObject()
payment_mode = None
for accepted_currency_uid, accepted_payment_mode, is_activated in [
(portal.currency_module.EUR.getUid(), 'payzen', portal.Base_getPayzenServiceRelativeUrl()),
# (portal.currency_module.CNY, 'wechat', portal.Base_getWechatServiceRelativeUrl())
]:
if is_activated and (currency_uid == accepted_currency_uid):
payment_mode = accepted_payment_mode
return payment_mode
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>currency_uid</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Base_getPaymentModeForCurrency</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
""" Return a dict with vads_urls required for payzen."""
if web_site is None:
web_site = context.getWebSiteValue()
if web_site is None:
raise ValueError("This script must be called from a web site")
base = "%(payment_transaction_url)s/PaymentTransaction_triggerPaymentCheckAlarmAndRedirectToPanel?result=%(result)s"
......
......@@ -50,7 +50,7 @@
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>web_site</string> </value>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
......
if (context.getPaymentMode() == "wechat"):
return context.PaymentTransaction_redirectToManualWechatPayment()
elif (context.getPaymentMode() == "payzen"):
return context.PaymentTransaction_redirectToManualPayzenPayment()
else:
return context.PaymentTransaction_triggerPaymentCheckAlarmAndRedirectToPanel(result="contact_us")
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>PaymentTransaction_redirectToManualPayment</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
portal = context.getPortalObject()
from DateTime import DateTime
date = DateTime()
entity = portal.portal_membership.getAuthenticatedMember().getUserValue()
outstanding_amount = context
web_site = context.getWebSiteValue()
assert web_site is not None
assert web_site.getLayoutProperty("configuration_payment_url_template", None) is not None
assert outstanding_amount.getLedgerUid() == portal.portal_categories.ledger.automated.getUid()
assert outstanding_amount.getDestinationSectionUid() == entity.getUid()
payment_mode = None
resource_uid = outstanding_amount.getPriceCurrencyUid()
for accepted_resource_uid, accepted_payment_mode, is_activated in [
(portal.currency_module.EUR.getUid(), 'payzen', portal.Base_getPayzenServiceRelativeUrl()),
]:
if is_activated and (resource_uid == accepted_resource_uid):
payment_mode = accepted_payment_mode
assert payment_mode is not None
def wrapWithShadow(entity, outstanding_amount):
return entity.Entity_createPaymentTransaction(
entity.Entity_getOutstandingAmountList(
section_uid=outstanding_amount.getSourceSectionUid(),
resource_uid=outstanding_amount.getPriceCurrencyUid(),
ledger_uid=outstanding_amount.getLedgerUid(),
group_by_node=False
),
start_date=date,
payment_mode=payment_mode
)
entity = outstanding_amount.getDestinationSectionValue(portal_type="Person")
payment_transaction = entity.Person_restrictMethodAsShadowUser(
shadow_document=entity,
callable_object=wrapWithShadow,
argument_list=[entity, outstanding_amount])
web_site = context.getWebSiteValue()
if (payment_mode == "wechat"):
return payment_transaction.PaymentTransaction_redirectToManualWechatPayment(web_site=web_site)
elif (payment_mode == "payzen"):
return payment_transaction.PaymentTransaction_redirectToManualPayzenPayment(web_site=web_site)
else:
raise NotImplementedError('not implemented')
return context.getPortalObject().accounting_module.Base_redirect(
"AccountingTransactionModule_viewCreateExternalPaymentTransactionOnSlaposPanelDialog")
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>**kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>SubscriptionRequest_jumpToPaymentPage</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -80,7 +80,6 @@
<string>my_configuration_content_security_policy</string>
<string>my_configuration_x_frame_options</string>
<string>my_configuration_compute_node_install_command_line</string>
<string>my_configuration_payment_url_template</string>
<string>my_configuration_slapos_master_api</string>
</list>
</value>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_configuration_payment_url_template</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_view_mode_reference</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Payment URL Template</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -89,6 +89,7 @@ Software Product | slapos_panel_view
Software Release Module | slapos_panel_view
Software Release | slapos_panel_view
Subscription Request Module | slapos_panel_view
Subscription Request | jump_pay_my_slapos_sale_invoice_transaction
Subscription Request | slapos_panel_view
Support Request Module | slapos_panel_view
Support Request Module | slapos_panel_view_my_ticket_list
......
......@@ -22,7 +22,7 @@ def ERP5Site_activateAlarmSlapOSPanelTest(self):
def ERP5Site_bootstrapSlapOSPanelTest(self, step, scenario, customer_login,
manager_login, remote_customer_login,
passwd):
passwd, currency=None):
if step not in ['trade_condition', 'account']:
raise ValueError('Unsupported bootstrap step: %s' % step)
......@@ -45,14 +45,15 @@ def ERP5Site_bootstrapSlapOSPanelTest(self, step, scenario, customer_login,
portal.portal_alarms.upgrader_check_post_upgrade.activeSense(fixit=True)
# Currency
currency = portal.currency_module.newContent(
portal_type="Currency",
reference="test-currency-%s" % self.generateNewId(),
short_title="tc%s" % self.generateNewId(),
title="Test currency",
base_unit_quantity=0.01
)
currency.validate()
if currency is None:
currency = portal.currency_module.newContent(
portal_type="Currency",
reference="test-currency-%s" % self.generateNewId(),
short_title="tc%s" % self.generateNewId(),
title="Test currency",
base_unit_quantity=0.01
)
currency.validate()
# Organisation
organisation = portal.organisation_module.newContent(
......@@ -105,10 +106,21 @@ def ERP5Site_bootstrapSlapOSPanelTest(self, step, scenario, customer_login,
trade_condition.validate()
if scenario == 'accounting':
# Sale trade condition
# Create trade condition for Deposit
portal.sale_trade_condition_module.newContent(
portal_type="Sale Trade Condition",
reference="Deposit for : %s" % currency.getRelativeUrl(),
trade_condition_type="deposit",
specialise_value=sale_trade_condition,
source_value=organisation,
source_section_value=organisation,
price_currency_value=currency).validate()
# Sale Supply for Virtual Master
sale_supply = portal.sale_supply_module.newContent(
portal_type="Sale Supply",
title="Test project",
title="Sale Supply for Virtual Master (%s)" % currency.getRelativeUrl(),
price_currency_value=currency,
)
sale_supply.newContent(
......@@ -117,7 +129,6 @@ def ERP5Site_bootstrapSlapOSPanelTest(self, step, scenario, customer_login,
resource="service_module/slapos_virtual_master_subscription"
)
sale_supply.validate()
finally:
setSecurityManager(sm)
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Link" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>default_link</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Link</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>url_string</string> </key>
<value> <string>https://secure.payzen.eu/vads-payment/</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Link" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>wsdl_link</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Link</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>url_string</string> </key>
<value> <string>https://secure.payzen.eu/vads-ws/v3?wsdl</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -3,7 +3,6 @@ if REQUEST is not None:
raise Unauthorized
portal = context.getPortalObject()
integration_site = portal.restrictedTraverse(portal.portal_preferences.getPreferredPayzenIntegrationSite())
_, transaction_id = context.PaymentTransaction_getPayzenId()
if transaction_id is not None:
......@@ -13,19 +12,17 @@ if transaction_id is not None:
now = DateTime().toZone('UTC')
today = now.asdatetime().strftime('%Y%m%d')
preferred_integration_site = portal.portal_preferences.getPreferredPayzenIntegrationSite()
integration_site = portal.restrictedTraverse(preferred_integration_site)
if integration_site is None or not preferred_integration_site:
raise ValueError("Integration Site not found or not configured: %s" %
preferred_integration_site)
transaction_id = str(portal.portal_ids.generateNewId(
id_group='%s_%s' % (integration_site.getRelativeUrl(), today),
id_generator='uid')).zfill(6)
mapping_id = '%s_%s' % (today, transaction_id)
# integration_site.Causality[mapping_id].setDestinationReference(context.getRelativeUrl())
# try:
# integration_site.getCategoryFromMapping('Causality/%s' % mapping_id, create_mapping_line=True, create_mapping=True)
# except ValueError:
# mapping = integration_site.Causality[mapping_id]
# mapping.setDestinationReference('%s' % context.getRelativeUrl())
# else:
# raise ValueError, "Payzen transaction_id already exists"
try:
# Init for use later.
......@@ -35,6 +32,8 @@ try:
create_mapping=True)
except ValueError:
pass
mapping_id = '%s_%s' % (today, transaction_id)
integration_site.Causality[context.getId().replace('-', '_')].setDestinationReference(mapping_id)
return context.PaymentTransaction_getPayzenId()
......@@ -3,7 +3,12 @@ if REQUEST is not None:
raise Unauthorized
portal = context.getPortalObject()
integration_site = portal.restrictedTraverse(portal.portal_preferences.getPreferredPayzenIntegrationSite())
preferred_integration_site = portal.portal_preferences.getPreferredPayzenIntegrationSite()
integration_site = portal.restrictedTraverse(preferred_integration_site)
if integration_site is None or not preferred_integration_site:
raise ValueError("Integration Site not found or not configured: %s" %
preferred_integration_site)
payzen_id = integration_site.getCategoryFromMapping('Causality/%s' % context.getId().replace('-', '_'))
if payzen_id != 'causality/%s' % context.getId().replace('-', '_'):
......
......@@ -2,9 +2,9 @@ from zExceptions import Unauthorized
portal = context.getPortalObject()
person = portal.portal_membership.getAuthenticatedMember().getUserValue()
def wrapWithShadow(payment_transaction, web_site, person_relative_url):
def wrapWithShadow(payment_transaction, person_relative_url):
vads_url_dict = payment_transaction.PaymentTransaction_getVADSUrlDict(web_site)
vads_url_dict = payment_transaction.PaymentTransaction_getVADSUrlDict()
_ , transaction_id = payment_transaction.PaymentTransaction_getPayzenId()
vads_url_already_registered = vads_url_dict.pop('vads_url_already_registered')
......@@ -25,10 +25,10 @@ def wrapWithShadow(payment_transaction, web_site, person_relative_url):
if person is None:
if not portal.portal_membership.isAnonymousUser():
return wrapWithShadow(context, web_site, context.getDestinationSection())
return wrapWithShadow(context, context.getDestinationSection())
raise Unauthorized("You must be logged in")
return person.Person_restrictMethodAsShadowUser(
shadow_document=person,
callable_object=wrapWithShadow,
argument_list=[context, web_site, person.getRelativeUrl()])
argument_list=[context, person.getRelativeUrl()])
......@@ -50,7 +50,7 @@
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>web_site=None</string> </value>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
......
......@@ -7,6 +7,8 @@
<title tal:content="here/title"></title>
</head>
<body onload="document.payment.submit();">
<center><h2>Redirecting to payment processor...</h2></center>
<p><center><img src="ERP5VCS_imgs/wait.gif"></center></p>
<form method="POST" tal:attributes="action here/link_url_string" id="payment" name="payment">
<tal:block tal:repeat="value here/field_list">
<input type="hidden" tal:attributes="name python: value[0]; value python: value[1]">
......
......@@ -19,11 +19,11 @@
#
##############################################################################
from erp5.component.test.SlapOSTestCaseMixin import SlapOSTestCaseMixinWithAbort
from erp5.component.test.testSlapOSPayzenSkins import TestSlapOSPayzenMixin
from Products.ERP5Type.tests.utils import createZODBPythonScript
from DateTime import DateTime
class TestSlapOSPayzenUpdateStartedPayment(SlapOSTestCaseMixinWithAbort):
class TestSlapOSPayzenUpdateStartedPayment(TestSlapOSPayzenMixin):
def test_not_started_payment(self):
new_id = self.generateNewId()
......@@ -81,7 +81,7 @@ class Foo:
def updateStatus(self):
context.stop()
return Foo()
""" )
""")
self.commit()
def _simulatePaymentTransaction_createNotPaidPayzenEvent(self):
......@@ -99,7 +99,7 @@ class Foo:
def updateStatus(self):
pass
return Foo()
""" )
""")
self.commit()
def _dropPaymentTransaction_createPayzenEvent(self):
......@@ -168,7 +168,7 @@ return Foo()
'*args, **kwargs',
'# Script body\n'
"""portal_workflow = context.portal_workflow
portal_workflow.doActionFor(context, action='edit_action', comment='Visited by PaymentTransaction_updateStatus') """ )
portal_workflow.doActionFor(context, action='edit_action', comment='Visited by PaymentTransaction_updateStatus') """)
self.commit()
def _dropPaymentTransaction_updateStatus(self):
......
......@@ -19,14 +19,77 @@
#
##############################################################################
from erp5.component.test.SlapOSTestCaseMixin import SlapOSTestCaseMixinWithAbort
from erp5.component.test.SlapOSTestCaseMixin import SlapOSTestCaseMixinWithAbort, \
SlapOSTestCaseMixin, simulate
from DateTime import DateTime
from zExceptions import Unauthorized
from Products.ERP5Type.tests.utils import createZODBPythonScript
class TestSlapOSPayzenMixin(SlapOSTestCaseMixin):
def afterSetUp(self):
SlapOSTestCaseMixin.afterSetUp(self)
self.payzen_secure_payment = self.portal.portal_secure_payments.newContent(
portal_type="Payzen Service",
reference="PSERV-Payzen-Test-%s" % self.generateNewId()
)
# Include a simple Integration site
self.integration_site = self.portal.portal_integrations.newContent(
title="Integration site for: %s" % (self.payzen_secure_payment),
reference="payzen",
portal_type="Integration Site"
)
self.integration_site.newContent(
id="Causality",
portal_type="Integration Base Category Mapping",
default_source_reference="Causality",
default_destination_reference="causality"
)
resource_map = self.integration_site.newContent(
id="Resource",
portal_type="Integration Base Category Mapping",
default_source_reference="Resource",
default_destination_reference="resource"
)
resource_map.newContent(
# This is required for integration
id='978',
portal_type="Integration Category Mapping",
default_destination_reference='resource/currency_module/EUR',
default_source_reference='978'
)
system_preference = self.portal.portal_preferences.slapos_default_system_preference
self.older_service_reference = system_preference.getPreferredPayzenPaymentServiceReference()
system_preference.setPreferredPayzenPaymentServiceReference(
self.payzen_secure_payment.getReference())
self.older_integration_site = system_preference.getPreferredPayzenIntegrationSite()
system_preference.setPreferredPayzenIntegrationSite(
self.integration_site.getRelativeUrl()
)
self.tic()
def beforeTearDown(self):
SlapOSTestCaseMixin.beforeTearDown(self)
self.portal.portal_secure_payments.manage_delObjects(
ids=[self.payzen_secure_payment.getId()])
self.portal.portal_integrations.manage_delObjects(
ids=[self.integration_site.getId()])
system_preference = self.portal.portal_preferences.slapos_default_system_preference
system_preference.setPreferredPayzenPaymentServiceReference(
self.older_service_reference)
system_preference.setPreferredPayzenIntegrationSite(
self.older_integration_site
)
self.tic()
class TestSlapOSCurrency_getIntegrationMapping(SlapOSTestCaseMixinWithAbort):
class TestSlapOSCurrency_getIntegrationMapping(TestSlapOSPayzenMixin):
def test_integratedCurrency(self):
currency = self.portal.currency_module.EUR
......@@ -61,7 +124,7 @@ class TestSlapOSAccountingTransaction_updateStartDate(SlapOSTestCaseMixinWithAbo
date, REQUEST={})
class TestSlapOSPaymentTransaction_getPayzenId(SlapOSTestCaseMixinWithAbort):
class TestSlapOSPaymentTransaction_getPayzenId(TestSlapOSPayzenMixin):
def test_getPayzenId_newPaymentTransaction(self):
payment_transaction = self.createPaymentTransaction()
......@@ -101,7 +164,7 @@ class TestSlapOSPaymentTransaction_getPayzenId(SlapOSTestCaseMixinWithAbort):
REQUEST={})
class TestSlapOSPaymentTransaction_generatePayzenId(SlapOSTestCaseMixinWithAbort):
class TestSlapOSPaymentTransaction_generatePayzenId(TestSlapOSPayzenMixin):
def test_generatePayzenId_newPaymentTransaction(self):
payment_transaction = self.createPaymentTransaction()
......@@ -161,7 +224,7 @@ class TestSlapOSPaymentTransaction_generatePayzenId(SlapOSTestCaseMixinWithAbort
REQUEST={})
class TestSlapOSPaymentTransaction_createPayzenEvent(SlapOSTestCaseMixinWithAbort):
class TestSlapOSPaymentTransaction_createPayzenEvent(TestSlapOSPayzenMixin):
def test_createPayzenEvent_REQUEST_disallowed(self):
payment_transaction = self.createPaymentTransaction()
......@@ -171,24 +234,21 @@ class TestSlapOSPaymentTransaction_createPayzenEvent(SlapOSTestCaseMixinWithAbor
REQUEST={})
def test_createPayzenEvent_newPayment(self):
self.portal.portal_secure_payments.slapos_payzen_test.setReference("PSERV-Payzen-Test")
self.tic()
payment_transaction = self.createPaymentTransaction()
payzen_event = payment_transaction.PaymentTransaction_createPayzenEvent()
self.assertEqual(payzen_event.getPortalType(), "Payzen Event")
self.assertEqual(payzen_event.getSource(),
"portal_secure_payments/slapos_payzen_test")
self.assertEqual(payzen_event.getDestination(), payment_transaction.getRelativeUrl())
self.payzen_secure_payment.getRelativeUrl())
self.assertEqual(payzen_event.getDestination(),
payment_transaction.getRelativeUrl())
def test_createPayzenEvent_kwParameter(self):
self.portal.portal_secure_payments.slapos_payzen_test.setReference("PSERV-Payzen-Test")
self.tic()
payment_transaction = self.createPaymentTransaction()
payzen_event = payment_transaction.PaymentTransaction_createPayzenEvent(
title='foo')
self.assertEqual(payzen_event.getPortalType(), "Payzen Event")
self.assertEqual(payzen_event.getSource(),
"portal_secure_payments/slapos_payzen_test")
self.payzen_secure_payment.getRelativeUrl())
self.assertEqual(payzen_event.getDestination(), payment_transaction.getRelativeUrl())
self.assertEqual(payzen_event.getTitle(), "foo")
......@@ -226,7 +286,7 @@ class TestSlapOSPayzenEvent_processUpdate(SlapOSTestCaseMixinWithAbort):
data_kw = {
'status': 'ERROR',
'answer':{
'answer': {
'errorCode': "foo",
},
}
......@@ -552,32 +612,8 @@ class TestSlapOSPayzenEvent_processUpdate(SlapOSTestCaseMixinWithAbort):
'Automatic acknowledge as result of correct communication',
event.workflow_history['system_event_workflow'][-1]['comment'])
def _simulatePaymentTransaction_getRecentPayzenId(self):
script_name = 'PaymentTransaction_getPayzenId'
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'
"""return DateTime().toZone('UTC'), 'foo'""")
def _simulatePaymentTransaction_getOldPayzenId(self):
script_name = 'PaymentTransaction_getPayzenId'
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'
"""from erp5.component.module.DateUtils import addToDate
return addToDate(DateTime(), to_add={'day': -1, 'second': -1}).toZone('UTC'), 'foo'""")
def _dropPaymentTransaction_getPayzenId(self):
script_name = 'PaymentTransaction_getPayzenId'
if script_name in self.portal.portal_skins.custom.objectIds():
self.portal.portal_skins.custom.manage_delObjects(script_name)
@simulate("PaymentTransaction_getPayzenId", '*args, **kwargs',
"""return DateTime().toZone('UTC'), 'foo'""")
def test_processUpdate_recentNotFoundOnPayzenSide(self):
event = self.createPayzenEvent()
payment = self.createPaymentTransaction()
......@@ -589,12 +625,7 @@ return addToDate(DateTime(), to_add={'day': -1, 'second': -1}).toZone('UTC'), 'f
"errorCode": "PSP_010",
},
}
self._simulatePaymentTransaction_getRecentPayzenId()
try:
event.PayzenEvent_processUpdate(data_kw)
finally:
self._dropPaymentTransaction_getPayzenId()
event.PayzenEvent_processUpdate(data_kw)
self.assertEqual(event.getValidationState(), "acknowledged")
self.assertEqual(
......@@ -605,6 +636,9 @@ return addToDate(DateTime(), to_add={'day': -1, 'second': -1}).toZone('UTC'), 'f
'Error code PSP_010 (Not found) did not changed the document state.',
payment.workflow_history['edit_workflow'][-1]['comment'])
@simulate("PaymentTransaction_getPayzenId", '*args, **kwargs',
"""from erp5.component.module.DateUtils import addToDate
return addToDate(DateTime(), to_add={'day': -1, 'second': -1}).toZone('UTC'), 'foo'""")
def test_processUpdate_oldNotFoundOnPayzenSide(self):
"""
This Test is supposed to Fail as for now we do not want to cancel automatically
......@@ -619,12 +653,7 @@ return addToDate(DateTime(), to_add={'day': -1, 'second': -1}).toZone('UTC'), 'f
"errorCode": "PSP_010",
},
}
self._simulatePaymentTransaction_getOldPayzenId()
try:
event.PayzenEvent_processUpdate(data_kw)
finally:
self._dropPaymentTransaction_getPayzenId()
event.PayzenEvent_processUpdate(data_kw)
self.assertEqual(event.getValidationState(), "acknowledged")
self.assertEqual(
......@@ -662,7 +691,7 @@ return addToDate(DateTime(), to_add={'day': -1, 'second': -1}).toZone('UTC'), 'f
'Aborting refused payzen payment.',
payment.workflow_history['accounting_workflow'][-1]['comment'])
class TestSlapOSPayzenBase_getPayzenServiceRelativeUrl(SlapOSTestCaseMixinWithAbort):
class TestSlapOSPayzenBase_getPayzenServiceRelativeUrl(TestSlapOSPayzenMixin):
def test_getPayzenServiceRelativeUrl_REQUEST_disallowed(self):
self.assertRaises(
......@@ -671,35 +700,21 @@ class TestSlapOSPayzenBase_getPayzenServiceRelativeUrl(SlapOSTestCaseMixinWithAb
REQUEST={})
def test_getPayzenServiceRelativeUrl_default_result(self):
self.portal.portal_secure_payments.slapos_payzen_test.setReference("PSERV-Payzen-Test")
self.tic()
result = self.portal.Base_getPayzenServiceRelativeUrl()
self.assertEqual(result, 'portal_secure_payments/slapos_payzen_test')
self.assertEqual(result, self.payzen_secure_payment.getRelativeUrl())
def test_getPayzenServiceRelativeUrl_not_found(self):
self.portal.portal_secure_payments.slapos_payzen_test.setReference("disabled")
self.payzen_secure_payment.setReference("disabled")
self.tic()
result = self.portal.Base_getPayzenServiceRelativeUrl()
self.assertEqual(result, None)
class TestSlapOSPayzenPaymentTransaction_redirectToManualPayzenPayment(
SlapOSTestCaseMixinWithAbort):
TestSlapOSPayzenMixin):
def test_PaymentTransaction_redirectToManualPayzenPayment(self):
payment = self.createPaymentTransaction()
self.assertRaises(ValueError, payment.PaymentTransaction_redirectToManualPayzenPayment)
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()
@simulate("PaymentTransaction_getVADSUrlDict", '*args, **kwargs',
"""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),
......@@ -708,29 +723,39 @@ return dict(vads_url_already_registered="%s/already_registered" % (payment_trans
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 test_PaymentTransaction_redirectToManualPayzenPayment_unauthorzied(self):
payment = self.createPaymentTransaction()
self._simulatePaymentTransaction_getVADSUrlDict()
self.logout()
try:
self.assertRaises(Unauthorized, payment.PaymentTransaction_redirectToManualPayzenPayment)
finally:
self.login()
self._dropPaymentTransaction_getVADSUrlDict()
self.assertRaises(Unauthorized, payment.PaymentTransaction_redirectToManualPayzenPayment)
@simulate("PaymentTransaction_getVADSUrlDict", '*args, **kwargs',
"""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 test_PaymentTransaction_redirectToManualPayzenPayment_redirect(self):
self.portal.portal_secure_payments.slapos_payzen_test.setReference("PSERV-Payzen-Test")
# Ensure secure payment is consistent
self.payzen_secure_payment.edit(
payzen_vads_action_mode='INTERACTIVE',
payzen_vads_ctx_mode='TEST',
payzen_vads_page_action='PAYMENT',
payzen_vads_version='V2',
link_url_string="https://secure.payzen.eu/vads-payment/",
service_api_key="A",
service_password="B",
service_username="C"
)
self.tic()
project = self.addProject()
person = self.makePerson(project)
invoice = self.createStoppedSaleInvoiceTransaction(
invoice = self.createStoppedSaleInvoiceTransaction(
destination_section_value=person,
destination_project_value=project
)
......@@ -744,18 +769,14 @@ return dict(vads_url_already_registered="%s/already_registered" % (payment_trans
destination_project_value=invoice.getDestinationProjectValue(),
resource_value=self.portal.currency_module.EUR,
ledger="automated",
created_by_builder=1 # to prevent init script to create lines
created_by_builder=1 # to prevent init script to create lines
)
self.portal.portal_workflow._jumpToStateFor(payment, 'started')
self.tic()
self.login(person.getUserId())
self._simulatePaymentTransaction_getVADSUrlDict()
try:
text_content = payment.PaymentTransaction_redirectToManualPayzenPayment()
finally:
self._dropPaymentTransaction_getVADSUrlDict()
text_content = payment.PaymentTransaction_redirectToManualPayzenPayment()
payment_transaction_url = payment.getRelativeUrl()
for item in ["vads_site_id",
payment_transaction_url,
......@@ -784,10 +805,20 @@ return dict(vads_url_already_registered="%s/already_registered" % (payment_trans
self.assertEqual(
len(system_event_list[0].contentValues(portal_type="Payzen Event Message")), 1)
@simulate("PaymentTransaction_getVADSUrlDict", '*args, **kwargs',
"""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 test_PaymentTransaction_redirectToManualPayzenPayment_already_registered(self):
project = self.addProject()
person = self.makePerson(project)
invoice = self.createStoppedSaleInvoiceTransaction(
invoice = self.createStoppedSaleInvoiceTransaction(
destination_section_value=person,
destination_project_value=project
)
......@@ -808,11 +839,7 @@ return dict(vads_url_already_registered="%s/already_registered" % (payment_trans
payment.PaymentTransaction_generatePayzenId()
self.tic()
self.login(person.getUserId())
self._simulatePaymentTransaction_getVADSUrlDict()
try:
redirect = payment.PaymentTransaction_redirectToManualPayzenPayment()
finally:
self._dropPaymentTransaction_getVADSUrlDict()
redirect = payment.PaymentTransaction_redirectToManualPayzenPayment()
self.assertEqual("%s/already_registered" % payment.getRelativeUrl(),
redirect)
......
# Copyright (c) 2002-2012 Nexedi SA and Contributors. All Rights Reserved.
from erp5.component.test.SlapOSTestCaseMixin import SlapOSTestCaseMixinWithAbort
# -*- coding:utf-8 -*-
##############################################################################
#
# Copyright (c) 2022 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.SlapOSTestCaseMixin import simulate
from erp5.component.test.testSlapOSPayzenSkins import TestSlapOSPayzenMixin
import lxml.html
from DateTime import DateTime
from Products.ERP5Type.tests.utils import createZODBPythonScript
import difflib
HARDCODED_PRICE = -99.6
......@@ -15,7 +34,14 @@ vads_url_refused = 'http://example.org/refused'
vads_url_success = 'http://example.org/success'
vads_url_return = 'http://example.org/return'
class TestSlapOSPayzenInterfaceWorkflow(SlapOSTestCaseMixinWithAbort):
class TestSlapOSPayzenInterfaceWorkflow(TestSlapOSPayzenMixin):
def createPayzenService(self):
self.payzen_secure_payment = self.portal.portal_secure_payments.newContent(
portal_type="Payzen Service",
reference="PSERV-Payzen-Test"
)
self.tic()
slapos_payzen_html = '''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
......@@ -26,6 +52,8 @@ class TestSlapOSPayzenInterfaceWorkflow(SlapOSTestCaseMixinWithAbort):
<title>title</title>
</head>
<body onload="document.payment.submit();">
<center><h2>Redirecting to payment processor...</h2></center>
<p></p><center><img src="ERP5VCS_imgs/wait.gif"></img></center>
<form action="%(action)s" id="payment" method="POST" name="payment">
<input name="signature" type="hidden" value="%(signature)s"></input>
......@@ -94,21 +122,6 @@ class TestSlapOSPayzenInterfaceWorkflow(SlapOSTestCaseMixinWithAbort):
</body>
</html>'''
def _simulatePaymentTransaction_getTotalPayablePrice(self):
script_name = 'PaymentTransaction_getTotalPayablePrice'
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\nreturn %f' % HARDCODED_PRICE)
def _dropPaymentTransaction_getTotalPayablePrice(self):
script_name = 'PaymentTransaction_getTotalPayablePrice'
if script_name in self.portal.portal_skins.custom.objectIds():
self.portal.portal_skins.custom.manage_delObjects(script_name)
def test_generateManualPaymentPage_mandatoryParameters(self):
event = self.createPayzenEvent()
# vads_url_cancel
......@@ -175,7 +188,7 @@ class TestSlapOSPayzenInterfaceWorkflow(SlapOSTestCaseMixinWithAbort):
event = self.createPayzenEvent()
payment = self.createPaymentTransaction()
event.edit(destination_value=payment)
_ , _ = payment.PaymentTransaction_generatePayzenId()
payment.PaymentTransaction_generatePayzenId()
self.assertRaises(ValueError, event.generateManualPaymentPage,
vads_url_cancel=vads_url_cancel,
vads_url_error=vads_url_error,
......@@ -199,11 +212,12 @@ class TestSlapOSPayzenInterfaceWorkflow(SlapOSTestCaseMixinWithAbort):
)
def test_generateManualPaymentPage_noCurrency(self):
self.createPayzenService()
event = self.createPayzenEvent()
payment = self.createPaymentTransaction()
event.edit(
destination_value=payment,
source="portal_secure_payments/slapos_payzen_test",
source=self.payzen_secure_payment.getRelativeUrl(),
)
self.assertRaises(AttributeError, event.generateManualPaymentPage,
vads_url_cancel=vads_url_cancel,
......@@ -214,7 +228,21 @@ class TestSlapOSPayzenInterfaceWorkflow(SlapOSTestCaseMixinWithAbort):
vads_url_return=vads_url_return,
)
@simulate("PaymentTransaction_getTotalPayablePrice", '*args, **kwargs',
'# Script body\nreturn %f' % HARDCODED_PRICE)
def test_generateManualPaymentPage_defaultUseCase(self):
self.createPayzenService()
self.payzen_secure_payment.edit(
payzen_vads_action_mode='INTERACTIVE',
payzen_vads_ctx_mode='TEST',
payzen_vads_page_action='PAYMENT',
payzen_vads_version='V2',
link_url_string="https://secure.payzen.eu/vads-payment/",
service_api_key="A",
service_password="B",
service_username="C"
)
self.tic()
event = self.createPayzenEvent()
payment = self.createPaymentTransaction()
payment.edit(
......@@ -222,13 +250,11 @@ class TestSlapOSPayzenInterfaceWorkflow(SlapOSTestCaseMixinWithAbort):
)
event.edit(
destination_value=payment,
source="portal_secure_payments/slapos_payzen_test",
source=self.payzen_secure_payment.getRelativeUrl(),
)
before_date = DateTime()
self._simulatePaymentTransaction_getTotalPayablePrice()
try:
event.generateManualPaymentPage(
event.generateManualPaymentPage(
vads_url_cancel=vads_url_cancel,
vads_url_error=vads_url_error,
vads_url_referral=vads_url_referral,
......@@ -236,8 +262,6 @@ class TestSlapOSPayzenInterfaceWorkflow(SlapOSTestCaseMixinWithAbort):
vads_url_success=vads_url_success,
vads_url_return=vads_url_return,
)
finally:
self._dropPaymentTransaction_getTotalPayablePrice()
after_date = DateTime()
# Payment start date is modified
......@@ -271,7 +295,8 @@ class TestSlapOSPayzenInterfaceWorkflow(SlapOSTestCaseMixinWithAbort):
'vads_site_id': 'foo',
}
# Calculate the signature...
self.portal.portal_secure_payments.slapos_payzen_test._getFieldList(data_dict)
self.payzen_secure_payment._getFieldList(data_dict)
data_dict['action'] = 'https://secure.payzen.eu/vads-payment/'
if getattr(self, "custom_slapos_payzen_html", None):
......@@ -314,45 +339,30 @@ class TestSlapOSPayzenInterfaceWorkflow(SlapOSTestCaseMixinWithAbort):
event.edit(
destination_value=payment,
)
_ , _ = payment.PaymentTransaction_generatePayzenId()
payment.PaymentTransaction_generatePayzenId()
self.assertRaises(AttributeError, event.updateStatus)
def mockRestGetInfo(self, method_to_call, expected_args, result_tuple):
payment_service = self.portal.portal_secure_payments.slapos_payzen_test
def mockrest_getInfo(arg1, arg2):
self.assertEqual(arg1, expected_args[0])
self.assertEqual(arg2, expected_args[1])
return result_tuple
setattr(payment_service, 'rest_getInfo', mockrest_getInfo)
setattr(self.payzen_secure_payment, 'rest_getInfo', mockrest_getInfo)
try:
return method_to_call()
finally:
del payment_service.rest_getInfo
def _simulatePayzenEvent_processUpdate(self):
script_name = 'PayzenEvent_processUpdate'
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'
"""portal_workflow = context.portal_workflow
portal_workflow.doActionFor(context, action='edit_action', comment='Visited by PayzenEvent_processUpdate') """ )
self.commit()
def _dropPayzenEvent_processUpdate(self):
script_name = 'PayzenEvent_processUpdate'
if script_name in self.portal.portal_skins.custom.objectIds():
self.portal.portal_skins.custom.manage_delObjects(script_name)
self.commit()
del self.payzen_secure_payment.rest_getInfo
@simulate("PayzenEvent_processUpdate", '*args, **kwargs',
"""portal_workflow = context.portal_workflow
portal_workflow.doActionFor(context, action='edit_action', comment='Visited by PayzenEvent_processUpdate') """)
def test_updateStatus_defaultUseCase(self):
self.createPayzenService()
event = self.createPayzenEvent()
payment = self.createPaymentTransaction()
event.edit(
destination_value=payment,
source="portal_secure_payments/slapos_payzen_test",
source_value=self.payzen_secure_payment,
)
transaction_date, transaction_id = \
payment.PaymentTransaction_generatePayzenId()
......@@ -361,17 +371,13 @@ portal_workflow.doActionFor(context, action='edit_action', comment='Visited by P
mocked_sent_text = 'mocked_sent_text'
mocked_received_text = 'mocked_received_text'
self._simulatePayzenEvent_processUpdate()
try:
self.mockRestGetInfo(
event.updateStatus,
(transaction_date.toZone('UTC').asdatetime(),
"%s-%s" % (transaction_date.toZone('UTC')\
.asdatetime().strftime('%Y%m%d'), transaction_id)),
(mocked_data_kw, mocked_sent_text, mocked_received_text),
)
finally:
self._dropPayzenEvent_processUpdate()
self.mockRestGetInfo(
event.updateStatus,
(transaction_date.toZone('UTC').asdatetime(),
"%s-%s" % (transaction_date.toZone('UTC')\
.asdatetime().strftime('%Y%m%d'), transaction_id)),
(mocked_data_kw, mocked_sent_text, mocked_received_text),
)
event_message_list = event.contentValues(portal_type="Payzen Event Message")
self.assertEqual(len(event_message_list), 2)
......
......@@ -4,6 +4,4 @@ portal_integrations/slapos_payzen_test_integration/Causality
portal_integrations/slapos_payzen_test_integration/Resource
portal_integrations/slapos_payzen_test_integration/Resource/**
portal_integrations/slapos_payzen_test_integration/SourceProject
portal_secure_payments/slapos_payzen_test
portal_secure_payments/slapos_payzen_test/**
sale_trade_condition_module/slapos_manual_accounting_trade_condition
\ No newline at end of file
......@@ -20,10 +20,6 @@ if item is None:
resource = subscription_request.getResourceValue()
raise ValueError('Unsupported resource: %s' % resource.getRelativeUrl())
# Use list setter, to ensure it crashes if item is still None
# subscription_request.setAggregateValueList([item])
# If the virtual master is not in the expected subscription status,
# do not accept any new service (compute node, instance) for it
if (((subscription_request.getSourceProjectValue() is not None) and
......@@ -37,55 +33,17 @@ if (((subscription_request.getSourceProjectValue() is not None) and
total_price = subscription_request.getTotalPrice()
if 0 < total_price:
# Check that user has enough guarantee deposit to request a new service
portal = context.getPortalObject()
assert_price_kw = {
'resource_uid': subscription_request.getPriceCurrencyUid(),
'portal_type': portal.getPortalAccountingMovementTypeList(),
'ledger_uid': portal.portal_categories.ledger.automated.getUid(),
}
deposit_amount = portal.portal_simulation.getInventoryAssetPrice(
section_uid= subscription_request.getDestinationSectionUid(),
mirror_section_uid= subscription_request.getSourceSectionUid(),
mirror_node_uid=portal.restrictedTraverse('account_module/deposit_received').getUid(),
#node_category_strict_membership=['account_type/income'],
simulation_state= ('stopped', 'delivered'),
# Do not gather deposit reimburse
# when it does not yet have a grouping_reference
omit_asset_decrease=1,
grouping_reference=None,
#src__=1,
**assert_price_kw
)
#return deposit_amount
payable_amount = portal.portal_simulation.getInventoryAssetPrice(
mirror_section_uid= subscription_request.getDestinationSectionUid(),
section_uid= subscription_request.getSourceSectionUid(),
# Do not gather deposit receivable
# when it does not yet have a grouping_reference
omit_asset_decrease=1,
node_category_strict_membership=['account_type/asset/receivable',
'account_type/liability/payable'],
simulation_state= ('planned', 'confirmed', 'started', 'stopped', 'delivered'),
grouping_reference=None,
**assert_price_kw
)
customer = subscription_request.getDestinationSectionValue()
balance = customer.Entity_getDepositBalanceAmount([subscription_request])
# XXX what is the guarantee deposit account_type?
if deposit_amount < payable_amount + total_price:
# if not enough, user will have to pay a deposit for the subscription
# XXX probably create an event asking for a deposit
#pass
if balance < total_price:
return markHistory(subscription_request,
'Not enough deposit from user')
# raise NotImplementedError('NO deposit_amount %s\npayable_amount %s\ntotal_price %s' % (deposit_amount, payable_amount, total_price))
#return 'YES deposit_amount %s\npayable_amount %s\ntotal_price %s' % (deposit_amount, payable_amount, total_price)
'Your user does not have enough deposit.')
if subscription_request.checkConsistency():
return markHistory(subscription_request, str(subscription_request.checkConsistency()[0].getTranslatedMessage()))
return markHistory(subscription_request,
str(subscription_request.checkConsistency()[0].getTranslatedMessage()))
subscription_request.SubscriptionRequest_createOpenSaleOrder()
subscription_request.validate()
......
......@@ -3,7 +3,13 @@ if REQUEST is not None:
raise Unauthorized
portal = context.getPortalObject()
integration_site = portal.restrictedTraverse(portal.portal_preferences.getPreferredWechatIntegrationSite())
preferred_integration_site = portal.portal_preferences.getPreferredWechatIntegrationSite()
integration_site = portal.restrictedTraverse(preferred_integration_site)
if integration_site is None or not preferred_integration_site:
raise ValueError("Integration Site not found or not configured: %s" %
preferred_integration_site)
wechat_id = integration_site.getCategoryFromMapping('Causality/%s' % context.getId().replace('-', '_'))
if wechat_id != 'causality/%s' % context.getId().replace('-', '_'):
......
......@@ -4,7 +4,7 @@ person = portal.portal_membership.getAuthenticatedMember().getUserValue()
def wrapWithShadow(payment_transaction, web_site, person_relative_url):
vads_url_dict = payment_transaction.PaymentTransaction_getVADSUrlDict(web_site)
vads_url_dict = payment_transaction.PaymentTransaction_getVADSUrlDict()
_ , transaction_id = payment_transaction.PaymentTransaction_getWechatId()
vads_url_already_registered = vads_url_dict.pop('vads_url_already_registered')
......
......@@ -553,11 +553,6 @@ class TestSlapOSWechatBase_getWechatServiceRelativeUrl(SlapOSTestCaseMixinWithAb
class TestSlapOSWechatPaymentTransaction_redirectToManualWechatPayment(
SlapOSTestCaseMixinWithAbort):
def test_PaymentTransaction_redirectToManualWechatPayment(self):
payment = self.createPaymentTransaction()
self.assertRaises(ValueError, payment.PaymentTransaction_redirectToManualWechatPayment)
def _simulatePaymentTransaction_getVADSUrlDict(self):
script_name = 'PaymentTransaction_getVADSUrlDict'
if script_name in self.portal.portal_skins.custom.objectIds():
......
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