+
+
diff --git a/app/javascript/dashboard/store/captain/reservations.js b/app/javascript/dashboard/store/captain/reservations.js
index ced5b0dd3..ffd3e188d 100644
--- a/app/javascript/dashboard/store/captain/reservations.js
+++ b/app/javascript/dashboard/store/captain/reservations.js
@@ -14,6 +14,14 @@ export default createStore({
return throwErrorMessage(error);
}
},
+ create: async function create(_, data) {
+ try {
+ const response = await CaptainReservationsAPI.create(data);
+ return response.data;
+ } catch (error) {
+ return throwErrorMessage(error);
+ }
+ },
fetchPix: async function fetchPix({ commit }, reservationId) {
commit(mutations.SET_UI_FLAG, { fetchingItem: true });
try {
diff --git a/config/routes.rb b/config/routes.rb
index f76ae4e4c..7ec4406df 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -75,7 +75,7 @@ Rails.application.routes.draw do
resources :custom_tools
resources :documents, only: [:index, :show, :create, :destroy]
resources :gallery_items
- resources :reservations, only: [:index, :show] do
+ resources :reservations, only: [:index, :show, :create] do
collection do
get :revenue
end
diff --git a/enterprise/app/controllers/api/v1/accounts/captain/reservations_controller.rb b/enterprise/app/controllers/api/v1/accounts/captain/reservations_controller.rb
index c267456dd..64427a1d4 100644
--- a/enterprise/app/controllers/api/v1/accounts/captain/reservations_controller.rb
+++ b/enterprise/app/controllers/api/v1/accounts/captain/reservations_controller.rb
@@ -27,6 +27,23 @@ class Api::V1::Accounts::Captain::ReservationsController < Api::V1::Accounts::Ba
@marker = Captain::Reservations::MarkerBuilder.build_for(@reservation)
end
+ def create
+ ActiveRecord::Base.transaction do
+ @reservation = @reservations_scope.new(create_params)
+ @reservation.created_by = current_user
+ @reservation.metadata ||= {}
+
+ ensure_contact_inbox!
+
+ if @reservation.save
+ @marker = Captain::Reservations::MarkerBuilder.build_for(@reservation)
+ render 'api/v1/accounts/captain/reservations/show'
+ else
+ render json: { error: @reservation.errors.full_messages.join(', ') }, status: :unprocessable_entity
+ end
+ end
+ end
+
def pix
marker = Captain::Reservations::MarkerBuilder.build_for(@reservation)
render json: {
@@ -153,4 +170,24 @@ class Api::V1::Accounts::Captain::ReservationsController < Api::V1::Accounts::Ba
:page, :per_page, :sort, :direction
)
end
+
+ def create_params
+ params.require(:reservation).permit(
+ :contact_id, :inbox_id, :captain_unit_id, :suite_identifier,
+ :check_in_at, :check_out_at, :total_amount
+ )
+ end
+
+ def ensure_contact_inbox!
+ return if @reservation.contact_inbox_id.present? || @reservation.contact_id.blank? || @reservation.inbox_id.blank?
+
+ contact_inbox = ContactInbox.find_or_create_by!(
+ contact_id: @reservation.contact_id,
+ inbox_id: @reservation.inbox_id
+ ) do |ci|
+ ci.source_id = SecureRandom.uuid
+ end
+
+ @reservation.contact_inbox_id = contact_inbox.id
+ end
end
diff --git a/progresso/reserva_manual.md b/progresso/reserva_manual.md
new file mode 100644
index 000000000..c36d89f8a
--- /dev/null
+++ b/progresso/reserva_manual.md
@@ -0,0 +1,40 @@
+# Criação de Reservas Manuais
+
+**Objetivo:**
+Permitir que as recepcionistas possam criar reservas manualmente (bypassando o comportamento automático da IA), incluindo a associação direta a uma caixa de entrada (inbox) e um contato, além de preencher dados como check-in, check-out e status.
+
+**Contexto:**
+Antes, a rotina de criação de reservas ocorria exclusivamente de forma automatizada via `AiReservationMessageWorker` ou fluxos da IA. Havia necessidade de que, caso a IA não tenha executado a ação, a equipe pudesse criar a reserva pela própria UI.
+
+**Passos:**
+1. **Model & Endpoint (Backend):**
+ - Confirmado que o model já possuía `inbox_id` (`belongs_to :inbox`).
+ - Criamos o método `create` no `Api::V1::Accounts::Captain::ReservationsController` para suportar `POST`, que além de tudo garante a criação de um `ContactInbox` na caixa de entrada fornecida se o contato não existisse ainda no pool da referida caixa. (Método privado `create_params` validando inputs usando Strong Parameters).
+ - Adicionamento de `post :create` no `config/routes.rb` para a rota namespace `captain/reservations`.
+
+2. **Store & API (Frontend):**
+ - No arquivo `captain/reservations.js` da API, introduzido método assíncrono genérico `.create(...)` postando ao endpoint.
+ - Adicionado no *Vuex Store* (`dashboard/store/captain/reservations.js`) a action `create` que despacha a requisição e sinaliza mensagens de erro/sucesso.
+
+3. **Componente de Modal & Tradução:**
+ - Adicionada as labels de tradução JSON de Reservas em PT e EN (Ex: `CAPTAIN_RESERVATIONS.NEW_RESERVATION_MODAL`).
+ - Criado o arquivo `NewReservationModal.vue` usando componentes globais modulares (`Dialog`, `Input`, `ComboBox` e etc) e validando props de injeção direta de `inbox-id` e `contact-id`.
+
+4. **Integração nas Telas (Views):**
+ - **`Index.vue`** (Reservas em Lista Geral): Renderiza o subcomponente modal em overlay disparado pelo Header Button "Nova Reserva", onde recarrega as reservas (`fetchReservations(1)`) após inserção de sucesso.
+ - **`ReservationSummary.vue`** (Painel lateral das conversas): Disponibilizado um novo botão que repassa diretamente os identificadores do Contato Atual e a Inbox Atual para que o formulário da Reserva seja gerado já pré-povoado e associado devidamente, exibido caso `!hasMarker`.
+
+**Principais Códigos e Arquivos Alterados:**
+- `app/javascript/dashboard/routes/dashboard/captain/reservations/components/NewReservationModal.vue`
+- `app/javascript/dashboard/routes/dashboard/captain/reservations/Index.vue`
+- `app/javascript/dashboard/routes/dashboard/conversation/reservation/ReservationSummary.vue`
+- `app/javascript/dashboard/routes/dashboard/conversation/ContactPanel.vue`
+- `enterprise/app/controllers/api/v1/accounts/captain/reservations_controller.rb`
+- `config/routes.rb`
+- Arquivos de tradução (pt_BR, en `captain.json`)
+- `app/javascript/dashboard/store/captain/reservations.js`
+- `app/javascript/dashboard/api/captain/reservations.js`
+
+**Como validar ou reverter:**
+1. **Validar:** Acessar a página global das IA Reservations ou o painel lateral de uma conversa e tocar em "Nova Reserva". Crie preenchendo as informações, e se aparecer as mensagens de confirmação sem console log error, a UI consumiu o Backend corretamente.
+2. **Reverter:** Realizar um `$ git revert` desta feature ou dar Rollback / desfazer os commits. Nenhuma migração de database extra foi executada neste processo (portanto, safe revert).