From 067c23f20e5541eacb37a188be379121c2e7ddfb Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 27 May 2026 11:45:23 +0530 Subject: [PATCH 01/36] fix: material transfer in transit issue (backport #55320) (#55324) Co-authored-by: Rohit Waghchaure --- erpnext/stock/doctype/stock_entry/stock_entry.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index f0d7e10ad73..e6d6dab7426 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -3132,12 +3132,12 @@ class StockEntry(StockController): args = { "source_dt": "Stock Entry Detail", "target_field": "transferred_qty", - "target_ref_field": "qty", + "target_ref_field": "transfer_qty", "target_dt": "Stock Entry Detail", "join_field": "ste_detail", "target_parent_dt": "Stock Entry", "target_parent_field": "per_transferred", - "source_field": "qty", + "source_field": "transfer_qty", "percent_join_field": "against_stock_entry", } From 93dcba40ec3819a175c9c088d885e37159f848d8 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Mon, 25 May 2026 11:40:25 +0530 Subject: [PATCH 02/36] fix: stock reco for legacy serial nos (cherry picked from commit 9d5fd11bcd80a1de1c3282de06845648736cfebb) --- erpnext/stock/stock_ledger.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index a50bc4f8325..a1dc9d13a4e 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -887,7 +887,7 @@ class update_entries_after: # Only run in reposting self.get_serialized_values(sle) self.wh_data.qty_after_transaction += flt(sle.actual_qty) - if sle.voucher_type == "Stock Reconciliation" and not sle.batch_no: + if sle.voucher_type == "Stock Reconciliation" and not sle.batch_no and has_correct_data(sle): self.wh_data.qty_after_transaction = sle.qty_after_transaction self.wh_data.stock_value = flt(self.wh_data.qty_after_transaction) * flt( @@ -2517,3 +2517,28 @@ def get_incoming_rate_for_serial_and_batch(item_code, row, sn_obj): @frappe.request_cache def is_repack_entry(stock_entry_id): return frappe.get_cached_value("Stock Entry", stock_entry_id, "purpose") == "Repack" + + +def has_correct_data(sle): + previous_sle = get_previous_sle( + { + "item_code": sle.item_code, + "warehouse": sle.warehouse, + "posting_date": sle.posting_date, + "posting_time": sle.posting_time, + "creation": sle.creation, + "sle": sle.name, + } + ) + + if not previous_sle: + return True + + previous_qty = previous_sle.get("qty_after_transaction") or 0 + if previous_qty and not frappe.db.get_value( + "Stock Ledger Entry", + {"voucher_detail_no": sle.voucher_detail_no, "is_cancelled": 0, "actual_qty": ("<", 0)}, + ): + return False + + return True From 41bf2f32fd223b1074988bea0a5dcecfaee651d7 Mon Sep 17 00:00:00 2001 From: Pandiyan P Date: Wed, 27 May 2026 18:39:59 +0530 Subject: [PATCH 03/36] fix(manufacturing): allow to edit batch size while creating a work order (#55332) --- .../doctype/bom_operation/bom_operation.json | 11 +++++++---- .../doctype/bom_operation/bom_operation.py | 2 +- .../manufacturing/doctype/work_order/work_order.py | 9 ++++++--- .../work_order_operation/work_order_operation.json | 8 +++++--- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/erpnext/manufacturing/doctype/bom_operation/bom_operation.json b/erpnext/manufacturing/doctype/bom_operation/bom_operation.json index a40d0d714ed..5ba6157d009 100644 --- a/erpnext/manufacturing/doctype/bom_operation/bom_operation.json +++ b/erpnext/manufacturing/doctype/bom_operation/bom_operation.json @@ -126,11 +126,13 @@ "label": "Image" }, { + "default": "1", "fetch_from": "operation.batch_size", "fetch_if_empty": 1, "fieldname": "batch_size", - "fieldtype": "Int", - "label": "Batch Size" + "fieldtype": "Float", + "label": "Batch Size", + "non_negative": 1 }, { "depends_on": "eval:doc.parenttype == \"Routing\" || !parent.routing", @@ -196,13 +198,14 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2026-02-17 15:33:28.495850", + "modified": "2026-05-27 12:09:44.797434", "modified_by": "Administrator", "module": "Manufacturing", "name": "BOM Operation", "owner": "Administrator", "permissions": [], + "row_format": "Dynamic", "sort_field": "modified", "sort_order": "DESC", "states": [] -} +} \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/bom_operation/bom_operation.py b/erpnext/manufacturing/doctype/bom_operation/bom_operation.py index 66ac02891b9..02c4acc5881 100644 --- a/erpnext/manufacturing/doctype/bom_operation/bom_operation.py +++ b/erpnext/manufacturing/doctype/bom_operation/bom_operation.py @@ -17,7 +17,7 @@ class BOMOperation(Document): base_cost_per_unit: DF.Float base_hour_rate: DF.Currency base_operating_cost: DF.Currency - batch_size: DF.Int + batch_size: DF.Float cost_per_unit: DF.Float description: DF.TextEditor | None fixed_time: DF.Check diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index 0584320726f..5d8382e7ebd 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -158,7 +158,7 @@ class WorkOrder(Document): self.calculate_operating_cost() self.validate_qty() self.validate_transfer_against() - self.validate_operation_time() + self.validate_operations() self.status = self.get_status() self.validate_workstation_type() self.reset_use_multi_level_bom() @@ -1120,9 +1120,12 @@ class WorkOrder(Document): title=_("Missing value"), ) - def validate_operation_time(self): + def validate_operations(self): for d in self.operations: - if not d.time_in_mins > 0: + if not d.batch_size or d.batch_size <= 0: + d.batch_size = 1 + + if d.time_in_mins <= 0: frappe.throw(_("Operation Time must be greater than 0 for Operation {0}").format(d.operation)) def update_required_items(self): diff --git a/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.json b/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.json index 38b325b73ab..9c895251a51 100644 --- a/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.json +++ b/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.json @@ -185,10 +185,11 @@ "read_only": 1 }, { + "default": "1", "fieldname": "batch_size", "fieldtype": "Float", "label": "Batch Size", - "read_only": 1 + "non_negative": 1 }, { "fieldname": "sequence_id", @@ -225,14 +226,15 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2025-05-15 15:10:06.885440", + "modified": "2026-05-27 12:56:37.240431", "modified_by": "Administrator", "module": "Manufacturing", "name": "Work Order Operation", "owner": "Administrator", "permissions": [], + "row_format": "Dynamic", "sort_field": "modified", "sort_order": "DESC", "states": [], "track_changes": 1 -} +} \ No newline at end of file From 264433b23d61ffa41a75adcc9c554941e1de4e29 Mon Sep 17 00:00:00 2001 From: khushi8112 Date: Thu, 21 May 2026 15:05:44 +0530 Subject: [PATCH 04/36] fix: use get_query instead of get_all for data fetching (cherry picked from commit 1fd99337b343ef394926d6baedffa9da3b86019a) --- .../report/sales_analytics/sales_analytics.py | 74 ++++++++++++------- 1 file changed, 49 insertions(+), 25 deletions(-) diff --git a/erpnext/selling/report/sales_analytics/sales_analytics.py b/erpnext/selling/report/sales_analytics/sales_analytics.py index d4f7ad42b43..52372659981 100644 --- a/erpnext/selling/report/sales_analytics/sales_analytics.py +++ b/erpnext/selling/report/sales_analytics/sales_analytics.py @@ -138,12 +138,30 @@ class Analytics: self.get_sales_transactions_based_on_project() self.get_rows() + def _get_permitted_parent_names(self): + return frappe.qb.get_query( + table=self.filters.doc_type, + fields=["name"], + filters={ + "docstatus": 1, + "company": ["in", self.filters.company], + self.date_field: ("between", [self.filters.from_date, self.filters.to_date]), + }, + ignore_permissions=False, + ).run(pluck="name") + def get_sales_transactions_based_on_order_type(self): if self.filters["value_quantity"] == "Value": value_field = "base_net_total" else: value_field = "total_qty" + permitted_names = self._get_permitted_parent_names() + if not permitted_names: + self.entries = [] + self.get_teams() + return + doctype = DocType(self.filters.doc_type) self.entries = ( @@ -153,12 +171,7 @@ class Analytics: doctype[self.date_field], doctype[value_field].as_("value_field"), ) - .where( - (doctype.docstatus == 1) - & (doctype.company.isin(self.filters.company)) - & (doctype[self.date_field].between(self.filters.from_date, self.filters.to_date)) - & (IfNull(doctype.order_type, "") != "") - ) + .where((doctype.name.isin(permitted_names)) & (IfNull(doctype.order_type, "") != "")) .orderby(doctype.order_type) ).run(as_dict=True) @@ -186,9 +199,12 @@ class Analytics: if self.filters.doc_type in ["Sales Invoice", "Purchase Invoice", "Payment Entry"]: filters.update({"is_opening": "No"}) - self.entries = frappe.get_all( - self.filters.doc_type, fields=[entity, entity_name, value_field, self.date_field], filters=filters - ) + self.entries = frappe.qb.get_query( + table=self.filters.doc_type, + fields=[entity, entity_name, value_field, self.date_field], + filters=filters, + ignore_permissions=False, + ).run(as_dict=True) self.entity_names = {} for d in self.entries: @@ -200,6 +216,12 @@ class Analytics: else: value_field = "stock_qty" + permitted_names = self._get_permitted_parent_names() + if not permitted_names: + self.entries = [] + self.entity_names = {} + return + doctype = DocType(self.filters.doc_type) doctype_item = DocType(f"{self.filters.doc_type} Item") @@ -214,11 +236,7 @@ class Analytics: doctype_item[value_field].as_("value_field"), doctype[self.date_field], ) - .where( - (doctype_item.docstatus == 1) - & (doctype.company.isin(self.filters.company)) - & (doctype[self.date_field].between(self.filters.from_date, self.filters.to_date)) - ) + .where((doctype_item.docstatus == 1) & (doctype.name.isin(permitted_names))) ).run(as_dict=True) self.entity_names = {} @@ -248,11 +266,12 @@ class Analytics: if self.filters.doc_type in ["Sales Invoice", "Purchase Invoice", "Payment Entry"]: filters.update({"is_opening": "No"}) - self.entries = frappe.get_all( - self.filters.doc_type, + self.entries = frappe.qb.get_query( + table=self.filters.doc_type, fields=[entity_field, value_field, self.date_field], filters=filters, - ) + ignore_permissions=False, + ).run(as_dict=True) self.get_groups() def get_sales_transactions_based_on_item_group(self): @@ -261,6 +280,12 @@ class Analytics: else: value_field = "qty" + permitted_names = self._get_permitted_parent_names() + if not permitted_names: + self.entries = [] + self.get_groups() + return + doctype = DocType(self.filters.doc_type) doctype_item = DocType(f"{self.filters.doc_type} Item") @@ -273,11 +298,7 @@ class Analytics: doctype_item[value_field].as_("value_field"), doctype[self.date_field], ) - .where( - (doctype_item.docstatus == 1) - & (doctype.company.isin(self.filters.company)) - & (doctype[self.date_field].between(self.filters.from_date, self.filters.to_date)) - ) + .where((doctype_item.docstatus == 1) & (doctype.name.isin(permitted_names))) ).run(as_dict=True) self.get_groups() @@ -300,9 +321,12 @@ class Analytics: if self.filters.doc_type in ["Sales Invoice", "Purchase Invoice", "Payment Entry"]: filters.update({"is_opening": "No"}) - self.entries = frappe.get_all( - self.filters.doc_type, fields=[entity, value_field, self.date_field], filters=filters - ) + self.entries = frappe.qb.get_query( + table=self.filters.doc_type, + fields=[entity, value_field, self.date_field], + filters=filters, + ignore_permissions=False, + ).run(as_dict=True) def get_rows(self): self.data = [] From 4669ff295f6beab550fd05980bc6927297ee36a7 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 28 May 2026 16:01:36 +0530 Subject: [PATCH 05/36] fix: new bom version should not recalculate operations through routing (backport #55370) (#55371) Co-authored-by: Mihir Kandoi fix: new bom version should not recalculate operations through routing (#55370) --- erpnext/manufacturing/doctype/bom/bom.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js index 3895f0bf17a..06b329e169e 100644 --- a/erpnext/manufacturing/doctype/bom/bom.js +++ b/erpnext/manufacturing/doctype/bom/bom.js @@ -438,7 +438,7 @@ frappe.ui.form.on("BOM", { }, routing(frm) { - if (frm.doc.routing) { + if (frm.doc.routing && frm.doc.with_operations && !frm.doc.operations) { frappe.call({ doc: frm.doc, method: "get_routing", From ad6e3a45d224b420a7b3ff4ed20c72cb40783e7f Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 28 May 2026 22:40:11 +0530 Subject: [PATCH 06/36] fix(stock): get_actual_qty during cancellations (backport #55388) (#55391) Co-authored-by: archielister fix(stock): get_actual_qty during cancellations (#55388) --- erpnext/stock/doctype/bin/bin.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/doctype/bin/bin.py b/erpnext/stock/doctype/bin/bin.py index 79e9776b91c..2af1f645494 100644 --- a/erpnext/stock/doctype/bin/bin.py +++ b/erpnext/stock/doctype/bin/bin.py @@ -263,8 +263,9 @@ def update_qty(bin_name, args): # actual qty is already updated by processing current voucher actual_qty = bin_details.actual_qty or 0.0 - # actual qty is not up to date in case of backdated transaction - if future_sle_exists(args): + # actual qty is not up to date in case of backdated transactions + # or when cancellations are the most recent SLE + if future_sle_exists(args) or args.get("is_cancelled"): actual_qty = get_actual_qty(args.get("item_code"), args.get("warehouse")) ordered_qty = flt(bin_details.ordered_qty) + flt(args.get("ordered_qty")) From 5c392d61236176c367544dc336468b82b38eff5b Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Fri, 29 May 2026 19:17:34 +0530 Subject: [PATCH 07/36] fix: billing address does not belongs to the company error (cherry picked from commit 9df07b367a29eceae700614d5a98485cf48df080) --- erpnext/public/js/controllers/buying.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js index 01d458d6b16..ff7218d78ae 100644 --- a/erpnext/public/js/controllers/buying.js +++ b/erpnext/public/js/controllers/buying.js @@ -176,14 +176,9 @@ erpnext.buying = { callback: (r) => { if (!r.message) return; - if (!this.frm.doc.billing_address) { - this.frm.set_value("billing_address", r.message.primary_address || ""); - } + this.frm.set_value("billing_address", r.message.primary_address || ""); - if ( - frappe.meta.has_field(this.frm.doc.doctype, "shipping_address") && - !this.frm.doc.shipping_address - ) { + if (frappe.meta.has_field(this.frm.doc.doctype, "shipping_address")) { this.frm.set_value("shipping_address", r.message.shipping_address || ""); } }, From a2d924c48f4192eccba4be010b04dd6f68b3ea44 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Sat, 30 May 2026 14:20:40 +0000 Subject: [PATCH 08/36] fix(quotation): made customer contact column visible (backport #55433) (#55434) * fix(quotation): made customer contact column visible (#55433) (cherry picked from commit 9758eb868d2f2ad4b03f769e53ccd8908a785871) # Conflicts: # erpnext/selling/doctype/quotation/quotation.json * chore: resolved conflicts --------- Co-authored-by: Diptanil Saha --- erpnext/selling/doctype/quotation/quotation.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/erpnext/selling/doctype/quotation/quotation.json b/erpnext/selling/doctype/quotation/quotation.json index ae5b980bb9b..58f18dd731a 100644 --- a/erpnext/selling/doctype/quotation/quotation.json +++ b/erpnext/selling/doctype/quotation/quotation.json @@ -308,7 +308,6 @@ "read_only": 1 }, { - "depends_on": "eval:(doc.quotation_to=='Customer' && doc.party_name)", "fieldname": "col_break98", "fieldtype": "Column Break", "width": "50%" @@ -1108,7 +1107,7 @@ "idx": 82, "is_submittable": 1, "links": [], - "modified": "2025-07-31 17:23:48.875382", + "modified": "2026-05-30 17:40:02.667637", "modified_by": "Administrator", "module": "Selling", "name": "Quotation", From 2a52ea6850e84e45338456d93c226c8085962746 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Sat, 30 May 2026 22:00:19 +0530 Subject: [PATCH 09/36] fix(regional): Japanese CT Rate (backport #54998) (#55437) Co-authored-by: mh35 fix(regional): Japanese CT Rate (#54998) --- erpnext/setup/setup_wizard/data/country_wise_tax.json | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/erpnext/setup/setup_wizard/data/country_wise_tax.json b/erpnext/setup/setup_wizard/data/country_wise_tax.json index 3259a2323b7..18c513b3c2b 100644 --- a/erpnext/setup/setup_wizard/data/country_wise_tax.json +++ b/erpnext/setup/setup_wizard/data/country_wise_tax.json @@ -4115,9 +4115,14 @@ }, "Japan": { - "Japan Tax": { - "account_name": "CT", - "tax_rate": 5.00 + "Japan Tax 10%": { + "account_name": "CT 10%", + "tax_rate": 10.00, + "default": 1 + }, + "Japan Tax 8%": { + "account_name": "CT 8%", + "tax_rate": 8.00 } }, From cad14ac3e6ec4a294e032eb3e3bdef499fabe495 Mon Sep 17 00:00:00 2001 From: Raffael Meyer <14891507+barredterra@users.noreply.github.com> Date: Sat, 30 May 2026 21:09:45 +0200 Subject: [PATCH 10/36] chore: mark as out of beta (backport #55439) (#55440) --- .../bank_statement_import.json | 8 +++++--- erpnext/accounts/doctype/dunning/dunning.json | 6 +++--- .../doctype/dunning_type/dunning_type.json | 5 +++-- .../opening_invoice_creation_tool.json | 15 +++++++++------ .../opening_invoice_creation_tool.py | 1 + erpnext/portal/doctype/homepage/homepage.json | 4 ++-- 6 files changed, 23 insertions(+), 16 deletions(-) diff --git a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.json b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.json index 3210457c645..b57b257cbef 100644 --- a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.json +++ b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.json @@ -1,7 +1,6 @@ { "actions": [], "autoname": "format:Bank Statement Import on {creation}", - "beta": 1, "creation": "2019-08-04 14:16:08.318714", "doctype": "DocType", "editable_grid": 1, @@ -211,10 +210,11 @@ ], "hide_toolbar": 1, "links": [], - "modified": "2024-06-25 17:32:07.658250", + "modified": "2026-05-30 20:51:10.353723", "modified_by": "Administrator", "module": "Accounts", "name": "Bank Statement Import", + "naming_rule": "Expression (old style)", "owner": "Administrator", "permissions": [ { @@ -230,7 +230,9 @@ "write": 1 } ], + "row_format": "Dynamic", "sort_field": "modified", "sort_order": "DESC", + "states": [], "track_changes": 1 -} +} \ No newline at end of file diff --git a/erpnext/accounts/doctype/dunning/dunning.json b/erpnext/accounts/doctype/dunning/dunning.json index 496097417ba..948fb84cf25 100644 --- a/erpnext/accounts/doctype/dunning/dunning.json +++ b/erpnext/accounts/doctype/dunning/dunning.json @@ -2,7 +2,6 @@ "actions": [], "allow_events_in_timeline": 1, "autoname": "naming_series:", - "beta": 1, "creation": "2019-07-05 16:34:31.013238", "doctype": "DocType", "engine": "InnoDB", @@ -400,7 +399,7 @@ ], "is_submittable": 1, "links": [], - "modified": "2024-11-26 13:46:07.760867", + "modified": "2026-05-30 20:40:30.851842", "modified_by": "Administrator", "module": "Accounts", "name": "Dunning", @@ -449,9 +448,10 @@ "write": 1 } ], + "row_format": "Dynamic", "sort_field": "modified", "sort_order": "ASC", "states": [], "title_field": "customer_name", "track_changes": 1 -} +} \ No newline at end of file diff --git a/erpnext/accounts/doctype/dunning_type/dunning_type.json b/erpnext/accounts/doctype/dunning_type/dunning_type.json index 5e39769735e..857a5a1f31d 100644 --- a/erpnext/accounts/doctype/dunning_type/dunning_type.json +++ b/erpnext/accounts/doctype/dunning_type/dunning_type.json @@ -1,7 +1,6 @@ { "actions": [], "allow_rename": 1, - "beta": 1, "creation": "2019-12-04 04:59:08.003664", "doctype": "DocType", "editable_grid": 1, @@ -107,7 +106,7 @@ "link_fieldname": "dunning_type" } ], - "modified": "2021-11-13 00:25:35.659283", + "modified": "2026-05-30 20:40:09.952533", "modified_by": "Administrator", "module": "Accounts", "name": "Dunning Type", @@ -151,7 +150,9 @@ "write": 1 } ], + "row_format": "Dynamic", "sort_field": "modified", "sort_order": "DESC", + "states": [], "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.json b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.json index 5a43e1dbf3d..e39e4041e7a 100644 --- a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.json +++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.json @@ -1,6 +1,6 @@ { + "actions": [], "allow_copy": 1, - "beta": 1, "creation": "2017-08-29 02:22:54.947711", "doctype": "DocType", "editable_grid": 1, @@ -64,10 +64,10 @@ "options": "Cost Center" }, { - "fieldname": "project", - "fieldtype": "Link", - "label": "Project", - "options": "Project" + "fieldname": "project", + "fieldtype": "Link", + "label": "Project", + "options": "Project" }, { "collapsible": 1, @@ -82,7 +82,8 @@ ], "hide_toolbar": 1, "issingle": 1, - "modified": "2022-01-04 15:25:06.053187", + "links": [], + "modified": "2026-05-30 20:43:36.282738", "modified_by": "Administrator", "module": "Accounts", "name": "Opening Invoice Creation Tool", @@ -99,7 +100,9 @@ } ], "quick_entry": 1, + "row_format": "Dynamic", "sort_field": "modified", "sort_order": "DESC", + "states": [], "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py index 4f133a2fb7d..4003f533ded 100644 --- a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py +++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py @@ -31,6 +31,7 @@ class OpeningInvoiceCreationTool(Document): create_missing_party: DF.Check invoice_type: DF.Literal["Sales", "Purchase"] invoices: DF.Table[OpeningInvoiceCreationToolItem] + project: DF.Link | None # end: auto-generated types def onload(self): diff --git a/erpnext/portal/doctype/homepage/homepage.json b/erpnext/portal/doctype/homepage/homepage.json index 2b891f72680..8c19157d74a 100644 --- a/erpnext/portal/doctype/homepage/homepage.json +++ b/erpnext/portal/doctype/homepage/homepage.json @@ -1,6 +1,5 @@ { "actions": [], - "beta": 1, "creation": "2016-04-22 05:27:52.109319", "doctype": "DocType", "document_type": "Setup", @@ -87,7 +86,7 @@ ], "issingle": 1, "links": [], - "modified": "2022-12-19 21:10:29.127277", + "modified": "2026-05-30 20:51:04.415019", "modified_by": "Administrator", "module": "Portal", "name": "Homepage", @@ -114,6 +113,7 @@ "write": 1 } ], + "row_format": "Dynamic", "sort_field": "modified", "sort_order": "DESC", "states": [], From 715ca39abca050b5c0132984207ca2aa6e24f4f0 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Sun, 31 May 2026 09:40:26 +0000 Subject: [PATCH 11/36] refactor(pos_profile): migrating raw sql to qb in set_defaults (backport #55447) (#55449) Co-authored-by: Diptanil Saha --- .../accounts/doctype/pos_profile/pos_profile.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/erpnext/accounts/doctype/pos_profile/pos_profile.py b/erpnext/accounts/doctype/pos_profile/pos_profile.py index 882b8c58eee..82c3103a039 100644 --- a/erpnext/accounts/doctype/pos_profile/pos_profile.py +++ b/erpnext/accounts/doctype/pos_profile/pos_profile.py @@ -202,15 +202,14 @@ class POSProfile(Document): def set_defaults(self, include_current_pos=True): frappe.defaults.clear_default("is_pos") - if not include_current_pos: - condition = " where pfu.name != '%s' and pfu.default = 1 " % self.name.replace("'", "'") - else: - condition = " where pfu.default = 1 " + pfu = frappe.qb.DocType("POS Profile User") - pos_view_users = frappe.db.sql_list( - f"""select pfu.user - from `tabPOS Profile User` as pfu {condition}""" - ) + query = frappe.qb.from_(pfu).select(pfu.user).where(pfu.default == 1) + + if not include_current_pos: + query = query.where(pfu.name != self.name) + + pos_view_users = query.run(as_list=1, pluck=True) for user in pos_view_users: if user: From 2a12ae1afe368c122a63d56a5153271f23fa311f Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Sun, 31 May 2026 16:06:25 +0000 Subject: [PATCH 12/36] fix(book_appointment): when scheduling is disabled, block API endpoints (backport #55455) (#55456) Co-authored-by: Diptanil Saha fix(book_appointment): when scheduling is disabled, block API endpoints (#55455) --- erpnext/www/book_appointment/index.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/erpnext/www/book_appointment/index.py b/erpnext/www/book_appointment/index.py index f50c207ab98..7cdf95c03b5 100644 --- a/erpnext/www/book_appointment/index.py +++ b/erpnext/www/book_appointment/index.py @@ -12,10 +12,13 @@ no_cache = 1 def get_context(context): - is_enabled = frappe.db.get_single_value("Appointment Booking Settings", "enable_scheduling") - if is_enabled: - return context - else: + handle_appointment_booking_disabled() + + return context + + +def handle_appointment_booking_disabled(): + if not frappe.get_single_value("Appointment Booking Settings", "enable_scheduling"): frappe.redirect_to_message( _("Appointment Scheduling Disabled"), _("Appointment Scheduling has been disabled for this site"), @@ -27,9 +30,9 @@ def get_context(context): @frappe.whitelist(allow_guest=True) def get_appointment_settings(): - settings = frappe.get_cached_value( + handle_appointment_booking_disabled() + settings = frappe.get_single_value( "Appointment Booking Settings", - None, ["advance_booking_days", "appointment_duration", "success_redirect_url"], as_dict=True, ) @@ -38,6 +41,7 @@ def get_appointment_settings(): @frappe.whitelist(allow_guest=True) def get_timezones(): + handle_appointment_booking_disabled() import pytz return pytz.all_timezones @@ -46,6 +50,7 @@ def get_timezones(): @frappe.whitelist(allow_guest=True) def get_appointment_slots(date, timezone): # Convert query to local timezones + handle_appointment_booking_disabled() format_string = "%Y-%m-%d %H:%M:%S" query_start_time = datetime.datetime.strptime(date + " 00:00:00", format_string) query_end_time = datetime.datetime.strptime(date + " 23:59:59", format_string) @@ -54,7 +59,11 @@ def get_appointment_slots(date, timezone): now = convert_to_guest_timezone(timezone, datetime.datetime.now()) # Database queries - settings = frappe.get_doc("Appointment Booking Settings") + settings = frappe.get_single_value( + "Appointment Booking Settings", + ["holiday_list", "appointment_duration", "number_of_agents", "availability_of_slots"], + as_dict=True, + ) holiday_list = frappe.get_doc("Holiday List", settings.holiday_list) timeslots = get_available_slots_between(query_start_time, query_end_time, settings) @@ -95,6 +104,7 @@ def get_available_slots_between(query_start_time, query_end_time, settings): @frappe.whitelist(allow_guest=True) def create_appointment(date, time, tz, contact): + handle_appointment_booking_disabled() format_string = "%Y-%m-%d %H:%M:%S" scheduled_time = datetime.datetime.strptime(date + " " + time, format_string) # Strip tzinfo from datetime objects since it's handled by the doctype From 2a805e090cea172172e601020b537c0c5774fff0 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Sun, 31 May 2026 22:07:01 +0530 Subject: [PATCH 13/36] refactor: task_info portal pages (backport #55448) (#55453) Co-authored-by: Diptanil Saha --- erpnext/templates/pages/task_info.html | 116 +++++-------------------- erpnext/templates/pages/task_info.py | 7 +- 2 files changed, 27 insertions(+), 96 deletions(-) diff --git a/erpnext/templates/pages/task_info.html b/erpnext/templates/pages/task_info.html index fe4d304a398..4a98b425e73 100644 --- a/erpnext/templates/pages/task_info.html +++ b/erpnext/templates/pages/task_info.html @@ -1,11 +1,11 @@ {% extends "templates/web.html" %} -{% block title %} {{ doc.name }} {% endblock %} +{% block title %} {{ doc.name|e }} {% endblock %} {% block breadcrumbs %} -