[IMP] point_of_sale,{pos_}loyalty: ux misc improvements

- The calculator logo of the cash opening popup has been changed to a
bill logo to be more explicite for the end user.
- The cash input is autofocused at the opening of the cash opening
popup. Select number input on focus and align numbers right money
details popup.
- Rearrange Close pos popup layout.
- Set the Gift Card amount to the price of the refound if there is one.
- Change pos_payement_method_view form id order to sequence. Set the
order of payement methods in PayementScreen to sequence.
- Fix markut issue in the chatter.

Task-3215901

closes odoo/odoo#118288

Signed-off-by: Joseph Caburnay (jcb) <jcb@odoo.com>
This commit is contained in:
Loukas Wets (lowe)
2023-05-11 18:25:00 +02:00
parent aa5ba2a101
commit a19cdd6e27
22 changed files with 206 additions and 90 deletions
+1 -1
View File
@@ -11,8 +11,8 @@
'security/loyalty_security.xml',
'report/loyalty_report_templates.xml',
'report/loyalty_report.xml',
'data/loyalty_data.xml',
'data/mail_template_data.xml',
'data/loyalty_data.xml',
'wizard/loyalty_generate_wizard_views.xml',
'views/loyalty_card_views.xml',
'views/loyalty_mail_views.xml',
+26
View File
@@ -22,4 +22,30 @@
<field name="value">False</field>
</record>
</data>
<!-- Gift Cards -->
<record id="gift_card_program" model="loyalty.program">
<field name="name">Gift Cards</field>
<field name="program_type">gift_card</field>
<field name="applies_on">future</field>
<field name="trigger">auto</field>
<field name="portal_visible">True</field>
<field name="portal_point_name">$</field>
<field name="mail_template_id" ref="loyalty.mail_template_gift_card"/>
</record>
<record id="gift_card_program_reward" model="loyalty.reward">
<field name="reward_type">discount</field>
<field name="discount_mode">per_point</field>
<field name="discount">1</field>
<field name="discount_applicability">order</field>
<field name="required_points">1</field>
<field name="program_id" ref="loyalty.gift_card_program"/>
</record>
<record id="gift_card_program_rule" model="loyalty.rule">
<field name="reward_point_amount">1</field>
<field name="reward_point_mode">money</field>
<field name="reward_point_split">True</field>
<field name="product_ids" eval="[(4, ref('loyalty.gift_card_product_50'))]"/>
<field name="program_id" ref="loyalty.gift_card_program"/>
</record>
</odoo>
-27
View File
@@ -72,31 +72,4 @@
<field name="mail_template_id" ref="loyalty.mail_template_loyalty_card"/>
<field name="program_id" ref="loyalty.10_percent_coupon"/>
</record>
<!-- Gift Cards -->
<record id="gift_card_program" model="loyalty.program">
<field name="name">Gift Cards</field>
<field name="program_type">gift_card</field>
<field name="applies_on">future</field>
<field name="trigger">auto</field>
<field name="portal_visible">True</field>
<field name="portal_point_name">$</field>
<field name="mail_template_id" ref="loyalty.mail_template_gift_card"/>
</record>
<record id="gift_card_program_rule" model="loyalty.rule">
<field name="reward_point_amount">1</field>
<field name="reward_point_mode">money</field>
<field name="reward_point_split">True</field>
<field name="product_ids" eval="[(4, ref('loyalty.gift_card_product_50'))]"/>
<field name="program_id" ref="loyalty.gift_card_program"/>
</record>
<record id="gift_card_program_reward" model="loyalty.reward">
<field name="reward_type">discount</field>
<field name="discount_mode">per_point</field>
<field name="discount">1</field>
<field name="discount_applicability">order</field>
<field name="required_points">1</field>
<field name="program_id" ref="loyalty.gift_card_program"/>
</record>
</odoo>
@@ -5,12 +5,13 @@ from odoo.exceptions import UserError
class PosPaymentMethod(models.Model):
_name = "pos.payment.method"
_description = "Point of Sale Payment Methods"
_order = "id asc"
_order = "sequence"
def _get_payment_terminal_selection(self):
return []
name = fields.Char(string="Method", required=True, translate=True, help='Defines the name of the payment method that will be displayed in the Point of Sale when the payments are selected.')
sequence = fields.Integer(copy=False)
outstanding_account_id = fields.Many2one('account.account',
string='Outstanding Account',
ondelete='restrict',
@@ -81,7 +82,8 @@ class PosPaymentMethod(models.Model):
pm.is_cash_count = pm.type == 'cash'
def _is_write_forbidden(self, fields):
return bool(fields and self.open_session_ids)
whitelisted_fields = {'sequence'}
return bool(fields - whitelisted_fields and self.open_session_ids)
def write(self, vals):
if self._is_write_forbidden(set(vals.keys())):
+5 -5
View File
@@ -4,7 +4,7 @@
from collections import defaultdict
from datetime import timedelta
from itertools import groupby
from markupsafe import Markup
from markupsafe import Markup, escape
from odoo import api, fields, models, _, Command
from odoo.exceptions import AccessError, UserError, ValidationError
@@ -1499,9 +1499,9 @@ class PosSession(models.Model):
message = f"{state} difference: " \
f"{self.currency_id.symbol + ' ' if self.currency_id.position == 'before' else ''}" \
f"{self.currency_id.round(difference)} " \
f"{self.currency_id.symbol if self.currency_id.position == 'after' else ''}<br/>"
f"{self.currency_id.symbol if self.currency_id.position == 'after' else ''}" + Markup('<br/>')
if notes:
message += notes.replace('\n', Markup('<br/>'))
message += escape(notes).replace('\n', Markup('<br/>'))
if message:
self.message_post(body=message)
@@ -1979,8 +1979,8 @@ class PosSession(models.Model):
return {
'search_params': {
'domain': ['|', ('active', '=', False), ('active', '=', True)],
'fields': ['name', 'is_cash_count', 'use_payment_terminal', 'split_transactions', 'type', 'image'],
'order': 'is_cash_count desc, id',
'fields': ['name', 'is_cash_count', 'use_payment_terminal', 'split_transactions', 'type', 'image', 'sequence'],
'order': 'sequence',
},
}
@@ -200,7 +200,6 @@ export class PosStore extends Reactive {
if (!options) {
return;
}
// Add the product after having the extra information.
this.addProductFromUi(product, options);
this.numberBuffer.reset();
@@ -1,5 +1,5 @@
.pos .opening-cash-control .body{
margin: 40px;
margin: 24px;
}
.pos .opening-cash-control .opening-cash-section {
@@ -33,4 +33,5 @@
line-height: 20px;
resize: none;
height: 150px;
border-radius: 0px;
}
@@ -8,17 +8,22 @@
padding: 3% 5%;
}
.pos .close-pos-popup .body.notes{
border-top: solid 1px rgba(60, 60, 60, 0.1);
}
.pos .close-pos-popup header {
display: flex;
justify-content: space-between;
width: auto;
height: 65px;
background-color: rgb(255, 255, 255);
border-bottom: solid 1px rgba(60, 60, 60, 0.1);
}
.pos .close-pos-popup .title,
.pos .close-pos-popup .total-orders {
padding: 2.5%;
border-bottom: none;
}
.pos .close-pos-popup .total-orders .amount {
@@ -28,20 +33,38 @@
.notes-container {
display: flex;
justify-content: space-around;
width: 100%;
padding-top: 1%;
box-sizing: border-box;
gap:20px;
height: 120px;
}
.pos .close-pos-popup .opening-notes-container{
text-align: left;
display: flex;
flex-direction: column;
flex-grow: 1;
gap: 5px
}
.pos .close-pos-popup .opening-notes {
color: darkgrey;
text-align: left;
font-size: 16px;
font-weight: 350;
box-sizing: border-box;
min-width: 40%;
padding: 5px 10px;
border-left: solid 3px darkgray;
line-height: 20px;
overflow-y: auto;
word-break: break-word;
border-radius: 0px;
resize: none;
height: 100%;
}
.pos .close-pos-popup .closing-notes-container{
text-align: left;
display: flex;
flex-direction: column;
flex-grow: 1;
gap: 5px;
}
.pos .close-pos-popup .closing-notes {
@@ -49,10 +72,9 @@
font-weight: 350;
box-sizing: border-box;
line-height: 20px;
width: 100%;
min-width: 60%;
min-height: 100px;
resize: none;
border-radius: 0px;
height: 100%;
}
.pos .close-pos-popup .payment-methods-overview {
@@ -71,7 +93,7 @@
.pos .close-pos-popup .flex {
display: flex;
}
max-width: 200px;}
.pos .close-pos-popup th:nth-child(1),
.pos .close-pos-popup td:nth-child(1) {
@@ -92,7 +114,7 @@
.pos .close-pos-popup th:nth-child(4),
.pos .close-pos-popup td:nth-child(4) {
text-align: left;
text-align: right;
padding-left: 10px;
}
.pos .close-pos-popup .payment-methods-overview table .pos-input {
@@ -119,7 +141,9 @@
}
.pos .close-pos-popup .payment-methods-overview .cash-overview {
border-left: solid 2px #555555;
border-left: solid 2px darkgrey;
color: darkgrey;
font-size: 14px;
}
.pos .close-pos-popup .payment-methods-overview .cash-overview tr td:first-child {
@@ -173,7 +197,13 @@
.pos .close-pos-popup .footer .small.button {
float: right;
width: 6%;
min-width: 45px;
min-width: 120px;
}
.pos .close-pos-popup .footer .small.button .daily.sale {
font-size : 14px;
display: inline;
margin-right: 10px;
}
.pos .close-pos-popup .footer .button.disabled {
@@ -1,7 +1,7 @@
/** @odoo-module */
import { AbstractAwaitablePopup } from "@point_of_sale/js/Popups/AbstractAwaitablePopup";
import { useService } from "@web/core/utils/hooks";
import { useAutofocus, useService } from "@web/core/utils/hooks";
import { usePos } from "@point_of_sale/app/pos_hook";
import { MoneyDetailsPopup } from "./MoneyDetailsPopup";
import { useState } from "@odoo/owl";
@@ -21,6 +21,7 @@ export class CashOpeningPopup extends AbstractAwaitablePopup {
});
this.popup = useService("popup");
this.orm = useService("orm");
useAutofocus({ refName: "cash-input" });
}
//@override
async confirm() {
+27 -7
View File
@@ -466,6 +466,8 @@ td {
}
.pos .oe_link_icon{
cursor:pointer;
text-align: right;
width: 50px;
}
/* ********* Contains everything below the bar ********* */
@@ -2516,12 +2518,14 @@ td {
height:100%;
background-color: rgba(0,0,0,0.5);
z-index:1000;
display:flex;
align-items:center;
justify-content:center;
}
.pos .modal-dialog header{
position: relative;
}
.pos .modal-dialog .popup{
position: absolute;
margin: auto;
max-width:500px;
width: 100%;
@@ -2533,10 +2537,6 @@ td {
z-index:1200;
font-family: 'Lato';
font-family: Lato;
/* position the popup at center and and still making it draggable*/
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.pos .modal-dialog .popup-med{
@@ -2562,7 +2562,7 @@ td {
.pos .popup .body {
font-weight: normal;
font-size: 18px;
margin: 16px;
padding: 16px;
white-space: pre-line;
}
@@ -2627,6 +2627,18 @@ td {
.pos .popup .button.icon {
width: 40px;
font-size: 20px;
display: flex;
justify-content: center;
align-items: center;
}
.pos .popup .button.icon.ClosePosPopup{
height: 35px;
font-size: 20px;
margin-top: 0px;
margin-right: 0px;
display: flex;
justify-content: center;
align-items: center;
}
.pos .popup .button:active{
color: white;
@@ -3134,6 +3146,10 @@ td {
overflow-y: auto;
font-size: medium;
}
.pos .orders .cashier {
font-style: italic;
font-size: 12px;
}
.pos .orders .header-row{
display: flex;
@@ -3173,6 +3189,7 @@ td {
position: sticky;
top: 0;
background: $gray-300;
z-index: 100;
}
.ticket-screen .controls button.search {
margin: 0;
@@ -3185,6 +3202,9 @@ td {
.ticket-screen .rightpane {
width: auto;
}
.pos .orders {
position: sticky;
}
}
.pos .orders .order-row:hover, .pos .orders .order-row.highlight {
@@ -3252,7 +3272,7 @@ td {
justify-content: space-between;
align-items: center;
padding: 0px 10px;
flex: 0 0 80px;
flex: 0 0 80px
}
.ticket-screen .controls button {
@@ -9,9 +9,9 @@
<div class="opening-cash-section">
<span class="info-title">Opening cash</span>
<div class="cash-input-sub-section" t-on-input="handleInputChange">
<input class="pos-input" type="number" t-model.number="state.openingCash"/>
<input class="pos-input" type="number" t-model.number="state.openingCash" t-ref="cash-input" t-on-focus="ev=>ev.target.select()"/>
<div class="button icon" t-on-click="openDetailsPopup">
<i class="fa fa-calculator" role="img" title="Open the money details popup"/>
<i class="fa fa-money" role="img" title="Open the money details popup"/>
</div>
</div>
</div>
@@ -17,7 +17,7 @@
<tr>
<th>Payment Method</th>
<th>Expected</th>
<th style="width: 25%">Counted</th>
<th style="width: 20%">Counted</th>
<th style="width: 20%">Difference</th>
</tr>
</thead>
@@ -27,9 +27,9 @@
<td t-esc="defaultCashDetails.name"/>
<td t-esc="env.utils.formatCurrency(defaultCashDetails.amount)"/>
<td class="flex" t-on-input="() => this.handleInputChange(defaultCashDetails.id)">
<input class="pos-input" type="number" t-model.number="state.payments[defaultCashDetails.id].counted"/>
<div class="button icon" t-on-click="openDetailsPopup">
<i class="fa fa-calculator" role="img" title="Open the money details popup"/>
<input class="pos-input" type="number" t-model.number="state.payments[defaultCashDetails.id].counted" t-on-focus="ev=>ev.target.select()"/>
<div class="button icon ClosePosPopup" t-on-click="openDetailsPopup">
<i class="fa fa-money" role="img" title="Open the money details popup"/>
</div>
</td>
<td t-esc="env.utils.formatCurrency(state.payments[defaultCashDetails.id].difference)" t-att-class="{'warning': state.payments[defaultCashDetails.id].difference}"/>
@@ -65,17 +65,25 @@
<td t-esc="pm.name"/>
<td t-esc="env.utils.formatCurrency(pm.amount)"/>
<t t-set="_showDiff" t-value="_getShowDiff(pm)" />
<td t-if="_showDiff" t-on-input="() => this.handleInputChange(pm.id)"><input class="pos-input" type="number" t-model.number="state.payments[pm.id].counted"/></td>
<td t-if="_showDiff" t-on-input="() => this.handleInputChange(pm.id)"><input class="pos-input" type="number" t-model.number="state.payments[pm.id].counted" t-on-focus="ev=>ev.target.select()"/></td>
<td t-if="_showDiff" t-esc="env.utils.formatCurrency(state.payments[pm.id].difference)" t-att-class="{'warning': state.payments[pm.id].difference}"/>
</tr>
</tbody>
</table>
</div>
</main>
<main class="body notes">
<div class="notes-container">
<div class="opening-notes" t-if="openingNotes" >
<t t-esc="openingNotes"/>
<div class="opening-notes-container" t-if="openingNotes" >
Opening note
<textarea class="opening-notes">
<t t-esc="openingNotes"/>
</textarea>
</div>
<div class="closing-notes-container">
Closing note
<textarea class="closing-notes" placeholder="Add a closing note..." t-model="state.notes"/>
</div>
<textarea class="closing-notes" placeholder="Add a closing note..." t-model="state.notes"/>
</div>
</main>
<footer class="footer">
@@ -85,6 +93,7 @@
<div class="small button icon"
t-on-click="downloadSalesReport"
title="Download a report with all the sales of the current PoS Session">
<div class="daily sale">Daily Sale</div>
<i class="fa fa-download" role="img"/>
</div>
<!-- Print Sale Details -->
@@ -10,7 +10,7 @@
<div t-foreach="[firstHalfMoneyDetails, lastHalfMoneyDetails]" t-as="moneyDetailsList" t-key="moneyDetailsList_index">
<t t-foreach="moneyDetailsList" t-as="moneyValue" t-key="moneyValue">
<div class="money-details-value" t-on-input="updateMoneyDetailsAmount">
<input class="pos-input" t-att-id="moneyValue" type="number" t-model.number="state.moneyDetails[moneyValue]"/>
<input class="pos-input" t-att-id="moneyValue" type="number" t-model.number="state.moneyDetails[moneyValue]" t-on-focus="ev=>ev.target.select()"/>
<CurrencyAmount forTarget="moneyValue" currency="currency" amount="moneyValue"/>
</div>
</t>
@@ -71,31 +71,27 @@
<t t-foreach="_filteredOrderList" t-as="order" t-key="order.cid">
<div class="order-row" t-att-class="{ highlight: isHighlighted(order) }" t-on-click="() => this.onClickOrder(order)">
<div class="col wide">
<div t-if="env.isMobile">Date</div>
<div><t t-esc="getDate(order)"></t></div>
<div t-if="env.isMobile"><t t-esc="getTotal(order)"></t></div>
</div>
<div class="col wide">
<div t-if="env.isMobile">Receipt Number</div>
<div><t t-esc="order.name"></t></div>
<div t-if="env.isMobile"><t t-esc="getStatus(order)"></t></div>
</div>
<div class="col">
<div t-if="env.isMobile">Customer</div>
<div class="col" t-if="!env.isMobile">
<div><t t-esc="getPartner(order)"></t></div>
</div>
<div t-if="showCardholderName()" class="col">
<div t-if="env.isMobile">Cardholder Name</div>
<div t-if="showCardholderName() &amp;&amp; !env.isMobile" class="col">
<div><t t-esc="getCardholderName(order)"></t></div>
</div>
<div class="col">
<div t-if="env.isMobile">Cashier</div>
<div><t t-esc="getCashier(order)"></t></div>
<div t-if="env.isMobile"><t t-esc="getPartner(order)"></t></div>
<div t-att-class = "env.isMobile ? 'cashier':''"><t t-esc="getCashier(order)"></t></div>
</div>
<div class="col end">
<div t-if="env.isMobile">Total</div>
<div class="col end" t-if="!env.isMobile">
<div><t t-esc="getTotal(order)"></t></div>
</div>
<div class="col narrow">
<div t-if="env.isMobile">Status</div>
<div class="col narrow" t-if="!env.isMobile">
<div><t t-esc="getStatus(order)"></t></div>
</div>
<div t-if="!shouldHideDeleteButton(order)" class="col very-narrow delete-button" name="delete" t-on-click.stop="() => this.onDeleteOrder(order)">
@@ -135,6 +135,12 @@ class Check {
{
trigger: `.ticket-screen .order-row > .col:nth-child(2):contains("${orderName}") ~ .col:nth-child(6):contains(${status})`,
run: () => {},
mobile: false,
},
{
trigger: `.ticket-screen .order-row .col:nth-child(2) div:contains("${orderName}") ~ div:contains(${status})`,
run: () => {},
mobile: true,
},
];
}
+1 -1
View File
@@ -531,7 +531,7 @@ class TestPoSCommon(ValuationReconciliationTestCommon):
# 2. generate the payments
total_amount_incl = sum(line[2]['price_subtotal_incl'] for line in order_lines)
if payments is None:
default_cash_pm = self.config.payment_method_ids.filtered(lambda pm: pm.is_cash_count)[:1]
default_cash_pm = self.config.payment_method_ids.filtered(lambda pm: pm.is_cash_count and not pm.split_transactions)[:1]
if not default_cash_pm:
raise Exception('There should be a cash payment method set in the pos.config.')
payments = [create_payment(default_cash_pm, total_amount_incl)]
@@ -48,6 +48,7 @@
<field name="arch" type="xml">
<tree string="Payment Methods" create="1" delete="1">
<field name="type" invisible="1"/>
<field name="sequence" widget="handle"/>
<field name="name" />
<field name="split_transactions" optional="hide" />
<field name="journal_id" attrs="{'required': [('split_transactions', '=', False)]}" />
@@ -8,4 +8,8 @@
<field name="available_in_pos">True</field>
<field name="taxes_id" eval="False"/>
</record>
<!-- Gift Cards -->
<record id="loyalty.gift_card_program" model="loyalty.program">
<field name="pos_report_print_id" ref="loyalty.report_gift_card"/>
</record>
</odoo>
@@ -90,8 +90,4 @@
<field name="program_id" ref="pos_loyalty.loyalty_program"/>
</record>
<!-- Gift Cards -->
<record id="loyalty.gift_card_program" model="loyalty.program">
<field name="pos_report_print_id" ref="loyalty.report_gift_card"/>
</record>
</odoo>
@@ -32,6 +32,14 @@ patch(PosStore.prototype, "pos_loyalty.PosStore", {
} else if (linkedPrograms.length === 1) {
selectedProgram = linkedPrograms[0];
}
const orderTotal = this.globalState.get_order().get_total_with_tax();
if (
selectedProgram &&
["gift_card", "ewallet"].includes(selectedProgram.program_type) &&
orderTotal < 0
) {
options.price = -orderTotal;
}
if (selectedProgram && selectedProgram.program_type == "gift_card") {
const shouldProceed = await this._setupGiftCardOptions(selectedProgram, options);
if (!shouldProceed) {
@@ -52,7 +60,6 @@ patch(PosStore.prototype, "pos_loyalty.PosStore", {
}
}
}
await _super(product, options);
await order._updatePrograms();
if (rewardsToApply.length == 1) {
@@ -5,6 +5,7 @@ import { ProductScreen } from "@point_of_sale/../tests/tours/helpers/ProductScre
import { TextInputPopup } from "@point_of_sale/../tests/tours/helpers/TextInputPopupTourMethods";
import { getSteps, startSteps } from "@point_of_sale/../tests/tours/helpers/utils";
import { registry } from "@web/core/registry";
import { TicketScreen } from "@point_of_sale/../tests/tours/helpers/TicketScreenTourMethods";
//#region GiftCardProgramCreateSetTour1
startSteps();
@@ -13,7 +14,9 @@ ProductScreen.do.clickHomeCategory();
ProductScreen.do.clickDisplayedProduct("Gift Card");
PosLoyalty.check.orderTotalIs("50.00");
PosLoyalty.exec.finalizeOrder("Cash", "50");
registry.category("web_tour.tours").add("GiftCardProgramCreateSetTour1", { test: true, url: "/pos/web", steps: getSteps() });
registry
.category("web_tour.tours")
.add("GiftCardProgramCreateSetTour1", { test: true, url: "/pos/web", steps: getSteps() });
//#endregion
//#region GiftCardProgramCreateSetTour2
@@ -23,7 +26,9 @@ ProductScreen.do.clickDisplayedProduct("Whiteboard Pen");
PosLoyalty.do.enterCode("044123456");
PosLoyalty.check.orderTotalIs("0.00");
PosLoyalty.exec.finalizeOrder("Cash", "0");
registry.category("web_tour.tours").add("GiftCardProgramCreateSetTour2", { test: true, url: "/pos/web", steps: getSteps() });
registry
.category("web_tour.tours")
.add("GiftCardProgramCreateSetTour2", { test: true, url: "/pos/web", steps: getSteps() });
//#endregion
//#region GiftCardProgramScanUseTour
@@ -47,5 +52,27 @@ ProductScreen.exec.addOrderline("Whiteboard Pen", "6", "6", "36.0");
PosLoyalty.do.enterCode("044123456");
PosLoyalty.check.orderTotalIs("35.00");
PosLoyalty.exec.finalizeOrder("Cash", "35");
registry.category("web_tour.tours").add("GiftCardProgramScanUseTour", { test: true, url: "/pos/web", steps: getSteps() });
registry
.category("web_tour.tours")
.add("GiftCardProgramScanUseTour", { test: true, url: "/pos/web", steps: getSteps() });
//#endregion
startSteps();
ProductScreen.do.confirmOpeningPopup();
ProductScreen.do.clickHomeCategory();
ProductScreen.exec.addOrderline("Magnetic Board", "1"); // 1.98
PosLoyalty.check.orderTotalIs("1.98");
PosLoyalty.exec.finalizeOrder("Cash", "20");
ProductScreen.do.clickRefund();
TicketScreen.do.selectOrder("-0001");
TicketScreen.do.clickOrderline("Magnetic Board");
TicketScreen.do.pressNumpad("1");
TicketScreen.do.confirmRefund();
ProductScreen.check.isShown();
ProductScreen.check.selectedOrderlineHas("Magnetic Board", "-1.00");
ProductScreen.exec.addOrderline("Gift Card", "1");
ProductScreen.check.selectedOrderlineHas("Gift Card", "1");
PosLoyalty.check.orderTotalIs("0.0");
registry
.category("web_tour.tours")
.add("GiftCardWithRefundtTour", { test: true, url: "/pos/web", steps: getSteps() });
+18
View File
@@ -815,3 +815,21 @@ class TestUi(TestPointOfSaleHttpCommon):
"PosLoyaltyFreeProductTour2",
login="accountman",
)
def test_refund_with_gift_card(self):
"""When adding a gift card when there is a refund in the order, the amount
of the gift card is set to the amount of the refund"""
LoyaltyProgram = self.env['loyalty.program']
# Deactivate all other programs to avoid interference
(LoyaltyProgram.search([])).write({'pos_ok': False})
# But activate the gift_card_product_50 because it's shared among new gift card programs.
self.env.ref('loyalty.gift_card_product_50').write({'active': True})
# Create gift card program
self.create_programs([('arbitrary_name', 'gift_card')])
# Change the gift card program settings
self.main_pos_config.write({'gift_card_settings': 'create_set'})
self.start_tour(
"/pos/web?config_id=%d" % self.main_pos_config.id,
"GiftCardWithRefundtTour",
login="accountman"
)