Commit Graph

59501 Commits

Author SHA1 Message Date
Mihir Kandoi
b0331f13f1 fix(accounts): log bank-entry failure without the rolled-back doc (review)
The savepoint rollback erases the just-inserted Bank Transaction row, so bank_transaction.log_error() created an Error Log pointing at a row that no longer exists. Use frappe.log_error(title=...) with no doc reference.
2026-06-30 12:17:36 +05:30
Mihir Kandoi
f41e8208d8 fix(crm): savepoint Email Campaign send loop (Postgres)
send_mail (called per campaign schedule in a loop) inserts a Communication via make(); on failure the except calls frappe.log_error with no rollback, raising InFailedSqlTransaction on Postgres and poisoning subsequent sends. Savepoint before make() + rollback(save_point=) before log_error. No-op on MariaDB.
2026-06-29 22:48:28 +05:30
Mihir Kandoi
4feb9f9910 fix(assets): savepoint per-entry depreciation posting (Postgres)
make_depreciation_entry posts a Journal Entry per schedule row in a loop; the except only stored the error, so the next row's je.save()/submit() ran on the Postgres-poisoned txn (InFailedSqlTransaction). Savepoint per iteration + rollback(save_point=) before storing the error; the final raise of the collected error is unchanged. No-op on MariaDB.
2026-06-29 22:48:27 +05:30
Mihir Kandoi
944eeb5921 fix(accounts): savepoint subscription-status update loop in Payment Entry (Postgres)
trigger_invoice_update_for_subscriptions loops invoices calling refresh_subscription_status (db_set/save); on failure the except calls frappe.log_error with no rollback, raising InFailedSqlTransaction on Postgres, and the next invoice runs in the poisoned txn. Savepoint per iteration + rollback(save_point=) before log_error. No-op on MariaDB.
2026-06-29 22:48:26 +05:30
Mihir Kandoi
f3785f10a2 fix(accounts): savepoint per-row merge in Ledger Merge (Postgres)
start_merge merges accounts in a loop; on failure it only rolled back when not in_test, so in tests a failed merge_account left the Postgres txn poisoned and the except log_error + the finally db_set(status) raised InFailedSqlTransaction. Wrap each row in savepoint('ledger_merge_row') and rollback to it unconditionally before log_error - this recovers the txn in both paths without the full rollback discarding the rest of the test transaction. Production still commits per successful merge, so the per-iteration savepoint rollback is equivalent to the prior full rollback. No-op on MariaDB.
2026-06-29 22:48:25 +05:30
Mihir Kandoi
6b0f3cd243 fix(crm): rollback before logging in Frappe CRM webhook handlers (Postgres)
create_prospect/create_address/create_customer insert docs and on failure call frappe.log_error with no rollback; on Postgres (untrusted external CRM webhook input) a failed insert poisons the txn so log_error raises InFailedSqlTransaction. Full frappe.db.rollback() before each log_error. No-op on MariaDB.
2026-06-29 22:45:22 +05:30
Mihir Kandoi
5110e7f0fd fix(accounts): rollback before log_error in deferred-accounting in_test branch (Postgres)
book_deferred_entries' make_gl_entries failure path: the else branch already rolls back before log_error, but the frappe.in_test branch ran doc.log_error then re-raised with no rollback -> on Postgres log_error hits InFailedSqlTransaction and masks the original error. Rollback before log_error in the in_test branch too. No-op on MariaDB.
2026-06-29 22:45:21 +05:30
Mihir Kandoi
c643fe5274 fix(manufacturing): rollback before marking BOM Creator failed (Postgres)
create_production_plan_bom (background job) save+submits BOMs in a loop; on failure the except runs self.db_set(status=Failed, error_log) with no rollback, raising InFailedSqlTransaction on Postgres so status is never set. Full frappe.db.rollback() at the top of the except. No-op on MariaDB.
2026-06-29 22:45:20 +05:30
Mihir Kandoi
790560ebf8 fix(stock): rollback before marking Stock Closing Entry failed (Postgres)
prepare_closing_stock_balance (background job) saves Stock Closing Balance rows + db_set status; on failure the except runs db_set('Failed')+log_error with no rollback, raising InFailedSqlTransaction on Postgres so the doc is never marked Failed and the job dies. Full frappe.db.rollback() before the handler's db_set. No-op on MariaDB.
2026-06-29 22:45:19 +05:30
Mihir Kandoi
44458b0ba5 fix(setup): rollback before logging in update_regional_tax_settings (Postgres)
Regional tax-template setup writes docs; on failure the except calls frappe.log_error with no rollback -> InFailedSqlTransaction on Postgres. Full rollback before log_error. No-op on MariaDB.
2026-06-29 22:42:49 +05:30
Mihir Kandoi
8c0b4a99cf fix(setup): rollback before logging in install_country_fixtures (Postgres)
Regional fixture setup writes docs; on failure the except calls frappe.log_error before frappe.throw with no rollback -> InFailedSqlTransaction on Postgres. Full rollback before log_error. No-op on MariaDB.
2026-06-29 22:42:48 +05:30
Mihir Kandoi
01811ccf85 fix(telephony): rollback before logging in call_log link_existing_conversations (Postgres)
The hook saves Call Logs in a loop; on failure the except calls frappe.log_error (INSERT) with no rollback, raising InFailedSqlTransaction on Postgres (it runs on every Contact create/update). Full frappe.db.rollback() before log_error. No-op on MariaDB.
2026-06-29 22:42:48 +05:30
Mihir Kandoi
09a3eb8509 fix(integrations): savepoint the Plaid bank-account update branch + rollback add_institution (Postgres)
add_bank_accounts hardened only the INSERT branch with savepoint('plaid_bank_account'); the parallel else/UPDATE branch ran log_error+throw after a failed existing_account.save() with no rollback -> InFailedSqlTransaction on Postgres (masking the friendly throw). Mirror the insert branch with savepoint('plaid_update_account')+rollback. Also add_institution's except log_error after a failed bank.insert() now rolls back first. No-op on MariaDB.
2026-06-29 22:42:47 +05:30
Mihir Kandoi
298df4d3aa fix(stock): savepoint per-company Material Request creation in reorder (Postgres)
create_material_request loops companies inserting+submitting a Material Request; the except calls mr.log_error (INSERT) with no rollback, raising InFailedSqlTransaction on Postgres in the scheduled reorder job, and the next company runs in the poisoned txn. Savepoint per iteration + rollback(save_point=) before log_error. No-op on MariaDB.
2026-06-29 22:38:02 +05:30
Mihir Kandoi
c97eac34bf fix(accounts): savepoint per-row bank entry in Bank Transaction upload (Postgres)
create_bank_entries loops rows inserting+submitting a Bank Transaction; on failure the except calls bank_transaction.log_error (INSERT) with no rollback, raising InFailedSqlTransaction on Postgres, and the next row runs in the poisoned txn. Savepoint per row + rollback(save_point=) before log_error. No-op on MariaDB.
2026-06-29 22:38:02 +05:30
Mihir Kandoi
4a572311bc fix(buying): insert default Supplier Scorecard records with ignore_if_duplicate (Postgres)
make_default_records inserted Scorecard Variable/Standing rows in a loop and swallowed DuplicateEntryError (frappe.NameError). On Postgres the failed insert poisons the txn so the next iteration's insert raises InFailedSqlTransaction. insert(ignore_if_duplicate=True) emits ON CONFLICT DO NOTHING, never poisoning the txn. No-op on MariaDB.
2026-06-29 22:38:01 +05:30
Mihir Kandoi
1dde2b5f1e fix(stock): savepoint repost loop in Stock Ledger Invariant Check (Postgres)
Same shape: the rows loop submits a Repost Item Valuation; a caught DuplicateEntryError poisons the Postgres txn so the next iteration's submit raises InFailedSqlTransaction. Savepoint + rollback(save_point=) before continue. No-op on MariaDB.
2026-06-29 22:38:00 +05:30
Mihir Kandoi
d7a81affc2 fix(stock): savepoint repost loop in Stock and Account Value Comparison (Postgres)
The item/warehouse loop submits a Repost Item Valuation; a DuplicateEntryError poisons the Postgres transaction, so the next iteration's .submit() raises InFailedSqlTransaction. MariaDB continues. Savepoint per iteration + rollback(save_point=) on the caught duplicate (mirrors repost_item_valuation:782). No-op on MariaDB.
2026-06-29 22:37:59 +05:30
Mihir Kandoi
91dae91769 fix(setup): deterministic tiebreaker in get_exchange_rate Currency Exchange lookup (Postgres)
get_exchange_rate orders Currency Exchange by 'date desc' LIMIT 1 with no unique tiebreaker. Currency Exchange autoname {date}-{from}-{to}-{purpose} allows multiple same-date rows (different purpose) for one currency pair; on the no-purpose-filter path all match, so MariaDB and Postgres can return a different exchange_rate for the same inputs. Add 'name desc' so both engines pick the same row. MariaDB row count unchanged.
2026-06-29 22:25:39 +05:30
Mihir Kandoi
8c03029f28 fix(controllers): guard return-rate division against a zero stock qty (Postgres)
get_rate_for_return builds Abs(stock_value_difference / actual_qty) for Sales/Delivery returns and passes it to get_value with no actual_qty filter. A matched Stock Ledger Entry with actual_qty=0 (a zero-qty repost / serial-batch row) makes Postgres raise 'division by zero' while MariaDB returns NULL. Wrap the divisor in NullIf(actual_qty, 0) so both engines return NULL. MariaDB output unchanged. Sibling of the already-fixed /actual_qty sites in stock_ledger.py and incorrect_serial_no_valuation.py.
2026-06-29 22:25:19 +05:30
Mihir Kandoi
c26ad9fc36 Merge pull request #56625 from mihir-kandoi/pg-isi-txn-fix
fix: survive a failed invoice during Import Supplier Invoice on Postgres
2026-06-29 22:20:06 +05:30
Mihir Kandoi
0431b20945 Merge pull request #56620 from mihir-kandoi/pg-orderby-limit1-tiebreakers
fix: deterministic tiebreakers for ORDER BY <date> DESC LIMIT 1 lookups (MariaDB↔Postgres parity)
2026-06-29 22:18:04 +05:30
Mihir Kandoi
4952ce0cac Merge pull request #56622 from mihir-kandoi/pg-savepoint-txn-abort
fix: savepoint catch-and-continue DB writes to survive Postgres txn-abort (InFailedSqlTransaction)
2026-06-29 22:11:47 +05:30
Mihir Kandoi
dc2d3c433d Merge pull request #56624 from mihir-kandoi/pg-ci-fanout-stop-guard
ci(postgres): fail setup if pg_ctl stop fails; drop redundant ALTER SYSTEM block
2026-06-29 22:10:52 +05:30
Mihir Kandoi
65539d44b8 fix(regional): survive a failed invoice during Import Supplier Invoice on Postgres
create_purchase_invoice caught its own failure and then ran frappe.db.set_value + log_error in the SAME transaction. On Postgres a failed insert/save aborts the whole transaction, so the error-marking died with InFailedSqlTransaction and the failure cascaded through prepare_data_for_import's per-file loop, killing the entire import; MariaDB recovers per-statement and continues.

Let create_purchase_invoice raise, and wrap each call in prepare_data_for_import in frappe.db.savepoint + rollback(save_point=...). On failure the savepoint rollback un-poisons the transaction, the error is logged, and the per-file status is set to Error and committed (self.db_set(commit=True), matching the existing process_file_data status commit) so an interrupted import durably reflects Error instead of staying at the already-committed Processing File Data; the loop then continues to the next file. The savepoint is taken after create_supplier/create_address so those are preserved exactly as before.

Behaviour change (MariaDB): a failed invoice's partially-created draft Purchase Invoice is now rolled back on BOTH engines instead of being left as an orphan draft on MariaDB. Deliberate and more correct - a failed import should not leave a partial invoice; release-note worthy.
2026-06-29 22:10:00 +05:30
Mihir Kandoi
9157c9a67b Merge pull request #56623 from frappe/patch-test-download-from-release
ci(patch): pull v14 baseline from GitHub release instead of frappe.io
2026-06-29 21:47:04 +05:30
Mihir Kandoi
f645e51338 ci(patch): fetch v14 baseline from public release URL without a token
Greptile flagged that `gh release download` with `github.token` could be
rejected for fork pull requests (token scoped to the fork, asset in
frappe/erpnext). The release is public and published, so the asset is
downloadable anonymously from objects.githubusercontent.com — drop the token
and curl the public URL directly. Removes the cross-repo token dependency and
keeps fork PRs working. Cloudflare is still bypassed since GitHub serves the
asset, not frappe.io.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 21:33:42 +05:30
Mihir Kandoi
b93a3bca16 ci(postgres): fail setup if pg_ctl stop fails before baking the datadir
The "Stop DB and stage datadir" step swallowed a failed `pg_ctl -m fast -w
stop` with `|| true`, then moved and tarred the PGDATA regardless. A stop
that times out or errors would bake a still-running, crash-inconsistent
cluster into the artifact every test shard consumes — and with
full_page_writes off, crash recovery can't repair torn pages. Drop the
`|| true` so a failed stop fails the job, mirroring the MariaDB sister's
"don't bake a dirty datadir" guard.

Also drop the redundant `ALTER SYSTEM SET fsync/synchronous_commit/
full_page_writes = off` block from install.sh. Its comment claimed the
postgres workflow "runs a service-container DB and never calls start-db.sh",
but it does call start-db.sh, which already applies those flags via `-o` on
every postgres start (setup job and each shard). The block was a no-op and
its justification was factually wrong.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 21:29:22 +05:30
Mihir Kandoi
6e955bdf3f ci(patch): download v14 baseline from GitHub release instead of frappe.io
The Patch Test job intermittently failed on the "Download erpnext v14 backup"
step with HTTP 403 Forbidden: frappe.io sits behind Cloudflare, and wget's
default User-Agent gets flagged by bot protection on cache misses. This caused
random failures across PRs that only a re-run would clear.

Pull the fixed baseline from the v14-baseline GitHub release using the built-in
token instead. Release assets are served from GitHub's CDN and authenticated
from the runner, so no rate-limit roulette.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 21:28:08 +05:30
Mihir Kandoi
0978d0304f test(manufacturing): savepoint duplicate Routing insert in create_routing (Postgres)
create_routing inserts a Routing and, on DuplicateEntryError, re-fetches and updates. On Postgres the failed insert aborts the transaction so the get_doc/save in the except raises InFailedSqlTransaction; MariaDB recovers. Savepoint + rollback before the fallback path.
2026-06-29 20:50:05 +05:30
Mihir Kandoi
2b966b69ce fix(stock): savepoint per-voucher accounting repost submit (Postgres)
make_reposting_for_accounting_ledgers submits a new Repost Item Valuation per voucher in a loop under except Exception. On Postgres a failed submit aborts the transaction so the next iteration's DB work dies with InFailedSqlTransaction; MariaDB continues. Savepoint per iteration, roll back on failure. No-op on MariaDB.
2026-06-29 20:50:05 +05:30
Mihir Kandoi
864fe50b24 fix(subcontracting): savepoint Purchase Receipt submit in make_purchase_receipt (Postgres)
Same submit()/add_comment-in-except shape as the PO->SCO mapper: on Postgres a failed submit aborts the transaction so the follow-on Comment insert raises InFailedSqlTransaction; MariaDB continues. Savepoint + rollback before add_comment. No-op on MariaDB.
2026-06-29 20:50:05 +05:30
Mihir Kandoi
b6165844ed fix(buying): savepoint Subcontracting Order submit in make_subcontracting_order (Postgres)
target_doc.submit() is wrapped in except Exception whose handler calls add_comment (a Comment insert). On Postgres a failed submit poisons the transaction so the add_comment insert raises InFailedSqlTransaction; MariaDB logs the comment. Savepoint + rollback before add_comment. No-op on MariaDB.
2026-06-29 20:50:05 +05:30
Jatin3128
6f97c7199c fix: carry item-level project to Purchase Receipt GL entries (#56568)
Purchase Receipt stock and asset GL lines used the item row's cost center
but always fell back to the document-level project, unlike Purchase Invoice
which uses the item-level project. add_gl_entry accepted a project argument
but never wrote it to the GL dict, so the inward, Stock Received But Not
Billed, landed cost, divisional loss, sub-contracting and exchange rate
lines dropped the row's project.

Write project into the GL dict and pass project=item.project on the entries
that were missing it, so project behaves like cost center and matches
Purchase Invoice.

Ticket: 72523
v14-baseline
2026-06-29 17:22:20 +05:30
Mihir Kandoi
70142d147e fix(selling): break last-sales-amount ties deterministically in Inactive Customers
get_last_sales_amt ordered by the sales date DESC only; same-date documents made the reported Last Order Amount engine-dependent. Add name DESC tiebreaker.
2026-06-29 16:29:46 +05:30
Mihir Kandoi
e52b9825e3 fix(accounts): break last-purchase-rate ties deterministically in Gross Profit
get_last_purchase_rate ordered by posting_date DESC only; same-date Purchase Invoices yielded an undefined last_purchase_rate that diverged between MariaDB and Postgres. Add purchase_invoice.name DESC tiebreaker.
2026-06-29 16:29:45 +05:30
Mihir Kandoi
93c186fea7 fix(assets): break latest asset-movement ties deterministically
get_latest_location_and_custodian ordered by transaction_date DESC only; equal-dated movements left the current location/custodian engine-dependent. Add asm.name DESC tiebreaker so both engines pick the same movement.
2026-06-29 16:29:44 +05:30
Mihir Kandoi
63ea907881 fix(accounts): break exchange-rate revaluation GLE ties deterministically
calculate_exchange_rate_using_last_gle ordered the latest-GLE lookups by posting_date DESC only. With multiple GL Entries on the latest posting_date the picked row was undefined, so MariaDB and Postgres could choose different vouchers and return a different last_exchange_rate (and revaluation gain/loss). Add gl.name DESC as a tiebreaker so both engines pick the same row; MariaDB row count unchanged.
2026-06-29 16:29:43 +05:30
Shllokkk
d4ee034637 Merge pull request #56199 from Shllokkk/create-payment-entries-from-payable-report
feat: create payment entries from accounts payable report
2026-06-29 15:21:49 +05:30
Mihir Kandoi
d0d32cb994 Merge pull request #56614 from mihir-kandoi/claude/wizardly-lamport-d0bc51
fix: delete Lead-linked Addresses on transaction deletion
2026-06-29 15:20:36 +05:30
Mihir Kandoi
56a7ee6346 fix: delete Lead-linked Addresses on transaction deletion
The lead/address cleanup pre-escaped each address name before passing the
list into a query-builder .isin() filter, which escapes again. The
double-escaping produced `name IN ('''Addr''')`, matching nothing, so
Lead-linked Addresses were never deleted on either MariaDB or Postgres.

Pass the raw list straight into .isin() so the builder escapes once.
2026-06-29 15:10:24 +05:30
Shllokkk
98b77f427b feat: create payment entries from accounts payable report 2026-06-29 14:53:46 +05:30
Ankush Menat
747374e767 fix: Use correct doctype name for PCV perm-check (#56606)
closes https://github.com/frappe/erpnext/issues/56593
2026-06-29 08:56:46 +00:00
rohitwaghchaure
5523c15ab8 fix: for purchases do voucher based reposting (#56601) 2026-06-29 14:17:13 +05:30
Sowmiya P K
6115af720b fix: adjust outstanding amount calculation in purchase and sales registers 2026-06-29 10:41:42 +05:30
MochaMind
1a66fe9907 fix: sync translations from crowdin (#56595)
* fix: French translations

* fix: Danish translations

* fix: Persian translations

* fix: Uzbek translations

* fix: Spanish translations

* fix: Arabic translations

* fix: Bulgarian translations

* fix: Czech translations

* fix: German translations

* fix: Hungarian translations

* fix: Italian translations

* fix: Korean translations

* fix: Dutch translations

* fix: Polish translations

* fix: Portuguese translations

* fix: Russian translations

* fix: Slovenian translations

* fix: Serbian (Cyrillic) translations

* fix: Swedish translations

* fix: Turkish translations

* fix: Chinese Simplified translations

* fix: Vietnamese translations

* fix: Portuguese, Brazilian translations

* fix: Indonesian translations

* fix: Thai translations

* fix: Croatian translations

* fix: Hindi translations

* fix: Burmese translations

* fix: Bosnian translations

* fix: Norwegian Bokmal translations

* fix: Serbian (Latin) translations

* fix: Esperanto translations
2026-06-29 00:36:35 +02:00
MochaMind
d8c267c253 fix: sync translations from crowdin (#56590) 2026-06-28 21:29:24 +02:00
MochaMind
56926ffe00 chore: update POT file (#56592) 2026-06-28 21:28:18 +02:00
rohitwaghchaure
6c38856f65 feat: Standard Valuation Rate (#56570)
* feat: standard rate valuation

* fix: greptile comments

* fix: PPV account should be mandatory for standard cost valuation
2026-06-28 20:35:01 +05:30
Mihir Kandoi
081fbe9e3f Merge pull request #56586 from mihir-kandoi/alias-no-copy
fix: party aliases should be no copy
2026-06-27 16:24:40 +05:30