Address review (#56105): when there's no matching communication, first_contact is
None and date_diff(invoice_date, None) treats None as today, giving a wrong
(negative) duration. Skip the entry instead, mirroring the communication_count guard.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address review (#56105): the IS NOT NULL guard can return no rows (the count above
filters on sender, this query on recipients), so [0][0] would raise IndexError.
Fall back to None when empty, matching the prior behaviour for that case.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Parity sweep findings in queries already merged in develop:
- pos_invoice.py: serial_no return-match matched case-sensitively on Postgres (case-insensitive
on MariaDB). Replaced the get_all or_filters lookup with a qb query that case-folds both sides
via Lower() (no-op on MariaDB).
- controllers/queries.py + pick_list.py: the Locate()-based relevance ranking in link-query
ORDER BY is case-sensitive on Postgres (Strpos) vs case-insensitive on MariaDB (Locate), so
autocomplete order differed. Lower() both arguments so the ranking matches on both engines.
- crm/lead_conversion_time.py: "first contact" used ORDER BY communication_date LIMIT 1 read by
index; a NULL date sorts first on MariaDB but last on Postgres, changing the result. Added
`communication_date IS NOT NULL` so both engines return the earliest real contact date.
Verified on MariaDB and Postgres: test_pick_list 40/40, test_pos_invoice 26/26 on both engines.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
get_pick_list_query selects Sales Order.customer (a joined table's column) while
grouping only by Pick List.name. Postgres' functional-dependency relaxation applies
to a table's own primary key, not to a joined table's columns, so the query raises
GroupingError on Postgres. MariaDB arbitrary-picks and runs.
customer is already pinned to a single value by `WHERE Sales Order.customer = filter`,
so adding it to the GROUP BY is identical on MariaDB and valid on Postgres.
Test (errors with GroupingError on the old code on Postgres, passes on both engines):
- test_get_pick_list_query_postgres_valid: a submitted pick list for a customer is
returned by the link query.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The test was mutating an already-submitted RFQ, which raised
UpdateAfterSubmitError because cost_center lacks allow_on_submit.
Use do_not_submit=True, set cost_center on the draft, save, then submit.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Three Query Reports embedded double-quoted string literals and an unquoted table
identifier that error on PostgreSQL. Portability-only, no behaviour change on either engine:
- material_requests_for_which_supplier_quotations_are_not_created,
requested_items_to_be_transferred: double-quoted string literals ("Stopped",
"Material Transfer") -> single quotes (double quotes are identifiers on postgres, not strings).
- items_to_be_requested: quote the `tabBin` table identifier so postgres doesn't lower-case it.
(received_items_to_be_billed was dropped: it is a Script Report, so its `query` field is dead
code and the fix never reaches the DB.)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
3-way merged onto develop (preserving the get_party_bank_account import move).
get_subscription_details passes order_by="" so get_all does not inject the
doctype default sort the raw query never had.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
3-way merged onto develop, preserving develop's set_exchange_rate(ref_doc=doc) change.
One portable raw query is intentionally kept (as on the source branch).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The raw get_fiscal_years query had no ORDER BY (de-facto oldest-first); the
get_all port adds explicit order_by="name asc" so the Fiscal Year doctype
default (name DESC) does not reverse the report column order / cumulative values.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>