[FIX] sale: avoid re-invoicing invoiced SO lines

- Create a product:
  * Invoicing Policy: Delivered quantities
  * Re-invoice Expenses: At cost
- Create a SO with the created product in Order Lines
- Make sure the subtotal of the SO line is equal to 0, by setting an Unit Price to 0
  or by applying a 100% discount
- Confirm SO and create an invoice (Regular invoice)
- Post the invoice
A new line with the same product and the same delivered quantity is added to the SO.

It is not possible to invoice a SO line with a product having an expense policy and
a subtotal equal to 0, without having it reinvoiced to the SO.

This fix will prevent account move lines linked to a SO line from being reinvoiced.

opw-2479560

closes odoo/odoo#69623

X-original-commit: b41cf0077c9a6d1d74cc0c7987c0edcc58e368d1
Signed-off-by: Anh Thao PHAM <kitan191@users.noreply.github.com>
Signed-off-by: Victor Feyens (vfe) <vfe@odoo.com>
This commit is contained in:
Anh Thao Pham (pta)
2021-04-21 15:11:17 +00:00
parent f8ca384ba7
commit fbc32db828
2 changed files with 43 additions and 0 deletions
+2
View File
@@ -72,6 +72,8 @@ class AccountMoveLine(models.Model):
For Vendor Bill flow, if the product has a 'erinvoice policy' and is a cost, then we will find the SO on which reinvoice the AAL
"""
self.ensure_one()
if self.sale_line_ids:
return False
uom_precision_digits = self.env['decimal.precision'].precision_get('Product Unit of Measure')
return float_compare(self.credit or 0.0, self.debit or 0.0, precision_digits=uom_precision_digits) != 1 and self.product_id.expense_policy not in [False, 'no']
+41
View File
@@ -218,3 +218,44 @@ class TestReInvoice(TestSaleCommon):
self.assertEqual(len(self.sale_order.order_line), 1, "No SO line should have been created (or removed) when validating vendor bill")
self.assertTrue(invoice_a.mapped('line_ids.analytic_line_ids'), "Analytic lines should be generated")
def test_not_reinvoicing_invoiced_so_lines(self):
""" Test that invoiced SO lines are not re-invoiced. """
so_line1 = self.env['sale.order.line'].create({
'name': self.company_data['product_delivery_cost'].name,
'product_id': self.company_data['product_delivery_cost'].id,
'product_uom_qty': 1,
'product_uom': self.company_data['product_delivery_cost'].uom_id.id,
'price_unit': self.company_data['product_delivery_cost'].list_price,
'discount': 100.00,
'order_id': self.sale_order.id,
})
so_line1.product_id_change()
so_line2 = self.env['sale.order.line'].create({
'name': self.company_data['product_delivery_sales_price'].name,
'product_id': self.company_data['product_delivery_sales_price'].id,
'product_uom_qty': 1,
'product_uom': self.company_data['product_delivery_sales_price'].uom_id.id,
'price_unit': self.company_data['product_delivery_sales_price'].list_price,
'discount': 100.00,
'order_id': self.sale_order.id,
})
so_line2.product_id_change()
self.sale_order.onchange_partner_id()
self.sale_order._compute_tax_id()
self.sale_order.action_confirm()
for line in self.sale_order.order_line:
line.qty_delivered = 1
# create invoice and validate it
invoice = self.sale_order._create_invoices()
invoice.action_post()
so_line3 = self.sale_order.order_line.filtered(lambda sol: sol != so_line1 and sol.product_id == self.company_data['product_delivery_cost'])
so_line4 = self.sale_order.order_line.filtered(lambda sol: sol != so_line2 and sol.product_id == self.company_data['product_delivery_sales_price'])
self.assertFalse(so_line3, "No re-invoicing should have created a new sale line with product #1")
self.assertFalse(so_line4, "No re-invoicing should have created a new sale line with product #2")
self.assertEqual(so_line1.qty_delivered, 1, "No re-invoicing should have impacted exising SO line 1")
self.assertEqual(so_line2.qty_delivered, 1, "No re-invoicing should have impacted exising SO line 2")