fix(captain/reservations): prioritize confirmed bookings

This commit is contained in:
Codex CLI 2026-05-03 11:03:01 +00:00
parent c954f0fab4
commit d670c5644b
8 changed files with 66 additions and 13 deletions

View File

@ -45,7 +45,7 @@
"HIDE": "Ocultar filtros"
},
"KPI": {
"TOTAL": "Total na página",
"TOTAL": "Total filtrado",
"PENDING_PIX": "Aguardando PIX",
"CHECKIN_TODAY": "Check-in hoje",
"REVENUE_TODAY": "Receita hoje"

View File

@ -102,7 +102,7 @@ const groupedReservations = computed(() => {
return groups;
});
const statusCounts = computed(() => {
const pageStatusCounts = computed(() => {
const counts = {
all: reservations.value.length,
draft: 0,
@ -117,6 +117,23 @@ const statusCounts = computed(() => {
return counts;
});
const statusCounts = computed(() => {
const metaCounts = reservationsMeta.value.statusCounts || {};
return {
all: Number(
metaCounts.all ??
reservationsMeta.value.totalCount ??
pageStatusCounts.value.all
),
draft: Number(metaCounts.draft ?? pageStatusCounts.value.draft),
pending_payment: Number(
metaCounts.pending_payment ?? pageStatusCounts.value.pending_payment
),
confirmed: Number(metaCounts.confirmed ?? pageStatusCounts.value.confirmed),
cancelled: Number(metaCounts.cancelled ?? pageStatusCounts.value.cancelled),
};
});
const todayRevenue = computed(() => {
const today = new Date();
today.setHours(0, 0, 0, 0);

View File

@ -5,6 +5,16 @@ import { throwErrorMessage } from 'dashboard/store/utils/api';
export default createStore({
name: 'CaptainReservation',
API: CaptainReservationsAPI,
mutations: {
SET_CAPTAINRESERVATION_META(state, meta) {
state.meta = {
...state.meta,
totalCount: Number(meta.total_count),
page: Number(meta.page),
statusCounts: meta.status_counts || meta.statusCounts || {},
};
},
},
actions: mutations => ({
fetchRevenue: async function fetchRevenue(_, params = {}) {
try {

View File

@ -1,6 +1,6 @@
# rubocop:disable Metrics/ClassLength
class Api::V1::Accounts::Captain::ReservationsController < Api::V1::Accounts::BaseController
CONFIRMED_STATUSES = %i[scheduled active completed].freeze
CONFIRMED_STATUSES = %i[scheduled active completed confirmed].freeze
RESULTS_PER_PAGE = 25
MAX_RESULTS_PER_PAGE = 100
SORTABLE_FIELDS = %w[check_in_at created_at updated_at].freeze
@ -13,7 +13,9 @@ class Api::V1::Accounts::Captain::ReservationsController < Api::V1::Accounts::Ba
before_action :set_reservation, only: [:show, :pix, :cancel, :mark_as_paid, :regenerate_pix]
def index
scoped = apply_filters(@reservations_scope)
common_scoped = apply_common_filters(@reservations_scope)
@status_counts = status_counts_for(common_scoped)
scoped = apply_status_filter(common_scoped)
scoped = apply_sort(scoped)
@reservations_count = scoped.count
@reservations = scoped.page(@current_page).per(@per_page)
@ -178,6 +180,21 @@ class Api::V1::Accounts::Captain::ReservationsController < Api::V1::Accounts::Ba
)
end
def status_counts_for(scope)
counts_by_status = scope.group(:status).count.transform_keys do |key|
Captain::Reservation.statuses.key(key) || key.to_s
end
confirmed_count = CONFIRMED_STATUSES.sum { |status| counts_by_status[status.to_s].to_i }
{
all: counts_by_status.values.sum,
draft: counts_by_status['draft'].to_i,
pending_payment: counts_by_status['pending_payment'].to_i,
confirmed: confirmed_count,
cancelled: counts_by_status['cancelled'].to_i
}
end
def apply_sort(scope)
return default_order(scope) if permitted_params[:sort].blank?
@ -192,11 +209,12 @@ class Api::V1::Accounts::Captain::ReservationsController < Api::V1::Accounts::Ba
scope.order(
Arel.sql(
'CASE captain_reservations.status ' \
"WHEN #{Captain::Reservation.statuses[:pending_payment]} THEN 0 " \
"WHEN #{Captain::Reservation.statuses[:draft]} THEN 1 " \
"WHEN #{Captain::Reservation.statuses[:scheduled]} THEN 2 " \
"WHEN #{Captain::Reservation.statuses[:active]} THEN 2 " \
"WHEN #{Captain::Reservation.statuses[:completed]} THEN 2 " \
"WHEN #{Captain::Reservation.statuses[:scheduled]} THEN 0 " \
"WHEN #{Captain::Reservation.statuses[:active]} THEN 0 " \
"WHEN #{Captain::Reservation.statuses[:completed]} THEN 0 " \
"WHEN #{Captain::Reservation.statuses[:confirmed]} THEN 0 " \
"WHEN #{Captain::Reservation.statuses[:pending_payment]} THEN 1 " \
"WHEN #{Captain::Reservation.statuses[:draft]} THEN 2 " \
"WHEN #{Captain::Reservation.statuses[:cancelled]} THEN 3 " \
'ELSE 4 END ASC, captain_reservations.check_in_at ASC'
)

View File

@ -5,6 +5,7 @@ class Captain::Reservations::MarkerBuilder
'scheduled' => 'confirmed',
'active' => 'confirmed',
'completed' => 'confirmed',
'confirmed' => 'confirmed',
'cancelled' => 'cancelled'
}.freeze

View File

@ -7,4 +7,5 @@ end
json.meta do
json.total_count @reservations_count
json.page @current_page
json.status_counts @status_counts || {}
end

View File

@ -62,14 +62,19 @@ RSpec.describe 'Api::V1::Accounts::Captain::Reservations', type: :request do
)
end
it 'returns paginated reservations ordered by operational priority by default' do
it 'returns paginated reservations with confirmed reservations first by default' do
get "/api/v1/accounts/#{account.id}/captain/reservations",
headers: admin.create_new_auth_token
expect(response).to have_http_status(:ok)
expect(json_response['payload'].pluck('id')).to eq([pending_reservation.id, confirmed_reservation.id])
expect(json_response['payload'].pluck('id')).to eq([confirmed_reservation.id, pending_reservation.id])
expect(json_response.dig('meta', 'total_count')).to eq(2)
expect(json_response.dig('payload', 0, 'ui_status')).to eq('pending_payment')
expect(json_response.dig('meta', 'status_counts')).to include(
'all' => 2,
'pending_payment' => 1,
'confirmed' => 1
)
expect(json_response.dig('payload', 0, 'ui_status')).to eq('confirmed')
end
it 'filters by confirmed ui status and search query' do

View File

@ -34,6 +34,7 @@ RSpec.describe Captain::Reservations::MarkerBuilder do
expect(described_class.ui_status(:scheduled)).to eq('confirmed')
expect(described_class.ui_status(:active)).to eq('confirmed')
expect(described_class.ui_status(:completed)).to eq('confirmed')
expect(described_class.ui_status(:confirmed)).to eq('confirmed')
expect(described_class.ui_status(:cancelled)).to eq('cancelled')
end
end