fix(pos): escape item data on pos item selector (#55503)

This commit is contained in:
Diptanil Saha
2026-06-01 16:57:35 +05:30
committed by GitHub
parent 65b87ec045
commit 24b28b4d29

View File

@@ -112,17 +112,37 @@ erpnext.PointOfSale.ItemSelector = class {
render_item_list_column_header() { render_item_list_column_header() {
return `<div class="list-column"> return `<div class="list-column">
<div class="column-name">Name</div> <div class="column-name">${__("Name")}</div>
<div class="column-price">Price</div> <div class="column-price">${__("Price")}</div>
<div class="column-uom">UOM</div> <div class="column-uom">${__("UOM")}</div>
<div class="column-qty-available">Quantity Available</div> <div class="column-qty-available">${__("Quantity Available")}</div>
</div>`; </div>`;
} }
get_item_html(item) { get_item_html(item) {
const me = this; const me = this;
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
const { item_image, serial_no, batch_no, barcode, actual_qty, uom, price_list_rate } = item; function sanitize_item_data(item) {
return Object.fromEntries(
Object.entries(item).map(([key, value]) => [
key,
typeof value === "string" ? frappe.utils.escape_html(value) : value,
])
);
}
const sanitize_item = sanitize_item_data(item);
const {
item_code,
stock_uom,
item_name,
item_image,
serial_no,
batch_no,
barcode,
actual_qty,
uom,
price_list_rate,
} = sanitize_item;
const precision = flt(price_list_rate, 2) % 1 != 0 ? 2 : 0; const precision = flt(price_list_rate, 2) % 1 != 0 ? 2 : 0;
let indicator_color; let indicator_color;
let qty_to_display = actual_qty; let qty_to_display = actual_qty;
@@ -149,29 +169,29 @@ erpnext.PointOfSale.ItemSelector = class {
<img <img
onerror="cur_pos.item_selector.handle_broken_image(this)" onerror="cur_pos.item_selector.handle_broken_image(this)"
class="item-img" src="${item_image}" class="item-img" src="${item_image}"
alt="${item.item_name}" alt="${item_name}"
> >
</div>`; </div>`;
} else { } else {
return `<div class="item-qty-pill"> return `<div class="item-qty-pill">
<span class="indicator-pill whitespace-nowrap ${indicator_color}">${qty_to_display}</span> <span class="indicator-pill whitespace-nowrap ${indicator_color}">${qty_to_display}</span>
</div> </div>
<div class="item-display abbr">${frappe.get_abbr(item.item_name)}</div>`; <div class="item-display abbr">${frappe.get_abbr(item_name)}</div>`;
} }
} }
return `<div class="item-wrapper" return `<div class="item-wrapper"
data-item-code="${escape(item.item_code)}" data-serial-no="${escape(serial_no)}" data-item-code="${item_code}" data-serial-no="${serial_no}"
data-batch-no="${escape(batch_no)}" data-uom="${escape(uom)}" data-batch-no="${batch_no}" data-uom="${uom}"
data-rate="${escape(price_list_rate || 0)}" data-rate="${price_list_rate || 0}"
data-stock-uom="${escape(item.stock_uom)}" data-stock-uom="${stock_uom}"
title="${item.item_name}"> title="${item_name}">
${get_item_image_html()} ${get_item_image_html()}
<div class="item-detail"> <div class="item-detail">
<div class="item-name"> <div class="item-name">
${!me.hide_images ? frappe.ellipsis(item.item_name, 18) : item.item_name} ${!me.hide_images ? frappe.ellipsis(item_name, 18) : item_name}
</div> </div>
${ ${
!me.hide_images !me.hide_images
@@ -189,7 +209,7 @@ erpnext.PointOfSale.ItemSelector = class {
} }
handle_broken_image($img) { handle_broken_image($img) {
const item_abbr = $($img).attr("alt"); const item_abbr = frappe.utils.escape_html($($img).attr("alt"));
$($img).parent().replaceWith(`<div class="item-display abbr">${item_abbr}</div>`); $($img).parent().replaceWith(`<div class="item-display abbr">${item_abbr}</div>`);
} }
@@ -244,7 +264,7 @@ erpnext.PointOfSale.ItemSelector = class {
set_item_selector_filter_label(value) { set_item_selector_filter_label(value) {
const $filter_label = this.$component.find(".label"); const $filter_label = this.$component.find(".label");
$filter_label.html(value ? __(value) : __("All Items")); $filter_label.html(value ? frappe.utils.escape_html(__(value)) : __("All Items"));
} }
hide_open_link_btn() { hide_open_link_btn() {
@@ -329,12 +349,12 @@ erpnext.PointOfSale.ItemSelector = class {
this.$component.on("click", ".item-wrapper", function () { this.$component.on("click", ".item-wrapper", function () {
const $item = $(this); const $item = $(this);
const item_code = unescape($item.attr("data-item-code")); const item_code = $item.attr("data-item-code");
let batch_no = unescape($item.attr("data-batch-no")); let batch_no = $item.attr("data-batch-no");
let serial_no = unescape($item.attr("data-serial-no")); let serial_no = $item.attr("data-serial-no");
let uom = unescape($item.attr("data-uom")); let uom = $item.attr("data-uom");
let rate = unescape($item.attr("data-rate")); let rate = $item.attr("data-rate");
let stock_uom = unescape($item.attr("data-stock-uom")); let stock_uom = $item.attr("data-stock-uom");
// escape(undefined) returns "undefined" then unescape returns "undefined" // escape(undefined) returns "undefined" then unescape returns "undefined"
batch_no = batch_no === "undefined" ? undefined : batch_no; batch_no = batch_no === "undefined" ? undefined : batch_no;