iachat/enterprise/app/services/captain/notifications/send_notification_service.rb
Rodrigo Borba 44908f32d1 feat: sistema de notificações de reserva com templates configuráveis
- Adiciona check_in_at/duration_hours ao schema do tool CreateReservationIntent
  para que a IA capture o horário EXATO de chegada informado pelo cliente
- Cria captain_notification_templates: label, content, timing_minutes,
  timing_direction (before/after), active, position
- Implementa SendNotificationService com interpolação de variáveis
  (guest_name, check_in_time, check_out_time, suite_name, unit_name)
- Implementa NotificationScannerJob (Sidekiq-cron a cada 5min) com
  janela de tolerância de ±5min e idempotência via metadata JSONB
- API REST: /captain/units/:unit_id/notification_templates (CRUD)
- Store Vuex captainNotificationTemplates + API client
- UI: página de gestão de templates com editor inline e botão '+'
- Configura rota captain_settings_notifications
- i18n PT/EN para todas as strings novas
- Rubocop e ESLint: zero offenses
2026-03-01 21:53:11 -03:00

55 lines
1.6 KiB
Ruby

class Captain::Notifications::SendNotificationService
VARIABLES = {
'{{guest_name}}' => ->(r) { r.contact.name.to_s },
'{{check_in_time}}' => ->(r) { r.check_in_at.strftime('%H:%M') },
'{{check_out_time}}' => ->(r) { r.check_out_at.strftime('%H:%M') },
'{{suite_name}}' => ->(r) { r.suite_identifier.to_s },
'{{unit_name}}' => ->(r) { r.unit&.name.to_s }
}.freeze
def initialize(reservation, template)
@reservation = reservation
@template = template
end
def perform
return unless @reservation.conversation_id?
rendered = render_content
send_message(rendered)
mark_template_sent
rescue StandardError => e
Rails.logger.error "[SendNotificationService] Failed for reservation #{@reservation.id}, template #{@template.id}: #{e.message}"
end
private
def render_content
content = @template.content.dup
VARIABLES.each do |placeholder, resolver|
content.gsub!(placeholder, resolver.call(@reservation))
end
content
end
def send_message(content)
conversation = @reservation.conversation
assistant = conversation.inbox&.captain_inbox&.assistant
conversation.messages.create!(
content: content,
message_type: :outgoing,
account: conversation.account,
inbox: conversation.inbox,
sender: assistant
)
end
def mark_template_sent
current_notified = @reservation.metadata.to_h.fetch('notified_templates', [])
updated = (current_notified + [@template.id]).uniq
new_metadata = @reservation.metadata.to_h.merge('notified_templates' => updated)
@reservation.update!(metadata: new_metadata)
end
end