diff --git a/addons/pos_loyalty/models/pos_order.py b/addons/pos_loyalty/models/pos_order.py index 40ae1d3a4ed..972a817d17c 100644 --- a/addons/pos_loyalty/models/pos_order.py +++ b/addons/pos_loyalty/models/pos_order.py @@ -63,6 +63,8 @@ class PosOrder(models.Model): get_partner_id = lambda partner_id: partner_id and self.env['res.partner'].browse(partner_id).exists() and partner_id or False # Keys are stringified when using rpc coupon_data = {int(k): v for k, v in coupon_data.items()} + + self._check_existing_loyalty_cards(coupon_data) # Map negative id to newly created ids. coupon_new_id_map = {k: k for k in coupon_data.keys() if k > 0} @@ -145,6 +147,25 @@ class PosOrder(models.Model): 'coupon_report': coupon_per_report, } + def _check_existing_loyalty_cards(self, coupon_data): + coupon_key_to_modify = [] + for coupon_id, coupon_vals in coupon_data.items(): + partner_id = coupon_vals.get('partner_id', False) + if partner_id: + partner_coupons = self.env['loyalty.card'].search( + [('partner_id', '=', partner_id), ('program_type', '=', 'loyalty')]) + existing_coupon_for_program = partner_coupons.filtered(lambda c: c.program_id.id == coupon_vals['program_id']) + if existing_coupon_for_program: + coupon_vals['coupon_id'] = existing_coupon_for_program[0].id + coupon_key_to_modify.append([coupon_id, existing_coupon_for_program[0].id]) + for old_key, new_key in coupon_key_to_modify: + coupon_data[new_key] = coupon_data.pop(old_key) + + def _get_fields_for_order_line(self): + fields = super(PosOrder, self)._get_fields_for_order_line() + fields.extend(['is_reward_line', 'reward_id', 'coupon_id', 'reward_identifier_code', 'points_cost']) + return fields + def _add_mail_attachment(self, name, ticket): attachment = super()._add_mail_attachment(name, ticket) gift_card_programs = self.config_id._get_program_ids().filtered(lambda p: p.program_type == 'gift_card' and diff --git a/addons/pos_sale_loyalty/__manifest__.py b/addons/pos_sale_loyalty/__manifest__.py index 3564478fbf9..f387343d254 100644 --- a/addons/pos_sale_loyalty/__manifest__.py +++ b/addons/pos_sale_loyalty/__manifest__.py @@ -18,6 +18,9 @@ This module correct some behaviors when both module are installed. 'point_of_sale._assets_pos': [ 'pos_sale_loyalty/static/src/**/*', ], + 'web.assets_tests': [ + 'pos_sale_loyalty/static/tests/tours/**/*', + ], }, 'license': 'LGPL-3', } diff --git a/addons/pos_sale_loyalty/static/tests/tours/PosSaleLoyaltyTour.js b/addons/pos_sale_loyalty/static/tests/tours/PosSaleLoyaltyTour.js new file mode 100644 index 00000000000..9cfa002f617 --- /dev/null +++ b/addons/pos_sale_loyalty/static/tests/tours/PosSaleLoyaltyTour.js @@ -0,0 +1,25 @@ +/** @odoo-module **/ + +import * as PaymentScreen from "@point_of_sale/../tests/tours/helpers/PaymentScreenTourMethods"; +import * as ReceiptScreen from "@point_of_sale/../tests/tours/helpers/ReceiptScreenTourMethods"; +import * as ProductScreenPos from "@point_of_sale/../tests/tours/helpers/ProductScreenTourMethods"; +import * as ProductScreenSale from "@pos_sale/../tests/helpers/ProductScreenTourMethods"; +const ProductScreen = { ...ProductScreenPos, ...ProductScreenSale }; +import { registry } from "@web/core/registry"; + +registry + .category("web_tour.tours") + .add('PosSaleLoyaltyTour1', { + test: true, + url: '/pos/ui', + steps: () => [ + ProductScreen.confirmOpeningPopup(), + ProductScreen.clickQuotationButton(), + ProductScreen.selectFirstOrder(), + ProductScreen.clickDisplayedProduct('Desk Pad'), + ProductScreen.clickPayButton(), + PaymentScreen.clickPaymentMethod('Bank'), + PaymentScreen.clickValidate(), + ReceiptScreen.isShown(), + ].flat(), + }); diff --git a/addons/pos_sale_loyalty/tests/__init__.py b/addons/pos_sale_loyalty/tests/__init__.py new file mode 100644 index 00000000000..a31f1972ab2 --- /dev/null +++ b/addons/pos_sale_loyalty/tests/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import test_pos_sale_loyalty diff --git a/addons/pos_sale_loyalty/tests/test_pos_sale_loyalty.py b/addons/pos_sale_loyalty/tests/test_pos_sale_loyalty.py new file mode 100644 index 00000000000..c6cc67b52e3 --- /dev/null +++ b/addons/pos_sale_loyalty/tests/test_pos_sale_loyalty.py @@ -0,0 +1,45 @@ +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo.addons.point_of_sale.tests.test_frontend import TestPointOfSaleHttpCommon +from odoo.tests import tagged + + +@tagged("post_install", "-at_install") +class TestPoSSaleLoyalty(TestPointOfSaleHttpCommon): + def test_pos_sale_loyalty_1(self): + """Test that only one loyalty card is created when settling an unconfirmed order.""" + self.env['loyalty.program'].search([]).write({'active': False}) + self.env['loyalty.program'].create({ + 'name': 'Test Loyalty Program', + 'program_type': 'loyalty', + 'trigger': 'auto', + 'applies_on': 'both', + 'rule_ids': [ + (0, 0, { + 'reward_point_mode': 'money', + 'minimum_amount': 1, + 'reward_point_amount': 1, + }), + ], + 'reward_ids': [ + (0, 0, { + 'reward_type': 'discount', + 'discount': 1, + 'required_points': 1000, + 'discount_mode': 'percent', + 'discount_applicability': 'order', + }), + ], + }) + self.env['sale.order'].create({ + 'partner_id': self.partner_a.id, + 'order_line': [(0, 0, { + 'product_id': self.desk_organizer.id, + 'product_uom_qty': 1, + 'price_unit': 100, + })] + }) + + self.main_pos_config.open_ui() + self.start_tour("/pos/web?config_id=%d" % self.main_pos_config.id, "PosSaleLoyaltyTour1", login="accountman") + self.assertEqual(self.env['loyalty.card'].search_count([('partner_id', '=', self.partner_a.id)]), 1)