summaryrefslogtreecommitdiff
path: root/addons/payment/views
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/payment/views
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/payment/views')
-rw-r--r--addons/payment/views/account_invoice_views.xml28
-rw-r--r--addons/payment/views/account_payment_views.xml21
-rw-r--r--addons/payment/views/assets.xml15
-rw-r--r--addons/payment/views/payment_acquirer_onboarding_templates.xml92
-rw-r--r--addons/payment/views/payment_portal_templates.xml169
-rw-r--r--addons/payment/views/payment_templates.xml186
-rw-r--r--addons/payment/views/payment_views.xml439
-rw-r--r--addons/payment/views/res_partner_views.xml29
8 files changed, 979 insertions, 0 deletions
diff --git a/addons/payment/views/account_invoice_views.xml b/addons/payment/views/account_invoice_views.xml
new file mode 100644
index 00000000..8e57cda0
--- /dev/null
+++ b/addons/payment/views/account_invoice_views.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<odoo>
+ <data>
+ <record id="account_invoice_view_form_inherit_payment" model="ir.ui.view">
+ <field name="name">account.move.view.form.inherit.payment</field>
+ <field name="model">account.move</field>
+ <field name="inherit_id" ref="account.view_move_form"/>
+ <field name="arch" type="xml">
+ <!--
+ The user must capture/void the authorized transactions before registering a new payment.
+ -->
+ <xpath expr="//button[@id='account_invoice_payment_btn']" position="attributes">
+ <attribute name="attrs">{'invisible': ['|', '|', '|', ('state', '!=', 'posted'), ('payment_state', 'not in', ('partial', 'not_paid')), ('move_type', 'not in', ('out_invoice', 'out_refund', 'in_invoice', 'in_refund', 'out_receipt', 'in_receipt')), ('authorized_transaction_ids', '!=', [])]}</attribute>
+ </xpath>
+ <xpath expr="//button[@id='account_invoice_payment_btn']" position="after">
+ <field name="authorized_transaction_ids" invisible="1"/>
+ <button name="payment_action_capture" type="object"
+ string="Capture Transaction" class="oe_highlight"
+ attrs="{'invisible': ['|', '|', ('move_type', 'not in', ('out_invoice', 'out_refund', 'in_invoice', 'in_refund')), ('state', '!=', 'posted'), ('authorized_transaction_ids', '=', [])]}"/>
+ <button name="payment_action_void" type="object"
+ string="Void Transaction"
+ confirm="Are you sure you want to void the authorized transaction? This action can't be undone."
+ attrs="{'invisible': ['|', '|', ('move_type', 'not in', ('out_invoice', 'out_refund', 'in_invoice', 'in_refund')), ('state', '!=', 'posted'), ('authorized_transaction_ids', '=', [])]}"/>
+ </xpath>
+ </field>
+ </record>
+ </data>
+</odoo>
diff --git a/addons/payment/views/account_payment_views.xml b/addons/payment/views/account_payment_views.xml
new file mode 100644
index 00000000..c6ce4c1a
--- /dev/null
+++ b/addons/payment/views/account_payment_views.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<odoo>
+ <data>
+ <record id="view_account_payment_form_inherit_payment" model="ir.ui.view">
+ <field name="name">view.account.payment.form.inherit.payment</field>
+ <field name="model">account.payment</field>
+ <field name="inherit_id" ref="account.view_account_payment_form"/>
+ <field name="arch" type="xml">
+ <xpath expr='//group[2]' position="inside">
+ <field name="payment_transaction_id" groups="base.group_no_one" attrs="{'invisible': [('payment_method_code', '!=', 'electronic')]}"/>
+ </xpath>
+ <field name="payment_method_id" position="after">
+ <field name="payment_method_code" invisible="1"/>
+ <field name="related_partner_ids" invisible="1"/>
+ <field name="payment_token_id" options="{'no_create': True}"
+ attrs="{'invisible': [('payment_method_code', '!=', 'electronic')], 'readonly': [('state', '!=', 'draft')]}"/>
+ </field>
+ </field>
+ </record>
+ </data>
+</odoo>
diff --git a/addons/payment/views/assets.xml b/addons/payment/views/assets.xml
new file mode 100644
index 00000000..a1a2206e
--- /dev/null
+++ b/addons/payment/views/assets.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+ <template id="assets_frontend" inherit_id="web.assets_frontend">
+ <xpath expr="link[last()]" position="after">
+ <link rel="stylesheet" type="text/scss" href="/payment/static/src/scss/portal_payment.scss"/>
+ <link rel="stylesheet" type="text/scss" href="/payment/static/src/scss/payment_form.scss"/>
+ </xpath>
+ <xpath expr="script[last()]" position="after">
+ <script type="text/javascript" src="/payment/static/lib/jquery.payment/jquery.payment.js"></script>
+ <script type="text/javascript" src="/payment/static/src/js/payment_portal.js"></script>
+ <script type="text/javascript" src="/payment/static/src/js/payment_form.js"></script>
+ <script type="text/javascript" src="/payment/static/src/js/payment_processing.js"></script>
+ </xpath>
+ </template>
+</odoo>
diff --git a/addons/payment/views/payment_acquirer_onboarding_templates.xml b/addons/payment/views/payment_acquirer_onboarding_templates.xml
new file mode 100644
index 00000000..b94d2031
--- /dev/null
+++ b/addons/payment/views/payment_acquirer_onboarding_templates.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+ <!-- onboarding step -->
+ <template id="onboarding_payment_acquirer_step">
+ <t t-call="base.onboarding_step">
+ <t t-set="title">Payment Method</t>
+ <t t-set="description">Choose your default customer payment method.</t>
+ <t t-set="btn_text">Set payments</t>
+ <t t-set="done_text">Payment method set!</t>
+ <t t-set="method" t-value="'action_open_payment_onboarding_payment_acquirer'" />
+ <t t-set="model" t-value="'res.company'" />
+ <t t-set="state" t-value="state.get('payment_acquirer_onboarding_state')" />
+ </t>
+ </template>
+ <!--PAYMENT ACQUIRER-->
+ <record model="ir.ui.view" id="payment_acquirer_onboarding_wizard_form">
+ <field name="name">payment.acquirer.onboarding.wizard.form</field>
+ <field name="model">payment.acquirer.onboarding.wizard</field>
+ <field name="arch" type="xml">
+ <form string="Choose a payment method" class="o_onboarding_payment_acquirer_wizard">
+ <div class="container">
+ <div class="row align-items-start">
+ <div class="col col-4" name="left-column">
+ <group>
+ <field name="payment_method" widget="radio" nolabel="1"/>
+ </group>
+ </div>
+ <div class="col" name="right-column">
+ <div attrs="{'invisible': [('payment_method', '!=', 'paypal')]}">
+ <group>
+ <field name="paypal_user_type" widget="radio" nolabel="1"/>
+ <field name="paypal_email_account" attrs="{'required': [('payment_method', '=', 'paypal')]}" string="Email"/>
+ <field name="paypal_seller_account" attrs="{'invisible': [('paypal_user_type', '=', 'new_user')], 'required': [('paypal_user_type', '!=', 'new_user'), ('payment_method', '=', 'paypal')]}" />
+ <field name="paypal_pdt_token" password="True" attrs="{'invisible': [('paypal_user_type', '=', 'new_user')], 'required': [('paypal_user_type', '!=', 'new_user'), ('payment_method', '=', 'paypal')]}" />
+ </group>
+ <p attrs="{'invisible': [('paypal_user_type', '!=', 'new_user')]}">
+ <span>Start selling directly without an account; an email will be sent by Paypal to create your new account and collect your payments.</span>
+ </p>
+ <p attrs="{'invisible': [('paypal_user_type', '=', 'new_user')]}">
+ <a href="https://www.odoo.com/documentation/14.0/applications/general/payment_acquirers/paypal.html" target="_blank">
+ <span class="fa fa-arrow-right"> How to configure your PayPal account</span>
+ </a>
+ </p>
+ </div>
+ <div attrs="{'invisible': [('payment_method', '!=', 'stripe')]}">
+ <group>
+ <field name="stripe_secret_key" password="True"
+ attrs="{'required': [('payment_method', '=', 'stripe')]}" />
+ <field name="stripe_publishable_key" password="True"
+ attrs="{'required': [('payment_method', '=', 'stripe')]}" />
+ </group>
+ <p>
+ <a href="https://dashboard.stripe.com/account/apikeys" target="_blank">
+ <span class="fa fa-arrow-right"> Get my Stripe keys</span>
+ </a>
+ </p>
+ </div>
+
+ <div attrs="{'invisible': [('payment_method', '!=', 'other')]}">
+ <button type="object" name="action_onboarding_other_payment_acquirer">
+ Check here
+ </button>
+ to choose another payment method.
+ </div>
+ <div attrs="{'invisible': [('payment_method', '!=', 'manual')]}">
+ <group>
+ <field name="manual_name" attrs="{'required': [('payment_method', '=', 'manual')]}"/>
+ <field name="journal_name" attrs="{'required': [('payment_method', '=', 'manual')]}"/>
+ <field name="acc_number" attrs="{'required': [('payment_method', '=', 'manual')]}"/>
+ <field name="manual_post_msg" attrs="{'required': [('payment_method', '=', 'manual')]}"/>
+ </group>
+ </div>
+ </div>
+ </div>
+ </div>
+ <footer>
+ <button name="add_payment_methods" string="Apply" class="oe_highlight"
+ type="object" />
+ <button special="cancel" string="Cancel" />
+ </footer>
+ </form>
+ </field>
+ </record>
+ <record id="action_open_payment_onboarding_payment_acquirer_wizard" model="ir.actions.act_window">
+ <field name="name">Choose a payment method</field>
+ <field name="type">ir.actions.act_window</field>
+ <field name="res_model">payment.acquirer.onboarding.wizard</field>
+ <field name="view_mode">form</field>
+ <field name="view_id" ref="payment.payment_acquirer_onboarding_wizard_form" />
+ <field name="target">new</field>
+ </record>
+</odoo>
diff --git a/addons/payment/views/payment_portal_templates.xml b/addons/payment/views/payment_portal_templates.xml
new file mode 100644
index 00000000..c126368b
--- /dev/null
+++ b/addons/payment/views/payment_portal_templates.xml
@@ -0,0 +1,169 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+ <data>
+ <template id="pay_methods" name="Payment Methods">
+ <t t-call="portal.frontend_layout">
+ <t t-set="additional_title">Payment Methods</t>
+ <div class="wrap">
+ <div class="container">
+ <div class="row">
+ <div class="col-md-6">
+ <ol class="breadcrumb mt8">
+ <li class="breadcrumb-item"><a href="/my/home"><i class="fa fa-home" role="img" aria-label="Home" title="Home"/></a></li>
+ <li class="breadcrumb-item">Payment Methods</li>
+ </ol>
+ </div>
+ </div>
+ <div class="clearfix">
+ <div class="row">
+ <div class="col-md-8">
+ <h3>Manage Payment Methods</h3>
+ <t t-call="payment.payment_tokens_list">
+ <t t-set="acquirers" t-value="acquirers"/>
+ <t t-set="mode" t-value="'manage'"/>
+ </t>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </t>
+ </template>
+
+ <!-- TDE FIXME: was customize_show=True -->
+ <template id="pay_meth_link" inherit_id="portal.portal_layout">
+ <xpath expr="//div[hasclass('o_portal_my_details')]" position="inside">
+ <t t-if="request.env['payment.acquirer'].search([('state', 'in', ['enabled', 'test']), ('registration_view_template_id', '!=', False), ('payment_flow', '=', 's2s'), ('company_id', '=', request.env.company.id)])">
+ <div class='manage_payment_method mt16'><a href="/my/payment_method">Manage payment methods</a></div>
+ </t>
+ </xpath>
+ </template>
+
+ <template id="pay">
+ <t t-call="portal.frontend_layout">
+ <t t-set="additional_title">Payment</t>
+ <div class="wrap">
+ <div class="container o_website_payment">
+ <h1>Payment</h1>
+ <div class="row mt32 mb32">
+ <div class="col-lg-7">
+ <p><b>Reference:</b> <t t-esc="reference"/></p>
+ <p><b>Amount:</b> <t t-esc="amount" t-options="{'widget': 'monetary', 'display_currency': currency}"/></p>
+ <t t-call="payment.payment_tokens_list" t-if="reference and amount and currency">
+ <t t-set="mode" t-value="'payment'"/>
+ <t t-set="_overriden_reference" t-value="reference"/>
+ <t t-set="reference" t-value="quote_plus(reference).replace('+','%20')"/>
+ <t t-set="prepare_tx_url" t-value="'/website_payment/transaction/v2/' + str(amount) + '/' + str(currency.id) + '/' + reference + (('/' + str(partner_id)) if partner_id else '')"/>
+ <t t-set="form_action" t-value="'/website_payment/token/v2/' + str(amount) + '/' + str(currency.id) + '/' + reference + (('/' + str(partner_id)) if partner_id else '')"/>
+ <t t-set="reference" t-value="_overriden_reference"/>
+ </t>
+ <div t-if="not acquirers" class="alert alert-danger" role="alert">
+ <p>No payment acquirer found.</p>
+ <p>Please configure a payment acquirer.</p>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </t>
+ </template>
+
+ <template id="confirm">
+ <t t-call="portal.frontend_layout">
+ <t t-set="additional_title">Payment</t>
+ <div class="wrap">
+ <div class="container o_website_payment">
+ <h1>Payment</h1>
+ <div class="row">
+ <div class="col-lg-6">
+ <div>
+ <div t-attf-class="alert alert-#{status}" t-raw="message" role="status"/>
+ <div class="form-group row">
+ <label for="form_partner_name" class="col-md-3 col-form-label">From</label>
+ <div class="col-md-9">
+ <span name="form_partner_name" class="form-control" t-esc="tx.partner_name"/>
+ </div>
+ </div>
+ <div class="form-group row">
+ <label for="form_reference" class="col-md-3 col-form-label">Reference</label>
+ <div class="col-md-9">
+ <span name="form_reference" class="form-control" t-esc="tx.reference"/>
+ </div>
+ </div>
+ <div class="form-group row">
+ <label for="form_amount" class="col-md-3 col-form-label">Amount</label>
+ <div class="col-md-9">
+ <span name="form_amount" class="form-control" t-esc="tx.amount" t-options="{'widget': 'monetary', 'display_currency': tx.currency_id}"/>
+ </div>
+ </div>
+
+ <div t-if="tx.acquirer_id.qr_code">
+ <t t-set="qr_code" t-value="tx.acquirer_id.journal_id.bank_account_id.build_qr_code_url(tx.amount, tx.reference, None, tx.currency_id, tx.partner_id)"/>
+ <div class="card-body" t-if="qr_code">
+ <h3>Or scan me with your banking app.</h3>
+ <img class="border border-dark rounded" t-att-src="qr_code"/>
+ </div>
+ </div>
+ <div class="row">
+ <div class="col-md-5 offset-md-3 text-muted">
+ <span t-field="tx.acquirer_id.image_128" t-att-title="tx.acquirer_id.name" role="img" t-att-aria-label="tx.acquirer_id.name" t-options='{"widget": "image", "style":"max-width: 60px; display: inline-block"}'/>
+ <div>Processed by <t t-esc="tx.acquirer_id.name"/>.</div>
+ </div>
+ <div class="col-md-4 mt-2 pl-0">
+ <a role="button" t-attf-class="btn btn-#{status} float-right" href="/my/home"><i class="fa fa-arrow-circle-right"/> Back to My Account</a>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </t>
+ </template>
+
+ <template id="payment_confirmation_status">
+ <!--
+ Inform the portal user about the transaction status.
+
+ To be called with the 'payment_tx_id' value.
+ -->
+ <div t-if="payment_tx_id and payment_tx_id.state == 'pending'" class="alert alert-warning alert-dismissable" role="status">
+ <button type="button" class="close" data-dismiss="alert" aria-label="Close">×</button>
+ <span t-if='payment_tx_id.acquirer_id.pending_msg' t-raw="payment_tx_id.acquirer_id.pending_msg"/>
+ <span t-if='thanks_msg' t-raw="thanks_msg"/>
+ <div t-if="payment_tx_id.acquirer_id.provider == 'transfer' and reference">
+ <b>Communication: </b><span t-esc='reference'/>
+ </div>
+
+ <div t-if="payment_tx_id.acquirer_id.qr_code and (payment_tx_id.acquirer_id.provider == 'transfer')">
+ <t t-set="qr_code" t-value="payment_tx_id.acquirer_id.journal_id.bank_account_id.build_qr_code_url(payment_tx_id.amount,payment_tx_id.reference, None, payment_tx_id.currency_id, payment_tx_id.partner_id)"/>
+ <div class="card-body" t-if="qr_code">
+ <h3>Or scan me with your banking app.</h3>
+ <img class="border border-dark rounded" t-att-src="qr_code"/>
+ </div>
+ </div>
+ </div>
+ <div t-if="payment_tx_id and payment_tx_id.state == 'authorized' and payment_tx_id.acquirer_id.authorize_implemented" class="alert alert-success alert-dismissable" role="alert">
+ <button type="button" class="close" data-dismiss="alert" title="Dismiss" aria-label="Dismiss">×</button>
+ <!-- Your payment has been authorized. -->
+ <span t-if='payment_tx_id.acquirer_id.auth_msg' t-raw="payment_tx_id.acquirer_id.auth_msg"/>
+ </div>
+ <div t-if="payment_tx_id and payment_tx_id.state == 'done'" class="alert alert-success alert-dismissable">
+ <button type="button" class="close" data-dismiss="alert" title="Dismiss" aria-label="Dismiss">×</button>
+ <span t-if='payment_tx_id.acquirer_id.done_msg' t-raw="payment_tx_id.acquirer_id.done_msg"/>
+ <span t-if='thanks_msg' t-raw="thanks_msg"/>
+ <div t-if="thanks_msg and payment_tx_id.acquirer_id.provider == 'transfer' and reference">
+ <b>Communication: </b><span t-esc='reference'/>
+ </div>
+ </div>
+ <div t-if="payment_tx_id and payment_tx_id.state == 'cancel'" class="alert alert-danger alert-dismissable">
+ <button type="button" class="close" data-dismiss="alert" title="Dismiss" aria-label="Dismiss">×</button>
+ <span t-if='payment_tx_id.acquirer_id.cancel_msg' t-raw="payment_tx_id.acquirer_id.cancel_msg"/>
+ </div>
+ <div t-if="payment_tx_id and payment_tx_id.state_message">
+ <span t-esc="payment_tx_id.state_message"/>
+ </div>
+ </template>
+
+ </data>
+</odoo>
diff --git a/addons/payment/views/payment_templates.xml b/addons/payment/views/payment_templates.xml
new file mode 100644
index 00000000..b8de80be
--- /dev/null
+++ b/addons/payment/views/payment_templates.xml
@@ -0,0 +1,186 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+ <template id="assets_backend" name="Payment Assets Backend" inherit_id="web.assets_backend">
+ <xpath expr="." position="inside">
+ <link rel="stylesheet" type="text/scss" href="/payment/static/src/scss/payment_acquirer.scss"/>
+ </xpath>
+ </template>
+
+ <template id="payment_tokens_list" name="Payment Tokens list">
+ <!--
+ Variables description:
+ - 'submit_txt' the text displayed inside the submit button
+ - 'submit_class' the css classes to style the submit button
+ - 'icon_class' font awesome class (e.g. 'fa-trash', 'fa-lock')
+ - 'form_action' the URI to the page that will handle the form values given for server2server
+ - 'pms' the tokens
+ - 'checked_pm_id' the payment token that should be checked (for radio buttons)
+ - 'mode' can take two values, either 'payment' or 'manage'. 'manage' displays the add a new card and delete buttons. 'payment'
+ display a form that is used to pay and send the information to the form action url.
+ - 'acquirers' the list of both server2server and form payment acquirers
+ - 'verify_validity' if we need to verify if the payment method is valid when adding a new one
+ - 'prepare_tx_url' the url of the route which will handle the creation of a transaction for a form base payment (handles if the transaction is form or form_save)
+ - 'show_manage_btn' if True, a button is added in the footer to manage payment methods
+ -->
+ <form t-if="pms or acquirers" method="post" class="o_payment_form mt-3 clearfix"
+ t-att-action="form_action if form_action else '#'"
+ t-att-data-success-url="success_url or ''"
+ t-att-data-error-url="error_url or ''"
+ t-att-data-access-token="access_token or ''"
+ t-att-data-partner-id="partner_id"
+ t-att-data-callback-method="callback_method or ''"
+ t-att-data-order-id="order_id or ''"
+ t-att-data-invoice-id="invoice_id or ''"
+ t-att-data-mode="mode">
+ <input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
+ <input type="hidden" t-if="prepare_tx_url" name="prepare_tx_url" t-att-value="prepare_tx_url"/>
+ <input type="hidden" t-if="order_id" name="order_id" t-att-value="order_id"/>
+ <input type="hidden" t-if="invoice_id" name="invoice_id" t-att-value="invoice_id"/>
+ <!-- s2s form submission -->
+ <input type="hidden" t-if="access_token" name="access_token" t-att-value="access_token"/>
+ <input type="hidden" t-if="success_url" name="success_url" t-att-value="success_url"/>
+ <input type="hidden" t-if="error_url" name="error_url" t-att-value="error_url"/>
+ <input type="hidden" t-if="callback_method" name="callback_method" t-att-value="callback_method"/>
+
+ <div class="card">
+ <t t-set="acquirers_count" t-value="len(acquirers) if acquirers else 0"/>
+ <t t-set="pms_count" t-value="len(pms) if pms else 0"/>
+ <t t-set="MAX_BRAND_LINE" t-value="3"/>
+ <t t-foreach="acquirers" t-as="acq">
+ <div class="card-body o_payment_acquirer_select">
+ <label>
+ <t t-if="acq.payment_flow == 'form'">
+ <input type="radio" t-att-data-acquirer-id="acq.id"
+ t-att-data-form-payment="true"
+ t-att-data-provider="acq.provider"
+ t-att-class="'d-none' if (acquirers_count==1 and pms_count==0) else ''"
+ name="pm_id" t-attf-value="form_{{acq.id}}"
+ t-att-checked="acquirers_count==1 and pms_count==0 or acquirers[0] == acq"/>
+ </t>
+ <t t-else="acq.payment_flow == 's2s'">
+ <input type="radio" t-att-data-acquirer-id="acq.id"
+ t-att-data-s2s-payment="true"
+ t-att-data-provider="acq.provider"
+ name="pm_id" t-attf-value="new_{{acq.id}}"
+ t-att-class="'d-none' if (acquirers_count==1 and pms_count==0) else ''"
+ t-att-checked="acquirers_count==1 and pms_count==0 or acquirers[0] == acq"/>
+ </t>
+ <span class="payment_option_name">
+ <t t-esc="acq.display_as or acq.name"/>
+ <div t-if="acq.state == 'test'" class="badge-pill badge-warning float-right" style="margin-left:5px">
+ Test Mode
+ </div>
+ </span>
+ <t t-if="acq_extra_fees and acq_extra_fees.get(acq)">
+ <span class="badge badge-pill badge-secondary"> + <t t-esc="acq_extra_fees[acq]" t-options='{"widget": "monetary", "display_currency": acq_extra_fees["currency_id"]}'/> Fee </span>
+ </t>
+ <t t-elif="acq.fees_active">
+ <small class="text-muted">(Some fees may apply)</small>
+ </t>
+ </label>
+ <ul class="float-right list-inline payment_icon_list">
+ <t t-set="i" t-value="0"/>
+ <t t-foreach="acq.payment_icon_ids" t-as="pm_icon">
+ <li t-attf-class="list-inline-item#{'' if (i &lt; MAX_BRAND_LINE) else ' d-none'}">
+ <span t-field="pm_icon.image_payment_form"
+ t-options='{"widget": "image", "alt-field": "name"}'/>
+ </li>
+ <li t-if="i==MAX_BRAND_LINE" style="display:block;" class="list-inline-item">
+ <span class="float-right more_option text-info">
+ <a href="#" class="o_payment_form_pay_icon_more" data-toggle="tooltip" t-att-title="', '.join([opt.name for opt in acq.payment_icon_ids[MAX_BRAND_LINE:]])">and more</a>
+ </span>
+ </li>
+ <t t-set="i" t-value="i+1"/>
+ </t>
+ </ul>
+ <div t-raw="acq.pre_msg" class="text-muted ml-3"/>
+ </div>
+ <t t-if="acq.payment_flow == 'form'">
+ <div t-attf-id="o_payment_form_acq_{{acq.id}}"
+ t-attf-class="d-none {{'card-footer' if acq.save_token == 'ask' else ''}}">
+ <label t-if="acq.save_token == 'ask'">
+ <input type="checkbox" name="o_payment_form_save_token" data-remove-me=""/>
+ Save my payment data
+ </label>
+ <t t-if="acq.save_token == 'always'">
+ <input type="checkbox" name="o_payment_form_save_token" checked="'checked'" class="o_hidden" data-remove-me=""/>
+ </t>
+ </div>
+ </t>
+ <t t-else="acq.payment_flow == 's2s'">
+ <div t-attf-id="o_payment_add_token_acq_{{acq.id}}"
+ t-attf-class="card-footer {{'d-none' if(acquirers_count &gt; 1 and pms_count==0 and acquirers[0]!=acq) else 'd-none' if pms_count &gt;0 else ''}}">
+ <div class="clearfix">
+ <input type="hidden" t-if="(verify_validity==True or mode == 'manage') and acq.check_validity" name="verify_validity" t-att-value="acq.check_validity"/>
+ <t t-call="{{acq.sudo().get_s2s_form_xml_id()}}">
+ <t t-set="id" t-value="acq.id"/>
+ <t t-set="partner_id" t-value="partner_id"/>
+ <t t-if="not return_url" t-set="return_url" t-value="''"/>
+ </t>
+ </div>
+ </div>
+ </t>
+ </t>
+ <t t-foreach="pms" t-as="pm">
+ <t t-if="not verify_validity or (pm.acquirer_id.check_validity and pm.verified) or not pm.acquirer_id.check_validity">
+ <div class="card-body o_payment_acquirer_select">
+ <label>
+ <input t-if="mode == 'payment'" type="radio" name="pm_id" t-att-value="pm.id" t-att-checked="checked_pm_id == pm.id"/>
+ <span class="payment_option_name" t-esc="pm.name"/>
+ <t t-if="pm.verified">
+ <i class="fa fa-check text-success" title="This payment method is verified by our system." role="img" aria-label="Ok"></i>
+ </t>
+ <t t-else="">
+ <i class="fa fa-check text-muted" title="This payment method has not been verified by our system." role="img" aria-label="Not verified"></i>
+ </t>
+ </label>
+ <button t-if="mode == 'manage'" name="delete_pm" t-att-value="pm.id" class="btn btn-primary btn-sm float-right">
+ <i class="fa fa-trash"></i> Delete
+ </button>
+ </div>
+ </t>
+ </t>
+ </div>
+ <div t-if='back_button_txt' class="float-left mt-2">
+ <a role="button" t-att-href="back_button_link or '#'" t-att-class="back_button_class or 'btn btn-lg btn-secondary'">
+ <i t-if="back_button_icon_class" t-attf-class="fa {{back_button_icon_class}}"/>
+ <t t-esc="back_button_txt"/>
+ </a>
+ </div>
+ <div class="float-right mt-2">
+ <button t-if="mode == 'payment'" id="o_payment_form_pay" type="submit" t-att-class="submit_class if submit_class else 'btn btn-primary btn-lg mb8 mt8'" disabled="true">
+ <t t-if="submit_txt">
+ <i t-if="icon_class and not icon_right" t-attf-class="fa {{icon_class}}"/>
+ <t t-esc="submit_txt"/>
+ <i t-if="icon_class and icon_right" t-attf-class="fa {{icon_class}}"/>
+ </t>
+ <t t-else="">
+ <i class="fa fa-lock"/> Pay
+ </t>
+ </button>
+ <t t-if="show_manage_btn">
+ <a class="btn btn-link mb8 mt8" href="/my/payment_method">Manage your payment methods</a>
+ </t>
+ <button t-if="mode == 'manage' and list(filter(lambda x: x.payment_flow == 's2s', acquirers))" type="submit" id="o_payment_form_add_pm" class="btn btn-primary btn-lg mb8 mt8">
+ <i class="fa fa-plus-circle"/> Add new card
+ </button>
+ </div>
+ </form>
+ </template>
+
+ <template id="payment_process_page" name="Payment processing page">
+ <t t-call="portal.frontend_layout">
+ <div class="wrap">
+ <div class="container o_website_payment">
+ <div class="o_payment_processing">
+ <div class="row">
+ <div class="o_payment_processing_content col-sm-6 col-sm-offset-3">
+ <!-- The content here is generated in JS -->
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </t>
+ </template>
+</odoo>
diff --git a/addons/payment/views/payment_views.xml b/addons/payment/views/payment_views.xml
new file mode 100644
index 00000000..9925b8d1
--- /dev/null
+++ b/addons/payment/views/payment_views.xml
@@ -0,0 +1,439 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+ <data>
+
+ <record id="acquirer_form" model="ir.ui.view">
+ <field name="name">payment.acquirer.form</field>
+ <field name="model">payment.acquirer</field>
+ <field name="arch" type="xml">
+ <form string="Payment Acquirer">
+ <field name="fees_implemented" invisible='1'/>
+ <field name="token_implemented" invisible='1'/>
+ <field name="authorize_implemented" invisible="1"/>
+ <sheet>
+ <field name="module_id" invisible="1"/>
+ <field name="module_state" invisible="1"/>
+ <field name="module_to_buy" invisible="1"/>
+ <field name="inbound_payment_method_ids" invisible="1"/>
+ <field name="image_128" widget="image" class="oe_avatar"/>
+ <widget name="web_ribbon" title="Disabled" bg_color="bg-danger" attrs="{'invisible': [('state', '!=', 'disabled')]}"/>
+ <widget name="web_ribbon" title="Test Mode" bg_color="bg-warning" attrs="{'invisible': [('state', '!=', 'test')]}"/>
+ <div class="oe_title">
+ <h1><field name="name" placeholder="Name"/></h1>
+ <div attrs="{'invisible': ['|', ('module_state', '=', 'installed'), ('module_id', '=', False)]}">
+ <a attrs="{'invisible': [('module_to_buy', '=', False)]}" href="https://odoo.com/pricing?utm_source=db&amp;utm_medium=module" class="btn btn-info" role="button">Upgrade</a>
+ <button attrs="{'invisible': [('module_to_buy', '=', True)]}" type="object" class="btn btn-primary" name="button_immediate_install" string="Install"/>
+ </div>
+ </div>
+ <div attrs="{'invisible': ['|', ('module_state', '=', 'installed'), ('module_id', '=', False)]}">
+ <div class="o_payment_acquirer_desc">
+ <field name="description"/>
+ </div>
+ </div>
+ <group>
+ <group name="payment_state">
+ <field name="provider" groups="base.group_no_one" attrs="{'invisible': [('module_id', '!=', False), ('module_state', '!=', 'installed')]}"/>
+ <field name="state" widget="radio" attrs="{'invisible': [('module_state', '=', 'uninstalled')]}"/>
+ <field name="company_id" groups="base.group_multi_company" options='{"no_open":True}'/>
+ </group>
+ </group>
+ <notebook attrs="{'invisible': ['&amp;', ('module_id', '!=', False), ('module_state', '!=', 'installed')]}">
+ <page string="Credentials" name="acquirer_credentials" attrs="{'invisible': [('provider', '=', 'manual')]}">
+ <group name="acquirer">
+ </group>
+ </page>
+ <page string="Configuration" name="configuration">
+ <group name="acquirer_config">
+ <group string="Payment Form" name="payment_form">
+ <field name="display_as" placeholder="If not defined, the acquirer name will be used."/>
+ <field name="payment_icon_ids" widget="many2many_tags"/>
+ <field name="save_token" widget="radio" attrs="{'invisible': ['|', ('token_implemented', '=', False), ('payment_flow', '=', 's2s')]}"/>
+ <field name="capture_manually" attrs="{'invisible': [('authorize_implemented', '=', False)]}"/>
+ <field name="payment_flow" widget="radio" attrs="{'invisible': [('token_implemented', '=', False)]}"/>
+ <field name="view_template_id" groups="base.group_no_one"/>
+ <field name="registration_view_template_id" groups="base.group_no_one" attrs="{'invisible': [('payment_flow', '!=', 's2s')]}"/>
+ <field name="check_validity" attrs="{'invisible': [('payment_flow', '!=', 's2s')]}" groups="base.group_no_one"/>
+ <field name="qr_code" attrs="{'invisible': [('provider', '!=', 'transfer')]}"/>
+ </group>
+ <group string="Availability" name="availability">
+ <field name="country_ids" widget="many2many_tags" placeholder="Select countries. Leave empty to use everywhere."/>
+ </group>
+ <group string="Payment Followup" name="payment_followup">
+ <field name="journal_id" context="{'default_type': 'bank'}"
+ attrs="{'required': [('state', '!=', 'disabled'), ('provider', 'not in', ['manual', 'transfer'])]}"/>
+ </group>
+ </group>
+ </page>
+ <page string="Fees" name="fees" attrs="{'invisible': [('fees_implemented', '=', False)]}">
+ <group name="payment_fees">
+ <field name="fees_active"/>
+ <field name="fees_dom_fixed" attrs="{'invisible': [('fees_active', '=', False)]}"/>
+ <field name="fees_dom_var" attrs="{'invisible': [('fees_active', '=', False)]}"/>
+ <field name="fees_int_fixed" attrs="{'invisible': [('fees_active', '=', False)]}"/>
+ <field name="fees_int_var" attrs="{'invisible': [('fees_active', '=', False)]}"/>
+ </group>
+ </page>
+ <page string="Messages"
+ name="messages"
+ attrs="{'invisible': [('module_id', '=', True), ('module_state', '!=', 'installed')]}">
+ <group>
+ <field name="pre_msg"/>
+ <field name="auth_msg" attrs="{'invisible': [('authorize_implemented', '=', False)]}"/>
+ <field name="pending_msg"/>
+ <field name="done_msg"/>
+ <field name="cancel_msg"/>
+ </group>
+ </page>
+ </notebook>
+ </sheet>
+ </form>
+ </field>
+ </record>
+
+
+ <!-- Acquirer Kanban View -->
+ <record id="acquirer_kanban" model="ir.ui.view">
+ <field name="name">payment.acquirer.kanban</field>
+ <field name="model">payment.acquirer</field>
+ <field name="arch" type="xml">
+ <kanban quick_create="false" create="true" class="o_kanban_payment_acquirer o_kanban_dashboard">
+ <field name="id"/>
+ <field name="name"/>
+ <field name="description"/>
+ <field name="provider"/>
+ <field name="module_id"/>
+ <field name="module_state"/>
+ <field name="module_to_buy"/>
+ <field name="color"/>
+ <templates>
+ <t t-name="kanban-box">
+ <t t-set="installed" t-value="!record.module_id.value || (record.module_id.value &amp;&amp; record.module_state.raw_value === 'installed')"/>
+ <t t-set="to_buy" t-value="record.module_to_buy.raw_value === true"/>
+ <div t-attf-class="oe_kanban_global_click #{kanban_color(record.color.raw_value)}">
+ <div class="o_payment_acquirer_desc">
+ <div class="o_kanban_image">
+ <img type="open" t-att-src="kanban_image('payment.acquirer', 'image_128', record.id.raw_value)" alt="Acquirer"/>
+ </div>
+ <h3 class="mt4"><t t-esc="record.name.value"/></h3>
+ <t t-if="record.description.raw_value" t-raw="record.description.raw_value"/>
+ </div>
+ <div class="o_payment_acquirer_bottom">
+ <t t-if="installed">
+ <field name="state" widget="label_selection" options="{'classes': {'enabled': 'success', 'test': 'warning', 'disabled' : 'danger'}}"/>
+ </t>
+ <button t-if="!installed and !selection_mode and !to_buy" type="object" class="btn btn-secondary float-right" name="button_immediate_install">Install</button>
+ <t t-if="!installed and to_buy">
+ <button href="https://odoo.com/pricing?utm_source=db&amp;utm_medium=module" class="btn btn-info btn-sm float_right">Upgrade</button>
+ <span class="badge badge-primary oe_inline o_enterprise_label">Enterprise</span>
+ </t>
+ <button t-if="installed and record.state.raw_value == 'disabled' and !selection_mode" type="edit" class="btn btn-primary float-right">Activate</button>
+ <button t-if="installed and record.state.raw_value in ['enabled', 'test'] and !selection_mode" type="edit" class="btn btn-primary float-right">Configure</button>
+ </div>
+ </div>
+ </t>
+ </templates>
+ </kanban>
+ </field>
+ </record>
+
+ <record id="acquirer_list" model="ir.ui.view">
+ <field name="name">payment.acquirer.list</field>
+ <field name="model">payment.acquirer</field>
+ <field name="arch" type="xml">
+ <tree string="Payment Acquirers">
+ <field name="sequence" widget="handle"/>
+ <field name="name"/>
+ <field name="provider"/>
+ <field name="state"/>
+ <field name="country_ids" widget="many2many_tags" optional="hide"/>
+ <field name="company_id" groups="base.group_multi_company"/>
+ </tree>
+ </field>
+ </record>
+
+ <record id="acquirer_search" model="ir.ui.view">
+ <field name="name">payment.acquirer.search</field>
+ <field name="model">payment.acquirer</field>
+ <field name="arch" type="xml">
+ <search>
+ <field name="name" string="Acquirer" filter_domain="['|', ('name','ilike',self), ('description','ilike',self)]"/>
+ <field name="provider"/>
+ <filter name="acquirer_installed" string="Installed" domain="[('provider', '!=', 'manual')]"/>
+ <group expand="0" string="Group By">
+ <filter string="Provider" name="provider" domain="[]" context="{'group_by': 'provider'}"/>
+ <filter string="State" name="state" domain="[]" context="{'group_by': 'state'}"/>
+ </group>
+ </search>
+ </field>
+ </record>
+
+ <record id="action_payment_acquirer" model="ir.actions.act_window">
+ <field name="name">Payment Acquirers</field>
+ <field name="res_model">payment.acquirer</field>
+ <field name='view_mode'>kanban,tree,form</field>
+ <field name="help" type="html">
+ <p class="o_view_nocontent_smiling_face">
+ Create a new payment acquirer
+ </p>
+ </field>
+ </record>
+
+ <menuitem
+ action='action_payment_acquirer'
+ id='payment_acquirer_menu'
+ parent='account.root_payment_menu'
+ sequence='10' />
+
+ <!-- Payment transactions -->
+ <record id="transaction_form" model="ir.ui.view">
+ <field name="name">payment.transaction.form</field>
+ <field name="model">payment.transaction</field>
+ <field name="arch" type="xml">
+ <form string="Payment Transactions" create="false" edit="false">
+ <header>
+ <button type="object" name="action_capture" states="authorized" string="Capture Transaction" class="oe_highlight"/>
+ <button type="object" name="action_void" states="authorized" string="Void Transaction"
+ confirm="Are you sure you want to void the authorized transaction? This action can't be undone."/>
+ <field name="state" widget="statusbar"/>
+ </header>
+ <sheet>
+ <div class="oe_button_box" name="button_box">
+ <button name="action_view_invoices" type="object"
+ class="oe_stat_button" icon="fa-money"
+ attrs="{'invisible': [('invoice_ids_nbr', '=', 0)]}">
+ <field name="invoice_ids_nbr" widget="statinfo" string="Invoice(s)"/>
+ </button>
+ </div>
+ <group>
+ <group>
+ <field name="reference"/>
+ <field name="payment_id"/>
+ <label for="amount"/>
+ <div class="o_row">
+ <field name="amount"/>
+ <field name="currency_id" options="{'no_open': True, 'no_create': True}"/>
+ </div>
+ <field name="fees" readonly="1"/>
+ <label for="partner_id"/>
+ <div>
+ <field name="partner_id" context="{'show_address': 1}" options="{'always_reload': True}"/>
+ <div name="partner_details" class="o_address_format" attrs="{'invisible': [('partner_id', '!=', False)]}">
+ <field name="partner_name" placeholder="Name" attrs="{'readonly': [('partner_id', '!=', False)]}" class="o_address_street"/>
+ <field name="partner_address" placeholder="Address" attrs="{'readonly': [('partner_id', '!=', False)]}" class="o_address_street"/>
+ <field name="partner_city" placeholder="City" attrs="{'readonly': [('partner_id', '!=', False)]}" class="o_address_city"/>
+ <field name="partner_zip" placeholder="ZIP" attrs="{'readonly': [('partner_id', '!=', False)]}" class="o_address_zip"/>
+ <field name="partner_country_id" placeholder="Country" attrs="{'readonly': [('partner_id', '!=', False)]}" class="o_address_country"/>
+ <field name="partner_lang" attrs="{'readonly': [('partner_id', '!=', False)]}" class="o_address_street"/>
+ <field name="partner_email" placeholder="E-mail" attrs="{'readonly': [('partner_id', '!=', False)]}" class="o_address_street"/>
+ </div>
+ </div>
+ </group>
+ <group>
+ <field name="acquirer_id"/>
+ <field name="provider" invisible="1"/>
+ <field name="payment_token_id" options="{'no_create': True}"/>
+ <field name="acquirer_reference" readonly="1"/>
+ <field name="date"/>
+ </group>
+ </group>
+ <group string="Message">
+ <field name="state_message" nolabel="1"/>
+ </group>
+ </sheet>
+ </form>
+ </field>
+ </record>
+
+ <record id="transaction_list" model="ir.ui.view">
+ <field name="name">payment.transaction.list</field>
+ <field name="model">payment.transaction</field>
+ <field name="arch" type="xml">
+ <tree string="Payment Transactions" create="false">
+ <field name="reference"/>
+ <field name="create_date"/>
+ <field name="acquirer_id"/>
+ <field name="partner_id"/>
+ <field name="partner_name"/>
+ <field name="amount"/>
+ <field name="fees"/>
+ <field name="state"/>
+ </tree>
+ </field>
+ </record>
+
+ <record id="transaction_view_kanban" model="ir.ui.view">
+ <field name="name">payment.transaction.kanban</field>
+ <field name="model">payment.transaction</field>
+ <field name="arch" type="xml">
+ <kanban class="o_kanban_mobile" create="false">
+ <templates>
+ <t t-name="kanban-box">
+ <div t-attf-class="oe_kanban_content oe_kanban_global_click">
+ <div class="row">
+ <div class="col-6">
+ <strong><field name="reference"/></strong>
+ </div>
+ <div class="col-6">
+ <span><field name="partner_name"/></span>
+ </div>
+ <div class="col-6">
+ <span class="float-right">
+ <field name="amount" widget="monetary"/>
+ <field name="currency_id" invisible="1"/>
+ </span>
+ </div>
+ </div>
+ </div>
+ </t>
+ </templates>
+ </kanban>
+ </field>
+ </record>
+
+ <record id="transaction" model="ir.ui.view">
+ <field name="name">payment.transaction.search</field>
+ <field name="model">payment.transaction</field>
+ <field name="arch" type="xml">
+ <search>
+ <field name="reference"/>
+ <field name="acquirer_id"/>
+ <field name="partner_id"/>
+ <field name="partner_name"/>
+ </search>
+ </field>
+ </record>
+
+ <record id="action_payment_transaction" model="ir.actions.act_window">
+ <field name="name">Payment Transactions</field>
+ <field name="res_model">payment.transaction</field>
+ <field name='view_mode'>tree,kanban,form</field>
+ <field name="help" type="html">
+ <p class="o_view_nocontent_smiling_face">
+ Create a new payment transaction
+ </p>
+ </field>
+ </record>
+
+ <menuitem
+ action='action_payment_transaction'
+ id='payment_transaction_menu'
+ parent='account.root_payment_menu'
+ groups="base.group_no_one"
+ sequence='20' />
+
+ <!-- Payment Tokens -->
+ <record model='ir.ui.view' id='payment_token_tree_view'>
+ <field name='name'>payment.token.tree</field>
+ <field name='model'>payment.token</field>
+ <field name='arch' type='xml'>
+ <tree string='Payment Tokens'>
+ <field name="name"/>
+ <field name="active"/>
+ <field name='partner_id' />
+ <field name='acquirer_id' readonly='1'/>
+ <field name='acquirer_ref' readonly='1'/>
+ </tree>
+ </field>
+ </record>
+
+ <record id='payment_token_view_search' model='ir.ui.view'>
+ <field name='name'>payment.token.search</field>
+ <field name='model'>payment.token</field>
+ <field name='arch' type='xml'>
+ <search string='Payment Tokens'>
+ <field name='partner_id'/>
+ <separator/>
+ <filter string="Archived" name="inactive" domain="[('active', '=', False)]"/>
+ </search>
+ </field>
+ </record>
+
+ <record id="action_payment_tx_ids" model="ir.actions.act_window">
+ <field name="name">Payment Transactions</field>
+ <field name="res_model">payment.transaction</field>
+ <field name="view_mode">tree,form</field>
+ <field name="domain">[('payment_token_id','=', active_id)]</field>
+ <field name="context">{'create': False}</field>
+ </record>
+
+ <record model='ir.ui.view' id='payment_token_form_view'>
+ <field name='name'>payment.token.form</field>
+ <field name='model'>payment.token</field>
+ <field name='arch' type='xml'>
+ <form string='Payment Tokens' create='false' editable='bottom'>
+ <sheet>
+ <div class="oe_button_box" name="button_box">
+ <button class="oe_stat_button" name="%(action_payment_tx_ids)d"
+ type="action" icon="fa-money" string="Payments">
+ </button>
+ </div>
+ <group>
+ <field name="name"/>
+ <field name='partner_id' />
+ </group>
+ <group>
+ <field name="active" widget='boolean_toggle'/>
+ <field name='acquirer_id'/>
+ <field name='acquirer_ref'/>
+ </group>
+ </sheet>
+ </form>
+ </field>
+ </record>
+
+ <record model='ir.actions.act_window' id='payment_token_action'>
+ <field name='name'>Saved Payment Data</field>
+ <field name='res_model'>payment.token</field>
+ <field name='view_mode'>tree,form</field>
+ <field name="help" type="html">
+ <p class="o_view_nocontent_smiling_face">
+ Create a saved payment data
+ </p>
+ </field>
+ </record>
+
+ <menuitem
+ action='payment_token_action'
+ id='payment_token_menu'
+ parent='account.root_payment_menu'
+ groups='base.group_no_one'/>
+
+ <!-- Payment icons -->
+ <record model="ir.ui.view" id="payment_icon_form_view">
+ <field name="name">payment.icon.form</field>
+ <field name="model">payment.icon</field>
+ <field name="arch" type="xml">
+ <form string="Payment Icon">
+ <sheet>
+ <field name="image" widget="image" class="oe_avatar"/>
+ <div class="oe_title">
+ <h1><field name="name" placeholder="Name"/></h1>
+ </div>
+ <notebook>
+ <page string="Acquirers list" name="acquirers">
+ <field nolabel="1" name="acquirer_ids"/>
+ </page>
+ </notebook>
+ </sheet>
+ </form>
+ </field>
+ </record>
+
+ <record id="action_payment_icon" model="ir.actions.act_window">
+ <field name="name">Payment Icons</field>
+ <field name="res_model">payment.icon</field>
+ <field name="view_mode">tree,form</field>
+ <field name="help" type="html">
+ <p class="o_view_nocontent_smiling_face">
+ Create a payment icon
+ </p>
+ </field>
+ </record>
+
+ <menuitem
+ action="action_payment_icon"
+ id="payment_icon_menu"
+ parent="account.root_payment_menu"
+ groups="base.group_no_one"/>
+ </data>
+</odoo>
diff --git a/addons/payment/views/res_partner_views.xml b/addons/payment/views/res_partner_views.xml
new file mode 100644
index 00000000..7657ad09
--- /dev/null
+++ b/addons/payment/views/res_partner_views.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<odoo>
+ <data>
+
+ <!-- Add creditcard to res.partner -->
+ <record id="view_partners_form_payment_defaultcreditcard" model="ir.ui.view">
+ <field name="name">view.res.partner.form.payment.defaultcreditcard</field>
+ <field name="model">res.partner</field>
+ <field name="inherit_id" ref="base.view_partner_form"/>
+ <field name="priority" eval="15"/>
+ <field name="arch" type="xml">
+ <div name="button_box" position="inside">
+ <button type="action" class="oe_stat_button"
+ icon="fa-credit-card"
+ name="%(payment.payment_token_action)d"
+ context="{'search_default_partner_id': active_id, 'create': False, 'edit': False}"
+ attrs="{'invisible': [('payment_token_count', '=', 0)]}">
+ <div class="o_form_field o_stat_info">
+ <span class="o_stat_value">
+ <field name="payment_token_count" widget="statinfo" nolabel="1"/>
+ </span>
+ <span class="o_stat_text">Credit Cards</span>
+ </div>
+ </button>
+ </div>
+ </field>
+ </record>
+ </data>
+</odoo>