diff --git a/CODEOWNERS b/CODEOWNERS
index a0c68b87789..50f5b524719 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -8,7 +8,6 @@ erpnext/assets/ @khushi8112
erpnext/regional @ruthra-kumar
erpnext/selling @ruthra-kumar
erpnext/support/ @ruthra-kumar
-pos* @diptanilsaha
erpnext/buying/ @rohitwaghchaure @mihir-kandoi
erpnext/maintenance/ @rohitwaghchaure
diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py b/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py
index efb93874226..3513464fa77 100644
--- a/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py
+++ b/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py
@@ -18,6 +18,7 @@ def create_charts(
accounts = []
def _import_accounts(children, parent, root_type, root_account=False):
+ nonlocal custom_chart
for account_name, child in children.items():
if root_account:
root_type = child.get("root_type")
@@ -55,7 +56,8 @@ def create_charts(
"account_number": account_number,
"account_type": child.get("account_type"),
"account_currency": child.get("account_currency")
- or frappe.get_cached_value("Company", company, "default_currency"),
+ if custom_chart
+ else frappe.get_cached_value("Company", company, "default_currency"),
"tax_rate": child.get("tax_rate"),
}
)
diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py
index 7f97c3677bd..3ce867dc96e 100644
--- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py
+++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py
@@ -9,7 +9,7 @@ from frappe import _
from frappe.model.document import Document
from frappe.query_builder.custom import ConstantColumn
from frappe.query_builder.functions import Sum
-from frappe.utils import cint, flt
+from frappe.utils import cint, create_batch, flt
from erpnext import get_default_cost_center
from erpnext.accounts.doctype.bank_transaction.bank_transaction import get_total_allocated_amount
@@ -377,16 +377,17 @@ def auto_reconcile_vouchers(
bank_transactions = get_bank_transactions(bank_account)
if len(bank_transactions) > 10:
- frappe.enqueue(
- method="erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.start_auto_reconcile",
- queue="long",
- bank_transactions=bank_transactions,
- from_date=from_date,
- to_date=to_date,
- filter_by_reference_date=filter_by_reference_date,
- from_reference_date=from_reference_date,
- to_reference_date=to_reference_date,
- )
+ for bank_transaction_batch in create_batch(bank_transactions, 1000):
+ frappe.enqueue(
+ method="erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.start_auto_reconcile",
+ queue="long",
+ bank_transactions=bank_transaction_batch,
+ from_date=from_date,
+ to_date=to_date,
+ filter_by_reference_date=filter_by_reference_date,
+ from_reference_date=from_reference_date,
+ to_reference_date=to_reference_date,
+ )
frappe.msgprint(_("Auto Reconciliation has started in the background"))
else:
start_auto_reconcile(
diff --git a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.js b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.js
index 0f01e2dfb65..6412971898c 100644
--- a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.js
+++ b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.js
@@ -252,7 +252,7 @@ frappe.ui.form.on("Bank Statement Import", {
open_url_post(method, {
doctype: "Bank Transaction",
- export_records: "5_records",
+ export_records: "blank_template",
export_fields: {
"Bank Transaction": [
"date",
diff --git a/erpnext/accounts/doctype/budget/budget.py b/erpnext/accounts/doctype/budget/budget.py
index 7825b2716dc..eec203c6794 100644
--- a/erpnext/accounts/doctype/budget/budget.py
+++ b/erpnext/accounts/doctype/budget/budget.py
@@ -302,7 +302,7 @@ def compare_expense_with_budget(args, budget_amount, action_for, action, budget_
def get_expense_breakup(args, currency, budget_against):
- msg = "
Total Expenses booked through - "
+ msg = "
{{ _('Total Expenses booked through') }} - "
common_filters = frappe._dict(
{
@@ -316,7 +316,7 @@ def get_expense_breakup(args, currency, budget_against):
"- "
+ frappe.utils.get_link_to_report(
"General Ledger",
- label="Actual Expenses",
+ label=_("Actual Expenses"),
filters=common_filters.copy().update(
{
"from_date": frappe.get_cached_value("Fiscal Year", args.fiscal_year, "year_start_date"),
@@ -334,7 +334,7 @@ def get_expense_breakup(args, currency, budget_against):
"
- "
+ frappe.utils.get_link_to_report(
"Material Request",
- label="Material Requests",
+ label=_("Material Requests"),
report_type="Report Builder",
doctype="Material Request",
filters=common_filters.copy().update(
@@ -357,7 +357,7 @@ def get_expense_breakup(args, currency, budget_against):
"
- "
+ frappe.utils.get_link_to_report(
"Purchase Order",
- label="Unbilled Orders",
+ label=_("Unbilled Orders"),
report_type="Report Builder",
doctype="Purchase Order",
filters=common_filters.copy().update(
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.json b/erpnext/accounts/doctype/pos_invoice/pos_invoice.json
index b7114d920a7..94ee5a6c07b 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.json
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.json
@@ -296,6 +296,7 @@
"search_index": 1
},
{
+ "default": "Now",
"fieldname": "posting_time",
"fieldtype": "Time",
"label": "Posting Time",
@@ -1598,7 +1599,7 @@
"icon": "fa fa-file-text",
"is_submittable": 1,
"links": [],
- "modified": "2025-07-18 16:50:30.516162",
+ "modified": "2025-08-04 22:22:31.471752",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Invoice",
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.js b/erpnext/accounts/doctype/pricing_rule/pricing_rule.js
index cd5b00e6ad0..fda519e0851 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.js
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.js
@@ -41,56 +41,68 @@ frappe.ui.form.on("Pricing Rule", {
- {{__('Notes')}}
+ ${__("Notes")}
-
- {{__("Pricing Rule is made to overwrite Price List / define discount percentage, based on some criteria.")}}
+ ${__("Pricing Rule is made to overwrite Price List / define discount percentage, based on some criteria.")}
-
- {{__("If selected Pricing Rule is made for 'Rate', it will overwrite Price List. Pricing Rule rate is the final rate, so no further discount should be applied. Hence, in transactions like Sales Order, Purchase Order etc, it will be fetched in 'Rate' field, rather than 'Price List Rate' field.")}}
+ ${__(
+ "If selected Pricing Rule is made for 'Rate', it will overwrite Price List. Pricing Rule rate is the final rate, so no further discount should be applied. Hence, in transactions like Sales Order, Purchase Order etc, it will be fetched in 'Rate' field, rather than 'Price List Rate' field."
+ )}
-
- {{__('Discount Percentage can be applied either against a Price List or for all Price List.')}}
+ ${__("Discount Percentage can be applied either against a Price List or for all Price List.")}
-
- {{__('To not apply Pricing Rule in a particular transaction, all applicable Pricing Rules should be disabled.')}}
+ ${__(
+ "To not apply Pricing Rule in a particular transaction, all applicable Pricing Rules should be disabled."
+ )}
|
- {{__('How Pricing Rule is applied?')}}
+ ${__("How Pricing Rule is applied?")}
-
- {{__("Pricing Rule is first selected based on 'Apply On' field, which can be Item, Item Group or Brand.")}}
+ ${__("Pricing Rule is first selected based on 'Apply On' field, which can be Item, Item Group or Brand.")}
-
- {{__("Then Pricing Rules are filtered out based on Customer, Customer Group, Territory, Supplier, Supplier Type, Campaign, Sales Partner etc.")}}
+ ${__(
+ "Then Pricing Rules are filtered out based on Customer, Customer Group, Territory, Supplier, Supplier Type, Campaign, Sales Partner etc."
+ )}
-
- {{__('Pricing Rules are further filtered based on quantity.')}}
+ ${__("Pricing Rules are further filtered based on quantity.")}
-
- {{__('If two or more Pricing Rules are found based on the above conditions, Priority is applied. Priority is a number between 0 to 20 while default value is zero (blank). Higher number means it will take precedence if there are multiple Pricing Rules with same conditions.')}}
+ ${__(
+ "If two or more Pricing Rules are found based on the above conditions, Priority is applied. Priority is a number between 0 to 20 while default value is zero (blank). Higher number means it will take precedence if there are multiple Pricing Rules with same conditions."
+ )}
-
- {{__('Even if there are multiple Pricing Rules with highest priority, then following internal priorities are applied:')}}
+ ${__(
+ "Even if there are multiple Pricing Rules with highest priority, then following internal priorities are applied:"
+ )}
-
- {{__('Item Code > Item Group > Brand')}}
+ ${__("Item Code > Item Group > Brand")}
-
- {{__('Customer > Customer Group > Territory')}}
+ ${__("Customer > Customer Group > Territory")}
-
- {{__('Supplier > Supplier Type')}}
+ ${__("Supplier > Supplier Type")}
-
- {{__('If multiple Pricing Rules continue to prevail, users are asked to set Priority manually to resolve conflict.')}}
+ ${__(
+ "If multiple Pricing Rules continue to prevail, users are asked to set Priority manually to resolve conflict."
+ )}
|
diff --git a/erpnext/accounts/doctype/process_subscription/process_subscription.py b/erpnext/accounts/doctype/process_subscription/process_subscription.py
index b4d18a3c0a8..0cc3fae58a8 100644
--- a/erpnext/accounts/doctype/process_subscription/process_subscription.py
+++ b/erpnext/accounts/doctype/process_subscription/process_subscription.py
@@ -3,7 +3,7 @@
import frappe
from frappe.model.document import Document
-from frappe.utils import getdate
+from frappe.utils import create_batch, getdate
from erpnext.accounts.doctype.subscription.subscription import DateTimeLikeObject, process_all
@@ -23,7 +23,23 @@ class ProcessSubscription(Document):
# end: auto-generated types
def on_submit(self):
- process_all(subscription=self.subscription, posting_date=self.posting_date)
+ self.process_all_subscription()
+
+ def process_all_subscription(self):
+ filters = {"status": ("!=", "Cancelled")}
+
+ if self.subscription:
+ filters["name"] = self.subscription
+
+ subscriptions = frappe.get_all("Subscription", filters, pluck="name")
+
+ for subscription in create_batch(subscriptions, 500):
+ frappe.enqueue(
+ method="erpnext.accounts.doctype.subscription.subscription.process_all",
+ queue="long",
+ subscription=subscription,
+ posting_date=self.posting_date,
+ )
def create_subscription_process(
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index 6979f93f95b..91b1ee1ffb4 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -322,6 +322,7 @@
"search_index": 1
},
{
+ "default": "Now",
"fieldname": "posting_time",
"fieldtype": "Time",
"label": "Posting Time",
@@ -1668,7 +1669,7 @@
"idx": 204,
"is_submittable": 1,
"links": [],
- "modified": "2025-07-30 23:16:05.722875",
+ "modified": "2025-08-04 19:19:11.380664",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index 45f0fc3c418..b925bcd2a44 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -373,6 +373,7 @@
"search_index": 1
},
{
+ "default": "Now",
"fieldname": "posting_time",
"fieldtype": "Time",
"hide_days": 1,
@@ -2232,7 +2233,7 @@
"link_fieldname": "consolidated_invoice"
}
],
- "modified": "2025-06-26 14:06:56.773552",
+ "modified": "2025-08-04 19:20:28.732039",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
diff --git a/erpnext/accounts/doctype/subscription/subscription.py b/erpnext/accounts/doctype/subscription/subscription.py
index 2a8cb7e777c..4770df89351 100644
--- a/erpnext/accounts/doctype/subscription/subscription.py
+++ b/erpnext/accounts/doctype/subscription/subscription.py
@@ -756,18 +756,14 @@ def get_prorata_factor(
return diff / plan_days
-def process_all(subscription: str | None = None, posting_date: DateTimeLikeObject | None = None) -> None:
+def process_all(subscription: list, posting_date: DateTimeLikeObject | None = None) -> None:
"""
Task to updates the status of all `Subscription` apart from those that are cancelled
"""
- filters = {"status": ("!=", "Cancelled")}
- if subscription:
- filters["name"] = subscription
-
- for subscription in frappe.get_all("Subscription", filters, pluck="name"):
+ for subscription_name in subscription:
try:
- subscription = frappe.get_doc("Subscription", subscription)
+ subscription = frappe.get_doc("Subscription", subscription_name)
subscription.process(posting_date)
frappe.db.commit()
except frappe.ValidationError:
diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.json b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.json
index 1f06ce4529d..7463e07db30 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.json
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.json
@@ -61,7 +61,7 @@
},
{
"default": "0",
- "description": "Even invoices with apply tax withholding unchecked will be considered for checking cumulative threshold breach",
+ "description": "Only payment entries with apply tax withholding unchecked will be considered for checking cumulative threshold breach",
"fieldname": "consider_party_ledger_amount",
"fieldtype": "Check",
"label": "Consider Entire Party Ledger Amount"
@@ -83,10 +83,11 @@
],
"index_web_pages_for_search": 1,
"links": [],
- "modified": "2024-03-27 13:10:52.531436",
+ "modified": "2025-07-30 07:13:51.785735",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Tax Withholding Category",
+ "naming_rule": "Set by user",
"owner": "Administrator",
"permissions": [
{
@@ -126,8 +127,9 @@
"write": 1
}
],
+ "row_format": "Dynamic",
"sort_field": "creation",
"sort_order": "DESC",
"states": [],
"track_changes": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js
index bb8f0f1af7a..46ce1933834 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.js
+++ b/erpnext/accounts/report/general_ledger/general_ledger.js
@@ -197,6 +197,11 @@ frappe.query_reports["General Ledger"] = {
label: __("Show Net Values in Party Account"),
fieldtype: "Check",
},
+ {
+ fieldname: "show_amount_in_company_currency",
+ label: __("Show Credit / Debit in Company Currency"),
+ fieldtype: "Check",
+ },
{
fieldname: "add_values_in_transaction_currency",
label: __("Add Columns in Transaction Currency"),
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py
index 8b98ee9499b..16d6661ddec 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/general_ledger.py
@@ -627,6 +627,18 @@ def get_columns(filters):
company = filters.get("company") or get_default_company()
filters["presentation_currency"] = currency = get_company_currency(company)
+ company_currency = get_company_currency(filters.get("company") or get_default_company())
+
+ if (
+ filters.get("show_amount_in_company_currency")
+ and filters["presentation_currency"] != company_currency
+ ):
+ frappe.throw(
+ _(
+ f'Presentation Currency cannot be {frappe.bold(filters["presentation_currency"])} , When {frappe.bold("Show Credit / Debit in Company Currency")} is enabled.'
+ )
+ )
+
columns = [
{
"label": _("GL Entry"),
diff --git a/erpnext/accounts/report/tax_withholding_details/tax_withholding_details.py b/erpnext/accounts/report/tax_withholding_details/tax_withholding_details.py
index d8012377743..2f557d01710 100644
--- a/erpnext/accounts/report/tax_withholding_details/tax_withholding_details.py
+++ b/erpnext/accounts/report/tax_withholding_details/tax_withholding_details.py
@@ -45,6 +45,7 @@ def get_result(filters, tds_docs, tds_accounts, tax_category_map, journal_entry_
gle_map = get_gle_map(tds_docs)
out = []
+ entries = {}
for name, details in gle_map.items():
for entry in details:
tax_amount, total_amount, grand_total, base_total = 0, 0, 0, 0
@@ -119,8 +120,13 @@ def get_result(filters, tds_docs, tds_accounts, tax_category_map, journal_entry_
"supplier_invoice_date": bill_date,
}
)
- out.append(row)
+ key = entry.voucher_no
+ if key in entries:
+ entries[key]["tax_amount"] += tax_amount
+ else:
+ entries[key] = row
+ out = list(entries.values())
out.sort(key=lambda x: (x["section_code"], x["transaction_date"]))
return out
diff --git a/erpnext/accounts/report/utils.py b/erpnext/accounts/report/utils.py
index 136a0acbbb0..523fa0e0ee3 100644
--- a/erpnext/accounts/report/utils.py
+++ b/erpnext/accounts/report/utils.py
@@ -118,7 +118,7 @@ def convert_to_presentation_currency(gl_entries, currency_info, filters=None):
len(account_currencies) == 1
and account_currency == presentation_currency
and not exchange_gain_or_loss
- ):
+ ) and not filters.get("show_amount_in_company_currency"):
entry["debit"] = debit_in_account_currency
entry["credit"] = credit_in_account_currency
else:
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index e1366c1c365..9c97f6e7187 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -2,6 +2,7 @@
# License: GNU General Public License v3. See license.txt
+from collections import defaultdict
from json import loads
from typing import TYPE_CHECKING, Optional
@@ -2451,25 +2452,37 @@ def sync_auto_reconcile_config(auto_reconciliation_job_trigger: int = 15):
).save()
+def get_link_fields_grouped_by_option(doctype):
+ meta = frappe.get_meta(doctype)
+ link_fields_map = defaultdict(list)
+
+ for df in meta.fields:
+ if df.fieldtype == "Link" and df.options and not df.ignore_user_permissions:
+ link_fields_map[df.options].append(df.fieldname)
+
+ return link_fields_map
+
+
def build_qb_match_conditions(doctype, user=None) -> list:
match_filters = build_match_conditions(doctype, user, False)
+ link_fields_map = get_link_fields_grouped_by_option(doctype)
criterion = []
apply_strict_user_permissions = frappe.get_system_settings("apply_strict_user_permissions")
if match_filters:
- from frappe import qb
-
_dt = qb.DocType(doctype)
for filter in match_filters:
- for d, names in filter.items():
- fieldname = d.lower().replace(" ", "_")
- field = _dt[fieldname]
+ for link_option, allowed_values in filter.items():
+ fieldnames = link_fields_map.get(link_option, [])
- cond = field.isin(names)
- if not apply_strict_user_permissions:
- cond = (Coalesce(field, "") == "") | field.isin(names)
+ for fieldname in fieldnames:
+ field = _dt[fieldname]
+ cond = field.isin(allowed_values)
- criterion.append(cond)
+ if not apply_strict_user_permissions:
+ cond = (Coalesce(field, "") == "") | cond
+
+ criterion.append(cond)
return criterion
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 291f4309d85..886c3cca41a 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -1106,7 +1106,7 @@ def make_journal_entry(asset_name):
je.voucher_type = "Depreciation Entry"
je.naming_series = depreciation_series
je.company = asset.company
- je.remark = f"Depreciation Entry against asset {asset_name}"
+ je.remark = _("Depreciation Entry against asset {0}").format(asset_name)
je.append(
"accounts",
diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py
index a4aaa25b88a..f1aceb5cbf9 100644
--- a/erpnext/assets/doctype/asset/depreciation.py
+++ b/erpnext/assets/doctype/asset/depreciation.py
@@ -249,7 +249,9 @@ def setup_journal_entry_metadata(je, depr_schedule_doc, depr_series, depr_schedu
je.posting_date = depr_schedule.schedule_date
je.company = asset.company
je.finance_book = depr_schedule_doc.finance_book
- je.remark = f"Depreciation Entry against {asset.name} worth {depr_schedule.depreciation_amount}"
+ je.remark = _("Depreciation Entry against {0} worth {1}").format(
+ asset.name, depr_schedule.depreciation_amount
+ )
def get_credit_and_debit_entry(
diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py
index 1750a2a782f..53146ed37e0 100644
--- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py
+++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py
@@ -86,8 +86,24 @@ class AssetDepreciationSchedule(DepreciationScheduleController):
)
def on_submit(self):
+ self.validate_asset()
self.db_set("status", "Active")
+ def validate_asset(self):
+ asset = frappe.get_doc("Asset", self.asset)
+ if not asset.calculate_depreciation:
+ frappe.throw(
+ _("Asset {0} is not set to calculate depreciation.").format(
+ get_link_to_form("Asset", self.asset)
+ )
+ )
+ if asset.docstatus != 1:
+ frappe.throw(
+ _("Asset {0} is not submitted. Please submit the asset before proceeding.").format(
+ get_link_to_form("Asset", self.asset)
+ )
+ )
+
def on_cancel(self):
self.db_set("status", "Cancelled")
if not self.flags.should_not_cancel_depreciation_entries:
@@ -96,6 +112,13 @@ class AssetDepreciationSchedule(DepreciationScheduleController):
def cancel_depreciation_entries(self):
for d in self.get("depreciation_schedule"):
if d.journal_entry:
+ je_status = frappe.db.get_value("Journal Entry", d.journal_entry, "docstatus")
+ if je_status == 0:
+ frappe.throw(
+ _(
+ "Cannot cancel Asset Depreciation Schedule {0} as it has a draft journal entry {1}."
+ ).format(self.name, d.journal_entry)
+ )
frappe.get_doc("Journal Entry", d.journal_entry).cancel()
def update_shift_depr_schedule(self):
diff --git a/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log_list.js b/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log_list.js
index 13f2444742d..20e98631de6 100644
--- a/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log_list.js
+++ b/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log_list.js
@@ -3,13 +3,13 @@ frappe.listview_settings["Asset Maintenance Log"] = {
has_indicator_for_draft: 1,
get_indicator: function (doc) {
if (doc.maintenance_status == "Planned") {
- return [__(doc.maintenance_status), "orange", "status,=," + doc.maintenance_status];
+ return [__(doc.maintenance_status), "orange", "maintenance_status,=," + doc.maintenance_status];
} else if (doc.maintenance_status == "Completed") {
- return [__(doc.maintenance_status), "green", "status,=," + doc.maintenance_status];
+ return [__(doc.maintenance_status), "green", "maintenance_status,=," + doc.maintenance_status];
} else if (doc.maintenance_status == "Cancelled") {
- return [__(doc.maintenance_status), "red", "status,=," + doc.maintenance_status];
+ return [__(doc.maintenance_status), "red", "maintenance_status,=," + doc.maintenance_status];
} else if (doc.maintenance_status == "Overdue") {
- return [__(doc.maintenance_status), "red", "status,=," + doc.maintenance_status];
+ return [__(doc.maintenance_status), "red", "maintenance_status,=," + doc.maintenance_status];
}
},
};
diff --git a/erpnext/buying/report/procurement_tracker/procurement_tracker.py b/erpnext/buying/report/procurement_tracker/procurement_tracker.py
index bd0798236b3..6f610d2dc20 100644
--- a/erpnext/buying/report/procurement_tracker/procurement_tracker.py
+++ b/erpnext/buying/report/procurement_tracker/procurement_tracker.py
@@ -51,7 +51,7 @@ def get_columns(filters):
},
{
"label": _("Requestor"),
- "options": "Employee",
+ "options": "User",
"fieldname": "requestor",
"fieldtype": "Link",
"width": 140,
diff --git a/erpnext/edi/doctype/code_list/code_list_import.py b/erpnext/edi/doctype/code_list/code_list_import.py
index fe250a1873c..3909eb22766 100644
--- a/erpnext/edi/doctype/code_list/code_list_import.py
+++ b/erpnext/edi/doctype/code_list/code_list_import.py
@@ -60,7 +60,7 @@ def import_genericode():
"doctype": "File",
"attached_to_doctype": "Code List",
"attached_to_name": code_list.name,
- "folder": "Home/Attachments",
+ "folder": frappe.db.get_value("File", {"is_attachments_folder": 1}),
"file_name": frappe.local.uploaded_filename,
"file_url": frappe.local.uploaded_file_url,
"is_private": 1,
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index f8e82f01085..977864feca7 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -427,7 +427,7 @@ erpnext.patches.v15_0.set_status_cancelled_on_cancelled_pos_opening_entry_and_po
erpnext.patches.v15_0.set_company_on_pos_inv_merge_log
erpnext.patches.v15_0.update_payment_ledger_entries_against_advance_doctypes
erpnext.patches.v15_0.rename_price_list_to_buying_price_list
-erpnext.patches.v15_0.repost_gl_entries_with_no_account_subcontracting #2025-07-31
+erpnext.patches.v15_0.repost_gl_entries_with_no_account_subcontracting #2025-08-04
erpnext.patches.v15_0.patch_missing_buying_price_list_in_material_request
erpnext.patches.v15_0.remove_sales_partner_from_consolidated_sales_invoice
erpnext.patches.v15_0.add_company_payment_gateway_account
diff --git a/erpnext/patches/v15_0/repost_gl_entries_with_no_account_subcontracting.py b/erpnext/patches/v15_0/repost_gl_entries_with_no_account_subcontracting.py
index e7394f1071c..0bb47973194 100644
--- a/erpnext/patches/v15_0/repost_gl_entries_with_no_account_subcontracting.py
+++ b/erpnext/patches/v15_0/repost_gl_entries_with_no_account_subcontracting.py
@@ -2,24 +2,31 @@ import frappe
def execute():
+ def cancel_incorrect_gl_entries(gl_entries):
+ table = frappe.qb.DocType("GL Entry")
+ frappe.qb.update(table).set(table.is_cancelled, 1).where(table.name.isin(gl_entries)).run()
+
+ def recreate_gl_entries(voucher_nos):
+ for doc in voucher_nos:
+ doc = frappe.get_doc("Subcontracting Receipt", doc)
+ for item in doc.supplied_items:
+ account, cost_center = frappe.db.get_values(
+ "Subcontracting Receipt Item", item.reference_name, ["expense_account", "cost_center"]
+ )[0]
+
+ if not item.expense_account:
+ item.db_set("expense_account", account)
+ if not item.cost_center:
+ item.db_set("cost_center", cost_center)
+
+ doc.make_gl_entries()
+
docs = frappe.get_all(
"GL Entry",
+ fields=["name", "voucher_no"],
filters={"voucher_type": "Subcontracting Receipt", "account": ["is", "not set"], "is_cancelled": 0},
- pluck="voucher_no",
)
- for doc in docs:
- doc = frappe.get_doc("Subcontracting Receipt", doc)
- for item in doc.supplied_items:
- account, cost_center = frappe.db.get_values(
- "Subcontracting Receipt Item", item.reference_name, ["expense_account", "cost_center"]
- )[0]
- if not item.expense_account:
- item.db_set("expense_account", account)
- if not item.cost_center:
- item.db_set("cost_center", cost_center)
-
- doc.docstatus = 2
- doc.make_gl_entries_on_cancel()
- doc.docstatus = 1
- doc.make_gl_entries()
+ if docs:
+ cancel_incorrect_gl_entries([d.name for d in docs])
+ recreate_gl_entries([d.voucher_no for d in docs])
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index a2b9ec1e7dc..125f2ca8b65 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -943,15 +943,10 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
this.frm.refresh_fields();
}
- async set_default_payment(total_amount_to_pay, update_paid_amount) {
+ set_default_payment(total_amount_to_pay, update_paid_amount) {
var me = this;
var payment_status = true;
if(this.frm.doc.is_pos && (update_paid_amount===undefined || update_paid_amount)) {
- let r = await frappe.db.get_value("POS Profile", this.frm.doc.pos_profile, "set_grand_total_to_default_mop");
-
- if (!r.message.set_grand_total_to_default_mop) {
- return;
- }
$.each(this.frm.doc['payments'] || [], function(index, data) {
if(data.default && payment_status && total_amount_to_pay > 0) {
diff --git a/erpnext/selling/page/point_of_sale/pos_payment.js b/erpnext/selling/page/point_of_sale/pos_payment.js
index 242a49b536b..5c4efff1dc5 100644
--- a/erpnext/selling/page/point_of_sale/pos_payment.js
+++ b/erpnext/selling/page/point_of_sale/pos_payment.js
@@ -450,10 +450,11 @@ erpnext.PointOfSale.Payment = class {
}
render_payment_section() {
+ this.grand_total_to_default_mop();
this.render_payment_mode_dom();
this.make_invoice_field_dialog();
this.update_totals_section();
- this.set_grand_total_to_default_mop();
+ this.focus_on_default_mop();
}
after_render() {
@@ -497,6 +498,17 @@ erpnext.PointOfSale.Payment = class {
}
}
+ grand_total_to_default_mop() {
+ if (this.set_gt_to_default_mop) return;
+ const doc = this.events.get_frm().doc;
+ const payments = doc.payments;
+ payments.forEach((p) => {
+ if (p.default) {
+ frappe.model.set_value(p.doctype, p.name, "amount", 0);
+ }
+ });
+ }
+
render_payment_mode_dom() {
const doc = this.events.get_frm().doc;
const payments = doc.payments;
@@ -557,6 +569,7 @@ erpnext.PointOfSale.Payment = class {
}
focus_on_default_mop() {
+ if (!this.set_gt_to_default_mop) return;
const doc = this.events.get_frm().doc;
const payments = doc.payments;
payments.forEach((p) => {
@@ -711,12 +724,6 @@ erpnext.PointOfSale.Payment = class {
.toLowerCase();
}
- set_grand_total_to_default_mop() {
- if (this.set_gt_to_default_mop) {
- this.focus_on_default_mop();
- }
- }
-
validate_reqd_invoice_fields() {
if (this.invoice_fields.length === 0) return true;
const doc = this.events.get_frm().doc;
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.json b/erpnext/stock/doctype/delivery_note/delivery_note.json
index 5574519c9dd..b17bc277b13 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.json
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.json
@@ -251,6 +251,7 @@
"width": "100px"
},
{
+ "default": "Now",
"fieldname": "posting_time",
"fieldtype": "Time",
"label": "Posting Time",
@@ -1415,7 +1416,7 @@
"idx": 146,
"is_submittable": 1,
"links": [],
- "modified": "2025-01-06 15:02:30.558756",
+ "modified": "2025-08-04 19:20:47.724218",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note",
@@ -1506,6 +1507,7 @@
"write": 1
}
],
+ "row_format": "Dynamic",
"search_fields": "status,customer,customer_name, territory,base_grand_total",
"show_name_in_global_search": 1,
"sort_field": "creation",
@@ -1515,4 +1517,4 @@
"title_field": "customer_name",
"track_changes": 1,
"track_seen": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index f6fa4673195..f3069276fb9 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -96,7 +96,6 @@ class DeliveryNote(SellingController):
per_billed: DF.Percent
per_installed: DF.Percent
per_returned: DF.Percent
- pick_list: DF.Link | None
plc_conversion_rate: DF.Float
po_date: DF.Date | None
po_no: DF.SmallText | None
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
index de4087c8610..b2d593475b7 100755
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
@@ -243,6 +243,7 @@
"width": "100px"
},
{
+ "default": "Now",
"fieldname": "posting_time",
"fieldtype": "Time",
"label": "Posting Time",
@@ -1290,7 +1291,7 @@
"idx": 261,
"is_submittable": 1,
"links": [],
- "modified": "2025-04-09 16:52:19.323878",
+ "modified": "2025-08-04 19:18:47.754957",
"modified_by": "Administrator",
"module": "Stock",
"name": "Purchase Receipt",
@@ -1360,4 +1361,4 @@
"timeline_field": "supplier",
"title_field": "title",
"track_changes": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.json b/erpnext/stock/doctype/stock_entry/stock_entry.json
index 8229d6dbd9b..5dcd3510837 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.json
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.json
@@ -218,6 +218,7 @@
"search_index": 1
},
{
+ "default": "Now",
"fieldname": "posting_time",
"fieldtype": "Time",
"label": "Posting Time",
@@ -697,7 +698,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2024-08-13 19:05:42.386955",
+ "modified": "2025-08-04 19:21:03.338958",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Entry",
@@ -763,6 +764,7 @@
"write": 1
}
],
+ "row_format": "Dynamic",
"search_fields": "posting_date, from_warehouse, to_warehouse, purpose, remarks",
"show_name_in_global_search": 1,
"sort_field": "creation",
@@ -770,4 +772,4 @@
"states": [],
"title_field": "stock_entry_type",
"track_changes": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.json b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.json
index 41cefee2659..d13dc83c513 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.json
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.json
@@ -72,6 +72,7 @@
"reqd": 1
},
{
+ "default": "Now",
"fieldname": "posting_time",
"fieldtype": "Time",
"in_list_view": 1,
@@ -183,7 +184,7 @@
"idx": 1,
"is_submittable": 1,
"links": [],
- "modified": "2024-03-27 13:10:44.699413",
+ "modified": "2025-08-04 19:21:20.179658",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Reconciliation",
@@ -203,9 +204,10 @@
"write": 1
}
],
+ "row_format": "Dynamic",
"search_fields": "posting_date",
"show_name_in_global_search": 1,
"sort_field": "creation",
"sort_order": "DESC",
"states": []
-}
\ No newline at end of file
+}