19.0 vanilla

This commit is contained in:
Ernad Husremovic 2026-03-09 09:32:12 +01:00
parent 79f83631d5
commit 73afc09215
6267 changed files with 1534193 additions and 1130106 deletions

View file

@ -1,13 +1,18 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import date, timedelta
from odoo.addons.sale_loyalty.tests.common import TestSaleCouponCommon
from odoo.exceptions import ValidationError
from odoo import Command
from freezegun import freeze_time
from pytz import timezone
class TestProgramRules(TestSaleCouponCommon):
from odoo.exceptions import ValidationError
from odoo.fields import Command, Datetime
from odoo.addons.payment.tests.common import PaymentCommon
from odoo.addons.sale_loyalty.tests.common import TestSaleCouponCommon
class TestProgramRules(TestSaleCouponCommon, PaymentCommon):
# Test all the validity rules to allow a customer to have a reward.
# The check based on the products is already done in the basic operations test
@ -25,13 +30,11 @@ class TestProgramRules(TestSaleCouponCommon):
(0, False, {
'product_id': self.product_A.id,
'name': '1 Product A',
'product_uom': self.uom_unit.id,
'product_uom_qty': 1.0,
}),
(0, False, {
'product_id': self.product_B.id,
'name': '2 Product B',
'product_uom': self.uom_unit.id,
'product_uom_qty': 1.0,
})
]})
@ -39,18 +42,16 @@ class TestProgramRules(TestSaleCouponCommon):
self._claim_reward(order, self.immediate_promotion_program)
self.assertEqual(len(order.order_line.ids), 2, "The promo offer shouldn't have been applied as the purchased amount is not enough")
order = self.env['sale.order'].create({'partner_id': self.steve.id})
order = self.env['sale.order'].create({'partner_id': self.partner.id})
order.write({'order_line': [
(0, False, {
'product_id': self.product_A.id,
'name': '10 Product A',
'product_uom': self.uom_unit.id,
'product_uom_qty': 10.0,
}),
(0, False, {
'product_id': self.product_B.id,
'name': '2 Product B',
'product_uom': self.uom_unit.id,
'product_uom_qty': 1.0,
})
]})
@ -282,8 +283,8 @@ class TestProgramRules(TestSaleCouponCommon):
discounts = set(order.order_line.mapped('name')) - {'Product A'}
self.assertEqual(len(discounts), 1, "The order should contains the Product A line and a discount")
# The name of the discount is dynamically changed to smth looking like:
# "Discount: Get 5% discount if buy at least 2 Product - On product with following tax: Tax 15.00%"
self.assertTrue('Discount: 5% on your order' in discounts.pop(), "The discount should be a 5% discount")
# "Discount Get 5% discount if buy at least 2 Product - On product with following tax: Tax 15.00%"
self.assertTrue('Discount 5% on your order' in discounts.pop(), "The discount should be a 5% discount")
sol.product_uom_qty = 5
order._update_programs_and_rewards()
@ -291,71 +292,215 @@ class TestProgramRules(TestSaleCouponCommon):
self._claim_reward(order, p2)
discounts = set(order.order_line.mapped('name')) - {'Product A'}
self.assertEqual(len(discounts), 1, "The order should contains the Product A line and a discount")
self.assertTrue('Discount: 10% on your order' in discounts.pop(), "The discount should be a 10% discount")
self.assertTrue('Discount 10% on your order' in discounts.pop(), "The discount should be a 10% discount")
def test_program_rules_validity_dates_and_uses(self):
# Test case: Based on the validity dates and the number of allowed uses
@freeze_time('2011-11-02 09:00:21')
def test_program_rules_validity_dates(self):
# Test date_to (no date_from)
today = date.today()
past_day = today - timedelta(days=2)
future_day = today + timedelta(days=2)
self.immediate_promotion_program.write({'date_to': past_day})
order = self.empty_order
order.write({'order_line': [
Command.create({
'product_id': self.product_A.id,
'name': '1 Product A',
'product_uom_qty': 1.0,
}),
Command.create({
'product_id': self.product_B.id,
'name': '2 Product B',
'product_uom_qty': 1.0,
})
]})
self._auto_rewards(order, self.immediate_promotion_program)
msg = "The promo shouldn't have been applied as it is expired."
self.assertEqual(len(order.order_line.ids), 2, msg)
self.immediate_promotion_program.write({'date_to': future_day})
self._auto_rewards(order, self.immediate_promotion_program)
msg = "The promo should have been applied we're between the validity dates."
self.assertEqual(len(order.order_line.ids), 3, msg)
# Test date_from (no date_to)
self.immediate_promotion_program.write({
'date_from': future_day, 'date_to': False,
})
self._auto_rewards(order, self.immediate_promotion_program)
msg = "The promo shouldn't have been applied as it is not active yet."
self.assertEqual(len(order.order_line.ids), 2, msg)
self.immediate_promotion_program.write({'date_from': past_day})
self._auto_rewards(order, self.immediate_promotion_program)
msg = "The promo should have been applied we're between the validity dates."
self.assertEqual(len(order.order_line.ids), 3, msg)
# Test date_from and date_to
self.immediate_promotion_program.write({'date_from': past_day, 'date_to': future_day})
self._auto_rewards(order, self.immediate_promotion_program)
msg = "The promo should have been applied as we're between the validity dates"
self.assertEqual(len(order.order_line.ids), 3, msg)
self.immediate_promotion_program.write({
'date_to': date.today() - timedelta(days=2),
'date_from': today + timedelta(days=1),
'date_to': future_day,
})
self._auto_rewards(order, self.immediate_promotion_program)
msg = "The promo offer shouldn't have been applied as it is not active yet."
self.assertEqual(len(order.order_line.ids), 2, msg)
self.immediate_promotion_program.write({
'date_from': past_day,
'date_to': today - timedelta(days=1),
})
self._auto_rewards(order, self.immediate_promotion_program)
msg = "The promo offer shouldn't have been applied as it is expired."
self.assertEqual(len(order.order_line.ids), 2, msg)
self.immediate_promotion_program.write({'date_from': today, 'date_to': today})
self._auto_rewards(order, self.immediate_promotion_program)
msg = "The promo should have been applied as today is a valid starting and ending date."
self.assertEqual(len(order.order_line.ids), 3, msg)
def test_program_rules_number_of_uses(self):
# Test case: Based on the number of allowed uses
self.immediate_promotion_program.write({
'limit_usage': True,
'max_usage': 1,
})
order = self.empty_order
order.write({'order_line': [
(0, False, {
Command.create({
'product_id': self.product_A.id,
'name': '1 Product A',
'product_uom': self.uom_unit.id,
'product_uom_qty': 1.0,
}),
(0, False, {
'product_id': self.product_B.id,
'name': '2 Product B',
'product_uom': self.uom_unit.id,
'product_uom_qty': 1.0,
})
]})
self._auto_rewards(order, self.immediate_promotion_program)
self.assertEqual(len(order.order_line.ids), 2, "The promo offer shouldn't have been applied we're not between the validity dates")
self.assertEqual(len(order.order_line.ids), 2, "The promo offer should have been applied")
self.immediate_promotion_program.write({
'date_to': date.today() + timedelta(days=2),
order = self.env['sale.order'].create({
'partner_id': self.env['res.partner'].create({'name': 'My Partner'}).id
})
order = self.env['sale.order'].create({'partner_id': self.steve.id})
order.write({'order_line': [
(0, False, {
'product_id': self.product_A.id,
'name': '1 Product A',
'product_uom': self.uom_unit.id,
'product_uom_qty': 10.0,
}),
(0, False, {
Command.create({
'product_id': self.product_B.id,
'name': '2 Product B',
'product_uom': self.uom_unit.id,
'product_uom_qty': 1.0,
})
]})
self._auto_rewards(order, self.immediate_promotion_program)
self.assertEqual(len(order.order_line.ids), 3, "The promo offer should have been applied as we're between the validity dates")
order = self.env['sale.order'].create({'partner_id': self.env['res.partner'].create({'name': 'My Partner'}).id})
order.write({'order_line': [
(0, False, {
'product_id': self.product_A.id,
'name': '1 Product A',
'product_uom': self.uom_unit.id,
'product_uom_qty': 10.0,
}),
(0, False, {
'product_id': self.product_B.id,
'name': '2 Product B',
'product_uom': self.uom_unit.id,
'product_uom_qty': 1.0,
})
]})
# Invalidate total_order_count
self.immediate_promotion_program.invalidate_recordset(['order_count', 'total_order_count'])
self._auto_rewards(order, self.immediate_promotion_program)
self.assertEqual(len(order.order_line.ids), 2, "The promo offer shouldn't have been applied as the number of uses is exceeded")
msg = "The promo offer shouldn't have been applied as the number of uses is exceeded"
self.assertEqual(len(order.order_line.ids), 1, msg)
def test_program_rules_validity_date_timezones(self):
"""Test that the validity dates are checked according to the company's time zone"""
self.env.company.partner_id.tz = 'Europe/London'
self.partner.tz = 'America/Los_Angeles'
midnight = Datetime.today()
yesterday = (midnight - timedelta(days=1)).date()
self.immediate_promotion_program.update({
'date_to': yesterday,
'limit_usage': True,
'max_usage': 1,
})
order = self.empty_order.with_context(tz=self.partner.tz)
order.order_line = [
Command.create({'product_id': self.product_A.id}),
Command.create({'product_id': self.product_B.id}),
]
with freeze_time(midnight):
# Try apply reward at UTC midnight with LA time zone in context (expired)
self._auto_rewards(order, self.immediate_promotion_program)
self.assertFalse(
order.order_line.filtered('is_reward_line'),
"Promo should not be applied if only valid in the customer's time zone",
)
with freeze_time(timezone(self.env.company.partner_id.tz).localize(midnight)):
# Try apply reward at London midnight (expired)
self._auto_rewards(order, self.immediate_promotion_program)
self.assertFalse(
order.order_line.filtered('is_reward_line'),
"Promo should not be applied if only valid in the customer's time zone",
)
self.partner.tz = 'Europe/Brussels'
with freeze_time(timezone(self.partner.tz).localize(midnight)):
# Apply reward at Brussels midnight (still valid in company's time zone)
self._auto_rewards(order, self.immediate_promotion_program)
self.assertTrue(
order.order_line.filtered('is_reward_line'),
"Promo should be applied if valid in the company's time zone",
)
def test_program_rules_validity_date_transactions(self):
"""Test that the validity dates are checked according to the time of transaction."""
today = Datetime.today()
tomorrow = today + timedelta(days=1)
self.immediate_promotion_program.update({
'date_to': today,
'limit_usage': True,
'max_usage': 1,
'reward_ids': [Command.set(self.program_gift_card.reward_ids.ids)],
})
order = self.empty_order
order.order_line = [
Command.create({'product_id': self.product_A.id}),
Command.create({'product_id': self.product_B.id}),
]
intial_amount = order.amount_total
self._auto_rewards(order, self.immediate_promotion_program)
self.assertLess(order.amount_total, intial_amount, "A discount should be applied")
tx = order.transaction_ids = self._create_transaction(
flow='redirect',
sale_order_ids=[order.id],
state='pending',
reference=order.name,
amount=order.amount_total,
)
# Our slow provider only gets around to confirming the transaction the next day
with freeze_time(tomorrow):
tx._set_done()
tx._post_process()
self.assertAlmostEqual(
order.amount_total, tx.amount,
msg="Discount should still apply if transaction gets confirmed post-expiration",
)
def test_buy_x_get_y_free_applies_correctly_with_non_unit_uom(self):
buy_x_get_y = self.env['loyalty.program'].create({
'name': 'Buy 12 Take 6',
'program_type': 'buy_x_get_y',
'trigger': 'auto',
'applies_on': 'current',
'rule_ids': [Command.create({
'reward_point_mode': 'unit',
'product_ids': self.product_A.ids,
})],
'reward_ids': [Command.create({
'reward_type': 'product',
'reward_product_id': self.product_A.id,
'required_points': 12,
'reward_product_qty': 6,
})],
})
order = self.empty_order
order.order_line = [
Command.create({
'product_id': self.product_A.id,
'product_uom_id': self.ref('uom.product_uom_dozen'),
'product_uom_qty': 1,
}),
]
self._auto_rewards(order, buy_x_get_y)
reward_line = order.order_line.filtered('is_reward_line')
self.assertTrue(reward_line)
self.assertEqual(reward_line.product_uom_qty, 6)