From f24407e1199a07256628f35268fd221896e1314c Mon Sep 17 00:00:00 2001 From: Neil Trini Lasrado Date: Mon, 20 Oct 2014 16:04:19 +0530 Subject: [PATCH 1/6] Material Issue added to Material Request Type --- erpnext/stock/doctype/material_request/material_request.json | 4 ++-- erpnext/stock/doctype/material_request/material_request.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/erpnext/stock/doctype/material_request/material_request.json b/erpnext/stock/doctype/material_request/material_request.json index a9ace56d11..4b93d60310 100644 --- a/erpnext/stock/doctype/material_request/material_request.json +++ b/erpnext/stock/doctype/material_request/material_request.json @@ -17,7 +17,7 @@ "fieldtype": "Select", "in_list_view": 1, "label": "Type", - "options": "Purchase\nTransfer", + "options": "Purchase\nTransfer\nMaterial Issue", "permlevel": 0, "reqd": 1 }, @@ -235,7 +235,7 @@ "icon": "icon-ticket", "idx": 1, "is_submittable": 1, - "modified": "2014-09-09 05:35:31.735821", + "modified": "2014-10-20 14:13:11.043631", "modified_by": "Administrator", "module": "Stock", "name": "Material Request", diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py index f78c0a7bbf..3217513b8b 100644 --- a/erpnext/stock/doctype/material_request/material_request.py +++ b/erpnext/stock/doctype/material_request/material_request.py @@ -73,7 +73,7 @@ class MaterialRequest(BuyingController): from erpnext.utilities import validate_status validate_status(self.status, ["Draft", "Submitted", "Stopped", "Cancelled"]) - self.validate_value("material_request_type", "in", ["Purchase", "Transfer"]) + self.validate_value("material_request_type", "in", ["Purchase", "Transfer", "Material Issue"]) pc_obj = frappe.get_doc('Purchase Common') pc_obj.validate_for_items(self) @@ -112,7 +112,7 @@ class MaterialRequest(BuyingController): frappe.db.set(self,'status','Cancelled') def update_completed_qty(self, mr_items=None): - if self.material_request_type != "Transfer": + if self.material_request_type == "Purchase": return item_doclist = self.get("indent_details") From ce020cfb27d3110612078ff268539c349fc99ddd Mon Sep 17 00:00:00 2001 From: Neil Trini Lasrado Date: Mon, 27 Oct 2014 13:34:18 +0530 Subject: [PATCH 2/6] mapper added, type 'Transfer' renamed to 'Material Transfer', patch added --- erpnext/patches.txt | 1 + .../stock/doctype/material_request/material_request.js | 8 ++++++-- .../stock/doctype/material_request/material_request.json | 4 ++-- .../stock/doctype/material_request/material_request.py | 9 ++++++--- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 7c895bbdcf..d5f2ccb2ca 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -91,3 +91,4 @@ erpnext.patches.v4_2.update_requested_and_ordered_qty erpnext.patches.v4_2.party_model erpnext.patches.v5_0.update_frozen_accounts_permission_role erpnext.patches.v5_0.update_dn_against_doc_fields +execute:frappe.db.sql("update `tabMaterial Request` set material_request_type = 'Material Transfer' where material_request_type = 'Transfer'") \ No newline at end of file diff --git a/erpnext/stock/doctype/material_request/material_request.js b/erpnext/stock/doctype/material_request/material_request.js index 147a3b1d2c..54c1d8f3af 100644 --- a/erpnext/stock/doctype/material_request/material_request.js +++ b/erpnext/stock/doctype/material_request/material_request.js @@ -42,9 +42,13 @@ erpnext.buying.MaterialRequestController = erpnext.buying.BuyingController.exten this.make_supplier_quotation, frappe.boot.doctype_icons["Supplier Quotation"]); - if(doc.material_request_type === "Transfer" && doc.status === "Submitted") + if(doc.material_request_type === "Material Transfer" && doc.status === "Submitted") cur_frm.add_custom_button(__("Transfer Material"), this.make_stock_entry, frappe.boot.doctype_icons["Stock Entry"]); + + if(doc.material_request_type === "Material Issue" && doc.status === "Submitted") + cur_frm.add_custom_button(__("Issue Material"), this.make_stock_entry, + frappe.boot.doctype_icons["Stock Entry"]); if(flt(doc.per_ordered, 2) < 100) { if(doc.material_request_type === "Purchase") @@ -165,7 +169,7 @@ erpnext.buying.MaterialRequestController = erpnext.buying.BuyingController.exten // for backward compatibility: combine new and previous states $.extend(cur_frm.cscript, new erpnext.buying.MaterialRequestController({frm: cur_frm})); -cur_frm.cscript.qty = function(doc, cdt, cdn) { +cur_frm.cscript.qty = function(cdt, cdn) { var d = locals[cdt][cdn]; if (flt(d.qty) < flt(d.min_order_qty)) alert(__("Warning: Material Requested Qty is less than Minimum Order Qty")); diff --git a/erpnext/stock/doctype/material_request/material_request.json b/erpnext/stock/doctype/material_request/material_request.json index 4b93d60310..6107778d57 100644 --- a/erpnext/stock/doctype/material_request/material_request.json +++ b/erpnext/stock/doctype/material_request/material_request.json @@ -17,7 +17,7 @@ "fieldtype": "Select", "in_list_view": 1, "label": "Type", - "options": "Purchase\nTransfer\nMaterial Issue", + "options": "Purchase\nMaterial Transfer\nMaterial Issue", "permlevel": 0, "reqd": 1 }, @@ -235,7 +235,7 @@ "icon": "icon-ticket", "idx": 1, "is_submittable": 1, - "modified": "2014-10-20 14:13:11.043631", + "modified": "2014-10-27 12:16:38.833386", "modified_by": "Administrator", "module": "Stock", "name": "Material Request", diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py index 3217513b8b..715f66b50b 100644 --- a/erpnext/stock/doctype/material_request/material_request.py +++ b/erpnext/stock/doctype/material_request/material_request.py @@ -73,7 +73,7 @@ class MaterialRequest(BuyingController): from erpnext.utilities import validate_status validate_status(self.status, ["Draft", "Submitted", "Stopped", "Cancelled"]) - self.validate_value("material_request_type", "in", ["Purchase", "Transfer", "Material Issue"]) + self.validate_value("material_request_type", "in", ["Purchase", "Material Transfer", "Material Issue"]) pc_obj = frappe.get_doc('Purchase Common') pc_obj.validate_for_items(self) @@ -293,13 +293,16 @@ def make_supplier_quotation(source_name, target_doc=None): @frappe.whitelist() def make_stock_entry(source_name, target_doc=None): + + obj = frappe.get_doc("Material Request", source_name) + def update_item(obj, target, source_parent): target.conversion_factor = 1 target.qty = flt(obj.qty) - flt(obj.ordered_qty) target.transfer_qty = flt(obj.qty) - flt(obj.ordered_qty) def set_missing_values(source, target): - target.purpose = "Material Transfer" + target.purpose = obj.material_request_type target.run_method("get_stock_and_rate") doclist = get_mapped_doc("Material Request", source_name, { @@ -307,7 +310,7 @@ def make_stock_entry(source_name, target_doc=None): "doctype": "Stock Entry", "validation": { "docstatus": ["=", 1], - "material_request_type": ["=", "Transfer"] + "material_request_type": ["=", obj.material_request_type] } }, "Material Request Item": { From 67e9081bbf675bdf556ae00f93cd97075caec247 Mon Sep 17 00:00:00 2001 From: Neil Trini Lasrado Date: Thu, 30 Oct 2014 18:12:17 +0530 Subject: [PATCH 3/6] required modifications done --- .../doctype/material_request/material_request.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py index 715f66b50b..efb3edd73f 100644 --- a/erpnext/stock/doctype/material_request/material_request.py +++ b/erpnext/stock/doctype/material_request/material_request.py @@ -293,7 +293,7 @@ def make_supplier_quotation(source_name, target_doc=None): @frappe.whitelist() def make_stock_entry(source_name, target_doc=None): - + obj = frappe.get_doc("Material Request", source_name) def update_item(obj, target, source_parent): @@ -302,15 +302,19 @@ def make_stock_entry(source_name, target_doc=None): target.transfer_qty = flt(obj.qty) - flt(obj.ordered_qty) def set_missing_values(source, target): - target.purpose = obj.material_request_type + target.purpose = source.material_request_type target.run_method("get_stock_and_rate") + if obj.material_request_type=="Material Issue": + warehouse = "s_warehouse" + else: + warehouse = "t_warehouse" doclist = get_mapped_doc("Material Request", source_name, { "Material Request": { "doctype": "Stock Entry", "validation": { "docstatus": ["=", 1], - "material_request_type": ["=", obj.material_request_type] + "material_request_type": ["in", ["Material Transfer", "Material Issue"]] } }, "Material Request Item": { @@ -319,7 +323,7 @@ def make_stock_entry(source_name, target_doc=None): "name": "material_request_item", "parent": "material_request", "uom": "stock_uom", - "warehouse": "t_warehouse" + "warehouse": warehouse }, "postprocess": update_item } From f9ced8f28fc8d8a29305ab6db4e80e4f4cb4a122 Mon Sep 17 00:00:00 2001 From: Neil Trini Lasrado Date: Fri, 31 Oct 2014 17:22:47 +0530 Subject: [PATCH 4/6] test-cases added --- .../material_request/material_request.py | 12 ++++------- .../material_request/test_material_request.py | 21 ++++++++++++++----- .../stock/doctype/stock_entry/stock_entry.py | 3 ++- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py index efb3edd73f..80c61ab842 100644 --- a/erpnext/stock/doctype/material_request/material_request.py +++ b/erpnext/stock/doctype/material_request/material_request.py @@ -293,22 +293,19 @@ def make_supplier_quotation(source_name, target_doc=None): @frappe.whitelist() def make_stock_entry(source_name, target_doc=None): - - obj = frappe.get_doc("Material Request", source_name) - def update_item(obj, target, source_parent): target.conversion_factor = 1 target.qty = flt(obj.qty) - flt(obj.ordered_qty) target.transfer_qty = flt(obj.qty) - flt(obj.ordered_qty) + if source_parent.material_request_type == "Material Transfer": + target.t_warehouse = obj.warehouse + else: + target.s_warehouse = obj.warehouse def set_missing_values(source, target): target.purpose = source.material_request_type target.run_method("get_stock_and_rate") - if obj.material_request_type=="Material Issue": - warehouse = "s_warehouse" - else: - warehouse = "t_warehouse" doclist = get_mapped_doc("Material Request", source_name, { "Material Request": { "doctype": "Stock Entry", @@ -323,7 +320,6 @@ def make_stock_entry(source_name, target_doc=None): "name": "material_request_item", "parent": "material_request", "uom": "stock_uom", - "warehouse": warehouse }, "postprocess": update_item } diff --git a/erpnext/stock/doctype/material_request/test_material_request.py b/erpnext/stock/doctype/material_request/test_material_request.py index ab1d3ccd95..753c5b19a9 100644 --- a/erpnext/stock/doctype/material_request/test_material_request.py +++ b/erpnext/stock/doctype/material_request/test_material_request.py @@ -51,7 +51,7 @@ class TestMaterialRequest(unittest.TestCase): mr.name) mr = frappe.get_doc("Material Request", mr.name) - mr.material_request_type = "Transfer" + mr.material_request_type = "Material Transfer" mr.submit() se = make_stock_entry(mr.name) @@ -168,7 +168,7 @@ class TestMaterialRequest(unittest.TestCase): # submit material request of type Purchase mr = frappe.copy_doc(test_records[0]) - mr.material_request_type = "Transfer" + mr.material_request_type = "Material Transfer" mr.insert() mr.submit() @@ -257,7 +257,7 @@ class TestMaterialRequest(unittest.TestCase): # submit material request of type Purchase mr = frappe.copy_doc(test_records[0]) - mr.material_request_type = "Transfer" + mr.material_request_type = "Material Transfer" mr.insert() mr.submit() @@ -330,9 +330,9 @@ class TestMaterialRequest(unittest.TestCase): self.assertEquals(current_requested_qty_item2, existing_requested_qty_item2 + 3.0) def test_incorrect_mapping_of_stock_entry(self): - # submit material request of type Purchase + # submit material request of type Transfer mr = frappe.copy_doc(test_records[0]) - mr.material_request_type = "Transfer" + mr.material_request_type = "Material Transfer" mr.insert() mr.submit() @@ -363,6 +363,17 @@ class TestMaterialRequest(unittest.TestCase): se = frappe.copy_doc(se_doc) self.assertRaises(frappe.MappingMismatchError, se.insert) + # submit material request of type Transfer + mr = frappe.copy_doc(test_records[0]) + mr.material_request_type = "Material Issue" + mr.insert() + mr.submit() + + # map a stock entry + from erpnext.stock.doctype.material_request.material_request import make_stock_entry + se_doc = make_stock_entry(mr.name) + self.assertEquals(se_doc.get("mtn_details")[0].s_warehouse, "_Test Warehouse - _TC") + def test_warehouse_company_validation(self): from erpnext.stock.utils import InvalidWarehouseCompany mr = frappe.copy_doc(test_records[0]) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index d06a761075..839554a7f6 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -625,7 +625,8 @@ class StockEntry(StockController): mreq_item = frappe.db.get_value("Material Request Item", {"name": item.material_request_item, "parent": item.material_request}, ["item_code", "warehouse", "idx"], as_dict=True) - if mreq_item.item_code != item.item_code or mreq_item.warehouse != item.t_warehouse: + if mreq_item.item_code != item.item_code or \ + mreq_item.warehouse != (item.s_warehouse if self.purpose== "Material Issue" else item.t_warehouse): frappe.throw(_("Item or Warehouse for row {0} does not match Material Request").format(item.idx), frappe.MappingMismatchError) From 6d8f48ff8d521971bc95d2ec1bea9fb899ef9886 Mon Sep 17 00:00:00 2001 From: Neil Trini Lasrado Date: Tue, 4 Nov 2014 16:25:46 +0530 Subject: [PATCH 5/6] Test Cases Added - Work Pending --- .../material_request/material_request.py | 7 ++- .../material_request/test_material_request.py | 54 ++++++++++++++++++- .../stock/doctype/stock_entry/stock_entry.py | 2 +- erpnext/stock/stock_ledger.py | 2 +- 4 files changed, 59 insertions(+), 6 deletions(-) diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py index 80c61ab842..ec77cf3720 100644 --- a/erpnext/stock/doctype/material_request/material_request.py +++ b/erpnext/stock/doctype/material_request/material_request.py @@ -294,9 +294,12 @@ def make_supplier_quotation(source_name, target_doc=None): @frappe.whitelist() def make_stock_entry(source_name, target_doc=None): def update_item(obj, target, source_parent): + qty = flt(obj.qty) - flt(obj.ordered_qty) \ + if flt(obj.qty) > flt(obj.ordered_qty) else 0 + target.qty = qty + target.transfer_qty = qty target.conversion_factor = 1 - target.qty = flt(obj.qty) - flt(obj.ordered_qty) - target.transfer_qty = flt(obj.qty) - flt(obj.ordered_qty) + if source_parent.material_request_type == "Material Transfer": target.t_warehouse = obj.warehouse else: diff --git a/erpnext/stock/doctype/material_request/test_material_request.py b/erpnext/stock/doctype/material_request/test_material_request.py index 753c5b19a9..16abcf8f79 100644 --- a/erpnext/stock/doctype/material_request/test_material_request.py +++ b/erpnext/stock/doctype/material_request/test_material_request.py @@ -77,7 +77,7 @@ class TestMaterialRequest(unittest.TestCase): "stock_uom": "_Test UOM 1", "transfer_qty": qty1, "uom": "_Test UOM 1", - "t_warehouse": "_Test Warehouse 1 - _TC", + "t_warehouse": warehouse or "_Test Warehouse 1 - _TC", }, { "conversion_factor": 1.0, @@ -89,7 +89,7 @@ class TestMaterialRequest(unittest.TestCase): "stock_uom": "_Test UOM 1", "transfer_qty": qty2, "uom": "_Test UOM 1", - "t_warehouse": "_Test Warehouse 1 - _TC", + "t_warehouse": warehouse or "_Test Warehouse 1 - _TC", } ] }) @@ -383,6 +383,56 @@ class TestMaterialRequest(unittest.TestCase): def _get_requested_qty(self, item_code, warehouse): return flt(frappe.db.get_value("Bin", {"item_code": item_code, "warehouse": warehouse}, "indented_qty")) + def test_make_stock_entry_for_Material_Issue(self): + from erpnext.stock.doctype.material_request.material_request import make_stock_entry + + mr = frappe.copy_doc(test_records[0]).insert() + + self.assertRaises(frappe.ValidationError, make_stock_entry, + mr.name) + + mr = frappe.get_doc("Material Request", mr.name) + mr.material_request_type = "Material Issue" + mr.submit() + se = make_stock_entry(mr.name) + + self.assertEquals(se.doctype, "Stock Entry") + self.assertEquals(len(se.get("mtn_details")), len(mr.get("indent_details"))) + + def test_compleated_qty_for_issue(self): + def _get_requested_qty(): + return flt(frappe.db.get_value("Bin", {"item_code": "_Test Item Home Desktop 100", + "warehouse": "_Test Warehouse - _TC"}, "indented_qty")) + + from erpnext.stock.doctype.material_request.material_request import make_stock_entry + + existing_requested_qty = _get_requested_qty() + + mr = frappe.copy_doc(test_records[0]) + mr.material_request_type = "Material Issue" + mr.submit() + + #testing bin value after material request is submitted + self.assertEquals(_get_requested_qty(), existing_requested_qty + 54.0) + + # receive items to allow issue + self._insert_stock_entry(60, 6, "_Test Warehouse - _TC") + + # make stock entry against MR + + se_doc = make_stock_entry(mr.name) + se_doc.fiscal_year = "_Test Fiscal Year 2014" + se_doc.get("mtn_details")[0].qty = 60.0 + se_doc.insert() + se_doc.submit() + + # check if per complete is as expected + mr.load_from_db() + self.assertEquals(mr.get("indent_details")[0].ordered_qty, 60.0) + self.assertEquals(mr.get("indent_details")[1].ordered_qty, 3.0) + + #testing bin requested qty after issuing stock against material request + self.assertEquals(_get_requested_qty(), existing_requested_qty) test_dependencies = ["Currency Exchange"] test_records = frappe.get_test_records('Material Request') diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 839554a7f6..f0af283d99 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -219,7 +219,7 @@ class StockEntry(StockController): if not self.posting_date or not self.posting_time: frappe.throw(_("Posting date and posting time is mandatory")) - allow_negative_stock = cint(frappe.db.get_default("allow_negative_stock")) + allow_negative_stock = cint(frappe.db.get_value("Stock Settings", None, "allow_negative_stock")) for d in self.get('mtn_details'): d.transfer_qty = flt(d.transfer_qty) diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index eae1bf68bf..62cc397ef9 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -87,7 +87,7 @@ def update_entries_after(args, allow_zero_rate=False, verbose=1): stock_value_difference = 0.0 for sle in entries_to_fix: - if sle.serial_no or not cint(frappe.db.get_default("allow_negative_stock")): + if sle.serial_no or not cint(frappe.db.get_value("Stock Settings", None, "allow_negative_stock")): # validate negative stock for serialized items, fifo valuation # or when negative stock is not allowed for moving average if not validate_negative_stock(qty_after_transaction, sle): From 6bde5868a958f06769e77ab41e4cc40316e10f2d Mon Sep 17 00:00:00 2001 From: Neil Trini Lasrado Date: Wed, 5 Nov 2014 16:34:02 +0530 Subject: [PATCH 6/6] Test Cases Fixed --- erpnext/stock/doctype/material_request/test_material_request.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/material_request/test_material_request.py b/erpnext/stock/doctype/material_request/test_material_request.py index 16abcf8f79..0b23af057c 100644 --- a/erpnext/stock/doctype/material_request/test_material_request.py +++ b/erpnext/stock/doctype/material_request/test_material_request.py @@ -58,7 +58,7 @@ class TestMaterialRequest(unittest.TestCase): self.assertEquals(se.doctype, "Stock Entry") self.assertEquals(len(se.get("mtn_details")), len(mr.get("indent_details"))) - def _insert_stock_entry(self, qty1, qty2): + def _insert_stock_entry(self, qty1, qty2, warehouse = None ): se = frappe.get_doc({ "company": "_Test Company", "doctype": "Stock Entry",