[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:
@@ -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)
|
||||
|
||||
@@ -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':
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user