From dbb164a37de765e509388a033dc415a8eddcec82 Mon Sep 17 00:00:00 2001 From: Muhsin Keloth Date: Tue, 12 Aug 2025 16:31:56 +0530 Subject: [PATCH] fix: Improve WhatsApp template message error handling (#12168) WhatsApp template message errors were not being properly handled because the `@message instance` variable was only set in the `send_message` method but not in `send_template`. When template sending failed, the `handle_error` method couldn't update the message status due to the missing @message reference, resulting in silent failures with no user feedback. --- app/services/whatsapp/oneoff_campaign_service.rb | 2 +- app/services/whatsapp/providers/base_service.rb | 16 ++++++++-------- .../providers/whatsapp_360_dialog_service.rb | 10 +++++----- .../whatsapp/providers/whatsapp_cloud_service.rb | 10 +++++----- .../whatsapp/send_on_whatsapp_service.rb | 2 +- .../whatsapp/oneoff_campaign_service_spec.rb | 7 ++++--- .../providers/whatsapp_cloud_service_spec.rb | 6 +++--- 7 files changed, 27 insertions(+), 26 deletions(-) diff --git a/app/services/whatsapp/oneoff_campaign_service.rb b/app/services/whatsapp/oneoff_campaign_service.rb index 47a971f41..de2713ac0 100644 --- a/app/services/whatsapp/oneoff_campaign_service.rb +++ b/app/services/whatsapp/oneoff_campaign_service.rb @@ -84,7 +84,7 @@ class Whatsapp::OneoffCampaignService namespace: namespace, lang_code: lang_code, parameters: processed_parameters - }) + }, nil) rescue StandardError => e Rails.logger.error "Failed to send WhatsApp template message to #{to}: #{e.message}" diff --git a/app/services/whatsapp/providers/base_service.rb b/app/services/whatsapp/providers/base_service.rb index 97665f7ef..9fd1f6267 100644 --- a/app/services/whatsapp/providers/base_service.rb +++ b/app/services/whatsapp/providers/base_service.rb @@ -15,7 +15,7 @@ class Whatsapp::Providers::BaseService raise 'Overwrite this method in child class' end - def send_template(_phone_number, _template_info) + def send_template(_phone_number, _template_info, _message) raise 'Overwrite this method in child class' end @@ -31,27 +31,27 @@ class Whatsapp::Providers::BaseService raise 'Overwrite this method in child class' end - def process_response(response) + def process_response(response, message) parsed_response = response.parsed_response if response.success? && parsed_response['error'].blank? parsed_response['messages'].first['id'] else - handle_error(response) + handle_error(response, message) nil end end - def handle_error(response) + def handle_error(response, message) Rails.logger.error response.body - return if @message.blank? + return if message.blank? # https://developers.facebook.com/docs/whatsapp/cloud-api/support/error-codes/#sample-response error_message = error_message(response) return if error_message.blank? - @message.external_error = error_message - @message.status = :failed - @message.save! + message.external_error = error_message + message.status = :failed + message.save! end def create_buttons(items) diff --git a/app/services/whatsapp/providers/whatsapp_360_dialog_service.rb b/app/services/whatsapp/providers/whatsapp_360_dialog_service.rb index beb11d556..352f2d246 100644 --- a/app/services/whatsapp/providers/whatsapp_360_dialog_service.rb +++ b/app/services/whatsapp/providers/whatsapp_360_dialog_service.rb @@ -10,7 +10,7 @@ class Whatsapp::Providers::Whatsapp360DialogService < Whatsapp::Providers::BaseS end end - def send_template(phone_number, template_info) + def send_template(phone_number, template_info, message) response = HTTParty.post( "#{api_base_path}/messages", headers: api_headers, @@ -21,7 +21,7 @@ class Whatsapp::Providers::Whatsapp360DialogService < Whatsapp::Providers::BaseS }.to_json ) - process_response(response) + process_response(response, message) end def sync_templates @@ -68,7 +68,7 @@ class Whatsapp::Providers::Whatsapp360DialogService < Whatsapp::Providers::BaseS }.to_json ) - process_response(response) + process_response(response, message) end def send_attachment_message(phone_number, message) @@ -90,7 +90,7 @@ class Whatsapp::Providers::Whatsapp360DialogService < Whatsapp::Providers::BaseS }.to_json ) - process_response(response) + process_response(response, message) end def error_message(response) @@ -123,6 +123,6 @@ class Whatsapp::Providers::Whatsapp360DialogService < Whatsapp::Providers::BaseS }.to_json ) - process_response(response) + process_response(response, message) end end diff --git a/app/services/whatsapp/providers/whatsapp_cloud_service.rb b/app/services/whatsapp/providers/whatsapp_cloud_service.rb index 34939048a..68e965595 100644 --- a/app/services/whatsapp/providers/whatsapp_cloud_service.rb +++ b/app/services/whatsapp/providers/whatsapp_cloud_service.rb @@ -11,7 +11,7 @@ class Whatsapp::Providers::WhatsappCloudService < Whatsapp::Providers::BaseServi end end - def send_template(phone_number, template_info) + def send_template(phone_number, template_info, message) template_body = template_body_parameters(template_info) request_body = { @@ -28,7 +28,7 @@ class Whatsapp::Providers::WhatsappCloudService < Whatsapp::Providers::BaseServi body: request_body.to_json ) - process_response(response) + process_response(response, message) end def sync_templates @@ -92,7 +92,7 @@ class Whatsapp::Providers::WhatsappCloudService < Whatsapp::Providers::BaseServi }.to_json ) - process_response(response) + process_response(response, message) end def send_attachment_message(phone_number, message) @@ -115,7 +115,7 @@ class Whatsapp::Providers::WhatsappCloudService < Whatsapp::Providers::BaseServi }.to_json ) - process_response(response) + process_response(response, message) end def error_message(response) @@ -179,6 +179,6 @@ class Whatsapp::Providers::WhatsappCloudService < Whatsapp::Providers::BaseServi }.to_json ) - process_response(response) + process_response(response, message) end end diff --git a/app/services/whatsapp/send_on_whatsapp_service.rb b/app/services/whatsapp/send_on_whatsapp_service.rb index 5f91bce16..20419c0cd 100644 --- a/app/services/whatsapp/send_on_whatsapp_service.rb +++ b/app/services/whatsapp/send_on_whatsapp_service.rb @@ -33,7 +33,7 @@ class Whatsapp::SendOnWhatsappService < Base::SendOnChannelService namespace: namespace, lang_code: lang_code, parameters: processed_parameters - }) + }, message) message.update!(source_id: message_id) if message_id.present? end diff --git a/spec/services/whatsapp/oneoff_campaign_service_spec.rb b/spec/services/whatsapp/oneoff_campaign_service_spec.rb index 599081e23..dd8d51c54 100644 --- a/spec/services/whatsapp/oneoff_campaign_service_spec.rb +++ b/spec/services/whatsapp/oneoff_campaign_service_spec.rb @@ -133,7 +133,8 @@ describe Whatsapp::OneoffCampaignService do ) ) ) - ) + ), + nil ) described_class.new(campaign: campaign).perform @@ -164,8 +165,8 @@ describe Whatsapp::OneoffCampaignService do allow(whatsapp_channel).to receive(:send_template).and_return(nil) - expect(whatsapp_channel).to receive(:send_template).with(contact_error.phone_number, anything).and_raise(StandardError, error_message) - expect(whatsapp_channel).to receive(:send_template).with(contact_success.phone_number, anything).once + expect(whatsapp_channel).to receive(:send_template).with(contact_error.phone_number, anything, nil).and_raise(StandardError, error_message) + expect(whatsapp_channel).to receive(:send_template).with(contact_success.phone_number, anything, nil).once expect(Rails.logger).to receive(:error) .with("Failed to send WhatsApp template message to #{contact_error.phone_number}: #{error_message}") diff --git a/spec/services/whatsapp/providers/whatsapp_cloud_service_spec.rb b/spec/services/whatsapp/providers/whatsapp_cloud_service_spec.rb index 8735ccfbb..69ba69379 100644 --- a/spec/services/whatsapp/providers/whatsapp_cloud_service_spec.rb +++ b/spec/services/whatsapp/providers/whatsapp_cloud_service_spec.rb @@ -187,7 +187,7 @@ describe Whatsapp::Providers::WhatsappCloudService do ) .to_return(status: 200, body: whatsapp_response.to_json, headers: response_headers) - expect(service.send_template('+123456789', template_info)).to eq('message_id') + expect(service.send_template('+123456789', template_info, message)).to eq('message_id') end end end @@ -287,7 +287,7 @@ describe Whatsapp::Providers::WhatsappCloudService do context 'when there is a message' do it 'logs error and updates message status' do service.instance_variable_set(:@message, message) - service.send(:handle_error, error_response_object) + service.send(:handle_error, error_response_object, message) expect(message.reload.status).to eq('failed') expect(message.reload.external_error).to eq(error_message) @@ -305,7 +305,7 @@ describe Whatsapp::Providers::WhatsappCloudService do it 'logs error but does not update message' do service.instance_variable_set(:@message, message) - service.send(:handle_error, error_response_object) + service.send(:handle_error, error_response_object, message) expect(message.reload.status).not_to eq('failed') expect(message.reload.external_error).to be_nil