Merge pull request #12 from rede5/codex/implementar-crud-nas-rotas-e-documentar

Add CRUD endpoints for companies, products and orders; update repo/service/handlers and regenerate Swagger
This commit is contained in:
Tiago Yamamoto 2025-12-19 18:10:27 -03:00 committed by GitHub
commit 1309a120cb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 3227 additions and 0 deletions

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,52 @@
basePath: / basePath: /
definitions: definitions:
domain.AdminDashboard:
properties:
gmv_cents:
type: integer
new_companies:
type: integer
window_start_at:
type: string
type: object
domain.CartItem:
properties:
batch:
type: string
buyer_id:
type: string
created_at:
type: string
expires_at:
type: string
id:
type: string
product_id:
type: string
product_name:
type: string
quantity:
type: integer
unit_cents:
type: integer
updated_at:
type: string
type: object
domain.CartSummary:
properties:
discount_cents:
type: integer
discount_reason:
type: string
items:
items:
$ref: '#/definitions/domain.CartItem'
type: array
subtotal_cents:
type: integer
total_cents:
type: integer
type: object
domain.Company: domain.Company:
properties: properties:
cnpj: cnpj:
@ -20,6 +67,34 @@ definitions:
updated_at: updated_at:
type: string type: string
type: object type: object
domain.CompanyRating:
properties:
average_score:
type: number
company_id:
type: string
total_reviews:
type: integer
type: object
domain.InventoryItem:
properties:
batch:
type: string
expires_at:
type: string
name:
type: string
price_cents:
type: integer
product_id:
type: string
quantity:
type: integer
seller_id:
type: string
updated_at:
type: string
type: object
domain.Order: domain.Order:
properties: properties:
buyer_id: buyer_id:
@ -140,6 +215,40 @@ definitions:
updated_at: updated_at:
type: string type: string
type: object type: object
domain.Review:
properties:
buyer_id:
type: string
comment:
type: string
created_at:
type: string
id:
type: string
order_id:
type: string
rating:
type: integer
seller_id:
type: string
type: object
domain.SellerDashboard:
properties:
low_stock_alerts:
items:
$ref: '#/definitions/domain.Product'
type: array
orders_count:
type: integer
seller_id:
type: string
top_products:
items:
$ref: '#/definitions/domain.TopProduct'
type: array
total_sales_cents:
type: integer
type: object
domain.Shipment: domain.Shipment:
properties: properties:
carrier: carrier:
@ -180,6 +289,17 @@ definitions:
zip_code: zip_code:
type: string type: string
type: object type: object
domain.TopProduct:
properties:
name:
type: string
product_id:
type: string
revenue_cents:
type: integer
total_quantity:
type: integer
type: object
domain.User: domain.User:
properties: properties:
company_id: company_id:
@ -210,6 +330,13 @@ definitions:
$ref: '#/definitions/domain.User' $ref: '#/definitions/domain.User'
type: array type: array
type: object type: object
handler.addCartItemRequest:
properties:
product_id:
type: string
quantity:
type: integer
type: object
handler.authResponse: handler.authResponse:
properties: properties:
expires_at: expires_at:
@ -230,6 +357,15 @@ definitions:
shipping: shipping:
$ref: '#/definitions/domain.ShippingAddress' $ref: '#/definitions/domain.ShippingAddress'
type: object type: object
handler.createReviewRequest:
properties:
comment:
type: string
order_id:
type: string
rating:
type: integer
type: object
handler.createShipmentRequest: handler.createShipmentRequest:
properties: properties:
carrier: carrier:
@ -254,6 +390,15 @@ definitions:
role: role:
type: string type: string
type: object type: object
handler.inventoryAdjustRequest:
properties:
delta:
type: integer
product_id:
type: string
reason:
type: string
type: object
handler.loginRequest: handler.loginRequest:
properties: properties:
email: email:
@ -317,6 +462,36 @@ definitions:
stock: stock:
type: integer type: integer
type: object type: object
handler.updateCompanyRequest:
properties:
cnpj:
type: string
corporate_name:
type: string
is_verified:
type: boolean
license_number:
type: string
role:
type: string
type: object
handler.updateProductRequest:
properties:
batch:
type: string
description:
type: string
expires_at:
type: string
name:
type: string
price_cents:
type: integer
seller_id:
type: string
stock:
type: integer
type: object
handler.updateStatusRequest: handler.updateStatusRequest:
properties: properties:
status: status:
@ -380,7 +555,108 @@ paths:
summary: Registro de empresas summary: Registro de empresas
tags: tags:
- Empresas - Empresas
/api/companies/{id}:
delete:
parameters:
- description: Company ID
in: path
name: id
required: true
type: string
responses:
"204":
description: ""
"400":
description: Bad Request
schema:
additionalProperties:
type: string
type: object
"404":
description: Not Found
schema:
additionalProperties:
type: string
type: object
summary: Remover empresa
tags:
- Empresas
get:
parameters:
- description: Company ID
in: path
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Company'
"404":
description: Not Found
schema:
additionalProperties:
type: string
type: object
summary: Obter empresa
tags:
- Empresas
patch:
consumes:
- application/json
parameters:
- description: Company ID
in: path
name: id
required: true
type: string
- description: Campos para atualização
in: body
name: payload
required: true
schema:
$ref: '#/definitions/handler.updateCompanyRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Company'
"400":
description: Bad Request
schema:
additionalProperties:
type: string
type: object
"404":
description: Not Found
schema:
additionalProperties:
type: string
type: object
summary: Atualizar empresa
tags:
- Empresas
/api/orders: /api/orders:
get:
produces:
- application/json
responses:
"200":
description: OK
schema:
items:
$ref: '#/definitions/domain.Order'
type: array
security:
- BearerAuth: []
summary: Listar pedidos
tags:
- Pedidos
post: post:
consumes: consumes:
- application/json - application/json
@ -402,6 +678,33 @@ paths:
tags: tags:
- Pedidos - Pedidos
/api/orders/{id}: /api/orders/{id}:
delete:
parameters:
- description: Order ID
in: path
name: id
required: true
type: string
responses:
"204":
description: ""
"400":
description: Bad Request
schema:
additionalProperties:
type: string
type: object
"404":
description: Not Found
schema:
additionalProperties:
type: string
type: object
security:
- BearerAuth: []
summary: Remover pedido
tags:
- Pedidos
get: get:
parameters: parameters:
- description: Order ID - description: Order ID
@ -416,6 +719,8 @@ paths:
description: OK description: OK
schema: schema:
$ref: '#/definitions/domain.Order' $ref: '#/definitions/domain.Order'
security:
- BearerAuth: []
summary: Consulta pedido summary: Consulta pedido
tags: tags:
- Pedidos - Pedidos
@ -434,6 +739,8 @@ paths:
description: Created description: Created
schema: schema:
$ref: '#/definitions/domain.PaymentPreference' $ref: '#/definitions/domain.PaymentPreference'
security:
- BearerAuth: []
summary: Cria preferência de pagamento Mercado Pago com split nativo summary: Cria preferência de pagamento Mercado Pago com split nativo
tags: tags:
- Pagamentos - Pagamentos
@ -458,6 +765,8 @@ paths:
responses: responses:
"204": "204":
description: "" description: ""
security:
- BearerAuth: []
summary: Atualiza status do pedido summary: Atualiza status do pedido
tags: tags:
- Pedidos - Pedidos
@ -495,6 +804,92 @@ paths:
summary: Cadastro de produto com rastreabilidade de lote summary: Cadastro de produto com rastreabilidade de lote
tags: tags:
- Produtos - Produtos
/api/products/{id}:
delete:
parameters:
- description: Product ID
in: path
name: id
required: true
type: string
responses:
"204":
description: ""
"400":
description: Bad Request
schema:
additionalProperties:
type: string
type: object
"404":
description: Not Found
schema:
additionalProperties:
type: string
type: object
summary: Remover produto
tags:
- Produtos
get:
parameters:
- description: Product ID
in: path
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Product'
"404":
description: Not Found
schema:
additionalProperties:
type: string
type: object
summary: Obter produto
tags:
- Produtos
patch:
consumes:
- application/json
parameters:
- description: Product ID
in: path
name: id
required: true
type: string
- description: Campos para atualização
in: body
name: payload
required: true
schema:
$ref: '#/definitions/handler.updateProductRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Product'
"400":
description: Bad Request
schema:
additionalProperties:
type: string
type: object
"404":
description: Not Found
schema:
additionalProperties:
type: string
type: object
summary: Atualizar produto
tags:
- Produtos
/api/v1/auth/login: /api/v1/auth/login:
post: post:
consumes: consumes:
@ -563,6 +958,205 @@ paths:
summary: Cadastro de usuário summary: Cadastro de usuário
tags: tags:
- Autenticação - Autenticação
/api/v1/cart:
get:
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.CartSummary'
security:
- BearerAuth: []
summary: Obter carrinho
tags:
- Carrinho
post:
consumes:
- application/json
parameters:
- description: Item do carrinho
in: body
name: payload
required: true
schema:
$ref: '#/definitions/handler.addCartItemRequest'
produces:
- application/json
responses:
"201":
description: Created
schema:
$ref: '#/definitions/domain.CartSummary'
"400":
description: Bad Request
schema:
additionalProperties:
type: string
type: object
security:
- BearerAuth: []
summary: Adicionar item ao carrinho
tags:
- Carrinho
/api/v1/cart/{id}:
delete:
parameters:
- description: Cart item ID
in: path
name: id
required: true
type: string
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.CartSummary'
"400":
description: Bad Request
schema:
additionalProperties:
type: string
type: object
security:
- BearerAuth: []
summary: Remover item do carrinho
tags:
- Carrinho
/api/v1/companies/{id}/rating:
get:
parameters:
- description: Company ID
in: path
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.CompanyRating'
summary: Obter avaliação da empresa
tags:
- Empresas
/api/v1/companies/{id}/verify:
patch:
parameters:
- description: Company ID
in: path
name: id
required: true
type: string
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Company'
security:
- BearerAuth: []
summary: Verificar empresa
tags:
- Empresas
/api/v1/companies/me:
get:
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Company'
security:
- BearerAuth: []
summary: Obter minha empresa
tags:
- Empresas
/api/v1/dashboard/admin:
get:
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.AdminDashboard'
security:
- BearerAuth: []
summary: Dashboard do administrador
tags:
- Dashboard
/api/v1/dashboard/seller:
get:
parameters:
- description: Seller ID
in: query
name: seller_id
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.SellerDashboard'
security:
- BearerAuth: []
summary: Dashboard do vendedor
tags:
- Dashboard
/api/v1/inventory:
get:
parameters:
- description: Dias para expiração
in: query
name: expires_in_days
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
items:
$ref: '#/definitions/domain.InventoryItem'
type: array
security:
- BearerAuth: []
summary: Listar estoque
tags:
- Estoque
/api/v1/inventory/adjust:
post:
consumes:
- application/json
parameters:
- description: Ajuste de estoque
in: body
name: payload
required: true
schema:
$ref: '#/definitions/handler.inventoryAdjustRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.InventoryItem'
"400":
description: Bad Request
schema:
additionalProperties:
type: string
type: object
security:
- BearerAuth: []
summary: Ajustar estoque
tags:
- Estoque
/api/v1/payments/webhook: /api/v1/payments/webhook:
post: post:
consumes: consumes:
@ -584,6 +1178,35 @@ paths:
summary: Recebe notificações do Mercado Pago summary: Recebe notificações do Mercado Pago
tags: tags:
- Pagamentos - Pagamentos
/api/v1/reviews:
post:
consumes:
- application/json
parameters:
- description: Dados da avaliação
in: body
name: payload
required: true
schema:
$ref: '#/definitions/handler.createReviewRequest'
produces:
- application/json
responses:
"201":
description: Created
schema:
$ref: '#/definitions/domain.Review'
"400":
description: Bad Request
schema:
additionalProperties:
type: string
type: object
security:
- BearerAuth: []
summary: Criar avaliação
tags:
- Avaliações
/api/v1/shipments: /api/v1/shipments:
post: post:
consumes: consumes:
@ -602,6 +1225,8 @@ paths:
description: Created description: Created
schema: schema:
$ref: '#/definitions/domain.Shipment' $ref: '#/definitions/domain.Shipment'
security:
- BearerAuth: []
summary: Gera guia de postagem/transporte summary: Gera guia de postagem/transporte
tags: tags:
- Logistica - Logistica
@ -620,6 +1245,8 @@ paths:
description: OK description: OK
schema: schema:
$ref: '#/definitions/domain.Shipment' $ref: '#/definitions/domain.Shipment'
security:
- BearerAuth: []
summary: Rastreia entrega summary: Rastreia entrega
tags: tags:
- Logistica - Logistica

View file

@ -160,6 +160,114 @@ func (h *Handler) ListCompanies(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, companies) writeJSON(w, http.StatusOK, companies)
} }
// GetCompany godoc
// @Summary Obter empresa
// @Tags Empresas
// @Produce json
// @Param id path string true "Company ID"
// @Success 200 {object} domain.Company
// @Failure 404 {object} map[string]string
// @Router /api/companies/{id} [get]
func (h *Handler) GetCompany(w http.ResponseWriter, r *http.Request) {
id, err := parseUUIDFromPath(r.URL.Path)
if err != nil {
writeError(w, http.StatusBadRequest, err)
return
}
company, err := h.svc.GetCompany(r.Context(), id)
if err != nil {
writeError(w, http.StatusNotFound, err)
return
}
writeJSON(w, http.StatusOK, company)
}
// UpdateCompany godoc
// @Summary Atualizar empresa
// @Tags Empresas
// @Accept json
// @Produce json
// @Param id path string true "Company ID"
// @Param payload body updateCompanyRequest true "Campos para atualização"
// @Success 200 {object} domain.Company
// @Failure 400 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /api/companies/{id} [patch]
func (h *Handler) UpdateCompany(w http.ResponseWriter, r *http.Request) {
id, err := parseUUIDFromPath(r.URL.Path)
if err != nil {
writeError(w, http.StatusBadRequest, err)
return
}
var req updateCompanyRequest
if err := decodeJSON(r.Context(), r, &req); err != nil {
writeError(w, http.StatusBadRequest, err)
return
}
company, err := h.svc.GetCompany(r.Context(), id)
if err != nil {
writeError(w, http.StatusNotFound, err)
return
}
if req.Role != nil {
company.Role = *req.Role
}
if req.CNPJ != nil {
company.CNPJ = *req.CNPJ
}
if req.CorporateName != nil {
company.CorporateName = *req.CorporateName
}
if req.LicenseNumber != nil {
company.LicenseNumber = *req.LicenseNumber
}
if req.IsVerified != nil {
company.IsVerified = *req.IsVerified
}
if err := h.svc.UpdateCompany(r.Context(), company); err != nil {
writeError(w, http.StatusInternalServerError, err)
return
}
writeJSON(w, http.StatusOK, company)
}
// DeleteCompany godoc
// @Summary Remover empresa
// @Tags Empresas
// @Param id path string true "Company ID"
// @Success 204 ""
// @Failure 400 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /api/companies/{id} [delete]
func (h *Handler) DeleteCompany(w http.ResponseWriter, r *http.Request) {
id, err := parseUUIDFromPath(r.URL.Path)
if err != nil {
writeError(w, http.StatusBadRequest, err)
return
}
if err := h.svc.DeleteCompany(r.Context(), id); err != nil {
writeError(w, http.StatusBadRequest, err)
return
}
w.WriteHeader(http.StatusNoContent)
}
// VerifyCompany godoc
// @Summary Verificar empresa
// @Tags Empresas
// @Security BearerAuth
// @Param id path string true "Company ID"
// @Success 200 {object} domain.Company
// @Router /api/v1/companies/{id}/verify [patch]
// VerifyCompany toggles the verification flag for a company (admin only). // VerifyCompany toggles the verification flag for a company (admin only).
func (h *Handler) VerifyCompany(w http.ResponseWriter, r *http.Request) { func (h *Handler) VerifyCompany(w http.ResponseWriter, r *http.Request) {
if !strings.HasSuffix(r.URL.Path, "/verify") { if !strings.HasSuffix(r.URL.Path, "/verify") {
@ -182,6 +290,13 @@ func (h *Handler) VerifyCompany(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, company) writeJSON(w, http.StatusOK, company)
} }
// GetMyCompany godoc
// @Summary Obter minha empresa
// @Tags Empresas
// @Security BearerAuth
// @Produce json
// @Success 200 {object} domain.Company
// @Router /api/v1/companies/me [get]
// GetMyCompany returns the company linked to the authenticated user. // GetMyCompany returns the company linked to the authenticated user.
func (h *Handler) GetMyCompany(w http.ResponseWriter, r *http.Request) { func (h *Handler) GetMyCompany(w http.ResponseWriter, r *http.Request) {
claims, ok := middleware.GetClaims(r.Context()) claims, ok := middleware.GetClaims(r.Context())
@ -199,6 +314,13 @@ func (h *Handler) GetMyCompany(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, company) writeJSON(w, http.StatusOK, company)
} }
// GetCompanyRating godoc
// @Summary Obter avaliação da empresa
// @Tags Empresas
// @Produce json
// @Param id path string true "Company ID"
// @Success 200 {object} domain.CompanyRating
// @Router /api/v1/companies/{id}/rating [get]
// GetCompanyRating exposes the average score for a company. // GetCompanyRating exposes the average score for a company.
func (h *Handler) GetCompanyRating(w http.ResponseWriter, r *http.Request) { func (h *Handler) GetCompanyRating(w http.ResponseWriter, r *http.Request) {
if !strings.HasSuffix(r.URL.Path, "/rating") { if !strings.HasSuffix(r.URL.Path, "/rating") {
@ -269,6 +391,121 @@ func (h *Handler) ListProducts(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, products) writeJSON(w, http.StatusOK, products)
} }
// GetProduct godoc
// @Summary Obter produto
// @Tags Produtos
// @Produce json
// @Param id path string true "Product ID"
// @Success 200 {object} domain.Product
// @Failure 404 {object} map[string]string
// @Router /api/products/{id} [get]
func (h *Handler) GetProduct(w http.ResponseWriter, r *http.Request) {
id, err := parseUUIDFromPath(r.URL.Path)
if err != nil {
writeError(w, http.StatusBadRequest, err)
return
}
product, err := h.svc.GetProduct(r.Context(), id)
if err != nil {
writeError(w, http.StatusNotFound, err)
return
}
writeJSON(w, http.StatusOK, product)
}
// UpdateProduct godoc
// @Summary Atualizar produto
// @Tags Produtos
// @Accept json
// @Produce json
// @Param id path string true "Product ID"
// @Param payload body updateProductRequest true "Campos para atualização"
// @Success 200 {object} domain.Product
// @Failure 400 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /api/products/{id} [patch]
func (h *Handler) UpdateProduct(w http.ResponseWriter, r *http.Request) {
id, err := parseUUIDFromPath(r.URL.Path)
if err != nil {
writeError(w, http.StatusBadRequest, err)
return
}
var req updateProductRequest
if err := decodeJSON(r.Context(), r, &req); err != nil {
writeError(w, http.StatusBadRequest, err)
return
}
product, err := h.svc.GetProduct(r.Context(), id)
if err != nil {
writeError(w, http.StatusNotFound, err)
return
}
if req.SellerID != nil {
product.SellerID = *req.SellerID
}
if req.Name != nil {
product.Name = *req.Name
}
if req.Description != nil {
product.Description = *req.Description
}
if req.Batch != nil {
product.Batch = *req.Batch
}
if req.ExpiresAt != nil {
product.ExpiresAt = *req.ExpiresAt
}
if req.PriceCents != nil {
product.PriceCents = *req.PriceCents
}
if req.Stock != nil {
product.Stock = *req.Stock
}
if err := h.svc.UpdateProduct(r.Context(), product); err != nil {
writeError(w, http.StatusInternalServerError, err)
return
}
writeJSON(w, http.StatusOK, product)
}
// DeleteProduct godoc
// @Summary Remover produto
// @Tags Produtos
// @Param id path string true "Product ID"
// @Success 204 ""
// @Failure 400 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /api/products/{id} [delete]
func (h *Handler) DeleteProduct(w http.ResponseWriter, r *http.Request) {
id, err := parseUUIDFromPath(r.URL.Path)
if err != nil {
writeError(w, http.StatusBadRequest, err)
return
}
if err := h.svc.DeleteProduct(r.Context(), id); err != nil {
writeError(w, http.StatusBadRequest, err)
return
}
w.WriteHeader(http.StatusNoContent)
}
// ListInventory godoc
// @Summary Listar estoque
// @Tags Estoque
// @Security BearerAuth
// @Produce json
// @Param expires_in_days query int false "Dias para expiração"
// @Success 200 {array} domain.InventoryItem
// @Router /api/v1/inventory [get]
// ListInventory exposes stock with expiring batch filters. // ListInventory exposes stock with expiring batch filters.
func (h *Handler) ListInventory(w http.ResponseWriter, r *http.Request) { func (h *Handler) ListInventory(w http.ResponseWriter, r *http.Request) {
var filter domain.InventoryFilter var filter domain.InventoryFilter
@ -291,6 +528,16 @@ func (h *Handler) ListInventory(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, inventory) writeJSON(w, http.StatusOK, inventory)
} }
// AdjustInventory godoc
// @Summary Ajustar estoque
// @Tags Estoque
// @Security BearerAuth
// @Accept json
// @Produce json
// @Param payload body inventoryAdjustRequest true "Ajuste de estoque"
// @Success 200 {object} domain.InventoryItem
// @Failure 400 {object} map[string]string
// @Router /api/v1/inventory/adjust [post]
// AdjustInventory handles manual stock corrections. // AdjustInventory handles manual stock corrections.
func (h *Handler) AdjustInventory(w http.ResponseWriter, r *http.Request) { func (h *Handler) AdjustInventory(w http.ResponseWriter, r *http.Request) {
var req inventoryAdjustRequest var req inventoryAdjustRequest
@ -349,9 +596,27 @@ func (h *Handler) CreateOrder(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusCreated, order) writeJSON(w, http.StatusCreated, order)
} }
// ListOrders godoc
// @Summary Listar pedidos
// @Tags Pedidos
// @Security BearerAuth
// @Produce json
// @Success 200 {array} domain.Order
// @Router /api/orders [get]
func (h *Handler) ListOrders(w http.ResponseWriter, r *http.Request) {
orders, err := h.svc.ListOrders(r.Context())
if err != nil {
writeError(w, http.StatusInternalServerError, err)
return
}
writeJSON(w, http.StatusOK, orders)
}
// GetOrder godoc // GetOrder godoc
// @Summary Consulta pedido // @Summary Consulta pedido
// @Tags Pedidos // @Tags Pedidos
// @Security BearerAuth
// @Produce json // @Produce json
// @Param id path string true "Order ID" // @Param id path string true "Order ID"
// @Success 200 {object} domain.Order // @Success 200 {object} domain.Order
@ -375,6 +640,7 @@ func (h *Handler) GetOrder(w http.ResponseWriter, r *http.Request) {
// UpdateOrderStatus godoc // UpdateOrderStatus godoc
// @Summary Atualiza status do pedido // @Summary Atualiza status do pedido
// @Tags Pedidos // @Tags Pedidos
// @Security BearerAuth
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Param id path string true "Order ID" // @Param id path string true "Order ID"
@ -407,6 +673,40 @@ func (h *Handler) UpdateOrderStatus(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNoContent) w.WriteHeader(http.StatusNoContent)
} }
// DeleteOrder godoc
// @Summary Remover pedido
// @Tags Pedidos
// @Security BearerAuth
// @Param id path string true "Order ID"
// @Success 204 ""
// @Failure 400 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /api/orders/{id} [delete]
func (h *Handler) DeleteOrder(w http.ResponseWriter, r *http.Request) {
id, err := parseUUIDFromPath(r.URL.Path)
if err != nil {
writeError(w, http.StatusBadRequest, err)
return
}
if err := h.svc.DeleteOrder(r.Context(), id); err != nil {
writeError(w, http.StatusBadRequest, err)
return
}
w.WriteHeader(http.StatusNoContent)
}
// CreateReview godoc
// @Summary Criar avaliação
// @Tags Avaliações
// @Security BearerAuth
// @Accept json
// @Produce json
// @Param payload body createReviewRequest true "Dados da avaliação"
// @Success 201 {object} domain.Review
// @Failure 400 {object} map[string]string
// @Router /api/v1/reviews [post]
// CreateReview allows buyers to rate the seller after delivery. // CreateReview allows buyers to rate the seller after delivery.
func (h *Handler) CreateReview(w http.ResponseWriter, r *http.Request) { func (h *Handler) CreateReview(w http.ResponseWriter, r *http.Request) {
claims, ok := middleware.GetClaims(r.Context()) claims, ok := middleware.GetClaims(r.Context())
@ -430,6 +730,16 @@ func (h *Handler) CreateReview(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusCreated, review) writeJSON(w, http.StatusCreated, review)
} }
// AddToCart godoc
// @Summary Adicionar item ao carrinho
// @Tags Carrinho
// @Security BearerAuth
// @Accept json
// @Produce json
// @Param payload body addCartItemRequest true "Item do carrinho"
// @Success 201 {object} domain.CartSummary
// @Failure 400 {object} map[string]string
// @Router /api/v1/cart [post]
// AddToCart appends an item to the authenticated buyer cart respecting stock. // AddToCart appends an item to the authenticated buyer cart respecting stock.
func (h *Handler) AddToCart(w http.ResponseWriter, r *http.Request) { func (h *Handler) AddToCart(w http.ResponseWriter, r *http.Request) {
claims, ok := middleware.GetClaims(r.Context()) claims, ok := middleware.GetClaims(r.Context())
@ -453,6 +763,13 @@ func (h *Handler) AddToCart(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusCreated, summary) writeJSON(w, http.StatusCreated, summary)
} }
// GetCart godoc
// @Summary Obter carrinho
// @Tags Carrinho
// @Security BearerAuth
// @Produce json
// @Success 200 {object} domain.CartSummary
// @Router /api/v1/cart [get]
// GetCart returns cart contents and totals for the authenticated buyer. // GetCart returns cart contents and totals for the authenticated buyer.
func (h *Handler) GetCart(w http.ResponseWriter, r *http.Request) { func (h *Handler) GetCart(w http.ResponseWriter, r *http.Request) {
claims, ok := middleware.GetClaims(r.Context()) claims, ok := middleware.GetClaims(r.Context())
@ -469,6 +786,14 @@ func (h *Handler) GetCart(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, summary) writeJSON(w, http.StatusOK, summary)
} }
// DeleteCartItem godoc
// @Summary Remover item do carrinho
// @Tags Carrinho
// @Security BearerAuth
// @Param id path string true "Cart item ID"
// @Success 200 {object} domain.CartSummary
// @Failure 400 {object} map[string]string
// @Router /api/v1/cart/{id} [delete]
// DeleteCartItem removes a product from the cart and returns the updated totals. // DeleteCartItem removes a product from the cart and returns the updated totals.
func (h *Handler) DeleteCartItem(w http.ResponseWriter, r *http.Request) { func (h *Handler) DeleteCartItem(w http.ResponseWriter, r *http.Request) {
claims, ok := middleware.GetClaims(r.Context()) claims, ok := middleware.GetClaims(r.Context())
@ -495,6 +820,7 @@ func (h *Handler) DeleteCartItem(w http.ResponseWriter, r *http.Request) {
// CreatePaymentPreference godoc // CreatePaymentPreference godoc
// @Summary Cria preferência de pagamento Mercado Pago com split nativo // @Summary Cria preferência de pagamento Mercado Pago com split nativo
// @Tags Pagamentos // @Tags Pagamentos
// @Security BearerAuth
// @Produce json // @Produce json
// @Param id path string true "Order ID" // @Param id path string true "Order ID"
// @Success 201 {object} domain.PaymentPreference // @Success 201 {object} domain.PaymentPreference
@ -523,6 +849,7 @@ func (h *Handler) CreatePaymentPreference(w http.ResponseWriter, r *http.Request
// CreateShipment godoc // CreateShipment godoc
// @Summary Gera guia de postagem/transporte // @Summary Gera guia de postagem/transporte
// @Tags Logistica // @Tags Logistica
// @Security BearerAuth
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Param shipment body createShipmentRequest true "Dados de envio" // @Param shipment body createShipmentRequest true "Dados de envio"
@ -553,6 +880,7 @@ func (h *Handler) CreateShipment(w http.ResponseWriter, r *http.Request) {
// GetShipmentByOrderID godoc // GetShipmentByOrderID godoc
// @Summary Rastreia entrega // @Summary Rastreia entrega
// @Tags Logistica // @Tags Logistica
// @Security BearerAuth
// @Produce json // @Produce json
// @Param order_id path string true "Order ID" // @Param order_id path string true "Order ID"
// @Success 200 {object} domain.Shipment // @Success 200 {object} domain.Shipment
@ -598,6 +926,13 @@ func (h *Handler) HandlePaymentWebhook(w http.ResponseWriter, r *http.Request) {
} }
// GetSellerDashboard aggregates KPIs for the authenticated seller or the requested company. // GetSellerDashboard aggregates KPIs for the authenticated seller or the requested company.
// @Summary Dashboard do vendedor
// @Tags Dashboard
// @Security BearerAuth
// @Produce json
// @Param seller_id query string false "Seller ID"
// @Success 200 {object} domain.SellerDashboard
// @Router /api/v1/dashboard/seller [get]
func (h *Handler) GetSellerDashboard(w http.ResponseWriter, r *http.Request) { func (h *Handler) GetSellerDashboard(w http.ResponseWriter, r *http.Request) {
requester, err := getRequester(r) requester, err := getRequester(r)
if err != nil { if err != nil {
@ -635,6 +970,12 @@ func (h *Handler) GetSellerDashboard(w http.ResponseWriter, r *http.Request) {
} }
// GetAdminDashboard exposes platform-wide aggregated metrics. // GetAdminDashboard exposes platform-wide aggregated metrics.
// @Summary Dashboard do administrador
// @Tags Dashboard
// @Security BearerAuth
// @Produce json
// @Success 200 {object} domain.AdminDashboard
// @Router /api/v1/dashboard/admin [get]
func (h *Handler) GetAdminDashboard(w http.ResponseWriter, r *http.Request) { func (h *Handler) GetAdminDashboard(w http.ResponseWriter, r *http.Request) {
requester, err := getRequester(r) requester, err := getRequester(r)
if err != nil { if err != nil {
@ -1024,6 +1365,14 @@ type registerCompanyRequest struct {
LicenseNumber string `json:"license_number"` LicenseNumber string `json:"license_number"`
} }
type updateCompanyRequest struct {
Role *string `json:"role,omitempty"`
CNPJ *string `json:"cnpj,omitempty"`
CorporateName *string `json:"corporate_name,omitempty"`
LicenseNumber *string `json:"license_number,omitempty"`
IsVerified *bool `json:"is_verified,omitempty"`
}
type registerProductRequest struct { type registerProductRequest struct {
SellerID uuid.UUID `json:"seller_id"` SellerID uuid.UUID `json:"seller_id"`
Name string `json:"name"` Name string `json:"name"`
@ -1034,6 +1383,16 @@ type registerProductRequest struct {
Stock int64 `json:"stock"` Stock int64 `json:"stock"`
} }
type updateProductRequest struct {
SellerID *uuid.UUID `json:"seller_id,omitempty"`
Name *string `json:"name,omitempty"`
Description *string `json:"description,omitempty"`
Batch *string `json:"batch,omitempty"`
ExpiresAt *time.Time `json:"expires_at,omitempty"`
PriceCents *int64 `json:"price_cents,omitempty"`
Stock *int64 `json:"stock,omitempty"`
}
type createOrderRequest struct { type createOrderRequest struct {
BuyerID uuid.UUID `json:"buyer_id"` BuyerID uuid.UUID `json:"buyer_id"`
SellerID uuid.UUID `json:"seller_id"` SellerID uuid.UUID `json:"seller_id"`

View file

@ -74,6 +74,53 @@ WHERE id = :id`
return nil return nil
} }
func (r *Repository) DeleteCompany(ctx context.Context, id uuid.UUID) error {
var count int
if err := r.db.GetContext(ctx, &count, `SELECT COUNT(*) FROM users WHERE company_id = $1`, id); err != nil {
return err
}
if count > 0 {
return errors.New("company has related users")
}
if err := r.db.GetContext(ctx, &count, `SELECT COUNT(*) FROM products WHERE seller_id = $1`, id); err != nil {
return err
}
if count > 0 {
return errors.New("company has related products")
}
if err := r.db.GetContext(ctx, &count, `SELECT COUNT(*) FROM orders WHERE buyer_id = $1 OR seller_id = $1`, id); err != nil {
return err
}
if count > 0 {
return errors.New("company has related orders")
}
if err := r.db.GetContext(ctx, &count, `SELECT COUNT(*) FROM reviews WHERE buyer_id = $1 OR seller_id = $1`, id); err != nil {
return err
}
if count > 0 {
return errors.New("company has related reviews")
}
if err := r.db.GetContext(ctx, &count, `SELECT COUNT(*) FROM cart_items WHERE buyer_id = $1`, id); err != nil {
return err
}
if count > 0 {
return errors.New("company has related cart items")
}
res, err := r.db.ExecContext(ctx, `DELETE FROM companies WHERE id = $1`, id)
if err != nil {
return err
}
rows, err := res.RowsAffected()
if err != nil {
return err
}
if rows == 0 {
return errors.New("company not found")
}
return nil
}
func (r *Repository) CreateProduct(ctx context.Context, product *domain.Product) error { func (r *Repository) CreateProduct(ctx context.Context, product *domain.Product) error {
now := time.Now().UTC() now := time.Now().UTC()
product.CreatedAt = now product.CreatedAt = now
@ -104,6 +151,68 @@ func (r *Repository) GetProduct(ctx context.Context, id uuid.UUID) (*domain.Prod
return &product, nil return &product, nil
} }
func (r *Repository) UpdateProduct(ctx context.Context, product *domain.Product) error {
product.UpdatedAt = time.Now().UTC()
query := `UPDATE products
SET seller_id = :seller_id, name = :name, description = :description, batch = :batch, expires_at = :expires_at, price_cents = :price_cents, stock = :stock, updated_at = :updated_at
WHERE id = :id`
res, err := r.db.NamedExecContext(ctx, query, product)
if err != nil {
return err
}
rows, err := res.RowsAffected()
if err != nil {
return err
}
if rows == 0 {
return errors.New("product not found")
}
return nil
}
func (r *Repository) DeleteProduct(ctx context.Context, id uuid.UUID) error {
var count int
if err := r.db.GetContext(ctx, &count, `SELECT COUNT(*) FROM order_items WHERE product_id = $1`, id); err != nil {
return err
}
if count > 0 {
return errors.New("product has related orders")
}
tx, err := r.db.BeginTxx(ctx, nil)
if err != nil {
return err
}
if _, err := tx.ExecContext(ctx, `DELETE FROM inventory_adjustments WHERE product_id = $1`, id); err != nil {
_ = tx.Rollback()
return err
}
if _, err := tx.ExecContext(ctx, `DELETE FROM cart_items WHERE product_id = $1`, id); err != nil {
_ = tx.Rollback()
return err
}
res, err := tx.ExecContext(ctx, `DELETE FROM products WHERE id = $1`, id)
if err != nil {
_ = tx.Rollback()
return err
}
rows, err := res.RowsAffected()
if err != nil {
_ = tx.Rollback()
return err
}
if rows == 0 {
_ = tx.Rollback()
return errors.New("product not found")
}
return tx.Commit()
}
func (r *Repository) CreateOrder(ctx context.Context, order *domain.Order) error { func (r *Repository) CreateOrder(ctx context.Context, order *domain.Order) error {
now := time.Now().UTC() now := time.Now().UTC()
order.CreatedAt = now order.CreatedAt = now
@ -135,6 +244,62 @@ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)`
return tx.Commit() return tx.Commit()
} }
func (r *Repository) ListOrders(ctx context.Context) ([]domain.Order, error) {
var rows []struct {
ID uuid.UUID `db:"id"`
BuyerID uuid.UUID `db:"buyer_id"`
SellerID uuid.UUID `db:"seller_id"`
Status domain.OrderStatus `db:"status"`
TotalCents int64 `db:"total_cents"`
ShippingRecipientName string `db:"shipping_recipient_name"`
ShippingStreet string `db:"shipping_street"`
ShippingNumber string `db:"shipping_number"`
ShippingComplement string `db:"shipping_complement"`
ShippingDistrict string `db:"shipping_district"`
ShippingCity string `db:"shipping_city"`
ShippingState string `db:"shipping_state"`
ShippingZipCode string `db:"shipping_zip_code"`
ShippingCountry string `db:"shipping_country"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
}
query := `SELECT id, buyer_id, seller_id, status, total_cents, shipping_recipient_name, shipping_street, shipping_number, shipping_complement, shipping_district, shipping_city, shipping_state, shipping_zip_code, shipping_country, created_at, updated_at FROM orders ORDER BY created_at DESC`
if err := r.db.SelectContext(ctx, &rows, query); err != nil {
return nil, err
}
orders := make([]domain.Order, 0, len(rows))
itemQuery := `SELECT id, order_id, product_id, quantity, unit_cents, batch, expires_at FROM order_items WHERE order_id = $1`
for _, row := range rows {
var items []domain.OrderItem
if err := r.db.SelectContext(ctx, &items, itemQuery, row.ID); err != nil {
return nil, err
}
orders = append(orders, domain.Order{
ID: row.ID,
BuyerID: row.BuyerID,
SellerID: row.SellerID,
Status: row.Status,
TotalCents: row.TotalCents,
Items: items,
Shipping: domain.ShippingAddress{
RecipientName: row.ShippingRecipientName,
Street: row.ShippingStreet,
Number: row.ShippingNumber,
Complement: row.ShippingComplement,
District: row.ShippingDistrict,
City: row.ShippingCity,
State: row.ShippingState,
ZipCode: row.ShippingZipCode,
Country: row.ShippingCountry,
},
CreatedAt: row.CreatedAt,
UpdatedAt: row.UpdatedAt,
})
}
return orders, nil
}
func (r *Repository) GetOrder(ctx context.Context, id uuid.UUID) (*domain.Order, error) { func (r *Repository) GetOrder(ctx context.Context, id uuid.UUID) (*domain.Order, error) {
var row struct { var row struct {
ID uuid.UUID `db:"id"` ID uuid.UUID `db:"id"`
@ -204,6 +369,43 @@ func (r *Repository) UpdateOrderStatus(ctx context.Context, id uuid.UUID, status
return nil return nil
} }
func (r *Repository) DeleteOrder(ctx context.Context, id uuid.UUID) error {
tx, err := r.db.BeginTxx(ctx, nil)
if err != nil {
return err
}
if _, err := tx.ExecContext(ctx, `DELETE FROM reviews WHERE order_id = $1`, id); err != nil {
_ = tx.Rollback()
return err
}
if _, err := tx.ExecContext(ctx, `DELETE FROM shipments WHERE order_id = $1`, id); err != nil {
_ = tx.Rollback()
return err
}
if _, err := tx.ExecContext(ctx, `DELETE FROM order_items WHERE order_id = $1`, id); err != nil {
_ = tx.Rollback()
return err
}
res, err := tx.ExecContext(ctx, `DELETE FROM orders WHERE id = $1`, id)
if err != nil {
_ = tx.Rollback()
return err
}
rows, err := res.RowsAffected()
if err != nil {
_ = tx.Rollback()
return err
}
if rows == 0 {
_ = tx.Rollback()
return errors.New("order not found")
}
return tx.Commit()
}
func (r *Repository) CreateShipment(ctx context.Context, shipment *domain.Shipment) error { func (r *Repository) CreateShipment(ctx context.Context, shipment *domain.Shipment) error {
now := time.Now().UTC() now := time.Now().UTC()
shipment.CreatedAt = now shipment.CreatedAt = now

View file

@ -64,19 +64,27 @@ func New(cfg config.Config) (*Server, error) {
mux.Handle("POST /api/companies", chain(http.HandlerFunc(h.CreateCompany), middleware.Logger, middleware.Gzip)) mux.Handle("POST /api/companies", chain(http.HandlerFunc(h.CreateCompany), middleware.Logger, middleware.Gzip))
mux.Handle("GET /api/companies", chain(http.HandlerFunc(h.ListCompanies), middleware.Logger, middleware.Gzip)) mux.Handle("GET /api/companies", chain(http.HandlerFunc(h.ListCompanies), middleware.Logger, middleware.Gzip))
mux.Handle("GET /api/companies/", chain(http.HandlerFunc(h.GetCompany), middleware.Logger, middleware.Gzip))
mux.Handle("PATCH /api/companies/", chain(http.HandlerFunc(h.UpdateCompany), middleware.Logger, middleware.Gzip))
mux.Handle("DELETE /api/companies/", chain(http.HandlerFunc(h.DeleteCompany), middleware.Logger, middleware.Gzip))
mux.Handle("PATCH /api/v1/companies/", chain(http.HandlerFunc(h.VerifyCompany), middleware.Logger, middleware.Gzip, adminOnly)) mux.Handle("PATCH /api/v1/companies/", chain(http.HandlerFunc(h.VerifyCompany), middleware.Logger, middleware.Gzip, adminOnly))
mux.Handle("GET /api/v1/companies/me", chain(http.HandlerFunc(h.GetMyCompany), middleware.Logger, middleware.Gzip, auth)) mux.Handle("GET /api/v1/companies/me", chain(http.HandlerFunc(h.GetMyCompany), middleware.Logger, middleware.Gzip, auth))
mux.Handle("GET /api/v1/companies/", chain(http.HandlerFunc(h.GetCompanyRating), middleware.Logger, middleware.Gzip)) mux.Handle("GET /api/v1/companies/", chain(http.HandlerFunc(h.GetCompanyRating), middleware.Logger, middleware.Gzip))
mux.Handle("POST /api/products", chain(http.HandlerFunc(h.CreateProduct), middleware.Logger, middleware.Gzip)) mux.Handle("POST /api/products", chain(http.HandlerFunc(h.CreateProduct), middleware.Logger, middleware.Gzip))
mux.Handle("GET /api/products", chain(http.HandlerFunc(h.ListProducts), middleware.Logger, middleware.Gzip)) mux.Handle("GET /api/products", chain(http.HandlerFunc(h.ListProducts), middleware.Logger, middleware.Gzip))
mux.Handle("GET /api/products/", chain(http.HandlerFunc(h.GetProduct), middleware.Logger, middleware.Gzip))
mux.Handle("PATCH /api/products/", chain(http.HandlerFunc(h.UpdateProduct), middleware.Logger, middleware.Gzip))
mux.Handle("DELETE /api/products/", chain(http.HandlerFunc(h.DeleteProduct), middleware.Logger, middleware.Gzip))
mux.Handle("GET /api/v1/inventory", chain(http.HandlerFunc(h.ListInventory), middleware.Logger, middleware.Gzip, auth)) mux.Handle("GET /api/v1/inventory", chain(http.HandlerFunc(h.ListInventory), middleware.Logger, middleware.Gzip, auth))
mux.Handle("POST /api/v1/inventory/adjust", chain(http.HandlerFunc(h.AdjustInventory), middleware.Logger, middleware.Gzip, auth)) mux.Handle("POST /api/v1/inventory/adjust", chain(http.HandlerFunc(h.AdjustInventory), middleware.Logger, middleware.Gzip, auth))
mux.Handle("POST /api/orders", chain(http.HandlerFunc(h.CreateOrder), middleware.Logger, middleware.Gzip, auth)) mux.Handle("POST /api/orders", chain(http.HandlerFunc(h.CreateOrder), middleware.Logger, middleware.Gzip, auth))
mux.Handle("GET /api/orders", chain(http.HandlerFunc(h.ListOrders), middleware.Logger, middleware.Gzip, auth))
mux.Handle("GET /api/orders/", chain(http.HandlerFunc(h.GetOrder), middleware.Logger, middleware.Gzip, auth)) mux.Handle("GET /api/orders/", chain(http.HandlerFunc(h.GetOrder), middleware.Logger, middleware.Gzip, auth))
mux.Handle("PATCH /api/orders/", chain(http.HandlerFunc(h.UpdateOrderStatus), middleware.Logger, middleware.Gzip, auth)) mux.Handle("PATCH /api/orders/", chain(http.HandlerFunc(h.UpdateOrderStatus), middleware.Logger, middleware.Gzip, auth))
mux.Handle("DELETE /api/orders/", chain(http.HandlerFunc(h.DeleteOrder), middleware.Logger, middleware.Gzip, auth))
mux.Handle("POST /api/orders/", chain(http.HandlerFunc(h.CreatePaymentPreference), middleware.Logger, middleware.Gzip, auth)) mux.Handle("POST /api/orders/", chain(http.HandlerFunc(h.CreatePaymentPreference), middleware.Logger, middleware.Gzip, auth))
mux.Handle("POST /api/v1/shipments", chain(http.HandlerFunc(h.CreateShipment), middleware.Logger, middleware.Gzip, auth)) mux.Handle("POST /api/v1/shipments", chain(http.HandlerFunc(h.CreateShipment), middleware.Logger, middleware.Gzip, auth))

View file

@ -20,16 +20,21 @@ type Repository interface {
ListCompanies(ctx context.Context) ([]domain.Company, error) ListCompanies(ctx context.Context) ([]domain.Company, error)
GetCompany(ctx context.Context, id uuid.UUID) (*domain.Company, error) GetCompany(ctx context.Context, id uuid.UUID) (*domain.Company, error)
UpdateCompany(ctx context.Context, company *domain.Company) error UpdateCompany(ctx context.Context, company *domain.Company) error
DeleteCompany(ctx context.Context, id uuid.UUID) error
CreateProduct(ctx context.Context, product *domain.Product) error CreateProduct(ctx context.Context, product *domain.Product) error
ListProducts(ctx context.Context) ([]domain.Product, error) ListProducts(ctx context.Context) ([]domain.Product, error)
GetProduct(ctx context.Context, id uuid.UUID) (*domain.Product, error) GetProduct(ctx context.Context, id uuid.UUID) (*domain.Product, error)
UpdateProduct(ctx context.Context, product *domain.Product) error
DeleteProduct(ctx context.Context, id uuid.UUID) error
AdjustInventory(ctx context.Context, productID uuid.UUID, delta int64, reason string) (*domain.InventoryItem, error) AdjustInventory(ctx context.Context, productID uuid.UUID, delta int64, reason string) (*domain.InventoryItem, error)
ListInventory(ctx context.Context, filter domain.InventoryFilter) ([]domain.InventoryItem, error) ListInventory(ctx context.Context, filter domain.InventoryFilter) ([]domain.InventoryItem, error)
CreateOrder(ctx context.Context, order *domain.Order) error CreateOrder(ctx context.Context, order *domain.Order) error
ListOrders(ctx context.Context) ([]domain.Order, error)
GetOrder(ctx context.Context, id uuid.UUID) (*domain.Order, error) GetOrder(ctx context.Context, id uuid.UUID) (*domain.Order, error)
UpdateOrderStatus(ctx context.Context, id uuid.UUID, status domain.OrderStatus) error UpdateOrderStatus(ctx context.Context, id uuid.UUID, status domain.OrderStatus) error
DeleteOrder(ctx context.Context, id uuid.UUID) error
CreateShipment(ctx context.Context, shipment *domain.Shipment) error CreateShipment(ctx context.Context, shipment *domain.Shipment) error
GetShipmentByOrderID(ctx context.Context, orderID uuid.UUID) (*domain.Shipment, error) GetShipmentByOrderID(ctx context.Context, orderID uuid.UUID) (*domain.Shipment, error)
@ -89,6 +94,14 @@ func (s *Service) GetCompany(ctx context.Context, id uuid.UUID) (*domain.Company
return s.repo.GetCompany(ctx, id) return s.repo.GetCompany(ctx, id)
} }
func (s *Service) UpdateCompany(ctx context.Context, company *domain.Company) error {
return s.repo.UpdateCompany(ctx, company)
}
func (s *Service) DeleteCompany(ctx context.Context, id uuid.UUID) error {
return s.repo.DeleteCompany(ctx, id)
}
func (s *Service) RegisterProduct(ctx context.Context, product *domain.Product) error { func (s *Service) RegisterProduct(ctx context.Context, product *domain.Product) error {
product.ID = uuid.Must(uuid.NewV7()) product.ID = uuid.Must(uuid.NewV7())
return s.repo.CreateProduct(ctx, product) return s.repo.CreateProduct(ctx, product)
@ -98,6 +111,18 @@ func (s *Service) ListProducts(ctx context.Context) ([]domain.Product, error) {
return s.repo.ListProducts(ctx) return s.repo.ListProducts(ctx)
} }
func (s *Service) GetProduct(ctx context.Context, id uuid.UUID) (*domain.Product, error) {
return s.repo.GetProduct(ctx, id)
}
func (s *Service) UpdateProduct(ctx context.Context, product *domain.Product) error {
return s.repo.UpdateProduct(ctx, product)
}
func (s *Service) DeleteProduct(ctx context.Context, id uuid.UUID) error {
return s.repo.DeleteProduct(ctx, id)
}
func (s *Service) ListInventory(ctx context.Context, filter domain.InventoryFilter) ([]domain.InventoryItem, error) { func (s *Service) ListInventory(ctx context.Context, filter domain.InventoryFilter) ([]domain.InventoryItem, error) {
return s.repo.ListInventory(ctx, filter) return s.repo.ListInventory(ctx, filter)
} }
@ -112,6 +137,10 @@ func (s *Service) CreateOrder(ctx context.Context, order *domain.Order) error {
return s.repo.CreateOrder(ctx, order) return s.repo.CreateOrder(ctx, order)
} }
func (s *Service) ListOrders(ctx context.Context) ([]domain.Order, error) {
return s.repo.ListOrders(ctx)
}
func (s *Service) GetOrder(ctx context.Context, id uuid.UUID) (*domain.Order, error) { func (s *Service) GetOrder(ctx context.Context, id uuid.UUID) (*domain.Order, error) {
return s.repo.GetOrder(ctx, id) return s.repo.GetOrder(ctx, id)
} }
@ -120,6 +149,10 @@ func (s *Service) UpdateOrderStatus(ctx context.Context, id uuid.UUID, status do
return s.repo.UpdateOrderStatus(ctx, id, status) return s.repo.UpdateOrderStatus(ctx, id, status)
} }
func (s *Service) DeleteOrder(ctx context.Context, id uuid.UUID) error {
return s.repo.DeleteOrder(ctx, id)
}
// CreateShipment persists a freight label for an order if not already present. // CreateShipment persists a freight label for an order if not already present.
func (s *Service) CreateShipment(ctx context.Context, shipment *domain.Shipment) error { func (s *Service) CreateShipment(ctx context.Context, shipment *domain.Shipment) error {
if _, err := s.repo.GetOrder(ctx, shipment.OrderID); err != nil { if _, err := s.repo.GetOrder(ctx, shipment.OrderID); err != nil {