Merge branch 'version-16-hotfix' into mergify/bp/version-16-hotfix/pr-53588

This commit is contained in:
Khushi Rawat
2026-04-13 15:41:39 +05:30
committed by GitHub
235 changed files with 7998 additions and 4725 deletions

View File

@@ -7,7 +7,7 @@ from random import randint
import frappe
from frappe import _
from frappe.utils import add_days, getdate
from frappe.utils import add_days, get_url_to_form, getdate
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
from erpnext.accounts.utils import get_fiscal_year
@@ -16,21 +16,44 @@ from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice
from erpnext.setup.setup_wizard.operations.install_fixtures import create_bank_account
def setup_demo_data():
def setup_demo_data(company_name):
from frappe.utils.telemetry import capture
capture("demo_data_creation_started", "erpnext")
try:
company = create_demo_company()
frappe.db.savepoint("demo_data")
company = create_demo_company(company_name)
process_masters()
make_transactions(company)
frappe.cache.delete_keys("bootinfo")
frappe.publish_realtime("demo_data_complete")
capture("demo_data_creation_completed", "erpnext")
frappe.clear_messages()
except Exception:
frappe.log_error("Failed to create demo data")
frappe.db.rollback(save_point="demo_data")
error_log = frappe.log_error("Failed to create demo data")
log_demo_data_failed_notification(error_log)
capture("demo_data_creation_failed", "erpnext", properties={"exception": frappe.get_traceback()})
raise
capture("demo_data_creation_completed", "erpnext")
def log_demo_data_failed_notification(error_log):
from frappe.core.doctype.role.role import get_users
from frappe.desk.doctype.notification_log.notification_log import make_notification_logs
frappe.msgprint(
_("Demo data creation failed. Check notifications for more info."),
alert=True,
indicator="red",
realtime=True,
)
users = get_users("System Manager")
notif_log_doc = {
"subject": _("Demo Data creation failed."),
"type": "Alert",
"link": get_url_to_form("Error Log", error_log.name),
}
make_notification_logs(notif_log_doc, users)
@frappe.whitelist()
@@ -56,21 +79,8 @@ def clear_demo_data():
)
def create_demo_company():
if frappe.flags.in_test:
hash = frappe.generate_hash(length=3)
company_doc = frappe._dict(
{
"company_name": "Test Company" + " " + hash,
"abbr": "TC" + hash,
"default_currency": "INR",
"country": "India",
"chart_of_accounts": "Standard",
}
)
else:
company = frappe.db.get_all("Company")[0].name
company_doc = frappe.get_doc("Company", company).as_dict()
def create_demo_company(company):
company_doc = frappe.get_doc("Company", company).as_dict()
# Make a dummy company
new_company = frappe.new_doc("Company")

View File

@@ -820,7 +820,7 @@ class Company(NestedSet):
boms = frappe.db.sql_list("select name from tabBOM where company=%s", self.name)
if boms:
frappe.db.sql("delete from tabBOM where company=%s", self.name)
for dt in ("BOM Operation", "BOM Item", "BOM Scrap Item", "BOM Explosion Item"):
for dt in ("BOM Operation", "BOM Item", "BOM Secondary Item", "BOM Explosion Item"):
frappe.db.sql(
"delete from `tab{}` where parent in ({})".format(dt, ", ".join(["%s"] * len(boms))),
tuple(boms),
@@ -927,7 +927,7 @@ def update_transactions_annual_history(company, commit=False):
transactions_history = get_all_transactions_annual_history(company)
frappe.db.set_value("Company", company, "transactions_annual_history", json.dumps(transactions_history))
if commit:
if commit and not frappe.in_test:
frappe.db.commit()
@@ -936,7 +936,9 @@ def cache_companies_monthly_sales_history():
for company in companies:
update_company_monthly_sales(company)
update_transactions_annual_history(company)
frappe.db.commit()
if not frappe.in_test:
frappe.db.commit()
@frappe.whitelist()

View File

@@ -199,7 +199,9 @@ class TestCompany(ERPNextTestSuite):
def test_demo_data(self):
from erpnext.setup.demo import clear_demo_data, setup_demo_data
setup_demo_data()
self.load_test_records("Company")
setup_demo_data(self.globalTestRecords["Company"][0]["company_name"])
company_name = frappe.db.get_value("Company", {"name": ("like", "%(Demo)")})
self.assertTrue(company_name)

View File

@@ -180,5 +180,39 @@
"default_currency": "ZAR",
"doctype": "Company",
"create_chart_of_accounts_based_on": "Standard Template"
},
{
"abbr": "_TOIC",
"company_name": "_Test Opening Invoice Company",
"country": "Pakistan",
"default_currency": "INR",
"doctype": "Company",
"create_chart_of_accounts_based_on": "Standard Template"
},
{
"abbr": "TBC",
"company_name": "Trial Balance Company",
"country": "India",
"default_currency": "INR",
"doctype": "Company",
"create_chart_of_accounts_based_on": "Standard Template"
},
{
"abbr": "_TSS",
"company_name": "_Test Support SLA",
"country": "India",
"default_currency": "INR",
"doctype": "Company",
"chart_of_accounts": "Standard",
"create_chart_of_accounts_based_on": "Standard Template"
},
{
"abbr": "TQC",
"company_name": "Test Quality Company",
"country": "India",
"default_currency": "INR",
"doctype": "Company",
"chart_of_accounts": "Standard",
"create_chart_of_accounts_based_on": "Standard Template"
}
]

View File

@@ -301,7 +301,7 @@ class Employee(NestedSet):
frappe.throw(_("User {0} does not exist").format(self.user_id))
if self.status != "Active" and enabled or self.status == "Active" and enabled == 0:
frappe.set_value("User", self.user_id, "enabled", not enabled)
frappe.db.set_value("User", self.user_id, "enabled", not enabled)
def validate_duplicate_user_id(self):
Employee = frappe.qb.DocType("Employee")

View File

@@ -4,6 +4,7 @@
import frappe
from frappe.model.document import Document
from frappe.query_builder import DocType
class PartyType(Document):
@@ -24,29 +25,36 @@ class PartyType(Document):
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_party_type(doctype, txt, searchfield, start, page_len, filters):
cond = ""
account_type = None
def get_party_type(doctype: str, txt: str, searchfield: str, start: int, page_len: int, filters: dict):
PartyType = DocType("Party Type")
get_party_type_query = frappe.qb.from_(PartyType).select(PartyType.name).orderby(PartyType.name)
condition_list = []
if filters and filters.get("account"):
account_type = frappe.db.get_value("Account", filters.get("account"), "account_type")
if account_type:
if account_type in ["Receivable", "Payable"]:
# Include Employee regardless of its configured account_type, but still respect the text filter
cond = "and (account_type = %(account_type)s or name = 'Employee')"
condition_list.append(
(PartyType.account_type == account_type) | (PartyType.name == "Employee")
)
else:
cond = "and account_type = %(account_type)s"
condition_list.append(PartyType.account_type == account_type)
# Build parameters dictionary
params = {"txt": "%" + txt + "%", "start": start, "page_len": page_len}
if account_type:
params["account_type"] = account_type
for condition in condition_list:
get_party_type_query = get_party_type_query.where(condition)
result = frappe.db.sql(
f"""select name from `tabParty Type`
where `{searchfield}` LIKE %(txt)s {cond}
order by name limit %(page_len)s offset %(start)s""",
params,
)
if frappe.local.lang == "en":
get_party_type_query = get_party_type_query.where(getattr(PartyType, searchfield).like(f"%{txt}%"))
get_party_type_query = get_party_type_query.limit(page_len)
get_party_type_query = get_party_type_query.offset(start)
result = get_party_type_query.run()
else:
result = get_party_type_query.run()
test_str = txt.lower()
result = [row for row in result if test_str in frappe._(row[0]).lower()]
result = result[start : start + page_len]
return result or []

View File

@@ -10,39 +10,34 @@ from erpnext.setup.setup_wizard.operations import install_fixtures as fixtures
def get_setup_stages(args=None):
if frappe.db.sql("select name from tabCompany"):
stages = [
stages = [
{
"status": _("Installing presets"),
"fail_msg": _("Failed to install presets"),
"tasks": [{"fn": stage_fixtures, "args": args, "fail_msg": _("Failed to install presets")}],
},
{
"status": _("Setting up company"),
"fail_msg": _("Failed to setup company"),
"tasks": [{"fn": setup_company, "args": args, "fail_msg": _("Failed to setup company")}],
},
{
"status": _("Setting defaults"),
"fail_msg": _("Failed to set defaults"),
"tasks": [
{"fn": setup_defaults, "args": args, "fail_msg": _("Failed to setup defaults")},
],
},
]
if args.get("setup_demo"):
stages.append(
{
"status": _("Wrapping up"),
"fail_msg": _("Failed to login"),
"tasks": [{"fn": fin, "args": args, "fail_msg": _("Failed to login")}],
"status": _("Creating demo data"),
"fail_msg": _("Failed to create demo data"),
"tasks": [{"fn": setup_demo, "args": args, "fail_msg": _("Failed to create demo data")}],
}
]
else:
stages = [
{
"status": _("Installing presets"),
"fail_msg": _("Failed to install presets"),
"tasks": [{"fn": stage_fixtures, "args": args, "fail_msg": _("Failed to install presets")}],
},
{
"status": _("Setting up company"),
"fail_msg": _("Failed to setup company"),
"tasks": [{"fn": setup_company, "args": args, "fail_msg": _("Failed to setup company")}],
},
{
"status": _("Setting defaults"),
"fail_msg": "Failed to set defaults",
"tasks": [
{"fn": setup_defaults, "args": args, "fail_msg": _("Failed to setup defaults")},
],
},
{
"status": _("Wrapping up"),
"fail_msg": _("Failed to login"),
"tasks": [{"fn": fin, "args": args, "fail_msg": _("Failed to login")}],
},
]
)
return stages
@@ -59,19 +54,8 @@ def setup_defaults(args):
fixtures.install_defaults(frappe._dict(args))
def fin(args):
frappe.local.message_log = []
login_as_first_user(args)
def setup_demo(args):
if args.get("setup_demo"):
frappe.enqueue(setup_demo_data, enqueue_after_commit=True, at_front=True)
def login_as_first_user(args):
if args.get("email") and hasattr(frappe.local, "login_manager"):
frappe.local.login_manager.login_as(args.get("email"))
def setup_demo(args): # nosemgrep
setup_demo_data(args.get("company_name"))
# Only for programmatical use
@@ -79,4 +63,3 @@ def setup_complete(args=None):
stage_fixtures(args)
setup_company(args)
setup_defaults(args)
fin(args)