fix: handle missing program_id in POS reward lines and update module documentation
This commit is contained in:
parent
181429a887
commit
40ef3de37b
24
README.md
24
README.md
@ -1,15 +1,25 @@
|
|||||||
# POS Loyalty Safe Coupon Patch
|
# POS Loyalty Safe Coupon Patch
|
||||||
|
|
||||||
This custom Odoo module resolves a core Odoo 19 bug in the POS Loyalty module where standard Odoo code makes unsafe direct reads on `coupon_id.id` of reward lines.
|
This custom Odoo module resolves critical Point of Sale (POS) Loyalty bugs in Odoo 19 that cause the POS UI to crash or render as a blank screen.
|
||||||
|
|
||||||
|
## Unsafe Coupon Access Fix
|
||||||
When an order is restored (e.g., during table switching in a restaurant) and references a coupon that is not yet fully loaded in the local client registry, Odoo leaves `coupon_id` as `undefined`. Accessing `.id` on this undefined object crashes the POS UI.
|
When an order is restored (e.g., during table switching in a restaurant) and references a coupon that is not yet fully loaded in the local client registry, Odoo leaves `coupon_id` as `undefined`. Accessing `.id` on this undefined object crashes the POS UI.
|
||||||
|
|
||||||
## How it works
|
**How it works:**
|
||||||
Without modifying any core Odoo code, this module dynamically patches:
|
* Dynamically patches `PosOrder.getLoyaltyPoints()`, `OrderPaymentValidation.validateOrder()`, and `PosStore.postProcessLoyalty()`.
|
||||||
1. `PosOrder.getLoyaltyPoints()`
|
* Temporarily mocks any missing `coupon_id` references with `{ id: 0 }`.
|
||||||
2. `OrderPaymentValidation.validateOrder()`
|
* Intercepts `this.data.call` during `postProcessLoyalty` to strip out dummy coupon records with ID `0` before communicating with the backend.
|
||||||
3. `PosStore.postProcessLoyalty()`
|
|
||||||
|
|
||||||
During their respective execution, it temporarily mocks any missing `coupon_id` references with `{ id: 0 }`. It also wraps `this.data.call` during `postProcessLoyalty` to ensure dummy coupon records with ID `0` are filtered out before being communicated back to the Odoo backend server. After execution, the original `undefined` state of the coupon is safely restored.
|
---
|
||||||
|
|
||||||
|
## Invalid/Archived Rewards & program_id Fix
|
||||||
|
During startup or draft order restoration, if an existing order contains a reward line whose corresponding `reward_id` or `reward_id.program_id` is missing or archived (and therefore not loaded in the client registry), Odoo attempts to read `program_type` from it. This triggers a `TypeError: Cannot read properties of undefined (reading 'program_id')` or `(reading 'program_type')` and leaves a blank screen.
|
||||||
|
|
||||||
|
**How it works:**
|
||||||
|
* Dynamically patches `PosOrder._updateRewardLines()` and `PosStore.orderUpdateLoyaltyPrograms()`.
|
||||||
|
* Automatically filters and deletes reward lines that are missing a valid `reward_id` or its associated `program_id`.
|
||||||
|
* Restores non-corrupted order lines, safely healing the order state and allowing the POS session to load successfully.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
This ensures zero side effects, maximum stability, and clean compatibility with standard/custom addons.
|
This ensures zero side effects, maximum stability, and clean compatibility with standard/custom addons.
|
||||||
|
|||||||
@ -22,7 +22,7 @@ patch(PosOrder.prototype, {
|
|||||||
},
|
},
|
||||||
_updateRewardLines() {
|
_updateRewardLines() {
|
||||||
if (this.lines) {
|
if (this.lines) {
|
||||||
const invalidRewardLines = this.lines.filter((line) => line.is_reward_line && !line.reward_id);
|
const invalidRewardLines = this.lines.filter((line) => line.is_reward_line && (!line.reward_id || !line.reward_id.program_id));
|
||||||
for (const line of invalidRewardLines) {
|
for (const line of invalidRewardLines) {
|
||||||
line.delete();
|
line.delete();
|
||||||
}
|
}
|
||||||
@ -84,7 +84,7 @@ patch(PosStore.prototype, {
|
|||||||
async orderUpdateLoyaltyPrograms() {
|
async orderUpdateLoyaltyPrograms() {
|
||||||
const order = this.getOrder();
|
const order = this.getOrder();
|
||||||
if (order && order.lines) {
|
if (order && order.lines) {
|
||||||
const invalidRewardLines = order.lines.filter((line) => line.is_reward_line && !line.reward_id);
|
const invalidRewardLines = order.lines.filter((line) => line.is_reward_line && (!line.reward_id || !line.reward_id.program_id));
|
||||||
for (const line of invalidRewardLines) {
|
for (const line of invalidRewardLines) {
|
||||||
line.delete();
|
line.delete();
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user