From f5279a0d6753257d17b80640224cac169ecf950f Mon Sep 17 00:00:00 2001 From: pawan Date: Fri, 24 Nov 2017 11:21:47 +0530 Subject: [PATCH 01/10] [fix] #8427 --- .../doctype/purchase_order/purchase_order.py | 15 ++++++++- erpnext/stock/dashboard/item_dashboard.js | 2 +- erpnext/stock/dashboard/item_dashboard.py | 5 +-- erpnext/stock/doctype/bin/bin.json | 32 ++++++++++++++++++- erpnext/stock/doctype/bin/bin.py | 22 +++++++++++++ .../stock/doctype/stock_entry/stock_entry.py | 27 ++++++++++++++++ .../stock/page/stock_balance/stock_balance.js | 1 + erpnext/stock/stock_balance.py | 2 +- 8 files changed, 100 insertions(+), 6 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index bbaa043208..038683090b 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -13,7 +13,7 @@ from erpnext.stock.stock_balance import update_bin_qty, get_ordered_qty from frappe.desk.notifications import clear_doctype_notifications from erpnext.buying.utils import (validate_for_items, check_for_closed_status, update_last_purchase_rate) - +from erpnext.stock.utils import get_bin form_grid_templates = { "items": "templates/form_grid/item_grid.html" @@ -187,6 +187,8 @@ class PurchaseOrder(BuyingController): self.update_prevdoc_status() self.update_requested_qty() self.update_ordered_qty() + if self.is_subcontracted == "Yes": + self.update_reserved_qty_for_subcontract() frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype, self.company, self.base_grand_total) @@ -249,6 +251,17 @@ class PurchaseOrder(BuyingController): if item.delivered_by_supplier == 1: item.received_qty = item.qty + def update_reserved_qty_for_subcontract(self): + items = list(set([d.rm_item_code for d in self.get("supplied_items")])) + item_wh = frappe._dict(frappe.db.sql("""select item_code, default_warehouse + from `tabItem` where name in ({0})""".format(", ".join(["%s"] * len(items))), items)) + + for d in self.supplied_items: + if d.rm_item_code: + warehouse = item_wh.get(d.rm_item_code) + stock_bin = get_bin(d.rm_item_code, warehouse) + stock_bin.update_reserved_qty_for_sub_contracting(self.name, transferred_qty=0, transaction_type = "Reserve") + @frappe.whitelist() def close_or_unclose_purchase_orders(names, status): if not frappe.has_permission("Purchase Order", "write"): diff --git a/erpnext/stock/dashboard/item_dashboard.js b/erpnext/stock/dashboard/item_dashboard.js index 3c334c46b6..23820d32b2 100644 --- a/erpnext/stock/dashboard/item_dashboard.js +++ b/erpnext/stock/dashboard/item_dashboard.js @@ -89,7 +89,7 @@ erpnext.stock.ItemDashboard = Class.extend({ data.forEach(function(d) { d.actual_or_pending = d.projected_qty + d.reserved_qty + d.reserved_qty_for_production; d.pending_qty = 0; - d.total_reserved = d.reserved_qty + d.reserved_qty_for_production; + d.total_reserved = d.reserved_qty + d.reserved_qty_for_production + d.reserved_qty_for_sub_contract; if(d.actual_or_pending > d.actual_qty) { d.pending_qty = d.actual_or_pending - d.actual_qty; } diff --git a/erpnext/stock/dashboard/item_dashboard.py b/erpnext/stock/dashboard/item_dashboard.py index 0d75a9a544..f95daafd38 100644 --- a/erpnext/stock/dashboard/item_dashboard.py +++ b/erpnext/stock/dashboard/item_dashboard.py @@ -26,13 +26,14 @@ def get_data(item_code=None, warehouse=None, item_group=None, return frappe.db.sql(''' select b.item_code, b.warehouse, b.projected_qty, b.reserved_qty, - b.reserved_qty_for_production, b.actual_qty, b.valuation_rate, i.item_name + b.reserved_qty_for_production, b.reserved_qty_for_sub_contract, b.actual_qty, b.valuation_rate, i.item_name from tabBin b, tabItem i where b.item_code = i.name and - (b.projected_qty != 0 or b.reserved_qty != 0 or b.reserved_qty_for_production != 0 or b.actual_qty != 0) + (b.projected_qty != 0 or b.reserved_qty != 0 or b.reserved_qty_for_production != 0 + or b.reserved_qty_for_sub_contract != 0 or b.actual_qty != 0) {conditions} order by {sort_by} {sort_order} diff --git a/erpnext/stock/doctype/bin/bin.json b/erpnext/stock/doctype/bin/bin.json index 1f6e9e1785..def817b65d 100644 --- a/erpnext/stock/doctype/bin/bin.json +++ b/erpnext/stock/doctype/bin/bin.json @@ -296,6 +296,36 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "reserved_qty_for_sub_contract", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Reserved Qty for sub contract", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -463,7 +493,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-06-13 13:06:32.601505", + "modified": "2017-11-22 08:14:30.615638", "modified_by": "Administrator", "module": "Stock", "name": "Bin", diff --git a/erpnext/stock/doctype/bin/bin.py b/erpnext/stock/doctype/bin/bin.py index 626a9db97f..b3e89dc78d 100644 --- a/erpnext/stock/doctype/bin/bin.py +++ b/erpnext/stock/doctype/bin/bin.py @@ -94,6 +94,28 @@ class Bin(Document): self.db_set('reserved_qty_for_production', self.reserved_qty_for_production) self.db_set('projected_qty', self.projected_qty) + def update_reserved_qty_for_sub_contracting(self, po_name, transferred_qty, transaction_type): + #Update Reserved Quantity for Sub Contracting in Bin + if transaction_type == "Reserve": + required_qty = frappe.db.sql('''select sum(itemsup.required_qty) + from `tabItem` item, `tabPurchase Order` po, `tabPurchase Order Item Supplied` itemsup + where + item.name = itemsup.rm_item_code + and po.name = %s + and itemsup.rm_item_code = %s + and itemsup.parent = po.name + and po.docstatus = 1 + and po.is_subcontracted = 'Yes' + and item.default_warehouse = %s''', (po_name, self.item_code, self.warehouse))[0][0] + elif transaction_type == "Transfer": + required_qty = 0 + + reserved_qty_bin = self.reserved_qty_for_sub_contract + reserved_qty_for_sub_contract = reserved_qty_bin + required_qty - transferred_qty + + self.set_projected_qty() + self.db_set('reserved_qty_for_sub_contract', reserved_qty_for_sub_contract) + self.db_set('projected_qty', self.projected_qty) def update_item_projected_qty(item_code): '''Set total_projected_qty in Item as sum of projected qty in all warehouses''' diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 4d79e13d74..40e386ea67 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -11,6 +11,7 @@ from erpnext.stock.stock_ledger import get_previous_sle, NegativeStockError from erpnext.stock.get_item_details import get_bin_details, get_default_cost_center, get_conversion_factor from erpnext.stock.doctype.batch.batch import get_batch_no, set_batch_nos from erpnext.manufacturing.doctype.bom.bom import validate_bom_no +from erpnext.stock.utils import get_bin import json class IncorrectValuationRateError(frappe.ValidationError): pass @@ -64,6 +65,8 @@ class StockEntry(StockController): update_serial_nos_after_submit(self, "items") self.update_production_order() self.validate_purchase_order() + if self.purchase_order and self.purpose == "Subcontract": + self.update_purchase_order_supplied_items() self.make_gl_entries() def on_cancel(self): @@ -803,6 +806,30 @@ class StockEntry(StockController): if getdate(self.posting_date) > getdate(expiry_date): frappe.throw(_("Batch {0} of Item {1} has expired.").format(item.batch_no, item.item_code)) + def update_purchase_order_supplied_items(self): + materials_transferred = frappe._dict(frappe.db.sql(""" + select + concat(item_code, sed.s_warehouse), sum(qty) + from + `tabStock Entry` se, `tabStock Entry Detail` sed + where + se.name = sed.parent and se.docstatus=1 and se.purpose='Subcontract' + and se.purchase_order= %s and ifnull(sed.s_warehouse, '') != '' + group by sed.item_code, sed.s_warehouse + """, self.purchase_order)) + #Get PO Supplied Items Details + po_doc = frappe.get_doc("Purchase Order",self.purchase_order) + po_supplied_items = po_doc.get("supplied_items") + items = list(set([d.rm_item_code for d in po_supplied_items])) + item_wh = frappe._dict(frappe.db.sql("""select item_code as "item_code", default_warehouse as "warehouse" + from tabItem where name in ({0})""".format(", ".join(["%s"] * len(items))), items)) + #Update reserved sub contracted quantity in bin based on Supplied Item Details + for d in po_supplied_items: + warehouse = item_wh.get(d.rm_item_code) + transferred_qty = materials_transferred.get(d.rm_item_code + warehouse) + stock_bin = get_bin(d.rm_item_code, warehouse) + stock_bin.update_reserved_qty_for_sub_contracting(self.purchase_order, transferred_qty, transaction_type = "Transfer") + @frappe.whitelist() def get_production_order_details(production_order): production_order = frappe.get_doc("Production Order", production_order) diff --git a/erpnext/stock/page/stock_balance/stock_balance.js b/erpnext/stock/page/stock_balance/stock_balance.js index 16a85fa922..85ea5b19be 100644 --- a/erpnext/stock/page/stock_balance/stock_balance.js +++ b/erpnext/stock/page/stock_balance/stock_balance.js @@ -48,6 +48,7 @@ frappe.pages['stock-balance'].on_page_load = function(wrapper) { {fieldname: 'projected_qty', label: __('Projected qty')}, {fieldname: 'reserved_qty', label: __('Reserved for sale')}, {fieldname: 'reserved_qty_for_production', label: __('Reserved for manufacturing')}, + {fieldname: 'reserved_qty_for_sub_contract', label: __('Reserved for sub contracting')}, {fieldname: 'actual_qty', label: __('Actual qty in stock')}, ] }, diff --git a/erpnext/stock/stock_balance.py b/erpnext/stock/stock_balance.py index 6a4ac439ee..49909d9c56 100644 --- a/erpnext/stock/stock_balance.py +++ b/erpnext/stock/stock_balance.py @@ -150,7 +150,7 @@ def update_bin_qty(item_code, warehouse, qty_dict=None): if mismatch: bin.projected_qty = (flt(bin.actual_qty) + flt(bin.ordered_qty) + flt(bin.indented_qty) + flt(bin.planned_qty) - flt(bin.reserved_qty) - - flt(bin.reserved_qty_for_production)) + - flt(bin.reserved_qty_for_production)) - flt(bin.reserved_qty_for_sub_contract) bin.save() From 54465f5df1adbfd6157c7d62fb3af360224669d7 Mon Sep 17 00:00:00 2001 From: pawan Date: Wed, 29 Nov 2017 10:18:38 +0530 Subject: [PATCH 02/10] review comments changes --- .../doctype/purchase_order/purchase_order.py | 12 +- .../purchase_order_item_supplied.json | 113 +++++++++++++++++- erpnext/controllers/buying_controller.py | 4 + erpnext/stock/doctype/bin/bin.py | 59 ++++++--- .../stock/doctype/stock_entry/stock_entry.py | 21 +--- 5 files changed, 164 insertions(+), 45 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index 038683090b..6522a34a6e 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -202,6 +202,9 @@ class PurchaseOrder(BuyingController): if self.has_drop_ship_item(): self.update_delivered_qty_in_sales_order() + if self.is_subcontracted == "Yes": + self.update_reserved_qty_for_subcontract() + self.check_for_closed_status() frappe.db.set(self,'status','Cancelled') @@ -252,15 +255,10 @@ class PurchaseOrder(BuyingController): item.received_qty = item.qty def update_reserved_qty_for_subcontract(self): - items = list(set([d.rm_item_code for d in self.get("supplied_items")])) - item_wh = frappe._dict(frappe.db.sql("""select item_code, default_warehouse - from `tabItem` where name in ({0})""".format(", ".join(["%s"] * len(items))), items)) - for d in self.supplied_items: if d.rm_item_code: - warehouse = item_wh.get(d.rm_item_code) - stock_bin = get_bin(d.rm_item_code, warehouse) - stock_bin.update_reserved_qty_for_sub_contracting(self.name, transferred_qty=0, transaction_type = "Reserve") + stock_bin = get_bin(d.rm_item_code, d.reserve_warehouse) + stock_bin.update_reserved_qty_for_sub_contracting() @frappe.whitelist() def close_or_unclose_purchase_orders(names, status): diff --git a/erpnext/buying/doctype/purchase_order_item_supplied/purchase_order_item_supplied.json b/erpnext/buying/doctype/purchase_order_item_supplied/purchase_order_item_supplied.json index 4a870374ce..1bcf5e444b 100644 --- a/erpnext/buying/doctype/purchase_order_item_supplied/purchase_order_item_supplied.json +++ b/erpnext/buying/doctype/purchase_order_item_supplied/purchase_order_item_supplied.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, "beta": 0, @@ -10,16 +11,20 @@ "editable_grid": 1, "fields": [ { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "main_item_code", "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Item Code", "length": 0, "no_copy": 0, @@ -29,6 +34,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 1, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -36,16 +42,20 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "rm_item_code", "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Raw Material Item Code", "length": 0, "no_copy": 0, @@ -55,6 +65,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 1, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -62,16 +73,20 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "required_qty", "fieldtype": "Float", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Supplied Qty", "length": 0, "no_copy": 0, @@ -81,6 +96,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 1, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -88,16 +104,20 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "rate", "fieldtype": "Currency", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Rate", "length": 0, "no_copy": 0, @@ -108,6 +128,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -115,16 +136,20 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "amount", "fieldtype": "Currency", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Amount", "length": 0, "no_copy": 0, @@ -135,6 +160,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 1, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -142,16 +168,49 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, + "fieldname": "column_break_6", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, "fieldname": "bom_detail_no", "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "BOM Detail No", "length": 0, "no_copy": 0, @@ -161,6 +220,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 1, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -168,16 +228,20 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "reference_name", "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Reference Name", "length": 0, "no_copy": 0, @@ -187,6 +251,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 1, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -194,16 +259,20 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "conversion_factor", "fieldtype": "Float", "hidden": 1, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Conversion Factor", "length": 0, "no_copy": 0, @@ -213,6 +282,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 1, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -220,16 +290,20 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "stock_uom", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Stock Uom", "length": 0, "no_copy": 0, @@ -240,6 +314,39 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "", + "fieldname": "reserve_warehouse", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Reserve Warehouse", + "length": 0, + "no_copy": 0, + "options": "Warehouse", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -247,17 +354,17 @@ "unique": 0 } ], + "has_web_view": 0, "hide_heading": 0, "hide_toolbar": 1, "idx": 1, "image_view": 0, "in_create": 0, - "in_dialog": 0, "is_submittable": 0, "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2016-07-11 03:28:05.533063", + "modified": "2017-11-29 08:51:08.362463", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order Item Supplied", @@ -266,5 +373,7 @@ "quick_entry": 0, "read_only": 0, "read_only_onload": 0, + "show_name_in_global_search": 0, + "track_changes": 0, "track_seen": 0 } \ No newline at end of file diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index a31db6484c..5f762d50e1 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -160,6 +160,10 @@ class BuyingController(StockController): if item in self.sub_contracted_items and not item.bom: frappe.throw(_("Please select BOM in BOM field for Item {0}").format(item.item_code)) + for supplied_item in self.get("supplied_items"): + if not supplied_item.reserve_warehouse: + frappe.throw(_("Reserved Warehouse is mandatory for Item {0} in Raw Materials supplied").format(supplied_item.rm_item_code)) + else: for item in self.get("items"): if item.bom: diff --git a/erpnext/stock/doctype/bin/bin.py b/erpnext/stock/doctype/bin/bin.py index b3e89dc78d..efda055ccd 100644 --- a/erpnext/stock/doctype/bin/bin.py +++ b/erpnext/stock/doctype/bin/bin.py @@ -94,27 +94,48 @@ class Bin(Document): self.db_set('reserved_qty_for_production', self.reserved_qty_for_production) self.db_set('projected_qty', self.projected_qty) - def update_reserved_qty_for_sub_contracting(self, po_name, transferred_qty, transaction_type): - #Update Reserved Quantity for Sub Contracting in Bin - if transaction_type == "Reserve": - required_qty = frappe.db.sql('''select sum(itemsup.required_qty) - from `tabItem` item, `tabPurchase Order` po, `tabPurchase Order Item Supplied` itemsup - where - item.name = itemsup.rm_item_code - and po.name = %s - and itemsup.rm_item_code = %s - and itemsup.parent = po.name - and po.docstatus = 1 - and po.is_subcontracted = 'Yes' - and item.default_warehouse = %s''', (po_name, self.item_code, self.warehouse))[0][0] - elif transaction_type == "Transfer": - required_qty = 0 - - reserved_qty_bin = self.reserved_qty_for_sub_contract - reserved_qty_for_sub_contract = reserved_qty_bin + required_qty - transferred_qty + def update_reserved_qty_for_sub_contracting(self): + #reserved qty + reserved_qty_for_sub_contract = frappe.db.sql('''select ifnull(sum(itemsup.required_qty),0) + from `tabPurchase Order` po, `tabPurchase Order Item Supplied` itemsup + where + itemsup.rm_item_code = %s + and itemsup.parent = po.name + and po.docstatus = 1 + and po.is_subcontracted = 'Yes' + and itemsup.reserve_warehouse = %s''', (self.item_code, self.warehouse))[0][0] + #cancelled qty + reserved_qty_cancelled = frappe.db.sql('''select ifnull(sum(itemsup.required_qty),0) + from `tabPurchase Order` po, `tabPurchase Order Item Supplied` itemsup + where + itemsup.rm_item_code = %s + and itemsup.parent = po.name + and po.docstatus = 2 + and po.is_subcontracted = 'Yes' + and itemsup.reserve_warehouse = %s''', (self.item_code, self.warehouse))[0][0] + #Get Transferred Entries + materials_transferred = frappe.db.sql(""" + select + ifnull(sum(qty),0) + from + `tabStock Entry` se, `tabStock Entry Detail` sed + where + sed.item_code = %s and sed.s_warehouse = %s + and se.name = sed.parent and se.docstatus=1 and se.purpose='Subcontract' + and ifnull(se.purchase_order, '') !=''""", (self.item_code, self.warehouse))[0][0] + #Material Transfer Cancelled + materials_transfer_cancelled = frappe.db.sql(""" + select + ifnull(sum(qty),0) + from + `tabStock Entry` se, `tabStock Entry Detail` sed + where + sed.item_code = %s and sed.s_warehouse = %s + and se.name = sed.parent and se.docstatus=2 and se.purpose='Subcontract' + and ifnull(se.purchase_order, '') !=''""", (self.item_code, self.warehouse))[0][0] self.set_projected_qty() - self.db_set('reserved_qty_for_sub_contract', reserved_qty_for_sub_contract) + self.db_set('reserved_qty_for_sub_contract', (reserved_qty_for_sub_contract - reserved_qty_cancelled - materials_transferred + materials_transfer_cancelled)) self.db_set('projected_qty', self.projected_qty) def update_item_projected_qty(item_code): diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 40e386ea67..e05ccc90f9 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -72,6 +72,8 @@ class StockEntry(StockController): def on_cancel(self): self.update_stock_ledger() self.update_production_order() + if self.purchase_order and self.purpose == "Subcontract": + self.update_purchase_order_supplied_items() self.make_gl_entries_on_cancel() def validate_purpose(self): @@ -807,28 +809,13 @@ class StockEntry(StockController): frappe.throw(_("Batch {0} of Item {1} has expired.").format(item.batch_no, item.item_code)) def update_purchase_order_supplied_items(self): - materials_transferred = frappe._dict(frappe.db.sql(""" - select - concat(item_code, sed.s_warehouse), sum(qty) - from - `tabStock Entry` se, `tabStock Entry Detail` sed - where - se.name = sed.parent and se.docstatus=1 and se.purpose='Subcontract' - and se.purchase_order= %s and ifnull(sed.s_warehouse, '') != '' - group by sed.item_code, sed.s_warehouse - """, self.purchase_order)) #Get PO Supplied Items Details po_doc = frappe.get_doc("Purchase Order",self.purchase_order) po_supplied_items = po_doc.get("supplied_items") - items = list(set([d.rm_item_code for d in po_supplied_items])) - item_wh = frappe._dict(frappe.db.sql("""select item_code as "item_code", default_warehouse as "warehouse" - from tabItem where name in ({0})""".format(", ".join(["%s"] * len(items))), items)) #Update reserved sub contracted quantity in bin based on Supplied Item Details for d in po_supplied_items: - warehouse = item_wh.get(d.rm_item_code) - transferred_qty = materials_transferred.get(d.rm_item_code + warehouse) - stock_bin = get_bin(d.rm_item_code, warehouse) - stock_bin.update_reserved_qty_for_sub_contracting(self.purchase_order, transferred_qty, transaction_type = "Transfer") + stock_bin = get_bin(d.rm_item_code, d.reserve_warehouse) + stock_bin.update_reserved_qty_for_sub_contracting() @frappe.whitelist() def get_production_order_details(production_order): From 11398fd572c72c2d09bbd8c02bc8c7dbf4a2c80a Mon Sep 17 00:00:00 2001 From: pawan Date: Wed, 29 Nov 2017 21:16:02 +0530 Subject: [PATCH 03/10] Validation for reserved warhouse --- erpnext/buying/doctype/purchase_order/purchase_order.py | 4 ++-- .../purchase_order_item_supplied.json | 3 +-- erpnext/stock/doctype/stock_entry/stock_entry.py | 6 ++++++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index 6522a34a6e..942a2e6641 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -257,8 +257,8 @@ class PurchaseOrder(BuyingController): def update_reserved_qty_for_subcontract(self): for d in self.supplied_items: if d.rm_item_code: - stock_bin = get_bin(d.rm_item_code, d.reserve_warehouse) - stock_bin.update_reserved_qty_for_sub_contracting() + stock_bin = get_bin(d.rm_item_code, d.reserve_warehouse) + stock_bin.update_reserved_qty_for_sub_contracting() @frappe.whitelist() def close_or_unclose_purchase_orders(names, status): diff --git a/erpnext/buying/doctype/purchase_order_item_supplied/purchase_order_item_supplied.json b/erpnext/buying/doctype/purchase_order_item_supplied/purchase_order_item_supplied.json index 1bcf5e444b..5e8754fad3 100644 --- a/erpnext/buying/doctype/purchase_order_item_supplied/purchase_order_item_supplied.json +++ b/erpnext/buying/doctype/purchase_order_item_supplied/purchase_order_item_supplied.json @@ -327,7 +327,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "default": "", "fieldname": "reserve_warehouse", "fieldtype": "Link", "hidden": 0, @@ -364,7 +363,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-11-29 08:51:08.362463", + "modified": "2017-11-29 21:10:40.431423", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order Item Supplied", diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index e05ccc90f9..15d9c05041 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -812,6 +812,12 @@ class StockEntry(StockController): #Get PO Supplied Items Details po_doc = frappe.get_doc("Purchase Order",self.purchase_order) po_supplied_items = po_doc.get("supplied_items") + #Validate source warehouse is same as reserved warehouse + for item in self.get("items"): + if item.s_warehouse: + for d in po_supplied_items: + if item.item_code == d.rm_item_code and item.s_warehouse != d.reserve_warehouse: + frappe.throw(_("In case of Sub Contract Stock Entry, Source Warehouse: {0} should match with Reserved Warehouse: {1} on PO").format(item.s_warehouse,d.reserve_warehouse)) #Update reserved sub contracted quantity in bin based on Supplied Item Details for d in po_supplied_items: stock_bin = get_bin(d.rm_item_code, d.reserve_warehouse) From abc5523405ade03a738f94dc5893f0aafa064a0c Mon Sep 17 00:00:00 2001 From: pawan Date: Thu, 30 Nov 2017 12:23:46 +0530 Subject: [PATCH 04/10] code improvements --- .../stock/doctype/stock_entry/stock_entry.py | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 15d9c05041..dc668210d1 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -560,10 +560,18 @@ class StockEntry(StockController): frappe.throw(_("Manufacturing Quantity is mandatory")) item_dict = self.get_bom_raw_materials(self.fg_completed_qty) + #Get PO Supplied Items Details + if self.purchase_order and self.purpose == "Subcontract": + #Get PO Supplied Items Details + item_wh = frappe._dict(frappe.db.sql("""select rm_item_code, reserve_warehouse + from `tabPurchase Order` po, `tabPurchase Order Item Supplied` poitemsup + where po.name = poitemsup.parent + and po.name = %s""",self.purchase_order)) for item in item_dict.values(): if self.pro_doc and not self.pro_doc.skip_transfer: item["from_warehouse"] = self.pro_doc.wip_warehouse - + #Get Reserve Warehouse from PO + item["from_warehouse"] = item_wh.get(item.item_code) item["to_warehouse"] = self.to_warehouse if self.purpose=="Subcontract" else "" self.add_to_stock_entry_detail(item_dict) @@ -810,17 +818,18 @@ class StockEntry(StockController): def update_purchase_order_supplied_items(self): #Get PO Supplied Items Details - po_doc = frappe.get_doc("Purchase Order",self.purchase_order) - po_supplied_items = po_doc.get("supplied_items") + item_wh = frappe._dict(frappe.db.sql("""select rm_item_code, reserve_warehouse + from `tabPurchase Order` po, `tabPurchase Order Item Supplied` poitemsup + where po.name = poitemsup.parent + and po.name = %s""",self.purchase_order)) #Validate source warehouse is same as reserved warehouse for item in self.get("items"): - if item.s_warehouse: - for d in po_supplied_items: - if item.item_code == d.rm_item_code and item.s_warehouse != d.reserve_warehouse: - frappe.throw(_("In case of Sub Contract Stock Entry, Source Warehouse: {0} should match with Reserved Warehouse: {1} on PO").format(item.s_warehouse,d.reserve_warehouse)) + reserve_warehouse = item_wh.get(item.item_code) + if item.s_warehouse != reserve_warehouse: + frappe.throw(_("In case of Sub Contract Stock Entry, Source Warehouse: {0} should match with Reserved Warehouse: {1} entered on Purchase Order {2}").format(item.s_warehouse,reserve_warehouse,self.purchase_order)) #Update reserved sub contracted quantity in bin based on Supplied Item Details - for d in po_supplied_items: - stock_bin = get_bin(d.rm_item_code, d.reserve_warehouse) + for d in self.get("items"): + stock_bin = get_bin(d.item_code, d.s_warehouse) stock_bin.update_reserved_qty_for_sub_contracting() @frappe.whitelist() From e43cd915e865f82c1cf4b0f65ba9f9033658d334 Mon Sep 17 00:00:00 2001 From: pawan Date: Thu, 30 Nov 2017 12:31:32 +0530 Subject: [PATCH 05/10] alignment --- erpnext/stock/doctype/stock_entry/stock_entry.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index dc668210d1..91b75aa329 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -564,9 +564,9 @@ class StockEntry(StockController): if self.purchase_order and self.purpose == "Subcontract": #Get PO Supplied Items Details item_wh = frappe._dict(frappe.db.sql("""select rm_item_code, reserve_warehouse - from `tabPurchase Order` po, `tabPurchase Order Item Supplied` poitemsup - where po.name = poitemsup.parent - and po.name = %s""",self.purchase_order)) + from `tabPurchase Order` po, `tabPurchase Order Item Supplied` poitemsup + where po.name = poitemsup.parent + and po.name = %s""",self.purchase_order)) for item in item_dict.values(): if self.pro_doc and not self.pro_doc.skip_transfer: item["from_warehouse"] = self.pro_doc.wip_warehouse @@ -819,9 +819,9 @@ class StockEntry(StockController): def update_purchase_order_supplied_items(self): #Get PO Supplied Items Details item_wh = frappe._dict(frappe.db.sql("""select rm_item_code, reserve_warehouse - from `tabPurchase Order` po, `tabPurchase Order Item Supplied` poitemsup - where po.name = poitemsup.parent - and po.name = %s""",self.purchase_order)) + from `tabPurchase Order` po, `tabPurchase Order Item Supplied` poitemsup + where po.name = poitemsup.parent + and po.name = %s""",self.purchase_order)) #Validate source warehouse is same as reserved warehouse for item in self.get("items"): reserve_warehouse = item_wh.get(item.item_code) From f5bb2af92c36f3f9992c9c6eabe3a0660b3ad432 Mon Sep 17 00:00:00 2001 From: pawan Date: Thu, 30 Nov 2017 15:20:00 +0530 Subject: [PATCH 06/10] test case --- .../purchase_order/test_purchase_order.py | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py index 2af55825d4..ce85f8352d 100644 --- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py @@ -125,7 +125,21 @@ class TestPurchaseOrder(unittest.TestCase): "group_same_items": 1 }).insert(ignore_permissions=True) - + def test_reserved_qty_subcontract_po(self): + bin = frappe.get_all("Bin", filters={"warehouse": "_Test Warehouse - _TC"}, + fields=["item_code","reserved_qty_for_sub_contract"]) + + item_supplied = frappe.get_all("Purchase Order Item Supplied", filters={"main_item_code": "_Test FG Item", "reserve_warehouse": "_Test Warehouse - _TC"}, + fields=["rm_item_code","required_qty"]) + + for item_bin in bin: + total_sup_qty = 0 + for item_sup in item_supplied: + if item_bin["item_code"] == item_sup["rm_item_code"]: + total_sup_qty = total_sup_qty + item_sup["required_qty"] + + self.assertEquals(item_bin["reserved_qty_for_sub_contract"],total_sup_qty) + def get_same_items(): return [ { @@ -167,6 +181,10 @@ def create_purchase_order(**args): if not args.do_not_save: po.insert() if not args.do_not_submit: + if po.is_subcontracted == "Yes": + supp_items = po.get("supplied_items") + for d in supp_items: + d.reserve_warehouse = args.warehouse or "_Test Warehouse - _TC" po.submit() return po From e4aaff6686ddff57155a6349589c14b76ea129c0 Mon Sep 17 00:00:00 2001 From: pawan Date: Thu, 30 Nov 2017 15:49:54 +0530 Subject: [PATCH 07/10] message changes --- erpnext/controllers/buying_controller.py | 2 +- erpnext/stock/doctype/stock_entry/stock_entry.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index 5f762d50e1..6697e32cfd 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -162,7 +162,7 @@ class BuyingController(StockController): for supplied_item in self.get("supplied_items"): if not supplied_item.reserve_warehouse: - frappe.throw(_("Reserved Warehouse is mandatory for Item {0} in Raw Materials supplied").format(supplied_item.rm_item_code)) + frappe.throw(_("Reserved Warehouse is mandatory for Item {0} in Raw Materials supplied").format(frappe.bold(supplied_item.rm_item_code))) else: for item in self.get("items"): diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 91b75aa329..3ed157096e 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -826,7 +826,7 @@ class StockEntry(StockController): for item in self.get("items"): reserve_warehouse = item_wh.get(item.item_code) if item.s_warehouse != reserve_warehouse: - frappe.throw(_("In case of Sub Contract Stock Entry, Source Warehouse: {0} should match with Reserved Warehouse: {1} entered on Purchase Order {2}").format(item.s_warehouse,reserve_warehouse,self.purchase_order)) + frappe.throw(_("In case of Sub Contract Stock Entry, Source Warehouse: {0} should match with Reserved Warehouse: {1} entered on Purchase Order {2}").format(frappe.bold(item.s_warehouse),frappe.bold(reserve_warehouse),frappe.bold(self.purchase_order))) #Update reserved sub contracted quantity in bin based on Supplied Item Details for d in self.get("items"): stock_bin = get_bin(d.item_code, d.s_warehouse) From 2ff844e7403bffca91f386fdb21f294888922746 Mon Sep 17 00:00:00 2001 From: pawan Date: Thu, 30 Nov 2017 18:14:55 +0530 Subject: [PATCH 08/10] default warehouse / remove validation / change sql --- .../doctype/purchase_order/purchase_order.py | 5 ++-- erpnext/controllers/buying_controller.py | 4 +++ erpnext/stock/doctype/bin/bin.py | 28 ++++--------------- .../stock/doctype/stock_entry/stock_entry.py | 8 ++---- 4 files changed, 14 insertions(+), 31 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index 942a2e6641..bb78579ebd 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -257,8 +257,9 @@ class PurchaseOrder(BuyingController): def update_reserved_qty_for_subcontract(self): for d in self.supplied_items: if d.rm_item_code: - stock_bin = get_bin(d.rm_item_code, d.reserve_warehouse) - stock_bin.update_reserved_qty_for_sub_contracting() + warehouse = d.reserve_warehouse or bom_item_wh.get(d.rm_item_code) or item_wh.get(d.rm_item_code) + stock_bin = get_bin(d.rm_item_code, warehouse) + stock_bin.update_reserved_qty_for_sub_contracting() @frappe.whitelist() def close_or_unclose_purchase_orders(names, status): diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index 6697e32cfd..6956023d4f 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -193,6 +193,9 @@ class BuyingController(StockController): def update_raw_materials_supplied(self, item, raw_material_table): bom_items = self.get_items_from_bom(item.item_code, item.bom) raw_materials_cost = 0 + items = list(set([d.item_code for d in bom_items])) + item_wh = frappe._dict(frappe.db.sql("""select item_code, default_warehouse + from `tabItem` where name in ({0})""".format(", ".join(["%s"] * len(items))), items)) for bom_item in bom_items: # check if exists @@ -213,6 +216,7 @@ class BuyingController(StockController): rm.rm_item_code = bom_item.item_code rm.stock_uom = bom_item.stock_uom rm.required_qty = required_qty + rm.reserve_warehouse = bom_item.source_warehouse or item_wh.get(bom_item.item_code) rm.conversion_factor = item.conversion_factor diff --git a/erpnext/stock/doctype/bin/bin.py b/erpnext/stock/doctype/bin/bin.py index efda055ccd..0599db6343 100644 --- a/erpnext/stock/doctype/bin/bin.py +++ b/erpnext/stock/doctype/bin/bin.py @@ -104,38 +104,20 @@ class Bin(Document): and po.docstatus = 1 and po.is_subcontracted = 'Yes' and itemsup.reserve_warehouse = %s''', (self.item_code, self.warehouse))[0][0] - #cancelled qty - reserved_qty_cancelled = frappe.db.sql('''select ifnull(sum(itemsup.required_qty),0) - from `tabPurchase Order` po, `tabPurchase Order Item Supplied` itemsup - where - itemsup.rm_item_code = %s - and itemsup.parent = po.name - and po.docstatus = 2 - and po.is_subcontracted = 'Yes' - and itemsup.reserve_warehouse = %s''', (self.item_code, self.warehouse))[0][0] #Get Transferred Entries materials_transferred = frappe.db.sql(""" select ifnull(sum(qty),0) from - `tabStock Entry` se, `tabStock Entry Detail` sed + `tabStock Entry` se, `tabStock Entry Detail` sed, `tabPurchase Order` po where - sed.item_code = %s and sed.s_warehouse = %s + sed.item_code = %s and se.name = sed.parent and se.docstatus=1 and se.purpose='Subcontract' - and ifnull(se.purchase_order, '') !=''""", (self.item_code, self.warehouse))[0][0] - #Material Transfer Cancelled - materials_transfer_cancelled = frappe.db.sql(""" - select - ifnull(sum(qty),0) - from - `tabStock Entry` se, `tabStock Entry Detail` sed - where - sed.item_code = %s and sed.s_warehouse = %s - and se.name = sed.parent and se.docstatus=2 and se.purpose='Subcontract' - and ifnull(se.purchase_order, '') !=''""", (self.item_code, self.warehouse))[0][0] + and se.purchase_order = po.name + and ifnull(se.purchase_order, '') !=''""", (self.item_code))[0][0] self.set_projected_qty() - self.db_set('reserved_qty_for_sub_contract', (reserved_qty_for_sub_contract - reserved_qty_cancelled - materials_transferred + materials_transfer_cancelled)) + self.db_set('reserved_qty_for_sub_contract', (reserved_qty_for_sub_contract - materials_transferred)) self.db_set('projected_qty', self.projected_qty) def update_item_projected_qty(item_code): diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 3ed157096e..6528c285d7 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -822,14 +822,10 @@ class StockEntry(StockController): from `tabPurchase Order` po, `tabPurchase Order Item Supplied` poitemsup where po.name = poitemsup.parent and po.name = %s""",self.purchase_order)) - #Validate source warehouse is same as reserved warehouse - for item in self.get("items"): - reserve_warehouse = item_wh.get(item.item_code) - if item.s_warehouse != reserve_warehouse: - frappe.throw(_("In case of Sub Contract Stock Entry, Source Warehouse: {0} should match with Reserved Warehouse: {1} entered on Purchase Order {2}").format(frappe.bold(item.s_warehouse),frappe.bold(reserve_warehouse),frappe.bold(self.purchase_order))) #Update reserved sub contracted quantity in bin based on Supplied Item Details for d in self.get("items"): - stock_bin = get_bin(d.item_code, d.s_warehouse) + reserve_warehouse = item_wh.get(item.item_code) + stock_bin = get_bin(d.item_code, reserve_warehouse) stock_bin.update_reserved_qty_for_sub_contracting() @frappe.whitelist() From 14d570ed9eb081c027b466f4a0d50ab6daa14832 Mon Sep 17 00:00:00 2001 From: pawan Date: Thu, 30 Nov 2017 18:41:09 +0530 Subject: [PATCH 09/10] fix --- erpnext/buying/doctype/purchase_order/purchase_order.py | 3 +-- erpnext/controllers/buying_controller.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index bb78579ebd..6522a34a6e 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -257,8 +257,7 @@ class PurchaseOrder(BuyingController): def update_reserved_qty_for_subcontract(self): for d in self.supplied_items: if d.rm_item_code: - warehouse = d.reserve_warehouse or bom_item_wh.get(d.rm_item_code) or item_wh.get(d.rm_item_code) - stock_bin = get_bin(d.rm_item_code, warehouse) + stock_bin = get_bin(d.rm_item_code, d.reserve_warehouse) stock_bin.update_reserved_qty_for_sub_contracting() @frappe.whitelist() diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index 6956023d4f..f23aa297ee 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -268,7 +268,7 @@ class BuyingController(StockController): def get_items_from_bom(self, item_code, bom): bom_items = frappe.db.sql("""select t2.item_code, t2.stock_qty / ifnull(t1.quantity, 1) as qty_consumed_per_unit, - t2.rate, t2.stock_uom, t2.name, t2.description + t2.rate, t2.stock_uom, t2.name, t2.description, t2.source_warehouse from `tabBOM` t1, `tabBOM Item` t2, tabItem t3 where t2.parent = t1.name and t1.item = %s and t1.docstatus = 1 and t1.is_active = 1 and t1.name = %s From 990277a0ded5a7ceb78370786ae769cbb9c4adc6 Mon Sep 17 00:00:00 2001 From: pawan Date: Fri, 1 Dec 2017 16:45:47 +0530 Subject: [PATCH 10/10] patch --- .../update_reserved_qty_for_purchase_order.py | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 erpnext/patches/v9_2/update_reserved_qty_for_purchase_order.py diff --git a/erpnext/patches/v9_2/update_reserved_qty_for_purchase_order.py b/erpnext/patches/v9_2/update_reserved_qty_for_purchase_order.py new file mode 100644 index 0000000000..805c347c41 --- /dev/null +++ b/erpnext/patches/v9_2/update_reserved_qty_for_purchase_order.py @@ -0,0 +1,33 @@ +import frappe +from frappe import _ +from erpnext.stock.utils import get_bin + +def execute(): + def_warehouse = frappe.db.sql("""select min(name) from `tabWarehouse` where is_group = 0""")[0][0] + + po_item = list(frappe.db.sql(("""select distinct po.name as poname, poitem.rm_item_code as rm_item_code + from `tabPurchase Order` po, `tabPurchase Order Item Supplied` poitem + where po.name = poitem.parent + and po.is_subcontracted = "Yes" + and po.docstatus = 1"""),as_dict=1)) + + items = list(set([d.rm_item_code for d in po_item])) + item_wh = frappe._dict(frappe.db.sql("""select item_code, default_warehouse + from `tabItem` where name in ({0})""".format(", ".join(["%s"] * len(items))), items)) + #Update reserved warehouse + for item in po_item: + reserve_warehouse = item_wh.get(item.rm_item_code) or def_warehouse + update_res_warehouse = frappe.db.sql("""update `tabPurchase Order Item Supplied` + set reserve_warehouse = %s + where parent = %s and rm_item_code = %s""",(reserve_warehouse + ,item["poname"],item["rm_item_code"])) + #Update bin + item_wh_bin = frappe.db.sql(("""select distinct poitemsup.rm_item_code as rm_item_code, + poitemsup.reserve_warehouse as reserve_warehouse + from `tabPurchase Order` po, `tabPurchase Order Item Supplied` poitemsup + where po.name = poitemsup.parent + and po.is_subcontracted = "Yes" + and po.docstatus = 1"""),as_dict=1) + for d in item_wh_bin: + stock_bin = get_bin(d["rm_item_code"], d["reserve_warehouse"]) + stock_bin.update_reserved_qty_for_sub_contracting() \ No newline at end of file