From 8db05fc4da735f5901248c51ec0bdbc142e8bc92 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 5 Jun 2026 13:32:04 +0530 Subject: [PATCH] refactor(stock): drop 7 in-repo-only StockController delegators Remove the delegators whose only callers were in-repo StockController subclasses, repointing every caller to the owning service / free function: - validate_warehouse_of_sabb, validate_duplicate_serial_and_batch_bundle, validate_serialized_batch, clean_serial_nos -> SerialBatchBundleService - update_inventory_dimensions -> StockLedgerService - validate_putaway_capacity -> putaway_rule.validate_putaway_capacity (free fn) - set_landed_cost_voucher_amount -> landed_cost_voucher.set_landed_cost_voucher_amount Callers repointed: StockController.validate() (base), StockEntry.validate(), StockReconciliation (validate + reconciliation SLE build), BuyingController.validate(), and the Landed Cost Voucher submit (doc.set_landed_cost_voucher_amount on the receipt). Verified green: ledger snapshots, stock_entry (91), stock_reconciliation (34), landed_cost_voucher (15), subcontracting_receipt (32), delivery_note (71). --- erpnext/controllers/buying_controller.py | 6 ++- erpnext/controllers/stock_controller.py | 52 ++++--------------- .../landed_cost_voucher.py | 2 +- .../stock/doctype/stock_entry/stock_entry.py | 15 ++++-- .../stock_reconciliation.py | 15 ++++-- 5 files changed, 37 insertions(+), 53 deletions(-) diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index 1fac4f8b216..1b5574b764f 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -35,6 +35,10 @@ class BuyingController(SubcontractingController): self.flags.ignore_permlevel_for_fields = ["buying_price_list", "price_list_currency"] def validate(self): + from erpnext.stock.doctype.landed_cost_voucher.landed_cost_voucher import ( + set_landed_cost_voucher_amount, + ) + self.set_rate_for_standalone_debit_note() super().validate() @@ -59,7 +63,7 @@ class BuyingController(SubcontractingController): self.validate_rejected_warehouse() self.validate_accepted_rejected_qty() validate_for_items(self) - self.set_landed_cost_voucher_amount() + set_landed_cost_voucher_amount(self) if self.doctype in ("Purchase Receipt", "Purchase Invoice"): self.update_valuation_rate() diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index 20ed45a2b50..427d5a104e5 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -37,33 +37,33 @@ from erpnext.stock.stock_ledger import get_items_to_be_repost class StockController(AccountsController): def validate(self): + from erpnext.stock.doctype.putaway_rule.putaway_rule import validate_putaway_capacity + from erpnext.stock.services.serial_batch_bundle import SerialBatchBundleService + + sbb = SerialBatchBundleService(self) + super().validate() if self.docstatus == 0: for table_name in ["items", "packed_items", "supplied_items"]: - self.validate_duplicate_serial_and_batch_bundle(table_name) + sbb.validate_duplicate_serial_and_batch_bundle(table_name) if not self.get("is_return"): self.validate_inspection() - self.validate_warehouse_of_sabb() - self.validate_serialized_batch() - self.clean_serial_nos() + sbb.validate_warehouse_of_sabb() + sbb.validate_serialized_batch() + sbb.clean_serial_nos() self.validate_customer_provided_item() self.set_rate_of_stock_uom() StockInternalTransferService(self).validate_internal_transfer() - self.validate_putaway_capacity() + validate_putaway_capacity(self) self.reset_conversion_factor() def on_update(self): super().on_update() self.check_zero_rate() - def validate_warehouse_of_sabb(self): - from erpnext.stock.services.serial_batch_bundle import SerialBatchBundleService - - return SerialBatchBundleService(self).validate_warehouse_of_sabb() - def reset_conversion_factor(self): for row in self.get("items"): if row.uom != row.stock_uom: @@ -118,11 +118,6 @@ class StockController(AccountsController): if non_exists_items: frappe.throw(_("Items {0} do not exist in the Item master.").format(", ".join(non_exists_items))) - def validate_duplicate_serial_and_batch_bundle(self, table_name): - from erpnext.stock.services.serial_batch_bundle import SerialBatchBundleService - - return SerialBatchBundleService(self).validate_duplicate_serial_and_batch_bundle(table_name) - def get_item_wise_inventory_account_map(self): inventory_account_map = frappe._dict() for table in ["items", "packed_items", "supplied_items"]: @@ -207,16 +202,6 @@ class StockController(AccountsController): ) make_gl_entries(gl_entries, from_repost=from_repost) - def validate_serialized_batch(self): - from erpnext.stock.services.serial_batch_bundle import SerialBatchBundleService - - return SerialBatchBundleService(self).validate_serialized_batch() - - def clean_serial_nos(self): - from erpnext.stock.services.serial_batch_bundle import SerialBatchBundleService - - return SerialBatchBundleService(self).clean_serial_nos() - def make_bundle_using_old_serial_batch_fields(self, table_name=None, via_landed_cost_voucher=False): from erpnext.stock.services.serial_batch_bundle import SerialBatchBundleService @@ -277,13 +262,6 @@ class StockController(AccountsController): return StockLedgerService(self).get_sl_entries(d, args) - def set_landed_cost_voucher_amount(self): - from erpnext.stock.doctype.landed_cost_voucher.landed_cost_voucher import ( - set_landed_cost_voucher_amount, - ) - - return set_landed_cost_voucher_amount(self) - def get_item_account_wise_lcv_entries(self): from erpnext.stock.doctype.landed_cost_voucher.landed_cost_voucher import ( get_item_account_wise_lcv_entries, @@ -291,11 +269,6 @@ class StockController(AccountsController): return get_item_account_wise_lcv_entries(self) - def update_inventory_dimensions(self, row, sl_dict) -> None: - from erpnext.stock.services.stock_ledger import StockLedgerService - - return StockLedgerService(self).update_inventory_dimensions(row, sl_dict) - def make_sl_entries(self, sl_entries, allow_negative_stock=False, via_landed_cost_voucher=False): from erpnext.stock.services.stock_ledger import StockLedgerService @@ -386,11 +359,6 @@ class StockController(AccountsController): for d in self.get("items"): d.stock_uom_rate = d.rate / (d.conversion_factor or 1) - def validate_putaway_capacity(self): - from erpnext.stock.doctype.putaway_rule.putaway_rule import validate_putaway_capacity - - return validate_putaway_capacity(self) - def repost_future_sle_and_gle(self, force=False, via_landed_cost_voucher=False): from erpnext.stock.services.stock_ledger import StockLedgerService diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py index dc5384f76ee..6576380e862 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py @@ -315,7 +315,7 @@ class LandedCostVoucher(Document): self.validate_asset_qty_and_status(d.receipt_document_type, doc) # set landed cost voucher amount in pr item - doc.set_landed_cost_voucher_amount() + set_landed_cost_voucher_amount(doc) if d.receipt_document_type == "Subcontracting Receipt": doc.calculate_items_qty_and_amount() diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 1574efa67e9..41284504f7c 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -265,17 +265,22 @@ class StockEntry(StockController, SubcontractingInwardController): ) def validate(self): + from erpnext.stock.doctype.putaway_rule.putaway_rule import validate_putaway_capacity + from erpnext.stock.services.serial_batch_bundle import SerialBatchBundleService + + sbb = SerialBatchBundleService(self) + if self.purpose_cls: self.purpose_cls(self).validate() - self.validate_duplicate_serial_and_batch_bundle("items") + sbb.validate_duplicate_serial_and_batch_bundle("items") self.validate_posting_time() self.validate_item() self.validate_customer_provided_item() self.set_transfer_qty() self.validate_uom_is_integer("uom", "qty") self.validate_uom_is_integer("stock_uom", "transfer_qty") - self.validate_warehouse_of_sabb() + sbb.validate_warehouse_of_sabb() self.validate_source_stock_entry() self.validate_bom() self.set_process_loss_qty() @@ -294,11 +299,11 @@ class StockEntry(StockController, SubcontractingInwardController): self.validate_difference_account() self.validate_job_card_item() self.set_purpose_for_stock_entry() - self.clean_serial_nos() + sbb.clean_serial_nos() self.remove_fg_completed_qty() - self.validate_serialized_batch() + sbb.validate_serialized_batch() self.calculate_rate_and_amount() - self.validate_putaway_capacity() + validate_putaway_capacity(self) self.validate_closed_subcontracting_order() super().validate_subcontracting_inward() diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py index 388ab6793b8..5118c9c41ae 100644 --- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py @@ -65,6 +65,11 @@ class StockReconciliation(StockController): self.head_row = ["Item Code", "Warehouse", "Quantity", "Valuation Rate"] def validate(self): + from erpnext.stock.doctype.putaway_rule.putaway_rule import validate_putaway_capacity + from erpnext.stock.services.serial_batch_bundle import SerialBatchBundleService + + sbb = SerialBatchBundleService(self) + self.validate_items_exist() if not self.expense_account: self.expense_account = frappe.get_cached_value( @@ -75,16 +80,16 @@ class StockReconciliation(StockController): self.validate_posting_time() self.set_current_serial_and_batch_bundle() self.set_new_serial_and_batch_bundle() - self.validate_duplicate_serial_and_batch_bundle("items") + sbb.validate_duplicate_serial_and_batch_bundle("items") self.remove_items_with_no_change() self.validate_data() self.change_row_indexes() self.validate_expense_account() self.validate_customer_provided_item() self.set_zero_value_for_customer_provided_items() - self.clean_serial_nos() + sbb.clean_serial_nos() self.set_total_qty_and_amount() - self.validate_putaway_capacity() + validate_putaway_capacity(self) self.validate_inventory_dimension() self.validate_uom_is_integer("stock_uom", "qty") @@ -925,7 +930,9 @@ class StockReconciliation(StockController): data.qty_after_transaction = 0.0 data.incoming_rate = flt(row.valuation_rate) - self.update_inventory_dimensions(row, data) + from erpnext.stock.services.stock_ledger import StockLedgerService + + StockLedgerService(self).update_inventory_dimensions(row, data) return data