[FIX] sale, purchase: fix invoicing interaction with “Invoicing Switch Threshold”

Steps to reproduce:
- Create a sale order with a product that's invoiced on delivered
  quantities.
- Set delivered quantity (partial delivery) and create an invoice based
  on the delivered quantity. Set the  "Invoice Date" to sometime in the
  past.
- Go to the settings and set  "Invoicing Switch Threshold" to any date
  in the future (so that the invoice you created has a date BEFORE the
  new threshold)
- The invoice will get the label "invoicing app legacy".
- Go back to the sales order and change the delivered quantity.
You should see that the invoiced quantity is automatically set to 0.
A similar behavior can be observed with purchase orders.

Why this is happening:
When a new “Invoicing Switch Threshold”  is set, all posted invoices
before the threshold are marked as `canceled`. In v15, changing the
delivered quantities  triggers the invoiced quantities to be
recalculated as well. However, computing invoiced quantities doesn't
take into account  invoices that are marked as `canceled`. This mean
that the newly computed invoiced quantities won't include invoices
posted before threshold.

opw-2896797

closes odoo/odoo#98909

X-original-commit: cc979734bd7ef3f2a94b411cb7b4f3e782b7ddab
Signed-off-by: William André (wan) <wan@odoo.com>
Signed-off-by: Nshimiyimana Serge Séna (sesn) <sesn@odoo.com>
This commit is contained in:
Nshimiyimana Séna
2022-08-30 03:45:05 +02:00
parent e50bee88c4
commit 727fd4f208
4 changed files with 85 additions and 2 deletions
+1 -1
View File
@@ -1018,7 +1018,7 @@ class PurchaseOrderLine(models.Model):
# compute qty_invoiced
qty = 0.0
for inv_line in line._get_invoice_lines():
if inv_line.move_id.state not in ['cancel']:
if inv_line.move_id.state not in ['cancel'] or inv_line.move_id.payment_state == 'invoicing_legacy':
if inv_line.move_id.move_type == 'in_invoice':
qty += inv_line.product_uom_id._compute_quantity(inv_line.quantity, line.product_uom)
elif inv_line.move_id.move_type == 'in_refund':
@@ -3,6 +3,7 @@
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
from odoo.tests import tagged
from odoo.tests.common import Form
from odoo import Command, fields
@tagged('post_install', '-at_install')
@@ -413,3 +414,46 @@ class TestPurchaseToInvoice(AccountTestInvoicingCommon):
]
for line in invoice.invoice_line_ids.sorted('sequence'):
self.assertEqual(line.purchase_order_id, expected_purchase.pop(0))
def test_partial_billing_interaction_with_invoicing_switch_threshold(self):
""" Let's say you create a partial bill 'B' for a given PO. Now if you change the
'Invoicing Switch Threshold' such that the bill date of 'B' is before the new threshold,
the PO should still take bill 'B' into account.
"""
if not self.env['ir.module.module'].search([('name', '=', 'account_accountant'), ('state', '=', 'installed')]):
self.skipTest("This test requires the installation of the account_account module")
purchase_order = self.env['purchase.order'].with_context(tracking_disable=True).create({
'partner_id': self.partner_a.id,
'order_line': [
Command.create({
'name': self.product_deliver.name,
'product_id': self.product_deliver.id,
'product_qty': 20.0,
'product_uom': self.product_deliver.uom_id.id,
'price_unit': self.product_deliver.list_price,
'taxes_id': False,
}),
],
})
line = purchase_order.order_line[0]
purchase_order.button_confirm()
line.qty_received = 10
purchase_order.action_create_invoice()
invoice = purchase_order.invoice_ids
invoice.invoice_date = invoice.date
invoice.action_post()
self.assertEqual(line.qty_invoiced, 10)
self.env['res.config.settings'].create({
'invoicing_switch_threshold': fields.Date.add(invoice.invoice_date, days=30),
}).execute()
invoice.invalidate_model(fnames=['payment_state'])
self.assertEqual(line.qty_invoiced, 10)
line.qty_received = 15
self.assertEqual(line.qty_invoiced, 10)
+1 -1
View File
@@ -704,7 +704,7 @@ class SaleOrderLine(models.Model):
for line in self:
qty_invoiced = 0.0
for invoice_line in line._get_invoice_lines():
if invoice_line.move_id.state != 'cancel':
if invoice_line.move_id.state != 'cancel' or invoice_line.move_id.payment_state == 'invoicing_legacy':
if invoice_line.move_id.move_type == 'out_invoice':
qty_invoiced += invoice_line.product_uom_id._compute_quantity(invoice_line.quantity, line.product_uom)
elif invoice_line.move_id.move_type == 'out_refund':
+39
View File
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import fields
from odoo.fields import Command
from odoo.tests import Form, tagged
from odoo.tools import float_is_zero
@@ -706,3 +707,41 @@ class TestSaleToInvoice(TestSaleCommon):
inv.company_id,
self.company_data['company'],
'invoices should be created in the company of the SO, not the main company of the context')
def test_partial_invoicing_interaction_with_invoicing_switch_threshold(self):
""" Let's say you partially invoice a SO, let's call the resuling invoice 'A'. Now if you change the
'Invoicing Switch Threshold' such that the invoice date of 'A' is before the new threshold,
the SO should still take invoice 'A' into account.
"""
if not self.env['ir.module.module'].search([('name', '=', 'account_accountant'), ('state', '=', 'installed')]):
self.skipTest("This test requires the installation of the account_account module")
sale_order = self.env['sale.order'].create({
'partner_id': self.partner_a.id,
'order_line': [
Command.create({
'product_id': self.company_data['product_delivery_no'].id,
'product_uom_qty': 20,
}),
],
})
line = sale_order.order_line[0]
sale_order.action_confirm()
line.qty_delivered = 10
invoice = sale_order._create_invoices()
invoice.action_post()
self.assertEqual(line.qty_invoiced, 10)
self.env['res.config.settings'].create({
'invoicing_switch_threshold': fields.Date.add(invoice.invoice_date, days=30),
}).execute()
invoice.invalidate_model(fnames=['payment_state'])
self.assertEqual(line.qty_invoiced, 10)
line.qty_delivered = 15
self.assertEqual(line.qty_invoiced, 10)