fix(whatsapp): normalize contact phone numbers to prevent Brazil duplicates
WhatsApp Coexistence echo messages from the native WhatsApp app deliver Brazilian numbers without the mobile 9th digit. The contact-resolution layer only deduplicated at the contact_inbox source_id level, so when no matching contact_inbox existed it fell back to an exact phone_number match using the un-normalized number, missing the existing contact stored with the 9th digit and creating a duplicate. Normalize the phone number used for contact lookup/creation via the existing Brazil/Argentina normalizers so both formats resolve to the same contact. Non-affected countries are returned unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
73ba0b26e5
commit
fe4ba71cdf
@@ -76,11 +76,17 @@ module Whatsapp::IncomingMessageIdentifierHelper
|
||||
phone_number = whatsapp_phone_number(phone_identifier)
|
||||
return { name: name } if phone_number.blank?
|
||||
|
||||
formatted_phone_number = "+#{phone_number}"
|
||||
# Normalize before storing/matching so country-specific format variations (e.g. Brazil's
|
||||
# missing 9th digit) resolve to the same contact instead of creating duplicates.
|
||||
formatted_phone_number = "+#{normalized_phone_number(phone_number)}"
|
||||
display_name = name == phone_identifier ? formatted_phone_number : name
|
||||
{ name: display_name, phone_number: formatted_phone_number }
|
||||
end
|
||||
|
||||
def normalized_phone_number(phone_number)
|
||||
Whatsapp::PhoneNumberNormalizationService.new(inbox).normalize_number(phone_number)
|
||||
end
|
||||
|
||||
def update_whatsapp_identifiers(source_ids: [], username: nil, phone_number: nil)
|
||||
Whatsapp::IdentifierSyncService.new(contact_inbox: @contact_inbox, contact: @contact).perform(source_ids: source_ids, username: username,
|
||||
phone_number: phone_number)
|
||||
|
||||
@@ -29,6 +29,15 @@ class Whatsapp::PhoneNumberNormalizationService
|
||||
existing_contact_inbox&.source_id || raw_number
|
||||
end
|
||||
|
||||
# @param clean_number [String] Phone number in clean cloud format, e.g. "5541988887777"
|
||||
# @return [String] Country-normalized number, or the original when no normalizer applies
|
||||
def normalize_number(clean_number)
|
||||
normalizer = find_normalizer_for_country(clean_number)
|
||||
return clean_number unless normalizer
|
||||
|
||||
normalizer.normalize(clean_number)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :inbox
|
||||
|
||||
@@ -257,6 +257,41 @@ describe Whatsapp::IncomingMessageWhatsappCloudService do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when an echo (coexistence) message arrives for a Brazil number missing the 9th digit' do
|
||||
let(:echo_params) do
|
||||
{
|
||||
object: 'whatsapp_business_account',
|
||||
entry: [{
|
||||
changes: [{
|
||||
field: 'smb_message_echoes',
|
||||
value: {
|
||||
message_echoes: [{
|
||||
from: whatsapp_channel.phone_number.delete('+'),
|
||||
to: '551112345678',
|
||||
id: 'wamid.ECHO_MESSAGE_ID',
|
||||
timestamp: '1664799904',
|
||||
text: { body: 'Reply from the WhatsApp app' },
|
||||
type: 'text'
|
||||
}]
|
||||
}
|
||||
}]
|
||||
}]
|
||||
}.with_indifferent_access
|
||||
end
|
||||
|
||||
it 'reuses the existing contact stored with the normalized phone number instead of duplicating it' do
|
||||
existing_contact = create(:contact, phone_number: '+5511912345678', account: whatsapp_channel.account)
|
||||
|
||||
expect do
|
||||
described_class.new(inbox: whatsapp_channel.inbox, params: echo_params, outgoing_echo: true).perform
|
||||
end.not_to change(Contact, :count)
|
||||
|
||||
conversation = whatsapp_channel.inbox.conversations.last
|
||||
expect(conversation.contact).to eq(existing_contact)
|
||||
expect(conversation.messages.last.content).to eq('Reply from the WhatsApp app')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Métodos auxiliares para reduzir o tamanho do exemplo
|
||||
|
||||
Reference in New Issue
Block a user