Commit Graph

58744 Commits

Author SHA1 Message Date
Mihir Kandoi
08af36d86e Merge pull request #57870 from frappe/mergify/bp/version-16-hotfix/pr-57866
fix: optimize product bundle item search (backport #57866)
2026-08-07 16:11:03 +05:30
Mihir Kandoi
693cade177 chore: resolve conflict 2026-08-07 16:07:36 +05:30
Krishna Shirsath
29349711e4 fix: optimize product bundle item search
(cherry picked from commit b3867f1428)

# Conflicts:
#	erpnext/selling/doctype/product_bundle/product_bundle.js
2026-08-07 10:33:43 +00:00
Diptanil Saha
eb7dfa1337 Merge pull request #57846 from diptanilsaha/backport/57825
refactor(accounts)!: rework Purchase Invoice hold actions and enforce them on Journal Entry (backport #57825)
2026-08-07 15:06:59 +05:30
Mihir Kandoi
e1473140cc Merge pull request #57852 from frappe/mergify/bp/version-16-hotfix/pr-57851
fix: round Production Plan mr_items quantity to field precision (backport #57851)
2026-08-07 03:24:10 +05:30
Mihir Kandoi
460fe9af3e chore: resolve conflict 2026-08-06 21:32:24 +05:30
Mihir Kandoi
9f8aa3cf1b test: remaining purchase qty is rounded to field precision
Covers the _add_remaining_purchase_request path: partial stock in
another warehouse is allocated as a transfer and the residual purchase
qty goes through the second rounding site.

(cherry picked from commit 75145cc72c)
2026-08-06 15:41:41 +00:00
Mihir Kandoi
9f9cb5c3b6 test: mr_items quantity is rounded to field precision
(cherry picked from commit f5157bf3c4)
2026-08-06 15:41:41 +00:00
Mihir Kandoi
2d056aee3d fix: round production plan mr_items quantity to field precision
The stock-UOM qty is rounded in _accumulate_so_items, but the purchase
UOM conversion divided it by the conversion factor without re-rounding,
storing values like 5738748.300863984 in mr_items.quantity. The raw
value flowed into Material Request qty and the raw materials CSV, and
make_material_request compares quantity to requested_qty with exact
float equality, so any rounding downstream left dust quantities.

(cherry picked from commit ffc515f046)
2026-08-06 15:41:40 +00:00
Mihir Kandoi
e1c1c5ed7e refactor: remove unreachable UOM conversion in production plan
The division by conversion_factor in _adjust_required_qty_for_uom sits
directly after frappe.throw inside the same block, so it can never run.
It has been dead since commit 2a8cd05b44 (#27278) re-indented it into
the throw branch; the actual purchase-UOM conversion happens in
_material_request_item_row via _mr_purchase_conversion_factor.

(cherry picked from commit 44260b469f)

# Conflicts:
#	erpnext/manufacturing/doctype/production_plan/services/material_request.py
2026-08-06 15:41:40 +00:00
diptanilsaha
0bb0f6d689 test(journal_entry): added test cases for blocked purchase invoices 2026-08-06 17:07:26 +05:30
diptanilsaha
04718e15c9 fix(journal_entry): validate blocked purchase invoices 2026-08-06 16:50:33 +05:30
diptanilsaha
c8125b8b5a refactor(purchase_invoice): expose invoice hold actions as document methods 2026-08-06 16:23:44 +05:30
rohitwaghchaure
aa70d9bbc3 fix: purchase return of batchwise valuation batch valued at original receipt rate instead of batch avg rate (version-16-hotfix) (#57836)
* fix: use current batch avg rate for outward returns of batchwise valuation batches

* fix: honor zero batch average and avoid duplicate batch classification query
2026-08-06 15:44:56 +05:30
Mihir Kandoi
626e35135f fix(stock): drop call to confirm_if_drafts_exist missing on v16 (#57833) 2026-08-06 08:08:45 +00:00
Henil Maru
0e26f9b1db fix(sales-invoice): respect Customize Form hidden setting on Update Stock (#57819)
frm.toggle_display("update_stock", ...) unconditionally forced the
field visible based only on has_subcontracted, overwriting whatever
Customize Form had set on every refresh. OR it with the field's
original (property-setter-driven) hidden value instead.

Backport of #57818.
2026-08-05 17:58:58 +05:30
rohitwaghchaure
243266f5ef feat: stock validations in Period Closing Voucher and snapshot-seeded batch valuation (backport #57811) (#57816)
* feat: validate stock value and stock closing entry before period closing

(cherry picked from commit 20450bd4ec)

* fix: do not accept scoped stock closing entries as period closing prerequisite

(cherry picked from commit 359a347be2)

* feat: seed batch valuation from stock closing balance and freeze closed-period stock

(cherry picked from commit 49a127d59c)
2026-08-05 17:20:53 +05:30
mergify[bot]
af3184c8b4 fix(stock): handle multi-item opening balance in Stock Ledger report (backport #57591) (#57796)
* fix(stock): handle multi-item opening balance in Stock Ledger report (#57591)

* fix(stock): handle multi-item opening balance in Stock

* test(stock): add unit test for multi-item Stock Ledger report

---------

Co-authored-by: Afsal Syed <afsalsyed12@gmail.com>
(cherry picked from commit 0dbe410414)

# Conflicts:
#	erpnext/stock/report/stock_ledger/test_stock_ledger_report.py

* fix(stock): resolve stock ledger backport conflicts

---------

Co-authored-by: Sudharsanan Ashok <135326972+Sudharsanan11@users.noreply.github.com>
Co-authored-by: Sudharsanan11 <sudharsananashok1975@gmail.com>
2026-08-05 13:15:40 +05:30
Jatin3128
eeb3cd238e fix(subscription): don't reactivate a cancelled subscription (backport #57774)
* fix(subscription): don't reactivate a cancelled subscription

Backport of #57774 to version-16-hotfix.

set_subscription_status() unconditionally set status to Active once
there was no outstanding invoice, even if the subscription had been
intentionally cancelled. Paying off an invoice issued before
cancellation (directly, or via the Payment Entry -> refresh hook)
flipped a Cancelled subscription back to Active while cancelation_date
stayed set.

process()'s cancel_at_period_end check compared posting_date against
getdate(self.end_date), and getdate(None) returns today, so an empty
end_date was silently treated as "cancel now" on every scheduler run.
Combined with the reactivation bug, this let a cancelled subscription
toggle Cancelled -> Active on each run and generate another invoice at
the next period boundary.

Fixes #57761

* test: fix flaky test_update_bom_cost_in_all_boms via valuation reset

Backport of #56796 to version-16-hotfix.

reset_item_valuation_rate() only reconciled warehouses where the item
currently has positive stock (actual_qty > 0). get_valuation_rate()
averages Sum(stock_value)/Sum(actual_qty) across all of an item's
bins, so a negative balance left over in another warehouse by a prior
test can cancel out the reset qty and collapse the average to 0,
failing the assertion with 0.0 != 10.0.

This branch never got #56796 (it predates the frappe.get_all
refactor of this helper and still uses raw SQL), so applying the same
fix here: reconcile every warehouse with a non-zero balance, not just
positive ones.

* fix(subscription): don't let period rollover defeat cancel_at_period_end

process() can advance current_invoice_end to the next period (via
update_subscription_period(), when generating the current period's
invoice) before the cancel_at_period_end check further down runs. For
a subscription with no end_date, that check now compared posting_date
against the already-rolled-forward current_invoice_end, which is
always in the future, so cancel_at_period_end was silently never
honored.

Snapshot current_invoice_end before any rollover and use that in the
check instead, so it still targets the period that just ended.

Found via review on the version-15-hotfix backport (#57780).

---------

Co-authored-by: test <test@test.com>
2026-08-05 12:23:31 +05:30
mergify[bot]
adfa6768c9 fix: incorrect batch-wise valuation rate for entries with same posting datetime (backport #57794) (#57797)
fix: incorrect batch-wise valuation rate for entries with same posting datetime (#57794)

* fix: incorrect batch-wise valuation rate for entries with same posting datetime

The tie-breaker in get_batch_no_ledgers compared the bundle's creation
against the SLE's creation. These are different timelines - a bundle can
be created (drafted) much before its SLE (created at submission). For
entries sharing a posting datetime (backdated / amended vouchers), this
mis-ordered the entries against the ledger's replay order (SLE creation),
causing double counting or omission of batch qty / value and runaway
outgoing rates that no repost could heal.

Now the tie is broken using the creation of the bundle's own SLE (same
timeline on both sides). When the valuation runs through the bundle
before its SLE exists, the entry is by definition last in its timestamp
group, so all same-timestamp entries already in the ledger precede it.



* test: batch-wise valuation ordering for same posting datetime entries

Covers both tie-breaking branches of get_batch_no_ledgers:
- submission (pre-insertion) branch: same-timestamp inward at a different
  rate plus a multi-row outward voucher (same item and warehouse), at
  submission and after a backdated repost
- existing-SLE branch: a bundle created after its sibling's SLE, the
  ordering must follow the SLE creation and not the bundle creation

Both tests fail with the previous parent.creation < sle.creation
tie-breaker and pass with the fix.



---------

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-05 11:06:14 +05:30
Diptanil Saha
970a3f403d Merge pull request #57798 from diptanilsaha/backport/16/57734
fix(payment reconciliation): correct supplier gain/loss posting (backport #57734)
2026-08-05 00:13:14 +05:30
Sudharsanan11
61154e22ed test(payment reconciliation): cover supplier exchange gain posting 2026-08-04 23:58:33 +05:30
diptanilsaha
dc907add40 fix(payment reconciliation): correct supplier gain/loss posting 2026-08-04 23:58:19 +05:30
Shllokkk
b5700831d8 Merge pull request #57791 from frappe/mergify/bp/version-16-hotfix/pr-57790
test: child warehouse account override in stock vs account value comparison (backport #57790)
2026-08-04 20:15:59 +05:30
Shllokkk
a703e7a462 test: child warehouse account override excluded in stock vs account value comparison
(cherry picked from commit ef7a3cb4c8)

# Conflicts:
#	erpnext/stock/report/stock_and_account_value_comparison/test_stock_and_account_value_comparison.py
2026-08-04 18:54:44 +05:30
Mihir Kandoi
abc76eb49d Merge pull request #57789 from frappe/mergify/bp/version-16-hotfix/pr-57757
fix(opportunity): add validation for positive item quantities (backport #57757)
2026-08-04 17:13:29 +05:30
R-Jayaraman
37e96f931d chore: use flt() in qty check
(cherry picked from commit 69de8f2d62)
2026-08-04 11:24:02 +00:00
R-Jayaraman
a9f969e942 fix(opportunity): add validation for positive item quantities
(cherry picked from commit c47cc37441)
2026-08-04 11:24:01 +00:00
Mihir Kandoi
cd65a6d9ff Merge pull request #57785 from frappe/mergify/bp/version-16-hotfix/pr-57772
fix(accounts): skip party dashboard without invoice permission (backport #57772)
2026-08-04 16:48:17 +05:30
Sudharsanan11
ee6955d56c fix(accounts): skip party dashboard without invoice permission
(cherry picked from commit ed78dd37be)
2026-08-04 11:04:28 +00:00
Mihir Kandoi
02f407b82a Merge pull request #57779 from frappe/mergify/bp/version-16-hotfix/pr-57777
fix(manufacturing): reach the whole configurator from tree toolbar actions (backport #57777)
2026-08-04 16:11:23 +05:30
Mihir Kandoi
281e92fb6e fix(manufacturing): reach the whole configurator from tree toolbar actions
The toolbar handlers were copied onto view.events as unbound functions, so
`this` inside them was that object literal rather than the BOMConfigurator.
They worked only because the literal also carried `frm`, and broke as soon as
a handler called a method the literal did not list: get_item_code, added when
the tree started keying nodes on the row name, threw
"this.get_item_code is not a function" and killed Add Raw Material, Add Sub
Assembly and Convert to Sub Assembly.

Assign the instance instead of a hand-maintained whitelist. Every method is
reachable, `this.frm` keeps working, and no future method can be forgotten.

Fixes #57773

(cherry picked from commit 097ce0f348)
2026-08-04 10:09:12 +00:00
MochaMind
285aec3164 fix: sync translations from crowdin (#57741) 2026-08-04 10:00:24 +00:00
mergify[bot]
824ae57e44 fix: escape data in multiple templates (backport #57742) (#57770)
Co-authored-by: diptanilsaha <diptanil@frappe.io>
2026-08-04 06:52:25 +00:00
ruthra kumar
4193a441e6 Merge pull request #57767 from frappe/mergify/bp/version-16-hotfix/pr-57719
Fix/reversal journal entry custom remark (backport #57719)
2026-08-04 11:02:08 +05:30
Krishna Shirsath
b4dfca9ef1 fix: allow custom remark on reversal journal entry
(cherry picked from commit 5e0e9ba668)
2026-08-04 05:30:03 +00:00
Diptanil Saha
6153202231 fix(accounts): fetch deferred invoice docs on non-empty sales_docs or purchase_docs in repost accounting ledger (#57753) 2026-08-03 17:25:50 +05:30
Mihir Kandoi
4babce436f Merge pull request #57755 from mihir-kandoi/backport/secondary-item-valuation-fixes
fix(stock): correct secondary item valuation across stock entry purposes
2026-08-03 17:05:54 +05:30
Mihir Kandoi
aaa99f775d test(stock): cover secondary item valuation across stock entry purposes
Ports the five regression tests to this branch's `type` field name.
2026-08-03 16:53:20 +05:30
Mihir Kandoi
4ed03748fe fix(stock): correct secondary item valuation across stock entry purposes
Backport of five fixes merged to develop, adapted to this branch, where
the field is still named `type` and the stock entry rate logic has not
been split out of set_basic_rate.

- A secondary row with no BOM link is costed out of the finished good,
  as legacy scrap was. Finished goods are rated last so a single
  validate pass sees the secondary rows' amounts. (#57732)
- Repack no longer flags secondary rows as finished goods, so each side
  takes the share the BOM declares instead of the scrap absorbing the
  finished good's percentage. (#57735)
- A BOM allocation of 0% means the row carries no cost, rather than
  falling through to the item's own valuation rate. (#57736)
- Secondary Item Type no longer waives a quality inspection on purposes
  that do not produce secondary items. (#57737)
- The BOM allocation applies to the consumption entry's cost when the
  raw material cost comes from one. (#57738)

Replaces the individual backports, which could not be cherry-picked
cleanly: every hunk needed rewriting against the pre-rename field and
the un-refactored rate logic.
2026-08-03 16:53:20 +05:30
Mihir Kandoi
667b012065 Merge pull request #57750 from frappe/mergify/bp/version-16-hotfix/pr-57747
fix: disabled item attribute blocks unrelated edits to existing variants (backport #57747)
2026-08-03 16:33:22 +05:30
Mihir Kandoi
81e24442e3 test(stock): cover editing a variant whose attribute is disabled
Assert that a variant saves after its attribute is disabled when the edit
leaves the attribute rows alone, and that changing an attribute value still
throws.

(cherry picked from commit 8d5326196e)
2026-08-03 10:47:42 +00:00
Mihir Kandoi
00139081f6 fix(stock): validate only the variant attributes that changed
Disabling an Item Attribute writes `disabled = 1` into every Item Variant
Attribute row, including the rows on the template. `validate_variant` runs
on every save and walks the whole attribute table, so any later save of an
existing variant re-checked its untouched rows against the now-disabled
template row and threw. `update_variants` hit the same wall, which made a
single template save fail once an attribute was disabled.

The flag exists to keep an attribute out of new variants, not to freeze the
variants that already use it. item.js only reads it to drop the attribute
from the variant creation dialog.

Skip rows that are unchanged since the last save. New and edited rows are
still checked, so a disabled attribute cannot be added to an existing
variant, and the same guard covers the sibling checks for attributes and
values that the template no longer offers.

(cherry picked from commit 25cd793617)
2026-08-03 10:47:42 +00:00
Henil Maru
a5544d0bfb fix(pos): don't double-escape Item Group names in get_item_groups (#57673)
frappe.db.escape() wraps the value in quotes (e.g. "'Products'").
Callers pass the result into query-builder isin()/frappe.get_all
filters, which parameterize values themselves — so the pre-quoted
string never matches a real Item Group name, and POS shows no items
whenever a POS Profile restricts Item Groups.

Return raw names instead, matching develop.
2026-08-03 16:03:38 +05:30
mergify[bot]
ca6065398c fix(banking): fetch company list from DB instead of boot (backport #57731) (#57739)
fix(banking): fetch company list from DB instead of boot (#57731)

* fix(banking): fetch company list from DB instead of boot

* fix: show error banner for company list fail fetch

(cherry picked from commit abc3da6b97)

Co-authored-by: Nikhil Kothari <nik.kothari22@live.com>
2026-08-03 14:33:46 +05:30
Mihir Kandoi
eeab2a833f Merge pull request #57730 from frappe/mergify/bp/version-16-hotfix/pr-57647
fix(sales): reject sales returns where every item has zero quantity (backport #57647)
2026-08-03 13:44:09 +05:30
Mihir Kandoi
af4aea171b test(sales): import make_sales_return from delivery_note on version-16-hotfix 2026-08-03 13:29:40 +05:30
Mihir Kandoi
a2dfc9e50a Merge pull request #57728 from frappe/mergify/bp/version-16-hotfix/pr-57725
fix(stock): scope over deliver/receive role check to delivery and receipt overflow (backport #57725)
2026-08-03 13:13:22 +05:30
R-Jayaraman
f2a53247c5 test(sales): add coverage for zero-qty return rejection
Greptile flagged that the sales-side zero-qty-return fix had no dedicated
test proving the behavior - the existing suite happened to pass, but
nothing specifically asserted that an all-zero return is rejected while
a normal negative-qty return still succeeds.

Adds two tests covering the doctypes that rely entirely on this check
(no other guard covers them for a non-stock-effect return):
- Delivery Note return with qty 0 -> rejected
- Sales Invoice return with qty 0 (no update_stock) -> rejected

POS Invoice is not covered separately here since it always runs with
update_stock=1, which is already guarded by the pre-existing
validate_zero_qty_for_return_invoices_with_stock check regardless of
this fix.

(cherry picked from commit 732c884633)
2026-08-03 07:35:29 +00:00
R-Jayaraman
aa71cd695b fix(sales): reject sales returns where every item has zero quantity
validate_returned_items() set items_returned=True whenever a row matched
a valid item from the original document, even if its qty was 0. This let
a Sales Invoice, Delivery Note, or POS Invoice return be submitted with
every line at qty=0 - a no-op document with no stock or financial effect
that still consumed a document number and linked back to the original
transaction.

Scoped to the Sales side only: items_returned now flips to True for
Sales Invoice/Delivery Note/POS Invoice only when qty (or received_qty)
is actually negative, so an all-zero sales return correctly hits the
existing "At least one item should be entered with negative quantity"
check. Purchase Invoice, Purchase Receipt, and Subcontracting Receipt
are unchanged.

(cherry picked from commit a3e9d13da3)
2026-08-03 07:35:29 +00:00