How to Validate a Field Value if Date Range is Matched

Hello, I wrote a client script to validate a field Apartment using a selected date range by checking all existing records if that field value exists in other records for the same date range. Here is the script below:

frappe.ui.form.on("Guest Management Checklist", {
    validate: function(frm) {
        frappe.call({
            method: "frappe.client.get_list",
            args: {
                    doctype: "Guest Management Checklist",
                    fieldname: "apartment",
                    filters: {
                        apartment: frm.doc.apartment,
                        from_date: [
                          "between",
                          frm.doc.from_date,
                          frm.doc.to_date,
                        ],
                        to_date: [
                          "between",
                          frm.doc.from_date,
                          frm.doc.to_date,
                        ],
                      },
            },
            callback: function(response) {
                var to_date = response.message;
                if (to_date) {
                    frappe.msgprint("The value '" + frm.doc.apartment + "' is already used in another record with an overlapping date range.");
                                validated=false;
                                return false;
            
                }
            }
        })
    },
});

While the script works perfectly when the date range selected in the new record is present in existing records, it also invalidates all new records outside the date range.

Is there any part of the script that is wrong? I will appreciate any tips i can get.

@flexy2ky I think that your code should be like this…

frappe.ui.form.on("Guest Management Checklist", {
    validate: function(frm) {
        frappe.call({
            method: "frappe.client.get_list",
            args: {
                    doctype: "Guest Management Checklist",
                    fields: ["apartment"],
                    filters: {
                        apartment: frm.doc.apartment,
                        from_date: [
                          "between",
                          [frm.doc.from_date, frm.doc.to_date]
                        ],
                        to_date: [
                          "between",
                          [frm.doc.from_date, frm.doc.to_date]
                        ],
                      },
            },
            callback: function(response) {
                var to_date = response.message;
                if (to_date) {
                    frappe.msgprint("The value '" + frm.doc.apartment + "' is already used in another record with an overlapping date range.");
                                validated=false;
                                return false;
            
                }
            }
        })
    },
});
1 Like

@kid1194 Thanks for pointing out a clear error that was overlooked!!

Following your revised code, I was still getting the error but I realized that I was using both the validate function and a pre-existing function within the same script (to_date) to trigger the validation hence regardless of the response the response.message will always be triggered. I therefore modified the script thus:

frappe.ui.form.on("Guest Management Checklist", {
     validate: function(frm) {
        frappe.call({
            method: "frappe.client.get_list",
            args: {
                    doctype: "Guest Management Checklist",
                    fields: ["apartment"],
                    filters: {
                        apartment: frm.doc.apartment,
                        from_date: [
                            "between",
                            [frm.doc.from_date, frm.doc.to_date]
                        ],
                        to_date: [
                            "between",
                            [frm.doc.from_date, frm.doc.to_date]
                        ],
                    },
            },
            callback: function(response) {
                var conflicting_records = response.message;
                if (conflicting_records.length > 0) {
                    frappe.msgprint("The value '" + frm.doc.apartment + "' is already used in another record with an overlapping date range.");
                                validated=false;
                                return false;
            
                }
            }
        })
    },
});

This seemed to do the trick and the script seems to work albeit inconsistently. Sometimes the validation returns false as it should and sometimes it doesn’t return false and the apartment record is allowed to be saved. Is there any other edit you can suggest to help close this loophole? Thanks for your help.

@flexy2ky You should put the call inside a promise and return the promise so the code waits for the call to finish…

frappe.ui.form.on("Guest Management Checklist", {
    validate: function(frm) {
        return new Promise(function(resolve, reject) {
            frappe.call({
                method: "frappe.client.get_list",
                args: {
                    doctype: "Guest Management Checklist",
                    fields: ["apartment"],
                    filters: {
                        apartment: frm.doc.apartment,
                        from_date: [
                            "between",
                            [frm.doc.from_date, frm.doc.to_date]
                        ],
                        to_date: [
                            "between",
                            [frm.doc.from_date, frm.doc.to_date]
                        ],
                    },
                },
                callback: function(response) {
                    var conflicting_records = response.message;
                    if (conflicting_records.length > 0) {
                        frappe.msgprint("The value '" + frm.doc.apartment + "' is already used in another record with an overlapping date range.");
                        reject();
                    } else {
                        resolve();
                    }
                },
                error: function() {
                    reject();
                }
            });
        });
    },
});