Summary
Phone number fields default to a doubled dial-code prefix (+91 +91xxxxxxxx). Because of the duplicated +91, saving a Talk Proposal (and any other form using the phone input) fails with an "Invalid Phone Number" validation error, forcing users to manually clean up the value on every edit.
Reported in the community chat with a screenshot of the error:
The phone number fields by default have +91 +91xxxxxxxx. Due to having +91 twice it says incorrect phone number every time I edit a talk proposal record and save. Not good experience, extra clicks and cleaning up.
Root cause
The bug is in the frontend phone input, not the doctype (the phone field on Talk Proposal has no default value in talk_proposal.json).
In dashboard/src/components/PhoneInput.vue:
- The dial code is hardcoded to India:
const dialCode = ref("+91"); // line ~40
emitValue() always re-concatenates the dial code onto the number:
emit("update:modelValue", `${dialCode.value} ${localNumber.value}`); // line ~92
parsePhone() does not cleanly strip an existing dial code from the incoming value:
const match = value.match(/^(\+\d{1,4})[\s-]?(.*)$/); // line ~72
The regex is greedy on \d{1,4} and only strips a single separator. When a stored value already contains a dial code (e.g. +91 ...), the leftover +91 ends up inside localNumber, and emitValue() then prepends +91 again, producing "+91 +91 ...".
The malformed value is then rejected by the backend in buzz/api/__init__.py (validate_custom_fields, ~lines 320-325), which calls frappe.utils.validate_phone_number_with_country_code(...).
Suggested fix
- Make
parsePhone() reliably separate the dial code from the local number (match against the known dial-code list from buzz.api.forms.get_dial_codes rather than a greedy regex), and ensure emitValue() never double-prepends when the number already carries a code.
- Add a regression test for round-tripping a value that already contains a dial code.
Related note (US-first product)
The default dial code is currently +91. Since new business is US-only, the default should be +1. Happy to fold this into the fix or track separately.
Affected files
dashboard/src/components/PhoneInput.vue (dial-code default + parse/emit logic — primary)
dashboard/src/components/CustomFieldInput.vue (wires PhoneInput for Phone custom fields)
dashboard/src/components/ProposalEditDialog.vue (edits Talk Proposal phone via a raw FormControl type="tel", persists the string as-is)
buzz/api/__init__.py (validate_custom_fields phone validation)
buzz/api/forms.py (get_dial_codes)
Summary
Phone number fields default to a doubled dial-code prefix (
+91 +91xxxxxxxx). Because of the duplicated+91, saving a Talk Proposal (and any other form using the phone input) fails with an "Invalid Phone Number" validation error, forcing users to manually clean up the value on every edit.Reported in the community chat with a screenshot of the error:
Root cause
The bug is in the frontend phone input, not the doctype (the
phonefield on Talk Proposal has no default value intalk_proposal.json).In
dashboard/src/components/PhoneInput.vue:emitValue()always re-concatenates the dial code onto the number:parsePhone()does not cleanly strip an existing dial code from the incoming value:\d{1,4}and only strips a single separator. When a stored value already contains a dial code (e.g.+91 ...), the leftover+91ends up insidelocalNumber, andemitValue()then prepends+91again, producing"+91 +91 ...".The malformed value is then rejected by the backend in
buzz/api/__init__.py(validate_custom_fields, ~lines 320-325), which callsfrappe.utils.validate_phone_number_with_country_code(...).Suggested fix
parsePhone()reliably separate the dial code from the local number (match against the known dial-code list frombuzz.api.forms.get_dial_codesrather than a greedy regex), and ensureemitValue()never double-prepends when the number already carries a code.Related note (US-first product)
The default dial code is currently
+91. Since new business is US-only, the default should be+1. Happy to fold this into the fix or track separately.Affected files
dashboard/src/components/PhoneInput.vue(dial-code default + parse/emit logic — primary)dashboard/src/components/CustomFieldInput.vue(wiresPhoneInputfor Phone custom fields)dashboard/src/components/ProposalEditDialog.vue(edits Talk Proposalphonevia a rawFormControl type="tel", persists the string as-is)buzz/api/__init__.py(validate_custom_fieldsphone validation)buzz/api/forms.py(get_dial_codes)