From 1678f6d4ae77ff79649cb2add3517b734655bfd4 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Thu, 21 Feb 2013 16:55:14 +0530 Subject: [PATCH] update requested quantity in bin for both Purchase as well as Transfer type material request --- startup/report_data_map.py | 3 +- stock/doctype/bin/bin.py | 8 ++- .../material_request/material_request.py | 62 ++++++++++-------- .../material_request/test_material_request.py | 63 +++++++++++++++---- stock/doctype/stock_entry/stock_entry.py | 2 +- stock/doctype/warehouse/warehouse.py | 1 + 6 files changed, 95 insertions(+), 44 deletions(-) diff --git a/startup/report_data_map.py b/startup/report_data_map.py index c2e4023e9d..93995a9922 100644 --- a/startup/report_data_map.py +++ b/startup/report_data_map.py @@ -117,8 +117,7 @@ data_map = { "(ifnull(qty, 0) - ifnull(ordered_qty, 0)) as qty"], "from": "`tabMaterial Request Item` item, `tabMaterial Request` main", "conditions": ["item.parent = main.name", "main.docstatus=1", "main.status != 'Stopped'", - "material_request_type = 'Purchase'", "ifnull(warehouse, '')!=''", - "ifnull(qty, 0) > ifnull(ordered_qty, 0)"], + "ifnull(warehouse, '')!=''", "ifnull(qty, 0) > ifnull(ordered_qty, 0)"], "links": { "item_code": ["Item", "name"], "warehouse": ["Warehouse", "name"] diff --git a/stock/doctype/bin/bin.py b/stock/doctype/bin/bin.py index 56d116064b..37ecf85d2c 100644 --- a/stock/doctype/bin/bin.py +++ b/stock/doctype/bin/bin.py @@ -87,7 +87,7 @@ class DocType: if (flt(args.get("actual_qty")) < 0 or flt(args.get("reserved_qty")) > 0) \ and args.get("is_cancelled") == 'No' and args.get("is_amended")=='No': self.reorder_item(args.get("voucher_type"), args.get("voucher_no")) - + def get_first_sle(self): sle = sql(""" select * from `tabStock Ledger Entry` @@ -122,7 +122,8 @@ class DocType: self.create_material_request(doc_type, doc_name, reorder_level, reorder_qty, material_request_type) - def create_material_request(self, doc_type, doc_name, reorder_level, reorder_qty, material_request_type): + def create_material_request(self, doc_type, doc_name, reorder_level, reorder_qty, + material_request_type): """ Create indent on reaching reorder level """ defaults = webnotes.defaults.get_defaults() item = webnotes.doc("Item", self.doc.item_code) @@ -175,4 +176,5 @@ class DocType: formatdate(), doc_type, doc_name, bean.doc.doctype, get_url_to_form(bean.doc.doctype, bean.doc.name)) - sendmail(email_list, subject='Auto Material Request Generation Notification', msg = msg) + sendmail(email_list, subject='Auto Material Request Generation Notification', msg = msg) + diff --git a/stock/doctype/material_request/material_request.py b/stock/doctype/material_request/material_request.py index e476aa4743..708700d512 100644 --- a/stock/doctype/material_request/material_request.py +++ b/stock/doctype/material_request/material_request.py @@ -7,7 +7,7 @@ import webnotes from webnotes.utils import cstr, flt from webnotes.model.bean import getlist from webnotes.model.code import get_obj -from webnotes import msgprint +from webnotes import msgprint, _ from controllers.buying_controller import BuyingController class DocType(BuyingController): @@ -119,23 +119,22 @@ class DocType(BuyingController): def update_bin(self, is_submit, is_stopped): """ Update Quantity Requested for Purchase in Bin for Material Request of type 'Purchase'""" - if self.doc.material_request_type == "Purchase": - for d in getlist(self.doclist, 'indent_details'): - if webnotes.conn.get_value("Item", d.item_code, "is_stock_item") == "Yes": - if not d.warehouse: - msgprint("Please Enter Warehouse for Item %s as it is stock item" - % cstr(d.item_code), raise_exception=1) - - qty =flt(d.qty) - if is_stopped: - qty = (d.qty > d.ordered_qty) and flt(flt(d.qty) - flt(d.ordered_qty)) or 0 - - args = { - "item_code": d.item_code, - "indented_qty": (is_submit and 1 or -1) * flt(qty), - "posting_date": self.doc.transaction_date - } - get_obj('Warehouse', d.warehouse).update_bin(args) + for d in getlist(self.doclist, 'indent_details'): + if webnotes.conn.get_value("Item", d.item_code, "is_stock_item") == "Yes": + if not d.warehouse: + msgprint("Please Enter Warehouse for Item %s as it is stock item" + % cstr(d.item_code), raise_exception=1) + + qty =flt(d.qty) + if is_stopped: + qty = (d.qty > d.ordered_qty) and flt(flt(d.qty) - flt(d.ordered_qty)) or 0 + + args = { + "item_code": d.item_code, + "indented_qty": (is_submit and 1 or -1) * flt(qty), + "posting_date": self.doc.transaction_date + } + get_obj('Warehouse', d.warehouse).update_bin(args) def on_submit(self): purchase_controller = webnotes.get_obj("Purchase Common") @@ -196,7 +195,7 @@ class DocType(BuyingController): and material_request_item = %s and docstatus = 1""", (self.doc.name, d.name))[0][0]) webnotes.conn.set_value(d.doctype, d.name, "ordered_qty", d.ordered_qty) - + # note: if qty is 0, its row is still counted in len(item_doclist) # hence adding 1 to per_ordered if (d.ordered_qty > d.qty) or not d.qty: @@ -204,11 +203,9 @@ class DocType(BuyingController): elif d.qty > 0: per_ordered += flt(d.ordered_qty / flt(d.qty)) - if per_ordered: - self.doc.per_ordered = flt((per_ordered / flt(len(item_doclist))) * 100.0, 2) - webnotes.conn.set_value(self.doc.doctype, self.doc.name, "per_ordered", self.doc.per_ordered) - - + self.doc.per_ordered = flt((per_ordered / flt(len(item_doclist))) * 100.0, 2) + webnotes.conn.set_value(self.doc.doctype, self.doc.name, "per_ordered", self.doc.per_ordered) + def update_completed_qty(controller, caller_method): if controller.doc.doctype == "Stock Entry": material_request_map = {} @@ -218,7 +215,18 @@ def update_completed_qty(controller, caller_method): if d.material_request not in material_request_map: material_request_map[d.material_request] = [] material_request_map[d.material_request].append(d.material_request_item) - + webnotes.get_obj("Warehouse", d.t_warehouse).update_bin({ + "item_code": d.item_code, + "indented_qty": (d.docstatus==2 and 1 or -1) * d.transfer_qty, + "posting_date": controller.doc.posting_date, + }) + for mr_name, mr_items in material_request_map.items(): - webnotes.get_obj("Material Request", mr_name, with_children=1).update_completed_qty(mr_items) - \ No newline at end of file + mr_obj = webnotes.get_obj("Material Request", mr_name, with_children=1) + mr_doctype = webnotes.get_doctype("Material Request") + if mr_obj.doc.status in ["Stopped", "Cancelled"]: + msgprint(_("Material Request") + ": %s, " % mr_obj.doc.name + + _(mr_doctype.get_label("status")) + " = %s. " % _(mr_obj.doc.status) + + _("Cannot continue."), raise_exception=True) + + mr_obj.update_completed_qty(mr_items) \ No newline at end of file diff --git a/stock/doctype/material_request/test_material_request.py b/stock/doctype/material_request/test_material_request.py index 1fa1a9f458..3c2f421e95 100644 --- a/stock/doctype/material_request/test_material_request.py +++ b/stock/doctype/material_request/test_material_request.py @@ -10,7 +10,15 @@ class TestMaterialRequest(unittest.TestCase): for fieldname, val in expected.items(): self.assertEquals(val, doclist[i].fields.get(fieldname)) + def _test_requested_qty(self, qty1, qty2): + self.assertEqual(webnotes.conn.get_value("Bin", {"item_code": "_Test Item Home Desktop 100", + "warehouse": "_Test Warehouse"}, "indented_qty"), qty1) + self.assertEqual(webnotes.conn.get_value("Bin", {"item_code": "_Test Item Home Desktop 200", + "warehouse": "_Test Warehouse"}, "indented_qty"), qty2) + def test_completed_qty_for_purchase(self): + webnotes.conn.sql("""delete from `tabBin`""") + # submit material request of type Purchase mr = webnotes.bean(copy=test_records[0]) mr.insert() @@ -19,11 +27,12 @@ class TestMaterialRequest(unittest.TestCase): # check if per complete is None self._test_expected(mr.doclist, [{"per_ordered": None}, {"ordered_qty": None}, {"ordered_qty": None}]) + self._test_requested_qty(54.0, 3.0) + # map a purchase order - po = webnotes.map_doclist([["Material Request", "Purchase Order"], + po_doclist = webnotes.map_doclist([["Material Request", "Purchase Order"], ["Material Request Item", "Purchase Order Item"]], mr.doc.name) - po = webnotes.bean(po) - po.doc.fields.update({ + po_doclist[0].fields.update({ "supplier": "_Test Supplier", "supplier_name": "_Test Supplier", "transaction_date": mr.doc.transaction_date, @@ -32,21 +41,35 @@ class TestMaterialRequest(unittest.TestCase): "conversion_rate": 1.0, "grand_total_import": 0.0 }) - po.doclist[1].qty = 27.0 - po.doclist[2].qty = 1.5 + po_doclist[1].qty = 27.0 + po_doclist[2].qty = 1.5 + + # check for stopped status of Material Request + po = webnotes.bean(copy=po_doclist) + po.insert() + mr.obj.update_status('Stopped') + self.assertRaises(webnotes.ValidationError, po.submit) + self.assertRaises(webnotes.ValidationError, po.cancel) + + mr.obj.update_status('Submitted') + po = webnotes.bean(copy=po_doclist) po.insert() po.submit() # check if per complete is as expected mr.load_from_db() self._test_expected(mr.doclist, [{"per_ordered": 50}, {"ordered_qty": 27.0}, {"ordered_qty": 1.5}]) + self._test_requested_qty(27.0, 1.5) po.cancel() # check if per complete is as expected mr.load_from_db() self._test_expected(mr.doclist, [{"per_ordered": 0}, {"ordered_qty": 0}, {"ordered_qty": 0}]) + self._test_requested_qty(54.0, 3.0) def test_completed_qty_for_transfer(self): + webnotes.conn.sql("""delete from `tabBin`""") + # submit material request of type Purchase mr = webnotes.bean(copy=test_records[0]) mr.doc.material_request_type = "Transfer" @@ -56,33 +79,51 @@ class TestMaterialRequest(unittest.TestCase): # check if per complete is None self._test_expected(mr.doclist, [{"per_ordered": None}, {"ordered_qty": None}, {"ordered_qty": None}]) + self._test_requested_qty(54.0, 3.0) + # map a stock entry - se = webnotes.map_doclist([["Material Request", "Stock Entry"], + se_doclist = webnotes.map_doclist([["Material Request", "Stock Entry"], ["Material Request Item", "Stock Entry Detail"]], mr.doc.name) - se = webnotes.bean(se) - se.doc.fields.update({ + se_doclist[0].fields.update({ "posting_date": "2013-03-01", "posting_time": "00:00" }) - se.doclist[1].fields.update({ + se_doclist[1].fields.update({ "qty": 27.0, "transfer_qty": 27.0, "s_warehouse": "_Test Warehouse 1", "incoming_rate": 1.0 }) - se.doclist[2].fields.update({ + se_doclist[2].fields.update({ "qty": 1.5, "transfer_qty": 1.5, "s_warehouse": "_Test Warehouse 1", "incoming_rate": 1.0 }) + + # check for stopped status of Material Request + se = webnotes.bean(copy=se_doclist) + se.insert() + mr.obj.update_status('Stopped') + self.assertRaises(webnotes.ValidationError, se.submit) + self.assertRaises(webnotes.ValidationError, se.cancel) + + mr.obj.update_status('Submitted') + se = webnotes.bean(copy=se_doclist) se.insert() se.submit() # check if per complete is as expected mr.load_from_db() self._test_expected(mr.doclist, [{"per_ordered": 50}, {"ordered_qty": 27.0}, {"ordered_qty": 1.5}]) - + self._test_requested_qty(27.0, 1.5) + + # check if per complete is as expected for Stock Entry cancelled + se.cancel() + mr.load_from_db() + self._test_expected(mr.doclist, [{"per_ordered": 0}, {"ordered_qty": 0}, {"ordered_qty": 0}]) + self._test_requested_qty(54.0, 3.0) + test_records = [ [ { diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py index 342cd6b3ed..78d06ce910 100644 --- a/stock/doctype/stock_entry/stock_entry.py +++ b/stock/doctype/stock_entry/stock_entry.py @@ -63,7 +63,7 @@ class DocType(TransactionBase): self.update_stock_ledger(1) # update Production Order self.update_production_order(0) - + def validate_purpose(self): valid_purposes = ["Material Issue", "Material Receipt", "Material Transfer", "Manufacture/Repack", "Subcontract", "Sales Return", "Purchase Return"] diff --git a/stock/doctype/warehouse/warehouse.py b/stock/doctype/warehouse/warehouse.py index a7fc1853ce..dc8bfea0a9 100644 --- a/stock/doctype/warehouse/warehouse.py +++ b/stock/doctype/warehouse/warehouse.py @@ -207,3 +207,4 @@ class DocType: exists for this warehouse.""", raise_exception=1) else: sql("delete from `tabStock Ledger Entry` where warehouse = %s", self.doc.name) +