I’m developing a custom promotion program for Odoo 18 POS.
I created a popup (`SelectedPromotionPopup`) where the user can select a promotion and then click **Confirm** to apply it.
The problem: when I click **Confirm**, nothing happens — my `applyPromotions()` function is not being called.
Here’s a simplified version of the code:
ApplPromotionButton.js
/** @odoo-module */
import { ControlButtons } from "@point_of_sale/app/screens/product_screen/control_buttons/control_buttons";
import { patch } from "@web/core/utils/patch";
import { SelectedPromotionPopup } from "@promotion_program/app/utils/input_popups/SelectedPromotionPopup";
import { _t } from "@web/core/l10n/translation";
import { AlertDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
import { useService } from "@web/core/utils/hooks"; // Ensure useService is imported
patch(ControlButtons.prototype, {
setup() {
super.setup(...arguments);
this.dialog = useService("dialog");
this.pos = this.env.services.pos;
},
async onApplyPromotionClick() {
const order = this.pos.get_order();
const promotions = this.pos.promotions || [];
if (promotions.length > 0) {
try {
const { confirmed, payload } = await this.dialog.add(SelectedPromotionPopup, {
title: _t("Select Promotions to Apply"),
promotions: promotions,
confirmText: _t("Apply"),
cancelText: _t("Cancel"),
});
} catch (error) {
console.error("Error opening popup:", error);
}
} else if (order.orderlines.length > 0) {
this.dialog.add(AlertDialog, {
title: _t("No Promotion Available"),
body: _t("There is no promotion available for the current order!"),
});
}
}
});
SelectedPromotionPopup.js
applyPromotions(willApplyAll) {
console.log("applyPromotions called");
this.props.resolve({ confirmed: true, payload: this.state.selectedPromotions });
}
SelectedPromotionPopup.xml
<t t-name="promotion_program.SelectedPromotionPopup">
<Dialog title="props.title">
<div class="popup popup-textinput">
<div class="modal-body">
<div class="list-group mt-1">
<t t-foreach="props.promotions" t-as="promotion" t-key="promotion.id">
<div class="list-group-item list-group-item-action d-flex align-items-center"
t-att-class="{'selected-item': this.state.selectedPromotionId === promotion.id}"
t-attf-id="promotion-item-{{ promotion.id }}"
t-att-data-id="promotion.id"
t-on-click.prevent="() => this.selectPromotion(promotion.id)">
<!-- Icon -->
<div class="me-2" style="font-size: 28px;">
<i t-if="promotion.type == 'buy_one_get_one'" class="fa fa-gift" style="color:#5B0082"></i>
<i t-if="promotion.type == 'discount'" class="fa fa-percent" style="color:#008081"></i>
<i t-if="promotion.type == 'free_shipping'" class="fa fa-truck" style="color:#006401"></i>
</div>
<!-- Text -->
<div>
<div class="fw-bold">
<t t-esc="promotion.code"/>
</div>
<div class="text-muted small">
<t t-esc="promotion.description or ''"/>
</div>
</div>
</div>
</t>
</div>
</div>
<t t-set-slot="footer">
<div class="button confirm highlight btn btn-lg btn-primary"
t-att-disabled="!this.state.selectedPromotionId"
t-on-click.prevent="() => this.applyPromotions()">
<t t-esc="props.confirmText" />
</div>
<div class="button cancel btn btn-lg btn-secondary" t-on-click="props.cancel">
<t t-esc="props.cancelText" />
</div>
</t>
</div>
</Dialog>
</t>