Get Incoming Rate On Delivery Note Item

Hello,

I want to show item’s incoming rate (based on fifo) on a custom field: incoming_rate when adding item on delivery note.
Here’s my custom script:

frappe.ui.form.on("Delivery Note Item", "item_code", function(frm, cdt, cdn) {
    var d = locals[cdt][cdn];
    return frappe.call({
  method:"erpnext.stock.utils.get_incoming_rate", 
  args: {"item_code": d.item_code },
			callback: function(r) {
				if (!r.exc && r.message){
					frappe.model.set_value(cdt, cdn, "incoming_rate", r.message);
				}
			}
});
});

But it always shows “Not Permitted” upon item code change. Error on console:

File "/home/vef/frappe-bench/apps/frappe/frappe/app.py", line 67, in application
    response = frappe.handler.handle()
  File "/home/vef/frappe-bench/apps/frappe/frappe/handler.py", line 75, in handle
    execute_cmd(cmd)
  File "/home/vef/frappe-bench/apps/frappe/frappe/handler.py", line 107, in execute_cmd
    raise frappe.PermissionError('Not Allowed, {0}'.format(method))
 PermissionError: Not Allowed, <function get_incoming_rate at 0x7fd9743e5398>

Anybody can help? Tks

To call a function from the client, the function need to be whitelisted. I have pushed a fix, to make it whitelisted.

And note that, you have to pass item_code, warehouse, posting_date, time, qty and serial no to get correct incoming rate.

@nabinhait, got this error TypeError: get_incoming_rate() takes exactly 1 argument (0 given)

here’s the custom script:

frappe.ui.form.on("Delivery Note Item", "item_code", function(frm, cdt, cdn) {
    var d = locals[cdt][cdn];
    return frappe.call({
  method:"erpnext.stock.utils.get_incoming_rate", 
  args: {
            "item_code": d.item_code, 
            "warehouse": d.t_warehouse,
            "posting_date": frm.doc.posting_date,
            "posting_time": frm.doc.posting_time,
            "qty": d.qty,
            "serial_no": d.serial_no
        },
			callback: function(r) {
				if (r.message){
					frappe.model.set_value(cdt, cdn, "incoming_rate", r.message);
				}
			}
});
});

Try this:

frappe.ui.form.on("Delivery Note Item", "item_code", function(frm, cdt, cdn) {
	var d = locals[cdt][cdn];
	return frappe.call({
		method:"erpnext.stock.utils.get_incoming_rate", 
		args: {
			args: {
				"item_code": d.item_code, 
				"warehouse": d.t_warehouse,
				"posting_date": frm.doc.posting_date,
				"posting_time": frm.doc.posting_time,
				"qty": d.qty,
				"serial_no": d.serial_no
			}
		},
		callback: function(r) {
			if (r.message) {
				frappe.model.set_value(cdt, cdn, "incoming_rate", r.message);
			}
		}
	});
});

@nabinhait Got this error:

if (args.get("serial_no") or "").strip():
 AttributeError: 'unicode' object has no attribute 'get'

Any hints? Tks for your kind help

Really stuck…anybody can help? Tks

check type of args, is it may be json format. so convert it into dict first.

Needs to be fixed in get_incoming_rate function, will push a fix today

@jof2jc pull the latest update, and check if it works now.

Got error:

104, in get_incoming_rate
    previous_sle = get_previous_sle(args)
  File "/home/vef/frappe-bench/apps/erpnext/erpnext/stock/stock_ledger.py", line 359, in get_previous_sle
    sle = get_stock_ledger_entries(args, "<=", "desc", "limit 1", for_update=for_update)
  File "/home/vef/frappe-bench/apps/erpnext/erpnext/stock/stock_ledger.py", line 384, in get_stock_ledger_entries
    }, previous_sle, as_dict=1, debug=debug)
  File "/home/vef/frappe-bench/apps/frappe/frappe/database.py", line 135, in sql
    self._cursor.execute(query, values)
  File "/home/vef/frappe-bench/env/local/lib/python2.7/site-packages/MySQLdb/cursors.py", line 185, in execute
    for key, item in args.iteritems())
 KeyError: 'warehouse'

Here’s my custom script:

frappe.ui.form.on("Delivery Note Item", "item_code", function(frm, cdt, cdn) {
	var d = locals[cdt][cdn];
	frappe.call({
		method: "erpnext.stock.utils.get_incoming_rate", 
		args: {
			args: {
				"item_code": d.item_code, 
				"warehouse": d.warehouse,
				"posting_date": frm.doc.posting_date,
				"posting_time": frm.doc.posting_time,
				"qty": d.qty,
				"serial_no": d.serial_no
			}
		},
		callback: function(r) {
			if (r.message) {
				frappe.model.set_value(cdt, cdn, "incoming_rate", r.message);
			}
		}
	});
});

Do you have warehouse in all rows of DN?

I tried to pass ‘hard-coded’ value for warehouse and I can get incoming_rate.

frappe.ui.form.on("Delivery Note Item", "item_code", function(frm, cdt, cdn)

This is triggered when item_code change which seemed the warehouse value was not populated yet…

I tried this but doesn’t work…

frappe.ui.form.on("Delivery Note Item", "warehouse", function(frm, cdt, cdn)

I think this must be triggered after item_code change so warehouse is already populated. What’s your suggestion? Thanks

I need to trigger the function after item (warehouse) is fetched.
frappe.ui.form.on("Delivery Note Item", "refresh", function(frm, cdt, cdn) also doesn’t work…

Above code is not working because on item_code change event, item details like warehouse etc are not fetched yet. It’s fetched on 2nd field change.

I get this working by using another trigger from a custom field. I created custom field: imei_serial_no to pull item_code then trigger get_incoming_rate. But I believe there’s more simple way to do this. This is just the matter how we trigger events. I just want to fire the function after all item-details are fetched. Is there any example?

frappe.ui.form.on("Delivery Note Item", "imei_serial_no", function(frm, cdt, cdn) {
	var d = locals[cdt][cdn];
        var it = "test";
	if (d.imei_serial_no) {
		frappe.call({
			method: "erpnext.stock.get_item_details.get_item_code",
			args: {"serial_no": d.imei_serial_no },
			callback: function(r) {
				if (!r.exe && r.message){
					frappe.model.set_value(cdt, cdn, "item_code", r.message);                                
				}
                                else{
                                        validated = false;
                                        throw "IMEI not found. Invalid!";
                                }
			}
		});
                d.serial_no = d.imei_serial_no;               
                
	}
        frappe.call({
		method: "erpnext.stock.utils.get_incoming_rate", 
		args: {
			args: {
				"item_code": d.item_code, 
				"warehouse": d.warehouse,
				"posting_date": frm.doc.posting_date,
				"posting_time": frm.doc.posting_time,
				"qty": d.qty,
				"serial_no": d.serial_no
			}
		},
		callback: function(r) {
			if (r.message) {
				frappe.model.set_value(cdt, cdn, "incoming_rate", r.message);
			}
                        else {
				frappe.model.set_value(cdt, cdn, "incoming_rate", 0.0);
                               frappe.model.set_value(cdt, cdn, "item_code", "");
			}
		}
	});        
});

This is because of asynchronous behaviour of javascript. Actually, your function should be called on callback of get_item_details function. But while doing customization, you can’t do that.
Here, may be you should fetch incoming rate in validate function, in that case, rate will be fetched on saving of the document.