Skip to content
Snippets Groups Projects
Commit 9e17d081 authored by Damien Bouvy's avatar Damien Bouvy
Browse files

[FIX] sale: do not validate quotes on tx amount mismatch


The title says it all -_-

closes odoo/odoo#39699

Signed-off-by: default avatarDamien Bouvy (dbo) <dbo@odoo.com>
parent d22866f8
No related branches found
No related tags found
No related merge requests found
......@@ -3427,6 +3427,12 @@ msgstr ""
msgid "The margin is computed as the sum of product sales prices minus the cost set in their detail form."
msgstr ""
#. module: sale
#: code:addons/sale/models/payment.py:97
#, python-format
msgid "The order was not confirmed despite response from the acquirer (%s): order total is %r but acquirer replied with %r."
msgstr ""
#. module: sale
#: model:ir.model.fields,help:sale.field_sale_order__reference
msgid "The payment communication of this sale order."
......
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import logging
import re
from odoo import api, fields, models, _
from odoo.tools import float_compare
_logger = logging.getLogger(__name__)
class PaymentAcquirer(models.Model):
......@@ -70,6 +75,26 @@ class PaymentTransaction(models.Model):
for so in record.sale_order_ids:
so.reference = record._compute_sale_order_reference(so)
def _check_amount_and_confirm_order(self):
self.ensure_one()
for order in self.sale_order_ids.filtered(lambda so: so.state in ('draft', 'sent')):
if float_compare(self.amount, order.amount_total, 2) == 0:
order.with_context(send_email=True).action_confirm()
else:
_logger.warning(
'<%s> transaction AMOUNT MISMATCH for order %s (ID %s): expected %r, got %r',
self.acquirer_id.provider,order.name, order.id,
order.amount_total, self.amount,
)
order.message_post(
subject=_("Amount Mismatch (%s)") % self.acquirer_id.provider,
body=_("The order was not confirmed despite response from the acquirer (%s): order total is %r but acquirer replied with %r.") % (
self.acquirer_id.provider,
order.amount_total,
self.amount,
)
)
@api.multi
def _set_transaction_authorized(self):
# Override of '_set_transaction_authorized' in the 'payment' module
......@@ -77,19 +102,15 @@ class PaymentTransaction(models.Model):
super(PaymentTransaction, self)._set_transaction_authorized()
sales_orders = self.mapped('sale_order_ids').filtered(lambda so: so.state == 'draft')
sales_orders.force_quotation_send()
sales_orders = self.mapped('sale_order_ids').filtered(lambda so: so.state == 'sent')
for so in sales_orders:
# For loop because some override of action_confirm are ensure_one.
so.action_confirm()
for tx in self:
tx._check_amount_and_confirm_order()
@api.multi
def _reconcile_after_transaction_done(self):
# Override of '_set_transaction_done' in the 'payment' module
# to confirm the quotations automatically and to generate the invoices if needed.
sales_orders = self.mapped('sale_order_ids').filtered(lambda so: so.state in ('draft', 'sent'))
for so in sales_orders:
# For loop because some override of action_confirm are ensure_one.
so.with_context(send_email=True).action_confirm()
for tx in self:
tx._check_amount_and_confirm_order()
# invoice the sale orders if needed
self._invoice_sale_orders()
res = super(PaymentTransaction, self)._reconcile_after_transaction_done()
......
# -*- coding: utf-8 -*-
from odoo import tests
from odoo.addons.account.tests.account_test_classes import AccountingTestCase
from odoo.tools import mute_logger
@tests.tagged('post_install', '-at_install')
class TestSaleTransaction(AccountingTestCase):
def test_sale_invoicing_from_transaction(self):
''' Test the following scenario:
- Create a sale order
- Create a transaction for the sale order.
- Confirm the transaction but no invoice generated automatically.
- Create manually an invoice for this sale order.
=> The invoice must be paid.
'''
product = self.env['product.product'].create({
def setUp(self):
super(TestSaleTransaction, self).setUp()
self.product = self.env['product.product'].create({
'name': 'Product A',
})
order = self.env['sale.order'].create({
self.order = self.env['sale.order'].create({
'partner_id': self.env.ref('base.res_partner_1').id,
'order_line': [
(0, False, {
'product_id': product.id,
'product_id': self.product.id,
'name': '1 Product',
'price_unit': 100.0,
}),
],
})
transaction = order._create_payment_transaction({
self.transaction = self.order._create_payment_transaction({
'acquirer_id': self.env.ref('payment.payment_acquirer_transfer').id,
})
transaction._set_transaction_done()
transaction._post_process_after_done()
def test_sale_invoicing_from_transaction(self):
''' Test the following scenario:
- Create a sale order
- Create a transaction for the sale order.
- Confirm the transaction but no invoice generated automatically.
- Create manually an invoice for this sale order.
=> The invoice must be paid.
'''
self.transaction._set_transaction_done()
self.transaction._post_process_after_done()
# Assert a posted payment has been generated at this point.
self.assertTrue(transaction.payment_id)
self.assertEqual(transaction.payment_id.state, 'posted')
self.assertTrue(self.transaction.payment_id)
self.assertEqual(self.transaction.payment_id.state, 'posted')
invoice_ids = order.action_invoice_create()
invoice_ids = self.order.action_invoice_create()
invoice = self.env['account.invoice'].browse(invoice_ids)
invoice.action_invoice_open()
self.assertEqual(invoice.state, 'paid')
def test_sale_transaction_mismatch(self):
"""Test that a transaction for the incorrect amount does not validate the SO."""
# modify order total
self.order.order_line[0].price_unit = 200.0
self.transaction._set_transaction_done()
with mute_logger('odoo.addons.sale.models.payment'):
self.transaction._post_process_after_done()
self.assertEqual(self.order.state, 'draft', 'a transaction for an incorrect amount should not validate a quote')
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment