Melhorias na ferramenta send_suite_images para resolver confusão entre categoria e número de suíte: 1. **Descrições de parâmetros mais claras** - suite_category: exemplos específicos (Hidromassagem, ALEXA, STILO) - suite_number: apenas números (101, 102, 103) - remove exemplos confusos 2. **Instruções explícitas no system prompt** - Seção [Galeria de Fotos] com regras claras - Prioriza suite_category quando ambíguo - Evita confirmações desnecessárias com cliente 3. **Mensagens de erro melhoradas** - Sugere buscar por categoria quando busca por número falha - Feedback mais útil para a IA Resultado esperado: - Cliente: "Me manda foto da suite Alexa" - IA: busca por suite_category="Alexa" ✓ (sem pedir confirmação) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
92 lines
2.6 KiB
Ruby
92 lines
2.6 KiB
Ruby
class Captain::Reports::DailySnapshotJob < ApplicationJob
|
|
queue_as :scheduled_jobs
|
|
|
|
# Roda todo dia à meia-noite via Sidekiq-Cron.
|
|
# Salva um snapshot dos dados operacionais de ontem por unidade.
|
|
def perform
|
|
date = Date.yesterday
|
|
|
|
Account.find_each do |account|
|
|
save_snapshot(account, nil, date)
|
|
|
|
account.captain_units.find_each do |unit|
|
|
save_snapshot(account, unit, date)
|
|
end
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def save_snapshot(account, unit, date)
|
|
data = build_snapshot_data(account, unit, date)
|
|
|
|
Captain::ReportSnapshot.find_or_create_by!(
|
|
account_id: account.id,
|
|
captain_unit_id: unit&.id,
|
|
snapshot_date: date
|
|
) do |snap|
|
|
snap.data = data
|
|
end
|
|
end
|
|
|
|
# rubocop:disable Metrics/MethodLength
|
|
def build_snapshot_data(account, unit, date)
|
|
conversations = base_conversations(account, unit, date)
|
|
reservations = base_reservations(account, unit, date)
|
|
|
|
{
|
|
date: date.to_s,
|
|
unit_id: unit&.id,
|
|
unit_name: unit&.name,
|
|
conversations: {
|
|
total: conversations.count,
|
|
resolved: conversations.where(status: 'resolved').count,
|
|
open: conversations.where(status: 'open').count,
|
|
avg_resolution_minutes: avg_resolution(conversations)
|
|
},
|
|
reservations: {
|
|
total: reservations.count,
|
|
paid: reservations.where(status: 'paid').count,
|
|
expired: reservations.where(status: 'expired').count,
|
|
pending: reservations.where(status: %w[pending waiting]).count,
|
|
total_amount_cents: reservations.where(status: 'paid').sum(:amount_cents)
|
|
}
|
|
}
|
|
end
|
|
# rubocop:enable Metrics/MethodLength
|
|
|
|
def base_conversations(account, unit, date)
|
|
scope = account.conversations.where(created_at: date.all_day)
|
|
if unit
|
|
inbox_ids = unit.inboxes.pluck(:id)
|
|
scope = scope.where(inbox_id: inbox_ids) if inbox_ids.any?
|
|
end
|
|
scope
|
|
end
|
|
|
|
def base_reservations(account, unit, date)
|
|
scope = begin
|
|
account.captain_reservations.where(created_at: date.all_day)
|
|
rescue StandardError
|
|
account.captain_units.joins(:reservations).merge(Captain::Reservation.where(created_at: date.all_day))
|
|
end
|
|
scope = scope.where(captain_unit_id: unit.id) if unit
|
|
scope
|
|
rescue StandardError
|
|
Captain::Reservation.none
|
|
end
|
|
|
|
def avg_resolution(conversations)
|
|
resolved = conversations.where.not(first_reply_created_at: nil)
|
|
return 0 if resolved.none?
|
|
|
|
total_minutes = resolved.sum do |c|
|
|
next 0 unless c.first_reply_created_at
|
|
|
|
((c.updated_at - c.created_at) / 60).round
|
|
end
|
|
|
|
(total_minutes / resolved.count).round
|
|
end
|
|
end
|