Um Checkout representa a compra do cliente. Ele pode gerar um ou mais Orders, sempre separados por empresa. Cada Order possui um pagamento associado e tickets que ocupam assentos em segmentos específicos da viagem.
O Order pode nascer no canal digital (ONLINE) ou presencial (POS). Em venda POS, o sistema resolve ou cria User + Customer antes de criar o pedido; se a conta for nova, emite um Invite de ativação para uso posterior do app.
Status
| Status | Descrição |
|---|
PENDING | Pedido criado, aguardando confirmação do pagamento. |
PAID | Pagamento confirmado. |
PAYMENT_FAILED | Pagamento recusado ou falhou. |
CANCELED | Pedido cancelado. |
O status inicial depende do resultado retornado pelo provider de billing. Transições posteriores chegam por webhook.
Criação do pedido
Validações
| Validação | Resultado |
|---|
| Itinerário e assento existem na trip | Pedido rejeitado quando não encontrados |
| Trip disponível para venda | Apenas viagens SCHEDULED e futuras são vendáveis |
| Assento pertence ao veículo | Pedido rejeitado se o assento não faz parte do veículo da viagem |
| Assento livre nos segmentos do itinerário | Pedido rejeitado quando algum segmento já está ocupado |
| Tickets agrupados por empresa | Cada empresa gera um Order próprio |
| Customer obrigatório | Pedido POS também exige Customer resolvido ou criado |
| Benefícios e promoções válidos | Descontos só entram no Order quando as regras dos domains responsáveis permitem |
| Crédito interno da mesma empresa | Crédito só pode ser usado quando pertence ao Customer e à mesma Company do Order |
Cada ticket recebe seatPrice, tripItineraryPrice, price, qrCode, code, snapshot e os segmentos cobertos.
Quando o canal é POS, o operador informa ou resolve o Customer antes da criação do Order. Se o sistema criar uma conta sem senha para o passageiro, um Invite ACCOUNT_ACTIVATION é emitido para ativação posterior no app.
Reserva de assentos
A reserva é segmentada. Um ticket SP → Ribeirão ocupa todos os segmentos entre a parada de embarque e a parada de desembarque. Outro passageiro só pode usar o mesmo assento em segmentos que não se sobrepõem.
Se algum segmento já estiver ocupado, o pedido é rejeitado e nenhuma reserva parcial permanece.
Pagamento e confirmação
O pagamento é criado no provider de billing durante o checkout. Cada Order tem seu próprio Payment, pois cada Order pertence a uma única empresa. O pedido pode nascer PENDING ou já PAID, conforme a resposta do provider.
Confirmações, recusas e estornos posteriores chegam por webhook de billing e atualizam o pedido e o pagamento.
Cancelamento total
Um pedido pode ser cancelado quando suas regras de status permitem. Em pedidos pagos, o cancelamento solicita estorno ao provider antes de atualizar tickets e pagamento.
Efeitos do cancelamento total:
- Tickets válidos ficam
CANCELLED.
- Reservas de assento dos tickets são liberadas.
- Payment é marcado como
REFUNDED quando há estorno.
- Benefícios, promoções e créditos aplicados são revertidos conforme a regra de cada domínio.
- Order fica
CANCELED.
Cancelamento de ticket
Um ticket individual pode ser cancelado quando ainda restam outros tickets válidos no pedido.
- O valor do ticket cancelado define o estorno parcial.
- As reservas daquele ticket são liberadas.
- O
Order.amount passa a refletir a soma dos tickets restantes.
- Se o ticket cancelado era o último válido, o fluxo vira cancelamento total.
O preço do ticket é congelado no momento da compra. Mudanças posteriores na rota ou no assento não alteram tickets já emitidos.
Atividades do ticket
Validações de QR Code, embarques, rejeições, falhas e reimpressões são registradas em Ticket Activity. O Ticket guarda o estado consolidado; o histórico operacional fica append-only.