99 lines
4.6 KiB
Python
99 lines
4.6 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
import json
|
|
from odoo import models, fields, api
|
|
from odoo.fields import Domain
|
|
|
|
class LoyaltyReward(models.Model):
|
|
_inherit = 'loyalty.reward'
|
|
|
|
reward_product_applicability = fields.Selection([
|
|
('specific', 'Specific Product(s)'),
|
|
('cheapest', 'Cheapest Product on Order')
|
|
], string='Reward Product Applicability', default='specific')
|
|
|
|
reward_product_category_id = fields.Many2one(
|
|
'product.category', string='Reward Product Category',
|
|
help='If specified, only products under this category (including subcategories) will be considered for the cheapest product reward.'
|
|
)
|
|
|
|
reward_product_ids_json = fields.Char(
|
|
compute='_compute_reward_product_ids_json',
|
|
string='Reward Product IDs JSON'
|
|
)
|
|
|
|
@api.depends('reward_product_id', 'reward_product_tag_id', 'reward_type', 'reward_product_applicability', 'reward_product_category_id')
|
|
def _compute_multi_product(self):
|
|
# Override completely (no super()) to avoid recursive field invalidation.
|
|
# In Odoo 19, reassigning a computed field from within its own compute method
|
|
# (after calling super()) triggers cache invalidation and re-computation,
|
|
# causing a RecursionError via WeakSet.__iter__ during environment cleanup.
|
|
for reward in self:
|
|
tag_products = reward.reward_product_tag_id.product_ids.filtered(
|
|
lambda product: product.type != 'combo'
|
|
)
|
|
if reward.reward_type == 'product' and reward.reward_product_applicability == 'cheapest':
|
|
# For 'cheapest' applicability: include direct product + tag products,
|
|
# but not category products (to avoid large sets and reference cycles).
|
|
products = reward.reward_product_id + tag_products
|
|
reward.multi_product = False
|
|
reward.reward_product_ids = products
|
|
else:
|
|
# Default behaviour (mirrors the standard Odoo computation)
|
|
products = reward.reward_product_id + tag_products
|
|
reward.multi_product = reward.reward_type == 'product' and len(products) > 1
|
|
reward.reward_product_ids = (
|
|
products if reward.reward_type == 'product'
|
|
else self.env['product.product']
|
|
)
|
|
|
|
@api.depends('reward_product_id', 'reward_product_tag_id', 'reward_type', 'reward_product_applicability', 'reward_product_category_id')
|
|
def _compute_reward_product_ids_json(self):
|
|
for reward in self:
|
|
if reward.reward_type == 'product' and reward.reward_product_applicability == 'cheapest':
|
|
products = reward.reward_product_id + reward.reward_product_tag_id.product_ids.filtered(
|
|
lambda product: product.type != 'combo'
|
|
)
|
|
if reward.reward_product_category_id:
|
|
category_ids = self.env['product.category'].search([
|
|
('id', 'child_of', reward.reward_product_category_id.ids)
|
|
]).ids
|
|
cat_products = self.env['product.product'].search([
|
|
('categ_id', 'in', category_ids),
|
|
('type', '!=', 'combo')
|
|
])
|
|
products |= cat_products
|
|
reward.reward_product_ids_json = json.dumps(products.ids)
|
|
else:
|
|
reward.reward_product_ids_json = json.dumps([])
|
|
|
|
@api.model
|
|
def _load_pos_data_fields(self, config):
|
|
fields = super()._load_pos_data_fields(config)
|
|
if 'reward_product_applicability' not in fields:
|
|
fields.append('reward_product_applicability')
|
|
if 'reward_product_category_id' not in fields:
|
|
fields.append('reward_product_category_id')
|
|
if 'reward_product_ids_json' not in fields:
|
|
fields.append('reward_product_ids_json')
|
|
return fields
|
|
|
|
@api.model
|
|
def _load_pos_data_domain(self, data, config):
|
|
reward_product_tag_domain = [
|
|
('reward_product_tag_id', '!=', False),
|
|
'|',
|
|
('reward_product_tag_id.product_template_ids.active', '=', True),
|
|
('reward_product_tag_id.product_product_ids.active', '=', True),
|
|
]
|
|
return Domain.AND([
|
|
[('program_id', 'in', config._get_program_ids().ids)],
|
|
Domain.OR([
|
|
[('reward_type', '!=', 'product')],
|
|
[('reward_product_id.active', '=', True)],
|
|
[('reward_product_applicability', '=', 'cheapest')],
|
|
reward_product_tag_domain,
|
|
]),
|
|
])
|
|
|