diff --git a/Gemfile b/Gemfile
index faec53f56..db3fd7c30 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,6 +1,6 @@
source 'https://rubygems.org'
-ruby '3.4.4'
+ruby '>= 3.4.4'
##-- base gems for rails --##
gem 'rack-cors', '2.0.0', require: 'rack/cors'
diff --git a/app/controllers/api/v1/accounts/captain/reports/insights_controller.rb b/app/controllers/api/v1/accounts/captain/reports/insights_controller.rb
index 2eb0f6746..bbf99a836 100644
--- a/app/controllers/api/v1/accounts/captain/reports/insights_controller.rb
+++ b/app/controllers/api/v1/accounts/captain/reports/insights_controller.rb
@@ -32,6 +32,10 @@ class Api::V1::Accounts::Captain::Reports::InsightsController < Api::V1::Account
unit_id = params[:unit_id].present? ? params[:unit_id].to_i : nil
inbox_id = params[:inbox_id].present? ? params[:inbox_id].to_i : nil
+ # Log parameters to help debugging
+ Rails.logger.info '[Captain::Reports::InsightsController] Generating insight ' \
+ "for Unit: #{unit_id}, Inbox: #{inbox_id}, Period: #{period_start} to #{period_end}"
+
enqueue_insight(unit_id, inbox_id, period_start, period_end)
end
# rubocop:enable Metrics/AbcSize
@@ -69,8 +73,10 @@ class Api::V1::Accounts::Captain::Reports::InsightsController < Api::V1::Account
end
def parse_date(param, default)
- param.present? ? Date.parse(param) : default
- rescue ArgumentError
+ return default if param.blank?
+
+ Date.parse(param.to_s)
+ rescue ArgumentError, TypeError
default
end
diff --git a/app/javascript/dashboard/i18n/locale/en/captain.json b/app/javascript/dashboard/i18n/locale/en/captain.json
index 51c47a848..9df5e7e22 100644
--- a/app/javascript/dashboard/i18n/locale/en/captain.json
+++ b/app/javascript/dashboard/i18n/locale/en/captain.json
@@ -54,10 +54,12 @@
"ACTIONS": "Actions"
},
"STATUS": {
- "DRAFT": "Draft",
+ "SCHEDULED": "Scheduled",
"PENDING_PAYMENT": "Awaiting payment",
- "CONFIRMED": "Confirmed",
- "CANCELLED": "Cancelled"
+ "ACTIVE": "Active",
+ "COMPLETED": "Completed",
+ "CANCELLED": "Cancelled",
+ "DRAFT": "Draft"
},
"ACTIONS": {
"OPEN_CONVERSATION": "Open conversation",
diff --git a/app/javascript/dashboard/i18n/locale/pt_BR/captain.json b/app/javascript/dashboard/i18n/locale/pt_BR/captain.json
index fcd34059c..bb43238c9 100644
--- a/app/javascript/dashboard/i18n/locale/pt_BR/captain.json
+++ b/app/javascript/dashboard/i18n/locale/pt_BR/captain.json
@@ -54,10 +54,13 @@
"ACTIONS": "Ações"
},
"STATUS": {
- "DRAFT": "Rascunho",
+ "SCHEDULED": "Agendado",
"PENDING_PAYMENT": "Aguardando pagamento",
+ "ACTIVE": "Ativa",
"CONFIRMED": "Confirmada",
- "CANCELLED": "Cancelada"
+ "COMPLETED": "Concluída",
+ "CANCELLED": "Cancelada",
+ "DRAFT": "Rascunho"
},
"ACTIONS": {
"OPEN_CONVERSATION": "Abrir conversa",
diff --git a/app/javascript/dashboard/routes/dashboard/captain/reservations/components/NewReservationModal.vue b/app/javascript/dashboard/routes/dashboard/captain/reservations/components/NewReservationModal.vue
index 3045c4b0d..b60fe1637 100644
--- a/app/javascript/dashboard/routes/dashboard/captain/reservations/components/NewReservationModal.vue
+++ b/app/javascript/dashboard/routes/dashboard/captain/reservations/components/NewReservationModal.vue
@@ -76,8 +76,8 @@ const statusOptions = computed(() => [
value: 'pending_payment',
},
{
- label: t('CAPTAIN_RESERVATIONS.STATUS.ACTIVE'),
- value: 'active',
+ label: t('CAPTAIN_RESERVATIONS.STATUS.CONFIRMED'),
+ value: 'confirmed',
},
]);
diff --git a/app/javascript/dashboard/routes/dashboard/settings/captain/reports/Index.vue b/app/javascript/dashboard/routes/dashboard/settings/captain/reports/Index.vue
index 1ade106f3..fdafc46bf 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/captain/reports/Index.vue
+++ b/app/javascript/dashboard/routes/dashboard/settings/captain/reports/Index.vue
@@ -33,13 +33,16 @@ const onFilterChange = async event => {
};
const onGenerateInsight = async () => {
+ if (uiFlags.value.isGenerating) return;
try {
await store.dispatch('captainReports/generateInsight', {
inbox_id: selectedInboxId.value,
});
useAlert(t('CAPTAIN_REPORTS.GENERATE.SUCCESS'));
- } catch {
- useAlert(t('CAPTAIN_REPORTS.GENERATE.ERROR'));
+ } catch (error) {
+ const errorMessage =
+ error?.response?.data?.message || t('CAPTAIN_REPORTS.GENERATE.ERROR');
+ useAlert(errorMessage);
}
};
@@ -103,6 +106,7 @@ const periodLabel = insight =>
@@ -240,6 +244,7 @@ const periodLabel = insight =>
diff --git a/app/javascript/dashboard/store/modules/captainReports.js b/app/javascript/dashboard/store/modules/captainReports.js
index 338c85b2b..278bce921 100644
--- a/app/javascript/dashboard/store/modules/captainReports.js
+++ b/app/javascript/dashboard/store/modules/captainReports.js
@@ -1,4 +1,4 @@
-import * as MutationTypes from '../mutation-types';
+import MutationTypes from '../mutation-types';
import CaptainReportsAPI from '../../api/captain/reports';
export const getters = {
diff --git a/enterprise/app/jobs/captain/reports/generate_insights_job.rb b/enterprise/app/jobs/captain/reports/generate_insights_job.rb
index f0f3eda2c..0936ffd1a 100644
--- a/enterprise/app/jobs/captain/reports/generate_insights_job.rb
+++ b/enterprise/app/jobs/captain/reports/generate_insights_job.rb
@@ -4,6 +4,10 @@ class Captain::Reports::GenerateInsightsJob < ApplicationJob
# Gera insights de IA para uma unidade ou inbox específica em um período.
# Pode ser disparado on-demand (botão na UI) ou pelo WeeklyInsightsJob.
def perform(account_id, unit_id, period_start, period_end, inbox_id = nil)
+ # Ensure dates are Date objects as they might be serialized as strings in Sidekiq
+ period_start = period_start.is_a?(String) ? Date.parse(period_start) : period_start
+ period_end = period_end.is_a?(String) ? Date.parse(period_end) : period_end
+
account = Account.find_by(id: account_id)
return unless account
diff --git a/enterprise/app/models/captain/reservation.rb b/enterprise/app/models/captain/reservation.rb
index c33483803..c84bf9fea 100644
--- a/enterprise/app/models/captain/reservation.rb
+++ b/enterprise/app/models/captain/reservation.rb
@@ -60,11 +60,11 @@ class Captain::Reservation < ApplicationRecord
belongs_to :contact
belongs_to :contact_inbox
belongs_to :conversation, class_name: '::Conversation', optional: true
- belongs_to :brand, class_name: 'Captain::Brand', foreign_key: 'captain_brand_id', optional: true
- belongs_to :unit, class_name: 'Captain::Unit', foreign_key: 'captain_unit_id', optional: true
+ belongs_to :brand, class_name: 'Captain::Brand', foreign_key: 'captain_brand_id', optional: true, inverse_of: false
+ belongs_to :unit, class_name: 'Captain::Unit', foreign_key: 'captain_unit_id', optional: true, inverse_of: false
belongs_to :current_pix_charge, class_name: 'Captain::PixCharge', optional: true
- enum status: { scheduled: 0, active: 1, completed: 2, cancelled: 3, pending_payment: 4, draft: 5 }
+ enum status: { scheduled: 0, active: 1, completed: 2, cancelled: 3, pending_payment: 4, draft: 5, confirmed: 6 }
validates :suite_identifier, presence: true
validates :check_in_at, presence: true