[MERGE] payment, website_sale: improve view and use of acquirers

Purpose is to ease user flow and understanding when configuring and
managing payment methods. UX of acquirers (form, kanban) and their
integration in ecommerce is improved. Please refer to individual
commits for more details.

This merges 'dev/master-clean-payment-views-jpr-tde'.
This commit is contained in:
Jitendra Prajapati
2017-05-17 14:45:30 +02:00
committed by Thibault Delavallée
7 changed files with 85 additions and 64 deletions
+32 -25
View File
@@ -27,14 +27,16 @@
<p>
A payment gateway to accept online payments via credit cards.
</p>
<ul>
<li><i class="fa fa-check"/>eCommerce</li>
<ul class="list-inline">
<li><i class="fa fa-check"/>Online Payment</li>
<li><i class="fa fa-check"/>Payment Status Tracking</li>
</ul>
</field>
</record>
<record id="payment_acquirer_ogone" model="payment.acquirer">
<field name="name">Ingenico</field>
<field name="sequence">2</field>
<field name="view_template_id" ref="default_acquirer_button"/>
<field name="image" type="base64" file="payment_ogone/static/src/img/ogone_icon.png"/>
<field name="module_id" ref="base.module_payment_ogone"/>
@@ -43,9 +45,10 @@
Ingenico Payment Services (formerly Ogone) supports credit cards, debit cards and bank transfers.
</p>
<ul class="list-inline">
<li><i class="fa fa-check"/>eCommerce</li>
<li><i class="fa fa-check"/>Cards storage</li>
<li><i class="fa fa-check"/>Pay button in emails</li>
<li><i class="fa fa-check"/>Online Payment</li>
<li><i class="fa fa-check"/>Payment Status Tracking</li>
<li><i class="fa fa-check"/>Subscriptions</li>
<li><i class="fa fa-check"/>Save Cards</li>
</ul>
</field>
</record>
@@ -59,14 +62,16 @@
<p>
A payment gateway to accept online payments via credit cards, debit cards and bank transfers.
</p>
<ul>
<li><i class="fa fa-check"/>eCommerce</li>
<ul class="list-inline">
<li><i class="fa fa-check"/>Online Payment</li>
<li><i class="fa fa-check"/>Payment Status Tracking</li>
</ul>
</field>
</record>
<record id="payment_acquirer_authorize" model="payment.acquirer">
<field name="name">Authorize.net</field>
<field name="sequence">3</field>
<field name="view_template_id" ref="default_acquirer_button"/>
<field name="image" type="base64" file="payment_authorize/static/src/img/authorize_icon.png"/>
<field name="module_id" ref="base.module_payment_authorize"/>
@@ -75,15 +80,18 @@
A payment gateway to accept online payments via credit cards and e-checks.
</p>
<ul class="list-inline">
<li><i class="fa fa-check"/>eCommerce</li>
<li><i class="fa fa-check"/>Cards storage</li>
<li><i class="fa fa-check"/>Authorize &amp; Capture</li>
<li><i class="fa fa-check"/>Online Payment</li>
<li><i class="fa fa-check"/>Payment Status Tracking</li>
<li><i class="fa fa-check"/>Subscriptions</li>
<li><i class="fa fa-check"/>Save Cards</li>
<li><i class="fa fa-check"/>Manual Capture</li>
</ul>
</field>
</record>
<record id="payment_acquirer_transfer" model="payment.acquirer">
<field name="name">Wire Transfer</field>
<field name="sequence">2</field>
<field name="view_template_id" ref="default_acquirer_button"/>
<field name="image" type="base64" file="payment_transfer/static/src/img/transfer_icon.png"/>
<field name="module_id" ref="base.module_payment_transfer"/>
@@ -92,9 +100,6 @@
<p>
Provide instructions to customers so that they can pay their orders manually.
</p>
<ul>
<li><i class="fa fa-check"/>eCommerce</li>
</ul>
</field>
</record>
@@ -107,14 +112,16 @@
<p>
A payment gateway from Atos Worldline to accept online payments via credit cards.
</p>
<ul>
<li><i class="fa fa-check"/>eCommerce</li>
<ul class="list-inline">
<li><i class="fa fa-check"/>Online Payment</li>
<li><i class="fa fa-check"/>Payment Status Tracking</li>
</ul>
</field>
</record>
<record id="payment_acquirer_paypal" model="payment.acquirer">
<field name="name">Paypal</field>
<field name="sequence">1</field>
<field name="view_template_id" ref="default_acquirer_button"/>
<field name="image" type="base64" file="payment_paypal/static/src/img/paypal_icon.png"/>
<field name="module_id" ref="base.module_payment_paypal"/>
@@ -123,8 +130,8 @@
PayPal is the easiest way to accept payments via Paypal or credit cards.
</p>
<ul class="list-inline">
<li><i class="fa fa-check"/>eCommerce</li>
<li><i class="fa fa-check"/>Pay button in emails</li>
<li><i class="fa fa-check"/>Online Payment</li>
<li><i class="fa fa-check"/>Payment Status Tracking</li>
</ul>
</field>
</record>
@@ -138,8 +145,9 @@
<p>
A payment gateway to accept online payments via credit cards.
</p>
<ul>
<li><i class="fa fa-check"/>eCommerce</li>
<ul class="list-inline">
<li><i class="fa fa-check"/>Online Payment</li>
<li><i class="fa fa-check"/>Payment Status Tracking</li>
</ul>
</field>
@@ -153,10 +161,10 @@
<field name="module_id" ref="base.module_payment_transfer"/>
<field name="description" type="html">
<p>
A generic acquirer payment acquirer.
A generic payment method to send payment instructions to any payment acquirer.
</p>
<ul>
<li><i class="fa fa-check"/>eCommerce</li>
<ul class="list-inline">
<li><i class="fa fa-check"/>Online Payment</li>
</ul>
</field>
</record>
@@ -171,9 +179,8 @@
PayU India is an online payments solutions company serving the Indian market.
</p>
<ul class="list-inline">
<li><i class="fa fa-check"/>eCommerce</li>
<li><i class="fa fa-check"/>Subscription</li>
<li><i class="fa fa-check"/>Pay button in emails</li>
<li><i class="fa fa-check"/>Online Payment</li>
<li><i class="fa fa-check"/>Payment Status Tracking</li>
</ul>
</field>
</record>
+26 -15
View File
@@ -48,11 +48,11 @@ class PaymentAcquirer(models.Model):
"""
_name = 'payment.acquirer'
_description = 'Payment Acquirer'
_order = 'sequence'
_order = 'website_published desc, sequence, name'
name = fields.Char('Name', required=True, translate=True)
description = fields.Html('Description')
sequence = fields.Integer('Sequence', help="Determine the display order")
sequence = fields.Integer('Sequence', default=10, help="Determine the display order")
provider = fields.Selection(
selection=[('manual', 'Manual Configuration')], string='Provider',
default='manual', required=True)
@@ -73,9 +73,9 @@ class PaymentAcquirer(models.Model):
help="Make this payment acquirer available (Customer invoices, etc.)")
auto_confirm = fields.Selection([
('none', 'No automatic confirmation'),
('authorize', 'Authorize the amount and confirm the SO on acquirer confirmation (capture manually)'),
('confirm_so', 'Authorize & capture the amount and confirm the SO on acquirer confirmation'),
('generate_and_pay_invoice', 'Authorize & capture the amount, confirm the SO and auto-validate the invoice on acquirer confirmation')],
('authorize', 'Authorize the amount and confirm the order on acquirer confirmation (capture manually)'),
('confirm_so', 'Authorize & capture the amount and confirm the order on acquirer confirmation'),
('generate_and_pay_invoice', 'Authorize & capture the amount, confirm the order and auto-validate the invoice on acquirer confirmation')],
string='Order Confirmation', default='confirm_so', required=True)
journal_id = fields.Many2one(
'account.journal', 'Payment Journal',
@@ -109,13 +109,12 @@ class PaymentAcquirer(models.Model):
help='Message displayed, if error is occur during the payment process.')
save_token = fields.Selection([
('none', 'Never'),
('ask', 'Let the customer decide'),
('always', 'Always')],
string='Store Card Data', default='none',
help="Determine if card data is saved as a token automatically or not. "
"Payment tokens allow your customer to reuse their cards in the e-commerce "
"or allow you to charge an invoice directly on a credit card. If set to "
"'let the customer decide', ecommerce customers will have a checkbox displayed on the payment page.")
('ask', 'Let the customer decide (recommended for eCommerce)'),
('always', 'Always (recommended for Subscriptions)')],
string='Save Cards', default='none',
help="This option allows customers to save their credit card as a payment token and to reuse it for a later purchase."
"If you manage subscriptions (recurring invoicing), you need it to automatically charge the customer when you "
"issue an invoice.")
token_implemented = fields.Boolean('Saving Card Data supported', compute='_compute_feature_support')
fees_implemented = fields.Boolean('Fees Computation Supported', compute='_compute_feature_support')
@@ -163,7 +162,7 @@ class PaymentAcquirer(models.Model):
def _check_authorization_support(self):
for acquirer in self:
if acquirer.auto_confirm == 'authorize' and acquirer.provider not in self._get_feature_support()['authorize']:
raise ValidationError('Transaction Authorization is not supported by this payment provider.')
raise ValidationError('You cannot capture payments manually with this payment method. Please choose another Order Confirmation mode (in Configuration tab).')
return True
_constraints = [
@@ -193,6 +192,11 @@ class PaymentAcquirer(models.Model):
image_resize_images(vals)
return super(PaymentAcquirer, self).write(vals)
@api.multi
def toggle_website_published(self):
self.write({'website_published': not self.website_published})
return True
@api.multi
def get_form_action_url(self):
""" Returns the form action URL, for form-based acquirer implementations. """
@@ -406,6 +410,7 @@ class PaymentTransaction(models.Model):
create_date = fields.Datetime('Creation Date', readonly=True)
date_validate = fields.Datetime('Validation Date')
acquirer_id = fields.Many2one('payment.acquirer', 'Acquirer', required=True)
provider = fields.Selection(string='Provider', related='acquirer_id.provider')
type = fields.Selection([
('server2server', 'Server To Server'),
('form', 'Form'),
@@ -433,7 +438,7 @@ class PaymentTransaction(models.Model):
required=True, help='Internal reference of the TX')
acquirer_reference = fields.Char('Acquirer Reference', help='Reference of the TX as stored in the acquirer database')
# duplicate partner / transaction data to store the values at transaction time
partner_id = fields.Many2one('res.partner', 'Partner', track_visibility='onchange')
partner_id = fields.Many2one('res.partner', 'Customer', track_visibility='onchange')
partner_name = fields.Char('Partner Name')
partner_lang = fields.Selection(_lang_get, 'Language', default=lambda self: self.env.lang)
partner_email = fields.Char('Email')
@@ -454,7 +459,7 @@ class PaymentTransaction(models.Model):
@api.onchange('partner_id')
def _onchange_partner_id(self):
onchange_vals = self.on_change_partner_id(self.partner_id.id).get('value', {})
self.write(onchange_vals)
self.update(onchange_vals)
@api.multi
def on_change_partner_id(self, partner_id):
@@ -480,6 +485,12 @@ class PaymentTransaction(models.Model):
raise exceptions.ValidationError(_('The payment transaction reference must be unique!'))
return True
@api.constrains('state', 'acquirer_id')
def _check_authorize_state(self):
failed_tx = self.filtered(lambda tx: tx.state == 'authorized' and tx.acquirer_id.provider not in self.env['payment.acquirer']._get_feature_support()['authorize'])
if failed_tx:
raise exceptions.ValidationError(_('The %s payment acquirers are not allowed to manual capture mode!' % failed_tx.mapped('acquirer_id.name')))
@api.model
def create(self, values):
if values.get('partner_id'): # @TDENOTE: not sure
+20 -13
View File
@@ -30,13 +30,19 @@
<field name="module_id" invisible="1"/>
<field name="module_state" invisible="1"/>
<div class="oe_button_box" name="button_box" attrs="{'invisible': ['&amp;', ('module_id', '!=', False), ('module_state', '!=', 'installed')]}">
<button name="toggle_website_published"
class="oe_stat_button"
type="object" icon="fa-globe">
<field name="website_published" widget="boolean_button"
options='{"terminology": {"string_true": "Published", "hover_false": "Publish"}}'/>
</button>
<!-- transfer referenced here due to view inheritance issue in current master (post-saas-16) -->
<button name="toggle_environment_value"
attrs="{'invisible': ['|', ('environment', '=', 'test'), ('provider', '=', 'transfer')]}"
class="oe_stat_button"
type="object" icon="fa-play">
<div class="o_stat_info o_field_widget">
<span class="text-success">Production</span>
<span class="text-success">Production</span>
<span class="o_stat_text">Environment</span>
</div>
</button>
@@ -141,10 +147,11 @@
<field name="provider"/>
<field name="module_id"/>
<field name="module_state"/>
<field name="website_published"/>
<templates>
<t t-name="kanban-box">
<div class="oe_kanban_global_click">
<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="installed" t-value="!record.module_id.value || (record.module_id.value &amp;&amp; record.module_state.raw_value === 'installed')"/>
<div t-attf-class="oe_kanban_global_click #{installed and record.website_published.raw_value ? 'oe_kanban_color_5' : 'oe_kanban_color_white'}">
<div class="o_kanban_image">
<img type="open" t-att-src="kanban_image('payment.acquirer', 'image_small', record.id.value)"/>
</div>
@@ -157,7 +164,8 @@
<field name="environment" widget="label_selection" options="{'classes': {'test': 'warning', 'production': 'success'}}"/>
</t>
<button t-if="!installed" type="object" class="btn btn-default pull-right btn-sm" name="button_immediate_install">Install</button>
<button t-if="installed" type="edit" class="btn btn-primary pull-right btn-sm">Configure</button>
<button t-if="installed and !record.website_published.raw_value" type="edit" class="btn btn-primary pull-right btn-sm">Activate</button>
<button t-if="installed and record.website_published.raw_value" type="edit" class="btn btn-primary pull-right btn-sm">Configure</button>
</div>
</div>
</t>
@@ -195,13 +203,13 @@
</record>
<record id="action_payment_acquirer" model="ir.actions.act_window">
<field name="name">Payment Acquirers</field>
<field name="name">Payment Methods</field>
<field name="res_model">payment.acquirer</field>
<field name='view_type'>form</field>
<field name='view_mode'>kanban,tree,form</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a payment acquirer.
Click to create a payment method.
</p>
</field>
</record>
@@ -232,11 +240,11 @@
<field name="amount"/>
<field name="currency_id" options="{'no_open': True, 'no_create': True}"/>
</div>
<field name="fees"/>
<field name="partner_id"/>
<label for="partner_details" string="Customer Details"/>
<field name="fees" readonly="1"/>
<label for="partner_id"/>
<div>
<div name="partner_details" class="o_address_format">
<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"/>
@@ -249,8 +257,9 @@
</group>
<group>
<field name="acquirer_id"/>
<field name="provider" invisible="1"/>
<field name="payment_token_id"/>
<field name="acquirer_reference"/>
<field name="acquirer_reference" readonly="1"/>
<field name="create_date"/>
<field name="date_validate"/>
</group>
@@ -258,8 +267,6 @@
<group string="Message">
<field name="state_message" nolabel="1"/>
</group>
<notebook>
</notebook>
</sheet>
</form>
</field>
@@ -27,12 +27,8 @@
<field name="model">payment.transaction</field>
<field name="inherit_id" ref="payment.transaction_form"/>
<field name="arch" type="xml">
<xpath expr='//notebook' position='inside'>
<page string="Paypal TX Details">
<group>
<field name="paypal_txn_type"/>
</group>
</page>
<xpath expr="//field[@name='acquirer_reference']" position="after">
<field name="paypal_txn_type" readonly="1" attrs="{'invisible': [('provider', '!=', 'paypal')]}"/>
</xpath>
</field>
</record>
@@ -24,11 +24,11 @@
<field name="model">payment.acquirer</field>
<field name="inherit_id" ref="payment.acquirer_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@class='oe_button_box']/*[1]" position="before">
<button name="toggle_website_published" position="replace">
<button class="oe_stat_button" name="website_publish_button" type="object" icon="fa-globe">
<field name="website_published" widget="website_button"/>
</button>
</xpath>
</button>
</field>
</record>
+1 -1
View File
@@ -1041,7 +1041,7 @@ Weight: 31 grams</field>
<field name="sale_order_id" ref="website_sale_order_13"/>
<field name="reference" ref="website_sale_order_13"/>
<field name="type">form</field>
<field name="state">authorized</field>
<field name="state">pending</field>
<field name="amount">1799.0</field>
<field name="currency_id" ref="base.USD"/>
<field name="partner_id" ref="base.res_partner_3"/>
+2 -2
View File
@@ -1472,7 +1472,7 @@
<div class="container oe_website_sale">
<div class="row">
<div class="col-md-9">
<h1 class="mb32">Order <em t-field="order.name" /> Confirmed</h1>
<h1 class="mb32">Order <em t-field="order.name" /> <t t-if="order.state == 'sale'">Confirmed</t></h1>
<div class="thanks_msg">
<h2>Thank you for your order.
<a class="btn btn-primary pull-right hidden-xs" href="/shop/print" target="_blank"><i class="fa fa-print"></i> Print</a>
@@ -1512,7 +1512,7 @@
<td class='td-qty'>
<div id="quote_qty">
<span t-field="line.product_uom_qty"/>
<span class='hidden-xs' t-field="line.product_uom"/>
<span class='hidden-xs' t-field="line.product_uom" groups="product.group_uom"/>
</div>
</td>
<td class='td-price'>