diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js
index fa6be1fdd6f..6d96cb92d59 100644
--- a/erpnext/stock/doctype/item/item.js
+++ b/erpnext/stock/doctype/item/item.js
@@ -856,57 +856,107 @@ $.extend(erpnext.item, {
}
frm.toggle_display("prices_html", true);
- const requested_item = frm.doc.name;
- const container = frm.fields_dict["prices_html"].$wrapper;
+ frappe.require("embedded_list.bundle.js", () => erpnext.item.build_prices_list(frm));
+ },
- container.html(
- `
${__("Loading...")}
`
- );
+ build_prices_list: function (frm) {
+ const item_code = frm.doc.name;
+ const container = frm.fields_dict["prices_html"].$wrapper.empty();
- frappe.call({
- method: "erpnext.stock.doctype.item.item.get_item_prices",
- args: { item_code: requested_item },
-
- callback: function (r) {
- if (requested_item !== frm.doc.name) return;
-
- if (!r.message) return;
-
- const { prices, has_more } = r.message;
-
- const html = frappe.render_template("item_prices", {
- prices,
- has_more,
- item_code: requested_item,
- stock_uom: frm.doc.stock_uom,
- });
-
- container.html(html);
-
- container.find(".add-price-btn").on("click", () => {
- const filters = {};
- if (frm.doc.is_sales_item && !frm.doc.is_purchase_item) {
- filters.selling = 1;
- } else if (frm.doc.is_purchase_item && !frm.doc.is_sales_item) {
- filters.buying = 1;
- }
- frappe.new_doc(
- "Item Price",
- { item_code: requested_item, uom: frm.doc.stock_uom },
- (dialog) => {
- if (Object.keys(filters).length) {
- dialog.fields_dict.price_list.get_query = () => ({ filters });
- }
- }
- );
- });
-
- container.find(".price-row").on("click", function (e) {
- if ($(e.target).is("a")) return;
-
- frappe.set_route("Form", "Item Price", $(this).data("name"));
+ const list = new frappe.ui.EmbeddedList({
+ wrapper: $("").appendTo(container),
+ description: __("All active prices for this item across buying and selling price lists."),
+ show_index: true,
+ show_search: false,
+ empty_icon: "tag",
+ empty_message: __("No active item prices found."),
+ add_button: {
+ label: __("Add Price"),
+ action: () => erpnext.item.new_item_price(frm),
+ },
+ on_row_click: (row) => frappe.set_route("Form", "Item Price", row.name),
+ get_data() {
+ return frappe
+ .xcall("erpnext.stock.doctype.item.item.get_item_prices", { item_code })
+ .then((r) => {
+ this._has_more = r.has_more;
+ return r.prices;
+ });
+ },
+ before_render() {
+ this._all_data.forEach((row) => {
+ row.price_type =
+ row.buying && row.selling
+ ? __("Buy & Sell")
+ : row.buying
+ ? __("Buying")
+ : __("Selling");
});
},
+ columns: [
+ { label: __("Price List"), fieldname: "price_list" },
+ {
+ label: __("Type"),
+ type: "badge",
+ fieldname: "price_type",
+ },
+ {
+ label: __("Party"),
+ type: "link",
+ text: (row) => row.customer || row.supplier || "",
+ route: (row) => [
+ "Form",
+ row.customer ? "Customer" : "Supplier",
+ row.customer || row.supplier,
+ ],
+ },
+ {
+ label: __("Rate"),
+ fieldname: "price_list_rate",
+ render: (row) => format_currency(row.price_list_rate, row.currency),
+ },
+ {
+ label: __("UOM"),
+ fieldname: "uom",
+ render: (row) => frappe.utils.escape_html(row.uom || frm.doc.stock_uom || ""),
+ },
+ {
+ label: __("Valid Upto"),
+ fieldname: "valid_upto",
+ render: (row) => (row.valid_upto ? frappe.datetime.str_to_user(row.valid_upto) : ""),
+ },
+ ],
+ });
+
+ list.refresh().then(() => {
+ if (!list._has_more) return;
+ frappe.ui
+ .button({
+ label: __("View All Prices"),
+ variant: "subtle",
+ size: "sm",
+ onclick: () => {
+ frappe.route_options = { item_code };
+ frappe.set_route("List", "Item Price");
+ },
+ })
+ .appendTo(
+ $('').appendTo(container)
+ );
+ });
+ },
+
+ new_item_price: function (frm) {
+ const filters = {};
+ if (frm.doc.is_sales_item && !frm.doc.is_purchase_item) {
+ filters.selling = 1;
+ } else if (frm.doc.is_purchase_item && !frm.doc.is_sales_item) {
+ filters.buying = 1;
+ }
+ frappe.new_doc("Item Price", { item_code: frm.doc.name, uom: frm.doc.stock_uom }, (dialog) => {
+ if (Object.keys(filters).length) {
+ dialog.fields_dict.price_list.get_query = () => ({ filters });
+ }
});
},
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index 0d3b549e5f4..836244d9ada 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -1594,6 +1594,9 @@ def get_child_warehouses(warehouse):
return get_child_warehouses(warehouse)
+ITEM_PRICES_LIMIT = 10
+
+
@frappe.whitelist()
def get_item_prices(item_code: str):
"""Fetch valid item prices for the item prices tab."""
@@ -1621,14 +1624,13 @@ def get_item_prices(item_code: str):
.where(ItemPrice.docstatus != 2)
.where((ItemPrice.valid_upto.isnull()) | (ItemPrice.valid_upto >= today))
.orderby(ItemPrice.price_list)
- .limit(11)
+ .limit(ITEM_PRICES_LIMIT + 1)
.run(as_dict=True)
)
- has_more = len(prices) == 11
return {
- "prices": prices[:10],
- "has_more": has_more,
+ "prices": prices[:ITEM_PRICES_LIMIT],
+ "has_more": len(prices) > ITEM_PRICES_LIMIT,
}
diff --git a/erpnext/stock/doctype/item/item_prices.html b/erpnext/stock/doctype/item/item_prices.html
deleted file mode 100644
index 277afaa4dea..00000000000
--- a/erpnext/stock/doctype/item/item_prices.html
+++ /dev/null
@@ -1,139 +0,0 @@
-
-
-
-
-
-{% if (prices && prices.length) { %}
-
-
-
-
-
- | {{ __("No.") }} |
- {{ __("Price List") }} |
- {{ __("Type") }} |
- {{ __("Party") }} |
- {{ __("Rate") }} |
- {{ __("UOM") }} |
- {{ __("Valid Upto") }} |
-
-
-
- {% for (var i=0; i < prices.length; i++) { var p = prices[i]; %}
-
- | {{ i + 1 }} |
- {{ p.price_list }} |
-
- {% if (p.buying && p.selling) { %}
- {{ __("Buy & Sell") }}
- {% } else if (p.buying) { %}
- {{ __("Buying") }}
- {% } else if (p.selling) { %}
- {{ __("Selling") }}
- {% } %}
- |
-
- {% if (p.customer) { %}
- {{ p.customer }}
- {% } else if (p.supplier) { %}
- {{ p.supplier }}
- {% } %}
- |
- {{ format_currency(p.price_list_rate, p.currency) }} |
- {{ p.uom || stock_uom }} |
- {{ p.valid_upto ? frappe.datetime.str_to_user(p.valid_upto) : "" }} |
-
- {% } %}
-
-
-
-
-
-
-{% } else { %}
-
-
-
{{ __("No active item prices found.") }}
-
-
-
-{% } %}
\ No newline at end of file