542 lines
27 KiB
XML
542 lines
27 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<odoo>
|
|
|
|
<template id="payment.form" name="Payment Form">
|
|
<!-- Form customization parameters:
|
|
- mode: The operation mode of the form: `payment` or `validation`; default: `payment`.
|
|
- allow_token_selection: Whether tokens can be selected for payment or assignation
|
|
(through the `assign_token_route` parameter); default: `True`.
|
|
- allow_token_deletion: Whether tokens can be deleted (archived); default: `False`.
|
|
- default_token_id: The id of the token that should be pre-selected; default: `None`.
|
|
- show_tokenize_input_mapping: For each provider, whether the tokenization checkbox is
|
|
shown; used only in `payment` mode.
|
|
- display_submit_button: Whether the submit button is displayed; default: `True`.
|
|
- submit_button_label: The label of the submit button; default: 'Pay'/'Save'.
|
|
-->
|
|
<!-- Payment context:
|
|
- reference_prefix: The custom prefix to compute the full transaction reference.
|
|
- amount: The amount to pay.
|
|
- currency: The currency of the payment, as a `res.currency` record.
|
|
- partner_id: The id of the partner on behalf of whom the payment should be made.
|
|
- providers_sudo: The compatible providers, as a sudoed `payment.provider` recordset.
|
|
- payment_methods_sudo: The compatible payment methods, as a sudoed `payment.method`
|
|
recordset.
|
|
- tokens_sudo: The available payment tokens, as a sudoed `payment.token` recordset.
|
|
- transaction_route: The route to call to create the transaction.
|
|
- assign_token_route: The route to call to assign a new or existing token to a record.
|
|
- landing_route: The route the user is redirected to after payment.
|
|
- access_token: The access token used to authenticate the partner.
|
|
-->
|
|
<t t-set="mode" t-value="mode or 'payment'"/>
|
|
<t t-set="allow_token_selection"
|
|
t-value="True if allow_token_selection is None else allow_token_selection"
|
|
/>
|
|
<t t-set="allow_token_deletion" t-value="allow_token_deletion or False"/>
|
|
<t t-set="selected_token_id"
|
|
t-value="allow_token_selection and (default_token_id or tokens_sudo[:1].id)"
|
|
/>
|
|
<t t-set="selected_method_id"
|
|
t-value="not selected_token_id
|
|
and len(payment_methods_sudo) == 1
|
|
and payment_methods_sudo[:1].id"
|
|
/>
|
|
<t t-set="collapse_payment_methods"
|
|
t-value="tokens_sudo and allow_token_selection and payment_methods_sudo"
|
|
/>
|
|
<t t-set="display_submit_button"
|
|
t-value="True if display_submit_button is None else display_submit_button"
|
|
/>
|
|
<t t-set="pay_label">Pay</t> <!-- Allow translating the label. -->
|
|
<t t-set="save_label">Save</t> <!-- Allow translating the label. -->
|
|
<t t-set="submit_button_label"
|
|
t-value="submit_button_label or (pay_label if mode == 'payment' else save_label)"
|
|
/>
|
|
<form t-if="payment_methods_sudo or tokens_sudo" id="o_payment_form"
|
|
class="o_payment_form"
|
|
t-att-data-mode="mode"
|
|
t-att-data-reference-prefix="reference_prefix"
|
|
t-att-data-amount="amount"
|
|
t-att-data-currency-id="currency and currency.id"
|
|
t-att-data-partner-id="partner_id"
|
|
t-att-data-transaction-route="transaction_route"
|
|
t-att-data-assign-token-route="assign_token_route"
|
|
t-att-data-landing-route="landing_route"
|
|
t-att-data-access-token="access_token"
|
|
>
|
|
<div id="o_payment_form_options" class="d-flex flex-column gap-3">
|
|
<!-- === Payment tokens === -->
|
|
<div t-if="tokens_sudo">
|
|
<!-- === Header === -->
|
|
<h4 id="o_payment_tokens_heading" class="fs-6 small text-uppercase fw-bolder">
|
|
Your payment methods
|
|
</h4>
|
|
<!-- === Body === -->
|
|
<ul class="list-group">
|
|
<t t-foreach="tokens_sudo" t-as="token_sudo">
|
|
<li name="o_payment_option"
|
|
t-att-class="'list-group-item d-flex flex-column gap-2 py-3'
|
|
+ (' o_outline' if allow_token_selection else '')"
|
|
>
|
|
<t t-call="payment.token_form">
|
|
<t t-set="is_selected"
|
|
t-value="token_sudo.id == selected_token_id"
|
|
/>
|
|
</t>
|
|
</li>
|
|
</t>
|
|
</ul>
|
|
</div>
|
|
<!-- === Payment methods === -->
|
|
<div t-if="payment_methods_sudo"
|
|
id="o_payment_methods"
|
|
t-att-class="'collapse' if collapse_payment_methods else ''"
|
|
>
|
|
<!-- === Header === -->
|
|
<h4 class="fs-6 small text-uppercase fw-bolder">
|
|
<t t-if="not collapse_payment_methods">Choose a payment method</t>
|
|
<t t-else="">Other payment methods</t>
|
|
<t t-call="payment.availability_report_button"/>
|
|
</h4>
|
|
<!-- === Body === -->
|
|
<ul class="list-group">
|
|
<t t-foreach="payment_methods_sudo" t-as="pm_sudo">
|
|
<li name="o_payment_option"
|
|
class="list-group-item d-flex flex-column gap-2 py-3 o_outline"
|
|
>
|
|
<t t-call="payment.method_form">
|
|
<t t-set="is_selected"
|
|
t-value="pm_sudo.id == selected_method_id"
|
|
/>
|
|
</t>
|
|
</li>
|
|
</t>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<div class="d-flex justify-content-end flex-column flex-md-row gap-2 my-2">
|
|
<!-- === Expand payment methods button === -->
|
|
<button t-if="collapse_payment_methods"
|
|
name="o_payment_expand_button"
|
|
type="button"
|
|
href="#o_payment_methods"
|
|
class="btn btn-link"
|
|
data-bs-toggle="collapse"
|
|
>
|
|
Choose another method <i class="oi oi-arrow-down"/>
|
|
</button>
|
|
<!-- === Submit button === -->
|
|
<t t-if="display_submit_button" t-call="payment.submit_button"/>
|
|
</div>
|
|
<!-- === Availability report === -->
|
|
<t t-call="payment.availability_report"/>
|
|
</form>
|
|
<t t-else="" t-call="payment.no_pms_available_warning"/>
|
|
</template>
|
|
|
|
<template id="payment.token_form" name="Payment Token Form">
|
|
<!-- Parameters description:
|
|
- token_sudo: The token to display, as a sudoed `payment.token` recordset.
|
|
- allow_token_selection: Whether tokens can be selected for payment or assignation (if
|
|
the `assign_route` parameter is provided); default: `True`.
|
|
- is_selected: Whether the radio button of the token should be checked.
|
|
-->
|
|
<t t-set="provider_sudo" t-value="token_sudo.provider_id"/>
|
|
<t t-set="is_test" t-value="provider_sudo.state == 'test'"/>
|
|
<t t-set="is_unpublished" t-value="not provider_sudo.is_published"/>
|
|
<t t-set="inline_form_xml_id" t-value="provider_sudo.token_inline_form_view_id.xml_id"/>
|
|
<div class="d-flex gap-3 align-items-start align-items-md-center">
|
|
<!-- === Delete button === -->
|
|
<button t-if="allow_token_deletion"
|
|
name="o_payment_delete_token"
|
|
t-att-class="'btn btn-link px-2 py-0 lh-lg z-1'
|
|
+ (' d-none' if mode != 'validation' else '')"
|
|
t-attf-data-linked-radio="o_payment_token_{{token_sudo.id}}"
|
|
>
|
|
<i class="fa fa-trash"
|
|
title="Delete payment method"
|
|
data-bs-toggle="tooltip"
|
|
data-bs-placement="top"
|
|
data-bs-delay="0"
|
|
/>
|
|
</button>
|
|
<div class="row flex-column flex-md-row flex-grow-1 gap-lg-3 align-items-start
|
|
align-items-md-center"
|
|
>
|
|
<div class="col col-lg-5">
|
|
<div t-att-class="'form-check mb-0'
|
|
+ (' ps-0' if not allow_token_selection else '')">
|
|
<!-- === Radio button === -->
|
|
<input t-attf-id="o_payment_token_{{token_sudo.id}}"
|
|
name="o_payment_radio"
|
|
type="radio"
|
|
t-att-checked="is_selected"
|
|
t-att-disabled="not allow_token_selection"
|
|
t-att-class="'form-check-input'
|
|
+ (' d-none' if not allow_token_selection else '')"
|
|
data-payment-option-type="token"
|
|
t-att-data-payment-option-id="token_sudo.id"
|
|
t-att-data-provider-code="token_sudo.provider_id._get_code()"
|
|
t-att-data-provider-id="token_sudo.provider_id.id"
|
|
/>
|
|
<div class="d-flex align-items-center flex-wrap gap-2">
|
|
<!-- === Token label === -->
|
|
<label t-out="token_sudo.payment_method_id.name"
|
|
class="o_payment_option_label text-break"
|
|
t-attf-for="o_payment_token_{{token_sudo.id}}"
|
|
/>
|
|
<div class="d-flex flex-nowrap gap-2">
|
|
<!-- === "Unpublished" icon === -->
|
|
<t t-if="is_unpublished" t-call="payment.form_icon">
|
|
<t t-set="icon_name" t-value="'eye-slash'"/>
|
|
<t t-set="color_name" t-value="'danger'"/>
|
|
<t t-set="title" t-value="'Unpublished'"/>
|
|
</t>
|
|
<!-- === "Test mode" icon === -->
|
|
<t t-if="is_test" t-call="payment.form_icon">
|
|
<t t-set="icon_name" t-value="'exclamation-triangle'"/>
|
|
<t t-set="color_name" t-value="'warning'"/>
|
|
<t t-set="title" t-value="'Test mode'"/>
|
|
</t>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- === Token name (payment details) === -->
|
|
<div class="col">
|
|
<p t-out="token_sudo.display_name"
|
|
t-att-class="'mb-0 small fw-bold text-break'
|
|
+ (' ms-4 ms-md-0' if allow_token_selection else '')"
|
|
/>
|
|
</div>
|
|
<!-- === Provider name (only for desktop and tablet) === -->
|
|
<t t-set="hide_secured_by" t-value="False"/>
|
|
<div class="col d-none d-md-block">
|
|
<p name="o_payment_secured_by_desktop" t-att-class="'mb-0 small text-600'
|
|
+ (' ms-4 ms-md-0' if allow_token_selection else '')
|
|
+ (' d-none' if hide_secured_by else '')"
|
|
>
|
|
<span><i class="fa fa-lock"/> Secured by</span>
|
|
<span t-out="dict(provider_sudo._fields['code']._description_selection(
|
|
provider_sudo.env
|
|
))[provider_sudo.code]"
|
|
class="text-break"
|
|
/>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<!-- === Payment method logo === -->
|
|
<div t-call="payment.form_logo">
|
|
<t t-set="logo_pm_sudo" t-value="token_sudo.payment_method_id"/>
|
|
</div>
|
|
</div>
|
|
<!-- === Inline form === -->
|
|
<div t-if="inline_form_xml_id"
|
|
name="o_payment_inline_form"
|
|
class="position-relative d-none"
|
|
>
|
|
<t t-call="{{inline_form_xml_id}}"/>
|
|
</div>
|
|
<!-- === Provider name (only for mobile) === -->
|
|
<p name="o_payment_secured_by_mobile"
|
|
t-att-class="'align-self-end d-block d-md-none mb-0 small text-600'
|
|
+ (' d-none' if hide_secured_by else '')"
|
|
>
|
|
<span><i class="fa fa-lock"/> Secured by</span>
|
|
<span t-out="dict(provider_sudo._fields['code']._description_selection(
|
|
provider_sudo.env
|
|
))[provider_sudo.code]"
|
|
class="text-break"
|
|
/>
|
|
</p>
|
|
</template>
|
|
|
|
<template id="payment.method_form" name="Payment Method Form">
|
|
<!-- Parameters description:
|
|
- pm_sudo: The payment method to display, as a sudoed `payment.method` recordset.
|
|
- is_selected: Whether the radio button of the payment method should be checked.
|
|
-->
|
|
<t t-set="provider_sudo"
|
|
t-value="pm_sudo.provider_ids.filtered(lambda p: p in providers_sudo)[:1]"
|
|
/>
|
|
<t t-set="is_test" t-value="provider_sudo.state == 'test'"/>
|
|
<t t-set="is_unpublished" t-value="not provider_sudo.is_published"/>
|
|
<t t-set="pms_to_display_sudo" t-value="pm_sudo.brand_ids or pm_sudo"/>
|
|
<t t-set="inline_form_xml_id" t-value="provider_sudo.inline_form_view_id.xml_id"/>
|
|
<div class="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-0 p-0"
|
|
for="o_payment_radio"
|
|
>
|
|
<div class="form-check d-flex flex-grow-1 flex-wrap mb-0">
|
|
<div class="d-flex justify-content-between align-items-center gap-2 flex-wrap w-100">
|
|
<!-- === Radio button === -->
|
|
<input t-attf-id="o_payment_method_{{pm_sudo.id}}"
|
|
name="o_payment_radio"
|
|
type="radio"
|
|
t-att-checked="is_selected"
|
|
class="form-check-input position-absolute mt-0"
|
|
data-payment-option-type="payment_method"
|
|
t-att-data-payment-option-id="pm_sudo.id"
|
|
t-att-data-payment-method-code="pm_sudo.code"
|
|
t-att-data-provider-id="provider_sudo.id"
|
|
t-att-data-provider-code="provider_sudo._get_code()"
|
|
t-att-data-provider-state="provider_sudo.state"
|
|
/>
|
|
<div class="d-flex gap-2 flex-grow-1 me-auto">
|
|
<!-- === Method label === -->
|
|
<label t-out="pm_sudo.name"
|
|
class="o_payment_option_label mb-0 text-break"
|
|
t-attf-for="o_payment_method_{{pm_sudo.id}}"
|
|
/>
|
|
<div class="d-flex flex-nowrap gap-2 mt-1">
|
|
<!-- === "Unpublished" icon === -->
|
|
<t t-if="is_unpublished" t-call="payment.form_icon">
|
|
<t t-set="icon_name" t-value="'eye-slash'"/>
|
|
<t t-set="color_name" t-value="'danger'"/>
|
|
<t t-set="title" t-value="'Unpublished'"/>
|
|
</t>
|
|
<!-- === "Test mode" icon === -->
|
|
<t t-if="is_test" t-call="payment.form_icon">
|
|
<t t-set="icon_name" t-value="'exclamation-triangle'"/>
|
|
<t t-set="color_name" t-value="'warning'"/>
|
|
<t t-set="title" t-value="'Test mode'"/>
|
|
</t>
|
|
</div>
|
|
</div>
|
|
<div class="gap-1 flex-wrap d-flex">
|
|
<!-- === Payment method logos === -->
|
|
<t t-set="pm_index" t-value="0"/>
|
|
<t t-foreach="pms_to_display_sudo" t-as="pm_to_display_sudo">
|
|
<t t-if="pm_index < 4" t-call="payment.form_logo">
|
|
<t t-set="logo_pm_sudo" t-value="pm_to_display_sudo"/>
|
|
</t>
|
|
<t t-set="pm_index" t-value="pm_index + 1"/>
|
|
</t>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- === Help message === -->
|
|
<div t-if="not is_html_empty(provider_sudo.pre_msg)"
|
|
class="w-100 mb-0 ms-4 small text-600"
|
|
>
|
|
<t t-out="provider_sudo.pre_msg"/>
|
|
</div>
|
|
</div>
|
|
<!-- === Inline form === -->
|
|
<div name="o_payment_inline_form" class="position-relative d-none">
|
|
<t t-if="inline_form_xml_id and provider_sudo._should_build_inline_form(
|
|
is_validation=mode == 'validation'
|
|
)"
|
|
t-call="{{inline_form_xml_id}}"
|
|
>
|
|
<t t-set="provider_id" t-value="provider_sudo.id"/>
|
|
</t>
|
|
<div class="d-flex flex-column flex-md-row align-md-items-center justify-content-between
|
|
gap-2 mt-2"
|
|
>
|
|
<!-- === Tokenization checkbox === -->
|
|
<div t-if="mode == 'payment'
|
|
and pm_sudo.support_tokenization
|
|
and show_tokenize_input_mapping[provider_sudo.id]"
|
|
name="o_payment_tokenize_container"
|
|
class="o-checkbox form-check m-0"
|
|
>
|
|
<label>
|
|
<input name="o_payment_tokenize_checkbox"
|
|
type="checkbox"
|
|
class="form-check-input"
|
|
/>
|
|
<small class="text-600">Save my payment details</small>
|
|
</label>
|
|
</div>
|
|
<!-- === Provider name === -->
|
|
<t t-set="hide_secured_by" t-value="False"/>
|
|
<p name="o_payment_secured_by"
|
|
t-att-class="'align-self-end mb-0 ms-auto small text-600'
|
|
+ (' d-none' if hide_secured_by else '')"
|
|
>
|
|
<span><i class="fa fa-lock"/> Secured by</span>
|
|
<span t-out="dict(provider_sudo._fields['code']._description_selection(
|
|
provider_sudo.env
|
|
))[provider_sudo.code]"
|
|
class="text-break"
|
|
/>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<template id="payment.form_icon" name="Form Icon">
|
|
<!-- Parameters description:
|
|
- icon_name: The name of the FontAwesome icon.
|
|
- color_name: The class name of the color (`warning`, `danger`...).
|
|
- title: The title to display on hover.
|
|
-->
|
|
<i t-attf-class="fa fa-{{icon_name}} text-{{color_name}} position-relative z-1"
|
|
t-att-title="title"
|
|
data-bs-toggle="tooltip"
|
|
data-bs-placement="top"
|
|
data-bs-delay="0"
|
|
/>
|
|
</template>
|
|
|
|
<template id="payment.form_logo" name="Form Logo">
|
|
<!-- Parameters description:
|
|
- logo_pm_sudo: The payment method whose logo to display, as a sudoed `payment.method`
|
|
record.
|
|
-->
|
|
<span t-field="logo_pm_sudo.image_payment_form"
|
|
t-options="{'widget': 'image', 'alt-field': 'name'}"
|
|
class="position-relative d-block rounded overflow-hidden z-1 shadow-sm"
|
|
t-att-title="logo_pm_sudo.name"
|
|
data-bs-toggle="tooltip"
|
|
data-bs-placement="top"
|
|
data-bs-delay="0"
|
|
/>
|
|
</template>
|
|
|
|
<template id="payment.submit_button" name="Submit Button">
|
|
<!-- Parameters description:
|
|
- label: The label of the submit button.
|
|
-->
|
|
<button name="o_payment_submit_button"
|
|
type="submit"
|
|
t-out="submit_button_label"
|
|
class="btn btn-primary w-100 w-md-auto ms-auto px-5"
|
|
disabled="true"
|
|
/>
|
|
</template>
|
|
|
|
<template id="payment.no_pms_available_warning">
|
|
<div class="alert alert-warning mt-2">
|
|
<div>
|
|
<strong>No payment method available</strong>
|
|
</div>
|
|
<div t-if="request.env.is_system()" class="mt-2">
|
|
<p t-if="providers_sudo">
|
|
None is configured for:
|
|
<t t-out="request.env.company.country_id.name"/>,
|
|
<t t-out="request.env.company.currency_id.name"/>.
|
|
</p>
|
|
<p t-else="">
|
|
No payment providers are configured.
|
|
</p>
|
|
<a
|
|
t-if="request.env.company.country_id.is_stripe_supported_country
|
|
and not providers_sudo"
|
|
name="activate_stripe"
|
|
href="/odoo/action-payment.action_activate_stripe"
|
|
role="button"
|
|
class="btn btn-primary me-2"
|
|
> ACTIVATE STRIPE </a>
|
|
<a
|
|
t-if="availability_report"
|
|
role="button"
|
|
class="btn-link alert-warning me-2"
|
|
data-bs-toggle="collapse"
|
|
href="#payment_availability_report"
|
|
>
|
|
<strong><i class="fa fa-file-text"/> Show availability report</strong>
|
|
</a>
|
|
<a
|
|
t-if="not providers_sudo"
|
|
role="button"
|
|
type="action"
|
|
class="btn-link alert-warning me-2"
|
|
href="/odoo/action-payment.action_payment_provider"
|
|
>
|
|
<strong><i class="oi oi-arrow-right"/> Payment Providers</strong>
|
|
</a>
|
|
<a
|
|
t-else=""
|
|
role="button"
|
|
type="action"
|
|
class="btn-link alert-warning"
|
|
href="/odoo/action-payment.action_payment_method"
|
|
>
|
|
<strong><i class="oi oi-arrow-right"/> Payment Methods</strong>
|
|
</a>
|
|
</div>
|
|
<div t-else="" class="mt-2">
|
|
If you believe that it is an error, please contact the website administrator.
|
|
</div>
|
|
</div>
|
|
<!-- === Availability report === -->
|
|
<t t-call="payment.availability_report"/>
|
|
</template>
|
|
|
|
<template id="payment.availability_report_button">
|
|
<a
|
|
t-if="request.env.user._is_system() and availability_report"
|
|
role="button"
|
|
data-bs-toggle="collapse"
|
|
href="#payment_availability_report"
|
|
aria-expanded="false"
|
|
aria-controls="payment_availability_report"
|
|
>
|
|
<i class="fa fa-bug"/>
|
|
</a>
|
|
</template>
|
|
|
|
<template id="payment.availability_report">
|
|
<div
|
|
t-if="request.env.user._is_system() and availability_report"
|
|
id="payment_availability_report"
|
|
class="collapse"
|
|
>
|
|
<h4 class="fs-6 text-uppercase fw-bolder"> Availability report </h4>
|
|
<h6 class="mt-3 text-uppercase fw-normal fs-6"> Payment providers </h6>
|
|
<t t-call="payment.availability_report_records">
|
|
<t t-set="records" t-value="availability_report.get('providers')"/>
|
|
</t>
|
|
<h6 class="mt-3 text-uppercase fw-normal fs-6"> Payment methods </h6>
|
|
<t t-call="payment.availability_report_records">
|
|
<t t-set="records" t-value="availability_report.get('payment_methods')"/>
|
|
</t>
|
|
</div>
|
|
</template>
|
|
|
|
<template id="availability_report_records">
|
|
<!-- Parameters description:
|
|
- records: The records to list in the availability report, as a dict with the structure
|
|
{record: {'available': bool, 'reason': str, supported_providers: list}}.
|
|
-->
|
|
<ul class="list-group">
|
|
<t t-foreach="records" t-as="r">
|
|
<t t-set="available" t-value="records[r]['available']"/>
|
|
<li class="list-group-item ps-0">
|
|
<div class="d-flex gap-2">
|
|
<div class="ms-2">
|
|
<i
|
|
t-attf-class="fa fa-fw fa-{{'check-circle' if available else 'times-circle'}}"
|
|
t-attf-style="color: {{'green' if available else 'red'}};"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<p class="lead mb-0">
|
|
<span class="fw-normal"><t t-out="r.name"/></span>
|
|
<span class="text-muted">(ID: <t t-out="r.id"/>)</span>
|
|
</p>
|
|
<t t-if="not available">
|
|
<p class="mb-0 fw-light">
|
|
Reason: <t t-out="records[r]['reason']"/>
|
|
</p>
|
|
</t>
|
|
<t t-if="r._name == 'payment.method' and 'supported_providers' in records[r]">
|
|
<p class="mb-0 fw-light">
|
|
Supported providers:
|
|
<t t-foreach="records[r]['supported_providers']" t-as="p">
|
|
<span t-attf-class="text-{{'success' if p[1] else 'danger'}}">
|
|
<t t-out="p[0].name"/>
|
|
</span>
|
|
<t t-if="records[r]['supported_providers'][-1] != p">,</t>
|
|
</t>
|
|
</p>
|
|
</t>
|
|
</div>
|
|
</div>
|
|
</li>
|
|
</t>
|
|
</ul>
|
|
</template>
|
|
|
|
</odoo>
|