From 5afc1947422947e14638ce18d1745c382318db4c Mon Sep 17 00:00:00 2001 From: Neil Lasrado Date: Thu, 14 Sep 2017 18:32:27 +0530 Subject: [PATCH 1/4] [BUG] Fixes make Production Order from Sales Order --- .../selling/doctype/sales_order/sales_order.js | 2 +- .../selling/doctype/sales_order/sales_order.py | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index 6f70ebe07e7..9b39ad011f3 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -193,7 +193,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( }); return; } - else if(!r.message.every(function(d) { return !!d.pending_qty })) { + else if(!r.message) { frappe.msgprint({ title: __('Production Order not created'), message: __('Production Order already created for all items with BOM'), diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index c3e28d21c74..e0ce3a4795d 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -336,14 +336,15 @@ class SalesOrder(SellingController): bom = get_default_bom_item(i.item_code) if bom: stock_qty = i.qty if i.doctype == 'Packed Item' else i.stock_qty - items.append(dict( - item_code= i.item_code, - bom = bom, - warehouse = i.warehouse, - pending_qty= stock_qty - flt(frappe.db.sql('''select sum(qty) from `tabProduction Order` - where production_item=%s and sales_order=%s''', (i.item_code, self.name))[0][0]) - )) - + pending_qty= stock_qty - flt(frappe.db.sql('''select sum(qty) from `tabProduction Order` + where production_item=%s and sales_order=%s and docstatus<2''', (i.item_code, self.name))[0][0]) + if pending_qty: + items.append(dict( + item_code= i.item_code, + bom = bom, + warehouse = i.warehouse, + pending_qty = pending_qty + )) return items def on_recurring(self, reference_doc, subscription_doc): From af091ac5dd5ed505d983bc024d560ec93fcdb7d5 Mon Sep 17 00:00:00 2001 From: Neil Lasrado Date: Fri, 15 Sep 2017 21:06:04 +0530 Subject: [PATCH 2/4] [BUG] Map Production Order with the exact Sales Order line item --- .../production_order/production_order.json | 32 ++++++++++++++++++- .../doctype/sales_order/sales_order.js | 2 ++ .../doctype/sales_order/sales_order.py | 6 ++-- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/erpnext/manufacturing/doctype/production_order/production_order.json b/erpnext/manufacturing/doctype/production_order/production_order.json index e56e5a1251f..71357f6d11a 100644 --- a/erpnext/manufacturing/doctype/production_order/production_order.json +++ b/erpnext/manufacturing/doctype/production_order/production_order.json @@ -1314,6 +1314,36 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "sales_order_item", + "fieldtype": "Data", + "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": "Sales Order Item", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "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, @@ -1358,7 +1388,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-07-10 14:29:00.457874", + "modified": "2017-09-15 11:34:10.018611", "modified_by": "Administrator", "module": "Manufacturing", "name": "Production Order", diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index 9b39ad011f3..70d79eb4b07 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -213,6 +213,8 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( }}, {fieldtype:'Float', fieldname:'pending_qty', reqd: 1, label: __('Qty'), in_list_view:1}, + {fieldtype:'Data', fieldname:'sales_order_item', reqd: 1, + label: __('Sales Order Item'), hidden:1} ], get_data: function() { return r.message diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index e0ce3a4795d..a3e13b679ca 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -337,13 +337,14 @@ class SalesOrder(SellingController): if bom: stock_qty = i.qty if i.doctype == 'Packed Item' else i.stock_qty pending_qty= stock_qty - flt(frappe.db.sql('''select sum(qty) from `tabProduction Order` - where production_item=%s and sales_order=%s and docstatus<2''', (i.item_code, self.name))[0][0]) + where production_item=%s and sales_order=%s and sales_order_item = %s and docstatus<2''', (i.item_code, self.name, i.name))[0][0]) if pending_qty: items.append(dict( item_code= i.item_code, bom = bom, warehouse = i.warehouse, - pending_qty = pending_qty + pending_qty = pending_qty, + sales_order_item = i.name )) return items @@ -768,6 +769,7 @@ def make_production_orders(items, sales_order, company, project=None): qty=i['pending_qty'], company=company, sales_order=sales_order, + sales_order_item=i['sales_order_item'], project=project, fg_warehouse=i['warehouse'] )).insert() From 7935d186f99c295111fcdc667dd59bb980bf2d13 Mon Sep 17 00:00:00 2001 From: Neil Lasrado Date: Tue, 26 Sep 2017 13:43:30 +0530 Subject: [PATCH 3/4] Auto set warehouses in Production Order if default warehouses are set in Manufacturing Settings and not mentioned in Production Order --- .../doctype/production_order/production_order.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/erpnext/manufacturing/doctype/production_order/production_order.py b/erpnext/manufacturing/doctype/production_order/production_order.py index f4d37760d31..a634bf269c2 100644 --- a/erpnext/manufacturing/doctype/production_order/production_order.py +++ b/erpnext/manufacturing/doctype/production_order/production_order.py @@ -35,6 +35,7 @@ class ProductionOrder(Document): validate_bom_no(self.production_item, self.bom_no) self.validate_sales_order() + self.set_default_warehouse() self.validate_warehouse_belongs_to_company() self.calculate_operating_cost() self.validate_qty() @@ -69,6 +70,12 @@ class ProductionOrder(Document): else: frappe.throw(_("Sales Order {0} is not valid").format(self.sales_order)) + def set_default_warehouse(self): + if not self.wip_warehouse: + self.wip_warehouse = frappe.db.get_single_value("Manufacturing Settings", "default_wip_warehouse") + if not self.fg_warehouse: + self.fg_warehouse = frappe.db.get_single_value("Manufacturing Settings", "default_fg_warehouse") + def validate_warehouse_belongs_to_company(self): warehouses = [self.fg_warehouse, self.wip_warehouse] for d in self.get("required_items"): From eb662b5a9a4c1e41c16bbac13da4eea23209b317 Mon Sep 17 00:00:00 2001 From: Neil Trini Lasrado Date: Wed, 18 Oct 2017 18:16:08 +0530 Subject: [PATCH 4/4] Added Test Cases --- .../doctype/sales_order/test_sales_order.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 9c5c82edc40..da600fbbc9d 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -10,6 +10,8 @@ from erpnext.selling.doctype.sales_order.sales_order \ import make_material_request, make_delivery_note, make_sales_invoice, WarehouseRequired from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry from frappe.tests.test_permissions import set_user_permission_doctypes +from erpnext.selling.doctype.sales_order.sales_order import make_production_orders +import json class TestSalesOrder(unittest.TestCase): def tearDown(self): @@ -505,6 +507,40 @@ class TestSalesOrder(unittest.TestCase): self.assertEquals(new_so.get("items")[0].rate, flt((price_list_rate*25)/100 + price_list_rate)) + def test_make_production_order(self): + # Make a new Sales Order + so = make_sales_order(**{ + "item_list": [{ + "item_code": "_Test FG Item", + "qty": 10, + "rate":100 + }, + { + "item_code": "_Test FG Item", + "qty": 20, + "rate":200 + }] + }) + + # Raise Production Orders + po_items= [] + so_item_name= {} + for item in so.get_production_order_items(): + po_items.append({ + "warehouse": item.get("warehouse"), + "item_code": item.get("item_code"), + "pending_qty": item.get("pending_qty"), + "sales_order_item": item.get("sales_order_item"), + "bom": item.get("bom") + }) + so_item_name[item.get("sales_order_item")]= item.get("pending_qty") + make_production_orders(json.dumps({"items":po_items}), so.name, so.company) + + # Check if Production Orders were raised + for item in so_item_name: + po_qty = frappe.db.sql("select sum(qty) from `tabProduction Order` where sales_order=%s and sales_order_item=%s", (so.name, item)) + self.assertEquals(po_qty[0][0], so_item_name.get(item)) + def make_sales_order(**args): so = frappe.new_doc("Sales Order") args = frappe._dict(args)