A batch is one valuation pool, so consumption is valued at the pooled
rate while slots may carry stale intra-batch detail (e.g. units
reconciled at zero and later merged). Consuming such a slot leaves a
negative value on positive qty. Spread the pool value across the
batch's slots when that happens; non-batchwise slots pool per
warehouse.
On cancel, update_entries_after replays every live SLE at the voucher's
posting datetime, but get_previous_sle_of_current_voucher seeded the
replay with the reversal SLE's creation, which resolves to the bucket's
own closing row. The bucket's net qty got double-counted into every
same-datetime row, so later submissions passed negative stock validation
against inflated balances, and the queued repost then rewrote correct
values with allow_negative_stock forced on, silently creating negative
stock. Backports the missing guard from eca71dce54.
Stock Balance builds stock ageing by passing its own SLE rows into
FIFOSlots, whose gates read row.has_batch_no and row.has_serial_no.
The query never selected has_batch_no at all, and read has_serial_no
from the SLE column, which is unset on rows predating v15's bundle
migration (no backfill patch exists). With the flags falsy, incoming
batch/serial stock was queued as plain qty slots while outgoing was
consumed batch/serial-wise, so the shapes never consume each other,
and bundle-based rows resolved no batch details, letting the plain
consume path overwrite batch slots in place (flt(batch_no) reads as
qty 0). Besides wrong ageing figures, sorting the resulting queue
crashed with TypeError: '<' not supported between 'int' and
'datetime.date'.
Select both flags from Item, matching Stock Ageing's own query. Only
this report is affected; develop dropped the sle_entries pass-in in
#44489.
get_single_value inside _revalue_reconciled_batch_slots runs while
rows stream through the unbuffered cursor on MariaDB, killing the
active iterator. Resolve it once in generate() with the other
prefetches.
stock_value_difference / qty equals the new batch rate only when the
reco entry carries the entire batch, as the split out/in reco SLEs and
batches reconciled from zero do. Partial direct-batch_no entries mix a
qty delta with existing stock, so their slots keep prior values.
Plain items need no such guard: the valuation engine collapses the
FIFO stack to qty_after * valuation_rate on every reconciliation, so
rescaling remaining slots at the reco rate matches the ledger. Lock
that with a test.
Batch items take the batch-slot path, which mirrors the same value
arithmetic: the reco's incoming entry dumps the revaluation remainder
on one slot. Rescale each reconciled batch's slots at its post-reco
rate (stock_value_difference / qty of the incoming bundle entry).
A reconciliation's stock_value_difference includes the revaluation of
stock already in the FIFO queue, but the whole amount was attached to
the qty-delta slot while older slots kept pre-revaluation values. A
downward revaluation therefore produced negative bucket values in the
Stock Ageing report, and repeated recos let the queue total drift away
from Stock Balance.
Re-derive every slot value as qty * valuation_rate after processing a
reco SLE, since a reconciliation values the entire balance at its rate.
Covers both single-SLE recos and the zero-out/re-add pair that flows
through the transfer bucket.
Default accounting dimensions were applied from the `company` client
trigger, which reads dimension data fetched asynchronously in
`setup_dimension_filters`. When the trigger fired before that fetch
returned, new documents were left without their default dimensions, and
Sales Order never called `update_dimension` at all.
- Apply defaults from the fetch callback in dimension_tree_filter.js so
they no longer depend on `company`-trigger timing. This fixes the race
for Sales Invoice, Purchase Invoice and Payment Entry, and populates
defaults on new Sales Orders.
- Add a `company()` override on SalesOrderController so the default is
re-applied when the company changes, matching the sibling doctypes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Stock Summary's sort selector only offered 5 of Bin's 10 qty fields; add
the rest (ordered, requested, planned, reserved for production plan,
reserved stock) and extend get_data's or_filters so bins whose only
nonzero qty is one of the new fields show up when sorted by it. Sort
labels now mirror Bin field labels.
Stock Projected Qty report had a column for every Bin qty field except
reserved_stock; add it.
(cherry picked from commit 59c0c15c2e)
The custom print template formatted debit/credit amounts with
format_currency() without passing a currency, so it fell back to the
company/system default currency (e.g. INR) instead of the selected bank
account's currency. The on-screen report already formats correctly via
the column's account_currency option.
Pass each row's account_currency to format_currency() so the printed/PDF
output matches the on-screen currency.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
update_item_rates passed price_not_uom_dependent, a key
get_price_list_rate_for never reads, and omitted conversion_factor, so a
stock-UOM price was never converted to the row UOM. The function's
(historically misnamed) price_list_uom_dependant ctx key carries the
Price List's price_not_uom_dependent value: truthy returns the found
rate as-is, falsy multiplies by conversion_factor.
Also guard on_update with is_new(): has_value_changed returns True when
there is no doc_before_save, so every first save re-wrote item rates.