Client Script to Validate Certain Fields on Item Master

Hi All,

I have four fields, Type, Serial Number, Part Number and Model on Item master. Now, I wrote a client script that validates the uniqueness of these fields. The user cannot save the Item master if the values in each field has been entered for another item. The user can only save the Item master if (a) the value does not exist for another item or (b) the value is ‘None’.

Here is the client script below. The problem is it works for one field and not for others, or another time it doesn’t just work. Please help me:

frappe.ui.form.on(‘Item’, {
validate: function (frm) {
const fields = [‘type’, ‘serial_number’, ‘part_number’, ‘model’];

    frappe.call({
        method: 'frappe.client.get_list',
        args: {
            doctype: 'Item',
            fields: fields,
            filters: [
                ['name', '!=', frm.doc.name]
            ]
        },
        callback: function (response) {
            if (response.message) {
                const items = response.message;
                const errorMessages = [];

                fields.forEach(field => {
                    if (frm.doc[field] && frm.doc[field] !== 'None') {
                        const isDuplicate = items.some(item => item[field] === frm.doc[field]);
                        if (isDuplicate) {
                            errorMessages.push(${field.replace(/_/g, ' ').toUpperCase()} must be unique.);
                        }
                    }
                });

                if (errorMessages.length > 0) {
                    frappe.msgprint({
                        title: __('Validation Error'),
                        message: errorMessages.join('<br>'),
                        indicator: 'red'
                    });
                    frappe.validated = false;
                }
            }
        }
    });
}

});

Please help. PLEASE.

Why don’t you just make the field unique?

Or if you want client script use this:

frappe.ui.form.on("Item", {
  validate: async function (frm) {
    const unique_fields = ["type", "serial_number", "part_number", "model"];

    const response = await frappe.call({
      method: "frappe.client.get_list",
      args: {
        doctype: "Item",
        fields: unique_fields,
        filters: [["name", "!=", frm.doc.name]],
      },
    });

    if (!response.message) return;

    const items = response.message;
    const errorMessages = [];

    for (field of unique_fields) {
      if (!frm.doc[field]) continue;

      const isDuplicate = items.some((item) => item[field] === frm.doc[field]);

      if (!isDuplicate) continue;

      errorMessages.push(
        __("{0} must be unique.", [__(frm.get_field(field).df.label)])
      );
    }

    if (!errorMessages) return;

    frappe.throw({
      title: __("Validation Error"),
      message: errorMessages.join("<br>"),
    });
  },
});

1 Like

Hi Abdeali, thank you very much.

I thought of this too but if we make the field unique, the “None” value cannot be repeated for other Items once it is entered for a particular item. The value “None” should be exempted, that is why we thought of client script.

Abdeali, once again thank you very much. I really appreciate your assistance.

However, we tried the suggested script, we noticed that after we makes changes in the Item master, the Save button stopped responding. We could not save any changes.

But why do you need None explicitly? If you don’t fill in the data, it is automatically null in JS and None in python.

You can see here:

View Demo

Or you can make one server script for this and use exists instead of get_list and validate, it would be more better and efficient.