Client script for a calculated field

I know that his is probably asked quite a bit and through my searching and following advice I still do not have a solution. I am trying to populate an integer field that is the result of the difference between 2 dates within a child table. Everything I try gives me a calculation of 0. I have tried force refreshing after changing the script. Here is a copy of the script below… Any help would be greatly appreciated.

// Client Script for Doctype: Injury_Illness Report
// Triggers calculation ONLY when BOTH start_date and return_date are present

frappe.ui.form.on(‘Days Away’, {
start_date: function(frm, cdt, cdn) {
trigger_calculation_if_ready(frm, cdt, cdn);

},
return_date: function(frm, cdt, cdn) {
    trigger_calculation_if_ready(frm, cdt, cdn);
}

});

function trigger_calculation_if_ready(frm, cdt, cdn) {
let row = locals[cdt][cdn];

// Only proceed if BOTH dates are filled
//if (!row.start_date || !row.return_date) {
    // Optional: clear the field when incomplete (uncomment if desired)
    // frappe.model.set_value(cdt, cdn, 'days_away', 0);
  //  return;
////}

// Optional: prevent invalid range
//if (row.return_date < row.start_date) {
 //   frappe.msgprint(__("Return Date cannot be before Start Date"));
//    frappe.model.set_value(cdt, cdn, 'number_of_days_away', 0);
//    return;

// }

// OSHA-compliant calculation
// Returns calendar days: return_date - start_date
// (does NOT count the return date itself)

let days = frappe.datetime.get_diff(row.return_date, row.start_date);

// Optional: OSHA allows capping at 180 days
// Comment out the next 3 lines if you want to record actual values >180
if (days > 180) {
    days = 180;
}

frm.set_value(cdt, cdn, 'number_of_days_away', days);
frm.refresh_field("number_of_days_away");

}

found the issue with your Frappe script the problem is this line:

frm.set_value(cdt, cdn, ‘number_of_days_away’, days);

frm.set_value() does NOT work for child table rows. It’s designed for parent form fields only, and silently ignores the cdt/cdn arguments which is exactly why you’re always getting 0.

The fix is to replace it with frappe.model.set_value() which correctly targets a specific child table row.

Here’s the corrected full script:

frappe.ui.form.on(‘Days Away’, {
start_date: function(frm, cdt, cdn) {
trigger_calculation_if_ready(frm, cdt, cdn);
},
return_date: function(frm, cdt, cdn) {
trigger_calculation_if_ready(frm, cdt, cdn);
}
});

function trigger_calculation_if_ready(frm, cdt, cdn) {
let row = locals[cdt][cdn];

if (!row.start_date || !row.return_date) {
    frappe.model.set_value(cdt, cdn, 'number_of_days_away', 0);
    return;
}

if (row.return_date < row.start_date) {
    frappe.msgprint(__("Return Date cannot be before Start Date"));
    frappe.model.set_value(cdt, cdn, 'number_of_days_away', 0);
    return;
}

let days = frappe.datetime.get_diff(row.return_date, row.start_date);

if (days > 180) {
    days = 180;
}

}

One more thing on the refresh_field line, make sure ‘days_away’ matches the fieldname of the child table as it appears on the parent doctype, not the child doctype name. If it’s named differently on your parent form, update that accordingly

Thank you for this feedback, I have made the changes. I am still having issues with getting 0 after updating my script. What refresh needs to be done if a client script is updated? Just a hard browser refresh? Also, I have attached a screenshot of the parent doctype. Are you stating that for the frm.refresh_field(); line that I should be using days_away?

frappe screenshot

For cache run ‘bench clear-cache’ on server, then hard refresh Or just test in Incognito window.

Yes use frm.refresh_field(‘days_away’); that’s already correct.

Looking at your screenshot are Start Date, Return Date, and Number of Days Away fields on the PARENT form or inside the child table? If they’re on the parent form, the script won’t work because the triggers are listening to the child table only.

The script is written for the child form. I added the other fields to the parent form with a similar script to check function of the script which works as expected which is why I am kinda confused.

Got it! So the parent form version works but the child table version gives 0. That points to one of these

  1. WRONG DOCTYPE NAME in the trigger double check the exact name you used in frappe.ui.form.on(‘Days Away’, …). It must match the child doctype name exactly (case-sensitive), not the field name or label. Go to Build > your child doctype and confirm its name.

  2. SCRIPT ATTACHED TO WRONG DOCTYPE the client script must be attached to the PARENT doctype (Injury_Illness Report), not the child doctype. Is that the case?

  3. CACHE did you run bench clear-cache and test in Incognito after the latest change?

Can you share what the child doctype is named in Build?

Problem solved! The doctype was Days Away from Work not Days Away From Work. Thank you for helping me work through this bit of frustration.

1 Like