diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml index 6701673cc7f..37d8363beaa 100644 --- a/.github/workflows/linters.yml +++ b/.github/workflows/linters.yml @@ -43,3 +43,6 @@ jobs: - name: Run Semgrep rules run: semgrep ci --config ./frappe-semgrep-rules/rules --config r/python.lang.correctness + + - name: Semgrep for Test Correctness + run: semgrep ci --include=**/test_*.py --config ./semgrep/test-correctness.yml diff --git a/erpnext/accounts/doctype/account/account_tree.js b/erpnext/accounts/doctype/account/account_tree.js index 315b41560ce..5ff4e4a47e2 100644 --- a/erpnext/accounts/doctype/account/account_tree.js +++ b/erpnext/accounts/doctype/account/account_tree.js @@ -52,60 +52,55 @@ frappe.treeview_settings["Account"] = { ], root_label: "Accounts", get_tree_nodes: "erpnext.accounts.utils.get_children", - on_get_node: function (nodes, deep = false) { - if (frappe.boot.user.can_read.indexOf("GL Entry") == -1) return; + on_node_render: function (node, deep) { + const render_balances = () => { + for (let account of cur_tree.account_balance_data) { + const node = cur_tree.nodes && cur_tree.nodes[account.value]; + if (!node || node.is_root) continue; - let accounts = []; - if (deep) { - // in case of `get_all_nodes` - accounts = nodes.reduce((acc, node) => [...acc, ...node.data], []); - } else { - accounts = nodes; - } + // show Dr if positive since balance is calculated as debit - credit else show Cr + const balance = account.balance_in_account_currency || account.balance; + const dr_or_cr = balance > 0 ? __("Dr") : __("Cr"); + const format = (value, currency) => format_currency(Math.abs(value), currency); - frappe.db.get_single_value("Accounts Settings", "show_balance_in_coa").then((value) => { - if (value) { - const get_balances = frappe.call({ - method: "erpnext.accounts.utils.get_account_balances", - args: { - accounts: accounts, - company: cur_tree.args.company, - include_default_fb_balances: true, - }, - }); - - get_balances.then((r) => { - if (!r.message || r.message.length == 0) return; - - for (let account of r.message) { - const node = cur_tree.nodes && cur_tree.nodes[account.value]; - if (!node || node.is_root) continue; - - // show Dr if positive since balance is calculated as debit - credit else show Cr - const balance = account.balance_in_account_currency || account.balance; - const dr_or_cr = balance > 0 ? __("Dr") : __("Cr"); - const format = (value, currency) => format_currency(Math.abs(value), currency); - - if (account.balance !== undefined) { - node.parent && node.parent.find(".balance-area").remove(); - $( - '' + - (account.balance_in_account_currency - ? format( - account.balance_in_account_currency, - account.account_currency - ) + " / " - : "") + - format(account.balance, account.company_currency) + - " " + - dr_or_cr + - "" - ).insertBefore(node.$ul); - } - } - }); + if (account.balance !== undefined) { + node.parent && node.parent.find(".balance-area").remove(); + $( + '' + + (account.account_currency != account.company_currency + ? format(account.balance_in_account_currency, account.account_currency) + + " / " + : "") + + format(account.balance, account.company_currency) + + " " + + dr_or_cr + + "" + ).insertBefore(node.$ul); + } } - }); + }; + + if (frappe.boot.user.can_read.indexOf("GL Entry") == -1) return; + if (!cur_tree.account_balance_data) { + frappe.db.get_single_value("Accounts Settings", "show_balance_in_coa").then((value) => { + if (value) { + frappe.call({ + method: "erpnext.accounts.utils.get_account_balances_coa", + args: { + company: cur_tree.args.company, + include_default_fb_balances: true, + }, + callback: function (r) { + if (!r.message || r.message.length === 0) return; + cur_tree.account_balance_data = r.message || []; + render_balances(); + }, + }); + } + }); + } else { + render_balances(); + } }, add_tree_node: "erpnext.accounts.utils.add_ac", menu_items: [ diff --git a/erpnext/accounts/doctype/account_category/account_category.json b/erpnext/accounts/doctype/account_category/account_category.json index d69d37bd78b..cc8f4103f21 100644 --- a/erpnext/accounts/doctype/account_category/account_category.json +++ b/erpnext/accounts/doctype/account_category/account_category.json @@ -26,8 +26,13 @@ ], "grid_page_length": 50, "index_web_pages_for_search": 1, - "links": [], - "modified": "2025-10-15 03:19:47.171349", + "links": [ + { + "link_doctype": "Account", + "link_fieldname": "account_category" + } + ], + "modified": "2026-02-23 01:19:49.589393", "modified_by": "Administrator", "module": "Accounts", "name": "Account Category", diff --git a/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py index 81e639dc6b2..250442a3cd4 100644 --- a/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py +++ b/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py @@ -10,9 +10,6 @@ from erpnext.tests.utils import ERPNextTestSuite class TestAccountingDimension(ERPNextTestSuite): - def setUp(self): - create_dimension() - def test_dimension_against_sales_invoice(self): si = create_sales_invoice(do_not_save=1) @@ -77,63 +74,3 @@ class TestAccountingDimension(ERPNextTestSuite): si.save() self.assertRaises(frappe.ValidationError, si.submit) - - -def create_dimension(): - frappe.set_user("Administrator") - - if not frappe.db.exists("Accounting Dimension", {"document_type": "Department"}): - dimension = frappe.get_doc( - { - "doctype": "Accounting Dimension", - "document_type": "Department", - } - ) - dimension.append( - "dimension_defaults", - { - "company": "_Test Company", - "reference_document": "Department", - "default_dimension": "_Test Department - _TC", - }, - ) - dimension.insert() - dimension.save() - else: - dimension = frappe.get_doc("Accounting Dimension", "Department") - dimension.disabled = 0 - dimension.save() - - if not frappe.db.exists("Accounting Dimension", {"document_type": "Location"}): - dimension1 = frappe.get_doc( - { - "doctype": "Accounting Dimension", - "document_type": "Location", - } - ) - - dimension1.append( - "dimension_defaults", - { - "company": "_Test Company", - "reference_document": "Location", - "default_dimension": "Block 1", - }, - ) - - dimension1.insert() - dimension1.save() - else: - dimension1 = frappe.get_doc("Accounting Dimension", "Location") - dimension1.disabled = 0 - dimension1.save() - - -def disable_dimension(): - dimension1 = frappe.get_doc("Accounting Dimension", "Department") - dimension1.disabled = 1 - dimension1.save() - - dimension2 = frappe.get_doc("Accounting Dimension", "Location") - dimension2.disabled = 1 - dimension2.save() diff --git a/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py b/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py index 9bed10824bb..fe7d4706967 100644 --- a/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py +++ b/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py @@ -5,10 +5,6 @@ import unittest import frappe -from erpnext.accounts.doctype.accounting_dimension.test_accounting_dimension import ( - create_dimension, - disable_dimension, -) from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice from erpnext.exceptions import InvalidAccountDimensionError, MandatoryAccountDimensionError from erpnext.tests.utils import ERPNextTestSuite @@ -16,7 +12,6 @@ from erpnext.tests.utils import ERPNextTestSuite class TestAccountingDimensionFilter(ERPNextTestSuite): def setUp(self): - create_dimension() create_accounting_dimension_filter() self.invoice_list = [] diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json index ee734184452..29673e89b6c 100644 --- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json +++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json @@ -65,6 +65,7 @@ "payment_options_section", "enable_loyalty_point_program", "column_break_ctam", + "fetch_payment_schedule_in_payment_request", "invoicing_settings_tab", "accounts_transactions_settings_section", "over_billing_allowance", @@ -688,6 +689,19 @@ "fieldname": "enable_accounting_dimensions", "fieldtype": "Check", "label": "Enable Accounting Dimensions" + }, + { + "default": "1", + "description": "Enable Subscription tracking in invoice", + "fieldname": "enable_subscription", + "fieldtype": "Check", + "label": "Enable Subscription" + }, + { + "default": "1", + "fieldname": "fetch_payment_schedule_in_payment_request", + "fieldtype": "Check", + "label": "Fetch Payment Schedule In Payment Request" } ], "grid_page_length": 50, @@ -697,7 +711,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2026-02-27 01:04:09.415288", + "modified": "2026-03-30 07:32:58.182018", "modified_by": "Administrator", "module": "Accounts", "name": "Accounts Settings", diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py index e75b8ad1710..94b35eba00a 100644 --- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py +++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py @@ -73,6 +73,7 @@ class AccountsSettings(Document): enable_loyalty_point_program: DF.Check enable_party_matching: DF.Check exchange_gain_loss_posting_date: DF.Literal["Invoice", "Payment", "Reconciliation Date"] + fetch_payment_schedule_in_payment_request: DF.Check fetch_valuation_rate_for_internal_transaction: DF.Check general_ledger_remarks_length: DF.Int ignore_account_closing_balance: DF.Check diff --git a/erpnext/accounts/doctype/advance_payment_ledger_entry/test_advance_payment_ledger_entry.py b/erpnext/accounts/doctype/advance_payment_ledger_entry/test_advance_payment_ledger_entry.py index 53047b61718..d910bef3d94 100644 --- a/erpnext/accounts/doctype/advance_payment_ledger_entry/test_advance_payment_ledger_entry.py +++ b/erpnext/accounts/doctype/advance_payment_ledger_entry/test_advance_payment_ledger_entry.py @@ -15,7 +15,7 @@ from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_orde from erpnext.tests.utils import ERPNextTestSuite -class TestAdvancePaymentLedgerEntry(AccountsTestMixin, ERPNextTestSuite): +class TestAdvancePaymentLedgerEntry(ERPNextTestSuite, AccountsTestMixin): """ Integration tests for AdvancePaymentLedgerEntry. Use this class for testing interactions between multiple components. diff --git a/erpnext/accounts/doctype/bank_account/bank_account.py b/erpnext/accounts/doctype/bank_account/bank_account.py index c0dc6467f8f..9fe5b4ba3fb 100644 --- a/erpnext/accounts/doctype/bank_account/bank_account.py +++ b/erpnext/accounts/doctype/bank_account/bank_account.py @@ -116,6 +116,7 @@ def get_default_company_bank_account(company, party_type, party): @frappe.whitelist() def get_bank_account_details(bank_account): + frappe.has_permission("Bank Account", doc=bank_account, ptype="read", throw=True) return frappe.get_cached_value( "Bank Account", bank_account, ["account", "bank", "bank_account_no"], as_dict=1 ) diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/test_bank_reconciliation_tool.py b/erpnext/accounts/doctype/bank_reconciliation_tool/test_bank_reconciliation_tool.py index 5354aa0c4dd..3a55b3fc1d8 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/test_bank_reconciliation_tool.py +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/test_bank_reconciliation_tool.py @@ -15,7 +15,7 @@ from erpnext.accounts.test.accounts_mixin import AccountsTestMixin from erpnext.tests.utils import ERPNextTestSuite -class TestBankReconciliationTool(AccountsTestMixin, ERPNextTestSuite): +class TestBankReconciliationTool(ERPNextTestSuite, AccountsTestMixin): def setUp(self): self.create_company() self.create_customer() diff --git a/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py b/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py index c69d255c51a..c7668a5a592 100644 --- a/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py +++ b/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py @@ -382,7 +382,7 @@ def add_vouchers(gl_account="_Test Bank - _TC"): frappe.get_doc( { "doctype": "Customer", - "customer_group": "All Customer Groups", + "customer_group": "Individual", "customer_type": "Company", "customer_name": "Poore Simon's", } @@ -413,7 +413,7 @@ def add_vouchers(gl_account="_Test Bank - _TC"): frappe.get_doc( { "doctype": "Customer", - "customer_group": "All Customer Groups", + "customer_group": "Individual", "customer_type": "Company", "customer_name": "Fayva", } diff --git a/erpnext/accounts/doctype/bank_transaction/test_bank_transaction_fees.py b/erpnext/accounts/doctype/bank_transaction/test_bank_transaction_fees.py index 95fc615d91d..e0ea8cd441a 100644 --- a/erpnext/accounts/doctype/bank_transaction/test_bank_transaction_fees.py +++ b/erpnext/accounts/doctype/bank_transaction/test_bank_transaction_fees.py @@ -2,10 +2,11 @@ # See license.txt import frappe -from frappe.tests import UnitTestCase + +from erpnext.tests.utils import ERPNextTestSuite -class TestBankTransactionFees(UnitTestCase): +class TestBankTransactionFees(ERPNextTestSuite): def test_included_fee_throws(self): """A fee that's part of a withdrawal cannot be bigger than the withdrawal itself.""" diff --git a/erpnext/accounts/doctype/exchange_rate_revaluation/test_exchange_rate_revaluation.py b/erpnext/accounts/doctype/exchange_rate_revaluation/test_exchange_rate_revaluation.py index 1310a8b482b..a6adba537e2 100644 --- a/erpnext/accounts/doctype/exchange_rate_revaluation/test_exchange_rate_revaluation.py +++ b/erpnext/accounts/doctype/exchange_rate_revaluation/test_exchange_rate_revaluation.py @@ -13,7 +13,7 @@ from erpnext.accounts.test.accounts_mixin import AccountsTestMixin from erpnext.tests.utils import ERPNextTestSuite -class TestExchangeRateRevaluation(AccountsTestMixin, ERPNextTestSuite): +class TestExchangeRateRevaluation(ERPNextTestSuite, AccountsTestMixin): def setUp(self): self.create_company() self.create_usd_receivable_account() diff --git a/erpnext/accounts/doctype/financial_report_template/financial_report_template.js b/erpnext/accounts/doctype/financial_report_template/financial_report_template.js index 739956631fd..304da47577b 100644 --- a/erpnext/accounts/doctype/financial_report_template/financial_report_template.js +++ b/erpnext/accounts/doctype/financial_report_template/financial_report_template.js @@ -3,6 +3,8 @@ frappe.ui.form.on("Financial Report Template", { refresh(frm) { + if (frm.is_new() || frm.doc.rows.length === 0) return; + // add custom button to view missed accounts frm.add_custom_button(__("View Account Coverage"), function () { let selected_rows = frm.get_field("rows").grid.get_selected_children(); @@ -20,7 +22,7 @@ frappe.ui.form.on("Financial Report Template", { }); }, - validate(frm) { + after_save(frm) { if (!frm.doc.rows || frm.doc.rows.length === 0) { frappe.msgprint(__("At least one row is required for a financial report template")); } @@ -34,14 +36,6 @@ frappe.ui.form.on("Financial Report Row", { update_formula_label(frm, row.data_source); update_formula_description(frm, row.data_source); - if (row.data_source !== "Account Data") { - frappe.model.set_value(cdt, cdn, "balance_type", ""); - } - - if (["Blank Line", "Column Break", "Section Break"].includes(row.data_source)) { - frappe.model.set_value(cdt, cdn, "calculation_formula", ""); - } - set_up_filters_editor(frm, cdt, cdn); }, @@ -322,6 +316,8 @@ function update_formula_description(frm, data_source) { const list_style = `style="margin-bottom: var(--margin-sm); color: var(--text-muted); font-size: 0.9em;"`; const note_style = `style="margin-bottom: 0; color: var(--text-muted); font-size: 0.9em;"`; const tip_style = `style="margin-bottom: 0; color: var(--text-color); font-size: 0.85em;"`; + const code_style = `style="background: var(--bg-light-gray); padding: var(--padding-xs); border-radius: var(--border-radius); font-size: 0.85em; width: max-content; margin-bottom: var(--margin-sm);"`; + const pre_style = `style="margin: 0; border-radius: var(--border-radius)"`; let description_html = ""; @@ -382,8 +378,13 @@ function update_formula_description(frm, data_source) {
my_app.financial_reports.get_kpi_datadef get_custom_data(filters, periods, row):+
# filters: dict — report filters (company, period, etc.)
# periods: list[dict] — period definitions
# row: dict — the current report row
return [1000.0, 1200.0, 1150.0] # one value per period
Numbers for each period: [1000.0, 1200.0, 1150.0]
A list of numbers, one for each period: [1000.0, 1200.0, 1150.0]
| \n\t\t\t\t\t \n\t\t\t\t\t\t \n\t\t\t\t\t{{ _(\"Supplier Name:\") }} \n\t\t\t\t\t\t{{ _(\"Shipping Address:\") }} \n\t\t\t\t\t\n\t\t\t\t\t\t \n\t\t\t\t{{ doc.vendor }} \n\t\t\t\t\t\t\n \t\t\t\t\t{% if doc.shipping_address %}\n \t\t\t\t\t\t{% set shipping_address = frappe.db.get_value(\"Address\", doc.shipping_address, [\"address_line1\", \"address_line2\", \"city\", \"state\", \"pincode\", \"country\"], as_dict=True) %}\n {{ doc.shipping_address }} \n\n\t\t\t\t\t\n \t\t\t\t\t\t{{ shipping_address.address_line1 or \"\" }} \n \t\t\t\t\t\t{% if shipping_address.address_line2 %}{{ shipping_address.address_line2 }} {% endif %}\n \t\t\t\t\t\t{{ shipping_address.city or \"\" }} {{ shipping_address.state or \"\" }} {{ shipping_address.pincode or \"\" }} {{ shipping_address.country or \"\" }} \n \t\t\t\t\t{% endif %}\n\t\t\t\t\t\t | \n\n\t\t\t\t\n\t\t\t\t\t \n\t\t\t\t\t\t \n\t\t\t\t\t{{ _(\"Order Date:\") }} \n\t\t\t\t\t\n\t\t\t\t\t\t \n\t\t\t\t\t{{ frappe.utils.format_date(doc.transaction_date) }} \n\t\t\t\t\t\n\t\t\t\t\t\t \n\t\t\t\t\t{{ _(\"Required By:\") }} \n\t\t\t\t\t\n\t\t\t\t\t\t \n\t\t\t\t{{ frappe.utils.format_date(doc.schedule_date) }} \n\t\t\t\t\t | \n\t\t\t
| {{ _(\"No\") }} | \n\t\t\t\t\t{{ _(\"Item\") }} | \n\t\t\t\t\t{% if item_naming_by != \"Item Code\" %}\n\t\t\t\t\t\t{{ _(\"Item Code\") }} | \n\t\t\t\t\t{% endif %}\n\t\t\t\t\t{{ _(\"Quantity\") }} | \n\t\t\t\t||
| {{ loop.index }} | \n\t\t\t\t\t\n\t\t\t\t\t\t
| \n\t\t\t\t\t{% if item_naming_by != \"Item Code\" %}\n\t\t\t\t\t\t{{ item.item_code }} | \n\t\t\t\t\t{% endif %}\n\n\t\t\t\t\t{{ item.get_formatted(\"qty\", 0) }} {{ item.uom }} | \n\t\t\t\t
| {%= __("Item") %} | -{%= __("Description") %} | -{%= __("Required Qty") %} | -{%= __("In Stock Qty") %} | -{%= __("Enough Parts to Build") %} | -{%= data[i][ __("Item")] %} | -{%= data[i][ __("Description")] %} | -{%= data[i][ __("Required Qty")] %} | -{%= data[i][ __("In Stock Qty")] %} | -{%= data[i][ __("Enough Parts to Build")] %} | - - {% } %} -
|---|
${__("Project")}: - + ${task.project}
`; } html += `${__("Progress")}: - ${ganttobj.progress}% + ${ganttobj.progress}%
`; if (task._assign) { const assign_list = JSON.parse(task._assign); const assignment_wrapper = ` Assigned to: - + ${assign_list.map((user) => frappe.user_info(user).fullname).join(", ")} `; diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 1100ab7a581..4971f914b1e 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -459,8 +459,12 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe reference_name: frm.doc.name, }, }); + const value = await frappe.db.get_single_value( + "Accounts Settings", + "fetch_payment_schedule_in_payment_request" + ); - if (!schedules.length) { + if (!value || !schedules.length) { this.make_payment_request(); return; } @@ -1851,7 +1855,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe "base_operating_cost", "base_raw_material_cost", "base_total_cost", - "base_scrap_material_cost", + "base_secondary_items_cost", "base_totals_section", ], company_currency @@ -1869,7 +1873,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe "paid_amount", "write_off_amount", "operating_cost", - "scrap_material_cost", + "secondary_items_cost", "raw_material_cost", "total_cost", "totals_section", @@ -1915,7 +1919,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe "base_operating_cost", "base_raw_material_cost", "base_total_cost", - "base_scrap_material_cost", + "base_secondary_items_cost", "base_rounding_adjustment", ], this.frm.doc.currency != company_currency @@ -1980,11 +1984,11 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe }); } - if (this.frm.doc.scrap_items && this.frm.doc.scrap_items.length > 0) { - this.frm.set_currency_labels(["rate", "amount"], this.frm.doc.currency, "scrap_items"); - this.frm.set_currency_labels(["base_rate", "base_amount"], company_currency, "scrap_items"); + if (this.frm.doc.secondary_items && this.frm.doc.secondary_items.length > 0) { + this.frm.set_currency_labels(["rate", "amount"], this.frm.doc.currency, "secondary_items"); + this.frm.set_currency_labels(["base_rate", "base_amount"], company_currency, "secondary_items"); - var item_grid = this.frm.fields_dict["scrap_items"].grid; + var item_grid = this.frm.fields_dict["secondary_items"].grid; $.each(["base_rate", "base_amount"], function (i, fname) { if (frappe.meta.get_docfield(item_grid.doctype, fname)) item_grid.set_column_disp(fname, me.frm.doc.currency != company_currency); diff --git a/erpnext/public/js/financial_statements.js b/erpnext/public/js/financial_statements.js index 25918a179b8..0c8366d4e95 100644 --- a/erpnext/public/js/financial_statements.js +++ b/erpnext/public/js/financial_statements.js @@ -230,7 +230,10 @@ erpnext.financial_statements = { value = default_formatter(value, row, column, data); - if (data && !data.parent_account && !data.parent_section) { + if ( + data && + ((!data.parent_account && !data.parent_section) || data.is_group_account || data.is_group) + ) { value = $(`${value}`); var $value = $(value).css("font-weight", "bold"); diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js index 6fb1b88060c..935cae7f571 100755 --- a/erpnext/public/js/utils.js +++ b/erpnext/public/js/utils.js @@ -21,6 +21,10 @@ $.extend(erpnext, { toggle_serial_batch_fields(frm) { let hide_fields = cint(frappe.user_defaults?.enable_serial_and_batch_no_for_item) === 0 ? 1 : 0; + if (!hide_fields) { + return; + } + let fields = ["serial_and_batch_bundle", "use_serial_batch_fields", "serial_no", "batch_no"]; if ( @@ -44,7 +48,11 @@ $.extend(erpnext, { } if (["Purchase Receipt", "Purchase Invoice", "Subcontracting Receipt"].includes(frm.doc.doctype)) { - fields.push("add_serial_batch_for_rejected_qty", "rejected_serial_and_batch_bundle"); + fields.push( + "add_serial_batch_for_rejected_qty", + "rejected_serial_and_batch_bundle", + "rejected_serial_no" + ); } let child_name = "items"; @@ -56,6 +64,12 @@ $.extend(erpnext, { child_name = "stock_items"; } + let sn_field = frm.fields_dict[child_name].grid.docfields.filter((d) => d.fieldname === "serial_no"); + if (sn_field?.length && sn_field[0].hidden === 1) { + // Already field is hidden + return; + } + fields.forEach((field) => { if (frm.fields_dict[child_name].get_field(field)) { frm.fields_dict[child_name].grid.update_docfield_property(field, "hidden", hide_fields); @@ -68,7 +82,11 @@ $.extend(erpnext, { if ( frm.doc.doctype === "Subcontracting Receipt" && - !["add_serial_batch_for_rejected_qty", "rejected_serial_and_batch_bundle"].includes(field) + ![ + "add_serial_batch_for_rejected_qty", + "rejected_serial_and_batch_bundle", + "rejected_serial_no", + ].includes(field) ) { frm.fields_dict["supplied_items"].grid.update_docfield_property( field, @@ -81,12 +99,14 @@ $.extend(erpnext, { "in_list_view", hide_fields ? 0 : 1 ); - - frm.fields_dict["supplied_items"].grid.reset_grid(); } } }); + if (frm.doc.doctype === "Subcontracting Receipt") { + frm.fields_dict["supplied_items"].grid.reset_grid(); + } + frm.fields_dict[child_name].grid.reset_grid(); }, diff --git a/erpnext/regional/address_template/templates/croatia.html b/erpnext/regional/address_template/templates/croatia.html new file mode 100644 index 00000000000..0c2ed73f0ae --- /dev/null +++ b/erpnext/regional/address_template/templates/croatia.html @@ -0,0 +1,4 @@ +{{ address_line1 }}