Commit Graph

60483 Commits

Author SHA1 Message Date
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
824415d50e test: cover AR/AP show-remarks, delivery notes and group-by-party filters
Add coverage for previously untested checkbox filters: Show Remarks (the
invoice remark appears in the row) and Show Linked Delivery Notes on the
receivable report, and Show Remarks and Group By Supplier on the payable
report.
2026-06-23 11:32:31 +05:30
Nabin Hait
d98b269033 test: cover all projected-qty components in Stock Projected Qty report
Add a test exercising the full projected_qty formula - actual + ordered +
requested + planned minus reserved, reserved-for-production, reserved-for-
subcontract and reserved-for-production-plan - and asserting each component
is surfaced as its own column.
2026-06-23 11:08:40 +05:30
Nabin Hait
8c124ed4a9 test: cover AR/AP journal-entry payments and credit notes
The receivable/payable reports lacked coverage for settling invoices via a
Journal Entry (rather than a Payment Entry) and for credit notes raised via
JE. Add: an invoice partially and fully paid via JE on the receivable side,
a standalone JE credit note showing as negative outstanding, and a supplier
invoice partially paid via JE on the payable side.
2026-06-23 11:04:17 +05:30
pandiyan
553b55b2f0 fix: skip qty over-allowance check for non-stock items only 2026-06-23 11:00:15 +05:30
Nabin Hait
e0114d56db test: cover Stock Balance include-zero and ageing checkbox filters
Add coverage for two untested Stock Balance checkbox filters: zero-balance
items are hidden unless 'include zero stock items' is on, and the stock
ageing columns appear only when 'show stock ageing data' is on.
2026-06-23 10:56:04 +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
vorasmit
48d5e8732b fix: whitelist get_tax_rate 2026-06-23 10:38:58 +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
Shllokkk
3251b40365 fix: show contextual balance label on party dashboard for net balances 2026-06-23 01:44:42 +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
0602a22e4b test(project): cover costing and billing roll-ups
Covers the sales/billing roll-up (total_sales_amount, total_billed_amount,
gross margin) via the whitelisted update_costing_and_billing, and
consumed-material cost from a project-linked Stock Entry issue. The
purchase-cost roll-up is already covered by the Purchase Invoice tests.
2026-06-22 18:38:51 +05:30
Nabin Hait
b90a364c31 test: add Cash Flow report correctness coverage
The Cash Flow report only had a smoke test. Add correctness tests for the
indirect method: a cash sale increases net change in cash by its amount,
and a cash purchase of a fixed asset is an investing outflow that reduces
it. Both measure the delta around a single transaction so they are
independent of existing company data.
2026-06-22 18:35:35 +05:30
Nabin Hait
b82461bf0f test: add General Ledger report filter coverage
The General Ledger report's everyday filters were untested (existing tests
only covered exchange-rate revaluation and the ignore-journals/cr-dr-notes
filters). Add coverage for opening/total/closing balance rows, group/
categorize by account subtotals, and the party filter.
2026-06-22 18:30:37 +05:30
Nabin Hait
b2bae839ac test(activity-cost): cover default-cost title and duplication
Covers the no-employee path (title set to the activity type and the
default-cost duplication guard) and employee_name being fetched for the
title. Brings activity_cost.py to full coverage.
2026-06-22 18:27:00 +05:30
Nabin Hait
6ef8b41c3c test(project-template): cover dependency-task validation
A template task that depends on another task requires that dependency to
also be present in the template's task list; covers both the rejection
and the valid case.
2026-06-22 18:25:17 +05:30
Nabin Hait
674157767a test: cover Trial Balance report filters and closing-balance setting
Extend Trial Balance coverage across its filters: show zero values, show
group accounts, show net values, period closing entry for current period,
show unclosed FY P&L balances, include default finance book entries, and
the ignore_account_closing_balance setting (cached Account Closing Balance
vs recomputed-from-GL opening).
2026-06-22 18:23:29 +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
bab97aaad0 test(timesheet): cover activity cost and billing-rate helpers
Covers get_activity_cost falling back to the Activity Type rates (and the
empty result for an unknown type), plus get_timesheet_data and
get_timesheet_detail_rate for a billable timesheet detail.
2026-06-22 18:14:40 +05:30
Nabin Hait
14b83b46ac test(task): cover bulk actions, template deps, and delete guards
Covers the whitelisted set_multiple_status and add_multiple_tasks helpers
(including the blank-subject skip), the template-task dependency
validation, the on_trash child-exists guard, and a child task
registering itself in its parent's depends_on.
2026-06-22 18:14:38 +05:30
Nabin Hait
ecfc8cc400 test: add correctness coverage for Trial Balance report
The report previously had a single dimension-filter test. Add tests using
fresh accounts: a posted journal entry lands in the period debit/credit
columns with the grand total balanced, and an entry before the from-date
rolls into the opening-balance columns.
2026-06-22 18:06:21 +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
53f0049e75 test(project): cover create_duplicate_project and set_project_status
Both are whitelisted, UI-triggered functions that had no server tests.
Covers duplicating a project with its tasks (and the same-name guard),
and bulk-setting a project plus its tasks to a terminal status (and the
invalid-status guard).
2026-06-22 18:04:53 +05:30
Nabin Hait
e59b772c36 test: add coverage for Stock Projected Qty report
The Stock Projected Qty report had no test file. Add tests for projected
qty rolling up actual + ordered, shortage qty derived from the warehouse
reorder level, and item filtering.
2026-06-22 18:00:36 +05:30
Nabin Hait
76b0123778 test(project): cover update_percent_complete for all methods
Adds assertions for the four percent_complete_method paths (Manual is
already covered), plus the status transitions: 100% flips a project to
Completed, reopening a task flips it back to Open, and a Cancelled
project keeps its status. The method was previously unasserted.
2026-06-22 17:38:23 +05:30