fix(voice): resolve contact via source_id and i18n call message bubble
This commit is contained in:
@@ -244,6 +244,9 @@ en:
|
||||
whatsapp:
|
||||
list_button_label: 'Choose an item'
|
||||
call_permission_request_body: 'We would like to call you regarding your conversation.'
|
||||
voice_call:
|
||||
twilio: 'Voice Call'
|
||||
whatsapp: 'WhatsApp Call'
|
||||
delivery_status:
|
||||
error_code: 'Error code: %{error_code}'
|
||||
activity:
|
||||
|
||||
@@ -27,7 +27,7 @@ class Voice::CallMessageBuilder
|
||||
|
||||
def create_message!
|
||||
params = {
|
||||
content: 'Voice Call',
|
||||
content: I18n.t("conversations.messages.voice_call.#{call.provider}"),
|
||||
message_type: call.outgoing? ? 'outgoing' : 'incoming',
|
||||
content_type: 'voice_call',
|
||||
content_attributes: { 'data' => build_data_payload }
|
||||
|
||||
@@ -19,8 +19,8 @@ class Voice::InboundCallBuilder
|
||||
return existing if existing
|
||||
|
||||
ActiveRecord::Base.transaction do
|
||||
contact = ensure_contact!
|
||||
contact_inbox = ensure_contact_inbox!(contact)
|
||||
contact_inbox = ensure_contact_inbox!
|
||||
contact = contact_inbox.contact
|
||||
conversation = resolve_conversation!(contact, contact_inbox)
|
||||
call = create_call!(contact, conversation)
|
||||
message = Voice::CallMessageBuilder.new(call).perform!
|
||||
@@ -43,21 +43,23 @@ class Voice::InboundCallBuilder
|
||||
.find_by(provider: provider, provider_call_id: call_sid)
|
||||
end
|
||||
|
||||
# Always look up by (inbox, source_id) first — that pair has a UNIQUE index, so
|
||||
# creating with a colliding source_id under a different contact would raise
|
||||
# RecordNotUnique. Reuse the existing ContactInbox (and its contact) when found.
|
||||
def ensure_contact_inbox!
|
||||
sid = source_id_for_provider
|
||||
existing = inbox.contact_inboxes.find_by(source_id: sid)
|
||||
return existing if existing
|
||||
|
||||
ContactInbox.create!(contact: ensure_contact!, inbox: inbox, source_id: sid)
|
||||
end
|
||||
|
||||
def ensure_contact!
|
||||
account.contacts.find_or_create_by!(phone_number: from_number) do |record|
|
||||
record.name = from_number if record.name.blank?
|
||||
end
|
||||
end
|
||||
|
||||
def ensure_contact_inbox!(contact)
|
||||
ContactInbox.find_or_create_by!(
|
||||
contact_id: contact.id,
|
||||
inbox_id: inbox.id
|
||||
) do |record|
|
||||
record.source_id = source_id_for_provider
|
||||
end
|
||||
end
|
||||
|
||||
# WhatsApp ContactInbox.source_id must be digits-only (the wa_id); Twilio accepts the +.
|
||||
def source_id_for_provider
|
||||
provider == :whatsapp ? from_number.to_s.delete_prefix('+') : from_number
|
||||
|
||||
@@ -29,10 +29,10 @@ class Whatsapp::CallPermissionReplyService
|
||||
{ from_number: message[:from], accepted: accepted }
|
||||
end
|
||||
|
||||
# WhatsApp routing is anchored on contact_inboxes.source_id (the wa_id), not on
|
||||
# contacts.phone_number — phone numbers can drift via normalization or edits.
|
||||
def find_contact(from_number)
|
||||
inbox.contact_inboxes.joins(:contact)
|
||||
.where(contacts: { phone_number: "+#{from_number}" })
|
||||
.first&.contact
|
||||
inbox.contact_inboxes.find_by(source_id: from_number)&.contact
|
||||
end
|
||||
|
||||
# Filter to threads that actually requested permission; multiple open threads otherwise hit the wrong one.
|
||||
|
||||
@@ -86,6 +86,20 @@ RSpec.describe Voice::InboundCallBuilder do
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a ContactInbox already exists for the source_id (different contact)' do
|
||||
let!(:original_contact) { create(:contact, account: account, phone_number: '+15550009999') }
|
||||
let!(:original_contact_inbox) do
|
||||
create(:contact_inbox, contact: original_contact, inbox: inbox, source_id: from_number)
|
||||
end
|
||||
|
||||
it 'reuses the existing ContactInbox instead of raising RecordNotUnique' do
|
||||
call = perform_builder
|
||||
|
||||
expect(call.contact).to eq(original_contact)
|
||||
expect(call.conversation.contact_inbox).to eq(original_contact_inbox)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the inbox has lock_to_single_conversation enabled' do
|
||||
let!(:contact) { create(:contact, account: account, phone_number: from_number) }
|
||||
let!(:contact_inbox) { create(:contact_inbox, contact: contact, inbox: inbox, source_id: from_number) }
|
||||
|
||||
Reference in New Issue
Block a user