Merge branch 'feat/whatsapp-call-incoming-pipeline' into feat/whatsapp-call-meta-bridge
This commit is contained in:
@@ -120,13 +120,25 @@ class Whatsapp::IncomingCallService
|
||||
next if call.terminal?
|
||||
|
||||
duration = payload[:duration]&.to_i
|
||||
status = answered?(call, duration) ? 'completed' : 'no_answer'
|
||||
reason = payload[:terminate_reason].to_s
|
||||
status = derive_terminate_status(call, duration, reason)
|
||||
meta = (call.meta || {}).merge('ended_at' => Time.zone.now.to_i)
|
||||
update_call!(call, status, duration_seconds: duration, end_reason: payload[:terminate_reason], meta: meta)
|
||||
update_call!(call, status, duration_seconds: duration, end_reason: reason, meta: meta)
|
||||
broadcast(call, 'voice_call.ended', status: call.display_status, duration_seconds: call.duration_seconds)
|
||||
end
|
||||
end
|
||||
|
||||
# Provider-reported failures trump the answered/no_answer heuristic. An
|
||||
# in_progress call that Meta later terminates with a failure reason would
|
||||
# otherwise be recorded as 'completed' purely because it had been accepted.
|
||||
FAILURE_REASONS = %w[failed error rejected busy invalid_offer cancelled].freeze
|
||||
|
||||
def derive_terminate_status(call, duration, reason)
|
||||
return 'failed' if FAILURE_REASONS.any? { |r| reason.include?(r) }
|
||||
|
||||
answered?(call, duration) ? 'completed' : 'no_answer'
|
||||
end
|
||||
|
||||
# accepted_by_agent_id is the initiating agent on outbound calls, so it only signals "answered" for inbound.
|
||||
def answered?(call, duration)
|
||||
call.in_progress? || duration.to_i.positive? || (call.incoming? && call.accepted_by_agent_id.present?)
|
||||
|
||||
@@ -104,6 +104,15 @@ describe Whatsapp::IncomingCallService do
|
||||
expect(call.reload.status).to eq('no_answer')
|
||||
end
|
||||
|
||||
it 'records the call as failed when Meta reports a failure reason for an in_progress call' do
|
||||
allow(ActionCable.server).to receive(:broadcast)
|
||||
|
||||
params = call_payload(event: 'terminate', duration: 12, terminate_reason: 'failed')
|
||||
described_class.new(inbox: inbox, params: params).perform
|
||||
|
||||
expect(call.reload).to have_attributes(status: 'failed', duration_seconds: 12, end_reason: 'failed')
|
||||
end
|
||||
|
||||
it 'is a no-op when the call is already terminal so retries cannot flip a completed call to no_answer' do
|
||||
call.update!(status: 'completed', duration_seconds: 5, direction: :outgoing, accepted_by_agent: nil)
|
||||
allow(ActionCable.server).to receive(:broadcast)
|
||||
|
||||
Reference in New Issue
Block a user