[IMP] payment: Remove auto_confirm field and simplify views.

PURPOSE
=======

The field auto_confirm is complicated to understand for common users. Furthermore, on of its options is only useful for authorize module.

SPECIFICATION
=============

Remove the auto_confirm field. The destinies of its options are the following:
- none: Simply disappear.
- authorize: Become capture_manually. It has nothing to do with the auto_confirm field has it's related to the autorize module (And could be extended to other payment acquirers too).
- confirm_so: Remove it. Will be automatic, and we will always validate the sales order and generate the accounting entries on acquirer validation.
- generate_and_pay_invoice: Is linked to the journal_id. The field journal_id is always set and we will use it to validate the sales order and generate the accounting entries on acquirer validation.

Bonus: website_sale: Allow to create/validate invoice automatically on `Mark as Paid`
This commit is contained in:
Yannick Tivisse
2017-06-02 15:31:47 +02:00
parent 4fe4c1e851
commit 4aa2fad313
18 changed files with 174 additions and 78 deletions
@@ -155,7 +155,6 @@
<record id="payment_acquirer_custom" model="payment.acquirer">
<field name="name">Custom</field>
<field name="auto_confirm">none</field>
<field name="company_id" ref="base.main_company"/>
<field name="view_template_id" ref="default_acquirer_button"/>
<field name="module_id" ref="base.module_payment_transfer"/>
+4 -4
View File
@@ -10,7 +10,7 @@ class AccountPayment(models.Model):
_inherit = 'account.payment'
payment_transaction_id = fields.Many2one('payment.transaction', string="Payment Transaction")
payment_token_id = fields.Many2one('payment.token', string="Saved payment token", domain=[('acquirer_id.auto_confirm', '!=', 'authorize')],
payment_token_id = fields.Many2one('payment.token', string="Saved payment token", domain=[('acquirer_id.capture_manually', '=', False)],
help="Note that tokens from acquirers set to only authorize transactions (instead of capturing the amount) are not available.")
@api.onchange('partner_id')
@@ -18,14 +18,14 @@ class AccountPayment(models.Model):
res = {}
if self.partner_id:
partners = self.partner_id | self.partner_id.commercial_partner_id | self.partner_id.commercial_partner_id.child_ids
res['domain'] = {'payment_token_id': [('partner_id', 'in', partners.ids), ('acquirer_id.auto_confirm', '!=', 'authorize')]}
res['domain'] = {'payment_token_id': [('partner_id', 'in', partners.ids), ('acquirer_id.capture_manually', '=', False)]}
return res
@api.onchange('payment_method_id', 'journal_id')
def _onchange_payment_method(self):
if self.payment_method_code == 'electronic':
self.payment_token_id = self.env['payment.token'].search([('partner_id', '=', self.partner_id.id), ('acquirer_id.auto_confirm', '!=', 'authorize')], limit=1)
self.payment_token_id = self.env['payment.token'].search([('partner_id', '=', self.partner_id.id), ('acquirer_id.capture_manually', '=', False)], limit=1)
else:
self.payment_token_id = False
@@ -38,7 +38,7 @@ class AccountPayment(models.Model):
return account_payment
def _do_payment(self):
if self.payment_token_id.acquirer_id.auto_confirm == 'authorize':
if self.payment_token_id.acquirer_id.capture_manually:
raise ValidationError(_('This feature is not available for payment acquirers set to the "Authorize" mode.\n'
'Please use a token from another provider than %s.') % self.payment_token_id.acquirer_id.name)
reference = "P-%s-%s" % (self.id, datetime.datetime.now().strftime('%y%m%d_%H%M%S'))
+17 -17
View File
@@ -71,15 +71,22 @@ class PaymentAcquirer(models.Model):
website_published = fields.Boolean(
'Visible in Portal / Website', copy=False,
help="Make this payment acquirer available (Customer invoices, etc.)")
auto_confirm = fields.Selection([
('none', 'No automatic 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)
# Formerly associated to `authorize` option from auto_confirm
capture_manually = fields.Boolean(string="Capture Amount Manually",
help="Capture the amount from Odoo, when the delivery is completed.")
# Formerly associated to `generate_and_pay_invoice` option from auto_confirm
journal_id = fields.Many2one(
'account.journal', 'Payment Journal',
help="Account journal used for automatic payment reconciliation.")
'account.journal', 'Payment Journal', domain=[('type', '=', 'bank')],
default=lambda self: self.env['account.journal'].search([('type', '=', 'bank')], limit=1),
help="""Payments will be registered into this journal. If you get paid straight on your bank account,
select your bank account. If you get paid in batch for several transactions, create a specific
payment journal for this payment acquirer to easily manage the bank reconciliation. You hold
the amount in a temporary transfer account of your books (created automatically when you create
the payment journal). Then when you get paid on your bank account by the payment acquirer, you
reconcile the bank statement line with this temporary transfer account. Use reconciliation
templates to do it in one-click.""")
specific_countries = fields.Boolean(string="Specific Countries",
help="If you leave it empty, the payment acquirer will be available for all the countries.")
country_ids = fields.Many2many(
'res.country', 'payment_country_rel',
'payment_id', 'country_id', 'Countries',
@@ -116,7 +123,7 @@ class PaymentAcquirer(models.Model):
"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')
authorize_implemented = fields.Boolean('Authorize Mechanism Supported', compute='_compute_feature_support')
fees_implemented = fields.Boolean('Fees Computation Supported', compute='_compute_feature_support')
fees_active = fields.Boolean('Add Extra Fees')
fees_dom_fixed = fields.Float('Fixed domestic fees')
@@ -142,11 +149,11 @@ class PaymentAcquirer(models.Model):
"resized as a 64x64px image, with aspect ratio preserved. "
"Use this field anywhere a small image is required.")
@api.multi
def _compute_feature_support(self):
feature_support = self._get_feature_support()
for acquirer in self:
acquirer.fees_implemented = acquirer.provider in feature_support['fees']
acquirer.authorize_implemented = acquirer.provider in feature_support['authorize']
acquirer.token_implemented = acquirer.provider in feature_support['tokenize']
@api.multi
@@ -158,13 +165,6 @@ class PaymentAcquirer(models.Model):
return False
return True
@api.constrains('auto_confirm')
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(_('You cannot capture payments manually with this payment method. Please choose another Order Confirmation mode (in Configuration tab).'))
return True
_constraints = [
(_check_required_if_provider, 'Required fields not filled', []),
]
+16 -16
View File
@@ -16,16 +16,11 @@
<field name="environment" invisible='1'/>
<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"/>
<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')]}"
@@ -46,6 +41,12 @@
<span class="o_stat_text">Environment</span>
</div>
</button>
<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>
</div>
<field name="image" widget='image' class="oe_avatar" options='{"preview_image": "image_medium"}'/>
<div class="oe_title">
@@ -80,10 +81,16 @@
</page>
<page string="Configuration">
<group name="acquirer_config">
<field name="auto_confirm" widget="radio"/>
<field name="capture_manually" attrs="{'invisible': [('authorize_implemented', '=', False)]}"/>
<field name="save_token" widget="radio" attrs="{'invisible': [('token_implemented', '=', False)]}"/>
<field name="journal_id" attrs="{'required': [('auto_confirm', '=', 'generate_and_pay_invoice')], 'invisible': [('auto_confirm', '!=', 'generate_and_pay_invoice')]}"/>
<field name="country_ids" widget="many2many_tags"/>
<field name="fees_active" attrs="{'invisible': [('fees_implemented', '=', False)]}"/>
<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)]}"/>
<field name="journal_id" context="{'default_type': 'bank'}" required="1"/>
<field name="specific_countries"/>
<field name="country_ids" widget="many2many_tags" attrs="{'invisible': [('specific_countries', '=', False)]}"/>
<label for="view_template_id" groups="base.group_no_one"/>
<div groups="base.group_no_one">
<field name="view_template_id" nolabel="1"/>
@@ -106,13 +113,6 @@
</div>
<field name="registration_view_template_id" groups="base.group_no_one"/>
</group>
<group name="fees_config" attrs="{'invisible': [('fees_implemented', '=', False)]}">
<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>
</notebook>
</sheet>
+2 -2
View File
@@ -66,7 +66,7 @@ class PaymentAcquirerAuthorize(models.Model):
'x_trans_key': self.authorize_transaction_key,
'x_amount': str(values['amount']),
'x_show_form': 'PAYMENT_FORM',
'x_type': 'AUTH_CAPTURE' if self.auto_confirm != 'authorize' else 'AUTH_ONLY',
'x_type': 'AUTH_CAPTURE' if not self.capture_manually else 'AUTH_ONLY',
'x_method': 'CC',
'x_fp_sequence': '%s%s' % (self.id, int(time.time())),
'x_version': '3.1',
@@ -246,7 +246,7 @@ class TxAuthorize(models.Model):
def authorize_s2s_do_transaction(self, **data):
self.ensure_one()
transaction = AuthorizeAPI(self.acquirer_id)
if self.acquirer_id.auto_confirm != "authorize":
if not self.acquirer_id.capture_manually:
res = transaction.auth_and_capture(self.payment_token_id, self.amount, self.reference)
else:
res = transaction.authorize(self.payment_token_id, self.amount, self.reference)
@@ -25,7 +25,7 @@ class AuthorizeCommon(PaymentAcquirerCommon):
# get the authorize account
self.authorize = self.env.ref('payment.payment_acquirer_authorize')
# Be sure to be in 'capture' mode
self.authorize.auto_confirm = 'confirm_so'
# self.authorize.auto_confirm = 'confirm_so'
@odoo.tests.common.at_install(True)
@@ -219,7 +219,7 @@ class AuthorizeForm(AuthorizeCommon):
# switch to 'authorize only'
# create authorize only s2s transaction & capture it
self.authorize.auto_confirm = 'authorize'
self.authorize.capture_manually = True
transaction = self.env['payment.transaction'].create({
'amount': 500,
'acquirer_id': authorize.id,
@@ -236,7 +236,7 @@ class AuthorizeForm(AuthorizeCommon):
self.assertEqual(transaction.state, 'done')
# create authorize only s2s transaction & void it
self.authorize.auto_confirm = 'authorize'
self.authorize.capture_manually = True
transaction = self.env['payment.transaction'].create({
'amount': 500,
'acquirer_id': authorize.id,
@@ -8,7 +8,6 @@
<field name="provider">transfer</field>
<field name="company_id" ref="base.main_company"/>
<field name="view_template_id" ref="transfer_acquirer_button"/>
<field name="auto_confirm">none</field>
<field name="environment">test</field>
<field name="website_published" eval="True"/>
<field name="pre_msg"><![CDATA[
@@ -17,9 +17,6 @@
<field name="error_msg" position="attributes">
<attribute name="attrs">{'invisible': [('provider', '=', 'transfer')]}</attribute>
</field>
<field name="auto_confirm" position="attributes">
<attribute name="attrs">{'invisible': [('provider', '=', 'transfer')]}</attribute>
</field>
</field>
</record>
</odoo>
+1 -1
View File
@@ -157,7 +157,7 @@
<button name="action_quotation_send" string="Send by Email" type="object" states="draft" class="btn-primary"/>
<button name="action_quotation_send" type="object" string="Send PRO-FORMA" groups="sale.group_proforma_sales" class="btn-primary" attrs="{'invisible': ['|', ('state', 'in', ['sent', 'sale']), ('invoice_count','&gt;=',1)]}" context="{'proforma': True}"/>
<button name="print_quotation" string="Print" type="object" states="draft" class="btn-primary o_sale_print"/>
<button name="action_confirm" states="sent" string="Confirm Sale" class="btn-primary" type="object" />
<button name="action_confirm" id="action_confirm" states="sent" string="Confirm Sale" class="btn-primary" type="object" />
<button name="action_confirm" states="draft" string="Confirm Sale" type="object" />
<button name="action_quotation_send" type="object" string="Send PRO-FORMA" groups="sale.group_proforma_sales" attrs="{'invisible': ['|', ('state', '=', 'draft'), ('invoice_count','&gt;=',1)]}" context="{'proforma': True}"/>
<button name="print_quotation" string="Print" type="object" states="sent,sale" class="o_sale_print"/>
+10 -9
View File
@@ -11,6 +11,7 @@ class PaymentTransaction(models.Model):
_inherit = 'payment.transaction'
# link with the sales order
# YTI FIXME: The auto_join seems useless
sale_order_id = fields.Many2one('sale.order', string='Sales Order', auto_join=True)
def _generate_and_pay_invoice(self, tx, acquirer_name):
@@ -29,13 +30,15 @@ class PaymentTransaction(models.Model):
acquirer_name, created_invoice.name, created_invoice.id, tx.sale_order_id.name, tx.sale_order_id.id)
created_invoice.action_invoice_open()
if tx.acquirer_id.journal_id:
if not tx.acquirer_id.journal_id:
default_journal = self.env['account.journal'].search([('type', '=', 'bank')], limit=1)
if not default_journal:
_logger.warning('<%s> transaction completed, could not auto-generate payment for %s (ID %s) (no journal set on acquirer)',
acquirer_name, tx.sale_order_id.name, tx.sale_order_id.id)
tx.acquirer_id.journal_id = default_journal
created_invoice.pay_and_reconcile(tx.acquirer_id.journal_id, pay_amount=created_invoice.amount_total)
if created_invoice.payment_ids:
created_invoice.payment_ids[0].payment_transaction_id = tx
else:
_logger.warning('<%s> transaction completed, could not auto-generate payment for %s (ID %s) (no journal set on acquirer)',
acquirer_name, tx.sale_order_id.name, tx.sale_order_id.id)
else:
_logger.warning('<%s> transaction completed, could not auto-generate invoice for %s (ID %s)',
acquirer_name, tx.sale_order_id.name, tx.sale_order_id.id)
@@ -69,15 +72,13 @@ class PaymentTransaction(models.Model):
if amount_matches:
if not acquirer_name:
acquirer_name = tx.sale_order_id.payment_acquirer_id.provider or 'unknown'
if tx.state == 'authorized' and tx.acquirer_id.auto_confirm == 'authorize':
if tx.state == 'authorized' and tx.acquirer_id.capture_manually:
_logger.info('<%s> transaction authorized, auto-confirming order %s (ID %s)', acquirer_name, tx.sale_order_id.name, tx.sale_order_id.id)
tx.sale_order_id.with_context(send_email=True).action_confirm()
if tx.state == 'done' and tx.acquirer_id.auto_confirm in ['confirm_so', 'generate_and_pay_invoice']:
if tx.state == 'done':
_logger.info('<%s> transaction completed, auto-confirming order %s (ID %s)', acquirer_name, tx.sale_order_id.name, tx.sale_order_id.id)
tx.sale_order_id.with_context(send_email=True).action_confirm()
if tx.acquirer_id.auto_confirm == 'generate_and_pay_invoice':
self._generate_and_pay_invoice(tx, acquirer_name)
self._generate_and_pay_invoice(tx, acquirer_name)
elif tx.state not in ['cancel', 'error'] and tx.sale_order_id.state == 'draft':
_logger.info('<%s> transaction pending/to confirm manually, sending quote email for order %s (ID %s)', acquirer_name, tx.sale_order_id.name, tx.sale_order_id.id)
tx.sale_order_id.force_quotation_send()
@@ -1,7 +1,9 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, exceptions, fields, models
from odoo import api, exceptions, fields, models, _
from odoo.exceptions import ValidationError
class SaleOrder(models.Model):
@@ -9,11 +11,18 @@ class SaleOrder(models.Model):
_inherit = 'sale.order'
website_url = fields.Char('Website URL', compute='_website_url', help='The full URL to access the document through the website.')
payment_transaction_count = fields.Integer(compute='_compute_payment_transaction_count', string="Number of payment transactions")
def _website_url(self):
for so in self:
so.website_url = '/my/orders/%s' % (so.id)
def _compute_payment_transaction_count(self):
transaction_data = self.env['payment.transaction'].read_group([('sale_order_id', 'in', self.ids)], ['sale_order_id'], ['sale_order_id'])
mapped_data = dict([(m['sale_order_id'][0], m['sale_order_id_count']) for m in transaction_data])
for order in self:
order.payment_transaction_count = mapped_data.get(order.id, 0)
@api.multi
def get_access_action(self):
""" Instead of the classic form view, redirect to the online quote for
@@ -62,6 +71,24 @@ class SaleOrder(models.Model):
model=self._name,
res_id=self.id)[self.partner_id.id]
def action_view_transaction(self):
action = {
'type': 'ir.actions.act_window',
'name': 'Payment Transactions',
'res_model': 'payment.transaction',
}
if self.payment_transaction_count == 1:
action.update({
'res_id': self.env['payment.transaction'].search([('sale_order_id', '=', self.id)]).id,
'view_mode': 'form',
})
else:
action.update({
'view_mode': 'tree,form',
'domain': [('sale_order_id', '=', self.id)],
})
return action
class SaleOrderLine(models.Model):
@@ -1,15 +1,26 @@
<?xml version="1.0"?>
<odoo>
<record id="view_account_invoice_filter_share" model="ir.ui.view">
<field name="name">account.invoice.select.share</field>
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.view_account_invoice_filter"/>
<field name="arch" type="xml">
<xpath expr='//field[@name="user_id"]' position="attributes">
<attribute name="domain">[('share','=', False)]</attribute>
</xpath>
</field>
</record>
<record id="view_account_invoice_filter_share" model="ir.ui.view">
<field name="name">account.invoice.select.share</field>
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.view_account_invoice_filter"/>
<field name="arch" type="xml">
<xpath expr='//field[@name="user_id"]' position="attributes">
<attribute name="domain">[('share','=', False)]</attribute>
</xpath>
</field>
</record>
<record id="sale_order_view_form" model="ir.ui.view">
<field name="name">sale.order.form</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@name='button_box']" position="inside">
<button name="action_view_transaction" type="object" class="oe_stat_button" icon="fa-money" attrs="{'invisible': [('payment_transaction_count', '=', 0)]}">
<field name="payment_transaction_count" widget="statinfo" string="Transactions"/>
</button>
</xpath>
</field>
</record>
</odoo>
+1 -1
View File
@@ -768,7 +768,7 @@ class WebsiteSale(http.Controller):
tx.partner_id == tx.sale_order_id.partner_id):
try:
s2s_result = tx.s2s_do_transaction()
valid_state = 'authorized' if tx.acquirer_id.auto_confirm == 'authorize' else 'done'
valid_state = 'authorized' if tx.acquirer_id.capture_manually else 'done'
if not s2s_result or tx.state != valid_state:
return dict(success=False, error=_("Payment transaction failed (%s)") % tx.state_message)
else:
+13 -2
View File
@@ -70,9 +70,10 @@ class WebsiteConfigSettings(models.TransientModel):
group='base.group_portal,base.group_user,base.group_public')
default_invoice_policy = fields.Selection([
('order', 'Invoice what is ordered (automatic)'),
('delivery', 'Invoice what is delivered (manual)')
('order', 'Invoice what is ordered'),
('delivery', 'Invoice what is delivered')
], 'Invoicing Policy', default='order')
automatic_invoice = fields.Boolean("Automatic Invoice")
group_multi_currency = fields.Boolean(string='Multi-Currencies', implied_group='base.group_multi_currency')
@@ -81,6 +82,16 @@ class WebsiteConfigSettings(models.TransientModel):
('subtotal', 'Tax-Excluded Prices')],
"Product Prices", default='total')
@api.multi
def set_automatic_invoice(self):
value = self.module_account_invoicing and self.default_invoice_policy == 'order' and self.automatic_invoice
self.env['ir.config_parameter'].sudo().set_param('website_sale.automatic_invoice', value)
@api.model
def get_default_automatic_invoice(self, fields):
value = self.env['ir.config_parameter'].sudo().get_param('website_sale.automatic_invoice', default=False)
return {'automatic_invoice': value}
@api.model
def get_default_sale_delivery_settings(self, fields):
sale_delivery_settings = 'none'
+26
View File
@@ -23,6 +23,16 @@ class SaleOrder(models.Model):
payment_acquirer_id = fields.Many2one('payment.acquirer', string='Payment Acquirer', copy=False)
payment_tx_id = fields.Many2one('payment.transaction', string='Last Transaction', copy=False)
only_services = fields.Boolean(compute='_compute_cart_info', string='Only Services')
can_directly_mark_as_paid = fields.Boolean(compute='_compute_can_directly_mark_as_paid',
string="Can be directly marked as paid", store=True,
help="""Checked if the sales order can directly be marked as paid, i.e. if the quotation
is sent or confirmed and if the payment acquire is of the type transfer or manual""")
@api.depends('state', 'payment_tx_id', 'payment_tx_id.state',
'payment_acquirer_id', 'payment_acquirer_id.provider')
def _compute_can_directly_mark_as_paid(self):
for order in self:
order.can_directly_mark_as_paid = order.state in ['sent', 'sale'] and order.payment_tx_id.state != 'done' and order.payment_acquirer_id.provider in ['transfer', 'manual']
@api.multi
@api.depends('website_order_line.product_uom_qty', 'website_order_line.product_id')
@@ -166,6 +176,22 @@ class SaleOrder(models.Model):
accessory_products -= order.website_order_line.mapped('product_id')
return random.sample(accessory_products, len(accessory_products))
def action_mark_as_paid(self):
""" Mark directly a sales order as paid if:
- State: Quotation Sent, or sales order
- Provider: wire transfer or manual config
The transaction is marked as done
The invoice may be generated and marked as paid if configured in the website settings
"""
self.ensure_one()
if self.can_directly_mark_as_paid:
self.action_confirm()
if self.env['ir.config_parameter'].sudo().get_param('website_sale.automatic_invoice', default=False):
self.payment_tx_id._generate_and_pay_invoice(self.payment_tx_id, self.payment_acquirer_id.provider)
self.payment_tx_id.state = 'done'
else:
raise ValidationError(_("The quote should be sent and the payment acquirer type should be manual or wire transfer"))
class ResCountry(models.Model):
_inherit = 'res.country'
@@ -15,10 +15,7 @@
<td>
<strong>Payment Method:</strong> <t t-esc="doc.payment_acquirer_id.name"/><br />
<strong>Payment Status:</strong>
<t t-if="doc.payment_acquirer_id.auto_confirm == 'none'">
<t t-raw="doc.payment_acquirer_id.pending_msg"/>
</t>
<t t-if="doc.payment_acquirer_id.auto_confirm in ['confirm_so', 'generate_and_pay_invoice']">
<t t-if="doc.payment_acquirer_id.journal_id">
<t t-if="doc.payment_tx_id.state == 'pending'">
<t t-raw="doc.payment_acquirer_id.pending_msg"/>
</t>
+13 -2
View File
@@ -227,15 +227,26 @@
<div class="o_setting_right_pane">
<label for="module_account_invoicing"/>
<div class="text-muted">
Send invoices to customers
Issue invoices to customers
</div>
<div class="content-group">
<div class="content-group" attrs="{'invisible': [('module_account_invoicing', '=', False)]}">
<div class="mt16">
<field name="default_invoice_policy" class="o_light_label" widget="radio"/>
</div>
</div>
</div>
</div>
<div class="col-xs-12 col-md-6 o_setting_box" attrs="{'invisible': ['|', ('default_invoice_policy', '=', 'delivery'), ('module_account_invoicing', '=', False)]}">
<div class="o_setting_left_pane">
<field name="automatic_invoice" nolabel="1"/>
</div>
<div class="o_setting_right_pane">
<label for="automatic_invoice"/>
<div class="text-muted">
Issue the invoice automatically at the order confirmation
</div>
</div>
</div>
</div>
<h2>Shipping</h2>
<div class="row mt16 o_settings_container" id="sale_shipping_settings">
@@ -133,4 +133,21 @@
action="product.variants_action"
parent="menu_product_settings" groups="product.group_product_variant" sequence="2"/>
<record id="sale_order_view_form" model="ir.ui.view">
<field name="name">sale.order.form</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<xpath expr="//button[@name='action_quotation_send']" position="after">
<button name="action_mark_as_paid" type="object" string="Mark as Paid" states="sent,sale" class="btn-primary" attrs="{'invisible': [('can_directly_mark_as_paid', '=', False)]}"/>
</xpath>
<field name="partner_id" position="after">
<field name="can_directly_mark_as_paid" invisible="1"/>
</field>
<xpath expr="//button[@id='action_confirm']" position="attributes">
<attribute name="attrs">{'invisible': [('can_directly_mark_as_paid', '=', True)]}</attribute>
</xpath>
</field>
</record>
</odoo>