From ebbdd772a912923c0781d8906dcb0e32ff55fd33 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 5 Jun 2015 18:20:21 +0530 Subject: [PATCH 1/2] [fix] Validate and update manufactured qty in Stock Entry --- .../stock/doctype/stock_entry/stock_entry.py | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 0196c31bf1..e374b3b862 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals import frappe import frappe.defaults -from frappe.utils import cstr, cint, flt, comma_or, nowdate, get_datetime +from frappe.utils import cstr, cint, flt, comma_or, get_datetime from frappe import _ from erpnext.stock.utils import get_incoming_rate @@ -185,11 +185,16 @@ class StockEntry(StockController): def validate_production_order(self): if self.purpose in ("Manufacture", "Material Transfer for Manufacture"): + if not self.bom_no: + frappe.throw(_("BOM No is mandatory")) + # check if production order is entered if not self.production_order: frappe.throw(_("Production order number is mandatory for stock entry purpose manufacture")) # check for double entry if self.purpose=="Manufacture": + if not self.fg_completed_qty: + frappe.throw(_("For Quantity (Manufactured Qty) is mandatory")) self.check_if_operations_completed() self.check_duplicate_entry_for_production_order() elif self.purpose != "Material Transfer": @@ -378,10 +383,21 @@ class StockEntry(StockController): def validate_finished_goods(self): """validation: finished good quantity should be same as manufacturing quantity""" + items_with_target_warehouse = [] for d in self.get('items'): if d.bom_no and flt(d.transfer_qty) != flt(self.fg_completed_qty): frappe.throw(_("Quantity in row {0} ({1}) must be same as manufactured quantity {2}"). \ format(d.idx, d.transfer_qty, self.fg_completed_qty)) + + if self.production_order and self.purpose == "Manufacture" and d.t_warehouse: + items_with_target_warehouse.append(d.item_code) + + if self.production_order and self.purpose == "Manufacture": + production_item = frappe.db.get_value("Production Order", + self.production_order, "production_item") + if production_item not in items_with_target_warehouse: + frappe.throw(_("Finished Item {0} must be entered for Manufacture type entry") + .format(production_item)) def validate_return_reference_doc(self): """validate item with reference doc""" @@ -399,7 +415,6 @@ class StockEntry(StockController): # posting date check ref_posting_datetime = "%s %s" % (ref.doc.posting_date, ref.doc.posting_time or "00:00:00") - this_posting_datetime = "%s %s" % (self.posting_date, self.posting_time) if get_datetime(ref_posting_datetime) < get_datetime(ref_posting_datetime): from frappe.utils.dateutils import datetime_in_user_format @@ -474,9 +489,10 @@ class StockEntry(StockController): pro_doc = frappe.get_doc("Production Order", self.production_order) _validate_production_order(pro_doc) pro_doc.run_method("update_status") - pro_doc.run_method("update_production_order_qty") - if self.purpose == "Manufacture": - self.update_planned_qty(pro_doc) + if self.fg_completed_qty: + pro_doc.run_method("update_production_order_qty") + if self.purpose == "Manufacture": + self.update_planned_qty(pro_doc) def update_planned_qty(self, pro_doc): from erpnext.stock.utils import update_bin @@ -546,9 +562,6 @@ class StockEntry(StockController): return ret def get_items(self): - if not self.fg_completed_qty or not self.bom_no: - frappe.throw(_("BOM and Manufacturing Quantity are required")) - self.set('items', []) self.validate_production_order() @@ -638,17 +651,16 @@ class StockEntry(StockController): issued_item_qty = self.get_issued_qty() max_qty = flt(self.pro_doc.qty) - only_pending_fetched = [] - for item in item_dict: pending_to_issue = (max_qty * item_dict[item]["qty"]) - issued_item_qty.get(item, 0) desire_to_transfer = flt(self.fg_completed_qty) * item_dict[item]["qty"] + if desire_to_transfer <= pending_to_issue: item_dict[item]["qty"] = desire_to_transfer - else: + elif pending_to_issue > 0: item_dict[item]["qty"] = pending_to_issue - if pending_to_issue: - only_pending_fetched.append(item) + else: + item_dict[item]["qty"] = 0 # delete items with 0 qty for item in item_dict.keys(): @@ -659,9 +671,6 @@ class StockEntry(StockController): if not len(item_dict): frappe.msgprint(_("""All items have already been transferred for this Production Order.""")) - elif only_pending_fetched: - frappe.msgprint(_("Pending Items {0} updated").format(only_pending_fetched)) - return item_dict def get_issued_qty(self): From 56fcf30cb901e1c1cfe819bc627c7d57151e74c9 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 5 Jun 2015 18:21:25 +0530 Subject: [PATCH 2/2] [Patch] Update material transferred for manufacturing for existing entries --- erpnext/patches.txt | 3 ++- ...rial_transferred_for_manufacturing_again.py | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 erpnext/patches/v5_0/update_material_transferred_for_manufacturing_again.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 2104f7bcf8..0d1d0de3c2 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -164,4 +164,5 @@ erpnext.patches.v5_0.update_item_and_description_again erpnext.patches.v5_0.repost_gle_for_jv_with_multiple_party erpnext.patches.v5_0.portal_fixes erpnext.patches.v5_0.reset_values_in_tools -execute:frappe.delete_doc("Page", "users") \ No newline at end of file +execute:frappe.delete_doc("Page", "users") +erpnext.patches.v5_0.update_material_transferred_for_manufacturing_again \ No newline at end of file diff --git a/erpnext/patches/v5_0/update_material_transferred_for_manufacturing_again.py b/erpnext/patches/v5_0/update_material_transferred_for_manufacturing_again.py new file mode 100644 index 0000000000..a74b4bd776 --- /dev/null +++ b/erpnext/patches/v5_0/update_material_transferred_for_manufacturing_again.py @@ -0,0 +1,18 @@ +import frappe + +def execute(): + pro_order_qty_transferred = frappe._dict() + for se in frappe.db.sql("""select production_order, sum(fg_completed_qty) as transferred_qty + from `tabStock Entry` + where docstatus=1 and ifnull(production_order, '') != '' + and purpose = 'Material Transfer for Manufacture' + group by production_order""", as_dict=1): + pro_order_qty_transferred.setdefault(se.production_order, se.transferred_qty) + + for d in frappe.get_all("Production Order", filters={"docstatus": 1}, fields=["name", "qty"]): + if d.name in pro_order_qty_transferred: + material_transferred_for_manufacturing = pro_order_qty_transferred.get(d.name) \ + if pro_order_qty_transferred.get(d.name) <= d.qty else d.qty + + frappe.db.sql("""update `tabProduction Order` set material_transferred_for_manufacturing=%s + where name=%s""", (material_transferred_for_manufacturing, d.name)) \ No newline at end of file