Merge pull request #38455 from rohitwaghchaure/fixed-incorrect-requested-qty-in-mr-for-sco
fix: incorrect requested quantity for the subcontracting order
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index 5f19657..595722d 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -221,6 +221,10 @@
self.reset_default_field_value("set_warehouse", "items", "warehouse")
def validate_with_previous_doc(self):
+ mri_compare_fields = [["project", "="], ["item_code", "="]]
+ if self.is_subcontracted:
+ mri_compare_fields = [["project", "="]]
+
super(PurchaseOrder, self).validate_with_previous_doc(
{
"Supplier Quotation": {
@@ -243,7 +247,7 @@
},
"Material Request Item": {
"ref_dn_field": "material_request_item",
- "compare_fields": [["project", "="], ["item_code", "="]],
+ "compare_fields": mri_compare_fields,
"is_child_table": True,
},
}
@@ -417,23 +421,6 @@
check_list.append(d.material_request)
check_on_hold_or_closed_status("Material Request", d.material_request)
- def update_requested_qty(self):
- material_request_map = {}
- for d in self.get("items"):
- if d.material_request_item:
- material_request_map.setdefault(d.material_request, []).append(d.material_request_item)
-
- for mr, mr_item_rows in material_request_map.items():
- if mr and mr_item_rows:
- mr_obj = frappe.get_doc("Material Request", mr)
-
- if mr_obj.status in ["Stopped", "Cancelled"]:
- frappe.throw(
- _("Material Request {0} is cancelled or stopped").format(mr), frappe.InvalidStatusError
- )
-
- mr_obj.update_requested_qty(mr_item_rows)
-
def update_ordered_qty(self, po_item_rows=None):
"""update requested qty (before ordered_qty is updated)"""
item_wh_list = []
@@ -475,7 +462,9 @@
self.update_status_updater()
self.update_prevdoc_status()
- self.update_requested_qty()
+ if not self.is_subcontracted or self.is_old_subcontracting_flow:
+ self.update_requested_qty()
+
self.update_ordered_qty()
self.validate_budget()
self.update_reserved_qty_for_subcontract()
@@ -509,7 +498,9 @@
# Must be called after updating ordered qty in Material Request
# bin uses Material Request Items to recalculate & update
- self.update_requested_qty()
+ if not self.is_subcontracted or self.is_old_subcontracting_flow:
+ self.update_requested_qty()
+
self.update_ordered_qty()
self.update_blanket_order()
@@ -875,6 +866,8 @@
"doctype": "Subcontracting Order Service Item",
"field_map": {
"name": "purchase_order_item",
+ "material_request": "material_request",
+ "material_request_item": "material_request_item",
},
"field_no_map": [],
},
diff --git a/erpnext/controllers/subcontracting_controller.py b/erpnext/controllers/subcontracting_controller.py
index 3d55a08..b52fbad 100644
--- a/erpnext/controllers/subcontracting_controller.py
+++ b/erpnext/controllers/subcontracting_controller.py
@@ -952,6 +952,23 @@
return self._sub_contracted_items
+ def update_requested_qty(self):
+ material_request_map = {}
+ for d in self.get("items"):
+ if d.material_request_item:
+ material_request_map.setdefault(d.material_request, []).append(d.material_request_item)
+
+ for mr, mr_item_rows in material_request_map.items():
+ if mr and mr_item_rows:
+ mr_obj = frappe.get_doc("Material Request", mr)
+
+ if mr_obj.status in ["Stopped", "Cancelled"]:
+ frappe.throw(
+ _("Material Request {0} is cancelled or stopped").format(mr), frappe.InvalidStatusError
+ )
+
+ mr_obj.update_requested_qty(mr_item_rows)
+
def get_item_details(items):
item = frappe.qb.DocType("Item")
diff --git a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py
index 68d98fc..6c187f8 100644
--- a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py
+++ b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py
@@ -80,6 +80,23 @@
transaction_date: DF.Date
# end: auto-generated types
+ def __init__(self, *args, **kwargs):
+ super(SubcontractingOrder, self).__init__(*args, **kwargs)
+
+ self.status_updater = [
+ {
+ "source_dt": "Subcontracting Order Item",
+ "target_dt": "Material Request Item",
+ "join_field": "material_request_item",
+ "target_field": "ordered_qty",
+ "target_parent_dt": "Material Request",
+ "target_parent_field": "per_ordered",
+ "target_ref_field": "stock_qty",
+ "source_field": "qty",
+ "percent_join_field": "material_request",
+ }
+ ]
+
def before_validate(self):
super(SubcontractingOrder, self).before_validate()
@@ -93,11 +110,15 @@
self.reset_default_field_value("set_warehouse", "items", "warehouse")
def on_submit(self):
+ self.update_prevdoc_status()
+ self.update_requested_qty()
self.update_ordered_qty_for_subcontracting()
self.update_reserved_qty_for_subcontracting()
self.update_status()
def on_cancel(self):
+ self.update_prevdoc_status()
+ self.update_requested_qty()
self.update_ordered_qty_for_subcontracting()
self.update_reserved_qty_for_subcontracting()
self.update_status()
@@ -237,6 +258,8 @@
"stock_uom": item.stock_uom,
"bom": bom,
"purchase_order_item": si.purchase_order_item,
+ "material_request": si.material_request,
+ "material_request_item": si.material_request_item,
}
)
else:
diff --git a/erpnext/subcontracting/doctype/subcontracting_order/test_subcontracting_order.py b/erpnext/subcontracting/doctype/subcontracting_order/test_subcontracting_order.py
index 3557858..37dabf1 100644
--- a/erpnext/subcontracting/doctype/subcontracting_order/test_subcontracting_order.py
+++ b/erpnext/subcontracting/doctype/subcontracting_order/test_subcontracting_order.py
@@ -628,6 +628,62 @@
self.assertEqual(ordered_qty + 10, new_ordered_qty)
+ def test_requested_qty_for_subcontracting_order(self):
+ from erpnext.stock.doctype.material_request.material_request import make_purchase_order
+ from erpnext.stock.doctype.material_request.test_material_request import make_material_request
+
+ requested_qty = frappe.db.get_value(
+ "Bin",
+ filters={"warehouse": "_Test Warehouse - _TC", "item_code": "Subcontracted Item SA8"},
+ fieldname="indented_qty",
+ )
+ requested_qty = flt(requested_qty)
+
+ mr = make_material_request(
+ item_code="Subcontracted Item SA8",
+ material_request_type="Purchase",
+ qty=10,
+ )
+
+ self.assertTrue(mr.docstatus == 1)
+
+ new_requested_qty = frappe.db.get_value(
+ "Bin",
+ filters={"warehouse": "_Test Warehouse - _TC", "item_code": "Subcontracted Item SA8"},
+ fieldname="indented_qty",
+ )
+ new_requested_qty = flt(new_requested_qty)
+
+ self.assertEqual(requested_qty + 10, new_requested_qty)
+
+ po = make_purchase_order(mr.name)
+ po.is_subcontracted = 1
+ po.supplier = "_Test Supplier"
+ po.items[0].fg_item = "Subcontracted Item SA8"
+ po.items[0].fg_item_qty = 10
+ po.items[0].item_code = "Subcontracted Service Item 8"
+ po.items[0].item_name = "Subcontracted Service Item 8"
+ po.items[0].qty = 10
+ po.supplier_warehouse = "_Test Warehouse 1 - _TC"
+ po.save()
+ po.submit()
+
+ self.assertTrue(po.items[0].material_request)
+ self.assertTrue(po.items[0].material_request_item)
+
+ sco = create_subcontracting_order(po_name=po.name)
+ self.assertTrue(sco.items[0].material_request)
+ self.assertTrue(sco.items[0].material_request_item)
+
+ new_requested_qty = frappe.db.get_value(
+ "Bin",
+ filters={"warehouse": "_Test Warehouse - _TC", "item_code": "Subcontracted Item SA8"},
+ fieldname="indented_qty",
+ )
+ new_requested_qty = flt(new_requested_qty)
+
+ self.assertEqual(requested_qty, new_requested_qty)
+
def create_subcontracting_order(**args):
args = frappe._dict(args)
diff --git a/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.json b/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.json
index 911e903..1ca90c3 100644
--- a/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.json
+++ b/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.json
@@ -40,13 +40,18 @@
"manufacture_section",
"manufacturer",
"manufacturer_part_no",
+ "column_break_impp",
+ "reference_section",
+ "material_request",
+ "column_break_fpyl",
+ "material_request_item",
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
"project",
"section_break_34",
- "page_break",
- "purchase_order_item"
+ "purchase_order_item",
+ "page_break"
],
"fields": [
{
@@ -335,6 +340,37 @@
"options": "Project"
},
{
+ "fieldname": "column_break_impp",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "material_request",
+ "fieldtype": "Link",
+ "label": "Material Request",
+ "no_copy": 1,
+ "options": "Material Request",
+ "read_only": 1,
+ "search_index": 1
+ },
+ {
+ "fieldname": "material_request_item",
+ "fieldtype": "Data",
+ "label": "Material Request Item",
+ "no_copy": 1,
+ "read_only": 1,
+ "search_index": 1
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "reference_section",
+ "fieldtype": "Section Break",
+ "label": "Reference"
+ },
+ {
+ "fieldname": "column_break_fpyl",
+ "fieldtype": "Column Break"
+ },
+ {
"fieldname": "purchase_order_item",
"fieldtype": "Data",
"hidden": 1,
@@ -348,7 +384,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2023-11-23 16:56:22.182698",
+ "modified": "2023-11-30 15:29:43.744618",
"modified_by": "Administrator",
"module": "Subcontracting",
"name": "Subcontracting Order Item",
diff --git a/erpnext/subcontracting/doctype/subcontracting_order_service_item/subcontracting_order_service_item.json b/erpnext/subcontracting/doctype/subcontracting_order_service_item/subcontracting_order_service_item.json
index dc18543..f1e94e1 100644
--- a/erpnext/subcontracting/doctype/subcontracting_order_service_item/subcontracting_order_service_item.json
+++ b/erpnext/subcontracting/doctype/subcontracting_order_service_item/subcontracting_order_service_item.json
@@ -19,7 +19,11 @@
"fg_item",
"column_break_12",
"fg_item_qty",
- "purchase_order_item"
+ "purchase_order_item",
+ "section_break_kphn",
+ "material_request",
+ "column_break_piqi",
+ "material_request_item"
],
"fields": [
{
@@ -122,11 +126,36 @@
"no_copy": 1,
"read_only": 1,
"search_index": 1
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "section_break_kphn",
+ "fieldtype": "Section Break",
+ "label": "Reference"
+ },
+ {
+ "fieldname": "material_request",
+ "fieldtype": "Link",
+ "label": "Material Request",
+ "no_copy": 1,
+ "options": "Material Request",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_piqi",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "material_request_item",
+ "fieldtype": "Data",
+ "label": "Material Request Item",
+ "no_copy": 1,
+ "read_only": 1
}
],
"istable": 1,
"links": [],
- "modified": "2023-11-23 17:05:04.561948",
+ "modified": "2023-11-30 13:29:31.017440",
"modified_by": "Administrator",
"module": "Subcontracting",
"name": "Subcontracting Order Service Item",