From 19f189dab7822959480349d34dfefcf7ef5fbfc3 Mon Sep 17 00:00:00 2001 From: Suherdy Yacob Date: Tue, 2 Jun 2026 13:35:49 +0700 Subject: [PATCH] feat: implement robust note splitting and defensive JSON parsing for POS order lines and customer display --- __manifest__.py | 5 ++ .../app/screens/product_screen/notes_patch.js | 84 +++++++++++++++++++ .../product_screen/portrait_mode_patch.js | 3 +- .../product_screen/portrait_screen.xml | 2 +- .../customer_display_patch.js | 14 ++++ 5 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 static/src/app/screens/product_screen/notes_patch.js create mode 100644 static/src/customer_display/customer_display_patch.js diff --git a/__manifest__.py b/__manifest__.py index 40124fd..e4a570a 100644 --- a/__manifest__.py +++ b/__manifest__.py @@ -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, diff --git a/static/src/app/screens/product_screen/notes_patch.js b/static/src/app/screens/product_screen/notes_patch.js new file mode 100644 index 0000000..754ba6b --- /dev/null +++ b/static/src/app/screens/product_screen/notes_patch.js @@ -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; + } + } +}); diff --git a/static/src/app/screens/product_screen/portrait_mode_patch.js b/static/src/app/screens/product_screen/portrait_mode_patch.js index 853acc9..caa87bf 100644 --- a/static/src/app/screens/product_screen/portrait_mode_patch.js +++ b/static/src/app/screens/product_screen/portrait_mode_patch.js @@ -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, }; diff --git a/static/src/app/screens/product_screen/portrait_screen.xml b/static/src/app/screens/product_screen/portrait_screen.xml index 8d1336d..5d545b5 100644 --- a/static/src/app/screens/product_screen/portrait_screen.xml +++ b/static/src/app/screens/product_screen/portrait_screen.xml @@ -43,7 +43,7 @@
- +