Skip to content

Commit 1cfb002

Browse files
authored
Merge pull request #47757 from frappe/version-14-hotfix
chore: release v14
2 parents 79a4b59 + 3b68682 commit 1cfb002

File tree

14 files changed

+102
-20
lines changed

14 files changed

+102
-20
lines changed

erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,7 @@ def get_tcs_amount(parties, inv, tax_details, vouchers, adv_vouchers):
622622
conditions.append(ple.party.isin(parties))
623623
conditions.append(ple.voucher_no == ple.against_voucher_no)
624624
conditions.append(ple.company == inv.company)
625+
conditions.append(ple.posting_date[tax_details.from_date : tax_details.to_date])
625626

626627
advance_amt = (
627628
qb.from_(ple).select(Abs(Sum(ple.amount))).where(Criterion.all(conditions)).run()[0][0] or 0.0

erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -243,17 +243,18 @@ def test_tcs_on_unallocated_advance_payments(self):
243243
frappe.db.set_value(
244244
"Customer", "Test TCS Customer", "tax_withholding_category", "Cumulative Threshold TCS"
245245
)
246+
fiscal_year = get_fiscal_year(today(), company="_Test Company")
246247

247248
vouchers = []
248249

249250
# create advance payment
250-
pe = create_payment_entry(
251+
pe1 = create_payment_entry(
251252
payment_type="Receive", party_type="Customer", party="Test TCS Customer", paid_amount=20000
252253
)
253-
pe.paid_from = "Debtors - _TC"
254-
pe.paid_to = "Cash - _TC"
255-
pe.submit()
256-
vouchers.append(pe)
254+
pe1.paid_from = "Debtors - _TC"
255+
pe1.paid_to = "Cash - _TC"
256+
pe1.submit()
257+
vouchers.append(pe1)
257258

258259
# create invoice
259260
si1 = create_sales_invoice(customer="Test TCS Customer", rate=5000)
@@ -275,6 +276,17 @@ def test_tcs_on_unallocated_advance_payments(self):
275276
# make another invoice
276277
# sum of unallocated amount from payment entry and this sales invoice will breach cumulative threashold
277278
# TDS should be calculated
279+
280+
# this payment should not be considered for TCS calculation as it is outside of fiscal year
281+
pe2 = create_payment_entry(
282+
payment_type="Receive", party_type="Customer", party="Test TCS Customer", paid_amount=10000
283+
)
284+
pe2.paid_from = "Debtors - _TC"
285+
pe2.paid_to = "Cash - _TC"
286+
pe2.posting_date = add_days(fiscal_year[1], -10)
287+
pe2.submit()
288+
vouchers.append(pe2)
289+
278290
si2 = create_sales_invoice(customer="Test TCS Customer", rate=15000)
279291
si2.submit()
280292
vouchers.append(si2)

erpnext/assets/doctype/asset_capitalization/asset_capitalization.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
380380
args: {
381381
item_code: item.item_code,
382382
warehouse: cstr(item.warehouse),
383-
qty: flt(item.stock_qty),
383+
qty: -1 * flt(item.stock_qty),
384384
serial_no: item.serial_no,
385385
posting_date: me.frm.doc.posting_date,
386386
posting_time: me.frm.doc.posting_time,

erpnext/buying/utils.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ def update_last_purchase_rate(doc, is_submit) -> None:
2020
this_purchase_date = getdate(doc.get("posting_date") or doc.get("transaction_date"))
2121

2222
for d in doc.get("items"):
23+
if d.get("is_free_item"):
24+
continue
25+
2326
# get last purchase details
2427
last_purchase_details = get_last_purchase_details(d.item_code, doc.name)
2528

erpnext/crm/doctype/contract/contract.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,10 @@ frappe.ui.form.on("Contract", {
2929
});
3030
}
3131
},
32+
party_name: function (frm) {
33+
let field = frm.doc.party_type.toLowerCase() + "_name";
34+
frappe.db.get_value(frm.doc.party_type, frm.doc.party_name, field, (r) => {
35+
frm.set_value("party_full_name", r[field]);
36+
});
37+
},
3238
});

erpnext/crm/doctype/contract/contract.json

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"party_user",
1515
"status",
1616
"fulfilment_status",
17+
"party_full_name",
1718
"sb_terms",
1819
"start_date",
1920
"cb_date",
@@ -244,11 +245,18 @@
244245
"fieldname": "authorised_by_section",
245246
"fieldtype": "Section Break",
246247
"label": "Authorised By"
248+
},
249+
{
250+
"fieldname": "party_full_name",
251+
"fieldtype": "Data",
252+
"label": "Party Full Name",
253+
"read_only": 1
247254
}
248255
],
256+
"grid_page_length": 50,
249257
"is_submittable": 1,
250258
"links": [],
251-
"modified": "2020-12-07 11:15:58.385521",
259+
"modified": "2025-05-23 13:54:03.346537",
252260
"modified_by": "Administrator",
253261
"module": "CRM",
254262
"name": "Contract",
@@ -315,9 +323,10 @@
315323
"write": 1
316324
}
317325
],
326+
"row_format": "Dynamic",
318327
"show_name_in_global_search": 1,
319328
"sort_field": "modified",
320329
"sort_order": "DESC",
321330
"track_changes": 1,
322331
"track_seen": 1
323-
}
332+
}

erpnext/crm/doctype/contract/contract.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,17 @@ def autoname(self):
2323
self.name = _(name)
2424

2525
def validate(self):
26+
self.set_missing_values()
2627
self.validate_dates()
2728
self.update_contract_status()
2829
self.update_fulfilment_status()
2930

31+
def set_missing_values(self):
32+
if not self.party_full_name:
33+
field = self.party_type.lower() + "_name"
34+
if res := frappe.db.get_value(self.party_type, self.party_name, field):
35+
self.party_full_name = res
36+
3037
def before_submit(self):
3138
self.signed_by_company = frappe.session.user
3239

erpnext/patches.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,3 +375,5 @@ erpnext.stock.doctype.stock_ledger_entry.patches.ensure_sle_indexes
375375
erpnext.patches.v14_0.rename_group_by_to_categorize_by
376376
execute:frappe.db.set_single_value("Accounts Settings", "receivable_payable_fetch_method", "Buffered Cursor")
377377
erpnext.patches.v14_0.set_update_price_list_based_on
378+
erpnext.patches.v14_0.rename_group_by_to_categorize_by_in_custom_reports
379+
erpnext.patches.v14_0.update_full_name_in_contract
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import json
2+
3+
import frappe
4+
5+
6+
def execute():
7+
custom_reports = frappe.get_all(
8+
"Report",
9+
filters={
10+
"report_type": "Custom Report",
11+
"reference_report": ["in", ["General Ledger", "Supplier Quotation Comparison"]],
12+
},
13+
fields=["name", "json"],
14+
)
15+
16+
for report in custom_reports:
17+
report_json = json.loads(report.json)
18+
19+
if "filters" in report_json and "group_by" in report_json["filters"]:
20+
report_json["filters"]["categorize_by"] = (
21+
report_json["filters"].pop("group_by").replace("Group", "Categorize")
22+
)
23+
24+
frappe.db.set_value("Report", report.name, "json", json.dumps(report_json))
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import frappe
2+
from frappe import qb
3+
4+
5+
def execute():
6+
con = qb.DocType("Contract")
7+
for c in (
8+
qb.from_(con)
9+
.select(con.name, con.party_type, con.party_name)
10+
.where(con.party_full_name.isnull())
11+
.run(as_dict=True)
12+
):
13+
field = c.party_type.lower() + "_name"
14+
if res := frappe.db.get_value(c.party_type, c.party_name, field):
15+
frappe.db.set_value("Contract", c.name, "party_full_name", res)

erpnext/public/js/controllers/taxes_and_totals.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
2626
item.discount_amount = flt(item.rate_with_margin) * flt(item.discount_percentage) / 100;
2727
}
2828

29-
if (item.discount_amount) {
29+
if (item.discount_amount > 0) {
3030
item_rate = flt((item.rate_with_margin) - (item.discount_amount), precision('rate', item));
3131
item.discount_percentage = 100 * flt(item.discount_amount) / flt(item.rate_with_margin);
3232
}

erpnext/stock/doctype/item/item.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
{
22
"actions": [],
3-
"allow_guest_to_view": 1,
43
"allow_import": 1,
54
"allow_rename": 1,
65
"autoname": "field:item_code",
@@ -897,10 +896,9 @@
897896
"icon": "fa fa-tag",
898897
"idx": 2,
899898
"image_field": "image",
900-
"index_web_pages_for_search": 1,
901899
"links": [],
902900
"make_attachments_public": 1,
903-
"modified": "2024-01-08 18:09:30.225085",
901+
"modified": "2025-02-03 23:43:57.253667",
904902
"modified_by": "Administrator",
905903
"module": "Stock",
906904
"name": "Item",

erpnext/stock/doctype/serial_no/serial_no.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -178,13 +178,13 @@ def get_last_sle(self, serial_no=None):
178178
entries = {}
179179
sle_dict = self.get_stock_ledger_entries(serial_no)
180180
if sle_dict:
181+
last_sle = sle_dict.get("last_sle") or {}
182+
entries["last_sle"] = last_sle
183+
181184
if sle_dict.get("incoming", []):
182185
entries["purchase_sle"] = sle_dict["incoming"][-1]
183186

184-
if len(sle_dict.get("incoming", [])) - len(sle_dict.get("outgoing", [])) > 0:
185-
entries["last_sle"] = sle_dict["incoming"][0]
186-
else:
187-
entries["last_sle"] = sle_dict["outgoing"][0]
187+
if last_sle.get("actual_qty") < 0 and sle_dict.get("outgoing", []):
188188
entries["delivery_sle"] = sle_dict["outgoing"][0]
189189

190190
return entries
@@ -221,6 +221,9 @@ def get_stock_ledger_entries(self, serial_no=None):
221221
as_dict=1,
222222
):
223223
if serial_no.upper() in get_serial_nos(sle.serial_no):
224+
if "last_sle" not in sle_dict:
225+
sle_dict["last_sle"] = sle
226+
224227
if cint(sle.actual_qty) > 0:
225228
sle_dict.setdefault("incoming", []).append(sle)
226229
else:

erpnext/stock/doctype/stock_entry/stock_entry.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -458,17 +458,19 @@ def validate_difference_account(self):
458458
if acc_details.account_type == "Stock":
459459
frappe.throw(
460460
_(
461-
"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"
461+
"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"
462462
).format(d.idx, get_link_to_form("Account", d.expense_account)),
463-
OpeningEntryAccountError,
463+
title=_("Difference Account in Items Table"),
464464
)
465465

466466
if self.purpose != "Material Issue" and acc_details.account_type == "Cost of Goods Sold":
467467
frappe.msgprint(
468468
_(
469-
"At row {0}: You have selected the Difference Account {1}, which is a Cost of Goods Sold type account. Please select a different account"
469+
"At row #{0}: you have selected the Difference Account {1}, which is a Cost of Goods Sold type account. Please select a different account"
470470
).format(d.idx, bold(get_link_to_form("Account", d.expense_account))),
471-
title=_("Warning : Cost of Goods Sold Account"),
471+
title=_("Cost of Goods Sold Account in Items Table"),
472+
indicator="orange",
473+
alert=1,
472474
)
473475

474476
def validate_warehouse(self):

0 commit comments

Comments
 (0)