fix(stock): restore subcontracting inward warehouse checks (#58183)

This commit is contained in:
Mihir Kandoi
2026-08-14 19:56:25 +05:30
committed by GitHub
parent fb7c2caf29
commit ef24974645
4 changed files with 83 additions and 4 deletions

View File

@@ -14,6 +14,7 @@ class MaterialReceiptStockEntry(BaseStockEntry):
self.validate_warehouse()
def set_default_warehouse(self):
self.doc.from_warehouse = None
for row in self.doc.items:
row.s_warehouse = None
if not row.t_warehouse and self.doc.to_warehouse:
@@ -27,6 +28,7 @@ class MaterialReceiptStockEntry(BaseStockEntry):
class BaseMaterialIssueStockEntry(BaseStockEntry):
def set_default_warehouse(self):
self.doc.to_warehouse = None
for row in self.doc.items:
row.t_warehouse = None
if not row.s_warehouse and self.doc.from_warehouse:
@@ -38,13 +40,15 @@ class BaseMaterialIssueStockEntry(BaseStockEntry):
frappe.throw(_("Source Warehouse is required for item {0}").format(row.item_code))
class MaterialIssueStockEntry(BaseMaterialIssueStockEntry):
class SourceOnlyStockEntry(BaseMaterialIssueStockEntry):
def before_validate(self):
self.set_default_warehouse()
def validate(self):
self.validate_warehouse()
class MaterialIssueStockEntry(SourceOnlyStockEntry):
def add_items(self):
self.add_raw_materials_based_on_bom()

View File

@@ -627,13 +627,15 @@ frappe.ui.form.on("Stock Entry", {
frm.fields_dict["items"].grid.update_docfield_property(
"s_warehouse",
"in_list_view",
!["Material Receipt", "Receive from Customer"].includes(frm.doc.purpose)
!["Material Receipt", "Receive from Customer", "Subcontracting Return"].includes(frm.doc.purpose)
);
frm.fields_dict["items"].grid.update_docfield_property(
"t_warehouse",
"in_list_view",
!["Material Issue"].includes(frm.doc.purpose)
!["Material Issue", "Return Raw Material to Customer", "Subcontracting Delivery"].includes(
frm.doc.purpose
)
);
frm.fields_dict["items"].grid.reset_grid();

View File

@@ -45,7 +45,11 @@ from .services.manufacturing import (
OperationsNotCompleteError,
RepackStockEntry,
)
from .services.material_receipt_issue import MaterialIssueStockEntry, MaterialReceiptStockEntry
from .services.material_receipt_issue import (
MaterialIssueStockEntry,
MaterialReceiptStockEntry,
SourceOnlyStockEntry,
)
from .services.material_transfer import (
MaterialRequestStockEntry,
MaterialTransferForManufactureStockEntry,
@@ -216,6 +220,10 @@ class StockEntry(StockController, SubcontractingInwardController):
"Send to Subcontractor": SendToSubcontractorStockEntry,
"Material Issue": MaterialIssueStockEntry,
"Material Receipt": MaterialReceiptStockEntry,
"Receive from Customer": MaterialReceiptStockEntry,
"Return Raw Material to Customer": SourceOnlyStockEntry,
"Subcontracting Delivery": SourceOnlyStockEntry,
"Subcontracting Return": MaterialReceiptStockEntry,
}
self.purpose_cls = purpose_map.get(self.purpose)

View File

@@ -61,6 +61,71 @@ class TestStockEntry(ERPNextTestSuite):
self.load_test_records("Stock Entry")
frappe.local.flags.dont_execute_stock_reposts = False
def test_subcontracting_inward_warehouse_direction(self):
source_warehouse = "_Test Warehouse - _TC"
target_warehouse = "_Test Warehouse 1 - _TC"
for purpose in ("Return Raw Material to Customer", "Subcontracting Delivery"):
with self.subTest(purpose=purpose):
stock_entry = frappe.new_doc("Stock Entry")
stock_entry.purpose = purpose
stock_entry.from_warehouse = source_warehouse
stock_entry.to_warehouse = target_warehouse
stock_entry.append(
"items",
{
"item_code": "_Test Item",
"t_warehouse": target_warehouse,
"cost_center": "Main - _TC",
},
)
stock_entry.before_validate()
self.assertEqual(stock_entry.from_warehouse, source_warehouse)
self.assertIsNone(stock_entry.to_warehouse)
self.assertEqual(stock_entry.items[0].s_warehouse, source_warehouse)
self.assertIsNone(stock_entry.items[0].t_warehouse)
for purpose in ("Receive from Customer", "Subcontracting Return"):
with self.subTest(purpose=purpose):
stock_entry = frappe.new_doc("Stock Entry")
stock_entry.purpose = purpose
stock_entry.from_warehouse = source_warehouse
stock_entry.to_warehouse = target_warehouse
stock_entry.append(
"items",
{
"item_code": "_Test Item",
"s_warehouse": source_warehouse,
"cost_center": "Main - _TC",
},
)
stock_entry.before_validate()
self.assertIsNone(stock_entry.from_warehouse)
self.assertEqual(stock_entry.to_warehouse, target_warehouse)
self.assertIsNone(stock_entry.items[0].s_warehouse)
self.assertEqual(stock_entry.items[0].t_warehouse, target_warehouse)
def test_subcontracting_inward_warehouse_is_mandatory(self):
purposes = {
"Return Raw Material to Customer": "Source Warehouse is required",
"Subcontracting Delivery": "Source Warehouse is required",
"Receive from Customer": "Target Warehouse is required",
"Subcontracting Return": "Target Warehouse is required",
}
for purpose, message in purposes.items():
with self.subTest(purpose=purpose):
stock_entry = frappe.new_doc("Stock Entry")
stock_entry.purpose = purpose
stock_entry.append("items", {"item_code": "_Test Item"})
with self.assertRaisesRegex(frappe.ValidationError, message):
stock_entry.validate()
def test_stock_entry_qty(self):
item_code = "_Test Item 2"
warehouse = "_Test Warehouse - _TC"