Commit 7991a59b authored by Rafael Monnerat's avatar Rafael Monnerat

slapos_panel: Add form to pay after request a payable instance

   Similar to "Pay" Section, it will display the outstanding amount right the way to pay. This allows the user "immediately" have their instance ready to allocate (validated) and it wont require to navigate to pay section or subscription request.
parent 91064874
portal = context.getPortalObject()
web_site = context.getWebSiteValue()
assert web_site is not None
# This script will be used to generate the payment
# compatible with external providers
person = portal.portal_membership.getAuthenticatedMember().getUserValue()
# Fetch to know if the subscription request is already created
subscription_request = portal.portal_catalog.getResultValue(
portal_type='Subscription Request',
aggregate__uid=context.getUid())
if subscription_request is not None:
if subscription_request.getSimulationState() != 'submitted':
# No need to continue if the subscription is already processed.
raise ValueError('No deposit is required, Subscription Request is not on submitted state')
else:
subscription_request = context.Item_createSubscriptionRequest(temp_object=True)
if subscription_request is None:
raise ValueError("Subscription Request was not found or generated")
outstanding_amount_list = person.Entity_getOutstandingDepositAmountList(
ledger_uid=subscription_request.getLedgerUid(),
source_section_uid=subscription_request.getSourceSectionUid(),
resource_uid=subscription_request.getPriceCurrencyUid())
if subscription_request.isTempObject():
outstanding_amount_list.append(
subscription_request.asContext(
total_price=subscription_request.getPrice(None))
)
payment_mode = subscription_request.Base_getPaymentModeForCurrency(
subscription_request.getPriceCurrencyUid())
def wrapWithShadow(person, outstanding_amount_list, payment_mode):
return person.Entity_createDepositPaymentTransaction(
subscription_list=outstanding_amount_list,
payment_mode=payment_mode
)
# Use proper acquisiton to generate the payment transaction
person = web_site.restrictedTraverse(person.getRelativeUrl())
payment_transaction = person.Person_restrictMethodAsShadowUser(
shadow_document=person,
callable_object=wrapWithShadow,
argument_list=[person, outstanding_amount_list, payment_mode])
return payment_transaction.PaymentTransaction_redirectToManualPayment()
<?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>InstanceTree_redirectToManualDepositPayment</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ERP5 Form" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>action</string> </key>
<value> <string>Base_redirect</string> </value>
</item>
<item>
<key> <string>action_title</string> </key>
<value> <string>Pay Later</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>edit_order</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>encoding</string> </key>
<value> <string>UTF-8</string> </value>
</item>
<item>
<key> <string>enctype</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>group_list</string> </key>
<value>
<list>
<string>left</string>
<string>right</string>
<string>center</string>
<string>bottom</string>
<string>hidden</string>
</list>
</value>
</item>
<item>
<key> <string>groups</string> </key>
<value>
<dictionary>
<item>
<key> <string>bottom</string> </key>
<value>
<list>
<string>your_pay_action_html</string>
</list>
</value>
</item>
<item>
<key> <string>center</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>hidden</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>left</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>right</string> </key>
<value>
<list/>
</value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>InstanceTree_viewCreateDirectDepositPaymentTransactionOnSlaposPanelDialog</string> </value>
</item>
<item>
<key> <string>method</string> </key>
<value> <string>POST</string> </value>
</item>
<item>
<key> <string>name</string> </key>
<value> <string>InstanceTree_viewCreateDirectDepositPaymentTransactionOnSlaposPanelDialog</string> </value>
</item>
<item>
<key> <string>pt</string> </key>
<value> <string>form_dialog</string> </value>
</item>
<item>
<key> <string>row_length</string> </key>
<value> <int>4</int> </value>
</item>
<item>
<key> <string>stored_encoding</string> </key>
<value> <string>UTF-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Pay</string> </value>
</item>
<item>
<key> <string>unicode_mode</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>update_action</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>update_action_title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="EditorField" module="Products.ERP5Form.EditorField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>your_pay_action_html</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>
<item>
<key> <string>line_too_long</string> </key>
<value> <string>A line was too long.</string> </value>
</item>
<item>
<key> <string>required_not_found</string> </key>
<value> <string>Input is required but no input given.</string> </value>
</item>
<item>
<key> <string>too_long</string> </key>
<value> <string>You entered too many characters.</string> </value>
</item>
<item>
<key> <string>too_many_lines</string> </key>
<value> <string>You entered too many lines.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>height</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_linelength</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_lines</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>text_editor</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>height</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_linelength</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_lines</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>text_editor</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>height</string> </key>
<value> <int>5</int> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_linelength</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_lines</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>text_editor</string> </key>
<value> <string>text_area</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Informations</string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <int>40</int> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: context.InstanceTree_viewCreateDirectDepositPaymentTransactionOnSlaposPanelHTML()</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
from zExceptions import Unauthorized
if REQUEST is not None:
raise Unauthorized
portal = context.getPortalObject()
web_site = context.getWebSiteValue()
assert web_site is not None
# This script will be used to generate the payment
# compatible with external providers
html_content = ''
entity = portal.portal_membership.getAuthenticatedMember().getUserValue()
if entity is None:
return '<p>Nothing to pay with your account</p>'
def isPaymentConfigured(currency_uid):
for uid, secure_service_relative_url in [
(portal.currency_module.EUR.getUid(), portal.Base_getPayzenServiceRelativeUrl()),
# (portal.currency_module.CNY.getUid(), portal.Base_getWechatServiceRelativeUrl())
]:
if currency_uid == uid and secure_service_relative_url is not None:
return 1
return 0
# Fetch to know if the subscription request is already created
subscription_request = portal.portal_catalog.getResultValue(
portal_type='Subscription Request',
aggregate__uid=context.getUid())
if subscription_request is not None:
if subscription_request.getSimulationState() != 'submitted':
# No need to continue if the subscription is already processed.
return '<p>Nothing to pay</p>'
else:
subscription_request = context.Item_createSubscriptionRequest(temp_object=True)
if subscription_request is not None:
currency_uid = subscription_request.getPriceCurrencyUid()
# Subscription is indexed so we just calculate like usual
price = 0
if subscription_request.isTempObject():
# Include temp object on the outstanting total price
price = subscription_request.getPrice(None)
if price is not None and price != 0:
balance = entity.Entity_getDepositBalanceAmount([subscription_request])
if balance > price:
return '<p>Nothing to Pay </p>'
def getUidWithShadow(portal, source_section):
# Source Section can be one organisation, so shadow is required
# Shadow has no access to freshly created or temp subscription requests
return (
portal.restrictedTraverse(source_section).getUid(),
)
section_section_uid = entity.Person_restrictMethodAsShadowUser(
shadow_document=entity,
callable_object=getUidWithShadow,
argument_list=[portal, subscription_request.getSourceSection()])
outstanding_amount_list = entity.Entity_getOutstandingDepositAmountList(
ledger_uid=subscription_request.getLedgerUid(),
source_section_uid=section_section_uid,
resource_uid=currency_uid)
assert len(outstanding_amount_list) in [0, 1]
outstanting_total_price = sum([i.total_price for i in outstanding_amount_list])
outstanting_total_price += price
if outstanting_total_price > 0:
if not isPaymentConfigured(currency_uid):
return '<p>Please contact us to handle your payment</p>'
payment_url = subscription_request.absolute_url() + "/Base_createExternalPaymentTransactionFromOutstandingAmountAndRedirect"
if subscription_request.isTempObject():
payment_url = context.absolute_url() + "/InstanceTree_redirectToManualDepositPayment"
html_content += """
<p><a href="%(payment_url)s">%(total_price)s %(currency)s</a></p>
""" % {
'total_price': outstanting_total_price,
'currency': subscription_request.getPriceCurrencyReference(),
'payment_url': payment_url
}
if not html_content:
html_content = '<p>Nothing to pay</p>'
return html_content
<?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>REQUEST=None</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>InstanceTree_viewCreateDirectDepositPaymentTransactionOnSlaposPanelHTML</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -64,42 +64,24 @@ if sla_xml: ...@@ -64,42 +64,24 @@ if sla_xml:
person.requestSoftwareInstance(**request_kw) person.requestSoftwareInstance(**request_kw)
request_instance_tree = context.REQUEST.get('request_instance_tree') request_instance_tree = context.REQUEST.get('request_instance_tree')
def wrapWithShadow(person, instance): web_site = context.getWebSectionValue()
# Evaluate if the user has to pay something,
# Since we need access to organisation_module on Entity_getDepositBalanceAmount
# evaluate as Shadow User.
subscription_request = instance.Item_createSubscriptionRequest(temp_object=True)
# Check if we could create the Subscription Request
if subscription_request is not None:
price = subscription_request.getPrice(None)
if price is not None and price != 0:
balance = person.Entity_getDepositBalanceAmount([subscription_request])
if balance - price < 0:
payment_mode=subscription_request.Base_getPaymentModeForCurrency(
subscription_request.getPriceCurrencyUid())
return person.Entity_createDepositPaymentTransaction(
subscription_list=[
subscription_request.asContext(total_price=price)],
payment_mode=payment_mode
)
web_site = context.getWebSiteValue()
assert web_site is not None assert web_site is not None
# Use proper acquisiton to generate the payment transaction # Evaluate if the user has to pay something,
person = web_site.restrictedTraverse(person.getRelativeUrl()) # Since we need access to organisation_module on Entity_getDepositBalanceAmount
# evaluate as Shadow User.
subscription_request = request_instance_tree.Item_createSubscriptionRequest(temp_object=True)
# Check if we could create the Subscription Request
if subscription_request is not None:
price = subscription_request.getPrice(None)
if price is not None and price != 0:
balance = person.Entity_getDepositBalanceAmount([subscription_request])
if balance < price:
instance = web_site.restrictedTraverse(request_instance_tree.getRelativeUrl())
return instance.Base_renderForm(
"InstanceTree_viewCreateDirectDepositPaymentTransactionOnSlaposPanelDialog",
message=context.Base_translateString("Your instance is created, please proceed to payment.")
)
payment_transaction = person.Person_restrictMethodAsShadowUser(
shadow_document=person,
callable_object=wrapWithShadow,
argument_list=[person, request_instance_tree])
if payment_transaction is not None:
return context.getPortalObject().REQUEST.RESPONSE.redirect(
payment_transaction.absolute_url() + "/PaymentTransaction_redirectToManualPayment",
status=302,
)
raise ValueError("NO")
return request_instance_tree.Base_redirect() return request_instance_tree.Base_redirect()
...@@ -58,6 +58,10 @@ ...@@ -58,6 +58,10 @@
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value> </value>
</item> </item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item> <item>
<key> <string>enabled</string> </key> <key> <string>enabled</string> </key>
<value> <value>
...@@ -78,9 +82,7 @@ ...@@ -78,9 +82,7 @@
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
<value> <value> <string></string> </value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item> </item>
</dictionary> </dictionary>
</value> </value>
...@@ -149,17 +151,4 @@ ...@@ -149,17 +151,4 @@
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>Price Information</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData> </ZopeData>
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