The shared get_data helper defaulted to posting_date for any doctype
other than Sales Order. Purchase Order also uses transaction_date, so
add it to the in-check to prevent the Unknown column SQL error.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Purchase Order, Purchase Invoice, and Purchase Receipt have no
territory field. Removed it from the base query SELECT, the common
filters loop, the column definitions, and the JS filter inputs in
Purchase Partner Commission Summary and Transaction Summary reports.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mirrors the Sales Partner Target Variance Based On Item Group report
for the purchase flow. Calls the shared get_data_column helper with
"Purchase Partner" so it reads Target Details with parenttype=Purchase
Partner and matches against the purchase_partner field on PO/PI/PR.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a set_query on purchase_person in the purchase_team child table
so the dropdown excludes group nodes (like "Purchase Team") and
disabled records, matching the same filter used for sales_person in
Sales Team.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Purchase Order, Purchase Invoice, and Purchase Receipt do not have a
territory field (unlike their selling counterparts), causing an
Unknown column SQL error. Removed territory from columns, SELECT, and
filter conditions in both Commission Summary and Transaction Summary.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Three new Script Reports in the Buying module:
- Purchase Person-wise Transaction Summary (mirrors Sales Person-wise)
- Purchase Person Commission Summary (mirrors Sales Person Commission)
- Purchase Person Target Variance Based On Item Group (mirrors Sales Person Target)
The shared `item_group_wise_sales_target_variance.get_actual_data` helper
gains a `purchase_person` branch that joins `Purchase Team` the same way
the existing `sales_person` branch joins `Sales Team`.
All three reports are added to the Buying workspace under a Purchase Person card.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mirrors the Sales Person/Sales Team fixture so fresh installs get a
root "Purchase Team" group node for the Purchase Person tree.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mirrors Sales Person/Sales Team functionality for the purchase flow.
Purchase Person is a tree DocType (Setup module) and Purchase Team is
a child table (Buying module). Both are added to Purchase Order,
Purchase Invoice, and Purchase Receipt. The BuyingController gains
calculate_contribution() and validate_purchase_team() methods, and
accounts_controller wires it into the calculate_totals flow.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix division-by-zero on PostgreSQL in purchase_partners_commission report
by wrapping sum(amount_eligible_for_commission) with NULLIF(..., 0)
- Replace lazy `from frappe import throw` with `frappe.throw()` in
buying_controller.calculate_commission to match selling controller pattern
- Fix indentation of purchase_partner() event handler in buying.js
- Mirror server-side validation in JS: block commission_rate < 0 as well
as > 100, with consistent error message "must be between 0 and 100"
- Remove unused IntegrationTestCase import from test_purchase_partner.py
- Add Purchase Partner Type fixtures (same types as Sales Partner Type)
installed via setup wizard so generic records exist out of the box
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fix(bom): fetch routing operations when routing is selected
frm.doc.operations is always an array in Frappe, so !frm.doc.operations
was always false (empty array [] is truthy in JS), causing get_routing()
to never fire when a Routing is selected on a BOM with no existing
operations.
Changed the guard to !frm.doc.operations.length so the fetch triggers
correctly when the operations table is empty.
Also wired the same fetch into the with_operations handler so that
enabling the checkbox after a Routing is already set will populate
operations without requiring the user to re-select the Routing.
Co-authored-by: Umair Sayed <umairsayed@Umairs-MacBook-Air-2.local>
row is a plain dict subclass, so row["item_code"] raised an unhandled
KeyError (500) when the payload had neither key. get_active_product_bundle
already returns None for falsy input, yielding an empty item list.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The legacy item_code path now resolves the active bundle's name via
get_active_product_bundle (same filters as the old joined query) so
frappe.has_permission can validate the specific document on both
branches. The orphaned get_product_bundle_items helper is removed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The whitelisted get_items_from_product_bundle endpoint now verifies read
permission on Product Bundle (doc-level when a name is passed, doctype-
level for the legacy item_code path) so authenticated users can't
enumerate bundle components. The disabled-bundle test also restores the
disabled flag via addCleanup.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Since Product Bundles became versioned, their names are PB-prefixed and
no longer double as the parent item code. The buying dialog kept passing
the picked bundle name as `item_code`, so the component lookup (which
filters `new_item_code`) matched nothing and the dialog silently added
no items.
The dialog now sends the selection as `product_bundle` and the endpoint
fetches that version's components by document name (rejecting
unsubmitted versions); passing `item_code` still resolves the parent
item's active version, preserving the legacy contract of the
whitelisted endpoint. The picker is also restricted to submitted
bundles.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Mutation testing on gl_composer surfaced that the foreign-row
debit/credit_in_transaction_currency conversion (amount / exchange_rate) was
unverified -- a / vs * bug survived. Assert those fields in test_multi_currency
and add a foreign-debit case so both conversion directions are now caught.
Add characterization tests for get_payment_entry_against_order (the Sales/
Purchase Order advance path, previously untested) and make_inter_company_journal_entry
(previously fully uncovered).
Split AssetService.unlink_asset_reference into _is_depreciation_asset_row /
_reverse_asset_depreciation / _restore_scheduled_depreciation /
_restore_finance_book_value / _block_scrap_journal_cancel, and add return type
hints and docstrings across the service. Behaviour preserved (netted by the
asset suite).
Split get_payment_entry into _reference_exchange_rate / _append_party_row /
_append_bank_row, and add return type hints and docstrings to all mapper
document builders. Behaviour preserved.
Add return type hints and option-A docstrings to JournalEntryReferenceValidator,
and split JournalEntryGLComposer.compose into _set_transaction_currency and
_gl_row helpers. Behaviour preserved.
Resolution skips disabled bundles, transactions referencing a disabled
version are blocked, rows without an explicit version stop packing, and
the Item Where Used report surfaces the disabled flag on bundle rows.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Un-deprecate the `disabled` checkbox: it is now editable (also after
submit) and parks a bundle version without ceding its active slot, so
re-enabling restores it without re-activation.
- `get_active_product_bundle` (the single resolution entry point) skips
disabled bundles, so every consumer stops treating the item as a bundle
while it is disabled
- the version pickers on transaction item rows and the buying "Get Items
from Product Bundle" dialog filter out disabled bundles
- an explicitly selected disabled version blocks the transaction with a
validation error instead of silently re-packing another version
- Product Bundle Balance report excludes disabled bundles
- list view indicator: Disabled (grey) / Active (green), falling back to
docstatus for drafts, cancelled and inactive submitted versions
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Stock Ageing iterates stock ledger entries through an unbuffered
(streaming) cursor. _get_batchwise_valuation() lazily queried
Batch.use_batchwise_valuation from inside that loop whenever a row
carried the legacy batch_no field, and the nested query invalidated
the active streaming result set — crashing the report (or silently
dropping the remaining rows, depending on the driver version).
Resolve the valuation flags in a single query before entering the
unbuffered cursor block; the lazy lookup now only serves callers that
pass stock ledger entries in directly, where no streaming is active.
Fixes https://github.com/frappe/erpnext/issues/55786
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace the single opaque `args` parameter of the whitelisted get_outstanding
with explicit named parameters (the supported interface), splitting the body
into _get_journal_entry_outstanding / _get_invoice_outstanding. The legacy
`args` payload is still accepted via kwargs for backward compatibility with
custom apps. Resolves the overusing-args semgrep finding.
Add characterization tests for the previously untested get_balance (difference
on a blank row), get_outstanding_invoices (write-off rows) and
unlink_advance_entry_reference (reference cleared on cancel). Remove the unused
get_average_exchange_rate, which has no callers in erpnext.
Add a class docstring plus docstrings for the lifecycle hooks and the public
API helpers (get_outstanding, get_against_jv, get_exchange_rate, etc.).
Self-evident one-line methods are intentionally left undocumented.
Decompose update_invoice_discounting, set_print_format_fields,
get_balance_for_periodic_accounting, set_exchange_rate, get_balance and
get_outstanding_invoices into focused per-row / row-building helpers (verb
prefixed, with docstrings). The nested closure in update_invoice_discounting
that ignored its row id is dropped. Behaviour preserved.
Split create_remarks into _cheque_remark / _reference_remark / _bill_remark
helpers, and validate_against_jv into _validate_jv_reference,
_validate_jv_reference_direction and _against_jv_entries. Add docstrings.
Behaviour preserved.
Add return annotations to the module-level helpers and to make_gl_entries,
get_balance and set_total_amount, plus parameter types for set_total_amount
and make_gl_entries.