Commit Graph

60483 Commits

Author SHA1 Message Date
Nabin Hait
2a9603fcd6 style(selling): organise Proforma Invoice form into sections
Group fields with section and column breaks: Details (two columns), Items with
right-aligned totals, Print Settings (two columns), and Status (two columns).
2026-07-17 20:12:37 +05:30
Nabin Hait
63607e91fd feat(selling): open the Proforma tab after creating a proforma
Flag the form on create and activate the Proforma tab once the reloaded form
has rendered the list, so the new proforma is shown immediately.
2026-07-17 20:04:18 +05:30
Nabin Hait
853c1d8986 feat(selling): add a New button below the proforma listing
Place a "+ New" button under the Proforma tab list to create another proforma
without leaving the tab.
2026-07-17 19:16:28 +05:30
Jatin3128
a33da337ec feat: block sales invoice submit when customer overdue exceeds threshold (#57230)
* feat: block sales invoice submit when customer overdue exceeds threshold

Adds an opt-in, per-customer Overdue Billing Threshold. When enabled in
Accounts Settings, submitting a Sales Invoice is blocked if the customer's
overdue amount exceeds their threshold, unless the current user holds a
configured bypass role. Modeled on the existing credit limit feature.

- Accounts Settings (Credit Limits tab): enable toggle + bypass role.
- Per-customer threshold on the Customer Credit Limit table, shown only
  when the feature is enabled via a property setter (same mechanism as
  subscription / accounting dimension sections). Table relabeled to
  "Credit & Overdue Limits".
- Overdue is read live from the ledger via get_outstanding_invoices
  (payments already netted), summing Sales Invoices past their due date.
- Enforced in Sales Invoice on_submit, after the credit-limit check;
  returns are exempt.
- validate_credit_limit_on_change no longer trips when a row sets only
  the overdue threshold (credit_limit = 0).

Fixes #52960

* fix: compute overdue amount in company currency and format with fmt_money

get_customer_overdue_amount now sums GL Entry debit - credit grouped per
invoice, which is always booked in company currency, instead of using
get_outstanding_invoices which returns the receivable-account currency.
The threshold is in company currency, so the previous comparison could mix
currencies for customers with a foreign-currency receivable account. This
mirrors how get_customer_outstanding computes the figure for the existing
credit-limit check.

The blocking message now formats both amounts with fmt_money using the
company currency.

Adds a test asserting a 100 USD invoice at a conversion rate of 50 is
counted as 5000 in company currency.

* refactor: drop redundant threshold coercion and dead test cleanup

- Coerce the overdue threshold with flt() once when reading it, instead of
  calling flt() on it at each of the three use sites.
- Remove a no-op set_overdue_billing_threshold() call in the feature-disabled
  block (the threshold was already set to that value) and the trailing reset,
  which is dead since each test is rolled back.

No behaviour change.

* fix: compute overdue amount from payment terms, matching the Overdue status

The overdue amount keyed on Sales Invoice.due_date, which set_due_date() sets
to the LAST payment term. An invoice whose first term was past due and unpaid
was therefore counted as zero, even though ERPNext already shows it as Overdue
in the invoice list. The gate and the UI could disagree.

get_customer_overdue_amount now follows the same rule as is_overdue(): per
invoice, the amount that has fallen due (sum of payment schedule terms past
their due date) minus what has been paid, clamped to the outstanding balance.
Invoices without a schedule (POS, opening) still fall back to the invoice due
date, mirroring is_overdue()'s own guard.

The ledger stays the source of truth for what is unpaid: the outstanding per
invoice is still SUM(debit) - SUM(credit) from GL Entry. base_payment_amount is
always stored in company currency, so no currency conversion is needed and the
comparison against the threshold stays consistent.

Adds a test covering a two-term invoice: only the past-due term counts, and
paying it off clears the overdue amount.

* feat: honour the overdue billing threshold set on the customer group

The threshold lives on Customer Credit Limit, which is also rendered on
Customer Group. A threshold set there was stored but never evaluated, so the
configuration was a silent no-op.

get_overdue_billing_threshold now reads the customer's row and falls back to
its customer group, mirroring get_credit_limit. The group's
bypass_credit_limit_check is deliberately not consulted: it is labelled for the
credit limit check at sales order and is unrelated to overdue billing.

get_customer_group_details also dropped the threshold when copying group rows
onto a customer, because it copied a single hardcoded field per table. It now
copies a list of fields per table, so credit_limit and overdue_billing_threshold
both carry over.
2026-07-17 18:58:10 +05:30
Nabin Hait
1da4657530 feat(selling): option to hide item qty on amount-based proforma print
Add a "Hide Item Quantity in Print" option (Amount basis only) that omits the
qty and rate columns from the printed proforma, for a clean value-based
document that shows only item and amount.
2026-07-17 17:44:04 +05:30
Nabin Hait
2242f1b230 feat(selling): make qty editable in amount-based proforma
In Amount basis, both qty and amount are now user-entered and the rate is
derived from them (rate = amount / qty). Previously qty was forced to the
ordered qty, which ignored an edited qty when switching basis.
2026-07-17 17:37:01 +05:30
rohitwaghchaure
40f861c0a0 fix: parallel reposting stalls between scheduler ticks (#57220) 2026-07-17 16:27:27 +05:30
Poovetha
7248961568 fix(projects): add project filter 2026-07-17 15:03:25 +05:30
Poovetha
79e5ccd370 test(projects): add test to ensure on hold project retains status 2026-07-17 15:03:25 +05:30
Poovetha
51a9fc0316 fix(projects): include on hold status in project filters and reports 2026-07-17 15:03:25 +05:30
Nabin Hait
77540403ab feat(selling): prefill remaining proforma qty/amount and reorder Create button
- Pre-fill each line with the remaining (ordered minus already proformed) qty
  and amount, so the default no longer trips the excess warning
- Place the Proforma Invoice action after the standard Create options
2026-07-17 14:11:26 +05:30
Mihir Kandoi
3f53475cad Merge pull request #57233 from mihir-kandoi/fix-stock-entry-pending-work-order-query
fix: replace column-literal work order filter with server-side query
2026-07-17 14:05:05 +05:30
Mihir Kandoi
eed7c98b30 fix: replace column-literal work order filter with server-side query
The work_order link filter in Stock Entry passed the string
`tabWork Order`.produced_qty as a filter value. It was never a real
column comparison: db_query coerces string values on numeric fields
with flt(), so the condition silently degraded to qty > 0, and on
backends that don't coerce text to numeric (postgres) such filters
fail with InvalidTextRepresentation.

Move the condition into a whitelisted search query that compares the
columns properly (qty > produced_qty), mirroring pick_list's
get_pending_work_orders.
2026-07-17 13:54:08 +05:30
Nabin Hait
4177101ac0 feat(selling): warn when total proforma exceeds the ordered qty/amount
Show a non-blocking notice below the item table when a line's total proforma
quantity (or amount) — this proforma plus already-issued ones — exceeds the
Sales Order line's ordered value. It updates live as the qty/amount or the
basis changes, and the user can still create the proforma.

Issued-proforma qty/amount are aggregated per line on demand (cancelled
proformas excluded); nothing is stored on the Sales Order.
2026-07-17 13:42:11 +05:30
Mihir Kandoi
d8eb029284 Merge pull request #57228 from mihir-kandoi/fix-transit-warehouse-company-fallback
fix: fall back to the company in-transit warehouse
2026-07-17 13:06:54 +05:30
Mihir Kandoi
920e64ded0 fix: fall back to the company in-transit warehouse
set_transit_warehouse re-tested from_warehouse inside a guard that
already requires it, so the Company branch of its ternary was
unreachable: with no default on the source warehouse the field stayed
empty and Company.default_in_transit_warehouse was silently ignored.
Try the warehouse's default first, then the company's.
2026-07-17 13:05:29 +05:30
Nabin Hait
f711375885 feat(selling): keep cancelled proformas visible with their PDF
Cancelling a proforma should void it, not erase history.

- Persist the Cancelled status on cancel (db_set) and keep the PDF attached
- Proforma tab now lists cancelled proformas with a red status badge, so the
  voided document and its PDF stay reachable for audit
2026-07-17 12:50:44 +05:30
Nabin Hait
473c655cb2 feat(selling): add amount-based proforma option
Let a proforma be created by editing item amount instead of quantity, for
value/advance-style proformas.

- "Based On" (Quantity | Amount) on the proforma and the create dialog
- Amount basis keeps the ordered qty and derives a rate so the line totals
  the entered amount; the PDF renders the same in-memory Sales Order copy
- Proforma Invoice Item now stores rate and amount
2026-07-17 12:50:44 +05:30
Nabin Hait
f9a09e1b3d refactor(selling): drop proforma quantity tracking
Remove the pending/proforma-qty machinery: it only fit staged, incremental
proformas and misrepresented the common whole-order / re-issued cases.

- Drop proforma_qty from Sales Order Item and its submit/cancel write-back
- Drop pending-qty aggregation and the over-qty soft warning
- The create dialog now pre-fills the ordered qty (editable down)
2026-07-17 11:51:03 +05:30
Nabin Hait
b0c53ac5a4 test(selling): add Proforma Invoice tests
Cover partial proforma being non-blocking on delivery/billing,
pending-qty aggregation with cancelled proformas excluded, tax scaling
to the partial qty, over-qty as a soft warning, and the settings gate.
2026-07-17 11:45:49 +05:30
Nabin Hait
fdc8879ce1 feat(selling): wire Proforma Invoice into Sales Order form
- Create > Proforma Invoice dialog with naming series, print format and
  letter head selectors, and an item-wise pending-qty grid
- Proforma tab listing issued proformas with inline view/email actions,
  shown only once at least one proforma exists
- Register the client script and add the connections dashboard link
2026-07-17 11:45:49 +05:30
Diptanil Saha
9fdb6dd875 Merge pull request #57224 from diptanilsaha/fix/dunning_type_validation
fix: added missing validations for `Dunning Type`
2026-07-17 10:45:40 +05:30
diptanilsaha
2325068b19 test: added tests for Dunning Type validation 2026-07-17 10:35:10 +05:30
diptanilsaha
c8e7674d63 fix: added missing validations for Dunning Type 2026-07-17 10:35:04 +05:30
Mihir Kandoi
0cba26c608 Merge pull request #57225 from mihir-kandoi/fix-duplicate-workspace-links
fix: remove duplicate links from home and projects workspaces
2026-07-17 08:05:53 +05:30
Mihir Kandoi
7fc43aba72 fix: remove duplicate links from home and projects workspaces
Workspace re-export in #56864 duplicated every link in the Home and
Projects workspaces, so desk renders each link twice. Same issue as
55afd95b20. Bumped modified so existing sites re-sync.
2026-07-17 07:55:17 +05:30
Mihir Kandoi
fc50e23daa Merge pull request #57194 from aerele/fix-operation-batch-size-flag-n-plus-one
fix: batch operation batch-size flag lookups to avoid n+1 query in wo…
2026-07-17 07:47:59 +05:30
pandiyan
6500752440 fix: batch operation batch-size flag lookups to avoid n+1 query in work order operations 2026-07-16 23:35:45 +05:30
MochaMind
2b4fc02c81 fix: sync translations from crowdin (#57188) 2026-07-16 18:01:04 +02:00
Shllokkk
76298d9bee Merge pull request #57198 from Shllokkk/strip-account-number-coa-importer
fix: strip account number when building account name in COA importer
2026-07-16 20:50:58 +05:30
Nishka Gosalia
5fc03a116a feat: map settings for DocTypes to show on settings dialog (#57025)
fix: mapping settings for DocType settings
2026-07-16 19:30:27 +05:30
Nabin Hait
65db3e374b feat(selling): add Proforma Invoice print format
Jinja print format on Sales Order, rendered against the in-memory
qty-adjusted copy so taxes and totals reflect the partial quantity.
2026-07-16 16:51:56 +05:30
Nabin Hait
07756f2bec feat(selling): add Proforma Invoice doctype and server API
- Submittable, non-accounting Proforma Invoice + Proforma Invoice Item
  child doctype (in_create; posts no GL/stock, stores item + qty only)
- Server API: pending-qty aggregation per Sales Order line (issued
  proformas only), make_proforma_invoice (sole creation path, gated on
  the settings toggle), PDF rendered from an in-memory qty-adjusted copy
  of the Sales Order and attached, send_proforma_email
- Non-blocking proforma_qty write-back to the Sales Order on submit/cancel
2026-07-16 16:51:48 +05:30
Nabin Hait
fbdc1f5b1f feat(selling): add proforma invoice settings and tracking field
- Selling Settings: "Enable Proforma Invoice" toggle (opt-in) and a
  default proforma print format
- Sales Order Item: non-blocking proforma_qty counter
2026-07-16 16:51:37 +05:30
Diptanil Saha
ac68db3fa6 refactor(dunning): converted get_dunning_letter_text to doc method and restrict_globals on render_template (#57205) 2026-07-16 16:06:13 +05:30
rohitwaghchaure
7b517a4e64 feat: book Expenses Added To Stock GL entries for stock vouchers (configurable) (#57190)
* feat: book Expenses Added To Stock GL entries for Stock Entry, Stock Reconciliation and LCV

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat: make stock expense GL booking configurable via Accounts Settings

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: skip stock expense booking for unconfigured companies, check flag once per compose

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 10:04:45 +00:00
Mihir Kandoi
a25acee43f Merge pull request #57179 from aerele/link-portal-users-to-contact-from-relevent-doctype
feat(stock): automatically link portal users to their associated contact profiles for customers and suppliers
2026-07-16 15:23:49 +05:30
Afsal Syed
9ae2069bd9 test(stock): add portal user contact link verification for customer and supplier 2026-07-16 15:11:28 +05:30
Afsal Syed
337a06dfb6 feat(stock): automatically link portal users to their associated contact profiles for customers and suppliers 2026-07-16 15:11:28 +05:30
Mihir Kandoi
103f3e50a7 Merge pull request #57202 from mihir-kandoi/pg-read-committed-gates
fix(stock): serialize postgres stock writes per (item, warehouse); block GL inserts during account rename
2026-07-16 14:10:56 +05:30
Mihir Kandoi
d0010fda68 Merge pull request #57204 from mihir-kandoi/fix-production-plan-min-order-qty
fix: consider min order qty in the purchase/transfer flow of production plan
2026-07-16 13:28:55 +05:30
Mihir Kandoi
448316fe8e test: assert row count in the min order qty split scenario 2026-07-16 12:56:11 +05:30
Mihir Kandoi
2f8d588093 fix: consider min order qty in the purchase/transfer flow of production plan
The transfer flow ignored Consider Minimum Order Qty twice: the JS
handler force-reset the checkbox before fetching items, and the
purchase remainder left after allocating transfers from other
warehouses was never raised to min_order_qty (the check runs on the
total requirement before the split).

Drop the JS reset and apply min order qty to the purchase remainder,
in stock UOM before the purchase UOM conversion.
2026-07-16 12:46:21 +05:30
Mihir Kandoi
b100e6d414 fix(stock): serialize pick list allocation per item on postgres
Two simultaneous allocations for the same item can both claim the same stock
on postgres: the picked-items locking read cannot see the rows another
in-flight creation is inserting, while MariaDB's gap locks make the creations
take turns. Advisory-gate set_item_locations per item (sorted against
deadlocks) so the second allocation waits, then subtracts the first's claim.
MariaDB unchanged.
2026-07-16 09:58:09 +05:30
Mihir Kandoi
897eca895a fix(stock): fall back gracefully when transaction_advisory_lock is unavailable
Same hasattr pattern as repost_gate: an ERPNext ahead of its frappe build keeps
the status-quo serialization-failure retries instead of failing every stock
submission on postgres.
2026-07-16 09:32:03 +05:30
Mihir Kandoi
35a9d7b09c fix(accounts): block GL Entry inserts during account rename on postgres
The for_update read in _ensure_idle_system only blocks new GL inserts on
MariaDB, via the gap lock it takes; a postgres row lock never blocks inserts,
so the guard silently degraded to the 5-minute recency check. LOCK TABLE IN
EXCLUSIVE MODE blocks writers (not readers) until the rename commits and NOWAIT
keeps the wait=False fail-fast, feeding the existing QueryTimeoutError path.
2026-07-16 09:21:17 +05:30
Mihir Kandoi
9cfdb482fc fix(stock): serialize stock writes per (item, warehouse) with a txn advisory lock on postgres
Postgres locking reads never see rows a concurrent transaction is inserting
(MariaDB's gap locks block the insert, then its locking reads return the fresh
row), so two concurrent writers for the same (item, warehouse) compute from the
same stale previous SLE and the loser overwrites Bin with a wrong absolute qty.
Today only the REPEATABLE READ serialization-failure retry catches this; the
gate makes correctness lock-based, covers the empty-history first-transaction
case (nothing exists to row-lock), and keeps negative-stock validation accurate
against concurrently inserted SLEs. Taken at the top of make_sl_entries (sorted
pairs, before the future_sle_exists cache warms) and in
update_entries_after.__init__ for the repost paths; re-entrant, released at
commit. MariaDB paths unchanged.
2026-07-16 09:21:07 +05:30
Shllokkk
6f6ec3072a Merge branch 'develop' into strip-account-number-coa-importer 2026-07-16 00:18:46 +05:30
Shllokkk
cbe406ee2a fix: strip account number when building account name in COA importer 2026-07-16 00:17:35 +05:30
Mihir Kandoi
7fe4dc1367 Merge pull request #56746 from frappe/mergify/configuration-deprecated-update
ci(mergify): upgrade configuration to current format
2026-07-15 12:53:07 +05:30