Merge branch 'master' of github.com:webnotes/erpnext into edge
This commit is contained in:
commit
c7cfe61229
@ -117,8 +117,7 @@ data_map = {
|
|||||||
"(ifnull(qty, 0) - ifnull(ordered_qty, 0)) as qty"],
|
"(ifnull(qty, 0) - ifnull(ordered_qty, 0)) as qty"],
|
||||||
"from": "`tabMaterial Request Item` item, `tabMaterial Request` main",
|
"from": "`tabMaterial Request Item` item, `tabMaterial Request` main",
|
||||||
"conditions": ["item.parent = main.name", "main.docstatus=1", "main.status != 'Stopped'",
|
"conditions": ["item.parent = main.name", "main.docstatus=1", "main.status != 'Stopped'",
|
||||||
"material_request_type = 'Purchase'", "ifnull(warehouse, '')!=''",
|
"ifnull(warehouse, '')!=''", "ifnull(qty, 0) > ifnull(ordered_qty, 0)"],
|
||||||
"ifnull(qty, 0) > ifnull(ordered_qty, 0)"],
|
|
||||||
"links": {
|
"links": {
|
||||||
"item_code": ["Item", "name"],
|
"item_code": ["Item", "name"],
|
||||||
"warehouse": ["Warehouse", "name"]
|
"warehouse": ["Warehouse", "name"]
|
||||||
|
@ -122,7 +122,8 @@ class DocType:
|
|||||||
self.create_material_request(doc_type, doc_name, reorder_level, reorder_qty,
|
self.create_material_request(doc_type, doc_name, reorder_level, reorder_qty,
|
||||||
material_request_type)
|
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 """
|
""" Create indent on reaching reorder level """
|
||||||
defaults = webnotes.defaults.get_defaults()
|
defaults = webnotes.defaults.get_defaults()
|
||||||
item = webnotes.doc("Item", self.doc.item_code)
|
item = webnotes.doc("Item", self.doc.item_code)
|
||||||
@ -176,3 +177,4 @@ class DocType:
|
|||||||
get_url_to_form(bean.doc.doctype, bean.doc.name))
|
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)
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import webnotes
|
|||||||
from webnotes.utils import cstr, flt
|
from webnotes.utils import cstr, flt
|
||||||
from webnotes.model.bean import getlist
|
from webnotes.model.bean import getlist
|
||||||
from webnotes.model.code import get_obj
|
from webnotes.model.code import get_obj
|
||||||
from webnotes import msgprint
|
from webnotes import msgprint, _
|
||||||
|
|
||||||
from controllers.buying_controller import BuyingController
|
from controllers.buying_controller import BuyingController
|
||||||
class DocType(BuyingController):
|
class DocType(BuyingController):
|
||||||
@ -119,7 +119,6 @@ class DocType(BuyingController):
|
|||||||
|
|
||||||
def update_bin(self, is_submit, is_stopped):
|
def update_bin(self, is_submit, is_stopped):
|
||||||
""" Update Quantity Requested for Purchase in Bin for Material Request of type 'Purchase'"""
|
""" 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'):
|
for d in getlist(self.doclist, 'indent_details'):
|
||||||
if webnotes.conn.get_value("Item", d.item_code, "is_stock_item") == "Yes":
|
if webnotes.conn.get_value("Item", d.item_code, "is_stock_item") == "Yes":
|
||||||
if not d.warehouse:
|
if not d.warehouse:
|
||||||
@ -204,11 +203,9 @@ class DocType(BuyingController):
|
|||||||
elif d.qty > 0:
|
elif d.qty > 0:
|
||||||
per_ordered += flt(d.ordered_qty / flt(d.qty))
|
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)
|
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)
|
webnotes.conn.set_value(self.doc.doctype, self.doc.name, "per_ordered", self.doc.per_ordered)
|
||||||
|
|
||||||
|
|
||||||
def update_completed_qty(controller, caller_method):
|
def update_completed_qty(controller, caller_method):
|
||||||
if controller.doc.doctype == "Stock Entry":
|
if controller.doc.doctype == "Stock Entry":
|
||||||
material_request_map = {}
|
material_request_map = {}
|
||||||
@ -218,7 +215,18 @@ def update_completed_qty(controller, caller_method):
|
|||||||
if d.material_request not in material_request_map:
|
if d.material_request not in material_request_map:
|
||||||
material_request_map[d.material_request] = []
|
material_request_map[d.material_request] = []
|
||||||
material_request_map[d.material_request].append(d.material_request_item)
|
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():
|
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)
|
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)
|
@ -10,7 +10,15 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
for fieldname, val in expected.items():
|
for fieldname, val in expected.items():
|
||||||
self.assertEquals(val, doclist[i].fields.get(fieldname))
|
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):
|
def test_completed_qty_for_purchase(self):
|
||||||
|
webnotes.conn.sql("""delete from `tabBin`""")
|
||||||
|
|
||||||
# submit material request of type Purchase
|
# submit material request of type Purchase
|
||||||
mr = webnotes.bean(copy=test_records[0])
|
mr = webnotes.bean(copy=test_records[0])
|
||||||
mr.insert()
|
mr.insert()
|
||||||
@ -19,11 +27,12 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
# check if per complete is None
|
# check if per complete is None
|
||||||
self._test_expected(mr.doclist, [{"per_ordered": None}, {"ordered_qty": None}, {"ordered_qty": 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
|
# 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)
|
["Material Request Item", "Purchase Order Item"]], mr.doc.name)
|
||||||
po = webnotes.bean(po)
|
po_doclist[0].fields.update({
|
||||||
po.doc.fields.update({
|
|
||||||
"supplier": "_Test Supplier",
|
"supplier": "_Test Supplier",
|
||||||
"supplier_name": "_Test Supplier",
|
"supplier_name": "_Test Supplier",
|
||||||
"transaction_date": mr.doc.transaction_date,
|
"transaction_date": mr.doc.transaction_date,
|
||||||
@ -32,21 +41,35 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
"conversion_rate": 1.0,
|
"conversion_rate": 1.0,
|
||||||
"grand_total_import": 0.0
|
"grand_total_import": 0.0
|
||||||
})
|
})
|
||||||
po.doclist[1].qty = 27.0
|
po_doclist[1].qty = 27.0
|
||||||
po.doclist[2].qty = 1.5
|
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.insert()
|
||||||
po.submit()
|
po.submit()
|
||||||
|
|
||||||
# check if per complete is as expected
|
# check if per complete is as expected
|
||||||
mr.load_from_db()
|
mr.load_from_db()
|
||||||
self._test_expected(mr.doclist, [{"per_ordered": 50}, {"ordered_qty": 27.0}, {"ordered_qty": 1.5}])
|
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()
|
po.cancel()
|
||||||
# check if per complete is as expected
|
# check if per complete is as expected
|
||||||
mr.load_from_db()
|
mr.load_from_db()
|
||||||
self._test_expected(mr.doclist, [{"per_ordered": 0}, {"ordered_qty": 0}, {"ordered_qty": 0}])
|
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):
|
def test_completed_qty_for_transfer(self):
|
||||||
|
webnotes.conn.sql("""delete from `tabBin`""")
|
||||||
|
|
||||||
# submit material request of type Purchase
|
# submit material request of type Purchase
|
||||||
mr = webnotes.bean(copy=test_records[0])
|
mr = webnotes.bean(copy=test_records[0])
|
||||||
mr.doc.material_request_type = "Transfer"
|
mr.doc.material_request_type = "Transfer"
|
||||||
@ -56,32 +79,50 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
# check if per complete is None
|
# check if per complete is None
|
||||||
self._test_expected(mr.doclist, [{"per_ordered": None}, {"ordered_qty": None}, {"ordered_qty": 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
|
# 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)
|
["Material Request Item", "Stock Entry Detail"]], mr.doc.name)
|
||||||
se = webnotes.bean(se)
|
se_doclist[0].fields.update({
|
||||||
se.doc.fields.update({
|
|
||||||
"posting_date": "2013-03-01",
|
"posting_date": "2013-03-01",
|
||||||
"posting_time": "00:00"
|
"posting_time": "00:00"
|
||||||
})
|
})
|
||||||
se.doclist[1].fields.update({
|
se_doclist[1].fields.update({
|
||||||
"qty": 27.0,
|
"qty": 27.0,
|
||||||
"transfer_qty": 27.0,
|
"transfer_qty": 27.0,
|
||||||
"s_warehouse": "_Test Warehouse 1",
|
"s_warehouse": "_Test Warehouse 1",
|
||||||
"incoming_rate": 1.0
|
"incoming_rate": 1.0
|
||||||
})
|
})
|
||||||
se.doclist[2].fields.update({
|
se_doclist[2].fields.update({
|
||||||
"qty": 1.5,
|
"qty": 1.5,
|
||||||
"transfer_qty": 1.5,
|
"transfer_qty": 1.5,
|
||||||
"s_warehouse": "_Test Warehouse 1",
|
"s_warehouse": "_Test Warehouse 1",
|
||||||
"incoming_rate": 1.0
|
"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.insert()
|
||||||
se.submit()
|
se.submit()
|
||||||
|
|
||||||
# check if per complete is as expected
|
# check if per complete is as expected
|
||||||
mr.load_from_db()
|
mr.load_from_db()
|
||||||
self._test_expected(mr.doclist, [{"per_ordered": 50}, {"ordered_qty": 27.0}, {"ordered_qty": 1.5}])
|
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 = [
|
test_records = [
|
||||||
[
|
[
|
||||||
|
@ -207,3 +207,4 @@ class DocType:
|
|||||||
exists for this warehouse.""", raise_exception=1)
|
exists for this warehouse.""", raise_exception=1)
|
||||||
else:
|
else:
|
||||||
sql("delete from `tabStock Ledger Entry` where warehouse = %s", self.doc.name)
|
sql("delete from `tabStock Ledger Entry` where warehouse = %s", self.doc.name)
|
||||||
|
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
{% include 'html/product_missing_image.html' %}
|
{% include 'html/product_missing_image.html' %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<h4><a href="{{ page_name }}">{{ item_name }}</a></h4>
|
<div style="height: 80px; overflow: hidden; font-size: 80%;">
|
||||||
|
<h4 style="margin-bottom: 2px;"><a href="{{ page_name }}">{{ item_name }}</a></h4>
|
||||||
<p class="help">Item Code: {{ name }}</p>
|
<p class="help">Item Code: {{ name }}</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
Loading…
x
Reference in New Issue
Block a user