[FIX] pos_loyalty: prevent using expired eWallets
Current behavior: It was possible to use an expired eWallet to pay for an order. It was also possible to put money on an expired eWallet. Steps to reproduce: - Create an eWallet with an expiration date in the past - Open PoS and add products to the order - Click on the eWallet button - You can still use the eWallet to pay for the order opw-3568270 closes odoo/odoo#149622 X-original-commit: e3492b9192d9ca56104e0ce92371fffc1731b406 Signed-off-by: Joseph Caburnay (jcb) <jcb@odoo.com> Signed-off-by: Robin Engels (roen) <roen@odoo.com>
This commit is contained in:
@@ -331,6 +331,20 @@ msgstr ""
|
||||
#. odoo-javascript
|
||||
#: code:addons/pos_loyalty/static/src/app/control_buttons/reward_button/reward_button.js:0
|
||||
#, python-format
|
||||
msgid "No rewards available."
|
||||
msgstr ""
|
||||
|
||||
#. module: pos_loyalty
|
||||
#. odoo-javascript
|
||||
#: code:addons/pos_loyalty/static/src/js/ControlButtons/eWalletButton.js:0
|
||||
#, python-format
|
||||
msgid "No valid eWallet found"
|
||||
msgstr ""
|
||||
|
||||
#. module: pos_loyalty
|
||||
#. odoo-javascript
|
||||
#: code:addons/pos_loyalty/static/src/js/ControlButtons/RewardButton.js:0
|
||||
#, python-format
|
||||
msgid "Please select a product for this reward"
|
||||
msgstr ""
|
||||
|
||||
@@ -754,6 +768,14 @@ msgstr ""
|
||||
msgid "You cannot set negative quantity or price to gift card or ewallet."
|
||||
msgstr ""
|
||||
|
||||
#. module: pos_loyalty
|
||||
#. odoo-javascript
|
||||
#: code:addons/pos_loyalty/static/src/js/ControlButtons/eWalletButton.js:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You either have not created an eWallet or all your eWallets have expired."
|
||||
msgstr ""
|
||||
|
||||
#. module: pos_loyalty
|
||||
#. odoo-python
|
||||
#: code:addons/pos_loyalty/models/loyalty_program.py:0
|
||||
|
||||
+11
-4
@@ -18,10 +18,10 @@ export class eWalletButton extends Component {
|
||||
|
||||
_getEWalletRewards(order) {
|
||||
const claimableRewards = order.getClaimableRewards();
|
||||
const eWalletRewards = claimableRewards.filter(
|
||||
({ reward }) => reward.program_id.program_type == "ewallet"
|
||||
);
|
||||
return eWalletRewards;
|
||||
return claimableRewards.filter((reward_line) => {
|
||||
const coupon = this.pos.couponCache[reward_line.coupon_id];
|
||||
return coupon && reward_line.reward.program_id.program_type == 'ewallet' && !coupon.isExpired();
|
||||
});
|
||||
}
|
||||
_getEWalletPrograms() {
|
||||
return this.pos.programs.filter((p) => p.program_type == "ewallet");
|
||||
@@ -31,6 +31,13 @@ export class eWalletButton extends Component {
|
||||
const eWalletPrograms = this.pos.programs.filter((p) => p.program_type == "ewallet");
|
||||
const orderTotal = order.get_total_with_tax();
|
||||
const eWalletRewards = this._getEWalletRewards(order);
|
||||
if (eWalletRewards.length === 0 && orderTotal >= 0) {
|
||||
this.popup.add(ErrorPopup, {
|
||||
title: _t('No valid eWallet found'),
|
||||
body: _t('You either have not created an eWallet or all your eWallets have expired.'),
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (orderTotal < 0 && eWalletPrograms.length >= 1) {
|
||||
let selectedProgram = null;
|
||||
if (eWalletPrograms.length == 1) {
|
||||
|
||||
@@ -25,13 +25,19 @@ export class PosLoyaltyCard {
|
||||
* @param {number} program_id id of loyalty.program
|
||||
* @param {number} partner_id id of res.partner
|
||||
* @param {number} balance points on the coupon, not counting the order's changes
|
||||
* @param {string} expiration_date
|
||||
*/
|
||||
constructor(code, id, program_id, partner_id, balance) {
|
||||
constructor(code, id, program_id, partner_id, balance, expiration_date = false) {
|
||||
this.code = code;
|
||||
this.id = id || nextId--;
|
||||
this.program_id = program_id;
|
||||
this.partner_id = partner_id;
|
||||
this.balance = balance;
|
||||
this.expiration_date = expiration_date && new Date(expiration_date);
|
||||
}
|
||||
|
||||
isExpired() {
|
||||
return this.expiration_date && this.expiration_date < new Date();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1547,7 +1553,8 @@ patch(Order.prototype, {
|
||||
payload.coupon_id,
|
||||
payload.program_id,
|
||||
payload.partner_id,
|
||||
payload.points
|
||||
payload.points,
|
||||
payload.expiration_date,
|
||||
);
|
||||
this.pos.couponCache[coupon.id] = coupon;
|
||||
this.codeActivatedCoupons.push(coupon);
|
||||
|
||||
@@ -309,7 +309,7 @@ patch(PosStore.prototype, {
|
||||
const result = await this.env.services.orm.searchRead(
|
||||
"loyalty.card",
|
||||
domain,
|
||||
["id", "points", "code", "partner_id", "program_id"],
|
||||
["id", "points", "code", "partner_id", "program_id", "expiration_date"],
|
||||
{ limit }
|
||||
);
|
||||
if (Object.keys(this.couponCache).length + result.length > COUPON_CACHE_MAX_SIZE) {
|
||||
@@ -327,7 +327,8 @@ patch(PosStore.prototype, {
|
||||
dbCoupon.id,
|
||||
dbCoupon.program_id[0],
|
||||
dbCoupon.partner_id[0],
|
||||
dbCoupon.points
|
||||
dbCoupon.points,
|
||||
dbCoupon.expiration_date
|
||||
);
|
||||
this.couponCache[coupon.id] = coupon;
|
||||
this.partnerId2CouponIds[coupon.partner_id] =
|
||||
|
||||
@@ -5,6 +5,7 @@ import * as ProductScreen from "@point_of_sale/../tests/tours/helpers/ProductScr
|
||||
import * as TicketScreen from "@point_of_sale/../tests/tours/helpers/TicketScreenTourMethods";
|
||||
import * as Chrome from "@point_of_sale/../tests/tours/helpers/ChromeTourMethods";
|
||||
import * as PartnerListScreen from "@point_of_sale/../tests/tours/helpers/PartnerListScreenTourMethods";
|
||||
import * as ErrorPopup from "@point_of_sale/../tests/tours/helpers/ErrorPopupTourMethods";
|
||||
import { registry } from "@web/core/registry";
|
||||
|
||||
//#region EWalletProgramTour1
|
||||
@@ -105,3 +106,21 @@ registry.category("web_tour.tours").add("EWalletProgramTour2", {
|
||||
});
|
||||
|
||||
//#endregion
|
||||
|
||||
registry
|
||||
.category("web_tour.tours")
|
||||
.add('ExpiredEWalletProgramTour', {
|
||||
test: true,
|
||||
url: '/pos/ui',
|
||||
steps: () => [
|
||||
ProductScreen.confirmOpeningPopup(),
|
||||
ProductScreen.clickHomeCategory(),
|
||||
ProductScreen.clickPartnerButton(),
|
||||
ProductScreen.clickCustomer('AAAA'),
|
||||
ProductScreen.addOrderline('Whiteboard Pen', '2', '6', '12.00'),
|
||||
PosLoyalty.eWalletButtonState({ highlighted: false }),
|
||||
PosLoyalty.clickEWalletButton(),
|
||||
ErrorPopup.isShown(),
|
||||
ErrorPopup.clickConfirm()
|
||||
].flat(),
|
||||
});
|
||||
|
||||
@@ -1428,3 +1428,32 @@ class TestUi(TestPointOfSaleHttpCommon):
|
||||
"PosLoyaltyTour9",
|
||||
login="pos_user",
|
||||
)
|
||||
|
||||
def test_ewallet_expiration_date(self):
|
||||
"""
|
||||
Test for ewallet program.
|
||||
- Collect points in EWalletProgramTour1.
|
||||
- Use points in EWalletProgramTour2.
|
||||
"""
|
||||
LoyaltyProgram = self.env['loyalty.program']
|
||||
# Deactivate all other programs to avoid interference
|
||||
(LoyaltyProgram.search([])).write({'pos_ok': False})
|
||||
# But activate the ewallet_product_50 because it's shared among new ewallet programs.
|
||||
self.env.ref('loyalty.ewallet_product_50').write({'active': True})
|
||||
# Create ewallet program
|
||||
ewallet_program = self.create_programs([('arbitrary_name', 'ewallet')])['arbitrary_name']
|
||||
# Create test partners
|
||||
partner_aaa = self.env['res.partner'].create({'name': 'AAAA'})
|
||||
#Create an eWallet for partner_aaa
|
||||
self.env['loyalty.card'].create({
|
||||
'partner_id': partner_aaa.id,
|
||||
'program_id': ewallet_program.id,
|
||||
'points': 50,
|
||||
'expiration_date': '2020-01-01',
|
||||
})
|
||||
self.main_pos_config.open_ui()
|
||||
self.start_tour(
|
||||
"/pos/web?config_id=%d" % self.main_pos_config.id,
|
||||
"ExpiredEWalletProgramTour",
|
||||
login="pos_user",
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user