diff --git a/backend/cmd/api/main.go b/backend/cmd/api/main.go index 2d11d6b..11ba763 100644 --- a/backend/cmd/api/main.go +++ b/backend/cmd/api/main.go @@ -6,6 +6,7 @@ import ( "photum-backend/docs" "photum-backend/internal/anos_formaturas" "photum-backend/internal/auth" + "photum-backend/internal/cadastro_fot" "photum-backend/internal/config" "photum-backend/internal/cursos" "photum-backend/internal/db" @@ -62,6 +63,7 @@ func main() { anosFormaturasService := anos_formaturas.NewService(queries) tiposServicosService := tipos_servicos.NewService(queries) tiposEventosService := tipos_eventos.NewService(queries) + cadastroFotService := cadastro_fot.NewService(queries) // Initialize handlers authHandler := auth.NewHandler(authService) @@ -72,6 +74,7 @@ func main() { anosFormaturasHandler := anos_formaturas.NewHandler(anosFormaturasService) tiposServicosHandler := tipos_servicos.NewHandler(tiposServicosService) tiposEventosHandler := tipos_eventos.NewHandler(tiposEventosService) + cadastroFotHandler := cadastro_fot.NewHandler(cadastroFotService) r := gin.Default() @@ -166,6 +169,12 @@ func main() { api.PUT("/tipos-eventos/:id", tiposEventosHandler.Update) api.DELETE("/tipos-eventos/:id", tiposEventosHandler.Delete) api.POST("/tipos-eventos/precos", tiposEventosHandler.SetPrice) + + api.GET("/cadastro-fot", cadastroFotHandler.List) + api.POST("/cadastro-fot", cadastroFotHandler.Create) + api.GET("/cadastro-fot/:id", cadastroFotHandler.Get) + api.PUT("/cadastro-fot/:id", cadastroFotHandler.Update) + api.DELETE("/cadastro-fot/:id", cadastroFotHandler.Delete) } log.Printf("Swagger Host Configured: %s", cfg.SwaggerHost) diff --git a/backend/docs/docs.go b/backend/docs/docs.go index d94d876..c147337 100644 --- a/backend/docs/docs.go +++ b/backend/docs/docs.go @@ -184,6 +184,182 @@ const docTemplate = `{ } } }, + "/api/cadastro-fot": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "cadastro_fot" + ], + "summary": "List all FOT records", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/cadastro_fot.CadastroFotResponse" + } + } + } + } + }, + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "cadastro_fot" + ], + "summary": "Create a new FOT record", + "parameters": [ + { + "description": "FOT Data", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/cadastro_fot.CreateInput" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/cadastro_fot.CadastroFotResponse" + } + } + } + } + }, + "/api/cadastro-fot/{id}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "cadastro_fot" + ], + "summary": "Get FOT record by ID", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/cadastro_fot.CadastroFotResponse" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "cadastro_fot" + ], + "summary": "Update FOT record", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Data", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/cadastro_fot.CreateInput" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/cadastro_fot.CadastroFotResponse" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "cadastro_fot" + ], + "summary": "Delete FOT record", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + } + } + } + }, "/api/cursos": { "get": { "security": [ @@ -1647,6 +1823,88 @@ const docTemplate = `{ } } }, + "cadastro_fot.CadastroFotResponse": { + "type": "object", + "properties": { + "ano_formatura_id": { + "type": "string" + }, + "ano_formatura_label": { + "type": "string" + }, + "cidade": { + "type": "string" + }, + "curso_id": { + "type": "string" + }, + "curso_nome": { + "type": "string" + }, + "empresa_id": { + "type": "string" + }, + "empresa_nome": { + "type": "string" + }, + "estado": { + "type": "string" + }, + "fot": { + "type": "integer" + }, + "gastos_captacao": { + "type": "number" + }, + "id": { + "type": "string" + }, + "instituicao": { + "type": "string" + }, + "observacoes": { + "type": "string" + }, + "pre_venda": { + "type": "boolean" + } + } + }, + "cadastro_fot.CreateInput": { + "type": "object", + "properties": { + "ano_formatura_id": { + "type": "string" + }, + "cidade": { + "type": "string" + }, + "curso_id": { + "type": "string" + }, + "empresa_id": { + "type": "string" + }, + "estado": { + "type": "string" + }, + "fot": { + "type": "integer" + }, + "gastos_captacao": { + "type": "number" + }, + "instituicao": { + "type": "string" + }, + "observacoes": { + "type": "string" + }, + "pre_venda": { + "type": "boolean" + } + } + }, "cursos.CreateCursoRequest": { "type": "object", "required": [ diff --git a/backend/docs/swagger.json b/backend/docs/swagger.json index bd2b29b..a8b1202 100644 --- a/backend/docs/swagger.json +++ b/backend/docs/swagger.json @@ -178,6 +178,182 @@ } } }, + "/api/cadastro-fot": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "cadastro_fot" + ], + "summary": "List all FOT records", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/cadastro_fot.CadastroFotResponse" + } + } + } + } + }, + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "cadastro_fot" + ], + "summary": "Create a new FOT record", + "parameters": [ + { + "description": "FOT Data", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/cadastro_fot.CreateInput" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/cadastro_fot.CadastroFotResponse" + } + } + } + } + }, + "/api/cadastro-fot/{id}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "cadastro_fot" + ], + "summary": "Get FOT record by ID", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/cadastro_fot.CadastroFotResponse" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "cadastro_fot" + ], + "summary": "Update FOT record", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Data", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/cadastro_fot.CreateInput" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/cadastro_fot.CadastroFotResponse" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "cadastro_fot" + ], + "summary": "Delete FOT record", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + } + } + } + }, "/api/cursos": { "get": { "security": [ @@ -1641,6 +1817,88 @@ } } }, + "cadastro_fot.CadastroFotResponse": { + "type": "object", + "properties": { + "ano_formatura_id": { + "type": "string" + }, + "ano_formatura_label": { + "type": "string" + }, + "cidade": { + "type": "string" + }, + "curso_id": { + "type": "string" + }, + "curso_nome": { + "type": "string" + }, + "empresa_id": { + "type": "string" + }, + "empresa_nome": { + "type": "string" + }, + "estado": { + "type": "string" + }, + "fot": { + "type": "integer" + }, + "gastos_captacao": { + "type": "number" + }, + "id": { + "type": "string" + }, + "instituicao": { + "type": "string" + }, + "observacoes": { + "type": "string" + }, + "pre_venda": { + "type": "boolean" + } + } + }, + "cadastro_fot.CreateInput": { + "type": "object", + "properties": { + "ano_formatura_id": { + "type": "string" + }, + "cidade": { + "type": "string" + }, + "curso_id": { + "type": "string" + }, + "empresa_id": { + "type": "string" + }, + "estado": { + "type": "string" + }, + "fot": { + "type": "integer" + }, + "gastos_captacao": { + "type": "number" + }, + "instituicao": { + "type": "string" + }, + "observacoes": { + "type": "string" + }, + "pre_venda": { + "type": "boolean" + } + } + }, "cursos.CreateCursoRequest": { "type": "object", "required": [ diff --git a/backend/docs/swagger.yaml b/backend/docs/swagger.yaml index a127059..b7564d5 100644 --- a/backend/docs/swagger.yaml +++ b/backend/docs/swagger.yaml @@ -45,6 +45,60 @@ definitions: role: type: string type: object + cadastro_fot.CadastroFotResponse: + properties: + ano_formatura_id: + type: string + ano_formatura_label: + type: string + cidade: + type: string + curso_id: + type: string + curso_nome: + type: string + empresa_id: + type: string + empresa_nome: + type: string + estado: + type: string + fot: + type: integer + gastos_captacao: + type: number + id: + type: string + instituicao: + type: string + observacoes: + type: string + pre_venda: + type: boolean + type: object + cadastro_fot.CreateInput: + properties: + ano_formatura_id: + type: string + cidade: + type: string + curso_id: + type: string + empresa_id: + type: string + estado: + type: string + fot: + type: integer + gastos_captacao: + type: number + instituicao: + type: string + observacoes: + type: string + pre_venda: + type: boolean + type: object cursos.CreateCursoRequest: properties: nome: @@ -408,6 +462,114 @@ paths: summary: Update a graduation year tags: - anos_formaturas + /api/cadastro-fot: + get: + consumes: + - application/json + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/cadastro_fot.CadastroFotResponse' + type: array + security: + - BearerAuth: [] + summary: List all FOT records + tags: + - cadastro_fot + post: + consumes: + - application/json + parameters: + - description: FOT Data + in: body + name: request + required: true + schema: + $ref: '#/definitions/cadastro_fot.CreateInput' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/cadastro_fot.CadastroFotResponse' + security: + - BearerAuth: [] + summary: Create a new FOT record + tags: + - cadastro_fot + /api/cadastro-fot/{id}: + delete: + consumes: + - application/json + parameters: + - description: ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "204": + description: No Content + security: + - BearerAuth: [] + summary: Delete FOT record + tags: + - cadastro_fot + get: + consumes: + - application/json + parameters: + - description: ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/cadastro_fot.CadastroFotResponse' + security: + - BearerAuth: [] + summary: Get FOT record by ID + tags: + - cadastro_fot + put: + consumes: + - application/json + parameters: + - description: ID + in: path + name: id + required: true + type: string + - description: Data + in: body + name: request + required: true + schema: + $ref: '#/definitions/cadastro_fot.CreateInput' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/cadastro_fot.CadastroFotResponse' + security: + - BearerAuth: [] + summary: Update FOT record + tags: + - cadastro_fot /api/cursos: get: consumes: diff --git a/backend/internal/cadastro_fot/handler.go b/backend/internal/cadastro_fot/handler.go new file mode 100644 index 0000000..1e3287b --- /dev/null +++ b/backend/internal/cadastro_fot/handler.go @@ -0,0 +1,209 @@ +package cadastro_fot + +import ( + "net/http" + + "photum-backend/internal/db/generated" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" + "github.com/jackc/pgx/v5/pgtype" +) + +type Handler struct { + service *Service +} + +func NewHandler(service *Service) *Handler { + return &Handler{service: service} +} + +type CadastroFotResponse struct { + ID string `json:"id"` + Fot int32 `json:"fot"` + EmpresaID string `json:"empresa_id"` + EmpresaNome string `json:"empresa_nome,omitempty"` + CursoID string `json:"curso_id"` + CursoNome string `json:"curso_nome,omitempty"` + AnoFormaturaID string `json:"ano_formatura_id"` + AnoFormaturaLabel string `json:"ano_formatura_label,omitempty"` + Instituicao string `json:"instituicao"` + Cidade string `json:"cidade"` + Estado string `json:"estado"` + Observacoes string `json:"observacoes"` + GastosCaptacao float64 `json:"gastos_captacao"` + PreVenda bool `json:"pre_venda"` +} + +func fromPgNumeric(n pgtype.Numeric) float64 { + f, _ := n.Float64Value() + return f.Float64 +} + +// Map Create result (no joins) +func toResponse(c generated.CadastroFot) CadastroFotResponse { + return CadastroFotResponse{ + ID: uuid.UUID(c.ID.Bytes).String(), + Fot: c.Fot, + EmpresaID: uuid.UUID(c.EmpresaID.Bytes).String(), + CursoID: uuid.UUID(c.CursoID.Bytes).String(), + AnoFormaturaID: uuid.UUID(c.AnoFormaturaID.Bytes).String(), + Instituicao: c.Instituicao.String, + Cidade: c.Cidade.String, + Estado: c.Estado.String, + Observacoes: c.Observacoes.String, + GastosCaptacao: fromPgNumeric(c.GastosCaptacao), + PreVenda: c.PreVenda.Bool, + } +} + +// Map List result (with joins) +func toListResponse(r generated.ListCadastroFotRow) CadastroFotResponse { + return CadastroFotResponse{ + ID: uuid.UUID(r.ID.Bytes).String(), + Fot: r.Fot, + EmpresaID: uuid.UUID(r.EmpresaID.Bytes).String(), + EmpresaNome: r.EmpresaNome, + CursoID: uuid.UUID(r.CursoID.Bytes).String(), + CursoNome: r.CursoNome, + AnoFormaturaID: uuid.UUID(r.AnoFormaturaID.Bytes).String(), + AnoFormaturaLabel: r.AnoFormaturaLabel, + Instituicao: r.Instituicao.String, + Cidade: r.Cidade.String, + Estado: r.Estado.String, + Observacoes: r.Observacoes.String, + GastosCaptacao: fromPgNumeric(r.GastosCaptacao), + PreVenda: r.PreVenda.Bool, + } +} + +// Map GetByID result +func toGetResponse(r generated.GetCadastroFotByIDRow) CadastroFotResponse { + return CadastroFotResponse{ + ID: uuid.UUID(r.ID.Bytes).String(), + Fot: r.Fot, + EmpresaID: uuid.UUID(r.EmpresaID.Bytes).String(), + EmpresaNome: r.EmpresaNome, + CursoID: uuid.UUID(r.CursoID.Bytes).String(), + CursoNome: r.CursoNome, + AnoFormaturaID: uuid.UUID(r.AnoFormaturaID.Bytes).String(), + AnoFormaturaLabel: r.AnoFormaturaLabel, + Instituicao: r.Instituicao.String, + Cidade: r.Cidade.String, + Estado: r.Estado.String, + Observacoes: r.Observacoes.String, + GastosCaptacao: fromPgNumeric(r.GastosCaptacao), + PreVenda: r.PreVenda.Bool, + } +} + +// Create godoc +// @Summary Create a new FOT record +// @Tags cadastro_fot +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param request body CreateInput true "FOT Data" +// @Success 201 {object} CadastroFotResponse +// @Router /api/cadastro-fot [post] +func (h *Handler) Create(c *gin.Context) { + var req CreateInput + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + res, err := h.service.Create(c.Request.Context(), req) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusCreated, toResponse(*res)) +} + +// List godoc +// @Summary List all FOT records +// @Tags cadastro_fot +// @Accept json +// @Produce json +// @Security BearerAuth +// @Success 200 {array} CadastroFotResponse +// @Router /api/cadastro-fot [get] +func (h *Handler) List(c *gin.Context) { + rows, err := h.service.List(c.Request.Context()) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + response := []CadastroFotResponse{} + for _, r := range rows { + response = append(response, toListResponse(r)) + } + c.JSON(http.StatusOK, response) +} + +// Get godoc +// @Summary Get FOT record by ID +// @Tags cadastro_fot +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param id path string true "ID" +// @Success 200 {object} CadastroFotResponse +// @Router /api/cadastro-fot/{id} [get] +func (h *Handler) Get(c *gin.Context) { + id := c.Param("id") + res, err := h.service.GetByID(c.Request.Context(), id) + if err != nil { + c.JSON(http.StatusNotFound, gin.H{"error": "Record not found"}) + return + } + c.JSON(http.StatusOK, toGetResponse(*res)) +} + +// Update godoc +// @Summary Update FOT record +// @Tags cadastro_fot +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param id path string true "ID" +// @Param request body CreateInput true "Data" +// @Success 200 {object} CadastroFotResponse +// @Router /api/cadastro-fot/{id} [put] +func (h *Handler) Update(c *gin.Context) { + id := c.Param("id") + var req CreateInput + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + res, err := h.service.Update(c.Request.Context(), id, req) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, toResponse(*res)) +} + +// Delete godoc +// @Summary Delete FOT record +// @Tags cadastro_fot +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param id path string true "ID" +// @Success 204 +// @Router /api/cadastro-fot/{id} [delete] +func (h *Handler) Delete(c *gin.Context) { + id := c.Param("id") + err := h.service.Delete(c.Request.Context(), id) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusNoContent, nil) +} diff --git a/backend/internal/cadastro_fot/service.go b/backend/internal/cadastro_fot/service.go new file mode 100644 index 0000000..dd788f6 --- /dev/null +++ b/backend/internal/cadastro_fot/service.go @@ -0,0 +1,112 @@ +package cadastro_fot + +import ( + "context" + "errors" + "strconv" + + "photum-backend/internal/db/generated" + + "github.com/google/uuid" + "github.com/jackc/pgx/v5/pgtype" +) + +type Service struct { + queries *generated.Queries +} + +func NewService(queries *generated.Queries) *Service { + return &Service{queries: queries} +} + +type CreateInput struct { + Fot int32 `json:"fot"` + EmpresaID string `json:"empresa_id"` + CursoID string `json:"curso_id"` + AnoFormaturaID string `json:"ano_formatura_id"` + Instituicao string `json:"instituicao"` + Cidade string `json:"cidade"` + Estado string `json:"estado"` + Observacoes string `json:"observacoes"` + GastosCaptacao float64 `json:"gastos_captacao"` + PreVenda bool `json:"pre_venda"` +} + +func (s *Service) Create(ctx context.Context, input CreateInput) (*generated.CadastroFot, error) { + empresaUUID, _ := uuid.Parse(input.EmpresaID) + cursoUUID, _ := uuid.Parse(input.CursoID) + anoUUID, _ := uuid.Parse(input.AnoFormaturaID) + + res, err := s.queries.CreateCadastroFot(ctx, generated.CreateCadastroFotParams{ + Fot: input.Fot, + EmpresaID: pgtype.UUID{Bytes: empresaUUID, Valid: true}, + CursoID: pgtype.UUID{Bytes: cursoUUID, Valid: true}, + AnoFormaturaID: pgtype.UUID{Bytes: anoUUID, Valid: true}, + Instituicao: pgtype.Text{String: input.Instituicao, Valid: true}, + Cidade: pgtype.Text{String: input.Cidade, Valid: true}, + Estado: pgtype.Text{String: input.Estado, Valid: true}, + Observacoes: pgtype.Text{String: input.Observacoes, Valid: true}, + GastosCaptacao: toPgNumeric(input.GastosCaptacao), + PreVenda: pgtype.Bool{Bool: input.PreVenda, Valid: true}, + }) + if err != nil { + return nil, err + } + return &res, nil +} + +func (s *Service) List(ctx context.Context) ([]generated.ListCadastroFotRow, error) { + return s.queries.ListCadastroFot(ctx) +} + +func (s *Service) GetByID(ctx context.Context, id string) (*generated.GetCadastroFotByIDRow, error) { + uuidVal, err := uuid.Parse(id) + if err != nil { + return nil, errors.New("invalid id") + } + item, err := s.queries.GetCadastroFotByID(ctx, pgtype.UUID{Bytes: uuidVal, Valid: true}) + return &item, err +} + +func (s *Service) Update(ctx context.Context, id string, input CreateInput) (*generated.CadastroFot, error) { + uuidVal, err := uuid.Parse(id) + if err != nil { + return nil, errors.New("invalid id") + } + empresaUUID, _ := uuid.Parse(input.EmpresaID) + cursoUUID, _ := uuid.Parse(input.CursoID) + anoUUID, _ := uuid.Parse(input.AnoFormaturaID) + + item, err := s.queries.UpdateCadastroFot(ctx, generated.UpdateCadastroFotParams{ + ID: pgtype.UUID{Bytes: uuidVal, Valid: true}, + Fot: input.Fot, + EmpresaID: pgtype.UUID{Bytes: empresaUUID, Valid: true}, + CursoID: pgtype.UUID{Bytes: cursoUUID, Valid: true}, + AnoFormaturaID: pgtype.UUID{Bytes: anoUUID, Valid: true}, + Instituicao: pgtype.Text{String: input.Instituicao, Valid: true}, + Cidade: pgtype.Text{String: input.Cidade, Valid: true}, + Estado: pgtype.Text{String: input.Estado, Valid: true}, + Observacoes: pgtype.Text{String: input.Observacoes, Valid: true}, + GastosCaptacao: toPgNumeric(input.GastosCaptacao), + PreVenda: pgtype.Bool{Bool: input.PreVenda, Valid: true}, + }) + return &item, err +} + +func (s *Service) Delete(ctx context.Context, id string) error { + uuidVal, err := uuid.Parse(id) + if err != nil { + return errors.New("invalid id") + } + return s.queries.DeleteCadastroFot(ctx, pgtype.UUID{Bytes: uuidVal, Valid: true}) +} + +// Helper to convert float to numeric robustly +func toPgNumeric(f float64) pgtype.Numeric { + var n pgtype.Numeric + s := strconv.FormatFloat(f, 'f', -1, 64) + if err := n.Scan(s); err != nil { + return pgtype.Numeric{Valid: false} + } + return n +} diff --git a/backend/internal/db/generated/cadastro_fot.sql.go b/backend/internal/db/generated/cadastro_fot.sql.go new file mode 100644 index 0000000..9da10df --- /dev/null +++ b/backend/internal/db/generated/cadastro_fot.sql.go @@ -0,0 +1,288 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.30.0 +// source: cadastro_fot.sql + +package generated + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const createCadastroFot = `-- name: CreateCadastroFot :one +INSERT INTO cadastro_fot ( + fot, empresa_id, curso_id, ano_formatura_id, instituicao, cidade, estado, observacoes, gastos_captacao, pre_venda +) VALUES ( + $1, $2, $3, $4, $5, $6, $7, $8, $9, $10 +) RETURNING id, fot, empresa_id, curso_id, ano_formatura_id, instituicao, cidade, estado, observacoes, gastos_captacao, pre_venda, created_at, updated_at +` + +type CreateCadastroFotParams struct { + Fot int32 `json:"fot"` + EmpresaID pgtype.UUID `json:"empresa_id"` + CursoID pgtype.UUID `json:"curso_id"` + AnoFormaturaID pgtype.UUID `json:"ano_formatura_id"` + Instituicao pgtype.Text `json:"instituicao"` + Cidade pgtype.Text `json:"cidade"` + Estado pgtype.Text `json:"estado"` + Observacoes pgtype.Text `json:"observacoes"` + GastosCaptacao pgtype.Numeric `json:"gastos_captacao"` + PreVenda pgtype.Bool `json:"pre_venda"` +} + +func (q *Queries) CreateCadastroFot(ctx context.Context, arg CreateCadastroFotParams) (CadastroFot, error) { + row := q.db.QueryRow(ctx, createCadastroFot, + arg.Fot, + arg.EmpresaID, + arg.CursoID, + arg.AnoFormaturaID, + arg.Instituicao, + arg.Cidade, + arg.Estado, + arg.Observacoes, + arg.GastosCaptacao, + arg.PreVenda, + ) + var i CadastroFot + err := row.Scan( + &i.ID, + &i.Fot, + &i.EmpresaID, + &i.CursoID, + &i.AnoFormaturaID, + &i.Instituicao, + &i.Cidade, + &i.Estado, + &i.Observacoes, + &i.GastosCaptacao, + &i.PreVenda, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const deleteCadastroFot = `-- name: DeleteCadastroFot :exec +DELETE FROM cadastro_fot WHERE id = $1 +` + +func (q *Queries) DeleteCadastroFot(ctx context.Context, id pgtype.UUID) error { + _, err := q.db.Exec(ctx, deleteCadastroFot, id) + return err +} + +const getCadastroFotByFOT = `-- name: GetCadastroFotByFOT :one +SELECT id, fot, empresa_id, curso_id, ano_formatura_id, instituicao, cidade, estado, observacoes, gastos_captacao, pre_venda, created_at, updated_at FROM cadastro_fot WHERE fot = $1 +` + +func (q *Queries) GetCadastroFotByFOT(ctx context.Context, fot int32) (CadastroFot, error) { + row := q.db.QueryRow(ctx, getCadastroFotByFOT, fot) + var i CadastroFot + err := row.Scan( + &i.ID, + &i.Fot, + &i.EmpresaID, + &i.CursoID, + &i.AnoFormaturaID, + &i.Instituicao, + &i.Cidade, + &i.Estado, + &i.Observacoes, + &i.GastosCaptacao, + &i.PreVenda, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const getCadastroFotByID = `-- name: GetCadastroFotByID :one +SELECT + c.id, c.fot, c.empresa_id, c.curso_id, c.ano_formatura_id, c.instituicao, c.cidade, c.estado, c.observacoes, c.gastos_captacao, c.pre_venda, c.created_at, c.updated_at, + e.nome as empresa_nome, + cur.nome as curso_nome, + a.ano_semestre as ano_formatura_label +FROM cadastro_fot c +JOIN empresas e ON c.empresa_id = e.id +JOIN cursos cur ON c.curso_id = cur.id +JOIN anos_formaturas a ON c.ano_formatura_id = a.id +WHERE c.id = $1 +` + +type GetCadastroFotByIDRow struct { + ID pgtype.UUID `json:"id"` + Fot int32 `json:"fot"` + EmpresaID pgtype.UUID `json:"empresa_id"` + CursoID pgtype.UUID `json:"curso_id"` + AnoFormaturaID pgtype.UUID `json:"ano_formatura_id"` + Instituicao pgtype.Text `json:"instituicao"` + Cidade pgtype.Text `json:"cidade"` + Estado pgtype.Text `json:"estado"` + Observacoes pgtype.Text `json:"observacoes"` + GastosCaptacao pgtype.Numeric `json:"gastos_captacao"` + PreVenda pgtype.Bool `json:"pre_venda"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + EmpresaNome string `json:"empresa_nome"` + CursoNome string `json:"curso_nome"` + AnoFormaturaLabel string `json:"ano_formatura_label"` +} + +func (q *Queries) GetCadastroFotByID(ctx context.Context, id pgtype.UUID) (GetCadastroFotByIDRow, error) { + row := q.db.QueryRow(ctx, getCadastroFotByID, id) + var i GetCadastroFotByIDRow + err := row.Scan( + &i.ID, + &i.Fot, + &i.EmpresaID, + &i.CursoID, + &i.AnoFormaturaID, + &i.Instituicao, + &i.Cidade, + &i.Estado, + &i.Observacoes, + &i.GastosCaptacao, + &i.PreVenda, + &i.CreatedAt, + &i.UpdatedAt, + &i.EmpresaNome, + &i.CursoNome, + &i.AnoFormaturaLabel, + ) + return i, err +} + +const listCadastroFot = `-- name: ListCadastroFot :many +SELECT + c.id, c.fot, c.empresa_id, c.curso_id, c.ano_formatura_id, c.instituicao, c.cidade, c.estado, c.observacoes, c.gastos_captacao, c.pre_venda, c.created_at, c.updated_at, + e.nome as empresa_nome, + cur.nome as curso_nome, + a.ano_semestre as ano_formatura_label +FROM cadastro_fot c +JOIN empresas e ON c.empresa_id = e.id +JOIN cursos cur ON c.curso_id = cur.id +JOIN anos_formaturas a ON c.ano_formatura_id = a.id +ORDER BY c.fot DESC +` + +type ListCadastroFotRow struct { + ID pgtype.UUID `json:"id"` + Fot int32 `json:"fot"` + EmpresaID pgtype.UUID `json:"empresa_id"` + CursoID pgtype.UUID `json:"curso_id"` + AnoFormaturaID pgtype.UUID `json:"ano_formatura_id"` + Instituicao pgtype.Text `json:"instituicao"` + Cidade pgtype.Text `json:"cidade"` + Estado pgtype.Text `json:"estado"` + Observacoes pgtype.Text `json:"observacoes"` + GastosCaptacao pgtype.Numeric `json:"gastos_captacao"` + PreVenda pgtype.Bool `json:"pre_venda"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + EmpresaNome string `json:"empresa_nome"` + CursoNome string `json:"curso_nome"` + AnoFormaturaLabel string `json:"ano_formatura_label"` +} + +func (q *Queries) ListCadastroFot(ctx context.Context) ([]ListCadastroFotRow, error) { + rows, err := q.db.Query(ctx, listCadastroFot) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListCadastroFotRow + for rows.Next() { + var i ListCadastroFotRow + if err := rows.Scan( + &i.ID, + &i.Fot, + &i.EmpresaID, + &i.CursoID, + &i.AnoFormaturaID, + &i.Instituicao, + &i.Cidade, + &i.Estado, + &i.Observacoes, + &i.GastosCaptacao, + &i.PreVenda, + &i.CreatedAt, + &i.UpdatedAt, + &i.EmpresaNome, + &i.CursoNome, + &i.AnoFormaturaLabel, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const updateCadastroFot = `-- name: UpdateCadastroFot :one +UPDATE cadastro_fot SET + fot = $2, + empresa_id = $3, + curso_id = $4, + ano_formatura_id = $5, + instituicao = $6, + cidade = $7, + estado = $8, + observacoes = $9, + gastos_captacao = $10, + pre_venda = $11, + updated_at = CURRENT_TIMESTAMP +WHERE id = $1 +RETURNING id, fot, empresa_id, curso_id, ano_formatura_id, instituicao, cidade, estado, observacoes, gastos_captacao, pre_venda, created_at, updated_at +` + +type UpdateCadastroFotParams struct { + ID pgtype.UUID `json:"id"` + Fot int32 `json:"fot"` + EmpresaID pgtype.UUID `json:"empresa_id"` + CursoID pgtype.UUID `json:"curso_id"` + AnoFormaturaID pgtype.UUID `json:"ano_formatura_id"` + Instituicao pgtype.Text `json:"instituicao"` + Cidade pgtype.Text `json:"cidade"` + Estado pgtype.Text `json:"estado"` + Observacoes pgtype.Text `json:"observacoes"` + GastosCaptacao pgtype.Numeric `json:"gastos_captacao"` + PreVenda pgtype.Bool `json:"pre_venda"` +} + +func (q *Queries) UpdateCadastroFot(ctx context.Context, arg UpdateCadastroFotParams) (CadastroFot, error) { + row := q.db.QueryRow(ctx, updateCadastroFot, + arg.ID, + arg.Fot, + arg.EmpresaID, + arg.CursoID, + arg.AnoFormaturaID, + arg.Instituicao, + arg.Cidade, + arg.Estado, + arg.Observacoes, + arg.GastosCaptacao, + arg.PreVenda, + ) + var i CadastroFot + err := row.Scan( + &i.ID, + &i.Fot, + &i.EmpresaID, + &i.CursoID, + &i.AnoFormaturaID, + &i.Instituicao, + &i.Cidade, + &i.Estado, + &i.Observacoes, + &i.GastosCaptacao, + &i.PreVenda, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} diff --git a/backend/internal/db/generated/models.go b/backend/internal/db/generated/models.go index 456f92d..bbbf8bf 100644 --- a/backend/internal/db/generated/models.go +++ b/backend/internal/db/generated/models.go @@ -14,6 +14,22 @@ type AnosFormatura struct { CriadoEm pgtype.Timestamptz `json:"criado_em"` } +type CadastroFot struct { + ID pgtype.UUID `json:"id"` + Fot int32 `json:"fot"` + EmpresaID pgtype.UUID `json:"empresa_id"` + CursoID pgtype.UUID `json:"curso_id"` + AnoFormaturaID pgtype.UUID `json:"ano_formatura_id"` + Instituicao pgtype.Text `json:"instituicao"` + Cidade pgtype.Text `json:"cidade"` + Estado pgtype.Text `json:"estado"` + Observacoes pgtype.Text `json:"observacoes"` + GastosCaptacao pgtype.Numeric `json:"gastos_captacao"` + PreVenda pgtype.Bool `json:"pre_venda"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + type CadastroProfissionai struct { ID pgtype.UUID `json:"id"` UsuarioID pgtype.UUID `json:"usuario_id"` diff --git a/backend/internal/db/queries/cadastro_fot.sql b/backend/internal/db/queries/cadastro_fot.sql new file mode 100644 index 0000000..23918aa --- /dev/null +++ b/backend/internal/db/queries/cadastro_fot.sql @@ -0,0 +1,52 @@ +-- name: CreateCadastroFot :one +INSERT INTO cadastro_fot ( + fot, empresa_id, curso_id, ano_formatura_id, instituicao, cidade, estado, observacoes, gastos_captacao, pre_venda +) VALUES ( + $1, $2, $3, $4, $5, $6, $7, $8, $9, $10 +) RETURNING *; + +-- name: ListCadastroFot :many +SELECT + c.*, + e.nome as empresa_nome, + cur.nome as curso_nome, + a.ano_semestre as ano_formatura_label +FROM cadastro_fot c +JOIN empresas e ON c.empresa_id = e.id +JOIN cursos cur ON c.curso_id = cur.id +JOIN anos_formaturas a ON c.ano_formatura_id = a.id +ORDER BY c.fot DESC; + +-- name: GetCadastroFotByID :one +SELECT + c.*, + e.nome as empresa_nome, + cur.nome as curso_nome, + a.ano_semestre as ano_formatura_label +FROM cadastro_fot c +JOIN empresas e ON c.empresa_id = e.id +JOIN cursos cur ON c.curso_id = cur.id +JOIN anos_formaturas a ON c.ano_formatura_id = a.id +WHERE c.id = $1; + +-- name: GetCadastroFotByFOT :one +SELECT * FROM cadastro_fot WHERE fot = $1; + +-- name: UpdateCadastroFot :one +UPDATE cadastro_fot SET + fot = $2, + empresa_id = $3, + curso_id = $4, + ano_formatura_id = $5, + instituicao = $6, + cidade = $7, + estado = $8, + observacoes = $9, + gastos_captacao = $10, + pre_venda = $11, + updated_at = CURRENT_TIMESTAMP +WHERE id = $1 +RETURNING *; + +-- name: DeleteCadastroFot :exec +DELETE FROM cadastro_fot WHERE id = $1; diff --git a/backend/internal/db/schema.sql b/backend/internal/db/schema.sql index 84e3e57..01e743d 100644 --- a/backend/internal/db/schema.sql +++ b/backend/internal/db/schema.sql @@ -145,6 +145,23 @@ CREATE TABLE IF NOT EXISTS precos_tipos_eventos ( UNIQUE(tipo_evento_id, funcao_profissional_id) ); +-- Cadastro FOT +CREATE TABLE IF NOT EXISTS cadastro_fot ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + fot INTEGER NOT NULL UNIQUE, + empresa_id UUID NOT NULL REFERENCES empresas(id), + curso_id UUID NOT NULL REFERENCES cursos(id), + ano_formatura_id UUID NOT NULL REFERENCES anos_formaturas(id), + instituicao VARCHAR(255), + cidade VARCHAR(255), + estado VARCHAR(2), + observacoes TEXT, + gastos_captacao NUMERIC(10, 2), + pre_venda BOOLEAN, + created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP +); + -- Seed Pricing Data DO $$ DECLARE