From bd3a1328687e6cd18580caf898dffac5baa5a4f4 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 14 Oct 2025 14:42:08 +0000 Subject: [PATCH 01/13] feat: set options for IBAN fields (backport #49377) (#49413) Co-authored-by: barredterra <14891507+barredterra@users.noreply.github.com> --- .../doctype/bank_account/bank_account.json | 7 +++- .../doctype/bank_account/bank_account.py | 34 +++------------- .../doctype/bank_account/test_bank_account.py | 39 +------------------ .../bank_guarantee/bank_guarantee.json | 3 +- .../bank_transaction/bank_transaction.json | 5 ++- .../payment_request/payment_request.json | 9 +++-- erpnext/setup/doctype/employee/employee.json | 8 ++-- 7 files changed, 27 insertions(+), 78 deletions(-) diff --git a/erpnext/accounts/doctype/bank_account/bank_account.json b/erpnext/accounts/doctype/bank_account/bank_account.json index 962551b2417..4946dc168ba 100644 --- a/erpnext/accounts/doctype/bank_account/bank_account.json +++ b/erpnext/accounts/doctype/bank_account/bank_account.json @@ -132,7 +132,8 @@ "fieldtype": "Data", "in_list_view": 1, "label": "IBAN", - "length": 30 + "length": 34, + "options": "IBAN" }, { "fieldname": "column_break_12", @@ -208,6 +209,7 @@ "label": "Disabled" } ], + "grid_page_length": 50, "links": [ { "group": "Transactions", @@ -250,7 +252,7 @@ "link_fieldname": "default_bank_account" } ], - "modified": "2024-10-30 09:41:14.113414", + "modified": "2025-08-29 12:32:01.081687", "modified_by": "Administrator", "module": "Accounts", "name": "Bank Account", @@ -282,6 +284,7 @@ "write": 1 } ], + "row_format": "Dynamic", "search_fields": "bank,account", "sort_field": "modified", "sort_order": "DESC", diff --git a/erpnext/accounts/doctype/bank_account/bank_account.py b/erpnext/accounts/doctype/bank_account/bank_account.py index 5a728eb415b..5a874701a39 100644 --- a/erpnext/accounts/doctype/bank_account/bank_account.py +++ b/erpnext/accounts/doctype/bank_account/bank_account.py @@ -9,7 +9,8 @@ from frappe.contacts.address_and_contact import ( load_address_and_contact, ) from frappe.model.document import Document -from frappe.utils import comma_and, get_link_to_form +from frappe.utils import comma_and, get_link_to_form, validate_iban +from frappe.utils.deprecations import deprecated class BankAccount(Document): @@ -52,7 +53,6 @@ class BankAccount(Document): def validate(self): self.validate_company() - self.validate_iban() self.validate_account() self.update_default_bank_account() @@ -72,34 +72,10 @@ class BankAccount(Document): if self.is_company_account and not self.company: frappe.throw(_("Company is manadatory for company account")) + @deprecated def validate_iban(self): - """ - Algorithm: https://en.wikipedia.org/wiki/International_Bank_Account_Number#Validating_the_IBAN - """ - # IBAN field is optional - if not self.iban: - return - - def encode_char(c): - # Position in the alphabet (A=1, B=2, ...) plus nine - return str(9 + ord(c) - 64) - - # remove whitespaces, upper case to get the right number from ord() - iban = "".join(self.iban.split(" ")).upper() - - # Move country code and checksum from the start to the end - flipped = iban[4:] + iban[:4] - - # Encode characters as numbers - encoded = [encode_char(c) if ord(c) >= 65 and ord(c) <= 90 else c for c in flipped] - - try: - to_check = int("".join(encoded)) - except ValueError: - frappe.throw(_("IBAN is not valid")) - - if to_check % 97 != 1: - frappe.throw(_("IBAN is not valid")) + """Kept for backward compatibility, will be removed in v16.""" + validate_iban(self.iban, throw=True) def update_default_bank_account(self): if self.is_default and not self.disabled: diff --git a/erpnext/accounts/doctype/bank_account/test_bank_account.py b/erpnext/accounts/doctype/bank_account/test_bank_account.py index 0ec388d9e5c..d285b89d10c 100644 --- a/erpnext/accounts/doctype/bank_account/test_bank_account.py +++ b/erpnext/accounts/doctype/bank_account/test_bank_account.py @@ -3,45 +3,8 @@ import unittest -import frappe -from frappe import ValidationError - # test_records = frappe.get_test_records('Bank Account') class TestBankAccount(unittest.TestCase): - def test_validate_iban(self): - valid_ibans = [ - "GB82 WEST 1234 5698 7654 32", - "DE91 1000 0000 0123 4567 89", - "FR76 3000 6000 0112 3456 7890 189", - ] - - invalid_ibans = [ - # wrong checksum (3rd place) - "GB72 WEST 1234 5698 7654 32", - "DE81 1000 0000 0123 4567 89", - "FR66 3000 6000 0112 3456 7890 189", - ] - - bank_account = frappe.get_doc({"doctype": "Bank Account"}) - - try: - bank_account.validate_iban() - except AttributeError: - msg = "BankAccount.validate_iban() failed for empty IBAN" - self.fail(msg=msg) - - for iban in valid_ibans: - bank_account.iban = iban - try: - bank_account.validate_iban() - except ValidationError: - msg = f"BankAccount.validate_iban() failed for valid IBAN {iban}" - self.fail(msg=msg) - - for not_iban in invalid_ibans: - bank_account.iban = not_iban - msg = f"BankAccount.validate_iban() accepted invalid IBAN {not_iban}" - with self.assertRaises(ValidationError, msg=msg): - bank_account.validate_iban() + pass diff --git a/erpnext/accounts/doctype/bank_guarantee/bank_guarantee.json b/erpnext/accounts/doctype/bank_guarantee/bank_guarantee.json index dc5413e973c..c255ce7ba8f 100644 --- a/erpnext/accounts/doctype/bank_guarantee/bank_guarantee.json +++ b/erpnext/accounts/doctype/bank_guarantee/bank_guarantee.json @@ -146,6 +146,7 @@ "fieldname": "iban", "fieldtype": "Data", "label": "IBAN", + "options": "IBAN", "read_only": 1 }, { @@ -216,7 +217,7 @@ ], "is_submittable": 1, "links": [], - "modified": "2025-09-25 23:44:12.473583", + "modified": "2025-09-26 00:38:17.584694", "modified_by": "Administrator", "module": "Accounts", "name": "Bank Guarantee", diff --git a/erpnext/accounts/doctype/bank_transaction/bank_transaction.json b/erpnext/accounts/doctype/bank_transaction/bank_transaction.json index 37fbd261898..02ff1dbf3e9 100644 --- a/erpnext/accounts/doctype/bank_transaction/bank_transaction.json +++ b/erpnext/accounts/doctype/bank_transaction/bank_transaction.json @@ -223,7 +223,8 @@ { "fieldname": "bank_party_iban", "fieldtype": "Data", - "label": "Party IBAN (Bank Statement)" + "label": "Party IBAN (Bank Statement)", + "options": "IBAN" }, { "fieldname": "bank_party_account_number", @@ -238,7 +239,7 @@ "grid_page_length": 50, "is_submittable": 1, "links": [], - "modified": "2025-09-26 17:06:29.207673", + "modified": "2025-10-14 11:53:45.908169", "modified_by": "Administrator", "module": "Accounts", "name": "Bank Transaction", diff --git a/erpnext/accounts/doctype/payment_request/payment_request.json b/erpnext/accounts/doctype/payment_request/payment_request.json index 5a19a080484..6853e9ca1fb 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.json +++ b/erpnext/accounts/doctype/payment_request/payment_request.json @@ -226,7 +226,8 @@ "fetch_from": "bank_account.iban", "fieldname": "iban", "fieldtype": "Read Only", - "label": "IBAN" + "label": "IBAN", + "options": "IBAN" }, { "fetch_from": "bank_account.branch_code", @@ -443,11 +444,12 @@ "label": "Phone Number" } ], + "grid_page_length": 50, "in_create": 1, "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2024-12-27 21:29:10.361894", + "modified": "2025-08-29 11:52:48.555415", "modified_by": "Administrator", "module": "Accounts", "name": "Payment Request", @@ -482,8 +484,9 @@ "write": 1 } ], + "row_format": "Dynamic", "show_preview_popup": 1, "sort_field": "modified", "sort_order": "DESC", "states": [] -} \ No newline at end of file +} diff --git a/erpnext/setup/doctype/employee/employee.json b/erpnext/setup/doctype/employee/employee.json index 1c80fd84965..cc23b44bff0 100644 --- a/erpnext/setup/doctype/employee/employee.json +++ b/erpnext/setup/doctype/employee/employee.json @@ -814,7 +814,8 @@ "depends_on": "eval:doc.salary_mode == 'Bank'", "fieldname": "iban", "fieldtype": "Data", - "label": "IBAN" + "label": "IBAN", + "options": "IBAN" } ], "icon": "fa fa-user", @@ -822,7 +823,7 @@ "image_field": "image", "is_tree": 1, "links": [], - "modified": "2025-07-04 08:29:34.347269", + "modified": "2025-08-29 11:52:12.819878", "modified_by": "Administrator", "module": "Setup", "name": "Employee", @@ -864,6 +865,7 @@ "write": 1 } ], + "row_format": "Dynamic", "search_fields": "employee_name", "show_name_in_global_search": 1, "sort_field": "modified", @@ -871,4 +873,4 @@ "states": [], "title_field": "employee_name", "track_changes": 1 -} \ No newline at end of file +} From 3d3e1167974393669ec2836a09bff886cb4226fc Mon Sep 17 00:00:00 2001 From: Kavin <78342682+kavin0411@users.noreply.github.com> Date: Tue, 14 Oct 2025 13:35:06 +0530 Subject: [PATCH 02/13] fix: handle flt conversion for prev_ordered_qty (cherry picked from commit 77c35ef47f186bcfec88a8db9795bcd4063edb71) --- erpnext/buying/doctype/purchase_order/purchase_order.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index 0f4d7cf496c..5cbba410f86 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -644,9 +644,8 @@ class PurchaseOrder(BuyingController): if not self.is_against_so(): return for item in removed_items: - prev_ordered_qty = ( + prev_ordered_qty = flt( frappe.get_cached_value("Sales Order Item", item.get("sales_order_item"), "ordered_qty") - or 0.0 ) frappe.db.set_value( From abb210bd18358149e77fa16dd08578c823efd6e1 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 14 Oct 2025 18:22:20 +0000 Subject: [PATCH 03/13] refactor: add supplier filter in buying (backport #50013) (#50107) * refactor: add supplier filter in buying (cherry picked from commit 108b108d645b169695513a73afcd415380921a14) # Conflicts: # erpnext/public/js/controllers/buying.js * chore: resolve conflicts --------- Co-authored-by: manikandan-s-18 Co-authored-by: Mihir Kandoi --- erpnext/public/js/controllers/buying.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js index 8c0be8042ac..e0e68c37451 100644 --- a/erpnext/public/js/controllers/buying.js +++ b/erpnext/public/js/controllers/buying.js @@ -17,7 +17,17 @@ erpnext.buying = { this.setup_queries(doc, cdt, cdn); super.onload(); - this.frm.set_query('shipping_rule', function() { + if (["Purchase Order", "Purchase Receipt", "Purchase Invoice"].includes(this.frm.doctype)) { + this.frm.set_query("supplier", function () { + return { + filters: { + is_transporter: 0, + }, + }; + }); + } + + this.frm.set_query("shipping_rule", function () { return { filters: { "shipping_rule_type": "Buying" From c64dcf34239cdded72b6eca3b285e569b6da4d89 Mon Sep 17 00:00:00 2001 From: Kavin <78342682+kavin0411@users.noreply.github.com> Date: Tue, 14 Oct 2025 17:12:04 +0530 Subject: [PATCH 04/13] fix: preview stock ledger for manual serial and batch values (cherry picked from commit c5f68d0b27450de4846301f638dac8b9bd16b896) --- erpnext/controllers/stock_controller.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index d7c9bb61a20..e4f0e8c684c 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -1544,7 +1544,9 @@ def get_stock_ledger_preview(doc, filters): if doc.get("update_stock") or doc.doctype in ("Purchase Receipt", "Delivery Note"): doc.docstatus = 1 + doc.make_bundle_using_old_serial_batch_fields() doc.update_stock_ledger() + columns = get_sl_columns(filters) sl_entries = get_sl_entries_for_preview(doc.doctype, doc.name, fields) From 76cfa28a424059c459c0a3d9853adb392432f225 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Wed, 15 Oct 2025 15:17:59 +0530 Subject: [PATCH 05/13] fix: adjustment entry (cherry picked from commit c0851abaee4f75901e378c2cfac6f4e5f49be92c) --- erpnext/stock/stock_ledger.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index a7a319e296e..54616149b37 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -896,7 +896,11 @@ class update_entries_after: if sle.is_adjustment_entry and flt(sle.qty_after_transaction, self.flt_precision) == 0: sle.stock_value_difference = ( get_stock_value_difference( - sle.item_code, sle.warehouse, sle.posting_date, sle.posting_time, sle.voucher_no + sle.item_code, + sle.warehouse, + sle.posting_date, + sle.posting_time, + voucher_detail_no=sle.voucher_detail_no, ) * -1 ) @@ -2353,7 +2357,9 @@ def is_internal_transfer(sle): return True -def get_stock_value_difference(item_code, warehouse, posting_date, posting_time, voucher_no=None): +def get_stock_value_difference( + item_code, warehouse, posting_date, posting_time, voucher_no=None, voucher_detail_no=None +): table = frappe.qb.DocType("Stock Ledger Entry") posting_datetime = get_combine_datetime(posting_date, posting_time) @@ -2368,7 +2374,10 @@ def get_stock_value_difference(item_code, warehouse, posting_date, posting_time, ) ) - if voucher_no: + if voucher_detail_no: + query = query.where(table.voucher_detail_no != voucher_detail_no) + + elif voucher_no: query = query.where(table.voucher_no != voucher_no) difference_amount = query.run() From a3a6d394369182ee94150464077176bf91ad6cd3 Mon Sep 17 00:00:00 2001 From: Diptanil Saha Date: Wed, 15 Oct 2025 18:57:07 +0530 Subject: [PATCH 06/13] fix: added exception handling on service level agreement apply hook (#50096) * fix: added exception handling on service level agreement apply hook * Revert "fix: added exception handling on service level agreement apply hook" This reverts commit dae93aa96f4756cbca4bee8b19e8cd4390617e9b. * fix: Ignore missing SLA table during install/uninstall --------- Co-authored-by: Ankush Menat (cherry picked from commit 182c9fd966fc40ec2128cdc58df7f369b8999876) --- .../service_level_agreement.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py index 6a39a434b6a..6f7c943ddad 100644 --- a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py +++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py @@ -484,10 +484,16 @@ def get_documents_with_active_service_level_agreement(): def set_documents_with_active_service_level_agreement(): - active = frozenset( - sla.document_type for sla in frappe.get_all("Service Level Agreement", fields=["document_type"]) - ) - frappe.cache.set_value("doctypes_with_active_sla", active) + try: + active = frozenset( + sla.document_type for sla in frappe.get_all("Service Level Agreement", fields=["document_type"]) + ) + frappe.cache.set_value("doctypes_with_active_sla", active) + except (frappe.DoesNotExistError, frappe.db.TableMissingError): + # This happens during install / uninstall when wildcard hook for SLA intercepts some doc action. + # In both cases, the error can be safely ignored. + active = frozenset() + return active From 2b0281c510ab8ea4bab29184a33e1332c3290562 Mon Sep 17 00:00:00 2001 From: diptanilsaha Date: Fri, 17 Oct 2025 01:26:31 +0530 Subject: [PATCH 07/13] fix(point-of-sale): render payment methods only payment component is visible (cherry picked from commit 7dc4306640bf0cb987af28f99ee2b4c774d6cc01) --- erpnext/selling/page/point_of_sale/pos_payment.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/erpnext/selling/page/point_of_sale/pos_payment.js b/erpnext/selling/page/point_of_sale/pos_payment.js index 92e9ad060df..165066a151a 100644 --- a/erpnext/selling/page/point_of_sale/pos_payment.js +++ b/erpnext/selling/page/point_of_sale/pos_payment.js @@ -394,6 +394,10 @@ erpnext.PointOfSale.Payment = class { const payments = doc.payments; const currency = doc.currency; + if (!this.$payment_modes.is(":visible")) { + return; + } + this.$payment_modes.html( `${payments .map((p, i) => { @@ -612,6 +616,10 @@ erpnext.PointOfSale.Payment = class { const currency = doc.currency; const label = __("Change Amount"); + if (!this.$totals.is(":visible")) { + return; + } + this.$totals.html( `
${__("Grand Total")}
From b9dd05f29264a7e9c295ed94f263353bda0b803d Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Thu, 16 Oct 2025 02:23:29 +0530 Subject: [PATCH 08/13] fix: validation for negative batch (cherry picked from commit f9c8f27586fedeca90ec72c901bd8ba38fb2b643) --- erpnext/stock/deprecated_serial_batch.py | 3 +++ .../serial_and_batch_bundle.py | 13 ++++++++----- erpnext/stock/serial_batch_bundle.py | 16 ++++++++++------ 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/erpnext/stock/deprecated_serial_batch.py b/erpnext/stock/deprecated_serial_batch.py index 69443e3a608..f6984c9edab 100644 --- a/erpnext/stock/deprecated_serial_batch.py +++ b/erpnext/stock/deprecated_serial_batch.py @@ -78,6 +78,7 @@ class DeprecatedBatchNoValuation: for ledger in entries: self.stock_value_differece[ledger.batch_no] += flt(ledger.batch_value) self.available_qty[ledger.batch_no] += flt(ledger.batch_qty) + self.total_qty[ledger.batch_no] += flt(ledger.batch_qty) @deprecated def get_sle_for_batches(self): @@ -230,6 +231,7 @@ class DeprecatedBatchNoValuation: batch_data = query.run(as_dict=True) for d in batch_data: self.available_qty[d.batch_no] += flt(d.batch_qty) + self.total_qty[d.batch_no] += flt(d.batch_qty) for d in batch_data: if self.available_qty.get(d.batch_no): @@ -330,6 +332,7 @@ class DeprecatedBatchNoValuation: batch_data = query.run(as_dict=True) for d in batch_data: self.available_qty[d.batch_no] += flt(d.batch_qty) + self.total_qty[d.batch_no] += flt(d.batch_qty) if not self.last_sle: return diff --git a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py index 977a41f0369..0655cd2cfd7 100644 --- a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py +++ b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py @@ -518,12 +518,15 @@ class SerialandBatchBundle(Document): else: d.incoming_rate = abs(flt(sn_obj.batch_avg_rate.get(d.batch_no))) - available_qty = flt(sn_obj.available_qty.get(d.batch_no), d.precision("qty")) - if self.docstatus == 1: - available_qty += flt(d.qty, d.precision("qty")) + precision = d.precision("qty") + for field in ["available_qty", "total_qty"]: + value = getattr(sn_obj, field) + available_qty = flt(value.get(d.batch_no), precision) + if self.docstatus == 1: + available_qty += flt(d.qty, precision) - if not allow_negative_stock: - self.validate_negative_batch(d.batch_no, available_qty) + if not allow_negative_stock: + self.validate_negative_batch(d.batch_no, available_qty) d.stock_value_difference = flt(d.qty) * flt(d.incoming_rate) diff --git a/erpnext/stock/serial_batch_bundle.py b/erpnext/stock/serial_batch_bundle.py index bea1cb7386e..fbd30075be3 100644 --- a/erpnext/stock/serial_batch_bundle.py +++ b/erpnext/stock/serial_batch_bundle.py @@ -3,6 +3,7 @@ from collections import defaultdict import frappe from frappe import _, bold from frappe.model.naming import make_autoname +from frappe.query_builder import Case from frappe.query_builder.functions import CombineDatetime, Sum, Timestamp from frappe.utils import add_days, cint, cstr, flt, get_link_to_form, now, nowtime, today from pypika import Order @@ -708,6 +709,7 @@ class BatchNoValuation(DeprecatedBatchNoValuation): for key, value in kwargs.items(): setattr(self, key, value) + self.total_qty = defaultdict(float) self.stock_queue = [] self.batch_nos = self.get_batch_nos() self.prepare_batches() @@ -729,6 +731,7 @@ class BatchNoValuation(DeprecatedBatchNoValuation): for ledger in entries: self.stock_value_differece[ledger.batch_no] += flt(ledger.incoming_rate) self.available_qty[ledger.batch_no] += flt(ledger.qty) + self.total_qty[ledger.batch_no] += flt(ledger.total_qty) self.calculate_avg_rate_from_deprecarated_ledgers() self.calculate_avg_rate_for_non_batchwise_valuation() @@ -762,13 +765,16 @@ class BatchNoValuation(DeprecatedBatchNoValuation): .on(parent.name == child.parent) .select( child.batch_no, - Sum(child.stock_value_difference).as_("incoming_rate"), - Sum(child.qty).as_("qty"), + Sum(Case().when(timestamp_condition, child.stock_value_difference).else_(0)).as_( + "incoming_rate" + ), + Sum(Case().when(timestamp_condition, child.qty).else_(0)).as_("qty"), + Sum(child.qty).as_("total_qty"), ) .where( - (child.batch_no.isin(self.batchwise_valuation_batches)) - & (parent.warehouse == self.sle.warehouse) + (parent.warehouse == self.sle.warehouse) & (parent.item_code == self.sle.item_code) + & (child.batch_no.isin(self.batchwise_valuation_batches)) & (parent.docstatus == 1) & (parent.is_cancelled == 0) & (parent.type_of_transaction.isin(["Inward", "Outward"])) @@ -784,8 +790,6 @@ class BatchNoValuation(DeprecatedBatchNoValuation): query = query.where(parent.voucher_no != self.sle.voucher_no) query = query.where(parent.voucher_type != "Pick List") - if timestamp_condition: - query = query.where(timestamp_condition) return query.run(as_dict=True) From 58a1383380c1e5a1dcee18207bbbc05bc9daaed9 Mon Sep 17 00:00:00 2001 From: Kavin <78342682+kavin0411@users.noreply.github.com> Date: Fri, 17 Oct 2025 18:35:53 +0530 Subject: [PATCH 09/13] fix(stock): remove duplicate fields --- .../doctype/stock_settings/stock_settings.json | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.json b/erpnext/stock/doctype/stock_settings/stock_settings.json index ec154c95136..0faa600cbc7 100644 --- a/erpnext/stock/doctype/stock_settings/stock_settings.json +++ b/erpnext/stock/doctype/stock_settings/stock_settings.json @@ -36,17 +36,6 @@ "show_barcode_field", "clean_description_html", "allow_internal_transfer_at_arms_length_price", - "quality_inspection_settings_section", - "action_if_quality_inspection_is_not_submitted", - "column_break_23", - "action_if_quality_inspection_is_rejected", - "stock_reservation_tab", - "enable_stock_reservation", - "column_break_rx3e", - "allow_partial_reservation", - "auto_reserve_stock_for_sales_order_on_purchase", - "serial_and_batch_reservation_section", - "auto_reserve_serial_and_batch", "serial_and_batch_item_settings_tab", "section_break_7", "allow_existing_serial_no", @@ -548,8 +537,8 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2025-05-06 02:39:24.284587", - "modified_by": "Administrator", + "modified": "2025-10-17 18:32:35.829395", + "modified_by": "hello@aerele.in", "module": "Stock", "name": "Stock Settings", "owner": "Administrator", @@ -569,8 +558,9 @@ } ], "quick_entry": 1, + "row_format": "Dynamic", "sort_field": "creation", "sort_order": "ASC", "states": [], "track_changes": 1 -} +} \ No newline at end of file From d67a439051b87feefbc64caa68d4059751579483 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Fri, 17 Oct 2025 18:28:19 +0530 Subject: [PATCH 10/13] fix: internal transfer entry with serial/batch (cherry picked from commit 9b4e62a75875993d28991f21b32d796e5e854e38) --- erpnext/accounts/doctype/sales_invoice/sales_invoice.py | 3 +++ erpnext/controllers/stock_controller.py | 8 ++++++++ erpnext/stock/doctype/delivery_note/delivery_note.py | 3 +++ 3 files changed, 14 insertions(+) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 2de3feb9a35..3dcbcbfc2ab 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -2411,6 +2411,9 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None): target.purchase_order = source.purchase_order target.po_detail = source.purchase_order_item + if (source.get("serial_no") or source.get("batch_no")) and not source.get("serial_and_batch_bundle"): + target.use_serial_batch_fields = 1 + item_field_map = { "doctype": target_doctype + " Item", "field_no_map": ["income_account", "expense_account", "cost_center", "warehouse"], diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index e4f0e8c684c..035dfc6e264 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -253,6 +253,14 @@ class StockController(AccountsController): "do_not_submit": True if not via_landed_cost_voucher else False, } + if self.is_internal_transfer() and row.get("from_warehouse") and not self.is_return: + self.update_bundle_details(bundle_details, table_name, row) + bundle_details["type_of_transaction"] = "Outward" + bundle_details["warehouse"] = row.get("from_warehouse") + bundle_details["qty"] = row.get("stock_qty") or row.get("qty") + self.create_serial_batch_bundle(bundle_details, row) + continue + if row.get("qty") or row.get("consumed_qty") or row.get("stock_qty"): self.update_bundle_details(bundle_details, table_name, row, parent_details=parent_details) self.create_serial_batch_bundle(bundle_details, row) diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py index d2a15c2bd66..792bbf902fc 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/delivery_note.py @@ -1310,6 +1310,9 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None): if source.get("use_serial_batch_fields"): target.set("use_serial_batch_fields", 1) + if (source.get("serial_no") or source.get("batch_no")) and not source.get("serial_and_batch_bundle"): + target.set("use_serial_batch_fields", 1) + doclist = get_mapped_doc( doctype, source_name, From 43941ecd5e9b6dbb87e802f3637a1e2b517309bd Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Sun, 19 Oct 2025 23:59:27 +0200 Subject: [PATCH 11/13] refactor: simplify expression (backport #50168) (#50170) Co-authored-by: barredterra <14891507+barredterra@users.noreply.github.com> --- erpnext/controllers/accounts_controller.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 96864bb5a60..b134e79a137 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -3073,9 +3073,7 @@ def set_balance_in_account_currency( _("Account: {0} with currency: {1} can not be selected").format(gl_dict.account, account_currency) ) - gl_dict["account_currency"] = ( - company_currency if account_currency == company_currency else account_currency - ) + gl_dict["account_currency"] = account_currency # set debit/credit in account currency if not provided if flt(gl_dict.debit) and not flt(gl_dict.debit_in_account_currency): From 0571ed07357951b58f21e1191ab310ed9193a91e Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 20 Oct 2025 22:42:19 +0400 Subject: [PATCH 12/13] perf: Add index for faster queries (#50175) (cherry picked from commit 7a91ec3e335843dfe83c2d751ad0ebd024d13480) --- .../journal_entry_account/journal_entry_account.json | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json index 5d31c627381..b333e103b59 100644 --- a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json +++ b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json @@ -272,7 +272,8 @@ "label": "Advance Voucher Type", "no_copy": 1, "options": "DocType", - "read_only": 1 + "read_only": 1, + "search_index": 1 }, { "fieldname": "advance_voucher_no", @@ -280,13 +281,14 @@ "label": "Advance Voucher No", "no_copy": 1, "options": "advance_voucher_type", - "read_only": 1 + "read_only": 1, + "search_index": 1 } ], "idx": 1, "istable": 1, "links": [], - "modified": "2025-09-29 13:01:48.916517", + "modified": "2025-10-20 17:46:47.344089", "modified_by": "Administrator", "module": "Accounts", "name": "Journal Entry Account", From afc2d957363b33ee552b5730a04044da6c2f7c30 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 21 Oct 2025 11:06:02 +0530 Subject: [PATCH 13/13] fix: correct monthly sales history (backport #50056) (#50179) fix: correct monthly sales history (#50056) * fix: correct monthly sales history * fix: correct monthly sales history calculation * chore: remove unrelated file accidentally committed --------- (cherry picked from commit f51ed30c23146cca7f98c7789b0e6ea394af144f) Co-authored-by: Ahmed AbuKhatwa <82771130+AhmedAbokhatwa@users.noreply.github.com> Co-authored-by: AhmedAbukhatwa --- erpnext/setup/doctype/company/company.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index e5f26073a33..eb1e33acafe 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -763,13 +763,11 @@ def update_company_current_month_sales(company): def update_company_monthly_sales(company): """Cache past year monthly sales of every company based on sales invoices""" - import json - from frappe.utils.goal import get_monthly_results - filter_str = f"company = {frappe.db.escape(company)} and status != 'Draft' and docstatus=1" + filter_dict = {"company": company, "status": ["!=", "Draft"], "docstatus": 1} month_to_value_dict = get_monthly_results( - "Sales Invoice", "base_grand_total", "posting_date", filter_str, "sum" + "Sales Invoice", "base_grand_total", "posting_date", filter_dict, "sum" ) frappe.db.set_value("Company", company, "sales_monthly_history", json.dumps(month_to_value_dict))