[FIX] (sale_loyalty_)delivery: fix invoice status

Steps to reproduce:
1) Create loyalty program with default settings (10% discount on all
   orders above $50)
2) Create quotation with amount >50, all products must be invoiceable on
   delivered quantity, not ordered quantity
3) Add promotion with 'Promotions' button
4) Confirm order
5) Order has invoice status 'Nothing to invoice'
6) Add shipping
7) Order now has invoice status 'To invoice'

An order with shipping and no promo, or no promo with shipping, would in
both cases have nothing to invoice as long as the 'real' products are
not delivered. But when you have both a promo and delivery line, the
order is 'to invoice'.

The '_compute_invoice_status' methods of sale.order in the delivery and
sale_loyalty modules are not compatible, as the delivery compute filters
out delivery but not reward lines.

OPW-3357289

closes odoo/odoo#139014

X-original-commit: 201a4fc7144935947cd2909e4830a666bbdac02d
Signed-off-by: Vallaeys Valentin (vava) <vava@odoo.com>
This commit is contained in:
vava-odoo
2023-10-18 13:39:19 +00:00
parent 0728b447a6
commit e013c8613c
3 changed files with 55 additions and 1 deletions
+10 -1
View File
@@ -135,10 +135,19 @@ class SaleOrder(models.Model):
for order in self:
if order.invoice_status in ['no', 'invoiced']:
continue
order_lines = order.order_line.filtered(lambda x: not x.is_delivery and not x.is_downpayment and not x.display_type and x.invoice_status != 'invoiced')
order_lines = order._get_lines_impacting_invoice_status()
if all(line.product_id.invoice_policy == 'delivery' and line.invoice_status == 'no' for line in order_lines):
order.invoice_status = 'no'
def _get_lines_impacting_invoice_status(self):
return self.order_line.filtered(
lambda line:
not line.is_delivery
and not line.is_downpayment
and not line.display_type
and line.invoice_status != 'invoiced'
)
@api.depends('order_line.product_uom_qty', 'order_line.product_uom')
def _compute_shipping_weight(self):
for order in self:
@@ -25,6 +25,11 @@ class SaleOrder(models.Model):
return res + self.order_line.filtered(
lambda line: line.is_delivery or line.reward_id.reward_type == 'shipping')
def _get_lines_impacting_invoice_status(self):
return super()._get_lines_impacting_invoice_status().filtered(
lambda line: not line.is_reward_line
)
def _get_reward_values_free_shipping(self, reward, coupon, **kwargs):
delivery_line = self.order_line.filtered(lambda l: l.is_delivery)
taxes = delivery_line.product_id.taxes_id.filtered(lambda t: t.company_id.id == self.company_id.id)
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import Command
from odoo.addons.sale_loyalty.tests.common import TestSaleCouponCommon
from odoo.tests import Form, tagged
@@ -317,3 +318,42 @@ class TestSaleCouponProgramRules(TestSaleCouponCommon):
self._apply_promo_code(order, loyalty_card.code)
# Check if there is an error in the sequence
# via `_apply_program_reward` in `apply_promo_code` method
def test_nothing_delivered_nothing_to_invoice(self):
program = self.env['loyalty.program'].create({
'name': '10% reduction on all orders',
'trigger': 'auto',
'program_type': 'promotion',
'rule_ids': [Command.create({
'minimum_amount': 50,
})],
'reward_ids': [Command.create({
'reward_type': 'discount',
'discount': 10,
'discount_mode': 'percent',
'discount_applicability': 'order',
})]
})
product = self.env['product.product'].create({
'name': 'Test product',
'type': 'product',
'list_price': 200.0,
'invoice_policy': 'delivery',
})
order = self.empty_order
self.env['sale.order.line'].create({
'product_id': product.id,
'order_id': order.id,
})
self._auto_rewards(order, program)
self.assertNotEqual(order.reward_amount, 0)
self.assertEqual(order.invoice_status, 'no')
delivery_wizard = Form(self.env['choose.delivery.carrier'].with_context({
'default_order_id': order.id,
'default_carrier_id': self.carrier.id
}))
choose_delivery_carrier = delivery_wizard.save()
choose_delivery_carrier.button_confirm()
order.action_confirm()
self.assertEqual(order.delivery_set, True)
self.assertEqual(order.invoice_status, 'no')