- Enables outbound voice calls in voice channel . We are only caring about wiring the logic to trigger outgoing calls to the call button introduced in previous PRs. We will connect it to call component in subsequent PRs ref: #11602 ## Screens <img width="2304" height="1202" alt="image" src="https://github.com/user-attachments/assets/b91543a8-8d4e-4229-bd80-9727b42c7b0f" /> <img width="2304" height="1200" alt="image" src="https://github.com/user-attachments/assets/1a1dad2a-8cb2-4aa2-9702-c062416556a7" /> --------- Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Co-authored-by: iamsivin <iamsivin@gmail.com> Co-authored-by: Vishnu Narayanan <vishnu@chatwoot.com>
99 lines
2.6 KiB
Ruby
99 lines
2.6 KiB
Ruby
class Voice::OutboundCallBuilder
|
|
attr_reader :account, :inbox, :user, :contact
|
|
|
|
def self.perform!(account:, inbox:, user:, contact:)
|
|
new(account: account, inbox: inbox, user: user, contact: contact).perform!
|
|
end
|
|
|
|
def initialize(account:, inbox:, user:, contact:)
|
|
@account = account
|
|
@inbox = inbox
|
|
@user = user
|
|
@contact = contact
|
|
end
|
|
|
|
def perform!
|
|
raise ArgumentError, 'Contact phone number required' if contact.phone_number.blank?
|
|
raise ArgumentError, 'Agent required' if user.blank?
|
|
|
|
timestamp = current_timestamp
|
|
|
|
ActiveRecord::Base.transaction do
|
|
contact_inbox = ensure_contact_inbox!
|
|
conversation = create_conversation!(contact_inbox)
|
|
conversation.reload
|
|
conference_sid = Voice::Conference::Name.for(conversation)
|
|
call_sid = initiate_call!
|
|
update_conversation!(conversation, call_sid, conference_sid, timestamp)
|
|
build_voice_message!(conversation, call_sid, conference_sid, timestamp)
|
|
{ conversation: conversation, call_sid: call_sid }
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def ensure_contact_inbox!
|
|
ContactInbox.find_or_create_by!(
|
|
contact_id: contact.id,
|
|
inbox_id: inbox.id
|
|
) do |record|
|
|
record.source_id = contact.phone_number
|
|
end
|
|
end
|
|
|
|
def create_conversation!(contact_inbox)
|
|
account.conversations.create!(
|
|
contact_inbox_id: contact_inbox.id,
|
|
inbox_id: inbox.id,
|
|
contact_id: contact.id,
|
|
status: :open
|
|
)
|
|
end
|
|
|
|
def initiate_call!
|
|
inbox.channel.initiate_call(
|
|
to: contact.phone_number
|
|
)[:call_sid]
|
|
end
|
|
|
|
def update_conversation!(conversation, call_sid, conference_sid, timestamp)
|
|
attrs = {
|
|
'call_direction' => 'outbound',
|
|
'call_status' => 'ringing',
|
|
'agent_id' => user.id,
|
|
'conference_sid' => conference_sid,
|
|
'meta' => { 'initiated_at' => timestamp }
|
|
}
|
|
|
|
conversation.update!(
|
|
identifier: call_sid,
|
|
additional_attributes: attrs,
|
|
last_activity_at: current_time
|
|
)
|
|
end
|
|
|
|
def build_voice_message!(conversation, call_sid, conference_sid, timestamp)
|
|
Voice::CallMessageBuilder.perform!(
|
|
conversation: conversation,
|
|
direction: 'outbound',
|
|
payload: {
|
|
call_sid: call_sid,
|
|
status: 'ringing',
|
|
conference_sid: conference_sid,
|
|
from_number: inbox.channel&.phone_number,
|
|
to_number: contact.phone_number
|
|
},
|
|
user: user,
|
|
timestamps: { created_at: timestamp, ringing_at: timestamp }
|
|
)
|
|
end
|
|
|
|
def current_timestamp
|
|
@current_timestamp ||= current_time.to_i
|
|
end
|
|
|
|
def current_time
|
|
@current_time ||= Time.zone.now
|
|
end
|
|
end
|