O TripSeatSegment controla a ocupação de assentos em nível de segmento. Cada registro é criado apenas quando um ticket é vendido, e a regra de unicidade impede que um assento seja vendido duas vezes para o mesmo segmento.
Campos
| Campo | Tipo | Descrição |
|---|
tripSeatSegmentId | UUID | Identificador único |
tripId | UUID | Viagem |
seatId | UUID | Assento do veículo |
segmentOrder | integer | Número do segmento |
ticketId | UUID | Ticket que ocupa este assento neste segmento |
createdBy | UUID? | Usuário que criou o registro, quando aplicável |
createdAt | datetime | Data de criação |
updatedBy | UUID? | Usuário que fez a última atualização, quando aplicável |
updatedAt | datetime | Data de última atualização |
Diferente de um modelo de pré-alocação, os TripSeatSegments não são criados antecipadamente. Eles só existem quando um ticket é vendido. A ausência de registro para um [tripId, seatId, segmentOrder] significa que o assento está livre naquele segmento.
Prevenção de venda dupla
A chave de ocupação é tripId + seatId + segmentOrder. Uma segunda venda para a mesma combinação é rejeitada como assento já ocupado.
Exemplo prático
Considere uma viagem SP → Campinas → Ribeirão com 2 segmentos:
| Segmento | Trecho |
|---|
| 1 | SP → Campinas |
| 2 | Campinas → Ribeirão |
Cenário: Passageiro A compra SP → Ribeirão (assento 5)
| tripId | seatId | segmentOrder | ticketId |
|---|
| trip-1 | seat-5 | 1 | ticket-A |
| trip-1 | seat-5 | 2 | ticket-A |
O assento 5 está ocupado nos dois segmentos. Ninguém mais pode comprá-lo para qualquer trecho desta viagem.
Cenário: Compartilhamento de assento em trechos distintos
Se Passageiro A compra apenas SP → Campinas (segmento 1):
| tripId | seatId | segmentOrder | ticketId |
|---|
| trip-1 | seat-5 | 1 | ticket-A |
O assento 5 no segmento 2 (Campinas → Ribeirão) não tem registro, portanto está livre. Passageiro B pode comprá-lo:
| tripId | seatId | segmentOrder | ticketId |
|---|
| trip-1 | seat-5 | 1 | ticket-A |
| trip-1 | seat-5 | 2 | ticket-B |
Esse modelo permite maximizar a ocupação do veículo — o mesmo assento físico pode ser utilizado por passageiros diferentes em trechos não-sobrepostos.
Disponibilidade de um itinerário
A contagem de assentos disponíveis para um itinerário é calculada como capacidade do veículo − assentos já vendidos no range de segmentos.
Onde vehicle_capacity é a contagem de assentos ativos do veículo. A disponibilidade é derivada das vendas a cada consulta.
Faixas de disponibilidade
A busca de ofertas classifica availableSeats em uma faixa (AvailableSeatsStatus):
| Faixa | Condição |
|---|
SOLD_OUT | availableSeats <= 0 |
LIMITED | 1 <= availableSeats <= 5 |
AVAILABLE | availableSeats > 5 |
A busca de ofertas (offerings) é paginada por cursor e retorna somente itinerários com availableSeats > 0. Itinerários esgotados ficam fora dos resultados.
Regra fundamental
Um assento conta como disponível para um itinerário se nenhum dos segmentos entre o stopOrder da parada de embarque (inclusive) e o stopOrder da parada de desembarque (exclusivo) possui um TripSeatSegment para aquele assento.
Mapa de assentos
O mapa de assentos de um itinerário lista os assentos do veículo por andar. Cada assento é marcado como:
AVAILABLE — o assento está ativo (status = AVAILABLE) e não possui nenhum TripSeatSegment no range do itinerário.
UNAVAILABLE — o assento está inativo/bloqueado ou já ocupado em algum segmento do range.
Reserva de assentos
Ao criar um Order com tickets, o DEVMOB reserva um TripSeatSegment por segmento entre as paradas do itinerário. Se algum segmento já estiver ocupado, a venda é rejeitada e nenhum trecho parcial é reservado.