chatwoot-develop/app/services/whatsapp/incoming_message_wuzapi_service.rb
2026-01-20 13:16:32 -03:00

99 lines
3.3 KiB
Ruby

module Whatsapp
class IncomingMessageWuzapiService < IncomingMessageBaseService
def perform
parser = Whatsapp::Providers::Wuzapi::PayloadParser.new(params)
# 1. Message Type Check (V1: Text + Presence)
# Fail fast for unsupported types (like ReadReceipts)
return unless [:text, :chat_presence].include?(parser.message_type)
# 2. V1 Scope: Ignore Groups
if parser.group_message?
Rails.logger.info "WuzAPI: Ignoring group message (ID: #{parser.external_id})"
return
end
# 3. Strong Dedupe (Critical for Sync)
# Skip dedupe for ChatPresence as it doesn't have a unique ID
if parser.message_type != :chat_presence && parser.external_id.present? && Message.exists?(source_id: parser.external_id, inbox_id: inbox.id)
Rails.logger.info "WuzAPI: Ignoring duplicate message (ID: #{parser.external_id})"
return
end
if parser.sender_phone_number.blank?
Rails.logger.warn "WuzAPI: Skipping processing for event with no valid phone (Type: #{parser.message_type})"
return
end
# 4. Process
Rails.logger.info "WuzAPI: Processing message from #{parser.sender_phone_number} (Type: #{parser.message_type})"
ActiveRecord::Base.transaction do
@contact = find_or_create_contact(parser)
Rails.logger.info "WuzAPI: Contact found/created: #{@contact.id}"
@conversation = find_or_create_conversation(@contact)
Rails.logger.info "WuzAPI: Conversation found/created: #{@conversation.id}"
if parser.message_type == :chat_presence
status = parser.presence_state == 'composing' ? 'on' : 'off'
@conversation.toggle_typing_status(status)
return
end
message = create_message(parser, @conversation)
Rails.logger.info "WuzAPI: Message created: #{message.id}"
end
rescue StandardError => e
Rails.logger.error "WuzAPI Error: #{e.message}"
Rails.logger.error e.backtrace.join("\n")
raise e
end
private
def find_or_create_contact(parser)
# Normalize phone
phone = parser.sender_phone_number
normalized_phone = "+#{phone}"
contact_inbox = ::ContactInboxWithContactBuilder.new(
source_id: phone,
inbox: inbox,
contact_attributes: {
name: parser.push_name || phone,
phone_number: normalized_phone
}
).perform
contact_inbox.contact
end
def find_or_create_conversation(contact)
conversation = inbox.conversations.where(contact_id: contact.id)
.where.not(status: :resolved)
.last
conversation || ::Conversation.create!(
account_id: inbox.account_id,
inbox_id: inbox.id,
contact_id: contact.id,
contact_inbox_id: ContactInbox.find_by(contact_id: contact.id, inbox_id: inbox.id)&.id
)
end
def create_message(parser, conversation)
is_outgoing = parser.from_me?
conversation.messages.create!(
content: parser.text_content,
account_id: inbox.account_id,
inbox_id: inbox.id,
message_type: is_outgoing ? :outgoing : :incoming,
sender: is_outgoing ? nil : @contact,
source_id: parser.external_id,
created_at: parser.timestamp
)
end
end
end