photum/backend/internal/logistica/handler.go

316 lines
9 KiB
Go

package logistica
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
type Handler struct {
service *Service
}
func NewHandler(service *Service) *Handler {
return &Handler{service: service}
}
// CreateCarro
func (h *Handler) CreateCarro(c *gin.Context) {
var req CreateCarroInput
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
carro, err := h.service.CreateCarro(c.Request.Context(), req)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusCreated, gin.H{"id": uuid.UUID(carro.ID.Bytes).String()})
}
// ListCarros
func (h *Handler) ListCarros(c *gin.Context) {
agendaID := c.Query("agenda_id")
if agendaID == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "agenda_id is required"})
return
}
carros, err := h.service.ListCarros(c.Request.Context(), agendaID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// Fetch passengers for each car? Or let frontend do it on demand?
// For main list, efficient to just list cars, or maybe passengers embedded.
// For simplicity, let's embed passengers if possible, but list returns row.
// We will return list of cars. The frontend can fetch passengers per car or we should use a transaction/composite query.
// MVP: Check if we can just return the cars now.
resp := make([]map[string]interface{}, len(carros))
for i, car := range carros {
var driverName string
// Logic: if system driver name exists, use it. Else use custom name.
if car.MotoristaNomeSistema.String != "" {
driverName = car.MotoristaNomeSistema.String
} else {
driverName = car.NomeMotorista.String
}
var avatar string
if car.MotoristaAvatar.Valid {
avatar = car.MotoristaAvatar.String
}
resp[i] = map[string]interface{}{
"id": uuid.UUID(car.ID.Bytes).String(),
"agenda_id": uuid.UUID(car.AgendaID.Bytes).String(),
"driver_id": uuid.UUID(car.MotoristaID.Bytes).String(), // May be empty UUID or nil representation
"driver_name": driverName,
"driver_avatar": avatar,
"arrival_time": car.HorarioChegada.String,
"notes": car.Observacoes.String,
}
}
c.JSON(http.StatusOK, resp)
}
// DeleteCarro
func (h *Handler) DeleteCarro(c *gin.Context) {
id := c.Param("id")
if id == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "id required"})
return
}
if err := h.service.DeleteCarro(c.Request.Context(), id); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"message": "deleted"})
}
// UpdateCarro
func (h *Handler) UpdateCarro(c *gin.Context) {
id := c.Param("id")
var req UpdateCarroInput
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
_, err := h.service.UpdateCarro(c.Request.Context(), id, req)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"message": "updated"})
}
// Passengers
type AddPassengerInput struct {
ProfissionalID string `json:"profissional_id"`
}
func (h *Handler) AddPassenger(c *gin.Context) {
carID := c.Param("id")
var req AddPassengerInput
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
err := h.service.AddPassageiro(c.Request.Context(), carID, req.ProfissionalID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"message": "passenger added"})
}
func (h *Handler) RemovePassenger(c *gin.Context) {
carID := c.Param("id")
profID := c.Param("profID")
err := h.service.RemovePassageiro(c.Request.Context(), carID, profID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"message": "passenger removed"})
}
func (h *Handler) ListPassengers(c *gin.Context) {
carID := c.Param("id")
passengers, err := h.service.ListPassageiros(c.Request.Context(), carID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
resp := make([]map[string]interface{}, len(passengers))
for i, p := range passengers {
resp[i] = map[string]interface{}{
"id": uuid.UUID(p.ID.Bytes).String(),
"profissional_id": uuid.UUID(p.ProfissionalID.Bytes).String(),
"name": p.Nome,
"avatar_url": p.AvatarUrl.String,
"role": p.FuncaoNome.String,
}
}
c.JSON(http.StatusOK, resp)
}
// ---- LOGISTICA DAILY INVITATIONS & PROFESSIONALS LIST ---- //
func (h *Handler) ListProfissionaisDisponiveis(c *gin.Context) {
var query ListDisponiveisInput
if err := c.ShouldBindQuery(&query); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
regiao := c.GetString("regiao")
res, err := h.service.ListProfissionaisDisponiveisLogistica(c.Request.Context(), query, regiao)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
formatted := make([]map[string]interface{}, len(res.Data))
for i, r := range res.Data {
formatted[i] = map[string]interface{}{
"id": uuid.UUID(r.ID.Bytes).String(),
"nome": r.Nome,
"role": r.FuncaoNome.String,
"avatar_url": r.AvatarUrl.String,
"whatsapp": r.Whatsapp.String,
"cidade": r.Cidade.String,
"carro_disponivel": r.CarroDisponivel.Bool,
}
}
c.JSON(http.StatusOK, gin.H{
"data": formatted,
"total": res.Total,
"page": res.Page,
"total_pages": res.TotalPages,
})
}
func (h *Handler) CreateConvite(c *gin.Context) {
var req CreateConviteInput
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
regiao := c.GetString("regiao")
convite, err := h.service.CreateConviteDiario(c.Request.Context(), req, regiao)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusCreated, gin.H{"id": uuid.UUID(convite.ID.Bytes).String()})
}
// Get Invitations for logged professional
func (h *Handler) ListConvitesProfissional(c *gin.Context) {
// For MVP: Let the frontend send the prof ID or use a dedicated endpoint where frontend provides it.
// Actually frontend can provide ?prof_id=...
pID := c.Query("prof_id")
if pID == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "prof_id is required"})
return
}
convites, err := h.service.ListConvitesDoProfissional(c.Request.Context(), pID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// Format response nicely
resp := make([]map[string]interface{}, len(convites))
for i, c := range convites {
// convert time.Time to YYYY-MM-DD
var dateStr string
if c.Data.Valid {
dateStr = c.Data.Time.Format("2006-01-02")
}
resp[i] = map[string]interface{}{
"id": uuid.UUID(c.ID.Bytes).String(),
"profissional_id": uuid.UUID(c.ProfissionalID.Bytes).String(),
"data": dateStr,
"status": c.Status.String,
"motivo_rejeicao": c.MotivoRejeicao.String,
"criado_em": c.CriadoEm.Time.Format("2006-01-02T15:04:05Z07:00"),
}
}
c.JSON(http.StatusOK, resp)
}
// Respond to an invitation
func (h *Handler) ResponderConvite(c *gin.Context) {
conviteID := c.Param("id")
if conviteID == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "id required"})
return
}
var req ResponderConviteInput
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
convite, err := h.service.ResponderConvite(c.Request.Context(), conviteID, req)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"status": convite.Status.String})
}
// Get Invitations by Date for Logistics Manager
func (h *Handler) ListConvitesPorData(c *gin.Context) {
dataStr := c.Query("data")
if dataStr == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "data is required"})
return
}
regiao := c.GetString("regiao")
convites, err := h.service.ListConvitesPorData(c.Request.Context(), dataStr, regiao)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// Format response
resp := make([]map[string]interface{}, len(convites))
for i, conv := range convites {
var dateStr string
if conv.Data.Valid {
dateStr = conv.Data.Time.Format("2006-01-02")
}
resp[i] = map[string]interface{}{
"id": uuid.UUID(conv.ID.Bytes).String(),
"profissional_id": uuid.UUID(conv.ProfissionalID.Bytes).String(),
"data": dateStr,
"status": conv.Status.String,
"motivo_rejeicao": conv.MotivoRejeicao.String,
"criado_em": conv.CriadoEm.Time.Format("2006-01-02T15:04:05Z07:00"),
}
}
c.JSON(http.StatusOK, resp)
}