Commit Graph

59117 Commits

Author SHA1 Message Date
ruthra kumar
3da7eefebb refactor: patch, display depends on and json changes 2026-06-24 13:03:07 +05:30
ruthra kumar
13b6c4a165 feat(accounts): add configurable job timeout for Process Period Closing Voucher
Adds a `pcv_job_timeout` Int field (default 3600s) to Accounts Settings
so admins can tune the enqueue timeout for PCV background jobs without
a code change. All three `frappe.enqueue` calls in
`process_period_closing_voucher.py` now read this value at runtime.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 12:57:31 +05:30
Mihir Kandoi
6a237f323f Merge pull request #56349 from mihir-kandoi/pg-compat-tooling-audit-learnings
ci(postgres): teach the PG-compat tooling the audit 6-9 divergence classes
2026-06-23 14:35:33 +05:30
Mihir Kandoi
d032e93f87 Merge pull request #56344 from mihir-kandoi/pg-mps-leadtime-intdiv
fix(manufacturing): keep MPS cumulative lead-time fractional across engines
2026-06-23 13:40:18 +05:30
NaviN
d1ffac36c1 fix(payment reconciliation): honour user permissions on accounting dimensions (#55803) 2026-06-23 13:36:29 +05:30
Mihir Kandoi
331f383777 ci(postgres): match CAST AS CHAR with nested parens in the checker
The [^)]* span stopped at the first inner ')', so CAST(ABS(col) AS CHAR) slipped through. Use a non-greedy .+? with re.S; still zero production false positives (verified). Addresses review feedback.
2026-06-23 13:24:49 +05:30
Mihir Kandoi
d225532595 test(manufacturing): make MPS lead-time fixture idempotent
Delete any existing Item Lead Time for the test item before inserting, so the test is re-runnable on a shared database (addresses review feedback).
2026-06-23 13:20:58 +05:30
Nishka Gosalia
ce4e56336e Merge pull request #56350 from nishkagosalia/gh-56067
fix: handling default company in purchase transactions created from project
2026-06-23 12:37:37 +05:30
nishkagosalia
359717115f fix: company default handling in purchase transactions made from project 2026-06-23 12:33:31 +05:30
Mihir Kandoi
fc9544435e ci(postgres): teach the PG-compat tooling the audit 6-9 divergence classes
The whole-repo MariaDB<->PostgreSQL audits surfaced classes the checker and
review guide did not yet cover. Add them:

Static checker (.github/helper/postgres_compat.py) - new mechanical breaks:
- .rlike() / raw RLIKE: frappe rewrites REGEXP->~* on Postgres but NOT RLIKE.
- Cast(x, "char") / raw CAST AS CHAR: bare CHAR is character(1) on Postgres
  and truncates multi-digit values; use "varchar".
(Both flag zero production code; the only repo hit is in patches/, which the
hook already excludes.)

Greptile config + POSTGRES_COMPATIBILITY.md - new semantic/hard classes:
- aggregate (Sum/Count) selected next to bare columns with no GROUP BY at all.
- .like()/LIKE on a non-text column (bigint ILIKE) -> Cast_ to varchar.
- get_all(fields=["CapitalCase"]) identifier-case (extends the get_value case).
- bool into a Check column via qb.update().set() (extends set_value/db_set).
- int/int division: float a literal (col/1440 -> col/1440.0).
- Concat over a nullable column leaking a bare prefix on Postgres.
- clarify REGEXP/.regexp() is translated but RLIKE/.rlike() is not.
2026-06-23 12:22:22 +05:30
Nabin Hait
ca908b69cf Merge pull request #56246 from nabinhait/commission-fields-depends-on-sales-partner
fix(selling): hide commission fields without a sales partner and stop copying them
2026-06-23 10:42:16 +05:30
Mihir Kandoi
28b5efcbe1 fix(manufacturing): keep MPS cumulative lead-time fractional across engines
get_item_lead_time in Master Production Schedule computes
manufacturing_time_in_mins / 1440 + purchase_time + buffer_time. As in the
MRP report, manufacturing_time_in_mins is an Int column and 1440 an int
literal, so the division truncates on PostgreSQL (720/1440 -> 0) while
MariaDB yields 0.5. The value is summed over the BOM tree, ceil'd, and
drives the planned order-release date, so it diverged by engine.

Use a float numerator (1440.0). MariaDB output is unchanged; PostgreSQL
now matches it.
2026-06-23 10:38:54 +05:30
Mihir Kandoi
b0b20edd3e Merge pull request #56343 from mihir-kandoi/pg-mrp-leadtime-intdiv
fix(manufacturing): keep MRP lead-time fractional across engines
2026-06-23 10:26:51 +05:30
Mihir Kandoi
060b0df55e Merge pull request #56342 from mihir-kandoi/pg-audit6-mariadb-corrections 2026-06-23 10:02:19 +05:30
Mihir Kandoi
75030bab0f Merge pull request #56341 from mihir-kandoi/pg-audit6-hard-errors 2026-06-23 10:02:06 +05:30
Mihir Kandoi
34293d107b Merge pull request #56339 from mihir-kandoi/pg-batch-search-groupby-pk 2026-06-23 10:01:48 +05:30
Mihir Kandoi
8a20c9f681 fix(manufacturing): keep MRP lead-time fractional across engines
get_item_lead_time computed the manufacturing lead time as
1440 / manufacturing_time_in_mins + buffer_time. Both columns are Int, so
integer/integer division truncates on PostgreSQL (1440/7 -> 205) while
MariaDB yields a decimal (205.71). The value feeds math.ceil() and then
release_date = add_days(delivery_date, -lead_time), so a user could see a
release date that differs by a day between engines.

Make the numerator a float literal (1440.0) so both engines do decimal
division. MariaDB already returned a decimal, so its output is unchanged;
PostgreSQL now matches it.
2026-06-23 10:01:20 +05:30
Mihir Kandoi
f11f8cb005 fix(regional): use correct lowercase fieldname in UAE VAT tax accounts
get_tax_accounts fetched fields=['Account'] but the UAE VAT Account fieldname is lowercase account. PostgreSQL treats the double-quoted identifier case-sensitively ('column "Account" does not exist'); MariaDB identifiers are case-insensitive so it worked there. Use the real fieldname account; output unchanged on MariaDB.
2026-06-23 09:13:52 +05:30
Mihir Kandoi
16b27ecdd1 fix(stock): group the Stock Ledger opening-balance dimension query
get_opening_balance_for_inv_dimension selected item_code and warehouse alongside Sum() aggregates with no GROUP BY, which PostgreSQL rejects ('column ...item_code must appear in the GROUP BY clause'). Add GROUP BY item_code, warehouse. The query already returns early unless a single item and warehouse is selected, so this stays one row with identical values on MariaDB while becoming valid on Postgres.
2026-06-23 09:13:51 +05:30
Mihir Kandoi
bde630b888 fix(controllers): cast idx to varchar in child-row picker for Postgres
get_filtered_child_rows searched child rows by row number with table.idx.like(...). idx is an integer column; frappe maps .like() to ILIKE on Postgres, which has no bigint ILIKE operator ('operator does not exist: bigint ~~* unknown'). Cast idx to string via frappe's Cast_ with 'varchar': a bare CAST(idx AS CHAR) is character(1) on Postgres and silently truncates a two-digit idx (11 -> '1'), dropping the row; CAST(idx AS VARCHAR) keeps the full value, and on MariaDB Cast_ rewrites to CONCAT(idx, '') matching the previous implicit coercion. MariaDB output unchanged. The test builds an order with >10 rows and searches row 11 (fails on Postgres with a char(1) cast).
2026-06-23 09:13:50 +05:30
Mihir Kandoi
9f1915800f fix(edi): make Common Code docname lookup valid on Postgres
get_docnames_for issued SELECT DISTINCT on Dynamic Link.link_name while ordering by Dynamic Link.idx, a column absent from the select list. This is a raw frappe.qb query (run via .run(), not get_all/get_list), so the ORDER BY is emitted verbatim and PostgreSQL rejects it: 'for SELECT DISTINCT, ORDER BY expressions must appear in select list'. Order by link_name (the selected, distinct column) instead; same docnames on both engines, now deterministically ordered.
2026-06-23 09:13:49 +05:30
Mihir Kandoi
dc4eee49cc fix(stock): make the batch-number picker Postgres-correct
The batch-number link picker (get_batch_no) had two Postgres-only defects in
both of its query builders (get_batches_from_stock_ledger_entries and
get_batches_from_serial_and_batch_bundle):

1. GROUP BY. They group by Stock Ledger Entry / Serial-and-Batch-Entry columns
   while selecting un-aggregated Batch-master columns (manufacturing_date,
   expiry_date, search fields). PostgreSQL only accepts that when the Batch
   primary key is in the GROUP BY, so the picker raised GroupingError. Adding
   batch_table.name (equal to the grouped batch_no via the join) keeps the
   group count - and the MariaDB result - unchanged while making it valid.

2. CONCAT over nullable dates. "MFG-"/"EXP-" labels were built with
   Concat("MFG-", manufacturing_date). When the date is NULL, MariaDB CONCAT
   returns NULL but Postgres CONCAT drops the NULL and yields a bare "MFG-"/
   "EXP-". Guard each with Case().when(date.isnotnull(), ...) so a missing date
   is NULL on both engines (matching MariaDB, fixing Postgres).

Both leave MariaDB output unchanged. test_get_batch_no_search_returns_batches
exercises both builders directly and asserts no bare "MFG-"/"EXP-" leaks;
reverting either fix makes it fail on Postgres.
2026-06-23 09:04:43 +05:30
Mihir Kandoi
b4aae9dea1 fix(crm): render Lead Details address consistently across engines
The Lead Details report concatenated address_line1 and address_line2 with
CONCAT_WS. An unfilled optional Data field is stored as '' on MariaDB but as
NULL on PostgreSQL; CONCAT_WS keeps the empty string (leaving a trailing
", ") on MariaDB while Postgres drops the NULL, so the same lead rendered a
different address on each engine.

Wrap both parts in NULLIF(part, '') so empty values are treated as NULL on
both engines: the report now produces the same clean address (no trailing
separator) everywhere.
2026-06-23 08:58:30 +05:30
Mihir Kandoi
295dec24db fix(stock): group get_picked_batches by batch and warehouse
get_picked_batches summed Serial-and-Batch-Entry qty while selecting bare
batch_no and warehouse with no GROUP BY. PostgreSQL rejects this outright:

    column "tabSerial and Batch Entry.batch_no" must appear in the GROUP BY clause

MariaDB does not error but collapses every picked row into a single result -
the grand-total qty pinned to one arbitrary batch - so the caller, which keys
the result by (batch_no, warehouse) to subtract already-picked stock, under-counts
whenever more than one batch is picked.

Add GROUP BY batch_no, warehouse so the query returns one correct row per batch
on both engines (this corrects the MariaDB result, not just Postgres validity).
2026-06-23 08:58:29 +05:30
Mihir Kandoi
edf1341f42 Merge pull request #56340 from mihir-kandoi/pg-mr-supplier-distinct-orderby
fix(stock): keep supplier-based Material Request picker valid on Postgres
2026-06-23 07:59:47 +05:30
Mihir Kandoi
90ef4f4776 fix(stock): keep supplier-based Material Request picker valid on Postgres
get_material_requests_based_on_supplier deduplicated requests with
SELECT DISTINCT (name, transaction_date, company) while ordering by
mr_item.item_code, which is not in the select list. MariaDB allows this;
PostgreSQL rejects it:

    psycopg2.errors.InvalidColumnReference: for SELECT DISTINCT,
    ORDER BY expressions must appear in select list

so the picker errored out there.

Group by the three selected columns (equivalent to the DISTINCT, so the
same set of requests is returned) and order by Min(item_code). The order
key stays item_code but is now a well-defined aggregate, making the query
valid - and the ordering deterministic and identical - on both engines.
2026-06-23 07:41:39 +05:30
Mihir Kandoi
ff737df55f Merge pull request #56336 from mihir-kandoi/pg-lint-distinct-orderby
ci(postgres): flag get_all(distinct=True, order_by=...) in the static checker
2026-06-22 23:42:11 +05:30
Mihir Kandoi
50c4ee4ccb Merge pull request #56334 from mihir-kandoi/pg-irs1099-payer-tiebreak
fix(regional): deterministic IRS-1099 payer-address pick across engines
2026-06-22 23:32:53 +05:30
Mihir Kandoi
ad237e5ec5 ci(postgres): flag get_all(distinct=True, order_by=...) in the static checker
frappe's db_query SILENTLY drops ORDER BY for distinct queries on Postgres (the ORDER BY
column must appear in the SELECT-DISTINCT list), so `get_all/get_list(distinct=True,
order_by="<col>")` is a no-op there and the result comes back unordered — the root cause of
the Sales Register, Purchase Register and Sales Analytics ordering fixes. Add an AST rule to
.github/helper/postgres_compat.py that flags this (literal order_by only; an empty order_by=""
suppression and a dynamic/variable order_by are not flagged). `# pg-ok` escape hatch as usual.

Grandfather the three pre-existing low-impact sites the rule surfaces (paging/iteration order
only, not data): job_card operation autocomplete, inventory_dimension config list, and a
work_order test loop.
2026-06-22 23:22:52 +05:30
Mihir Kandoi
fadad2d1c4 fix(regional): deterministic IRS-1099 payer-address pick across engines
get_payer_address_html picks one company address with ORDER BY (Postal DESC, Billing DESC)
LIMIT 1 and no column tie-break. When a company has two addresses of the same address_type
the two CASE keys tie, so the LIMIT-1 row is implementation-defined and MariaDB and PostgreSQL
can return a different address.name — i.e. a different payer address on the rendered IRS-1099
form for identical data.

Add a final .orderby(address.name), mirroring the sibling get_street_address_html in the same
file (which already carries the "deterministic LIMIT-1 tie-break across engines" order). The
pick is now the lexicographically-smallest name on both engines.
2026-06-22 23:13:29 +05:30
Mihir Kandoi
f026d1dac8 Merge pull request #56329 from mihir-kandoi/pg-sales-analytics-order
fix(selling): deterministic Sales Analytics order-type row order on both engines
2026-06-22 20:02:27 +05:30
Mihir Kandoi
a1ed913eba fix(selling): deterministic order-type row order in Sales Analytics on both engines
get_teams fetched distinct order_types with get_all(distinct=True, order_by="order_type").
frappe drops ORDER BY for distinct queries on postgres (db_query), so the order_by is a
no-op there and the report's order-type leaf rows are not guaranteed any order on PG
(PostgreSQL only sorts them incidentally via its DISTINCT plan). Sort in python with
key=str.casefold instead, matching MariaDB's case-insensitive collation and guaranteeing
an identical, stable order on both engines (same pattern as the Sales/Purchase Register
account-column fix). Add a test locking the sorted order-type row order.
2026-06-22 19:42:37 +05:30
Mihir Kandoi
3ed305c75c Merge pull request #56330 from mihir-kandoi/pg-queries-locate-case
fix(controllers): case-insensitive employee/lead/bom search ranking on Postgres
2026-06-22 19:30:02 +05:30
Mihir Kandoi
da4cf77d97 Merge pull request #56328 from mihir-kandoi/pg-pos-item-group-escape
fix(pos): restore item-group filtering broken by double-escaped names
2026-06-22 19:23:58 +05:30
Raffael Meyer
13f9130d42 fix: hide redundant company currency fields on transactions (#54691) 2026-06-22 15:37:29 +02:00
Mihir Kandoi
98e8d5690e fix(controllers): case-insensitive search ranking in employee/lead/bom queries on Postgres
employee_query, lead_query and bom() ranked autocomplete results with a bare
Locate(txt, col) in ORDER BY. frappe maps Locate -> strpos on Postgres, which is
case-sensitive, while MariaDB's LOCATE against a column uses the column's
case-insensitive collation. So the search-dropdown ordering diverged between engines for
mixed-case matches (row count/membership unchanged — the WHERE .like() is already ILIKE).

Wrap both Locate operands in Lower(), matching the sibling item_query/get_project_name
handlers in the same file: a no-op on MariaDB, and case-insensitive (MariaDB-faithful) on
Postgres. The existing test_queries suite stays green on both engines.
2026-06-22 19:01:18 +05:30
Mihir Kandoi
32216bd75b fix(pos): return raw Item Group names from get_item_groups (double-escape regression)
The Postgres-portability change moved the POS item-group filters to the query builder
(item.item_group.isin(...)) and frappe.get_all(["name","in",...]), which escape values
once. get_item_groups() still pre-escaped each name with frappe.db.escape(), so the
names were escaped TWICE -> `item_group IN ('''Products''')`, matching nothing. Any POS
Profile that restricts item groups returned ZERO items, on both MariaDB and Postgres.

Return raw names; the parameterized callers escape them correctly. (get_parent_item_group
also returned the quoted literal before this fix.) Add a regression test: a POS Profile
restricted to an item group must still surface that group's items — it returns 0 before
the fix and passes after, on both engines.
2026-06-22 19:00:35 +05:30
Nabin Hait
d694ad9428 Merge pull request #56293 from nabinhait/fix-lead-name-none-email
fix(lead): don't crash deriving lead name when only ignore_mandatory is set
2026-06-22 18:17:16 +05:30
Nabin Hait
eee1fdf276 fix: reset grant_commission to default 1 after tests
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-06-22 18:05:20 +05:30
Nabin Hait
a120bf8363 Merge pull request #56286 from nabinhait/ci-patch-test-no-workers-during-migrate
ci: don't run background workers during patch-test migrate
2026-06-22 17:05:15 +05:30
Nabin Hait
d48cffd1a5 Merge pull request #56303 from nabinhait/test-blanket-order-multirow
test(blanket_order): cover over-ordering aggregated across rows
2026-06-22 17:04:35 +05:30
Nabin Hait
92047e896c fix(selling): carry commission_rate through Make Delivery Note / Sales Invoice
commission_rate is no_copy so it is not carried on Duplicate/amend, but the
mapper also skips no_copy fields, leaving the mapped Delivery Note / Sales
Invoice showing 0 commission until saved (it only re-fetched from the sales
partner on save). Map commission_rate explicitly in the SO->DN, SO->SI and
DN->SI mappers so it carries over immediately; Duplicate still does not copy
it.
2026-06-22 17:01:40 +05:30
Mihir Kandoi
624844d52f Merge pull request #56308 from mihir-kandoi/gh55802
fix: submittable product bundle issues
2026-06-22 16:15:59 +05:30
Nishka Gosalia
c24fc063fc Merge pull request #56309 from nishkagosalia/migrating-document-naming-setting
fix: Removing the document naming series dialog and moving to framework
2026-06-22 16:07:08 +05:30
Nabin Hait
43d2c7335d refactor(lead): name the loops in remove_link_from_prospect
The outer and inner loops both used 'd'; name them linked_prospect and lead
so the prospect/lead iteration reads clearly. No behaviour change.
2026-06-22 15:59:26 +05:30
Nabin Hait
8f69697212 fix(lead): don't crash deriving lead name when only ignore_mandatory is set
set_lead_name fell through to email_id.split('@') when a lead had no name,
company or email but ignore_mandatory was set (e.g. data import), raising
AttributeError on a None email. Only derive from email when one exists; the
lead name is then left blank, as intended for that path.
2026-06-22 15:59:25 +05:30
Nabin Hait
3f832d4ee0 Merge pull request #56247 from nabinhait/commission-rate-data-to-percent
fix(selling): make commission_rate a Percent field on Sales Person and Sales Team
2026-06-22 15:56:30 +05:30
Mihir Kandoi
d48a1e0d16 fix: address product bundle review comments 2026-06-22 15:53:52 +05:30
nishkagosalia
aa7402b1e3 fix: removing the document naming series dialog and moving to framework 2026-06-22 15:46:15 +05:30
Mihir Kandoi
a218b8db8c fix: submittable product bundle issues 2026-06-22 15:40:16 +05:30