Default Warehouse and Sample Retention Warehouse were global singles, so every
consumer had to re-check that the warehouse belonged to the transaction's
company before using it. Both now live on Company, under a new Warehouse
Defaults section that also collects the warehouse fields Company already had.
The company check moves to Company.validate_warehouses, which also rejects
group warehouses for all seven fields — a group or cross-company value there
already failed at SLE time, this just surfaces it at the source.
New companies get their Stores warehouse as Default Warehouse via
create_default_warehouses, replacing the setup-wizard and test-fixture code
that seeded the global.
Subcontracting Receipt was left out of #57493. Its title_field is "title",
so the template does get rendered on insert, but never again — the title
goes stale as soon as the supplier changes.
Point title_field at supplier_name like Purchase Receipt, and give the
title field the same shape as its subcontracting siblings. Existing rows
already hold a rendered name, so no data patch is needed.
Also guard the whole class of bug: a "{...}" default on a title field is
only ever rendered when title_field is "title".
Company.create_default_warehouses stored warehouse_name through the
session _(), so a site set up in a non-English language keeps its
default warehouses under translated names. The opening-stock fallback
in item.py then looks up {"warehouse_name": _("Stores")} from an
arbitrary session and misses the warehouse whenever the lookup
session's language differs from the creation session's.
Create the default warehouses with canonical English names, matching
the identity-_ convention install_fixtures uses for other default
records. The exists-guard also matches the session translation so a
re-run on a legacy site does not insert English duplicates next to
translated warehouses.
The "Stores" fallback lookup moves to get_stores_warehouse, which
tries the canonical name first and falls back to the session
translation so legacy sites keep resolving their translated warehouse.
The setup-wizard and test-bootstrap lookups drop _() since they now
run after English creation (install_fixtures already used identity _,
so its lookup silently missed translated warehouses before this
change).
Same bug class as #57345.
Tests that create USD documents dated today() (e.g. Sales Order in
test_advance_payment_ledger_entry, USD BOM in test_routing) rely on
get_exchange_rate() finding a USD->INR Currency Exchange record. The
only seeded records are dated 2016, so the lookup misses and falls back
to an external API that is blocked in CI, returning 0. That surfaces as
"Exchange Rate is mandatory" on Sales Order validation and a
ZeroDivisionError in BOM.get_routing (hour_rate / conversion_rate).
Whether it passes depends on which shard incidentally committed the
2016 records first, making it an order-dependent flake that unrelated
PRs trip by shifting test distribution.
Seed today()-dated USD<->INR rates once in BootStrapTestData so the
lookup resolves deterministically without the external API. Rates
mirror the latest Currency Exchange test_records to keep cost
calculations unchanged.
* fix: added permission checks on various whitelisted functions
* fix: permission checks on `get_party_account` and using "select" `ptype`
* test(`BootStrapTestData`): assign `Accounts User` role to User `test@example.com`
Remove erpnext/tests/test_postgres_compat.py (and its pre-commit exclude); a unit
test for the dev-tooling lint helper isn't needed in the app test suite.
The Postgres test job is label-gated, so it does not run on every PR. This adds an
always-on pre-commit hook that statically flags the *mechanical* breaks: MySQL-only
functions (timestamp(date,time), timediff, str_to_date, date_format/add/sub,
group_concat, period_diff, SQL IF()), SHOW INDEX/TABLES/COLUMNS, single-quoted
aliases, UPDATE..JOIN, interpolated/f-string SQL carrying MySQL-isms,
set_value/db_set(<Check>, bool), and MySQL SHOW INDEX result keys.
It deliberately does NOT flag the framework auto-translations (ifnull->coalesce,
backtick/locate/REGEXP, .like()->ILIKE) nor the *semantic* divergences (loose GROUP
BY, case-sensitive ==/IN, NULL ordering, tiebreakers) — those need the test suite,
which remains the backstop. AST + structure-gated regex keep false positives near
zero (docstrings and prose skipped); '# pg-ok' exempts intentional MariaDB-only
branches. Scoped to erpnext/ excluding patches/. Includes a unit test of the checker.
SHOW INDEX is MySQL-only and errored on Postgres. Add a db-aware helper that reads
the leading index column from pg_index on Postgres and keeps SHOW INDEX on
MariaDB; both assert the field is the first column of some index.
BootStrapTestData.make_workstation() created _Test Workstation 1 referencing the
warehouse "_Test warehouse - _TC" (lowercase 'w'), but make_warehouse() never
creates that name -- it makes "_Test Warehouse - _TC" (capital W) and others.
On MariaDB the lowercase reference resolves to the capital warehouse via the default
case-insensitive collation, so it silently works. On PostgreSQL (case-sensitive) the
link cannot be found, so on a freshly-bootstrapped site make_workstation() raises
LinkValidationError: Could not find Warehouse: _Test warehouse - _TC, which aborts the
module-level BootStrapTestData() import and blocks every test extending ERPNextTestSuite.
It was masked only on sites where the workstation was already bootstrapped (make_records
skips existing) or where the lowercase name happened to exist from legacy data.
Point the fixture at the existing "_Test Warehouse - _TC". Verified on a freshly-reset
site: the buggy fixture raises the LinkValidationError on Postgres and passes after the
fix; MariaDB passes either way.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>