From 2e95d3a173a5abccae86290d080a3abe934161f4 Mon Sep 17 00:00:00 2001 From: Jacson Santos <87338089+jacsonsantospht@users.noreply.github.com> Date: Mon, 13 Mar 2023 04:50:53 -0300 Subject: [PATCH] fix: Duplicate conversations and contacts WA and Brazil numbers (#6222) Resolves issue when receiving a message from Brazil Whatsapp number. Fixes: #5840 Co-authored-by: Sojan --- .../whatsapp/incoming_message_base_service.rb | 4 +- .../incoming_message_service_helpers.rb | 32 +++++++++ .../whatsapp/incoming_message_service_spec.rb | 66 ++++++++++++++++++- 3 files changed, 99 insertions(+), 3 deletions(-) diff --git a/app/services/whatsapp/incoming_message_base_service.rb b/app/services/whatsapp/incoming_message_base_service.rb index 83a82a3b1..193cfce69 100644 --- a/app/services/whatsapp/incoming_message_base_service.rb +++ b/app/services/whatsapp/incoming_message_base_service.rb @@ -84,8 +84,10 @@ class Whatsapp::IncomingMessageBaseService contact_params = @processed_params[:contacts]&.first return if contact_params.blank? + waid = processed_waid(contact_params[:wa_id]) + contact_inbox = ::ContactInboxWithContactBuilder.new( - source_id: contact_params[:wa_id], + source_id: waid, inbox: inbox, contact_attributes: { name: contact_params.dig(:profile, :name), phone_number: "+#{@processed_params[:messages].first[:from]}" } ).perform diff --git a/app/services/whatsapp/incoming_message_service_helpers.rb b/app/services/whatsapp/incoming_message_service_helpers.rb index cdf260b4a..099f9e88f 100644 --- a/app/services/whatsapp/incoming_message_service_helpers.rb +++ b/app/services/whatsapp/incoming_message_service_helpers.rb @@ -47,6 +47,38 @@ module Whatsapp::IncomingMessageServiceHelpers %w[reaction ephemeral unsupported].include?(message_type) end + def brazil_phone_number?(phone_number) + phone_number.match(/^55/) + end + + # ref: https://github.com/chatwoot/chatwoot/issues/5840 + def normalised_brazil_mobile_number(phone_number) + # DDD : Area codes in Brazil are popularly known as "DDD codes" (códigos DDD) or simply "DDD", from the initials of "direct distance dialing" + # https://en.wikipedia.org/wiki/Telephone_numbers_in_Brazil + ddd = phone_number[2, 2] + # Remove country code and DDD to obtain the number + number = phone_number[4, phone_number.length - 4] + normalised_number = "55#{ddd}#{number}" + # insert 9 to convert the number to the new mobile number format + normalised_number = "55#{ddd}9#{number}" if normalised_number.length != 13 + normalised_number + end + + def processed_waid(waid) + # in case of Brazil, we need to do additional processing + # https://github.com/chatwoot/chatwoot/issues/5840 + if brazil_phone_number?(waid) + # check if there is an existing contact inbox with the normalised waid + # We will create conversation against it + contact_inbox = inbox.contact_inboxes.find_by(source_id: normalised_brazil_mobile_number(waid)) + + # if there is no contact inbox with the waid without 9, + # We will create contact inboxes and contacts with the number 9 added + waid = contact_inbox.source_id if contact_inbox.present? + end + waid + end + def error_webhook_event?(message) message.key?('errors') end diff --git a/spec/services/whatsapp/incoming_message_service_spec.rb b/spec/services/whatsapp/incoming_message_service_spec.rb index 9c2ee9127..b2bd87d18 100644 --- a/spec/services/whatsapp/incoming_message_service_spec.rb +++ b/spec/services/whatsapp/incoming_message_service_spec.rb @@ -7,10 +7,11 @@ describe Whatsapp::IncomingMessageService do end let!(:whatsapp_channel) { create(:channel_whatsapp, sync_templates: false) } + let(:wa_id) { '2423423243' } let!(:params) do { - 'contacts' => [{ 'profile' => { 'name' => 'Sojan Jose' }, 'wa_id' => '2423423243' }], - 'messages' => [{ 'from' => '2423423243', 'id' => 'SDFADSf23sfasdafasdfa', 'text' => { 'body' => 'Test' }, + 'contacts' => [{ 'profile' => { 'name' => 'Sojan Jose' }, 'wa_id' => wa_id }], + 'messages' => [{ 'from' => wa_id, 'id' => 'SDFADSf23sfasdafasdfa', 'text' => { 'body' => 'Test' }, 'timestamp' => '1633034394', 'type' => 'text' }] }.with_indifferent_access end @@ -246,5 +247,66 @@ describe Whatsapp::IncomingMessageService do expect(contact_attachments.fallback_title).to eq('+1 (415) 341-8386') end end + + # ref: https://github.com/chatwoot/chatwoot/issues/5840 + describe 'When the incoming waid is a brazilian number in new format with 9 included' do + let(:wa_id) { '5541988887777' } + + it 'creates appropriate conversations, message and contacts if contact does not exit' do + described_class.new(inbox: whatsapp_channel.inbox, params: params).perform + expect(whatsapp_channel.inbox.conversations.count).not_to eq(0) + expect(Contact.all.first.name).to eq('Sojan Jose') + expect(whatsapp_channel.inbox.messages.first.content).to eq('Test') + expect(whatsapp_channel.inbox.contact_inboxes.first.source_id).to eq(wa_id) + end + + it 'appends to existing contact if contact inbox exists' do + contact_inbox = create(:contact_inbox, inbox: whatsapp_channel.inbox, source_id: wa_id) + last_conversation = create(:conversation, inbox: whatsapp_channel.inbox, contact_inbox: contact_inbox) + described_class.new(inbox: whatsapp_channel.inbox, params: params).perform + # no new conversation should be created + expect(whatsapp_channel.inbox.conversations.count).to eq(1) + # message appended to the last conversation + expect(last_conversation.messages.last.content).to eq(params[:messages].first[:text][:body]) + end + end + + describe 'When incoming waid is a brazilian number in old format without the 9 included' do + let(:wa_id) { '554188887777' } + + context 'when a contact inbox exists in the old format without 9 included' do + it 'appends to existing contact' do + contact_inbox = create(:contact_inbox, inbox: whatsapp_channel.inbox, source_id: wa_id) + last_conversation = create(:conversation, inbox: whatsapp_channel.inbox, contact_inbox: contact_inbox) + described_class.new(inbox: whatsapp_channel.inbox, params: params).perform + # no new conversation should be created + expect(whatsapp_channel.inbox.conversations.count).to eq(1) + # message appended to the last conversation + expect(last_conversation.messages.last.content).to eq(params[:messages].first[:text][:body]) + end + end + + context 'when a contact inbox exists in the new format with 9 included' do + it 'appends to existing contact' do + contact_inbox = create(:contact_inbox, inbox: whatsapp_channel.inbox, source_id: '5541988887777') + last_conversation = create(:conversation, inbox: whatsapp_channel.inbox, contact_inbox: contact_inbox) + described_class.new(inbox: whatsapp_channel.inbox, params: params).perform + # no new conversation should be created + expect(whatsapp_channel.inbox.conversations.count).to eq(1) + # message appended to the last conversation + expect(last_conversation.messages.last.content).to eq(params[:messages].first[:text][:body]) + end + end + + context 'when a contact inbox does not exist in the new format with 9 included' do + it 'creates contact inbox with the incoming waid' do + described_class.new(inbox: whatsapp_channel.inbox, params: params).perform + expect(whatsapp_channel.inbox.conversations.count).not_to eq(0) + expect(Contact.all.first.name).to eq('Sojan Jose') + expect(whatsapp_channel.inbox.messages.first.content).to eq('Test') + expect(whatsapp_channel.inbox.contact_inboxes.first.source_id).to eq(wa_id) + end + end + end end end