summaryrefslogtreecommitdiff
path: root/addons/sale_coupon
diff options
context:
space:
mode:
authorAndrea Grazioso (agr-odoo) <agr@odoo.com>2020-12-22 17:20:09 +0000
committerVictor Feyens <vfe@odoo.com>2021-01-20 15:44:20 +0000
commit6532c6ba7acb2de53fc839d5a7c5d8b200716565 (patch)
tree79a33fcbb4e091f42edfd57a21a1eaf1fa5241ad /addons/sale_coupon
parent604c07edcd4da8cf2a663d06ba91f137eb74691b (diff)
[FIX] sale,sale_coupon: do not invoice only promotion lines
Create a promotion auto applied with 0 minimum amount on any product in catalog. Have a DEMO product invoiced on delivery Create a sale order with DEMO, apply the promotion. Confirm. Click on 'Create Invoice'. The invoice will only contain the promotion because the line for DEMO is to be invoiced only after delivery, while by default the promotion product has the invoice policy 'on order' This commit will: * avoid highlight the button 'create invoice' if the only invoiceable lines are promotion lines as well as raising an error if the invoice is created in the same scenario * refuse to invoice only promotion lines from a SO. * adds a test to cover the case opw-2414630 closes odoo/odoo#64721 X-original-commit: a3afb98b9a90b28454284528871dd805da9a95b1 Signed-off-by: Victor Feyens (vfe) <vfe@odoo.com>
Diffstat (limited to 'addons/sale_coupon')
-rw-r--r--addons/sale_coupon/models/sale_order.py27
-rw-r--r--addons/sale_coupon/tests/__init__.py1
-rw-r--r--addons/sale_coupon/tests/test_sale_invoicing.py54
3 files changed, 82 insertions, 0 deletions
diff --git a/addons/sale_coupon/models/sale_order.py b/addons/sale_coupon/models/sale_order.py
index 031a13a2bd6..61af502619b 100644
--- a/addons/sale_coupon/models/sale_order.py
+++ b/addons/sale_coupon/models/sale_order.py
@@ -427,6 +427,33 @@ class SaleOrder(models.Model):
"""
return self.code_promo_program_id + self.no_code_promo_program_ids + self.applied_coupon_ids.mapped('program_id')
+ def _get_invoice_status(self):
+ # Handling of a specific situation: an order contains
+ # a product invoiced on delivery and a promo line invoiced
+ # on order. We would avoid having the invoice status 'to_invoice'
+ # if the created invoice will only contain the promotion line
+ super()._get_invoice_status()
+ for order in self.filtered(lambda order: order.invoice_status == 'to invoice'):
+ paid_lines = order._get_paid_order_lines()
+ if not any(line.invoice_status == 'to invoice' for line in paid_lines):
+ order.invoice_status = 'no'
+
+ def _get_invoiceable_lines(self, final=False):
+ """ Ensures we cannot invoice only reward lines.
+
+ Since promotion lines are specified with service products,
+ those lines are directly invoiceable when the order is confirmed
+ which can result in invoices containing only promotion lines.
+
+ To avoid those cases, we allow the invoicing of promotion lines
+ iff at least another 'basic' lines is also invoiceable.
+ """
+ invoiceable_lines = super()._get_invoiceable_lines(final)
+ reward_lines = self._get_reward_lines()
+ if invoiceable_lines <= reward_lines:
+ return self.env['sale.order.line'].browse()
+ return invoiceable_lines
+
class SaleOrderLine(models.Model):
_inherit = "sale.order.line"
diff --git a/addons/sale_coupon/tests/__init__.py b/addons/sale_coupon/tests/__init__.py
index 96f8d513813..7ec9d2c0a7a 100644
--- a/addons/sale_coupon/tests/__init__.py
+++ b/addons/sale_coupon/tests/__init__.py
@@ -6,3 +6,4 @@ from . import test_program_with_code_operations
from . import test_program_rules
from . import test_program_numbers
from . import test_program_multi_company
+from . import test_sale_invoicing
diff --git a/addons/sale_coupon/tests/test_sale_invoicing.py b/addons/sale_coupon/tests/test_sale_invoicing.py
new file mode 100644
index 00000000000..773df314920
--- /dev/null
+++ b/addons/sale_coupon/tests/test_sale_invoicing.py
@@ -0,0 +1,54 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+from odoo.addons.sale_coupon.tests.common import TestSaleCouponCommon
+from odoo.exceptions import UserError
+from odoo.tests import tagged
+
+
+@tagged('post_install', '-at_install')
+class TestSaleInvoicing(TestSaleCouponCommon):
+
+ def test_invoicing_order_with_promotions(self):
+ discount_coupon_program = self.env['coupon.program'].create({
+ 'name': '10% Discount', # Default behavior
+ 'program_type': 'coupon_program',
+ 'reward_type': 'discount',
+ 'discount_apply_on': 'on_order',
+ 'promo_code_usage': 'no_code_needed',
+ })
+ # Override the default invoice_policy on products
+ discount_coupon_program.discount_line_product_id.invoice_policy = 'order'
+ product = self.env['product.product'].create({
+ 'invoice_policy': 'delivery',
+ 'name': 'Product invoiced on delivery',
+ 'lst_price': 500,
+ })
+
+ order = self.empty_order
+ order.write({
+ 'order_line': [
+ (0, 0, {
+ 'product_id': product.id,
+ })
+ ]
+ })
+
+ order.recompute_coupon_lines()
+ # Order is not confirmed, there shouldn't be any invoiceable line
+ invoiceable_lines = order._get_invoiceable_lines()
+ self.assertEqual(len(invoiceable_lines), 0)
+
+ order.action_confirm()
+ invoiceable_lines = order._get_invoiceable_lines()
+ # Product was not delivered, we cannot invoice
+ # the product line nor the promotion line
+ self.assertEqual(len(invoiceable_lines), 0)
+ with self.assertRaises(UserError):
+ order._create_invoices()
+
+ order.order_line[0].qty_delivered = 1
+ # Product is delivered, the two lines can be invoiced.
+ invoiceable_lines = order._get_invoiceable_lines()
+ self.assertEqual(order.order_line, invoiceable_lines)
+ account_move = order._create_invoices()
+ self.assertEqual(len(account_move.invoice_line_ids), 2)