Follow-up to 329126a8d2; review findings: the claim capped away
legitimate coverage and the claim-sum validation still blocked the
honest remainder.
- material_transferred_for_manufacturing is now owned solely by the
recomputation: finished-good qty covered by net item transfers
(non-additional transfers minus returns, alternatives mapped to the
original required item), capped at planned qty plus the transfer
allowance instead of a hard 1.0 fraction.
- update_work_order_qty delegates the field to that recomputation and no
longer validates SUM(fg_completed_qty) for transfers, so the
advertised remainder submits after an under-covered entry; inflated
claims cannot reach the stored value anyway.
- Coverage from For Quantity = 0 entries (pick list / material request)
adds to claimed entries instead of being capped away, and returns
reduce both the stored value and the In Process predicate.
A Material Transfer for Manufacture entry could claim any For Quantity
regardless of what its rows carry; the work order copied that claim into
material_transferred_for_manufacturing on submit. Editing rows down after
generating the entry marked the work order fully transferred, blocking
further transfers and allowing manufacture entries without material.
Cap SUM(fg_completed_qty) by the finished-good qty the transferred item
quantities actually cover (the pick-list min-fraction rule). Status now
treats any raw-material transfer as material movement, not only pick list
or material request sourced entries, so a zero-coverage partial transfer
still moves the work order to In Process.
* feat: capacity aware scheduling for production plan
* fix: do not apply incomplete schedule proposals
* fix: lock plan re-scheduling once work orders exist
* test: concurrent jobs across multiple machines with job capacity
* chore: fix linter and semgrep issues
* fix: readable subject for production plan schedule entries
* fix: persist computed start for item rows without explicit dates
* fix: block manual creation of production plan schedule entries
* chore: replace em-dashes with hyphens in design doc
* fix: cleared item-wise dates no longer constrain the schedule
* chore: format test file
The detailed-view chart collapsed every row into a single "today" column
and was additionally capped at 10 points, so the chart never matched the
report's date filters or the table data.
Two causes in get_detailed_view_chart_data:
1. `row.deliver_date` was a typo for `row.delivery_date` (the name used
everywhere else in this report). On a frappe._dict the missing
attribute resolves to None, so `getdate(None)` returned today and the
past-date filter silently compared every row against today instead of
its own delivery date.
2. A hard `if i == 10: break` truncated the chart to 10 date buckets.
Use the correct field name and drop the cap. The null check now runs
before the date comparison, since `getdate(None)` returning today meant
the original ordering could never filter a null delivery_date out.
Fixes#52632
The qty-sync fix corrects allocation going forward, but receipts billed
before it can keep understated billed_amt, per_billed, and status. The
earlier repair patch only selects over-billed PO items, so it never picks
these up.
Recompute every candidate PO item (multiple submitted receipts, PO-level
invoicing, no invoice-created receipts). update_billed_amount_based_on_po
only writes rows whose recomputed value differs, so already-correct items
are untouched and the patch stays idempotent. This also converges receipts
left with direct-only billed_amt by last-event-wins overwrites.
The amount-capped allocation branch reduced the remaining PO-invoiced
amount but left the invoiced qty untouched. A later receipt entering the
qty-proportional branch then divided by the stale qty and was under-billed:
PO 10 x 500, PO-level PI for 5 (2500), PR1 qty 3 with 500 billed directly
consumes 1000 (pool 2500 -> 1500, qty stuck at 5), PR2 qty 3 got
1500 * 3/5 = 900 instead of its full 1500. Scale the remaining qty by the
consumed fraction so both stay proportional.
Follow-up to #58021.
Move the insert-time check from before_insert to validate. before_insert
runs before set_new_name, so the validation message rendered the
warehouse name as None. validate runs after naming and only applies to
new documents via is_new().
Resolve inheritance through the parent's lft/rgt bounds instead of the
request-cached warehouse account map. The cached map can be stale within
a request (a parent created moments earlier is missing from it), which
made get_warehouse_account trigger a full nested-set rebuild_tree and
could falsely reject a child whose parent carries a valid account.
rebuild_tree enables auto_commit_on_many_writes, which must not run
inside a document insert.
A Purchase Receipt row created from a Purchase Invoice carries both
purchase_order_item and purchase_invoice_item, and its billed_amt is pinned
to the row amount by update_billing_status. Redistributing the PO-invoiced
pool over such rows zeroes the invoice-created receipt and flips it from
Completed to To Bill, so the repair leaves those PO Items untouched.
enable_auto_reserve_stock ran at the end of validate, after
make_packing_list. On a new Sales Order saved with auto_reserve_stock
enabled, packed item rows were built while the parent reserve_stock
flag was still unset, so they never inherited it. Since the stamping in
packed_item.py is gated on doc.is_new(), later saves could not repair
the rows either; only the client-side toggle could. Move the
auto-enable before packing list generation so packed rows are stamped
on first save.
sales invoice's update_current_stock ran one bin query per item row and one
per packed row. delivery note already batched the same work by warehouse, so
lift that into get_bin_qty_map in stock/utils.py and have both call it.
also batch the per-batch expiry_date lookup in get_batches_by_oldest, and drop
three now-unused per-row setters: delivery note's set_actual_qty (already dead
before this change), sales invoice item's set_actual_qty and packed item's
set_actual_and_projected_qty.
three cases: multiple warehouses get a column each plus the total qty
column, a selected group warehouse still expands to its children, and
multiple items report side by side while unselected items stay out.