From 2f6d56dd6280d08ad2e3bcf7fac44419d9976e9c Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Thu, 29 Jun 2023 18:44:40 +0530 Subject: [PATCH 1/2] fix: don't update SCO status to closed until full return --- .../doctype/subcontracting_order/subcontracting_order.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py index 39197332c1..0b14d4d9f5 100644 --- a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py +++ b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py @@ -163,9 +163,10 @@ class SubcontractingOrder(SubcontractingController): elif self.per_received > 0 and self.per_received < 100: status = "Partially Received" for item in self.supplied_items: - if item.returned_qty: - status = "Closed" + if not item.returned_qty or (item.supplied_qty - item.consumed_qty - item.returned_qty) > 0: break + else: + status = "Closed" else: total_required_qty = total_supplied_qty = 0 for item in self.supplied_items: From 2a60884abc367a46779b1577e8f0397d1f60f3fd Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Thu, 29 Jun 2023 18:59:18 +0530 Subject: [PATCH 2/2] fix: reduce return qty while calculating transferred qty --- .../controllers/subcontracting_controller.py | 82 ++++++++++--------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/erpnext/controllers/subcontracting_controller.py b/erpnext/controllers/subcontracting_controller.py index 40dcd0cc08..57339bf4ca 100644 --- a/erpnext/controllers/subcontracting_controller.py +++ b/erpnext/controllers/subcontracting_controller.py @@ -173,50 +173,52 @@ class SubcontractingController(StockController): self.qty_to_be_received[(row.item_code, row.parent)] += row.qty def __get_transferred_items(self): - fields = [ - f"`tabStock Entry`.`{self.subcontract_data.order_field}`", - "`tabStock Entry`.`name` as voucher_no", - ] + se = frappe.qb.DocType("Stock Entry") + se_detail = frappe.qb.DocType("Stock Entry Detail") - alias_dict = { - "item_code": "rm_item_code", - "subcontracted_item": "main_item_code", - "basic_rate": "rate", - } - - child_table_fields = [ - "item_code", - "item_name", - "description", - "qty", - "basic_rate", - "amount", - "serial_no", - "serial_and_batch_bundle", - "uom", - "subcontracted_item", - "stock_uom", - "batch_no", - "conversion_factor", - "s_warehouse", - "t_warehouse", - "item_group", - self.subcontract_data.rm_detail_field, - ] + query = ( + frappe.qb.from_(se) + .inner_join(se_detail) + .on(se.name == se_detail.parent) + .select( + se[self.subcontract_data.order_field], + se.name.as_("voucher_no"), + se_detail.item_code.as_("rm_item_code"), + se_detail.item_name, + se_detail.description, + ( + frappe.qb.terms.Case() + .when(((se.purpose == "Material Transfer") & (se.is_return == 1)), -1 * se_detail.qty) + .else_(se_detail.qty) + ).as_("qty"), + se_detail.basic_rate.as_("rate"), + se_detail.amount, + se_detail.serial_no, + se_detail.serial_and_batch_bundle, + se_detail.uom, + se_detail.subcontracted_item.as_("main_item_code"), + se_detail.stock_uom, + se_detail.batch_no, + se_detail.conversion_factor, + se_detail.s_warehouse, + se_detail.t_warehouse, + se_detail.item_group, + se_detail[self.subcontract_data.rm_detail_field], + ) + .where( + (se.docstatus == 1) + & (se[self.subcontract_data.order_field].isin(self.subcontract_orders)) + & ( + (se.purpose == "Send to Subcontractor") + | ((se.purpose == "Material Transfer") & (se.is_return == 1)) + ) + ) + ) if self.backflush_based_on == "BOM": - child_table_fields.append("original_item") + query = query.select(se_detail.original_item) - for field in child_table_fields: - fields.append(f"`tabStock Entry Detail`.`{field}` As {alias_dict.get(field, field)}") - - filters = [ - ["Stock Entry", "docstatus", "=", 1], - ["Stock Entry", "purpose", "=", "Send to Subcontractor"], - ["Stock Entry", self.subcontract_data.order_field, "in", self.subcontract_orders], - ] - - return frappe.get_all("Stock Entry", fields=fields, filters=filters) + return query.run(as_dict=True) def __set_alternative_item_details(self, row): if row.get("original_item"):