Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions rmax_custom/api/customer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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():
Expand Down Expand Up @@ -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.")
57 changes: 57 additions & 0 deletions rmax_custom/fixtures/custom_field.json
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
16 changes: 16 additions & 0 deletions rmax_custom/fixtures/property_setter.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
]
8 changes: 6 additions & 2 deletions rmax_custom/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"

]

Expand Down Expand Up @@ -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",
]
]
]
Expand All @@ -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"

]
]
Expand Down
16 changes: 16 additions & 0 deletions rmax_custom/public/js/contact_validation.js
Original file line number Diff line number Diff line change
@@ -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.");

}

});
}
});
141 changes: 141 additions & 0 deletions rmax_custom/public/js/vat_validation.js
Original file line number Diff line number Diff line change
@@ -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");
}
}
Loading