feat: implement robust note splitting and defensive JSON parsing for POS order lines and customer display
This commit is contained in:
parent
35f254ddb0
commit
19f189dab7
@ -39,9 +39,14 @@ Features
|
||||
# ProductScreen portrait tab state + layout
|
||||
'pos_ui_optimization/static/src/app/screens/product_screen/portrait_mode_patch.js',
|
||||
'pos_ui_optimization/static/src/app/screens/product_screen/portrait_screen.xml',
|
||||
# Note splitting and defensive parsing patches
|
||||
'pos_ui_optimization/static/src/app/screens/product_screen/notes_patch.js',
|
||||
# Portrait CSS (must load after all XML patches)
|
||||
'pos_ui_optimization/static/src/scss/portrait.scss',
|
||||
],
|
||||
'point_of_sale.customer_display_assets': [
|
||||
'pos_ui_optimization/static/src/customer_display/customer_display_patch.js',
|
||||
],
|
||||
},
|
||||
'installable': True,
|
||||
'application': False,
|
||||
|
||||
84
static/src/app/screens/product_screen/notes_patch.js
Normal file
84
static/src/app/screens/product_screen/notes_patch.js
Normal file
@ -0,0 +1,84 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { NoteButton, InternalNoteButton } from "@point_of_sale/app/screens/product_screen/control_buttons/orderline_note_button/orderline_note_button";
|
||||
import { Orderline } from "@point_of_sale/app/components/orderline/orderline";
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
|
||||
// 1. Patch NoteButton to fix line-splitting bug for customer notes in standard Odoo
|
||||
patch(NoteButton.prototype, {
|
||||
async setChanges(selectedOrderline, payload) {
|
||||
var quantity_with_note = 0;
|
||||
const changes = this.pos.getOrderChanges();
|
||||
for (const key in changes.orderlines) {
|
||||
if (changes.orderlines[key].uuid === selectedOrderline.uuid) {
|
||||
quantity_with_note = changes.orderlines[key].quantity;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const saved_quantity = selectedOrderline.qty - quantity_with_note;
|
||||
if (saved_quantity > 0 && quantity_with_note > 0) {
|
||||
const addLineParams = {
|
||||
product_tmpl_id: selectedOrderline.product_id.product_tmpl_id,
|
||||
qty: quantity_with_note,
|
||||
};
|
||||
if (this.type === "internal") {
|
||||
addLineParams.note = payload;
|
||||
} else {
|
||||
addLineParams.customer_note = payload;
|
||||
}
|
||||
await this.pos.addLineToCurrentOrder(addLineParams);
|
||||
selectedOrderline.qty = saved_quantity;
|
||||
for (const line of selectedOrderline.combo_line_ids) {
|
||||
line.setQuantity(line.uiState.oldQty);
|
||||
}
|
||||
} else {
|
||||
this.setOrderlineNote(payload);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 2. Patch InternalNoteButton to handle invalid JSON gracefully
|
||||
patch(InternalNoteButton.prototype, {
|
||||
async onClick() {
|
||||
const selectedOrderline = this.pos.getOrder().getSelectedOrderline();
|
||||
let selectedNote = [];
|
||||
try {
|
||||
selectedNote = JSON.parse(this.currentNote || "[]");
|
||||
} catch (e) {
|
||||
if (this.currentNote) {
|
||||
selectedNote = [{ text: this.currentNote, colorIndex: 0 }];
|
||||
}
|
||||
}
|
||||
const payload = await this.openTextInput(selectedNote.map((n) => n.text).join("\n"));
|
||||
const coloredNotes = payload ? this.reframeNotes(payload) : "[]";
|
||||
if (selectedOrderline) {
|
||||
this.setChanges(selectedOrderline, coloredNotes);
|
||||
} else {
|
||||
this.pos.getOrder().setInternalNote(coloredNotes);
|
||||
}
|
||||
return {
|
||||
confirmed: typeof payload === "string",
|
||||
inputNote: coloredNotes,
|
||||
oldNote: JSON.stringify(selectedNote),
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// 3. Patch Orderline to prevent UI crashes if note contains invalid JSON
|
||||
patch(Orderline.prototype, {
|
||||
get lineScreenValues() {
|
||||
const originalParse = JSON.parse;
|
||||
JSON.parse = function (str) {
|
||||
try {
|
||||
return originalParse(str);
|
||||
} catch (e) {
|
||||
return [{ text: str, colorIndex: 0 }];
|
||||
}
|
||||
};
|
||||
try {
|
||||
return super.lineScreenValues;
|
||||
} finally {
|
||||
JSON.parse = originalParse;
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1,7 +1,7 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { ProductScreen } from "@point_of_sale/app/screens/product_screen/product_screen";
|
||||
import { NoteButton } from "@point_of_sale/app/screens/product_screen/control_buttons/orderline_note_button/orderline_note_button";
|
||||
import { NoteButton, InternalNoteButton } from "@point_of_sale/app/screens/product_screen/control_buttons/orderline_note_button/orderline_note_button";
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
import { useState } from "@odoo/owl";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
@ -32,4 +32,5 @@ patch(ProductScreen.prototype, {
|
||||
ProductScreen.components = {
|
||||
...ProductScreen.components,
|
||||
NoteButton,
|
||||
InternalNoteButton,
|
||||
};
|
||||
|
||||
@ -43,7 +43,7 @@
|
||||
<xpath expr="//Numpad" position="before">
|
||||
<div t-if="portraitMode.isPortrait and !currentOrder.isEmpty() and pos.getOrder()?.uiState.selected_orderline_uuid"
|
||||
class="portrait-numpad-actions d-flex gap-2 mb-2 w-100">
|
||||
<NoteButton label="'Note'" class="'btn btn-outline-primary flex-fill d-flex align-items-center justify-content-center gap-2 py-3 fs-5 fw-bold rounded-3'" />
|
||||
<InternalNoteButton label="'Note'" class="'btn btn-outline-primary flex-fill d-flex align-items-center justify-content-center gap-2 py-3 fs-5 fw-bold rounded-3'" />
|
||||
<button class="btn btn-outline-danger flex-fill d-flex align-items-center justify-content-center gap-2 py-3 fs-5 fw-bold rounded-3"
|
||||
t-on-click="onDeleteLine">
|
||||
<i class="fa fa-trash-o fa-lg"/>Delete
|
||||
|
||||
14
static/src/customer_display/customer_display_patch.js
Normal file
14
static/src/customer_display/customer_display_patch.js
Normal file
@ -0,0 +1,14 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { CustomerDisplay } from "@point_of_sale/customer_display/customer_display";
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
|
||||
patch(CustomerDisplay.prototype, {
|
||||
getInternalNotes() {
|
||||
try {
|
||||
return JSON.parse(this.line.internalNote || "[]");
|
||||
} catch (e) {
|
||||
return [{ text: this.line.internalNote, colorIndex: 0 }];
|
||||
}
|
||||
}
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user