testcase fixes #478

This commit is contained in:
Nabin Hait 2014-04-07 16:00:28 +05:30
parent dc82d4f0cd
commit 088dec6c09
4 changed files with 162 additions and 162 deletions

View File

@ -77,13 +77,13 @@ def _make_customer(source_name, target_doc=None, ignore_permissions=False):
def set_missing_values(source, target): def set_missing_values(source, target):
if source.company_name: if source.company_name:
target[0].customer_type = "Company" target.customer_type = "Company"
target[0].customer_name = source.company_name target.customer_name = source.company_name
else: else:
target[0].customer_type = "Individual" target.customer_type = "Individual"
target[0].customer_name = source.lead_name target.customer_name = source.lead_name
target[0].customer_group = frappe.db.get_default("customer_group") target.customer_group = frappe.db.get_default("customer_group")
doclist = get_mapped_doc("Lead", source_name, doclist = get_mapped_doc("Lead", source_name,
{"Lead": { {"Lead": {

View File

@ -105,8 +105,8 @@ def _make_sales_order(source_name, target_doc=None, ignore_permissions=False):
def set_missing_values(source, target): def set_missing_values(source, target):
if customer: if customer:
target[0].customer = customer.name target.customer = customer.name
target[0].customer_name = customer.customer_name target.customer_name = customer.customer_name
si = frappe.get_doc(target) si = frappe.get_doc(target)
si.ignore_permissions = ignore_permissions si.ignore_permissions = ignore_permissions

View File

@ -29,84 +29,84 @@ class MaterialRequest(BuyingController):
so_items[d.sales_order_no][d.item_code] = flt(d.qty) so_items[d.sales_order_no][d.item_code] = flt(d.qty)
else: else:
so_items[d.sales_order_no][d.item_code] += flt(d.qty) so_items[d.sales_order_no][d.item_code] += flt(d.qty)
for so_no in so_items.keys(): for so_no in so_items.keys():
for item in so_items[so_no].keys(): for item in so_items[so_no].keys():
already_indented = frappe.db.sql("""select sum(ifnull(qty, 0)) already_indented = frappe.db.sql("""select sum(ifnull(qty, 0))
from `tabMaterial Request Item` from `tabMaterial Request Item`
where item_code = %s and sales_order_no = %s and where item_code = %s and sales_order_no = %s and
docstatus = 1 and parent != %s""", (item, so_no, self.name)) docstatus = 1 and parent != %s""", (item, so_no, self.name))
already_indented = already_indented and flt(already_indented[0][0]) or 0 already_indented = already_indented and flt(already_indented[0][0]) or 0
actual_so_qty = frappe.db.sql("""select sum(ifnull(qty, 0)) from `tabSales Order Item` actual_so_qty = frappe.db.sql("""select sum(ifnull(qty, 0)) from `tabSales Order Item`
where parent = %s and item_code = %s and docstatus = 1""", (so_no, item)) where parent = %s and item_code = %s and docstatus = 1""", (so_no, item))
actual_so_qty = actual_so_qty and flt(actual_so_qty[0][0]) or 0 actual_so_qty = actual_so_qty and flt(actual_so_qty[0][0]) or 0
if actual_so_qty and (flt(so_items[so_no][item]) + already_indented > actual_so_qty): if actual_so_qty and (flt(so_items[so_no][item]) + already_indented > actual_so_qty):
frappe.throw("You can raise indent of maximum qty: %s for item: %s against sales order: %s\ frappe.throw("You can raise indent of maximum qty: %s for item: %s against sales order: %s\
\n Anyway, you can add more qty in new row for the same item." \n Anyway, you can add more qty in new row for the same item."
% (actual_so_qty - already_indented, item, so_no)) % (actual_so_qty - already_indented, item, so_no))
def validate_schedule_date(self): def validate_schedule_date(self):
for d in self.get('indent_details'): for d in self.get('indent_details'):
if d.schedule_date < self.transaction_date: if d.schedule_date < self.transaction_date:
frappe.throw(_("Expected Date cannot be before Material Request Date")) frappe.throw(_("Expected Date cannot be before Material Request Date"))
# Validate # Validate
# --------------------- # ---------------------
def validate(self): def validate(self):
super(MaterialRequest, self).validate() super(MaterialRequest, self).validate()
self.validate_schedule_date() self.validate_schedule_date()
self.validate_uom_is_integer("uom", "qty") self.validate_uom_is_integer("uom", "qty")
if not self.status: if not self.status:
self.status = "Draft" self.status = "Draft"
from erpnext.utilities import validate_status from erpnext.utilities import validate_status
validate_status(self.status, ["Draft", "Submitted", "Stopped", "Cancelled"]) 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"])
pc_obj = frappe.get_doc('Purchase Common') pc_obj = frappe.get_doc('Purchase Common')
pc_obj.validate_for_items(self) pc_obj.validate_for_items(self)
# self.validate_qty_against_so() # self.validate_qty_against_so()
# NOTE: Since Item BOM and FG quantities are combined, using current data, it cannot be validated # NOTE: Since Item BOM and FG quantities are combined, using current data, it cannot be validated
# Though the creation of Material Request from a Production Plan can be rethought to fix this # Though the creation of Material Request from a Production Plan can be rethought to fix this
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'"""
from erpnext.stock.utils import update_bin from erpnext.stock.utils import update_bin
for d in self.get('indent_details'): for d in self.get('indent_details'):
if frappe.db.get_value("Item", d.item_code, "is_stock_item") == "Yes": if frappe.db.get_value("Item", d.item_code, "is_stock_item") == "Yes":
if not d.warehouse: if not d.warehouse:
frappe.throw("Please Enter Warehouse for Item %s as it is stock item" frappe.throw("Please Enter Warehouse for Item %s as it is stock item"
% cstr(d.item_code)) % cstr(d.item_code))
qty =flt(d.qty) qty =flt(d.qty)
if is_stopped: if is_stopped:
qty = (d.qty > d.ordered_qty) and flt(flt(d.qty) - flt(d.ordered_qty)) or 0 qty = (d.qty > d.ordered_qty) and flt(flt(d.qty) - flt(d.ordered_qty)) or 0
args = { args = {
"item_code": d.item_code, "item_code": d.item_code,
"warehouse": d.warehouse, "warehouse": d.warehouse,
"indented_qty": (is_submit and 1 or -1) * flt(qty), "indented_qty": (is_submit and 1 or -1) * flt(qty),
"posting_date": self.transaction_date "posting_date": self.transaction_date
} }
update_bin(args) update_bin(args)
def on_submit(self): def on_submit(self):
frappe.db.set(self, 'status', 'Submitted') frappe.db.set(self, 'status', 'Submitted')
self.update_bin(is_submit = 1, is_stopped = 0) self.update_bin(is_submit = 1, is_stopped = 0)
def check_modified_date(self): def check_modified_date(self):
mod_db = frappe.db.sql("""select modified from `tabMaterial Request` where name = %s""", mod_db = frappe.db.sql("""select modified from `tabMaterial Request` where name = %s""",
self.name) self.name)
date_diff = frappe.db.sql("""select TIMEDIFF('%s', '%s')""" date_diff = frappe.db.sql("""select TIMEDIFF('%s', '%s')"""
% (mod_db[0][0], cstr(self.modified))) % (mod_db[0][0], cstr(self.modified)))
if date_diff and date_diff[0][0]: if date_diff and date_diff[0][0]:
frappe.throw(cstr(self.doctype) + " => " + cstr(self.name) + " has been modified. Please Refresh.") frappe.throw(cstr(self.doctype) + " => " + cstr(self.name) + " has been modified. Please Refresh.")
@ -115,93 +115,93 @@ class MaterialRequest(BuyingController):
# Step 1:=> Update Bin # Step 1:=> Update Bin
self.update_bin(is_submit = (status == 'Submitted') and 1 or 0, is_stopped = 1) self.update_bin(is_submit = (status == 'Submitted') and 1 or 0, is_stopped = 1)
# Step 2:=> Set status # Step 2:=> Set status
frappe.db.set(self, 'status', cstr(status)) frappe.db.set(self, 'status', cstr(status))
# Step 3:=> Acknowledge User # Step 3:=> Acknowledge User
msgprint(self.doctype + ": " + self.name + " has been %s." % ((status == 'Submitted') and 'Unstopped' or cstr(status))) msgprint(self.doctype + ": " + self.name + " has been %s." % ((status == 'Submitted') and 'Unstopped' or cstr(status)))
def on_cancel(self): def on_cancel(self):
# Step 1:=> Get Purchase Common Obj # Step 1:=> Get Purchase Common Obj
pc_obj = frappe.get_doc('Purchase Common') pc_obj = frappe.get_doc('Purchase Common')
# Step 2:=> Check for stopped status # Step 2:=> Check for stopped status
pc_obj.check_for_stopped_status(self.doctype, self.name) pc_obj.check_for_stopped_status(self.doctype, self.name)
# Step 3:=> Check if Purchase Order has been submitted against current Material Request # Step 3:=> Check if Purchase Order has been submitted against current Material Request
pc_obj.check_docstatus(check = 'Next', doctype = 'Purchase Order', docname = self.name, detail_doctype = 'Purchase Order Item') pc_obj.check_docstatus(check = 'Next', doctype = 'Purchase Order', docname = self.name, detail_doctype = 'Purchase Order Item')
# Step 4:=> Update Bin # Step 4:=> Update Bin
self.update_bin(is_submit = 0, is_stopped = (cstr(self.status) == 'Stopped') and 1 or 0) self.update_bin(is_submit = 0, is_stopped = (cstr(self.status) == 'Stopped') and 1 or 0)
# Step 5:=> Set Status # Step 5:=> Set Status
frappe.db.set(self,'status','Cancelled') frappe.db.set(self,'status','Cancelled')
def update_completed_qty(self, mr_items=None): def update_completed_qty(self, mr_items=None):
if self.material_request_type != "Transfer": if self.material_request_type != "Transfer":
return return
item_doclist = self.get("indent_details") item_doclist = self.get("indent_details")
if not mr_items: if not mr_items:
mr_items = [d.name for d in item_doclist] mr_items = [d.name for d in item_doclist]
per_ordered = 0.0 per_ordered = 0.0
for d in item_doclist: for d in item_doclist:
if d.name in mr_items: if d.name in mr_items:
d.ordered_qty = flt(frappe.db.sql("""select sum(transfer_qty) d.ordered_qty = flt(frappe.db.sql("""select sum(transfer_qty)
from `tabStock Entry Detail` where material_request = %s from `tabStock Entry Detail` where material_request = %s
and material_request_item = %s and docstatus = 1""", and material_request_item = %s and docstatus = 1""",
(self.name, d.name))[0][0]) (self.name, d.name))[0][0])
frappe.db.set_value(d.doctype, d.name, "ordered_qty", d.ordered_qty) frappe.db.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) # note: if qty is 0, its row is still counted in len(item_doclist)
# hence adding 1 to per_ordered # hence adding 1 to per_ordered
if (d.ordered_qty > d.qty) or not d.qty: if (d.ordered_qty > d.qty) or not d.qty:
per_ordered += 1.0 per_ordered += 1.0
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))
self.per_ordered = flt((per_ordered / flt(len(item_doclist))) * 100.0, 2) self.per_ordered = flt((per_ordered / flt(len(item_doclist))) * 100.0, 2)
frappe.db.set_value(self.doctype, self.name, "per_ordered", self.per_ordered) frappe.db.set_value(self.doctype, self.name, "per_ordered", self.per_ordered)
def update_completed_qty(doc, method): def update_completed_qty(doc, method):
if doc.doctype == "Stock Entry": if doc.doctype == "Stock Entry":
material_request_map = {} material_request_map = {}
for d in doc.get("mtn_details"): for d in doc.get("mtn_details"):
if d.material_request: if d.material_request:
material_request_map.setdefault(d.material_request, []).append(d.material_request_item) material_request_map.setdefault(d.material_request, []).append(d.material_request_item)
for mr_name, mr_items in material_request_map.items(): for mr_name, mr_items in material_request_map.items():
mr_obj = frappe.get_doc("Material Request", mr_name) mr_obj = frappe.get_doc("Material Request", mr_name)
mr_doctype = frappe.get_meta("Material Request") mr_doctype = frappe.get_meta("Material Request")
if mr_obj.status in ["Stopped", "Cancelled"]: if mr_obj.status in ["Stopped", "Cancelled"]:
frappe.throw(_("Material Request") + ": %s, " % mr_obj.name frappe.throw(_("Material Request") + ": %s, " % mr_obj.name
+ _(mr_doctype.get_label("status")) + " = %s. " % _(mr_obj.status) + _(mr_doctype.get_label("status")) + " = %s. " % _(mr_obj.status)
+ _("Cannot continue."), exc=frappe.InvalidStatusError) + _("Cannot continue."), exc=frappe.InvalidStatusError)
_update_requested_qty(doc, mr_obj, mr_items) _update_requested_qty(doc, mr_obj, mr_items)
# update ordered percentage and qty # update ordered percentage and qty
mr_obj.update_completed_qty(mr_items) mr_obj.update_completed_qty(mr_items)
def _update_requested_qty(doc, mr_obj, mr_items): def _update_requested_qty(doc, mr_obj, mr_items):
"""update requested qty (before ordered_qty is updated)""" """update requested qty (before ordered_qty is updated)"""
from erpnext.stock.utils import update_bin from erpnext.stock.utils import update_bin
for mr_item_name in mr_items: for mr_item_name in mr_items:
mr_item = mr_obj.get("indent_details", {"name": mr_item_name}) mr_item = mr_obj.get("indent_details", {"name": mr_item_name})
se_detail = doc.get("mtn_details", {"material_request": mr_obj.name, se_detail = doc.get("mtn_details", {"material_request": mr_obj.name,
"material_request_item": mr_item_name}) "material_request_item": mr_item_name})
if mr_item and se_detail: if mr_item and se_detail:
mr_item = mr_item[0] mr_item = mr_item[0]
se_detail = se_detail[0] se_detail = se_detail[0]
mr_item.ordered_qty = flt(mr_item.ordered_qty) mr_item.ordered_qty = flt(mr_item.ordered_qty)
mr_item.qty = flt(mr_item.qty) mr_item.qty = flt(mr_item.qty)
se_detail.transfer_qty = flt(se_detail.transfer_qty) se_detail.transfer_qty = flt(se_detail.transfer_qty)
if se_detail.docstatus == 2 and mr_item.ordered_qty > mr_item.qty \ if se_detail.docstatus == 2 and mr_item.ordered_qty > mr_item.qty \
and se_detail.transfer_qty == mr_item.ordered_qty: and se_detail.transfer_qty == mr_item.ordered_qty:
add_indented_qty = mr_item.qty add_indented_qty = mr_item.qty
@ -210,7 +210,7 @@ def _update_requested_qty(doc, mr_obj, mr_items):
add_indented_qty = mr_item.qty - mr_item.ordered_qty add_indented_qty = mr_item.qty - mr_item.ordered_qty
else: else:
add_indented_qty = se_detail.transfer_qty add_indented_qty = se_detail.transfer_qty
update_bin({ update_bin({
"item_code": se_detail.item_code, "item_code": se_detail.item_code,
"warehouse": se_detail.t_warehouse, "warehouse": se_detail.t_warehouse,
@ -221,7 +221,7 @@ def _update_requested_qty(doc, mr_obj, mr_items):
def set_missing_values(source, target_doc): def set_missing_values(source, target_doc):
po = frappe.get_doc(target_doc) po = frappe.get_doc(target_doc)
po.run_method("set_missing_values") po.run_method("set_missing_values")
def update_item(obj, target, source_parent): def update_item(obj, target, source_parent):
target.conversion_factor = 1 target.conversion_factor = 1
target.qty = flt(obj.qty) - flt(obj.ordered_qty) target.qty = flt(obj.qty) - flt(obj.ordered_qty)
@ -232,18 +232,18 @@ def make_purchase_order(source_name, target_doc=None):
doclist = get_mapped_doc("Material Request", source_name, { doclist = get_mapped_doc("Material Request", source_name, {
"Material Request": { "Material Request": {
"doctype": "Purchase Order", "doctype": "Purchase Order",
"validation": { "validation": {
"docstatus": ["=", 1], "docstatus": ["=", 1],
"material_request_type": ["=", "Purchase"] "material_request_type": ["=", "Purchase"]
} }
}, },
"Material Request Item": { "Material Request Item": {
"doctype": "Purchase Order Item", "doctype": "Purchase Order Item",
"field_map": [ "field_map": [
["name", "prevdoc_detail_docname"], ["name", "prevdoc_detail_docname"],
["parent", "prevdoc_docname"], ["parent", "prevdoc_docname"],
["parenttype", "prevdoc_doctype"], ["parenttype", "prevdoc_doctype"],
["uom", "stock_uom"], ["uom", "stock_uom"],
["uom", "uom"] ["uom", "uom"]
], ],
@ -252,7 +252,7 @@ def make_purchase_order(source_name, target_doc=None):
}, target_doc, set_missing_values) }, target_doc, set_missing_values)
return doclist.as_dict() return doclist.as_dict()
@frappe.whitelist() @frappe.whitelist()
def make_purchase_order_based_on_supplier(source_name, target_doc=None): def make_purchase_order_based_on_supplier(source_name, target_doc=None):
from frappe.model.mapper import get_mapped_doc from frappe.model.mapper import get_mapped_doc
@ -261,44 +261,44 @@ def make_purchase_order_based_on_supplier(source_name, target_doc=None):
import json import json
target_doc = frappe.get_doc(json.loads(target_doc)) target_doc = frappe.get_doc(json.loads(target_doc))
target_doc = target_doc.get({"parentfield": ["!=", "po_details"]}) target_doc = target_doc.get({"parentfield": ["!=", "po_details"]})
material_requests, supplier_items = get_material_requests_based_on_supplier(source_name) material_requests, supplier_items = get_material_requests_based_on_supplier(source_name)
def postprocess(source, target_doc): def postprocess(source, target_doc):
target_doc[0].supplier = source_name target_doc[0].supplier = source_name
set_missing_values(source, target_doc) set_missing_values(source, target_doc)
po_items = target_doc.get({"parentfield": "po_details"}) po_items = target_doc.get({"parentfield": "po_details"})
target_doc = target_doc.get({"parentfield": ["!=", "po_details"]}) + \ target_doc = target_doc.get({"parentfield": ["!=", "po_details"]}) + \
[d for d in po_items [d for d in po_items
if d.get("item_code") in supplier_items and d.get("qty") > 0] if d.get("item_code") in supplier_items and d.get("qty") > 0]
return target_doc return target_doc
for mr in material_requests: for mr in material_requests:
target_doc = get_mapped_doc("Material Request", mr, { target_doc = get_mapped_doc("Material Request", mr, {
"Material Request": { "Material Request": {
"doctype": "Purchase Order", "doctype": "Purchase Order",
}, },
"Material Request Item": { "Material Request Item": {
"doctype": "Purchase Order Item", "doctype": "Purchase Order Item",
"field_map": [ "field_map": [
["name", "prevdoc_detail_docname"], ["name", "prevdoc_detail_docname"],
["parent", "prevdoc_docname"], ["parent", "prevdoc_docname"],
["parenttype", "prevdoc_doctype"], ["parenttype", "prevdoc_doctype"],
["uom", "stock_uom"], ["uom", "stock_uom"],
["uom", "uom"] ["uom", "uom"]
], ],
"postprocess": update_item "postprocess": update_item
} }
}, target_doc, postprocess) }, target_doc, postprocess)
return target_doc.as_dict() return target_doc.as_dict()
def get_material_requests_based_on_supplier(supplier): def get_material_requests_based_on_supplier(supplier):
supplier_items = [d[0] for d in frappe.db.get_values("Item", supplier_items = [d[0] for d in frappe.db.get_values("Item",
{"default_supplier": supplier})] {"default_supplier": supplier})]
material_requests = frappe.db.sql_list("""select distinct mr.name material_requests = frappe.db.sql_list("""select distinct mr.name
from `tabMaterial Request` mr, `tabMaterial Request Item` mr_item from `tabMaterial Request` mr, `tabMaterial Request Item` mr_item
where mr.name = mr_item.parent where mr.name = mr_item.parent
and mr_item.item_code in (%s) and mr_item.item_code in (%s)
@ -308,59 +308,59 @@ def get_material_requests_based_on_supplier(supplier):
and mr.status != 'Stopped'""" % ', '.join(['%s']*len(supplier_items)), and mr.status != 'Stopped'""" % ', '.join(['%s']*len(supplier_items)),
tuple(supplier_items)) tuple(supplier_items))
return material_requests, supplier_items return material_requests, supplier_items
@frappe.whitelist() @frappe.whitelist()
def make_supplier_quotation(source_name, target_doc=None): def make_supplier_quotation(source_name, target_doc=None):
from frappe.model.mapper import get_mapped_doc from frappe.model.mapper import get_mapped_doc
doclist = get_mapped_doc("Material Request", source_name, { doclist = get_mapped_doc("Material Request", source_name, {
"Material Request": { "Material Request": {
"doctype": "Supplier Quotation", "doctype": "Supplier Quotation",
"validation": { "validation": {
"docstatus": ["=", 1], "docstatus": ["=", 1],
"material_request_type": ["=", "Purchase"] "material_request_type": ["=", "Purchase"]
} }
}, },
"Material Request Item": { "Material Request Item": {
"doctype": "Supplier Quotation Item", "doctype": "Supplier Quotation Item",
"field_map": { "field_map": {
"name": "prevdoc_detail_docname", "name": "prevdoc_detail_docname",
"parent": "prevdoc_docname", "parent": "prevdoc_docname",
"parenttype": "prevdoc_doctype" "parenttype": "prevdoc_doctype"
} }
} }
}, target_doc, set_missing_values) }, target_doc, set_missing_values)
return doclist.as_dict() return doclist.as_dict()
@frappe.whitelist() @frappe.whitelist()
def make_stock_entry(source_name, target_doc=None): def make_stock_entry(source_name, target_doc=None):
from frappe.model.mapper import get_mapped_doc from frappe.model.mapper import get_mapped_doc
def update_item(obj, target, source_parent): def update_item(obj, target, source_parent):
target.conversion_factor = 1 target.conversion_factor = 1
target.qty = flt(obj.qty) - flt(obj.ordered_qty) target.qty = flt(obj.qty) - flt(obj.ordered_qty)
target.transfer_qty = flt(obj.qty) - flt(obj.ordered_qty) target.transfer_qty = flt(obj.qty) - flt(obj.ordered_qty)
def set_missing_values(source, target): def set_missing_values(source, target):
target[0].purpose = "Material Transfer" target.purpose = "Material Transfer"
se = frappe.get_doc(target) se = frappe.get_doc(target)
se.run_method("get_stock_and_rate") se.run_method("get_stock_and_rate")
doclist = get_mapped_doc("Material Request", source_name, { doclist = get_mapped_doc("Material Request", source_name, {
"Material Request": { "Material Request": {
"doctype": "Stock Entry", "doctype": "Stock Entry",
"validation": { "validation": {
"docstatus": ["=", 1], "docstatus": ["=", 1],
"material_request_type": ["=", "Transfer"] "material_request_type": ["=", "Transfer"]
} }
}, },
"Material Request Item": { "Material Request Item": {
"doctype": "Stock Entry Detail", "doctype": "Stock Entry Detail",
"field_map": { "field_map": {
"name": "material_request_item", "name": "material_request_item",
"parent": "material_request", "parent": "material_request",
"uom": "stock_uom", "uom": "stock_uom",
"warehouse": "t_warehouse" "warehouse": "t_warehouse"
}, },
"postprocess": update_item "postprocess": update_item

View File

@ -17,89 +17,89 @@ class TestMaterialRequest(unittest.TestCase):
mr = frappe.copy_doc(test_records[0]).insert() mr = frappe.copy_doc(test_records[0]).insert()
self.assertRaises(frappe.ValidationError, make_purchase_order, self.assertRaises(frappe.ValidationError, make_purchase_order,
mr.name) mr.name)
mr = frappe.get_doc("Material Request", mr.name) mr = frappe.get_doc("Material Request", mr.name)
mr.submit() mr.submit()
po = make_purchase_order(mr.name) po = make_purchase_order(mr.name)
self.assertEquals(po[0]["doctype"], "Purchase Order") self.assertEquals(po[0]["doctype"], "Purchase Order")
self.assertEquals(len(po), len(mr)) self.assertEquals(len(po), len(mr))
def test_make_supplier_quotation(self): def test_make_supplier_quotation(self):
from erpnext.stock.doctype.material_request.material_request import make_supplier_quotation from erpnext.stock.doctype.material_request.material_request import make_supplier_quotation
mr = frappe.copy_doc(test_records[0]).insert() mr = frappe.copy_doc(test_records[0]).insert()
self.assertRaises(frappe.ValidationError, make_supplier_quotation, self.assertRaises(frappe.ValidationError, make_supplier_quotation,
mr.name) mr.name)
mr = frappe.get_doc("Material Request", mr.name) mr = frappe.get_doc("Material Request", mr.name)
mr.submit() mr.submit()
sq = make_supplier_quotation(mr.name) sq = make_supplier_quotation(mr.name)
self.assertEquals(sq[0]["doctype"], "Supplier Quotation") self.assertEquals(sq[0]["doctype"], "Supplier Quotation")
self.assertEquals(len(sq), len(mr)) self.assertEquals(len(sq), len(mr))
def test_make_stock_entry(self): def test_make_stock_entry(self):
from erpnext.stock.doctype.material_request.material_request import make_stock_entry from erpnext.stock.doctype.material_request.material_request import make_stock_entry
mr = frappe.copy_doc(test_records[0]).insert() mr = frappe.copy_doc(test_records[0]).insert()
self.assertRaises(frappe.ValidationError, make_stock_entry, self.assertRaises(frappe.ValidationError, make_stock_entry,
mr.name) mr.name)
mr = frappe.get_doc("Material Request", mr.name) mr = frappe.get_doc("Material Request", mr.name)
mr.material_request_type = "Transfer" mr.material_request_type = "Transfer"
mr.submit() mr.submit()
se = make_stock_entry(mr.name) se = make_stock_entry(mr.name)
self.assertEquals(se[0]["doctype"], "Stock Entry") self.assertEquals(se[0]["doctype"], "Stock Entry")
self.assertEquals(len(se), len(mr)) self.assertEquals(len(se), len(mr))
def _test_expected(self, doc, expected_values): def _test_expected(self, doc, expected_values):
for i, expected in enumerate(expected_values): for i, expected in enumerate(expected_values):
for fieldname, val in expected.items(): for fieldname, val in expected.items():
self.assertEquals(val, doc[i].get(fieldname)) self.assertEquals(val, doc.get(fieldname))
def _test_requested_qty(self, qty1, qty2): def _test_requested_qty(self, qty1, qty2):
self.assertEqual(flt(frappe.db.get_value("Bin", {"item_code": "_Test Item Home Desktop 100", self.assertEqual(flt(frappe.db.get_value("Bin", {"item_code": "_Test Item Home Desktop 100",
"warehouse": "_Test Warehouse - _TC"}, "indented_qty")), qty1) "warehouse": "_Test Warehouse - _TC"}, "indented_qty")), qty1)
self.assertEqual(flt(frappe.db.get_value("Bin", {"item_code": "_Test Item Home Desktop 200", self.assertEqual(flt(frappe.db.get_value("Bin", {"item_code": "_Test Item Home Desktop 200",
"warehouse": "_Test Warehouse - _TC"}, "indented_qty")), qty2) "warehouse": "_Test Warehouse - _TC"}, "indented_qty")), qty2)
def _insert_stock_entry(self, qty1, qty2): def _insert_stock_entry(self, qty1, qty2):
se = frappe.get_doc({ se = frappe.get_doc({
"company": "_Test Company", "company": "_Test Company",
"doctype": "Stock Entry", "doctype": "Stock Entry",
"posting_date": "2013-03-01", "posting_date": "2013-03-01",
"posting_time": "00:00:00", "posting_time": "00:00:00",
"purpose": "Material Receipt", "purpose": "Material Receipt",
"fiscal_year": "_Test Fiscal Year 2013", "fiscal_year": "_Test Fiscal Year 2013",
"mtn_details": [ "mtn_details": [
{ {
"conversion_factor": 1.0, "conversion_factor": 1.0,
"doctype": "Stock Entry Detail", "doctype": "Stock Entry Detail",
"item_code": "_Test Item Home Desktop 100", "item_code": "_Test Item Home Desktop 100",
"parentfield": "mtn_details", "parentfield": "mtn_details",
"incoming_rate": 100, "incoming_rate": 100,
"qty": qty1, "qty": qty1,
"stock_uom": "_Test UOM 1", "stock_uom": "_Test UOM 1",
"transfer_qty": qty1, "transfer_qty": qty1,
"uom": "_Test UOM 1", "uom": "_Test UOM 1",
"t_warehouse": "_Test Warehouse 1 - _TC", "t_warehouse": "_Test Warehouse 1 - _TC",
}, },
{ {
"conversion_factor": 1.0, "conversion_factor": 1.0,
"doctype": "Stock Entry Detail", "doctype": "Stock Entry Detail",
"item_code": "_Test Item Home Desktop 200", "item_code": "_Test Item Home Desktop 200",
"parentfield": "mtn_details", "parentfield": "mtn_details",
"incoming_rate": 100, "incoming_rate": 100,
"qty": qty2, "qty": qty2,
"stock_uom": "_Test UOM 1", "stock_uom": "_Test UOM 1",
"transfer_qty": qty2, "transfer_qty": qty2,
"uom": "_Test UOM 1", "uom": "_Test UOM 1",
"t_warehouse": "_Test Warehouse 1 - _TC", "t_warehouse": "_Test Warehouse 1 - _TC",
} }
@ -107,20 +107,20 @@ class TestMaterialRequest(unittest.TestCase):
}) })
se.insert() se.insert()
se.submit() se.submit()
def test_completed_qty_for_purchase(self): def test_completed_qty_for_purchase(self):
frappe.db.sql("""delete from `tabBin`""") frappe.db.sql("""delete from `tabBin`""")
# submit material request of type Purchase # submit material request of type Purchase
mr = frappe.copy_doc(test_records[0]) mr = frappe.copy_doc(test_records[0])
mr.insert() mr.insert()
mr.submit() mr.submit()
# check if per complete is None # check if per complete is None
self._test_expected(mr, [{"per_ordered": None}, {"ordered_qty": None}, {"ordered_qty": None}]) self._test_expected(mr, [{"per_ordered": None}, {"ordered_qty": None}, {"ordered_qty": None}])
self._test_requested_qty(54.0, 3.0) self._test_requested_qty(54.0, 3.0)
# map a purchase order # map a purchase order
from erpnext.stock.doctype.material_request.material_request import make_purchase_order from erpnext.stock.doctype.material_request.material_request import make_purchase_order
po_doc = make_purchase_order(mr.name) po_doc = make_purchase_order(mr.name)
@ -131,34 +131,34 @@ class TestMaterialRequest(unittest.TestCase):
po_doc.get("po_details")[0]["schedule_date"] = "2013-07-09" po_doc.get("po_details")[0]["schedule_date"] = "2013-07-09"
po_doc.get("po_details")[1]["schedule_date"] = "2013-07-09" po_doc.get("po_details")[1]["schedule_date"] = "2013-07-09"
# check for stopped status of Material Request # check for stopped status of Material Request
po = frappe.copy_doc(po_doc) po = frappe.copy_doc(po_doc)
po.insert() po.insert()
mr.obj.update_status('Stopped') mr.update_status('Stopped')
self.assertRaises(frappe.ValidationError, po.submit) self.assertRaises(frappe.ValidationError, po.submit)
self.assertRaises(frappe.ValidationError, po.cancel) self.assertRaises(frappe.ValidationError, po.cancel)
mr.obj.update_status('Submitted') mr.update_status('Submitted')
po = frappe.copy_doc(po_doc) po = frappe.copy_doc(po_doc)
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, [{"per_ordered": 50}, {"ordered_qty": 27.0}, {"ordered_qty": 1.5}]) self._test_expected(mr, [{"per_ordered": 50}, {"ordered_qty": 27.0}, {"ordered_qty": 1.5}])
self._test_requested_qty(27.0, 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, [{"per_ordered": None}, {"ordered_qty": None}, {"ordered_qty": None}]) self._test_expected(mr, [{"per_ordered": None}, {"ordered_qty": None}, {"ordered_qty": None}])
self._test_requested_qty(54.0, 3.0) self._test_requested_qty(54.0, 3.0)
def test_completed_qty_for_transfer(self): def test_completed_qty_for_transfer(self):
frappe.db.sql("""delete from `tabBin`""") frappe.db.sql("""delete from `tabBin`""")
frappe.db.sql("""delete from `tabStock Ledger Entry`""") frappe.db.sql("""delete from `tabStock Ledger Entry`""")
# submit material request of type Purchase # submit material request of type Purchase
mr = frappe.copy_doc(test_records[0]) mr = frappe.copy_doc(test_records[0])
mr.material_request_type = "Transfer" mr.material_request_type = "Transfer"
@ -167,11 +167,11 @@ class TestMaterialRequest(unittest.TestCase):
# check if per complete is None # check if per complete is None
self._test_expected(mr, [{"per_ordered": None}, {"ordered_qty": None}, {"ordered_qty": None}]) self._test_expected(mr, [{"per_ordered": None}, {"ordered_qty": None}, {"ordered_qty": None}])
self._test_requested_qty(54.0, 3.0) self._test_requested_qty(54.0, 3.0)
from erpnext.stock.doctype.material_request.material_request import make_stock_entry from erpnext.stock.doctype.material_request.material_request import make_stock_entry
# map a stock entry # map a stock entry
se_doc = make_stock_entry(mr.name) se_doc = make_stock_entry(mr.name)
se_doc.update({ se_doc.update({
@ -191,37 +191,37 @@ class TestMaterialRequest(unittest.TestCase):
"s_warehouse": "_Test Warehouse 1 - _TC", "s_warehouse": "_Test Warehouse 1 - _TC",
"incoming_rate": 1.0 "incoming_rate": 1.0
}) })
# make available the qty in _Test Warehouse 1 before transfer # make available the qty in _Test Warehouse 1 before transfer
self._insert_stock_entry(27.0, 1.5) self._insert_stock_entry(27.0, 1.5)
# check for stopped status of Material Request # check for stopped status of Material Request
se = frappe.copy_doc(se_doc) se = frappe.copy_doc(se_doc)
se.insert() se.insert()
mr.obj.update_status('Stopped') mr.update_status('Stopped')
self.assertRaises(frappe.ValidationError, se.submit) self.assertRaises(frappe.ValidationError, se.submit)
self.assertRaises(frappe.ValidationError, se.cancel) self.assertRaises(frappe.ValidationError, se.cancel)
mr.obj.update_status('Submitted') mr.update_status('Submitted')
se = frappe.copy_doc(se_doc) se = frappe.copy_doc(se_doc)
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, [{"per_ordered": 50}, {"ordered_qty": 27.0}, {"ordered_qty": 1.5}]) self._test_expected(mr, [{"per_ordered": 50}, {"ordered_qty": 27.0}, {"ordered_qty": 1.5}])
self._test_requested_qty(27.0, 1.5) self._test_requested_qty(27.0, 1.5)
# check if per complete is as expected for Stock Entry cancelled # check if per complete is as expected for Stock Entry cancelled
se.cancel() se.cancel()
mr.load_from_db() mr.load_from_db()
self._test_expected(mr, [{"per_ordered": 0}, {"ordered_qty": 0}, {"ordered_qty": 0}]) self._test_expected(mr, [{"per_ordered": 0}, {"ordered_qty": 0}, {"ordered_qty": 0}])
self._test_requested_qty(54.0, 3.0) self._test_requested_qty(54.0, 3.0)
def test_completed_qty_for_over_transfer(self): def test_completed_qty_for_over_transfer(self):
frappe.db.sql("""delete from `tabBin`""") frappe.db.sql("""delete from `tabBin`""")
frappe.db.sql("""delete from `tabStock Ledger Entry`""") frappe.db.sql("""delete from `tabStock Ledger Entry`""")
# submit material request of type Purchase # submit material request of type Purchase
mr = frappe.copy_doc(test_records[0]) mr = frappe.copy_doc(test_records[0])
mr.material_request_type = "Transfer" mr.material_request_type = "Transfer"
@ -230,9 +230,9 @@ class TestMaterialRequest(unittest.TestCase):
# check if per complete is None # check if per complete is None
self._test_expected(mr, [{"per_ordered": None}, {"ordered_qty": None}, {"ordered_qty": None}]) self._test_expected(mr, [{"per_ordered": None}, {"ordered_qty": None}, {"ordered_qty": None}])
self._test_requested_qty(54.0, 3.0) self._test_requested_qty(54.0, 3.0)
# map a stock entry # map a stock entry
from erpnext.stock.doctype.material_request.material_request import make_stock_entry from erpnext.stock.doctype.material_request.material_request import make_stock_entry
@ -257,30 +257,30 @@ class TestMaterialRequest(unittest.TestCase):
# make available the qty in _Test Warehouse 1 before transfer # make available the qty in _Test Warehouse 1 before transfer
self._insert_stock_entry(60.0, 3.0) self._insert_stock_entry(60.0, 3.0)
# check for stopped status of Material Request # check for stopped status of Material Request
se = frappe.copy_doc(se_doc) se = frappe.copy_doc(se_doc)
se.insert() se.insert()
mr.obj.update_status('Stopped') mr.update_status('Stopped')
self.assertRaises(frappe.ValidationError, se.submit) self.assertRaises(frappe.ValidationError, se.submit)
self.assertRaises(frappe.ValidationError, se.cancel) self.assertRaises(frappe.ValidationError, se.cancel)
mr.obj.update_status('Submitted') mr.update_status('Submitted')
se = frappe.copy_doc(se_doc) se = frappe.copy_doc(se_doc)
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, [{"per_ordered": 100}, {"ordered_qty": 60.0}, {"ordered_qty": 3.0}]) self._test_expected(mr, [{"per_ordered": 100}, {"ordered_qty": 60.0}, {"ordered_qty": 3.0}])
self._test_requested_qty(0.0, 0.0) self._test_requested_qty(0.0, 0.0)
# check if per complete is as expected for Stock Entry cancelled # check if per complete is as expected for Stock Entry cancelled
se.cancel() se.cancel()
mr.load_from_db() mr.load_from_db()
self._test_expected(mr, [{"per_ordered": 0}, {"ordered_qty": 0}, {"ordered_qty": 0}]) self._test_expected(mr, [{"per_ordered": 0}, {"ordered_qty": 0}, {"ordered_qty": 0}])
self._test_requested_qty(54.0, 3.0) self._test_requested_qty(54.0, 3.0)
def test_incorrect_mapping_of_stock_entry(self): def test_incorrect_mapping_of_stock_entry(self):
# submit material request of type Purchase # submit material request of type Purchase
mr = frappe.copy_doc(test_records[0]) mr = frappe.copy_doc(test_records[0])
@ -290,7 +290,7 @@ class TestMaterialRequest(unittest.TestCase):
# map a stock entry # map a stock entry
from erpnext.stock.doctype.material_request.material_request import make_stock_entry from erpnext.stock.doctype.material_request.material_request import make_stock_entry
se_doc = make_stock_entry(mr.name) se_doc = make_stock_entry(mr.name)
se_doc.update({ se_doc.update({
"posting_date": "2013-03-01", "posting_date": "2013-03-01",
@ -310,11 +310,11 @@ class TestMaterialRequest(unittest.TestCase):
"s_warehouse": "_Test Warehouse 1 - _TC", "s_warehouse": "_Test Warehouse 1 - _TC",
"incoming_rate": 1.0 "incoming_rate": 1.0
}) })
# check for stopped status of Material Request # check for stopped status of Material Request
se = frappe.copy_doc(se_doc) se = frappe.copy_doc(se_doc)
self.assertRaises(frappe.MappingMismatchError, se.insert) self.assertRaises(frappe.MappingMismatchError, se.insert)
def test_warehouse_company_validation(self): def test_warehouse_company_validation(self):
from erpnext.stock.utils import InvalidWarehouseCompany from erpnext.stock.utils import InvalidWarehouseCompany
mr = frappe.copy_doc(test_records[0]) mr = frappe.copy_doc(test_records[0])
@ -322,4 +322,4 @@ class TestMaterialRequest(unittest.TestCase):
self.assertRaises(InvalidWarehouseCompany, mr.insert) self.assertRaises(InvalidWarehouseCompany, mr.insert)
test_dependencies = ["Currency Exchange"] test_dependencies = ["Currency Exchange"]
test_records = frappe.get_test_records('Material Request') test_records = frappe.get_test_records('Material Request')