diff --git a/admin/modals/vendor_template/vendor_template_edit.php b/admin/modals/vendor_template/vendor_template_edit.php index 6599c8415..38069756d 100644 --- a/admin/modals/vendor_template/vendor_template_edit.php +++ b/admin/modals/vendor_template/vendor_template_edit.php @@ -14,7 +14,7 @@ $vendor_description = escapeHtml($row['vendor_template_description']); $vendor_account_number = escapeHtml($row['vendor_template_account_number']); $vendor_contact_name = escapeHtml($row['vendor_template_contact_name']); $vendor_phone_country_code = intval($row['vendor_template_phone_country_code']); -$vendor_phone = formatPhoneNumber($row['vendor_template_phone'], $vendor_phone_country_code); +$vendor_phone = formatPhoneNumber($row['vendor_template_phone'], $vendor_phone_country_code, false); $vendor_extension = escapeHtml($row['vendor_template_extension']); $vendor_email = escapeHtml($row['vendor_template_email']); $vendor_website = escapeHtml($row['vendor_template_website']); diff --git a/admin/settings_company.php b/admin/settings_company.php index 9f7b0048f..82b3e9428 100644 --- a/admin/settings_company.php +++ b/admin/settings_company.php @@ -14,8 +14,12 @@ $company_address = escapeHtml($row['company_address']); $company_city = escapeHtml($row['company_city']); $company_state = escapeHtml($row['company_state']); $company_zip = escapeHtml($row['company_zip']); -$company_phone_country_code = formatPhoneNumber($row['company_phone_country_code']); -$company_phone = escapeHtml(formatPhoneNumber($row['company_phone'], $company_phone_country_code)); +// escapeHtml, not formatPhoneNumber - this is a dial code, not a number. +// The old call was a no-op (no $country_code arg means no reformatting) but +// it left the value unescaped on the way into a hidden input, unlike every +// sibling modal. +$company_phone_country_code = escapeHtml($row['company_phone_country_code']); +$company_phone = escapeHtml(formatPhoneNumber($row['company_phone'], $company_phone_country_code, false)); $company_email = escapeHtml($row['company_email']); $company_website = escapeHtml($row['company_website']); $company_logo = escapeHtml($row['company_logo']); diff --git a/agent/modals/contact/contact_edit.php b/agent/modals/contact/contact_edit.php index e8a7eb08d..ab0e6a260 100644 --- a/agent/modals/contact/contact_edit.php +++ b/agent/modals/contact/contact_edit.php @@ -37,9 +37,9 @@ $contact_title = escapeHtml($row['contact_title']); $contact_department = escapeHtml($row['contact_department']); $contact_extension = escapeHtml($row['contact_extension']); $contact_phone_country_code = escapeHtml($row['contact_phone_country_code']); -$contact_phone = escapeHtml(formatPhoneNumber($row['contact_phone'], $contact_phone_country_code)); +$contact_phone = escapeHtml(formatPhoneNumber($row['contact_phone'], $contact_phone_country_code, false)); $contact_mobile_country_code = escapeHtml($row['contact_mobile_country_code']); -$contact_mobile = escapeHtml(formatPhoneNumber($row['contact_mobile'], $contact_mobile_country_code)); +$contact_mobile = escapeHtml(formatPhoneNumber($row['contact_mobile'], $contact_mobile_country_code, false)); $contact_email = escapeHtml($row['contact_email']); $contact_pin = escapeHtml($row['contact_pin']); $contact_photo = escapeHtml($row['contact_photo']); diff --git a/agent/modals/location/location_edit.php b/agent/modals/location/location_edit.php index 3105f1366..a168cbc0c 100644 --- a/agent/modals/location/location_edit.php +++ b/agent/modals/location/location_edit.php @@ -21,10 +21,10 @@ $location_city = escapeHtml($row['location_city']); $location_state = escapeHtml($row['location_state']); $location_zip = escapeHtml($row['location_zip']); $location_phone_country_code = escapeHtml($row['location_phone_country_code']); -$location_phone = escapeHtml(formatPhoneNumber($row['location_phone'], $location_phone_country_code)); +$location_phone = escapeHtml(formatPhoneNumber($row['location_phone'], $location_phone_country_code, false)); $location_extension = escapeHtml($row['location_phone_extension']); $location_fax_country_code = escapeHtml($row['location_fax_country_code']); -$location_fax = escapeHtml(formatPhoneNumber($row['location_fax'], $location_fax_country_code)); +$location_fax = escapeHtml(formatPhoneNumber($row['location_fax'], $location_fax_country_code, false)); $location_hours = escapeHtml($row['location_hours']); $location_photo = escapeHtml($row['location_photo']); $location_notes = escapeHtml($row['location_notes']); diff --git a/agent/modals/vendor/vendor_edit.php b/agent/modals/vendor/vendor_edit.php index 801d611c9..e19fb2c4f 100644 --- a/agent/modals/vendor/vendor_edit.php +++ b/agent/modals/vendor/vendor_edit.php @@ -17,7 +17,7 @@ $vendor_description = escapeHtml($row['vendor_description']); $vendor_account_number = escapeHtml($row['vendor_account_number']); $vendor_contact_name = escapeHtml($row['vendor_contact_name']); $vendor_phone_country_code = escapeHtml($row['vendor_phone_country_code']); -$vendor_phone = escapeHtml(formatPhoneNumber($row['vendor_phone'], $vendor_phone_country_code)); +$vendor_phone = escapeHtml(formatPhoneNumber($row['vendor_phone'], $vendor_phone_country_code, false)); $vendor_extension = escapeHtml($row['vendor_extension']); $vendor_email = escapeHtml($row['vendor_email']); $vendor_website = escapeHtml($row['vendor_website']); diff --git a/functions/export.php b/functions/export.php index 2b1c7d371..f9d9f7a9d 100644 --- a/functions/export.php +++ b/functions/export.php @@ -384,7 +384,7 @@ function guardExportPdfRowCount($format, $num_rows) { * Presentation only. CSV keeps numbers raw so spreadsheets and importers still * see a number; the PDF is for reading, so it gets thousands separators. */ -function formatExportValue($value, $format, $output) { +function formatExportValue($value, $format, $output, $row = [], $field = '') { // An empty field is empty, whatever its format - a blank amount is not 0.00 if ($value === null || $value === '') { @@ -392,7 +392,10 @@ function formatExportValue($value, $format, $output) { } if ($format === 'phone') { - return formatPhoneNumber($value); + // Every phone column in the schema is paired with _country_code, + // and the export queries all select the table wholesale, so the code is + // already in the row - it just was not reachable from here before. + return formatPhoneNumber($value, $row[$field . '_country_code'] ?? ''); } if ($output === 'pdf' && $format === 'money') { @@ -701,7 +704,7 @@ function addExportRow(&$export, $row) { $export['missing'][$field] = true; } - $values[$column_key] = formatExportValue($row[$field] ?? '', $column['format'] ?? '', $export['format']); + $values[$column_key] = formatExportValue($row[$field] ?? '', $column['format'] ?? '', $export['format'], $row, $field); } if ($export['format'] === 'csv') { diff --git a/functions/format.php b/functions/format.php index 09c0e4d90..1caec710c 100644 --- a/functions/format.php +++ b/functions/format.php @@ -30,7 +30,20 @@ function truncate($text, $chars) { } -function formatPhoneNumber($phoneNumber, $country_code = '', $show_country_code = false) { +/** + * A number for reading. + * + * $show_country_code defaults to TRUE: a phone number on screen, in a PDF, in + * an email or in an export is being read by a human who may need to dial it, + * and a bare national number is ambiguous the moment a client is abroad. The + * dial code is only prepended when one is actually stored, so records without + * one look exactly as they did. + * + * Pass false where the output feeds a form INPUT - intl-tel-input runs in + * separateDialCode mode, so its dropdown owns the code and the field must hold + * the national number alone. Those are the only call sites that should. + */ +function formatPhoneNumber($phoneNumber, $country_code = '', $show_country_code = true) { // Remove all non-digit characters $digits = preg_replace('/\D/', '', $phoneNumber ?? ''); $formatted = '';