Merge pull request #2329 from neilLasrado/material-issue
Material Issue added to Material Request #2320
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 7c895bb..d5f2ccb 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -91,3 +91,4 @@
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 147a3b1..54c1d8f 100644
--- a/erpnext/stock/doctype/material_request/material_request.js
+++ b/erpnext/stock/doctype/material_request/material_request.js
@@ -42,9 +42,13 @@
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 @@
// 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 a9ace56..6107778 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\nMaterial Transfer\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-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 f78c0a7..ec77cf3 100644
--- a/erpnext/stock/doctype/material_request/material_request.py
+++ b/erpnext/stock/doctype/material_request/material_request.py
@@ -73,7 +73,7 @@
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", "Material Transfer", "Material Issue"])
pc_obj = frappe.get_doc('Purchase Common')
pc_obj.validate_for_items(self)
@@ -112,7 +112,7 @@
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")
@@ -294,12 +294,19 @@
@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:
+ target.s_warehouse = obj.warehouse
def set_missing_values(source, target):
- target.purpose = "Material Transfer"
+ target.purpose = source.material_request_type
target.run_method("get_stock_and_rate")
doclist = get_mapped_doc("Material Request", source_name, {
@@ -307,7 +314,7 @@
"doctype": "Stock Entry",
"validation": {
"docstatus": ["=", 1],
- "material_request_type": ["=", "Transfer"]
+ "material_request_type": ["in", ["Material Transfer", "Material Issue"]]
}
},
"Material Request Item": {
@@ -316,7 +323,6 @@
"name": "material_request_item",
"parent": "material_request",
"uom": "stock_uom",
- "warehouse": "t_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 ab1d3cc..0b23af0 100644
--- a/erpnext/stock/doctype/material_request/test_material_request.py
+++ b/erpnext/stock/doctype/material_request/test_material_request.py
@@ -51,14 +51,14 @@
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)
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",
@@ -77,7 +77,7 @@
"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 @@
"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",
}
]
})
@@ -168,7 +168,7 @@
# 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 @@
# 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 @@
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 @@
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])
@@ -372,6 +383,56 @@
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 d06a761..f0af283 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -219,7 +219,7 @@
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)
@@ -625,7 +625,8 @@
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)
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index eae1bf6..62cc397 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -87,7 +87,7 @@
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):