mirror of
https://github.com/frappe/erpnext.git
synced 2026-04-16 21:35:09 +00:00
Merge pull request #47757 from frappe/version-14-hotfix
chore: release v14
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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]);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
15
erpnext/patches/v14_0/update_full_name_in_contract.py
Normal file
15
erpnext/patches/v14_0/update_full_name_in_contract.py
Normal file
@@ -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)
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user