Merge pull request #51440 from rohitwaghchaure/rc-2

chore: v16 beta RC 2
This commit is contained in:
rohitwaghchaure
2026-01-01 19:01:53 +05:30
committed by GitHub
150 changed files with 24845 additions and 19682 deletions

View File

@@ -1,7 +1,7 @@
{
"chart_name": "Profit and Loss",
"chart_type": "Report",
"creation": "2020-07-17 11:25:34.448572",
"creation": "2025-04-01 20:38:16.986176",
"docstatus": 0,
"doctype": "Dashboard Chart",
"dynamic_filters_json": "{\"company\":\"frappe.defaults.get_user_default(\\\"Company\\\")\",\"from_fiscal_year\":\"erpnext.utils.get_fiscal_year()\",\"to_fiscal_year\":\"erpnext.utils.get_fiscal_year()\"}",
@@ -9,7 +9,7 @@
"idx": 0,
"is_public": 1,
"is_standard": 1,
"modified": "2023-07-19 13:08:56.470390",
"modified": "2025-12-19 12:37:31.673782",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Profit and Loss",
@@ -17,8 +17,9 @@
"owner": "Administrator",
"report_name": "Profit and Loss Statement",
"roles": [],
"show_values_over_chart": 1,
"timeseries": 0,
"type": "Bar",
"type": "Line",
"use_report_chart": 1,
"y_axis": []
}
}

View File

@@ -125,7 +125,7 @@ class BankClearance(Document):
)
msg += "</ul>"
frappe.throw(_(msg))
msgprint(_(msg))
return
if not entries_to_update:

View File

@@ -30,8 +30,7 @@
"label": "Payment Entry",
"oldfieldname": "voucher_id",
"oldfieldtype": "Link",
"options": "payment_document",
"width": "50"
"options": "payment_document"
},
{
"columns": 2,
@@ -69,7 +68,7 @@
"read_only": 1
},
{
"columns": 2,
"columns": 1,
"fieldname": "cheque_number",
"fieldtype": "Data",
"in_list_view": 1,
@@ -79,8 +78,10 @@
"read_only": 1
},
{
"columns": 2,
"fieldname": "cheque_date",
"fieldtype": "Date",
"in_list_view": 1,
"label": "Cheque Date",
"oldfieldname": "cheque_date",
"oldfieldtype": "Date",
@@ -96,17 +97,19 @@
"oldfieldtype": "Date"
}
],
"grid_page_length": 50,
"idx": 1,
"istable": 1,
"links": [],
"modified": "2024-03-27 13:06:37.609319",
"modified": "2025-12-17 14:33:45.913311",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bank Clearance Detail",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"row_format": "Dynamic",
"sort_field": "creation",
"sort_order": "ASC",
"states": []
}
}

View File

@@ -304,6 +304,7 @@ def create_payment_entry_bts(
project=None,
cost_center=None,
allow_edit=None,
company_bank_account=None,
):
# Create a new payment entry based on the bank transaction
bank_transaction = frappe.db.get_values(
@@ -345,6 +346,9 @@ def create_payment_entry_bts(
pe.project = project
pe.cost_center = cost_center
if company_bank_account:
pe.bank_account = company_bank_account
pe.validate()
if allow_edit:

View File

@@ -50,6 +50,9 @@ class BankTransaction(Document):
self.handle_excluded_fee()
self.update_allocated_amount()
def on_discard(self):
self.db_set("status", "Cancelled")
def validate(self):
self.validate_included_fee()
self.validate_duplicate_references()

View File

@@ -9,8 +9,8 @@ frappe.listview_settings["Invoice Discounting"] = {
return [__("Disbursed"), "blue", "status,=,Disbursed"];
} else if (doc.status == "Settled") {
return [__("Settled"), "orange", "status,=,Settled"];
} else if (doc.status == "Canceled") {
return [__("Canceled"), "red", "status,=,Canceled"];
} else if (doc.status == "Cancelled") {
return [__("Cancelled"), "red", "status,=,Cancelled"];
}
},
};

View File

@@ -427,7 +427,15 @@ frappe.ui.form.on("Payment Entry", {
if (frm.doc.payment_type == "Internal Transfer") {
$.each(
["party", "party_type", "paid_from", "paid_to", "references", "total_allocated_amount"],
[
"party",
"party_type",
"paid_from",
"paid_to",
"references",
"total_allocated_amount",
"party_name",
],
function (i, field) {
frm.set_value(field, null);
}

View File

@@ -100,7 +100,10 @@ class PaymentRequest(Document):
subscription_plans: DF.Table[SubscriptionPlanDetail]
swift_number: DF.ReadOnly | None
transaction_date: DF.Date | None
# end: auto-generated types
def on_discard(self):
self.db_set("status", "Cancelled")
def validate(self):
if self.get("__islocal"):

View File

@@ -35,7 +35,10 @@ class ProcessPaymentReconciliation(Document):
]
to_invoice_date: DF.Date | None
to_payment_date: DF.Date | None
# end: auto-generated types
def on_discard(self):
self.db_set("status", "Cancelled")
def validate(self):
self.validate_receivable_payable_account()

View File

@@ -36,7 +36,10 @@ class ProcessPeriodClosingVoucher(Document):
parent_pcv: DF.Link
status: DF.Literal["Queued", "Running", "Paused", "Completed", "Cancelled"]
z_opening_balances: DF.Table[ProcessPeriodClosingVoucherDetail]
# end: auto-generated types
def on_discard(self):
self.db_set("status", "Cancelled")
def validate(self):
self.status = "Queued"

View File

@@ -115,6 +115,10 @@ class RepostAccountingLedger(Document):
def generate_preview(self):
from erpnext.accounts.report.general_ledger.general_ledger import get_columns as get_gl_columns
if not self.vouchers:
frappe.msgprint(_("Add vouchers to generate preview."))
return
gl_columns = []
gl_data = []
@@ -142,6 +146,7 @@ class RepostAccountingLedger(Document):
account_repost_doc=self.name,
is_async=True,
job_name=job_name,
enqueue_after_commit=True,
)
frappe.msgprint(_("Repost has started in the background"))
else:

View File

@@ -25,7 +25,6 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
get_accounting_dimensions,
)
from erpnext.accounts.doctype.subscription_plan.subscription_plan import get_plan_rate
from erpnext.accounts.party import get_party_account_currency
class InvoiceCancelled(frappe.ValidationError):
@@ -432,7 +431,6 @@ class Subscription(Document):
items_list = self.get_items_from_plans(self.plans, is_prorate())
for item in items_list:
item["cost_center"] = self.cost_center
invoice.append("items", item)
# Taxes

View File

@@ -653,7 +653,7 @@ def reset_settings():
def create_subscription(**kwargs):
subscription = frappe.new_doc("Subscription")
subscription.party_type = (kwargs.get("party_type") or "Customer",)
subscription.party_type = kwargs.get("party_type") or "Customer"
subscription.company = kwargs.get("company") or "_Test Company"
subscription.party = kwargs.get("party") or "_Test Customer"
subscription.trial_period_start = kwargs.get("trial_period_start")

View File

@@ -1214,8 +1214,6 @@ class TestTaxWithholdingCategory(IntegrationTestCase):
# First invoice - below threshold, should be under withheld
pi = create_purchase_invoice(supplier="Test TDS Supplier6", rate=4000, do_not_save=True)
pi.apply_tds = 1
pi.tax_withholding_category = "Test Multi Invoice Category"
pi.save()
pi.submit()
invoices.append(pi)
@@ -1478,7 +1476,6 @@ class TestTaxWithholdingCategory(IntegrationTestCase):
pi = create_purchase_invoice(supplier="Test TDS Supplier6", rate=12000, do_not_save=True)
pi.apply_tds = 1
pi.tax_withholding_category = "Test Multi Invoice Category"
advances = pi.get_advance_entries()
pi.append(
"advances",
@@ -2096,7 +2093,6 @@ class TestTaxWithholdingCategory(IntegrationTestCase):
# Create purchase invoice that settles the payment entry
pi = create_purchase_invoice(supplier="Test TDS Supplier6", rate=8000, do_not_save=True)
pi.apply_tds = 1
pi.tax_withholding_category = "Test Multi Invoice Category"
advances = pi.get_advance_entries()
pi.append(
"advances",
@@ -2719,7 +2715,6 @@ class TestTaxWithholdingCategory(IntegrationTestCase):
# Create purchase invoice with manual override
pi = create_purchase_invoice(supplier="Test TDS Supplier6", rate=20000, do_not_save=True)
pi.apply_tds = 1
pi.tax_withholding_category = "Test Multi Invoice Category"
pi.ignore_tax_withholding_threshold = 1
pi.save()
@@ -2749,7 +2744,6 @@ class TestTaxWithholdingCategory(IntegrationTestCase):
# Step 2: Create Purchase Invoice with partial adjustment and manual rate change
pi = create_purchase_invoice(supplier="Test TDS Supplier8", rate=80000, do_not_save=True)
pi.tax_withholding_category = "Test Multi Invoice Category"
pi.override_tax_withholding_entries = 1 # Enable manual override
pi.tax_withholding_entries = []
@@ -2790,6 +2784,7 @@ class TestTaxWithholdingCategory(IntegrationTestCase):
)
pi.save()
pi.reload()
pi.submit()
# Step 3: Verify the tax withholding entries
@@ -2870,7 +2865,6 @@ class TestTaxWithholdingCategory(IntegrationTestCase):
# Step 2: Create Purchase Invoice with partial adjustment and manual rate change
pi = create_purchase_invoice(supplier="Test TDS Supplier8", rate=80000, do_not_save=True)
pi.tax_withholding_category = "Test Multi Invoice Category"
pi.override_tax_withholding_entries = 1 # Enable manual override
pi.tax_withholding_entries = []
@@ -2911,6 +2905,7 @@ class TestTaxWithholdingCategory(IntegrationTestCase):
)
pi.save()
pi.reload()
pi.submit()
# Step 3: Verify the tax withholding entries
@@ -2993,7 +2988,6 @@ class TestTaxWithholdingCategory(IntegrationTestCase):
self.validate_tax_withholding_entries("Payment Entry", pe.name, pe_expected)
pi = create_purchase_invoice(supplier="Test TDS Supplier8", rate=50000, do_not_save=True)
pi.tax_withholding_category = "Test Multi Invoice Category"
pi.override_tax_withholding_entries = 1
pi.tax_withholding_entries = []

View File

@@ -377,30 +377,23 @@ class TaxWithholdingController:
return category_names
def calculate(self):
# Always get category details first for account mapping
self.category_details = self._get_category_details()
self._update_taxable_amounts()
if not self.doc.override_tax_withholding_entries:
self._generate_withholding_entries()
# Final processing - entry status and tax_update
self._process_withholding_entries()
def _generate_withholding_entries(self):
# Clear existing entries
self.doc.tax_withholding_entries = []
# Calculate taxable amounts for each category
self._update_taxable_amounts()
# Apply threshold rules
self._evaluate_thresholds()
# Generate entries for each category
for category in self.category_details.values():
self.entries += self._create_entries_for_category(category)
# Add all generated entries to the document
self.doc.extend("tax_withholding_entries", self.entries)
def _create_entries_for_category(self, category):

View File

@@ -1063,3 +1063,21 @@ def add_party_account(party_type, party, company, account):
def render_address(address, check_permissions=True):
return frappe.call(_render_address, address, check_permissions=check_permissions)
def validate_party_currency_before_merging(party_type, old_party, new_party):
for company in frappe.get_all("Company"):
old_party_currency = get_party_gle_currency(party_type, old_party, company.name)
new_party_currency = get_party_gle_currency(party_type, new_party, company.name)
if old_party_currency and new_party_currency and old_party_currency != new_party_currency:
frappe.throw(
_(
"Cannot merge {0} '{1}' into '{2}' as both have existing accounting entries in different currencies for company '{3}'."
).format(
party_type,
old_party,
new_party,
company.name,
)
)

View File

@@ -6,7 +6,7 @@
"label": "Profit and Loss"
}
],
"content": "[{\"id\":\"nDhfcJYbKH\",\"type\":\"chart\",\"data\":{\"chart_name\":\"Profit and Loss\",\"col\":12}},{\"id\":\"VVvJ1lUcfc\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Total Outgoing Bills\",\"col\":3}},{\"id\":\"Vlj2FZtlHV\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Total Incoming Bills\",\"col\":3}},{\"id\":\"VVVjQVAhPf\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Total Incoming Payment\",\"col\":3}},{\"id\":\"DySNdlysIW\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Total Outgoing Payment\",\"col\":3}},{\"id\":\"tHb3yxthkR\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports &amp; Masters</b></span>\",\"col\":12}},{\"id\":\"DnNtsmxpty\",\"type\":\"card\",\"data\":{\"card_name\":\"Accounting Masters\",\"col\":4}},{\"id\":\"nKKr6fjgjb\",\"type\":\"card\",\"data\":{\"card_name\":\"Payments\",\"col\":4}},{\"id\":\"KlqilF5R_V\",\"type\":\"card\",\"data\":{\"card_name\":\"Tax Masters\",\"col\":4}},{\"id\":\"jTUy8LB0uw\",\"type\":\"card\",\"data\":{\"card_name\":\"Cost Center and Budgeting\",\"col\":4}},{\"id\":\"Wn2lhs7WLn\",\"type\":\"card\",\"data\":{\"card_name\":\"Multi Currency\",\"col\":4}},{\"id\":\"PAQMqqNkBM\",\"type\":\"card\",\"data\":{\"card_name\":\"Banking\",\"col\":4}},{\"id\":\"kxhoaiqdLq\",\"type\":\"card\",\"data\":{\"card_name\":\"Opening and Closing\",\"col\":4}},{\"id\":\"q0MAlU2j_Z\",\"type\":\"card\",\"data\":{\"card_name\":\"Subscription Management\",\"col\":4}},{\"id\":\"ptm7T6Hwu-\",\"type\":\"card\",\"data\":{\"card_name\":\"Share Management\",\"col\":4}}]",
"content": "[{\"id\":\"nDhfcJYbKH\",\"type\":\"chart\",\"data\":{\"chart_name\":\"Profit and Loss\",\"col\":12}},{\"id\":\"VVvJ1lUcfc\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Outgoing Bills\",\"col\":3}},{\"id\":\"Vlj2FZtlHV\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Incoming Bills\",\"col\":3}},{\"id\":\"VVVjQVAhPf\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Incoming Payment\",\"col\":3}},{\"id\":\"DySNdlysIW\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Outgoing Payment\",\"col\":3}},{\"id\":\"tHb3yxthkR\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports &amp; Masters</b></span>\",\"col\":12}},{\"id\":\"DnNtsmxpty\",\"type\":\"card\",\"data\":{\"card_name\":\"Accounting Masters\",\"col\":4}},{\"id\":\"nKKr6fjgjb\",\"type\":\"card\",\"data\":{\"card_name\":\"Payments\",\"col\":4}},{\"id\":\"KlqilF5R_V\",\"type\":\"card\",\"data\":{\"card_name\":\"Tax Masters\",\"col\":4}},{\"id\":\"jTUy8LB0uw\",\"type\":\"card\",\"data\":{\"card_name\":\"Cost Center and Budgeting\",\"col\":4}},{\"id\":\"Wn2lhs7WLn\",\"type\":\"card\",\"data\":{\"card_name\":\"Multi Currency\",\"col\":4}},{\"id\":\"PAQMqqNkBM\",\"type\":\"card\",\"data\":{\"card_name\":\"Banking\",\"col\":4}},{\"id\":\"kxhoaiqdLq\",\"type\":\"card\",\"data\":{\"card_name\":\"Opening and Closing\",\"col\":4}},{\"id\":\"q0MAlU2j_Z\",\"type\":\"card\",\"data\":{\"card_name\":\"Subscription Management\",\"col\":4}},{\"id\":\"ptm7T6Hwu-\",\"type\":\"card\",\"data\":{\"card_name\":\"Share Management\",\"col\":4}}]",
"creation": "2020-03-02 15:41:59.515192",
"custom_blocks": [],
"docstatus": 0,
@@ -14,7 +14,7 @@
"for_user": "",
"hide_custom": 0,
"icon": "accounting",
"idx": 0,
"idx": 3,
"indicator_color": "",
"is_hidden": 0,
"label": "Accounting",
@@ -587,25 +587,25 @@
"type": "Link"
}
],
"modified": "2025-11-17 14:35:00.910131",
"modified": "2025-12-24 13:20:34.857205",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounting",
"number_cards": [
{
"label": "Total Outgoing Bills",
"label": "Outgoing Bills",
"number_card_name": "Total Outgoing Bills"
},
{
"label": "Total Incoming Bills",
"label": "Incoming Bills",
"number_card_name": "Total Incoming Bills"
},
{
"label": "Total Incoming Payment",
"label": "Incoming Payment",
"number_card_name": "Total Incoming Payment"
},
{
"label": "Total Outgoing Payment",
"label": "Outgoing Payment",
"number_card_name": "Total Outgoing Payment"
}
],

View File

@@ -1,13 +1,19 @@
{
"charts": [],
"content": "[{\"id\":\"nKKr6fjgjb\",\"type\":\"card\",\"data\":{\"card_name\":\"Ledgers\",\"col\":4}},{\"id\":\"p7NY6MHe2Y\",\"type\":\"card\",\"data\":{\"card_name\":\"Financial Statements\",\"col\":4}},{\"id\":\"3AK1Zf0oew\",\"type\":\"card\",\"data\":{\"card_name\":\"Profitability\",\"col\":4}},{\"id\":\"Q_hBCnSeJY\",\"type\":\"card\",\"data\":{\"card_name\":\"Other Reports\",\"col\":4}}]",
"app": "erpnext",
"charts": [
{
"chart_name": "Profit and Loss",
"label": "Profit and Loss"
}
],
"content": "[{\"id\":\"tS7ZWzC24I\",\"type\":\"chart\",\"data\":{\"chart_name\":\"Profit and Loss\",\"col\":12}},{\"id\":\"8Ej2KxPxOt\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"p7NY6MHe2Y\",\"type\":\"card\",\"data\":{\"card_name\":\"Financial Statements\",\"col\":4}},{\"id\":\"nKKr6fjgjb\",\"type\":\"card\",\"data\":{\"card_name\":\"Ledgers\",\"col\":4}},{\"id\":\"3AK1Zf0oew\",\"type\":\"card\",\"data\":{\"card_name\":\"Profitability\",\"col\":4}},{\"id\":\"Q_hBCnSeJY\",\"type\":\"card\",\"data\":{\"card_name\":\"Other Reports\",\"col\":4}}]",
"creation": "2024-01-05 16:09:16.766939",
"custom_blocks": [],
"docstatus": 0,
"doctype": "Workspace",
"for_user": "",
"hide_custom": 0,
"icon": "file",
"icon": "table",
"idx": 0,
"indicator_color": "",
"is_hidden": 0,
@@ -260,7 +266,7 @@
"type": "Link"
}
],
"modified": "2024-01-18 22:13:07.596844",
"modified": "2025-12-24 12:49:25.266357",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Financial Reports",
@@ -273,5 +279,6 @@
"roles": [],
"sequence_id": 5.0,
"shortcuts": [],
"title": "Financial Reports"
}
"title": "Financial Reports",
"type": "Workspace"
}

View File

@@ -1,204 +0,0 @@
{
"charts": [],
"content": "[{\"id\":\"rMMsfn2eB4\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Shortcuts</b></span>\",\"col\":12}},{\"id\":\"G984SgVRJN\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Purchase Invoice\",\"col\":3}},{\"id\":\"F9f4I1viNr\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Payment Entry\",\"col\":3}},{\"id\":\"1ArNvt9qhz\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Journal Entry\",\"col\":3}},{\"id\":\"4IBBOIxfqW\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Accounts Payable\",\"col\":3}},{\"id\":\"B7-uxs8tkU\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"jAcOH-cC-Q\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports &amp; Masters</b></span>\",\"col\":12}},{\"id\":\"7dj93PEUjW\",\"type\":\"card\",\"data\":{\"card_name\":\"Invoicing\",\"col\":4}},{\"id\":\"_Cb7C8XdJJ\",\"type\":\"card\",\"data\":{\"card_name\":\"Payments\",\"col\":4}},{\"id\":\"9yseIkdG50\",\"type\":\"card\",\"data\":{\"card_name\":\"Reports\",\"col\":4}}]",
"creation": "2024-01-05 15:29:11.144373",
"custom_blocks": [],
"docstatus": 0,
"doctype": "Workspace",
"for_user": "",
"hide_custom": 0,
"icon": "arrow-left",
"idx": 0,
"indicator_color": "",
"is_hidden": 0,
"label": "Payables",
"links": [
{
"hidden": 0,
"is_query_report": 0,
"label": "Invoicing",
"link_count": 2,
"link_type": "DocType",
"onboard": 0,
"type": "Card Break"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Purchase Invoice",
"link_count": 0,
"link_to": "Purchase Invoice",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Supplier",
"link_count": 0,
"link_to": "Supplier",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Payments",
"link_count": 3,
"link_type": "DocType",
"onboard": 0,
"type": "Card Break"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Payment Entry",
"link_count": 0,
"link_to": "Payment Entry",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Journal Entry",
"link_count": 0,
"link_to": "Journal Entry",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Payment Reconciliation",
"link_count": 0,
"link_to": "Payment Reconciliation",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Reports",
"link_count": 7,
"link_type": "DocType",
"onboard": 0,
"type": "Card Break"
},
{
"hidden": 0,
"is_query_report": 1,
"label": "Accounts Payable",
"link_count": 0,
"link_to": "Accounts Payable",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 1,
"label": "Accounts Payable Summary",
"link_count": 0,
"link_to": "Accounts Payable Summary",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 1,
"label": "Purchase Register",
"link_count": 0,
"link_to": "Purchase Register",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 1,
"label": "Item-wise Purchase Register",
"link_count": 0,
"link_to": "Item-wise Purchase Register",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 1,
"label": "Purchase Order Analysis",
"link_count": 0,
"link_to": "Purchase Order Analysis",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 1,
"label": "Received Items To Be Billed",
"link_count": 0,
"link_to": "Received Items To Be Billed",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 1,
"label": "Supplier Ledger Summary",
"link_count": 0,
"link_to": "Supplier Ledger Summary",
"link_type": "Report",
"onboard": 0,
"type": "Link"
}
],
"modified": "2024-01-18 22:09:46.221549",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payables",
"number_cards": [],
"owner": "Administrator",
"parent_page": "Accounting",
"public": 1,
"quick_lists": [],
"restrict_to_domain": "",
"roles": [],
"sequence_id": 3.0,
"shortcuts": [
{
"doc_view": "",
"label": "Accounts Payable",
"link_to": "Accounts Payable",
"type": "Report"
},
{
"doc_view": "",
"label": "Purchase Invoice",
"link_to": "Purchase Invoice",
"type": "DocType"
},
{
"doc_view": "",
"label": "Journal Entry",
"link_to": "Journal Entry",
"type": "DocType"
},
{
"doc_view": "",
"label": "Payment Entry",
"link_to": "Payment Entry",
"type": "DocType"
}
],
"title": "Payables"
}

View File

@@ -1,254 +0,0 @@
{
"charts": [],
"content": "[{\"id\":\"vikWSkNm6_\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Shortcuts</b></span>\",\"col\":12}},{\"id\":\"G984SgVRJN\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Invoice\",\"col\":3}},{\"id\":\"5yHldR0JNk\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"POS Invoice\",\"col\":3}},{\"id\":\"F9f4I1viNr\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Payment Entry\",\"col\":3}},{\"id\":\"1ArNvt9qhz\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Journal Entry\",\"col\":3}},{\"id\":\"4IBBOIxfqW\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Accounts Receivable\",\"col\":3}},{\"id\":\"ILlIxJuexy\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Cost Center\",\"col\":3}},{\"id\":\"B7-uxs8tkU\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"tHb3yxthkR\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports &amp; Masters</b></span>\",\"col\":12}},{\"id\":\"jLgv00c6ek\",\"type\":\"card\",\"data\":{\"card_name\":\"Invoicing\",\"col\":4}},{\"id\":\"npwfXlz0u1\",\"type\":\"card\",\"data\":{\"card_name\":\"Payments\",\"col\":4}},{\"id\":\"am70C27Jrb\",\"type\":\"card\",\"data\":{\"card_name\":\"Dunning\",\"col\":4}},{\"id\":\"xOHTyD8b5l\",\"type\":\"card\",\"data\":{\"card_name\":\"Reports\",\"col\":4}}]",
"creation": "2024-01-05 15:29:21.084241",
"custom_blocks": [],
"docstatus": 0,
"doctype": "Workspace",
"for_user": "",
"hide_custom": 0,
"icon": "arrow-right",
"idx": 0,
"indicator_color": "",
"is_hidden": 0,
"label": "Receivables",
"links": [
{
"hidden": 0,
"is_query_report": 0,
"label": "Invoicing",
"link_count": 2,
"link_type": "DocType",
"onboard": 0,
"type": "Card Break"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Sales Invoice",
"link_count": 0,
"link_to": "Sales Invoice",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Customer",
"link_count": 0,
"link_to": "Customer",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Payments",
"link_count": 4,
"link_type": "DocType",
"onboard": 0,
"type": "Card Break"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Payment Entry",
"link_count": 0,
"link_to": "Payment Entry",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Payment Request",
"link_count": 0,
"link_to": "Payment Request",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Payment Reconciliation",
"link_count": 0,
"link_to": "Payment Reconciliation",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Payment Gateway Account",
"link_count": 0,
"link_to": "Payment Gateway Account",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Dunning",
"link_count": 2,
"link_type": "DocType",
"onboard": 0,
"type": "Card Break"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Dunning",
"link_count": 0,
"link_to": "Dunning",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Dunning Type",
"link_count": 0,
"link_to": "Dunning Type",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Reports",
"link_count": 6,
"link_type": "DocType",
"onboard": 0,
"type": "Card Break"
},
{
"dependencies": "Sales Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Accounts Receivable",
"link_count": 0,
"link_to": "Accounts Receivable",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Sales Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Accounts Receivable Summary",
"link_count": 0,
"link_to": "Accounts Receivable Summary",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Sales Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Sales Register",
"link_count": 0,
"link_to": "Sales Register",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Sales Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Item-wise Sales Register",
"link_count": 0,
"link_to": "Item-wise Sales Register",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Sales Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Sales Order Analysis",
"link_count": 0,
"link_to": "Sales Order Analysis",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Sales Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Delivered Items To Be Billed",
"link_count": 0,
"link_to": "Delivered Items To Be Billed",
"link_type": "Report",
"onboard": 0,
"type": "Link"
}
],
"modified": "2024-01-18 22:11:51.474477",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Receivables",
"number_cards": [],
"owner": "Administrator",
"parent_page": "Accounting",
"public": 1,
"quick_lists": [],
"restrict_to_domain": "",
"roles": [],
"sequence_id": 4.0,
"shortcuts": [
{
"color": "Grey",
"doc_view": "List",
"label": "POS Invoice",
"link_to": "POS Invoice",
"stats_filter": "[]",
"type": "DocType"
},
{
"color": "Grey",
"doc_view": "List",
"label": "Cost Center",
"link_to": "Cost Center",
"type": "DocType"
},
{
"doc_view": "",
"label": "Sales Invoice",
"link_to": "Sales Invoice",
"stats_filter": "[]",
"type": "DocType"
},
{
"doc_view": "",
"label": "Journal Entry",
"link_to": "Journal Entry",
"type": "DocType"
},
{
"doc_view": "",
"label": "Payment Entry",
"link_to": "Payment Entry",
"type": "DocType"
},
{
"doc_view": "",
"label": "Accounts Receivable",
"link_to": "Accounts Receivable",
"type": "Report"
}
],
"title": "Receivables"
}

View File

@@ -1,11 +1,12 @@
{
"app": "erpnext",
"charts": [
{
"chart_name": "Asset Value Analytics",
"label": "Asset Value Analytics"
}
],
"content": "[{\"type\":\"onboarding\",\"data\":{\"onboarding_name\":\"Assets\",\"col\":12}},{\"type\":\"chart\",\"data\":{\"chart_name\":\"Asset Value Analytics\",\"col\":12}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Your Shortcuts</b></span>\",\"col\":12}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Asset\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Asset Category\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Fixed Asset Register\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Dashboard\",\"col\":3}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports & Masters</b></span>\",\"col\":12}},{\"type\":\"card\",\"data\":{\"card_name\":\"Assets\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Maintenance\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Reports\",\"col\":4}}]",
"content": "[{\"id\":\"Q-Cl7bMXDm\",\"type\":\"chart\",\"data\":{\"chart_name\":\"Asset Value Analytics\",\"col\":12}},{\"id\":\"gsSQjvl0Tx\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"xRYRq1sW1O\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports &amp; Masters</b></span>\",\"col\":12}},{\"id\":\"Kx2j5N9BKZ\",\"type\":\"card\",\"data\":{\"card_name\":\"Assets\",\"col\":4}},{\"id\":\"jeNsxtLaH3\",\"type\":\"card\",\"data\":{\"card_name\":\"Maintenance\",\"col\":4}},{\"id\":\"EX5e3NvL51\",\"type\":\"card\",\"data\":{\"card_name\":\"Reports\",\"col\":4}}]",
"creation": "2020-03-02 15:43:27.634865",
"custom_blocks": [],
"docstatus": 0,
@@ -182,6 +183,7 @@
"link_to": "Asset Maintenance",
"link_type": "Report",
"onboard": 0,
"report_ref_doctype": "Asset Maintenance",
"type": "Link"
},
{
@@ -193,10 +195,11 @@
"link_to": "Asset Activity",
"link_type": "Report",
"onboard": 0,
"report_ref_doctype": "Asset Activity",
"type": "Link"
}
],
"modified": "2024-01-05 17:40:34.570041",
"modified": "2025-12-31 16:22:38.132729",
"modified_by": "Administrator",
"module": "Assets",
"name": "Assets",
@@ -208,27 +211,7 @@
"restrict_to_domain": "",
"roles": [],
"sequence_id": 7.0,
"shortcuts": [
{
"label": "Asset",
"link_to": "Asset",
"type": "DocType"
},
{
"label": "Asset Category",
"link_to": "Asset Category",
"type": "DocType"
},
{
"label": "Fixed Asset Register",
"link_to": "Fixed Asset Register",
"type": "Report"
},
{
"label": "Dashboard",
"link_to": "Asset",
"type": "Dashboard"
}
],
"title": "Assets"
}
"shortcuts": [],
"title": "Assets",
"type": "Workspace"
}

View File

@@ -248,6 +248,23 @@ frappe.ui.form.on("Request for Quotation", {
}
refresh_field("items");
},
email_template(frm) {
if (frm.doc.email_template) {
frappe.db
.get_value("Email Template", frm.doc.email_template, [
"use_html",
"response",
"response_html",
])
.then((r) => {
frm.set_value(
"message_for_supplier",
r.message.use_html ? r.message.response_html : r.message.response
);
});
}
},
preview: (frm) => {
let dialog = new frappe.ui.Dialog({
title: __("Preview Email"),

View File

@@ -139,8 +139,6 @@
},
{
"allow_on_submit": 1,
"fetch_from": "email_template.response",
"fetch_if_empty": 1,
"fieldname": "message_for_supplier",
"fieldtype": "Text Editor",
"in_list_view": 1,
@@ -322,7 +320,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2025-03-03 16:48:39.856779",
"modified": "2025-12-29 14:44:18.934901",
"modified_by": "Administrator",
"module": "Buying",
"name": "Request for Quotation",
@@ -393,4 +391,4 @@
"sort_field": "creation",
"sort_order": "DESC",
"states": []
}
}

View File

@@ -66,6 +66,7 @@ class RequestforQuotation(BuyingController):
def before_validate(self):
self.set_has_unit_price_items()
self.flags.allow_zero_qty = self.has_unit_price_items
self.set_message_for_supplier()
def validate(self):
self.validate_duplicate_supplier()
@@ -90,6 +91,13 @@ class RequestforQuotation(BuyingController):
not row.qty for row in self.get("items") if (row.item_code and not row.qty)
)
def set_message_for_supplier(self):
if self.email_template and not self.message_for_supplier:
data = frappe.get_value(
"Email Template", self.email_template, ["use_html", "response", "response_html"], as_dict=True
)
self.message_for_supplier = data.response_html if data.use_html else data.response
def validate_duplicate_supplier(self):
supplier_list = [d.supplier for d in self.suppliers]
if len(supplier_list) != len(set(supplier_list)):

View File

@@ -14,6 +14,7 @@ from frappe.model.naming import set_name_by_naming_series, set_name_from_naming_
from erpnext.accounts.party import (
get_dashboard_info,
validate_party_accounts,
validate_party_currency_before_merging,
)
from erpnext.controllers.website_list_for_contact import add_role_for_portal_user
from erpnext.utilities.transaction_base import TransactionBase
@@ -213,6 +214,10 @@ class Supplier(TransactionBase):
delete_contact_and_address("Supplier", self.name)
def before_rename(self, olddn, newdn, merge=False):
if merge:
validate_party_currency_before_merging("Supplier", olddn, newdn)
def after_rename(self, olddn, newdn, merge=False):
if frappe.defaults.get_global_default("supp_master_name") == "Supplier Name":
self.db_set("supplier_name", newdn)

View File

@@ -45,7 +45,7 @@ class SupplierScorecardCriteria(Document):
mylist = re.finditer(regex, test_formula, re.MULTILINE | re.DOTALL)
for _dummy1, match in enumerate(mylist):
for _dummy2 in range(0, len(match.groups())):
test_formula = test_formula.replace("{" + match.group(1) + "}", "0")
test_formula = test_formula.replace("{" + match.group(1) + "}", "1")
try:
frappe.safe_eval(test_formula, None, {"max": max, "min": min})

View File

@@ -17,7 +17,6 @@ class TestSupplierScorecardCriteria(IntegrationTestCase):
def test_formula_validate(self):
delete_test_scorecards()
self.assertRaises(frappe.ValidationError, frappe.get_doc(test_bad_criteria[1]).insert)
self.assertRaises(frappe.ValidationError, frappe.get_doc(test_bad_criteria[2]).insert)
def delete_test_scorecards():
@@ -68,16 +67,8 @@ test_bad_criteria = [
"name": "Fake Criteria 2",
"weight": 40.0,
"doctype": "Supplier Scorecard Criteria",
"formula": "(({cost_of_on_time_shipments} / {tot_cost_shipments}))* 100", # Force 0 divided by 0
"formula": "(({cost_of_on_time_shipments} {cost_of_on_time_shipments} / {tot_cost_shipments}))* 100", # Two variables beside eachother
"criteria_name": "Fake Criteria 2",
"max_score": 100.0,
},
{
"name": "Fake Criteria 3",
"weight": 40.0,
"doctype": "Supplier Scorecard Criteria",
"formula": "(({cost_of_on_time_shipments} {cost_of_on_time_shipments} / {tot_cost_shipments}))* 100", # Two variables beside eachother
"criteria_name": "Fake Criteria 3",
"max_score": 100.0,
},
]

View File

@@ -188,7 +188,7 @@ def find_variant(template, args, variant_item_code=None):
for attribute, value in args.items():
for row in variant.attributes:
if row.attribute == attribute and row.attribute_value == cstr(value):
if row.attribute == _(attribute) and row.attribute_value == cstr(value):
# this row matches
match_count += 1
break
@@ -209,7 +209,7 @@ def create_variant(item, args, use_template_image=False):
variant_attributes = []
for d in template.attributes:
variant_attributes.append({"attribute": d.attribute, "attribute_value": args.get(d.attribute)})
variant_attributes.append({"attribute": d.attribute, "attribute_value": args.get(_(d.attribute))})
variant.set("attributes", variant_attributes)
copy_attributes_to_variant(template, variant)

View File

@@ -1022,10 +1022,19 @@ class SellingController(StockController):
def set_default_income_account_for_item(obj):
for d in obj.get("items"):
if d.item_code:
if getattr(d, "income_account", None):
set_item_default(d.item_code, obj.company, "income_account", d.income_account)
"""Set income account as default for items in the transaction.
Updates the item default income account for each item in the transaction
if it differs from the company's default income account.
Args:
obj: Transaction document containing items table with income_account field
"""
company_default = frappe.get_cached_value("Company", obj.company, "default_income_account")
for d in obj.get("items", default=[]):
income_account = getattr(d, "income_account", None)
if d.item_code and income_account and income_account != company_default:
set_item_default(d.item_code, obj.company, "income_account", income_account)
def get_serial_and_batch_bundle(child, parent, delivery_note_child=None):

View File

@@ -184,6 +184,9 @@ class StatusUpdater(Document):
Installation Note: Update Installed Qty, Update Percent Qty and Validate over installation
"""
def on_discard(self):
self.db_set("status", "Cancelled")
def update_prevdoc_status(self):
self.update_qty()
self.validate_qty()

View File

@@ -1401,6 +1401,7 @@ def make_rm_stock_entry(
stock_entry.set_stock_entry_type()
over_transfer_allowance = frappe.get_single_value("Buying Settings", "over_transfer_allowance")
for fg_item_code in fg_item_code_list:
for rm_item in rm_items:
if (
@@ -1408,14 +1409,27 @@ def make_rm_stock_entry(
or rm_item.get("item_code") == fg_item_code
):
rm_item_code = rm_item.get("rm_item_code")
qty = rm_item.get("qty") or max(
rm_item.get("required_qty") - rm_item.get("total_supplied_qty"), 0
)
if qty <= 0 and rm_item.get("total_supplied_qty"):
per_transferred = (
flt(
rm_item.get("total_supplied_qty") / rm_item.get("required_qty"),
frappe.db.get_default("float_precision"),
)
* 100
)
if per_transferred >= 100 + over_transfer_allowance:
continue
items_dict = {
rm_item_code: {
rm_detail_field: rm_item.get("name"),
"item_name": rm_item.get("item_name")
or item_wh.get(rm_item_code, {}).get("item_name", ""),
"description": item_wh.get(rm_item_code, {}).get("description", ""),
"qty": rm_item.get("qty")
or max(rm_item.get("required_qty") - rm_item.get("total_supplied_qty"), 0),
"qty": qty,
"from_warehouse": rm_item.get("warehouse")
or rm_item.get("reserve_warehouse"),
"to_warehouse": subcontract_order.supplier_warehouse,

View File

@@ -85,7 +85,7 @@
"in_standard_filter": 1,
"label": "Status",
"no_copy": 1,
"options": "Unsigned\nActive\nInactive"
"options": "Unsigned\nActive\nInactive\nCancelled"
},
{
"allow_on_submit": 1,
@@ -257,11 +257,11 @@
"grid_page_length": 50,
"is_submittable": 1,
"links": [],
"modified": "2025-06-19 17:48:45.049007",
"modified": "2025-12-24 21:33:51.240497",
"modified_by": "Administrator",
"module": "CRM",
"name": "Contract",
"naming_rule": "Expression (old style)",
"naming_rule": "Expression",
"owner": "Administrator",
"permissions": [
{

View File

@@ -43,7 +43,7 @@ class Contract(Document):
signed_on: DF.Datetime | None
signee: DF.Data | None
start_date: DF.Date | None
status: DF.Literal["Unsigned", "Active", "Inactive"]
status: DF.Literal["Unsigned", "Active", "Inactive", "Cancelled"]
# end: auto-generated types
def validate(self):
@@ -61,6 +61,9 @@ class Contract(Document):
def before_submit(self):
self.signed_by_company = frappe.session.user
def on_discard(self):
self.db_set("status", "Cancelled")
def before_update_after_submit(self):
self.update_contract_status()
self.update_fulfilment_status()

View File

@@ -1,6 +1,6 @@
{
"app": "erpnext",
"creation": "2025-11-17 13:19:04.309749",
"creation": "2025-11-17 20:55:11.854086",
"docstatus": 0,
"doctype": "Desktop Icon",
"hidden": 0,
@@ -10,7 +10,7 @@
"label": "Accounting",
"link_to": "Accounting",
"link_type": "Workspace",
"modified": "2025-11-17 13:33:35.788242",
"modified": "2025-12-31 16:06:04.678577",
"modified_by": "Administrator",
"name": "Accounting",
"owner": "Administrator",

View File

@@ -1,21 +1,20 @@
{
"app": "erpnext",
"creation": "2025-11-17 13:19:04.299276",
"creation": "2025-11-17 20:55:11.845676",
"docstatus": 0,
"doctype": "Desktop Icon",
"hidden": 0,
"icon": "assets",
"icon_type": "Link",
"idx": 8,
"idx": 1,
"label": "Assets",
"link_to": "Assets",
"link_type": "Workspace",
"logo_url": "/assets/erpnext/desktop_icons/asset.svg",
"modified": "2025-11-17 17:41:41.635533",
"modified": "2025-12-22 13:07:02.129228",
"modified_by": "Administrator",
"name": "Assets",
"owner": "Administrator",
"parent_icon": "",
"parent_icon": "ERPNext",
"roles": [],
"standard": 1
}

View File

@@ -8,9 +8,9 @@
"icon_type": "Link",
"idx": 5,
"label": "Banking",
"link_to": "Bank Reconciliation Tool",
"link_to": "Bank Clearance",
"link_type": "DocType",
"modified": "2025-11-19 15:57:20.139306",
"modified": "2025-12-22 16:53:37.020794",
"modified_by": "Administrator",
"name": "Banking",
"owner": "Administrator",

View File

@@ -1,21 +1,20 @@
{
"app": "erpnext",
"creation": "2025-11-17 13:19:04.327790",
"creation": "2025-11-17 20:55:11.868134",
"docstatus": 0,
"doctype": "Desktop Icon",
"hidden": 0,
"icon": "buying",
"icon_type": "Link",
"idx": 3,
"idx": 1,
"label": "Buying",
"link_to": "Buying",
"link_type": "Workspace",
"logo_url": "/assets/erpnext/desktop_icons/buying.svg",
"modified": "2025-11-17 17:38:19.203107",
"modified": "2025-12-22 13:06:55.022406",
"modified_by": "Administrator",
"name": "Buying",
"owner": "Administrator",
"parent_icon": "",
"parent_icon": "ERPNext",
"roles": [],
"standard": 1
}

View File

@@ -1,21 +1,20 @@
{
"app": "erpnext",
"creation": "2025-11-17 13:19:04.340610",
"creation": "2025-11-17 20:55:11.876996",
"docstatus": 0,
"doctype": "Desktop Icon",
"hidden": 0,
"icon": "crm",
"icon_type": "Link",
"idx": 7,
"idx": 1,
"label": "CRM",
"link_to": "CRM",
"link_type": "Workspace",
"logo_url": "/assets/erpnext/desktop_icons/crm.svg",
"modified": "2025-11-17 19:39:59.734778",
"modified": "2025-12-22 13:06:47.900639",
"modified_by": "Administrator",
"name": "CRM",
"owner": "Administrator",
"parent_icon": "",
"parent_icon": "ERPNext",
"roles": [],
"standard": 1
}

View File

@@ -1,20 +1,21 @@
{
"app": "erpnext",
"creation": "2025-11-05 12:11:24.655043",
"creation": "2025-11-17 20:55:11.772622",
"docstatus": 0,
"doctype": "Desktop Icon",
"hidden": 0,
"icon": "file",
"icon_type": "Link",
"idx": 7,
"idx": 0,
"label": "Financial Reports",
"link_to": "Financial Reports",
"link_type": "Workspace",
"modified": "2025-11-17 13:34:48.074533",
"modified": "2025-12-31 16:07:27.060176",
"modified_by": "Administrator",
"name": "Financial Reports",
"owner": "Administrator",
"parent_icon": "Accounts",
"roles": [],
"sidebar": "",
"standard": 1
}

View File

@@ -1,21 +1,20 @@
{
"app": "erpnext",
"creation": "2025-11-17 13:19:04.269805",
"creation": "2025-11-17 20:55:11.824443",
"docstatus": 0,
"doctype": "Desktop Icon",
"hidden": 0,
"icon": "organization",
"icon_type": "Link",
"idx": 5,
"idx": 1,
"label": "Manufacturing",
"link_to": "Manufacturing",
"link_type": "Workspace",
"logo_url": "/assets/erpnext/desktop_icons/manufacturing.svg",
"modified": "2025-11-17 17:40:14.207766",
"modified": "2025-12-22 13:07:15.536476",
"modified_by": "Administrator",
"name": "Manufacturing",
"owner": "Administrator",
"parent_icon": "",
"parent_icon": "ERPNext",
"roles": [],
"standard": 1
}

View File

@@ -1,20 +0,0 @@
{
"app": "erpnext",
"creation": "2025-11-12 15:15:15.824801",
"docstatus": 0,
"doctype": "Desktop Icon",
"hidden": 0,
"icon": "panel-top-open",
"icon_type": "Link",
"idx": 2,
"label": "Opening & Closing",
"link_to": "Period Closing Voucher",
"link_type": "DocType",
"modified": "2025-11-19 15:59:14.805915",
"modified_by": "Administrator",
"name": "Opening & Closing",
"owner": "Administrator",
"parent_icon": "Accounts",
"roles": [],
"standard": 1
}

View File

@@ -1,20 +0,0 @@
{
"app": "erpnext",
"creation": "2025-11-17 13:19:04.255041",
"docstatus": 0,
"doctype": "Desktop Icon",
"hidden": 0,
"icon": "arrow-left",
"icon_type": "Link",
"idx": 0,
"label": "Payables",
"link_to": "Payables",
"link_type": "Workspace",
"modified": "2025-11-17 15:53:14.737052",
"modified_by": "Administrator",
"name": "Payables",
"owner": "Administrator",
"parent_icon": "Accounts",
"roles": [],
"standard": 1
}

View File

@@ -1,21 +1,20 @@
{
"app": "erpnext",
"creation": "2025-11-17 13:19:04.293376",
"creation": "2025-11-17 20:55:11.841426",
"docstatus": 0,
"doctype": "Desktop Icon",
"hidden": 0,
"icon": "project",
"icon_type": "Link",
"idx": 9,
"idx": 1,
"label": "Projects",
"link_to": "Projects",
"link_type": "Workspace",
"logo_url": "/assets/erpnext/desktop_icons/projects.svg",
"modified": "2025-11-17 17:42:29.470661",
"modified": "2025-12-22 13:07:07.027692",
"modified_by": "Administrator",
"name": "Projects",
"owner": "Administrator",
"parent_icon": "",
"parent_icon": "ERPNext",
"roles": [],
"standard": 1
}

View File

@@ -1,21 +1,20 @@
{
"app": "erpnext",
"creation": "2025-11-17 13:19:04.281193",
"creation": "2025-11-17 20:55:11.828716",
"docstatus": 0,
"doctype": "Desktop Icon",
"hidden": 0,
"icon": "quality",
"icon_type": "Link",
"idx": 9,
"idx": 1,
"label": "Quality",
"link_to": "Quality",
"link_type": "Workspace",
"logo_url": "/assets/erpnext/desktop_icons/quality.svg",
"modified": "2025-11-17 17:42:48.371889",
"modified": "2025-12-22 13:07:13.506034",
"modified_by": "Administrator",
"name": "Quality",
"owner": "Administrator",
"parent_icon": "",
"parent_icon": "ERPNext",
"roles": [],
"standard": 1
}

View File

@@ -1,20 +0,0 @@
{
"app": "erpnext",
"creation": "2025-11-17 13:19:04.249828",
"docstatus": 0,
"doctype": "Desktop Icon",
"hidden": 0,
"icon": "arrow-right",
"icon_type": "Link",
"idx": 0,
"label": "Receivables",
"link_to": "Receivables",
"link_type": "Workspace",
"modified": "2025-11-17 15:53:24.958812",
"modified_by": "Administrator",
"name": "Receivables",
"owner": "Administrator",
"parent_icon": "Accounts",
"roles": [],
"standard": 1
}

View File

@@ -1,21 +1,20 @@
{
"app": "erpnext",
"creation": "2025-11-17 13:19:04.335051",
"creation": "2025-11-17 20:55:11.872574",
"docstatus": 0,
"doctype": "Desktop Icon",
"hidden": 0,
"icon": "sell",
"icon_type": "Link",
"idx": 2,
"idx": 1,
"label": "Selling",
"link_to": "Selling",
"link_type": "Workspace",
"logo_url": "/assets/erpnext/desktop_icons/selling.svg",
"modified": "2025-11-17 17:37:59.847865",
"modified": "2025-12-22 13:06:51.346923",
"modified_by": "Administrator",
"name": "Selling",
"owner": "Administrator",
"parent_icon": "",
"parent_icon": "ERPNext",
"roles": [],
"standard": 1
}

View File

@@ -1,21 +1,20 @@
{
"app": "erpnext",
"creation": "2025-11-17 13:19:04.304517",
"creation": "2025-11-17 20:55:11.849904",
"docstatus": 0,
"doctype": "Desktop Icon",
"hidden": 0,
"icon": "stock",
"icon_type": "Link",
"idx": 4,
"idx": 1,
"label": "Stock",
"link_to": "Stock",
"link_type": "Workspace",
"logo_url": "/assets/erpnext/desktop_icons/stock.svg",
"modified": "2025-11-17 17:38:40.957627",
"modified": "2025-12-22 13:07:00.130510",
"modified_by": "Administrator",
"name": "Stock",
"owner": "Administrator",
"parent_icon": "",
"parent_icon": "ERPNext",
"roles": [],
"standard": 1
}

View File

@@ -6,11 +6,11 @@
"hidden": 0,
"icon": "monitor-check",
"icon_type": "Link",
"idx": 6,
"idx": 99,
"label": "Subscription",
"link_to": "Subscription",
"link_type": "DocType",
"modified": "2025-11-19 16:02:32.686833",
"modified": "2025-12-22 17:04:08.800434",
"modified_by": "Administrator",
"name": "Subscription",
"owner": "Administrator",

View File

@@ -1,21 +1,20 @@
{
"app": "erpnext",
"creation": "2025-11-17 13:19:04.288298",
"creation": "2025-11-17 20:55:11.837227",
"docstatus": 0,
"doctype": "Desktop Icon",
"hidden": 0,
"icon": "support",
"icon_type": "Link",
"idx": 10,
"idx": 1,
"label": "Support",
"link_to": "Support",
"link_type": "Workspace",
"logo_url": "/assets/erpnext/desktop_icons/support.svg",
"modified": "2025-11-17 17:43:09.335445",
"modified": "2025-12-22 13:07:11.812983",
"modified_by": "Administrator",
"name": "Support",
"owner": "Administrator",
"parent_icon": "",
"parent_icon": "ERPNext",
"roles": [],
"standard": 1
}

View File

@@ -8,13 +8,14 @@
"icon_type": "Link",
"idx": 3,
"label": "Taxes",
"link_to": "Item Tax Template",
"link_to": "Sales Taxes and Charges Template",
"link_type": "DocType",
"modified": "2025-11-19 15:58:21.226664",
"modified": "2025-12-31 16:59:14.978584",
"modified_by": "Administrator",
"name": "Taxes",
"owner": "Administrator",
"parent_icon": "Accounts",
"roles": [],
"sidebar": "",
"standard": 1
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -19,6 +19,20 @@ frappe.ui.form.on("BOM", {
};
});
frm.set_query("operation", "items", function () {
if (!frm.doc.operations?.length) {
frappe.throw(__("Please add Operations first."));
}
let operations = frm.doc.operations.map((d) => d.operation);
return {
filters: {
name: ["in", operations],
},
};
});
frm.set_query("bom_no", "operations", function (doc, cdt, cdn) {
let row = locals[cdt][cdn];
return {

View File

@@ -1036,10 +1036,14 @@ class BOM(WebsiteGenerator):
return erpnext.get_company_currency(self.company)
def add_to_cur_exploded_items(self, args):
if self.cur_exploded_items.get(args.item_code):
self.cur_exploded_items[args.item_code]["stock_qty"] += args.stock_qty
key = args.item_code
if args.operation:
key = (args.item_code, args.operation)
if self.cur_exploded_items.get(key):
self.cur_exploded_items[key]["stock_qty"] += args.stock_qty
else:
self.cur_exploded_items[args.item_code] = args
self.cur_exploded_items[key] = args
def get_child_exploded_items(self, bom_no, stock_qty, operation=None):
"""Add all items from Flat BOM of child BOM"""
@@ -1275,7 +1279,7 @@ def get_bom_items_as_dict(
):
item_dict = {}
group_by_cond = "group by item_code, stock_uom"
group_by_cond = "group by item_code, stock_uom, operation"
if frappe.get_cached_value("BOM", bom, "track_semi_finished_goods"):
fetch_exploded = 0
group_by_cond = "group by item_code, operation_row_id, stock_uom"
@@ -1360,6 +1364,9 @@ def get_bom_items_as_dict(
if item.operation_row_id:
key = (item.item_code, item.operation_row_id)
if item.operation:
key = (item.item_code, item.operation)
if item.get("is_phantom_item"):
data = get_bom_items_as_dict(
item.get("bom_no"),

View File

@@ -4,7 +4,7 @@
from collections import OrderedDict
import frappe
from frappe import _
from frappe import _, bold
from frappe.model.document import Document
from frappe.utils import cint, flt, sbool
from pypika.terms import ValueWrapper
@@ -78,6 +78,29 @@ class BOMCreator(Document):
def validate(self):
self.validate_items()
self.validate_duplicate_item()
def validate_duplicate_item(self):
# If same items added multiple times under same parent, raise error
item_map = {}
for row in self.items:
if not row.fg_reference_id:
continue
key = (row.item_code, row.fg_reference_id)
if key in item_map:
parent_item_code = next(
item.item_code for item in self.items if item.name == row.fg_reference_id
)
frappe.throw(
_(
"Item {0} added multiple times under the same parent item {1} at rows {2} and {3}"
).format(bold(row.item_code), bold(parent_item_code), item_map[key], row.idx),
title=_("Duplicate Item Under Same Parent"),
)
else:
item_map[key] = row.idx
def validate_items(self):
for row in self.items:
@@ -182,7 +205,7 @@ class BOMCreator(Document):
else:
row.rate = flt(self.get_raw_material_cost(row.item_code) * row.conversion_factor)
row.amount = flt(row.rate * row.qty)
row.amount = flt(row.rate) * flt(row.qty)
amount += flt(row.amount)
return amount

View File

@@ -147,8 +147,10 @@
},
{
"depends_on": "eval:doc.parenttype == \"Routing\"",
"description": "If you want to run operations in parallel, keep the same sequence ID for them.",
"fieldname": "sequence_id",
"fieldtype": "Int",
"in_list_view": 1,
"label": "Sequence ID"
},
{
@@ -295,7 +297,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2025-08-12 19:27:20.682797",
"modified": "2026-01-01 17:15:59.806874",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Operation",

View File

@@ -52,7 +52,7 @@
"fieldname": "status",
"fieldtype": "Select",
"label": "Status",
"options": "Queued\nIn Progress\nCompleted\nFailed"
"options": "Queued\nIn Progress\nCompleted\nFailed\nCancelled"
},
{
"fieldname": "amended_from",
@@ -98,11 +98,11 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2024-03-27 13:06:41.658172",
"modified": "2025-12-24 12:27:06.478893",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Update Log",
"naming_rule": "Expression (old style)",
"naming_rule": "Expression",
"owner": "Administrator",
"permissions": [
{
@@ -131,8 +131,9 @@
"write": 1
}
],
"row_format": "Dynamic",
"sort_field": "creation",
"sort_order": "DESC",
"states": [],
"track_changes": 1
}
}

View File

@@ -41,7 +41,7 @@ class BOMUpdateLog(Document):
error_log: DF.Link | None
new_bom: DF.Link | None
processed_boms: DF.LongText | None
status: DF.Literal["Queued", "In Progress", "Completed", "Failed"]
status: DF.Literal["Queued", "In Progress", "Completed", "Failed", "Cancelled"]
update_type: DF.Literal["Replace BOM", "Update Cost"]
# end: auto-generated types
@@ -64,6 +64,9 @@ class BOMUpdateLog(Document):
self.status = "Queued"
def on_discard(self):
self.db_set("status", "Cancelled")
def validate_boms_are_specified(self):
if self.update_type == "Replace BOM" and not (self.current_bom and self.new_bom):
frappe.throw(

View File

@@ -405,7 +405,8 @@
"fieldname": "employee",
"fieldtype": "Table MultiSelect",
"label": "Employee",
"options": "Job Card Time Log"
"options": "Job Card Time Log",
"read_only": 1
},
{
"fieldname": "serial_no",
@@ -625,7 +626,7 @@
"grid_page_length": 50,
"is_submittable": 1,
"links": [],
"modified": "2025-08-04 15:47:54.514290",
"modified": "2025-12-22 14:20:07.817118",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Job Card",

View File

@@ -144,6 +144,9 @@ class JobCard(Document):
self.set_onload("work_order_closed", self.is_work_order_closed())
self.set_onload("has_stock_entry", self.has_stock_entry())
def on_discard(self):
self.db_set("status", "Cancelled")
def has_stock_entry(self):
return frappe.db.exists("Stock Entry", {"job_card": self.name, "docstatus": ["!=", 2]})
@@ -162,6 +165,7 @@ class JobCard(Document):
self.set_total_completed_qty_from_sub_operations()
self.validate_work_order()
self.set_employees()
def on_update(self):
self.validate_job_card_qty()
@@ -631,11 +635,6 @@ class JobCard(Document):
row = self.append("time_logs", args)
row.db_update()
def set_employees(self, employees):
for name in employees:
self.append("employee", {"employee": name.get("employee"), "completed_qty": 0.0})
self.save()
def update_sub_operation_status(self):
if not self.sub_operations:
return
@@ -1230,6 +1229,12 @@ class JobCard(Document):
if self.is_work_order_closed():
frappe.throw(_("You can't make any changes to Job Card since Work Order is closed."))
def set_employees(self):
self.employee = []
for item in self.time_logs:
if not any(d.employee == item.employee for d in self.employee):
self.append("employee", {"employee": item.employee, "completed_qty": 0.0})
def is_work_order_closed(self):
if self.work_order:
status = frappe.get_value("Work Order", self.work_order)
@@ -1285,10 +1290,8 @@ class JobCard(Document):
self.set_status(update_status=update_status)
if not self.employee and kwargs.employees:
self.set_employees(kwargs.employees)
self.validate_time_logs(save=True)
self.save()
def update_workstation_status(self):
status_map = {
@@ -1329,17 +1332,15 @@ class JobCard(Document):
kwargs = frappe._dict(kwargs)
if kwargs.end_time:
if kwargs.for_quantity:
self.for_quantity = kwargs.for_quantity
self.add_time_logs(
to_time=kwargs.end_time,
completed_qty=kwargs.qty,
employees=self.employee,
sub_operation=kwargs.get("sub_operation"),
)
if kwargs.for_quantity:
self.for_quantity = kwargs.for_quantity
self.save()
else:
self.add_time_logs(completed_qty=kwargs.qty, employees=self.employee)
self.save()

View File

@@ -119,6 +119,9 @@ class ProductionPlan(Document):
frappe.db.get_single_value("Stock Settings", "enable_stock_reservation"),
)
def on_discard(self):
self.db_set("status", "Cancelled")
def validate(self):
self.set_pending_qty_in_row_without_reference()
self.calculate_total_planned_qty()

View File

@@ -143,7 +143,7 @@
"fieldtype": "Select",
"in_list_view": 1,
"label": "Status",
"options": "Planned\nMPS Generated",
"options": "Planned\nMPS Generated\nCancelled",
"read_only": 1
},
{
@@ -166,7 +166,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2025-11-13 16:33:49.682684",
"modified": "2025-12-24 11:40:44.263700",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Sales Forecast",

View File

@@ -33,9 +33,12 @@ class SalesForecast(Document):
parent_warehouse: DF.Link
posting_date: DF.Date | None
selected_items: DF.TableMultiSelect[SalesForecastItem]
status: DF.Literal["Planned", "MPS Generated"]
status: DF.Literal["Planned", "MPS Generated", "Cancelled"]
# end: auto-generated types
def on_discard(self):
self.db_set("status", "Cancelled")
def validate(self):
self.validate_demand_qty()

View File

@@ -180,6 +180,9 @@ class WorkOrder(Document):
return False
def on_discard(self):
self.db_set("status", "Cancelled")
def validate(self):
self.validate_production_item()
if self.bom_no:

View File

@@ -454,4 +454,5 @@ erpnext.patches.v16_0.populate_budget_distribution_total
erpnext.patches.v16_0.set_mr_picked_qty
erpnext.patches.v16_0.update_tax_withholding_field_in_payment_entry
erpnext.patches.v16_0.migrate_tax_withholding_data
erpnext.patches.v16_0.update_corrected_cancelled_status
erpnext.patches.v16_0.fix_barcode_typo

View File

@@ -0,0 +1,7 @@
import frappe
def execute():
frappe.qb.update("Item Barcode").set("barcode_type", "EAN-13").where(
frappe.qb.Field("barcode_type") == "EAN-12"
).run()

View File

@@ -1,6 +1,10 @@
import frappe
from frappe.utils import add_months, flt, get_first_day, get_last_day
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
get_accounting_dimensions,
)
def execute():
remove_old_property_setter()
@@ -79,6 +83,10 @@ def create_new_budget_from_row(budget_doc, fiscal_year, account_row, percentage_
for field in core_fields:
new_budget.set(field, budget_doc.get(field))
for fieldname in get_accounting_dimensions():
if budget_doc.get(fieldname):
new_budget.set(fieldname, budget_doc.get(fieldname))
new_budget.from_fiscal_year = fiscal_year.name
new_budget.to_fiscal_year = fiscal_year.name
new_budget.budget_start_date = fiscal_year.year_start_date

View File

@@ -0,0 +1,16 @@
import frappe
def execute():
stock_closing_entry = frappe.qb.DocType("Stock Closing Entry")
call_log = frappe.qb.DocType("Call Log")
# updating stock closing entry status to cancelled from canceled
(
frappe.qb.update(stock_closing_entry)
.set(stock_closing_entry.status, "Cancelled")
.where(stock_closing_entry.status == "Canceled")
).run()
# updating call log status to cancelled from canceled
(frappe.qb.update(call_log).set(call_log.status, "Cancelled").where(call_log.status == "Canceled")).run()

View File

@@ -8,6 +8,7 @@ from frappe.tests import IntegrationTestCase
from frappe.utils import add_to_date, now_datetime, nowdate
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.projects.doctype.task.test_task import create_task
from erpnext.projects.doctype.timesheet.timesheet import OverlapError, make_sales_invoice
from erpnext.setup.doctype.employee.test_employee import make_employee
from erpnext.tests.utils import ERPNextTestSuite
@@ -22,6 +23,55 @@ class TestTimesheet(ERPNextTestSuite):
def setUp(self):
frappe.db.delete("Timesheet")
def test_timesheet_post_update(self):
frappe.get_doc(
{
"doctype": "Property Setter",
"doctype_or_field": "DocField",
"doc_type": "Timesheet",
"field_name": "time_logs",
"property": "allow_on_submit",
"property_type": "Check",
"value": "1",
}
).insert(ignore_permissions=True)
task = create_task("Test Task 1")
timesheet = frappe.new_doc("Timesheet")
timesheet.append(
"time_logs",
{
"task": task.name,
"from_time": now_datetime(),
"to_time": now_datetime() + datetime.timedelta(hours=1),
"company": "_Test Company",
},
)
timesheet.save()
timesheet.submit()
task.reload()
self.assertEqual(task.actual_time, 1)
timesheet.append(
"time_logs",
{
"task": task.name,
"from_time": now_datetime(),
"to_time": now_datetime() + datetime.timedelta(hours=2),
"hours": 2,
},
)
timesheet.save()
task.reload()
self.assertEqual(task.actual_time, 3)
frappe.db.delete(
"Property Setter",
{"doc_type": "Timesheet", "field_name": "time_logs", "property": "allow_on_submit"},
)
def test_timesheet_base_amount(self):
emp = make_employee("test_employee_6@salary.com")
timesheet = make_timesheet(emp, simulate=True, is_billable=1)

View File

@@ -73,6 +73,13 @@ class Timesheet(Document):
self.calculate_percentage_billed()
self.set_dates()
def on_discard(self):
self.db_set("status", "Cancelled")
def on_update_after_submit(self):
self.validate_mandatory_fields()
self.update_task_and_project()
def calculate_hours(self):
for row in self.time_logs:
if row.to_time and row.from_time:

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -361,6 +361,21 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager {
mandatory_depends_on:
"eval:doc.action=='Create Voucher' && doc.document_type=='Payment Entry'",
},
{
fieldname: "bank_account",
fieldtype: "Link",
label: "Company Bank Account",
options: "Bank Account",
depends_on: "eval:doc.party",
get_query: function () {
return {
filters: {
is_company_account: 1,
company: this.company,
},
};
},
},
{
fieldname: "project",
fieldtype: "Link",
@@ -511,6 +526,7 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager {
mode_of_payment: values.mode_of_payment,
project: values.project,
cost_center: values.cost_center,
company_bank_account: values?.bank_account || this?.bank_account,
},
callback: (response) => {
const alert_string = __("Bank Transaction {0} added as Payment Entry", [
@@ -582,6 +598,7 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager {
project: values.project,
cost_center: values.cost_center,
allow_edit: true,
company_bank_account: values?.bank_account || this?.bank_account,
},
callback: (r) => {
const doc = frappe.model.sync(r.message);

Some files were not shown because too many files have changed in this diff Show More