Cover both shapes: a single operation that books the loss itself, and a
chain where an earlier operation books it and the final operation loses
nothing, so the sum over the operations is the only correct source.
(cherry picked from commit 24de81f9fa)
# Conflicts:
# erpnext/manufacturing/doctype/job_card/test_job_card.py
update_work_order_qty() returns early when track_semi_finished_goods is
enabled, so set_process_loss_qty() never ran and Work Order.process_loss_qty
stayed at zero even though the job cards and the work order operations had
booked the loss. The work order also never reached the Completed status,
since that needs produced_qty + process_loss_qty to cover the ordered qty.
Calling set_process_loss_qty() from that early return is not enough: the
final operation has no semi finished good bom, so its manufacture entry is
not from a bom, remove_fg_completed_qty() zeroes fg_completed_qty and
update_work_order_qty() is never reached at all.
The manufacture entries cannot be summed either. Each one is reset to
MAX(Work Order Operation.process_loss_qty), so every entry of a multi
operation chain carries the running maximum instead of the loss of its own
operation. Aggregate the operations instead, and refresh the work order from
the job card, which is where the operation loss is written.
(cherry picked from commit 0eb61c9fac)
# Conflicts:
# erpnext/manufacturing/doctype/job_card/job_card.py
# erpnext/manufacturing/doctype/work_order/services/status.py
Existing submitted BOMs may carry operations without a finished good,
and no migration repairs them. Exempting every semi FG job card from
the transfer check let such a card submit after a partial transfer.
Exempt only cards that skip material transfer; legacy cards with
transfer enabled keep the strict transferred qty check.
(cherry picked from commit 1deae664ce)
Every generated entry copied each Job Card Item's full required_qty in
the skip-transfer and BOM-backflush paths, so two entries for one job
card consumed the requirement twice. Scale the rows to the share of
production this entry accounts for and cap them at the requirement
still unconsumed, dropping rows that have nothing left. An entry whose
materials are exhausted then fails the existing at-least-one-raw-material
check instead of minting finished goods from nothing.
(cherry picked from commit 0428cddf5b)
Saving a submitted manufacture entry to change an allowed field re-ran
the pending production cap with a manufactured aggregate that already
includes the entry itself, so the save was rejected against the
post-entry remainder. Quantities are not editable after submit, so the
check has nothing to protect there.
(cherry picked from commit bed957fa67)
The WIP warehouse change also removed the Target Warehouse exemption
for semi FG orders, but those may validly carry the target on each
operation instead. Restore the exemption in the form and the submit
check; the WIP warehouse requirement stays.
(cherry picked from commit 9df527bf3f)
After a partial entry booked the job card's full process loss, the
next generated entry was sized qty-to-produce minus manufactured only.
It exceeded the pending production cap, so Make Stock Entry could not
finish the card. Subtract the consumed loss when sizing the entry.
(cherry picked from commit b8dd886cd4)
# Conflicts:
# erpnext/manufacturing/doctype/job_card/job_card.py
Entries from operations without their own BOM carry no For Quantity,
so the finished-good reconciliation cannot run for them and a draft
created before other entries were submitted could still over-produce.
Validate every job-card manufacture entry against the job card
directly: finished goods plus process loss must fit in what the job
card still has left to produce after earlier submitted entries.
(cherry picked from commit 94cd27ce5d)
The finished_good derivation ran in validate_semi_finished_goods,
after set_materials_based_on_operation_bom had already expanded
operation BOM materials. A single-pass insert-and-submit (API or
import) with bom_no set but finished_good empty skipped the expansion,
persisting a submitted BOM without the referenced components. The
derivation also let a final operation inherit another item from its
bom_no, so downstream job cards would produce the wrong item.
Move the derivation into set_operation_finished_goods, called before
the expansion, prefer the BOM's own item for the final operation, and
reject a final operation whose FG item is not the BOM's item.
(cherry picked from commit 1e2e87daac)
# Conflicts:
# erpnext/manufacturing/doctype/bom/bom.py
get_item_details returns the whole Item document, so the dialog row's
name became the item code. get_item_data then matched that item code
against every Components row regardless of operation, so adding an item
already used by another operation silently updated that row's qty
instead of appending one for the target operation — which stayed empty
and failed 'please add raw materials or set a BOM' on submit.
Match the existing row by item code within the same operation: same
operation updates the qty, any other match appends a new row.
(cherry picked from commit 24f1f3dea8)
# Conflicts:
# erpnext/manufacturing/doctype/bom/bom.py
set_process_loss_qty stamped MAX(process_loss_qty) across every
operation of the work order onto each manufacture entry. With semi
finished goods tracking, one operation's process loss leaked into the
entries of every other operation: validate_fg_completed_qty then
rejected the entry when it had a BOM, or the wrong loss was recorded
silently when it did not, double-counting the loss across operations.
When the entry belongs to a job card, use that job card's loss net of
what its earlier entries already booked. The MAX fallback stays for
work-order level entries without a job card.
Fixesfrappe/erpnext#57892
(cherry picked from commit 1b335973b7)
# Conflicts:
# erpnext/stock/doctype/stock_entry/stock_entry.py
When a previous operation manufactured less than the current job card
is completing, the error always said 'Submit the manufacturing entry
for the operation first' — even when the entry was already submitted
and the missing quantity was booked as process loss, which made the
advice a dead end.
Sum the process loss of the previous operation's job cards alongside
the manufactured quantity. When manufactured + process loss covers the
requested quantity, say the shortfall is process loss so the user
knows to reduce the completed quantity; keep the submit-first message
for genuinely pending manufacturing entries.
(cherry picked from commit 1e22695eae)
# Conflicts:
# erpnext/manufacturing/doctype/job_card/job_card.py
Work orders with track_semi_finished_goods were exempt from the
Work-in-Progress Warehouse requirement in three places: the field's
mandatory_depends_on, the fg_warehouse reqd toggle in the form script,
and validate_warehouse on submit.
The exemption was misleading. The flow still transfers materials to a
WIP warehouse when 'Skip Material Transfer' is unchecked: operations
default their WIP warehouse from the work order, and
set_default_warehouse silently restores the company default after the
user clears the field. Make the field genuinely required instead of
pretending it is optional.
(cherry picked from commit 198eb60df7)
validate_transfer_qty uses an empty finished_good to detect legacy job
cards, and unlike validate_semi_finished_goods it ignores
skip_material_transfer. A job card tracking semi finished goods whose
operation had no finished_good fell into the legacy branch and could
not be submitted even with 'Skip Material Transfer' checked on the
work order.
Return early for semi FG job cards; validate_semi_finished_goods
already enforces the transfer requirement for them and honours
skip_material_transfer.
(cherry picked from commit 6c8f0b9b56)
A BOM with track_semi_finished_goods enabled could be saved with no
finished_good on any operation: validate_semi_finished_goods only
checked that one row had 'Is Final Finished Good' set, and a list
containing None passed the emptiness check.
Such a BOM breaks every downstream step. The work order copies the
empty finished_good into its operations, job cards inherit it, and
Make Stock Entry finally fails with 'Item None not found' because the
manufacture entry has no production item.
Derive the finished good where it is unambiguous: an operation that
references a BOM produces that BOM's item, and the final operation
produces the BOM's own item. Otherwise require it on the row, since
each operation's job card books its output through it.
(cherry picked from commit 3497a6a6bf)
The Italy regional setup created Custom Fields first_name/last_name on
Customer. Since #46281 added standard quick-entry fields with the same
names, every Italian site carries duplicate field definitions:
- the setup wizard creates the duplicates silently because it skips
validation, and any later Custom Field on Customer then raises
UniqueFieldnameError (#50915)
- without the duplicates, creating an Italian company aborts inside
install_country_fixtures; on MariaDB an interrupted fixture run
persists Custom Field documents whose columns were never added, after
which every Company insert fails with "Unknown column
'fiscal_regime'" (#57215)
Re-land the rename from #50921 (reverted in #53409): the fields become
italy_customer_first_name/italy_customer_last_name and the e-invoice
template reads the new names. The migration patch runs only on sites
with Italy fixtures, re-runs them, explicitly syncs the schema of every
affected doctype (create_custom_fields skips unchanged fields, so its
own schema sync cannot restore missing columns), copies the old column
values wherever the new field is empty (also on sites that removed the
duplicate fields with the documented manual workaround), and deletes
the duplicate Custom Fields last so an interrupted run stays resumable.
The old insert_after anchor "salutation" no longer exists on Customer;
the renamed fields anchor after customer_type.
(cherry picked from commit 110d0a38a6)
# Conflicts:
# erpnext/patches.txt
update_qc_reference() writes the QI link and bumps the reference
document's modified timestamp via raw db writes, which emit no realtime
event. A reference form (Purchase Receipt, Delivery Note, Stock Entry,
Job Card) still open in the browser keeps the old timestamp and fails
the timestamp conflict check on the next save/submit, forcing a manual
refresh after every QI submit/cancel/delete.
Calling notify_update() on the reference publishes the standard
doc_update event, so an open, unedited form silently reloads and syncs
its timestamp. get_lazy_doc skips child table loading since
notify_update only needs the parent row.
(cherry picked from commit 647452c95b)
covers the case where the percentages are correct but the accumulated
sum is 100.00000000000001. two rows can never drift, since the second
reconstructs exactly as 100 - first, so the case needs three rows.
(cherry picked from commit 4afba94d1c)
# Conflicts:
# erpnext/selling/doctype/sales_order/test_sales_order.py
the total of allocated_percentage was compared to 100 with exact float
equality, so a correct allocation could be rejected when the sum drifts
in binary floating point (10.0 + 58.02 + 31.98 -> 100.00000000000001).
round the total to the field precision before comparing, in both
SellingController.calculate_contribution and Customer.validate.
(cherry picked from commit f7b2775829)