diff options
| author | Andrea Grazioso (agr-odoo) <agr@odoo.com> | 2020-12-22 17:20:09 +0000 |
|---|---|---|
| committer | Victor Feyens <vfe@odoo.com> | 2021-01-20 15:44:20 +0000 |
| commit | 6532c6ba7acb2de53fc839d5a7c5d8b200716565 (patch) | |
| tree | 79a33fcbb4e091f42edfd57a21a1eaf1fa5241ad /addons/sale_coupon | |
| parent | 604c07edcd4da8cf2a663d06ba91f137eb74691b (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.py | 27 | ||||
| -rw-r--r-- | addons/sale_coupon/tests/__init__.py | 1 | ||||
| -rw-r--r-- | addons/sale_coupon/tests/test_sale_invoicing.py | 54 |
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) |
