the batch selector silently overwrote the item qty with the bundle total,
so editing a row qty in the dialog changed the delivered qty without any
warning. prompt for confirmation when the rows do not add up to the qty
to fetch, and only proceed if the user agrees.
The section is marked collapsible with no condition, so it always
rendered collapsed. When the transaction currency differs from the
company currency the exchange rate is relevant and was hidden behind
a click.
Adds collapsible_depends_on so the section starts expanded whenever
the transaction currency differs from the company currency, and stays
collapsed otherwise.
Replaces the hand-rolled item_prices.html table with frappe.ui.EmbeddedList,
the same primitive the proforma list uses. Drops the custom markup and styles.
The 10-row cap and the "View All Prices" link stay: the query fetches 11 rows
to return 10 plus a has_more flag, and the link routes to the Item Price list
filtered by item.
* 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 report only narrowed by sales person when the filter was set, so a user
restricted to a Sales Person saw every row once the filter was cleared.
Resolve the permitted Sales Persons from user permissions and apply them on
top of the filter. Each Sales Team parent type is matched against its own
applicable_for scope, so a permission scoped to one doctype cannot authorise
rows through the other. Descendants are already expanded by
get_user_permissions, so Hide Descendants is respected. Gated to Receivable,
since the class is shared with Accounts Payable.
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.