Conservative cleanup of frappe.throw/msgprint messages per the message style
guide; meaning, severity, and .format() arguments are unchanged:
- index bare {} placeholders as {0}/{1}/... so translators can reorder
- move f-strings / .format() / concatenation out of _() (they break gettext
extraction and never translate)
- wrap translatable dynamic values (DocType/Select labels) in _()
- fix grammar and colloquialisms
- drop no-op _() wrapping runtime-built strings
Part of #53976.
Conservative cleanup of frappe.throw/msgprint messages per the message style
guide; meaning, severity, and .format() arguments are unchanged:
- index bare {} placeholders as {0}/{1}/... so translators can reorder
- move f-strings / .format() / concatenation out of _() (they break gettext
extraction and never translate)
- wrap translatable dynamic values (DocType/Select labels) in _()
- fix grammar and colloquialisms
- drop no-op _() wrapping runtime-built strings
Part of #53976.
Conservative cleanup of frappe.throw/msgprint messages per the message style
guide; meaning, severity, and .format() arguments are unchanged:
- index bare {} placeholders as {0}/{1}/... so translators can reorder
- move f-strings / .format() / concatenation out of _() (they break gettext
extraction and never translate)
- wrap translatable dynamic values (DocType/Select labels) in _()
- fix grammar and colloquialisms
- drop no-op _() wrapping runtime-built strings
Part of #53976.
Conservative cleanup of frappe.throw/msgprint messages per the message style
guide; meaning, severity, and .format() arguments are unchanged:
- index bare {} placeholders as {0}/{1}/... so translators can reorder
- move f-strings / .format() / concatenation out of _() (they break gettext
extraction and never translate)
- wrap translatable dynamic values (DocType/Select labels) in _()
- fix grammar and colloquialisms
- drop no-op _() wrapping runtime-built strings
Part of #53976.
Conservative cleanup of frappe.throw/msgprint messages per the message
style guide; meaning, severity, and .format() arguments are unchanged:
- index bare {} placeholders as {0}/{1}/... so translators can reorder
- move f-strings / .format() / concatenation out of _() (they break
gettext extraction and never translate)
- wrap translatable dynamic values (DocType/Select labels) in _()
- fix grammar and colloquialisms ("doesn't belongs" -> "does not belong",
"till" -> "until", "Rules exists" -> "Rules exist", exclusive "one of
X and Y" -> "one of X, Y, or Z")
- drop no-op _() wrapping runtime-built HTML strings
Part of #53976.
_get_pricing_rules orders by priority desc; get_pricing_rules then reads
pricing_rules[0].has_priority. priority is a Select (varchar): unset is '' on
MariaDB but NULL on Postgres, which sorts to the top under DESC and flips the
selection. Order by coalesce(priority, '') desc so the unset value sorts last
('' is the text minimum) on both backends.
get_serial_nos_based_on_filters with based_on='Expiry' orders by amc_expiry_date
asc and limits to qty. MariaDB sorts NULL (no-AMC) serials first; Postgres last,
so a different set of serials is auto-selected. Order by (amc_expiry_date IS NULL)
desc, amc_expiry_date so NULLs sort first on both (MariaDB unchanged).
Both Item Price lookups order by valid_from desc and take the first valid row.
MariaDB sorts NULL valid_from last; Postgres first, so the undated base price was
winning over a dated one. Order by (valid_from IS NULL) asc, valid_from desc (the
get_all is converted to qb since its order_by won't take such an expression).
MariaDB output is unchanged.
get_items orders Item Price by valid_from and picks the first match. MariaDB sorts
NULL valid_from last under DESC (so a dated price wins); Postgres sorts it first,
so the undated base price wins and POS shows the wrong rate. Order by
(valid_from IS NULL) asc, valid_from desc so NULLs sort last on both backends
regardless of any real date value (MariaDB unchanged).
Replaces the previous over-engineered stub with 7 short functions.
Account data, Account Closing Balance, and all metadata come from
frappe.db as normal; only tabGL Entry is read from the duckdb_conn.
Reuses get_opening_balance() for Account Closing Balance unchanged,
reuses all downstream compute helpers (calculate_values, prepare_data,
etc.) unchanged.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces the placeholder stub with 8 focused functions that mirror the
normal execute() flow using parameterized DuckDB SQL queries: account
fetch, period GL entries, opening balances (with Period Closing Voucher
path), and all filters (cost center, project, finance book, accounting
dimensions). Reuses existing pure-Python processing functions unchanged.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The calendar view sends filters as a list of [doctype, field, op, value]
conditions (filter_area.get()); get_filter_conditions_qb accepts dict or list.
create_prospect_against_crm_deal and create_customer read `contacts`
from form_dict (json.loads(doc.contacts) / customer_data.get("contacts")),
which arrives as a native list under JSON body mode. Use frappe.parse_json.
make_payment_request(**args) is whitelisted and the client passes
`schedules` as a list, so json.loads(args.get("schedules")) raised
TypeError under JSON body mode. Use frappe.parse_json.
Opt ERPNext into native application/json request bodies (frappe#40237).
Non-GET requests to erpnext.* endpoints now send args as a JSON body
instead of form-encoded, per-key JSON-stringified values. Safe after the
preceding commits hardened every whitelisted endpoint with frappe.parse_json.