diff --git a/rmax_custom/api/customer.py b/rmax_custom/api/customer.py index ce75d4e..c1b3651 100644 --- a/rmax_custom/api/customer.py +++ b/rmax_custom/api/customer.py @@ -2,6 +2,8 @@ from frappe import _ from frappe.utils import cstr from frappe.core.doctype.user_permission.user_permission import get_permitted_documents +import re + def _get_default_customer_group(): @@ -110,3 +112,44 @@ def create_customer_with_address( "message": "Customer and Address created successfully" } + + +@frappe.whitelist() +def validate_vat_customer(vat, customer_type, name=None): + if not vat: + return + if customer_type == "Branch": + return + + existing = frappe.get_all( + "Customer", + filters={ + "custom_vat_registration_number": vat, + "name": ["!=", name] + }, + fields=["name"] + ) + + if existing: + frappe.throw( + f" VAT Registration Number already used by Customer: {existing[0].name}" + ) + + return + + + +def count_digits(value): + if not value: + return 0 + return len(re.sub(r"\D", "", value)) + + +@frappe.whitelist() +def validate_phone_numbers(mobile_no=None, phone_no=None): + if mobile_no: + if count_digits(mobile_no) < 10: + frappe.throw("Mobile number must have at least 10 digits.") + if phone_no: + if count_digits(phone_no) < 10: + frappe.throw("Phone number must have at least 10 digits.") \ No newline at end of file diff --git a/rmax_custom/fixtures/custom_field.json b/rmax_custom/fixtures/custom_field.json index de83c96..275ef15 100644 --- a/rmax_custom/fixtures/custom_field.json +++ b/rmax_custom/fixtures/custom_field.json @@ -1,4 +1,61 @@ [ + { + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "collapsible_depends_on": null, + "columns": 0, + "default": null, + "depends_on": null, + "description": null, + "docstatus": 0, + "doctype": "Custom Field", + "dt": "Customer", + "fetch_from": null, + "fetch_if_empty": 0, + "fieldname": "custom_vat_registration_number", + "fieldtype": "Data", + "hidden": 0, + "hide_border": 0, + "hide_days": 0, + "hide_seconds": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_preview": 0, + "in_standard_filter": 0, + "insert_after": "customer_group", + "is_system_generated": 0, + "is_virtual": 0, + "label": "VAT Registration Number", + "length": 0, + "link_filters": null, + "mandatory_depends_on": "eval:doc.customer_type == \"Company\" || doc.customer_type == \"Branch\"", + "modified": "2026-04-13 16:41:56.725156", + "module": null, + "name": "Customer-custom_vat_registration_number", + "no_copy": 0, + "non_negative": 0, + "options": null, + "permlevel": 0, + "placeholder": null, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": null, + "read_only": 0, + "read_only_depends_on": null, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "show_dashboard": 0, + "sort_options": 0, + "translatable": 1, + "unique": 0, + "width": null + }, { "allow_in_quick_entry": 0, "allow_on_submit": 0, diff --git a/rmax_custom/fixtures/property_setter.json b/rmax_custom/fixtures/property_setter.json index 2766c52..0b89242 100644 --- a/rmax_custom/fixtures/property_setter.json +++ b/rmax_custom/fixtures/property_setter.json @@ -126,5 +126,21 @@ "property_type": "Check", "row_name": null, "value": "0" + }, + { + "default_value": null, + "doc_type": "Customer", + "docstatus": 0, + "doctype": "Property Setter", + "doctype_or_field": "DocField", + "field_name": "customer_type", + "is_system_generated": 0, + "modified": "2026-04-13 14:02:46.138091", + "module": null, + "name": "Customer-customer_type-options", + "property": "options", + "property_type": null, + "row_name": null, + "value": "Company\nIndividual\nPartnership\nBranch" } ] \ No newline at end of file diff --git a/rmax_custom/hooks.py b/rmax_custom/hooks.py index 8586758..6942c97 100644 --- a/rmax_custom/hooks.py +++ b/rmax_custom/hooks.py @@ -32,7 +32,9 @@ "/assets/rmax_custom/js/sales_invoice_popup.js", "/assets/rmax_custom/js/create_customer.js", "/assets/rmax_custom/js/create_multiple_supplier.js", - "/assets/rmax_custom/js/materiel_request.js" + "/assets/rmax_custom/js/materiel_request.js", + "/assets/rmax_custom/js/vat_validation.js", + "/assets/rmax_custom/js/contact_validation.js" ] @@ -286,6 +288,7 @@ "Landed Cost Voucher-custom_distribute_by_cbm", # Landed Cost Item (CBM per item) "Landed Cost Item-custom_cbm", + "Customer-custom_vat_registration_number", ] ] ] @@ -304,7 +307,8 @@ "Material Request Item-schedule_date-default", "Material Request-schedule_date-hidden", "Landed Cost Item-qty-columns", - "Material Request-material_request_type-default" + "Material Request-material_request_type-default", + "Customer-customer_type-options" ] ] diff --git a/rmax_custom/public/js/contact_validation.js b/rmax_custom/public/js/contact_validation.js new file mode 100644 index 0000000..6177261 --- /dev/null +++ b/rmax_custom/public/js/contact_validation.js @@ -0,0 +1,16 @@ +frappe.ui.form.on('Contact', { + validate: function(frm) { + function count_digits(val) { + return (val || "").replace(/\D/g, "").length; + } + + (frm.doc.phone_nos || []).forEach(row => { + + if (row.phone && count_digits(row.phone) < 10) { + frappe.throw("Mobile number must have at least 10 digits."); + + } + + }); + } +}); \ No newline at end of file diff --git a/rmax_custom/public/js/vat_validation.js b/rmax_custom/public/js/vat_validation.js new file mode 100644 index 0000000..cf83895 --- /dev/null +++ b/rmax_custom/public/js/vat_validation.js @@ -0,0 +1,141 @@ +frappe.ui.form.on('Customer', { + refresh: function(frm) { + let field = frm.get_field('custom_vat_registration_number'); + if (field && field.$input) { + field.$input.off('input').on('input', function() { + let value = this.value; + value = value.replace(/\D/g, ''); + if (value.length > 15) { + frappe.msgprint("Maximum 15 digits allowed"); + value = value.slice(0, 15); + } + this.value = value; + frm.set_value('custom_vat_registration_number', value); + }); + } + set_customer_type_filter(frm); + }, + +// validate: async function(frm) { + +// let vat = frm.doc.custom_vat_registration_number; + +// // ---------------- VAT VALIDATION ---------------- +// if (vat) { +// if (vat.length > 15) { +// frappe.throw("VAT cannot exceed 15 digits"); +// } + +// await frappe.call({ +// method: "rmax_custom.api.customer.validate_vat_customer", +// args: { +// vat: vat, +// customer_type: frm.doc.customer_type, +// name: frm.doc.name || null +// } +// }); +// } + +// if (frm.doc.customer_primary_contact) { + +// let r = await frappe.call({ +// method: "frappe.client.get", +// args: { +// doctype: "Contact", +// name: frm.doc.customer_primary_contact +// } +// }); + +// let contact = r.message; + +// function count_digits(val) { +// if (!val) return 0; +// return val.replace(/\D/g, "").length; +// } + +// (contact.phone_nos || []).forEach(row => { + +// if (row.phone && count_digits(row.phone) < 10) { + +// if (row.is_primary_mobile) { +// frappe.throw("Mobile number must have at least 10 digits."); +// } else { +// frappe.throw("Phone number must have at least 10 digits."); +// } + +// } + +// }); +// } +validate: async function(frm) { + + let vat = frm.doc.custom_vat_registration_number; + if (vat && vat.length !== 15) { + frappe.throw("VAT must be exactly 15 digits"); + } + if (vat) { + await frappe.call({ + method: "rmax_custom.api.customer.validate_vat_customer", + args: { + vat: vat, + customer_type: frm.doc.customer_type, + name: frm.doc.name || null + } + }); + } + if (frm.doc.customer_primary_contact) { + + let r = await frappe.call({ + method: "frappe.client.get", + args: { + doctype: "Contact", + name: frm.doc.customer_primary_contact + } + }); + + let contact = r.message; + + function count_digits(val) { + if (!val) return 0; + return val.replace(/\D/g, "").length; + } + + for (let row of (contact.phone_nos || [])) { + + if (row.phone && count_digits(row.phone) < 10) { + + if (row.is_primary_mobile) { + frappe.throw("Mobile number must have at least 10 digits."); + } else { + frappe.throw("Phone number must have at least 10 digits."); + } + } + } + } +}, + onload: function(frm) { + set_customer_type_filter(frm); + } +}); + + +function set_customer_type_filter(frm) { + let allowed_roles = ["System Manager", "Auditor"]; + let user_roles = frappe.user_roles || []; + + let is_allowed = allowed_roles.some(role => user_roles.includes(role)); + + let field = frm.get_field("customer_type"); + if (!field) return; + + let options = (field.df.options || "").split("\n"); + + if (!is_allowed) { + options = options.filter(opt => opt.trim() !== "Branch"); + + field.df.options = options.join("\n"); + frm.refresh_field("customer_type"); + + console.log("Branch removedss from Customer Type"); + } +} \ No newline at end of file