* Allow multiple loyalty programs. * Improve gift card workflow: https://app.excalidraw.com/l/65VNwvy7c4X/1Xt93llULvo * Integration with the ewallet programs: https://app.excalidraw.com/l/65VNwvy7c4X/4B9AEOSbaku Note that we prevent refunding eWallet and gift card top up and reward products. If for instance the user wants to refund gift cards they'll have to transfer the gift card to ewallet by topping up the customer's ewallet and paying with the gift card to be refunded. closes odoo/odoo#100891 Task-ids: 2959620, 2959661 X-original-commit: fa06e3225650ed9d1a96709b0398e7f33313acf5 Signed-off-by: Trinh Jacky (trj) <trj@odoo.com> Signed-off-by: Joseph Caburnay (jcb) <jcb@odoo.com>
124 lines
5.7 KiB
Python
124 lines
5.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from odoo import models
|
|
from odoo.osv.expression import OR
|
|
|
|
class PosSession(models.Model):
|
|
_inherit = 'pos.session'
|
|
|
|
def _pos_ui_models_to_load(self):
|
|
result = super()._pos_ui_models_to_load()
|
|
if self.config_id._get_program_ids():
|
|
result += [
|
|
'loyalty.program',
|
|
'loyalty.rule',
|
|
'loyalty.reward',
|
|
]
|
|
return result
|
|
|
|
def _loader_params_loyalty_program(self):
|
|
return {
|
|
'search_params': {
|
|
'domain': [('id', 'in', self.config_id._get_program_ids().ids)],
|
|
'fields': ['name', 'trigger', 'applies_on', 'program_type', 'date_to',
|
|
'limit_usage', 'max_usage', 'is_nominative', 'portal_visible', 'portal_point_name', 'trigger_product_ids'],
|
|
},
|
|
}
|
|
|
|
def _loader_params_loyalty_rule(self):
|
|
return {
|
|
'search_params': {
|
|
'domain': [('program_id', 'in', self.config_id._get_program_ids().ids)],
|
|
'fields': ['program_id', 'valid_product_ids', 'any_product', 'currency_id',
|
|
'reward_point_amount', 'reward_point_split', 'reward_point_mode',
|
|
'minimum_qty', 'minimum_amount', 'minimum_amount_tax_mode', 'mode', 'code'],
|
|
}
|
|
}
|
|
|
|
def _loader_params_loyalty_reward(self):
|
|
return {
|
|
'search_params': {
|
|
'domain': [('program_id', 'in', self.config_id._get_program_ids().ids)],
|
|
'fields': ['description', 'program_id', 'reward_type', 'required_points', 'clear_wallet', 'currency_id',
|
|
'discount', 'discount_mode', 'discount_applicability', 'all_discount_product_ids', 'is_global_discount',
|
|
'discount_max_amount', 'discount_line_product_id',
|
|
'multi_product', 'reward_product_ids', 'reward_product_qty', 'reward_product_uom_id'],
|
|
}
|
|
}
|
|
|
|
def _get_pos_ui_loyalty_program(self, params):
|
|
return self.env['loyalty.program'].search_read(**params['search_params'])
|
|
|
|
def _get_pos_ui_loyalty_rule(self, params):
|
|
return self.env['loyalty.rule'].search_read(**params['search_params'])
|
|
|
|
def _get_pos_ui_loyalty_reward(self, params):
|
|
return self.env['loyalty.reward'].search_read(**params['search_params'])
|
|
|
|
def _loader_params_product_product(self):
|
|
result = super(PosSession, self)._loader_params_product_product()
|
|
config = self.config_id
|
|
if config._get_program_ids():
|
|
programs = config._get_program_ids()
|
|
rewards = programs.reward_ids
|
|
products = (programs.rule_ids.valid_product_ids | rewards.discount_line_product_id) |\
|
|
(rewards.all_discount_product_ids | rewards.reward_product_ids)
|
|
result['search_params']['domain'] = OR([result['search_params']['domain'], [('id', 'in', products.ids)]])
|
|
return result
|
|
|
|
def _get_pos_ui_product_product(self, params):
|
|
result = super()._get_pos_ui_product_product(params)
|
|
rewards = self.config_id._get_program_ids().reward_ids
|
|
products = rewards.discount_line_product_id | rewards.reward_product_ids
|
|
products = self.env['product.product'].search_read([('id', 'in', products.ids)], fields=params['search_params']['fields'])
|
|
self._process_pos_ui_product_product(products)
|
|
result.extend(products)
|
|
return result
|
|
|
|
def _get_pos_ui_res_partner(self, params):
|
|
partners = super()._get_pos_ui_res_partner(params)
|
|
self._set_loyalty_cards(partners)
|
|
return partners
|
|
|
|
def get_pos_ui_res_partner_by_params(self, custom_search_params):
|
|
partners = super().get_pos_ui_res_partner_by_params(custom_search_params)
|
|
self._set_loyalty_cards(partners)
|
|
return partners
|
|
|
|
def _set_loyalty_cards(self, partners):
|
|
# Map partner_id to its loyalty cards from all loyalty programs.
|
|
loyalty_programs = self.config_id._get_program_ids().filtered(lambda p: p.program_type == 'loyalty')
|
|
loyalty_card_fields = ['points', 'code', 'program_id']
|
|
partner_id_to_loyalty_card = {}
|
|
for group in self.env['loyalty.card'].read_group(
|
|
domain=[('partner_id', 'in', [p['id'] for p in partners]), ('program_id', 'in', loyalty_programs.ids)],
|
|
fields=[f"{field_name}:array_agg" for field_name in loyalty_card_fields] + ["ids:array_agg(id)"],
|
|
groupby=['partner_id']
|
|
):
|
|
loyalty_cards = {}
|
|
for i in range(group['partner_id_count']):
|
|
loyalty_cards[group['ids'][i]] = {field_name: group[field_name][i] for field_name in loyalty_card_fields}
|
|
partner_id_to_loyalty_card[group['partner_id'][0]] = loyalty_cards
|
|
|
|
# Assign loyalty cards to each partner to load.
|
|
for partner in partners:
|
|
partner['loyalty_cards'] = partner_id_to_loyalty_card.get(partner['id'], {})
|
|
|
|
return partners
|
|
|
|
def _pos_data_process(self, loaded_data):
|
|
super()._pos_data_process(loaded_data)
|
|
|
|
# Additional post processing to link gift card and ewallet programs
|
|
# to their rules' products.
|
|
# Important because points from their products are only counted once.
|
|
product_id_to_program_ids = {}
|
|
for program in self.config_id._get_program_ids():
|
|
if program.program_type in ['gift_card', 'ewallet']:
|
|
for product in program.trigger_product_ids:
|
|
product_id_to_program_ids.setdefault(product['id'], [])
|
|
product_id_to_program_ids[product['id']].append(program['id'])
|
|
|
|
loaded_data['product_id_to_program_ids'] = product_id_to_program_ids
|