diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py index da329324e95..b4640b1ef3c 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py @@ -622,6 +622,7 @@ def get_tcs_amount(parties, inv, tax_details, vouchers, adv_vouchers): conditions.append(ple.party.isin(parties)) conditions.append(ple.voucher_no == ple.against_voucher_no) conditions.append(ple.company == inv.company) + conditions.append(ple.posting_date[tax_details.from_date : tax_details.to_date]) advance_amt = ( qb.from_(ple).select(Abs(Sum(ple.amount))).where(Criterion.all(conditions)).run()[0][0] or 0.0 diff --git a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py index 6a7fc3c43d2..2d8837cd9db 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py @@ -243,17 +243,18 @@ class TestTaxWithholdingCategory(FrappeTestCase): frappe.db.set_value( "Customer", "Test TCS Customer", "tax_withholding_category", "Cumulative Threshold TCS" ) + fiscal_year = get_fiscal_year(today(), company="_Test Company") vouchers = [] # create advance payment - pe = create_payment_entry( + pe1 = create_payment_entry( payment_type="Receive", party_type="Customer", party="Test TCS Customer", paid_amount=20000 ) - pe.paid_from = "Debtors - _TC" - pe.paid_to = "Cash - _TC" - pe.submit() - vouchers.append(pe) + pe1.paid_from = "Debtors - _TC" + pe1.paid_to = "Cash - _TC" + pe1.submit() + vouchers.append(pe1) # create invoice si1 = create_sales_invoice(customer="Test TCS Customer", rate=5000) @@ -275,6 +276,17 @@ class TestTaxWithholdingCategory(FrappeTestCase): # make another invoice # sum of unallocated amount from payment entry and this sales invoice will breach cumulative threashold # TDS should be calculated + + # this payment should not be considered for TCS calculation as it is outside of fiscal year + pe2 = create_payment_entry( + payment_type="Receive", party_type="Customer", party="Test TCS Customer", paid_amount=10000 + ) + pe2.paid_from = "Debtors - _TC" + pe2.paid_to = "Cash - _TC" + pe2.posting_date = add_days(fiscal_year[1], -10) + pe2.submit() + vouchers.append(pe2) + si2 = create_sales_invoice(customer="Test TCS Customer", rate=15000) si2.submit() vouchers.append(si2) diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js index 6f73dfc6736..7491c4a72aa 100644 --- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js +++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js @@ -380,7 +380,7 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s args: { item_code: item.item_code, warehouse: cstr(item.warehouse), - qty: flt(item.stock_qty), + qty: -1 * flt(item.stock_qty), serial_no: item.serial_no, posting_date: me.frm.doc.posting_date, posting_time: me.frm.doc.posting_time, diff --git a/erpnext/buying/utils.py b/erpnext/buying/utils.py index 8223917792c..9ee8868e2c7 100644 --- a/erpnext/buying/utils.py +++ b/erpnext/buying/utils.py @@ -20,6 +20,9 @@ def update_last_purchase_rate(doc, is_submit) -> None: this_purchase_date = getdate(doc.get("posting_date") or doc.get("transaction_date")) for d in doc.get("items"): + if d.get("is_free_item"): + continue + # get last purchase details last_purchase_details = get_last_purchase_details(d.item_code, doc.name) diff --git a/erpnext/crm/doctype/contract/contract.js b/erpnext/crm/doctype/contract/contract.js index 8d44c22db28..42bd7f9b769 100644 --- a/erpnext/crm/doctype/contract/contract.js +++ b/erpnext/crm/doctype/contract/contract.js @@ -29,4 +29,10 @@ frappe.ui.form.on("Contract", { }); } }, + party_name: function (frm) { + let field = frm.doc.party_type.toLowerCase() + "_name"; + frappe.db.get_value(frm.doc.party_type, frm.doc.party_name, field, (r) => { + frm.set_value("party_full_name", r[field]); + }); + }, }); diff --git a/erpnext/crm/doctype/contract/contract.json b/erpnext/crm/doctype/contract/contract.json index de3230f0e67..948243402fe 100755 --- a/erpnext/crm/doctype/contract/contract.json +++ b/erpnext/crm/doctype/contract/contract.json @@ -14,6 +14,7 @@ "party_user", "status", "fulfilment_status", + "party_full_name", "sb_terms", "start_date", "cb_date", @@ -244,11 +245,18 @@ "fieldname": "authorised_by_section", "fieldtype": "Section Break", "label": "Authorised By" + }, + { + "fieldname": "party_full_name", + "fieldtype": "Data", + "label": "Party Full Name", + "read_only": 1 } ], + "grid_page_length": 50, "is_submittable": 1, "links": [], - "modified": "2020-12-07 11:15:58.385521", + "modified": "2025-05-23 13:54:03.346537", "modified_by": "Administrator", "module": "CRM", "name": "Contract", @@ -315,9 +323,10 @@ "write": 1 } ], + "row_format": "Dynamic", "show_name_in_global_search": 1, "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, "track_seen": 1 -} \ No newline at end of file +} diff --git a/erpnext/crm/doctype/contract/contract.py b/erpnext/crm/doctype/contract/contract.py index db23d570644..f30d576213f 100644 --- a/erpnext/crm/doctype/contract/contract.py +++ b/erpnext/crm/doctype/contract/contract.py @@ -23,10 +23,17 @@ class Contract(Document): self.name = _(name) def validate(self): + self.set_missing_values() self.validate_dates() self.update_contract_status() self.update_fulfilment_status() + def set_missing_values(self): + if not self.party_full_name: + field = self.party_type.lower() + "_name" + if res := frappe.db.get_value(self.party_type, self.party_name, field): + self.party_full_name = res + def before_submit(self): self.signed_by_company = frappe.session.user diff --git a/erpnext/patches.txt b/erpnext/patches.txt index be4b89bfc6d..1d051fd2489 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -375,3 +375,5 @@ erpnext.stock.doctype.stock_ledger_entry.patches.ensure_sle_indexes erpnext.patches.v14_0.rename_group_by_to_categorize_by execute:frappe.db.set_single_value("Accounts Settings", "receivable_payable_fetch_method", "Buffered Cursor") erpnext.patches.v14_0.set_update_price_list_based_on +erpnext.patches.v14_0.rename_group_by_to_categorize_by_in_custom_reports +erpnext.patches.v14_0.update_full_name_in_contract diff --git a/erpnext/patches/v14_0/rename_group_by_to_categorize_by_in_custom_reports.py b/erpnext/patches/v14_0/rename_group_by_to_categorize_by_in_custom_reports.py new file mode 100644 index 00000000000..bc671a4a6ac --- /dev/null +++ b/erpnext/patches/v14_0/rename_group_by_to_categorize_by_in_custom_reports.py @@ -0,0 +1,24 @@ +import json + +import frappe + + +def execute(): + custom_reports = frappe.get_all( + "Report", + filters={ + "report_type": "Custom Report", + "reference_report": ["in", ["General Ledger", "Supplier Quotation Comparison"]], + }, + fields=["name", "json"], + ) + + for report in custom_reports: + report_json = json.loads(report.json) + + if "filters" in report_json and "group_by" in report_json["filters"]: + report_json["filters"]["categorize_by"] = ( + report_json["filters"].pop("group_by").replace("Group", "Categorize") + ) + + frappe.db.set_value("Report", report.name, "json", json.dumps(report_json)) diff --git a/erpnext/patches/v14_0/update_full_name_in_contract.py b/erpnext/patches/v14_0/update_full_name_in_contract.py new file mode 100644 index 00000000000..19ee055ad12 --- /dev/null +++ b/erpnext/patches/v14_0/update_full_name_in_contract.py @@ -0,0 +1,15 @@ +import frappe +from frappe import qb + + +def execute(): + con = qb.DocType("Contract") + for c in ( + qb.from_(con) + .select(con.name, con.party_type, con.party_name) + .where(con.party_full_name.isnull()) + .run(as_dict=True) + ): + field = c.party_type.lower() + "_name" + if res := frappe.db.get_value(c.party_type, c.party_name, field): + frappe.db.set_value("Contract", c.name, "party_full_name", res) diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js index bab4b715902..dca9f353457 100644 --- a/erpnext/public/js/controllers/taxes_and_totals.js +++ b/erpnext/public/js/controllers/taxes_and_totals.js @@ -26,7 +26,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { item.discount_amount = flt(item.rate_with_margin) * flt(item.discount_percentage) / 100; } - if (item.discount_amount) { + if (item.discount_amount > 0) { item_rate = flt((item.rate_with_margin) - (item.discount_amount), precision('rate', item)); item.discount_percentage = 100 * flt(item.discount_amount) / flt(item.rate_with_margin); } diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json index b9256c8ee56..29d59b4ce70 100644 --- a/erpnext/stock/doctype/item/item.json +++ b/erpnext/stock/doctype/item/item.json @@ -1,6 +1,5 @@ { "actions": [], - "allow_guest_to_view": 1, "allow_import": 1, "allow_rename": 1, "autoname": "field:item_code", @@ -897,10 +896,9 @@ "icon": "fa fa-tag", "idx": 2, "image_field": "image", - "index_web_pages_for_search": 1, "links": [], "make_attachments_public": 1, - "modified": "2024-01-08 18:09:30.225085", + "modified": "2025-02-03 23:43:57.253667", "modified_by": "Administrator", "module": "Stock", "name": "Item", diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py index 654f28e661c..bc4d4998d0b 100644 --- a/erpnext/stock/doctype/serial_no/serial_no.py +++ b/erpnext/stock/doctype/serial_no/serial_no.py @@ -178,13 +178,13 @@ class SerialNo(StockController): entries = {} sle_dict = self.get_stock_ledger_entries(serial_no) if sle_dict: + last_sle = sle_dict.get("last_sle") or {} + entries["last_sle"] = last_sle + if sle_dict.get("incoming", []): entries["purchase_sle"] = sle_dict["incoming"][-1] - if len(sle_dict.get("incoming", [])) - len(sle_dict.get("outgoing", [])) > 0: - entries["last_sle"] = sle_dict["incoming"][0] - else: - entries["last_sle"] = sle_dict["outgoing"][0] + if last_sle.get("actual_qty") < 0 and sle_dict.get("outgoing", []): entries["delivery_sle"] = sle_dict["outgoing"][0] return entries @@ -221,6 +221,9 @@ class SerialNo(StockController): as_dict=1, ): if serial_no.upper() in get_serial_nos(sle.serial_no): + if "last_sle" not in sle_dict: + sle_dict["last_sle"] = sle + if cint(sle.actual_qty) > 0: sle_dict.setdefault("incoming", []).append(sle) else: diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index ca15db485fd..eb020f55155 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -458,17 +458,19 @@ class StockEntry(StockController): if acc_details.account_type == "Stock": frappe.throw( _( - "At row {0}: the Difference Account must not be a Stock type account, please change the Account Type for the account {1} or select a different account" + "At row #{0}: the Difference Account must not be a Stock type account, please change the Account Type for the account {1} or select a different account" ).format(d.idx, get_link_to_form("Account", d.expense_account)), - OpeningEntryAccountError, + title=_("Difference Account in Items Table"), ) if self.purpose != "Material Issue" and acc_details.account_type == "Cost of Goods Sold": frappe.msgprint( _( - "At row {0}: You have selected the Difference Account {1}, which is a Cost of Goods Sold type account. Please select a different account" + "At row #{0}: you have selected the Difference Account {1}, which is a Cost of Goods Sold type account. Please select a different account" ).format(d.idx, bold(get_link_to_form("Account", d.expense_account))), - title=_("Warning : Cost of Goods Sold Account"), + title=_("Cost of Goods Sold Account in Items Table"), + indicator="orange", + alert=1, ) def validate_warehouse(self):