## Description Move WhatsApp webhook callback override from WABA level to phone number level, allowing multiple phone numbers on the same WABA to have independent callback URLs. ## Type of change - [x] Bug fix (non-breaking change which fixes an issue) ## How Has This Been Tested? - Connect a WhatsApp Cloud inbox via embedded signup - Verify webhook setup succeeds and messages are received - Connect a second phone number on the same WABA — both should receive messages independently - Delete an inbox and verify only that phone number's override is cleared ## Checklist: - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my code - [x] I have commented on my code, particularly in hard-to-understand areas - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes --------- Co-authored-by: tds-1 <tds-1@users.noreply.github.com> Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
59 lines
2.0 KiB
Ruby
59 lines
2.0 KiB
Ruby
class Whatsapp::WebhookTeardownService
|
|
def initialize(channel)
|
|
@channel = channel
|
|
end
|
|
|
|
def perform
|
|
return unless should_teardown_webhook?
|
|
|
|
api_client = Whatsapp::FacebookApiClient.new(provider_config['api_key'])
|
|
|
|
clear_phone_number_override(api_client)
|
|
unsubscribe_app_if_last_inbox(api_client)
|
|
rescue StandardError => e
|
|
# before_destroy must never block a channel delete — log and move on.
|
|
Rails.logger.error "[WHATSAPP] Webhook teardown failed for channel #{@channel&.id}: #{e.message}"
|
|
end
|
|
|
|
private
|
|
|
|
def provider_config
|
|
@channel.provider_config || {}
|
|
end
|
|
|
|
def should_teardown_webhook?
|
|
@channel.provider == 'whatsapp_cloud' &&
|
|
provider_config['source'] == 'embedded_signup' &&
|
|
provider_config['api_key'].present? &&
|
|
(provider_config['phone_number_id'].present? || provider_config['business_account_id'].present?)
|
|
end
|
|
|
|
def clear_phone_number_override(api_client)
|
|
phone_number_id = provider_config['phone_number_id']
|
|
return if phone_number_id.blank?
|
|
|
|
api_client.clear_phone_number_callback_override(phone_number_id)
|
|
Rails.logger.info "[WHATSAPP] Phone-level webhook override cleared for channel #{@channel.id}"
|
|
rescue StandardError => e
|
|
Rails.logger.error "[WHATSAPP] Phone-level webhook clear failed for channel #{@channel.id}: #{e.message}"
|
|
end
|
|
|
|
# The app subscription is shared by every inbox on the WABA, so only unsubscribe when this is the last one.
|
|
def unsubscribe_app_if_last_inbox(api_client)
|
|
waba_id = provider_config['business_account_id']
|
|
return if waba_id.blank?
|
|
return if waba_sibling_exists?(waba_id)
|
|
|
|
api_client.unsubscribe_app_from_waba(waba_id)
|
|
Rails.logger.info "[WHATSAPP] WABA app subscription removed for channel #{@channel.id}"
|
|
rescue StandardError => e
|
|
Rails.logger.error "[WHATSAPP] WABA app unsubscribe failed for channel #{@channel.id}: #{e.message}"
|
|
end
|
|
|
|
def waba_sibling_exists?(waba_id)
|
|
Channel::Whatsapp
|
|
.where.not(id: @channel.id)
|
|
.exists?(["provider_config ->> 'business_account_id' = ?", waba_id])
|
|
end
|
|
end
|