Set custom price rate via client script

I need to set a custom rate in the Purchase Receipt but ERPNext erases it after a while.

PM_SET_RATE_PROBLEM

Code:

var rowItem = frappe.model.add_child(frm.doc, 'Purchase Receipt Item', 'items');
frappe.model.set_value(rowItem.doctype, rowItem.name, 'item_code', r.message.item_code);
frappe.model.set_value(rowItem.doctype, rowItem.name, 'qty', barcode_info[0]["Satır Açıklaması"]);
frappe.model.set_value(rowItem.doctype, rowItem.name, 'uom', r.message.item_uom);
frappe.model.set_value(rowItem.doctype, rowItem.name, 'rate', purchase_rate_info.purchase_rate_per_unit);

My only workaround is setting the rate in a setTimeout() function.

setTimeout(() => {frappe.model.set_value(rowItem.doctype, rowItem.name, 'rate', purchase_rate_info.purchase_rate_per_unit)}, 3000);

What I tried:

  • Tried to set also “price_list_rate”.
  • Tried setting “frappe.flags.dont_fetch_price_list_rate” flag to true.

So, how do you set custom rates when you need to get it programmatically when buying or selling?

PS: I think that if rate is set, ERPNext should not alter it. Especially if it is greater then zero.

just an idea, instead of calling frappe.model.set_value which will trigger the standard field event handler, simply set new value by rowItem.rate = purchase_rate_info.purchase_rate_per_unit, and finally call frm.cscript.calculate_taxes_and_totals()

1 Like

I think ERPNext should behave like how user manually enters data. So I want to trigger calculations like user manually add it.

And I think rate evaluation begins when setting the item not “rowItem.rate”.

But your suggestion to trigger calculate_taxes_and_totals() calculation is a good one. I can try that.

Would calling calculate_taxes_and_totals() help in a case where one is recalculating amount?
In our case, we calculate, amount = qtydaysrate, days is a custom field
We had to customize calculate_taxes_and_totals directly/via hooks to handle this case, as it kept recalculating amount from qty*rate

I couldn’t get the problem. Do you have a screenshot?

We solved this via a custom app. By extending the stand method to suit our need.

1 Like

Hi @glz, is it possible to share this custom app or server scripts?

The app extension

The client scripts

//End date validation on End date change
var end_date_start_date_validation = function (frm, cdt, cdn) {
    var d = locals[cdt][cdn];
    if (d.end_date && d.start_date) {
        if (d.end_date < d.start_date) {
            msgprint('End date is before Start date, please amend to continue');
            frappe.validated = false;
        }
    } else if (d.days && !d.end_date && !d.start_date) {
        msgprint('Start Date and End Date are blank, please amend to continue');
        frappe.validated = false;
    }
}

//Days Calculation
var days_calculation = function (frm, cdt, cdn) {
    var row = locals[cdt][cdn];
    if (row.reservation_option === "Nights") { //For Nights
        if (row.end_date >= row.start_date) { //Days Calculation on End date change
            frappe.model.set_value(cdt, cdn, 'days', frappe.datetime.get_day_diff(row.end_date, row.start_date));
            frm.refresh_field("days");
        }
    } else {
        if (row.end_date >= row.start_date) { //Days Calculation on End date change
            //Days Calculation on End date change
            var daydiff = frappe.datetime.get_day_diff(row.end_date, row.start_date);
            daydiff = daydiff + 1;
            frappe.model.set_value(cdt, cdn, 'days', daydiff);
            frm.refresh_field("days");
        }
    }
}

//End Date Calculation-Not in use, creates cyclic calculations
var end_date_calculation = function (frm, cdt, cdn) {
    var row = locals[cdt][cdn];
    if (row.reservation_option === "Nights") { //For Nights
        if (row.days && row.start_date && !row.end_date) { //End date Calculation on Days change
            frappe.model.set_value(cdt, cdn, 'end_date', frappe.datetime.add_days(row.start_date, row.days));
            frm.refresh_field("end_date");
        }
    } else {
        if (row.days && row.start_date) { //End date Calculation on Days change
            var newdays = row.days + 1;
            frappe.model.set_value(cdt, cdn, 'end_date', frappe.datetime.add_days(row.start_date, newdays));
            frm.refresh_field("end_date");
        }
    }
}

//For Childdoctype
frappe.ui.form.on("Sales Order Item", "item_code", function (frm, cdt, cdn) {
    //Fetch reservation_option from item 
    var d = locals[cdt][cdn];
    frappe.db.get_value("Item", { "name": d.item_code }, "reservation_option", function (value) {
        d.reservation_option = value.reservation_option;
    });
})

frappe.ui.form.on("Sales Order Item", "end_date", function (frm, cdt, cdn) {
    //End date validation on End date change
    end_date_start_date_validation(frm, cdt, cdn);
    //Days or Dates Calculation
    days_calculation(frm, cdt, cdn);
})

frappe.ui.form.on("Sales Order Item", "start_date", function (frm, cdt, cdn) {
    //End date validation on End date change
    end_date_start_date_validation(frm, cdt, cdn);
    //Days or Dates Calculation
    days_calculation(frm, cdt, cdn);
})

Thanks! This is much help. If I understand this correctly, you override original calculate_taxes_and_totals function, right?

Yes. Otherwise, that client script won’t work. Will keep recalculating amount = qty * rate, instead of amount = qty * days * rate, as needed.

1 Like