Backend: - Implementa API de Endereços (`POST /enderecos`) e migration da tabela `addresses`. - Adiciona bloqueio de login para usuários de empresas não verificadas (status `pending`). - Criação automática do usuário Master (`seedAdmin`) com empresa verificada. - Adiciona aliases de rota em PT-BR (`/api/v1/empresas` GET/PATCH, `/api/v1/usuarios` PATCH) para compatibilidade com o frontend. - Atualiza DTOs para suportar campos em português no registro de empresas e atualização de usuários. - Endpoint `/auth/me` agora retorna `company_name` e flag `superadmin`. - Ajusta filtro de repositório para listar empresas por status de verificação. Frontend: - Nova página `/usuarios-pendentes` com layout padrão e funcionalidade de aprovação. - Atualiza [Header](cci:1://file:///c:/Projetos/saveinmed/saveinmed-frontend/src/components/Header.tsx:29:0-337:2) para exibir o nome da empresa do usuário logado. - Serviço `empresaApiService`: correções de mapeamento (`corporate_name` -> `razao_social`) e novos métodos. - Tipagem atualizada para incluir campos de empresa no [UserData](cci:2://file:///c:/Projetos/saveinmed/saveinmed-frontend/src/types/auth.ts:15:0-30:1). Fixes: - Correção de erro 405 (Method Not Allowed) nas rotas de atualização. - Correção de erro 404 na listagem de pendentes. - Resolução de campos vazios na listagem de empresas.
534 lines
20 KiB
Go
534 lines
20 KiB
Go
package domain
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/gofrs/uuid/v5"
|
|
)
|
|
|
|
// Tenant represents a B2B actor (pharmacy/distributor) in the marketplace.
|
|
type Tenant struct {
|
|
ID uuid.UUID `db:"id" json:"id"`
|
|
CNPJ string `db:"cnpj" json:"cnpj"`
|
|
CorporateName string `db:"corporate_name" json:"corporate_name"`
|
|
Category string `db:"category" json:"category"` // farmacia, distribuidora
|
|
LicenseNumber string `db:"license_number" json:"license_number"`
|
|
IsVerified bool `db:"is_verified" json:"is_verified"`
|
|
// Location
|
|
Latitude float64 `db:"latitude" json:"latitude"`
|
|
Longitude float64 `db:"longitude" json:"longitude"`
|
|
City string `db:"city" json:"city"`
|
|
State string `db:"state" json:"state"`
|
|
// Contact & Hours
|
|
Phone string `db:"phone" json:"phone"`
|
|
OperatingHours string `db:"operating_hours" json:"operating_hours"` // e.g. "Seg-Sex: 08:00-18:00, Sab: 08:00-12:00"
|
|
Is24Hours bool `db:"is_24_hours" json:"is_24_hours"`
|
|
// Credit Lines (Boleto a Prazo)
|
|
CreditLimitCents int64 `db:"credit_limit_cents" json:"credit_limit_cents"` // max credit allowed
|
|
CreditUsedCents int64 `db:"credit_used_cents" json:"credit_used_cents"` // currently in use
|
|
// Timestamps
|
|
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
|
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
|
}
|
|
|
|
// Company is an alias for Tenant for backward compatibility.
|
|
type Company = Tenant
|
|
|
|
// Role constants
|
|
const (
|
|
RoleAdmin = "Admin"
|
|
RoleOwner = "Dono"
|
|
RoleManager = "Gerente"
|
|
RolePurchaser = "Comprador"
|
|
RoleEmployee = "Colaborador"
|
|
RoleDelivery = "Entregador"
|
|
)
|
|
|
|
// User represents an authenticated actor inside a company.
|
|
type User struct {
|
|
ID uuid.UUID `db:"id" json:"id"`
|
|
CompanyID uuid.UUID `db:"company_id" json:"company_id"`
|
|
Role string `db:"role" json:"role"`
|
|
Name string `db:"name" json:"name"`
|
|
Username string `db:"username" json:"username"`
|
|
Email string `db:"email" json:"email"`
|
|
EmailVerified bool `db:"email_verified" json:"email_verified"`
|
|
PasswordHash string `db:"password_hash" json:"-"`
|
|
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
|
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
|
}
|
|
|
|
// UserFilter captures listing constraints.
|
|
type UserFilter struct {
|
|
CompanyID *uuid.UUID
|
|
Limit int
|
|
Offset int
|
|
}
|
|
|
|
// UserPage wraps paginated results.
|
|
type UserPage struct {
|
|
Users []User `json:"users"`
|
|
Total int64 `json:"total"`
|
|
Page int `json:"page"`
|
|
PageSize int `json:"page_size"`
|
|
}
|
|
|
|
// Product represents a medicine SKU with batch tracking.
|
|
type Product struct {
|
|
ID uuid.UUID `db:"id" json:"id"`
|
|
SellerID uuid.UUID `db:"seller_id" json:"seller_id"`
|
|
EANCode string `db:"ean_code" json:"ean_code"`
|
|
Name string `db:"name" json:"name"`
|
|
Description string `db:"description" json:"description"`
|
|
Manufacturer string `db:"manufacturer" json:"manufacturer"`
|
|
Category string `db:"category" json:"category"`
|
|
Subcategory string `db:"subcategory" json:"subcategory"`
|
|
Batch string `db:"batch" json:"batch"`
|
|
ExpiresAt time.Time `db:"expires_at" json:"expires_at"`
|
|
PriceCents int64 `db:"price_cents" json:"price_cents"`
|
|
Stock int64 `db:"stock" json:"stock"`
|
|
Observations string `db:"observations" json:"observations"`
|
|
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
|
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
|
}
|
|
|
|
// InventoryItem exposes stock tracking tied to product batches.
|
|
type InventoryItem struct {
|
|
ProductID uuid.UUID `db:"product_id" json:"product_id"`
|
|
SellerID uuid.UUID `db:"seller_id" json:"seller_id"`
|
|
Name string `db:"name" json:"name"`
|
|
Batch string `db:"batch" json:"batch"`
|
|
ExpiresAt time.Time `db:"expires_at" json:"expires_at"`
|
|
Quantity int64 `db:"quantity" json:"quantity"`
|
|
PriceCents int64 `db:"price_cents" json:"price_cents"`
|
|
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
|
}
|
|
|
|
// InventoryFilter allows filtering by expiration window with pagination.
|
|
type InventoryFilter struct {
|
|
ExpiringBefore *time.Time
|
|
SellerID *uuid.UUID
|
|
Limit int
|
|
Offset int
|
|
}
|
|
|
|
// InventoryPage wraps paginated inventory results.
|
|
type InventoryPage struct {
|
|
Items []InventoryItem `json:"items"`
|
|
Total int64 `json:"total"`
|
|
Page int `json:"page"`
|
|
PageSize int `json:"page_size"`
|
|
}
|
|
|
|
// ProductFilter captures product listing constraints.
|
|
type ProductFilter struct {
|
|
SellerID *uuid.UUID
|
|
Category string
|
|
Search string
|
|
Limit int
|
|
Offset int
|
|
}
|
|
|
|
// ProductPage wraps paginated product results.
|
|
type ProductPage struct {
|
|
Products []Product `json:"products"`
|
|
Total int64 `json:"total"`
|
|
Page int `json:"page"`
|
|
PageSize int `json:"page_size"`
|
|
}
|
|
|
|
// CompanyFilter captures company/tenant listing constraints.
|
|
type CompanyFilter struct {
|
|
Category string
|
|
Search string
|
|
City string
|
|
State string
|
|
IsVerified *bool
|
|
Limit int
|
|
Offset int
|
|
}
|
|
|
|
// TenantFilter is an alias for CompanyFilter.
|
|
type TenantFilter = CompanyFilter
|
|
|
|
// CompanyPage wraps paginated company/tenant results.
|
|
type CompanyPage struct {
|
|
Companies []Company `json:"tenants"`
|
|
Total int64 `json:"total"`
|
|
Page int `json:"page"`
|
|
PageSize int `json:"page_size"`
|
|
}
|
|
|
|
// TenantPage is an alias for CompanyPage.
|
|
type TenantPage = CompanyPage
|
|
|
|
// OrderFilter captures order listing constraints.
|
|
type OrderFilter struct {
|
|
BuyerID *uuid.UUID
|
|
SellerID *uuid.UUID
|
|
Status OrderStatus
|
|
Limit int
|
|
Offset int
|
|
}
|
|
|
|
// OrderPage wraps paginated order results.
|
|
type OrderPage struct {
|
|
Orders []Order `json:"orders"`
|
|
Total int64 `json:"total"`
|
|
Page int `json:"page"`
|
|
PageSize int `json:"page_size"`
|
|
}
|
|
|
|
// InventoryAdjustment records manual stock corrections.
|
|
type InventoryAdjustment struct {
|
|
ID uuid.UUID `db:"id" json:"id"`
|
|
ProductID uuid.UUID `db:"product_id" json:"product_id"`
|
|
Delta int64 `db:"delta" json:"delta"`
|
|
Reason string `db:"reason" json:"reason"`
|
|
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
|
}
|
|
|
|
// Order captures the status lifecycle and payment intent.
|
|
type Order struct {
|
|
ID uuid.UUID `db:"id" json:"id"`
|
|
BuyerID uuid.UUID `db:"buyer_id" json:"buyer_id"`
|
|
SellerID uuid.UUID `db:"seller_id" json:"seller_id"`
|
|
Status OrderStatus `db:"status" json:"status"`
|
|
TotalCents int64 `db:"total_cents" json:"total_cents"`
|
|
PaymentMethod PaymentMethod `db:"payment_method" json:"payment_method"`
|
|
Items []OrderItem `json:"items"`
|
|
Shipping ShippingAddress `json:"shipping"`
|
|
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
|
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
|
}
|
|
|
|
// OrderItem stores SKU-level batch tracking.
|
|
type OrderItem struct {
|
|
ID uuid.UUID `db:"id" json:"id"`
|
|
OrderID uuid.UUID `db:"order_id" json:"order_id"`
|
|
ProductID uuid.UUID `db:"product_id" json:"product_id"`
|
|
Quantity int64 `db:"quantity" json:"quantity"`
|
|
UnitCents int64 `db:"unit_cents" json:"unit_cents"`
|
|
Batch string `db:"batch" json:"batch"`
|
|
ExpiresAt time.Time `db:"expires_at" json:"expires_at"`
|
|
}
|
|
|
|
// PaymentPreference wraps the data needed for Mercado Pago split payments.
|
|
type PaymentPreference struct {
|
|
OrderID uuid.UUID `json:"order_id"`
|
|
Gateway string `json:"gateway"`
|
|
CommissionPct float64 `json:"commission_pct"`
|
|
MarketplaceFee int64 `json:"marketplace_fee"`
|
|
SellerReceivable int64 `json:"seller_receivable"`
|
|
PaymentURL string `json:"payment_url"`
|
|
}
|
|
|
|
// PaymentWebhookEvent represents Mercado Pago notifications with split amounts.
|
|
type PaymentWebhookEvent struct {
|
|
PaymentID string `json:"payment_id"`
|
|
OrderID uuid.UUID `json:"order_id"`
|
|
Status string `json:"status"`
|
|
MarketplaceFee int64 `json:"marketplace_fee"`
|
|
SellerAmount int64 `json:"seller_amount"`
|
|
TotalPaidAmount int64 `json:"total_paid_amount"`
|
|
}
|
|
|
|
// PaymentSplitResult echoes the amounts distributed between actors.
|
|
type PaymentSplitResult struct {
|
|
OrderID uuid.UUID `json:"order_id"`
|
|
PaymentID string `json:"payment_id"`
|
|
Status string `json:"status"`
|
|
MarketplaceFee int64 `json:"marketplace_fee"`
|
|
SellerReceivable int64 `json:"seller_receivable"`
|
|
TotalPaidAmount int64 `json:"total_paid_amount"`
|
|
}
|
|
|
|
// PaymentResult represents the result of a payment confirmation.
|
|
type PaymentResult struct {
|
|
PaymentID string `json:"payment_id"`
|
|
Status string `json:"status"`
|
|
Gateway string `json:"gateway"`
|
|
Message string `json:"message,omitempty"`
|
|
ConfirmedAt time.Time `json:"confirmed_at"`
|
|
}
|
|
|
|
// RefundResult represents the result of a refund operation.
|
|
type RefundResult struct {
|
|
RefundID string `json:"refund_id"`
|
|
PaymentID string `json:"payment_id"`
|
|
AmountCents int64 `json:"amount_cents"`
|
|
Status string `json:"status"`
|
|
RefundedAt time.Time `json:"refunded_at"`
|
|
}
|
|
|
|
// PixPaymentResult represents a Pix payment with QR code.
|
|
type PixPaymentResult struct {
|
|
PaymentID string `json:"payment_id"`
|
|
OrderID uuid.UUID `json:"order_id"`
|
|
Gateway string `json:"gateway"`
|
|
PixKey string `json:"pix_key"`
|
|
QRCode string `json:"qr_code"`
|
|
QRCodeBase64 string `json:"qr_code_base64"`
|
|
CopyPasta string `json:"copy_pasta"`
|
|
AmountCents int64 `json:"amount_cents"`
|
|
MarketplaceFee int64 `json:"marketplace_fee"`
|
|
SellerReceivable int64 `json:"seller_receivable"`
|
|
ExpiresAt time.Time `json:"expires_at"`
|
|
Status string `json:"status"`
|
|
}
|
|
|
|
// BoletoPaymentResult represents a Boleto payment.
|
|
type BoletoPaymentResult struct {
|
|
PaymentID string `json:"payment_id"`
|
|
OrderID uuid.UUID `json:"order_id"`
|
|
Gateway string `json:"gateway"`
|
|
BoletoURL string `json:"boleto_url"`
|
|
BarCode string `json:"bar_code"`
|
|
DigitableLine string `json:"digitable_line"`
|
|
AmountCents int64 `json:"amount_cents"`
|
|
MarketplaceFee int64 `json:"marketplace_fee"`
|
|
SellerReceivable int64 `json:"seller_receivable"`
|
|
DueDate time.Time `json:"due_date"`
|
|
Status string `json:"status"`
|
|
}
|
|
|
|
// SellerPaymentAccount represents a seller's payment gateway account.
|
|
type SellerPaymentAccount struct {
|
|
SellerID uuid.UUID `json:"seller_id" db:"seller_id"`
|
|
Gateway string `json:"gateway" db:"gateway"`
|
|
AccountID string `json:"account_id" db:"account_id"`
|
|
AccountType string `json:"account_type" db:"account_type"` // "connect", "subaccount"
|
|
Status string `json:"status" db:"status"` // "pending", "active", "suspended"
|
|
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
|
}
|
|
|
|
// Customer represents a buyer for payment gateway purposes.
|
|
type Customer struct {
|
|
ID uuid.UUID `json:"id" db:"id"`
|
|
Name string `json:"name" db:"name"`
|
|
Email string `json:"email" db:"email"`
|
|
CPF string `json:"cpf,omitempty" db:"cpf"`
|
|
Phone string `json:"phone,omitempty" db:"phone"`
|
|
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
|
}
|
|
|
|
// PaymentGatewayConfig stores encrypted gateway credentials.
|
|
type PaymentGatewayConfig struct {
|
|
Provider string `json:"provider" db:"provider"` // mercadopago, stripe, asaas
|
|
Active bool `json:"active" db:"active"`
|
|
Credentials string `json:"-" db:"credentials"` // Encrypted JSON
|
|
Environment string `json:"environment" db:"environment"` // sandbox, production
|
|
Commission float64 `json:"commission" db:"commission"`
|
|
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
|
}
|
|
|
|
// Address represents a physical location for users or companies.
|
|
type Address struct {
|
|
ID uuid.UUID `db:"id" json:"id"`
|
|
EntityID uuid.UUID `db:"entity_id" json:"entity_id"`
|
|
Title string `db:"title" json:"titulo"`
|
|
ZipCode string `db:"zip_code" json:"cep"`
|
|
Street string `db:"street" json:"logradouro"`
|
|
Number string `db:"number" json:"numero"`
|
|
Complement string `db:"complement" json:"complemento"`
|
|
District string `db:"district" json:"bairro"`
|
|
City string `db:"city" json:"cidade"`
|
|
State string `db:"state" json:"uf"`
|
|
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
|
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
|
}
|
|
|
|
// ShippingAddress captures delivery details at order time.
|
|
type ShippingAddress struct {
|
|
RecipientName string `json:"recipient_name" db:"shipping_recipient_name"`
|
|
Street string `json:"street" db:"shipping_street"`
|
|
Number string `json:"number" db:"shipping_number"`
|
|
Complement string `json:"complement,omitempty" db:"shipping_complement"`
|
|
District string `json:"district" db:"shipping_district"`
|
|
City string `json:"city" db:"shipping_city"`
|
|
State string `json:"state" db:"shipping_state"`
|
|
ZipCode string `json:"zip_code" db:"shipping_zip_code"`
|
|
Country string `json:"country" db:"shipping_country"`
|
|
}
|
|
|
|
// ShippingSettings stores configuration for calculating delivery fees.
|
|
type ShippingSettings struct {
|
|
VendorID uuid.UUID `db:"vendor_id" json:"vendor_id"`
|
|
Active bool `db:"active" json:"active"`
|
|
MaxRadiusKm float64 `db:"max_radius_km" json:"max_radius_km"`
|
|
PricePerKmCents int64 `db:"price_per_km_cents" json:"price_per_km_cents"`
|
|
MinFeeCents int64 `db:"min_fee_cents" json:"min_fee_cents"`
|
|
FreeShippingThresholdCents *int64 `db:"free_shipping_threshold_cents" json:"free_shipping_threshold_cents"`
|
|
PickupActive bool `db:"pickup_active" json:"pickup_active"`
|
|
PickupAddress string `db:"pickup_address" json:"pickup_address"`
|
|
PickupHours string `db:"pickup_hours" json:"pickup_hours"`
|
|
Latitude float64 `db:"latitude" json:"latitude"`
|
|
Longitude float64 `db:"longitude" json:"longitude"`
|
|
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
|
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
|
}
|
|
|
|
// Shipment stores freight label data and tracking linkage.
|
|
type Shipment struct {
|
|
ID uuid.UUID `db:"id" json:"id"`
|
|
OrderID uuid.UUID `db:"order_id" json:"order_id"`
|
|
Carrier string `db:"carrier" json:"carrier"`
|
|
TrackingCode string `db:"tracking_code" json:"tracking_code"`
|
|
ExternalTracking string `db:"external_tracking" json:"external_tracking"`
|
|
Status string `db:"status" json:"status"`
|
|
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
|
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
|
}
|
|
|
|
// ReviewFilter captures review listing constraints.
|
|
type ReviewFilter struct {
|
|
SellerID *uuid.UUID
|
|
Limit int
|
|
Offset int
|
|
}
|
|
|
|
// ReviewPage wraps paginated review results.
|
|
type ReviewPage struct {
|
|
Reviews []Review `json:"reviews"`
|
|
Total int64 `json:"total"`
|
|
Page int `json:"page"`
|
|
PageSize int `json:"page_size"`
|
|
}
|
|
|
|
// ShipmentFilter captures shipment listing constraints.
|
|
type ShipmentFilter struct {
|
|
SellerID *uuid.UUID
|
|
Limit int
|
|
Offset int
|
|
}
|
|
|
|
// ShipmentPage wraps paginated shipment results.
|
|
type ShipmentPage struct {
|
|
Shipments []Shipment `json:"shipments"`
|
|
Total int64 `json:"total"`
|
|
Page int `json:"page"`
|
|
PageSize int `json:"page_size"`
|
|
}
|
|
|
|
// OrderStatus enumerates supported transitions.
|
|
type OrderStatus string
|
|
|
|
const (
|
|
OrderStatusPending OrderStatus = "Pendente"
|
|
OrderStatusPaid OrderStatus = "Pago"
|
|
OrderStatusInvoiced OrderStatus = "Faturado"
|
|
OrderStatusShipped OrderStatus = "Enviado"
|
|
OrderStatusDelivered OrderStatus = "Entregue"
|
|
OrderStatusCompleted OrderStatus = "Concluído"
|
|
OrderStatusCancelled OrderStatus = "Cancelado"
|
|
)
|
|
|
|
// PaymentMethod enumerates supported payment types.
|
|
type PaymentMethod string
|
|
|
|
const (
|
|
PaymentMethodPix PaymentMethod = "pix"
|
|
PaymentMethodCredit PaymentMethod = "credit_card"
|
|
PaymentMethodDebit PaymentMethod = "debit_card"
|
|
)
|
|
|
|
// CartItem stores buyer selections with unit pricing.
|
|
type CartItem struct {
|
|
ID uuid.UUID `db:"id" json:"id"`
|
|
BuyerID uuid.UUID `db:"buyer_id" json:"buyer_id"`
|
|
ProductID uuid.UUID `db:"product_id" json:"product_id"`
|
|
Quantity int64 `db:"quantity" json:"quantity"`
|
|
UnitCents int64 `db:"unit_cents" json:"unit_cents"`
|
|
ProductName string `db:"product_name" json:"product_name"`
|
|
Batch string `db:"batch" json:"batch"`
|
|
ExpiresAt time.Time `db:"expires_at" json:"expires_at"`
|
|
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
|
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
|
}
|
|
|
|
// CartSummary aggregates cart totals and discounts.
|
|
type CartSummary struct {
|
|
Items []CartItem `json:"items"`
|
|
SubtotalCents int64 `json:"subtotal_cents"`
|
|
DiscountCents int64 `json:"discount_cents"`
|
|
TotalCents int64 `json:"total_cents"`
|
|
DiscountReason string `json:"discount_reason,omitempty"`
|
|
}
|
|
|
|
// Review captures the buyer feedback for a completed order.
|
|
type Review struct {
|
|
ID uuid.UUID `db:"id" json:"id"`
|
|
OrderID uuid.UUID `db:"order_id" json:"order_id"`
|
|
BuyerID uuid.UUID `db:"buyer_id" json:"buyer_id"`
|
|
SellerID uuid.UUID `db:"seller_id" json:"seller_id"`
|
|
Rating int `db:"rating" json:"rating"`
|
|
Comment string `db:"comment" json:"comment"`
|
|
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
|
}
|
|
|
|
// CompanyRating exposes the aggregate score for a seller or pharmacy.
|
|
type CompanyRating struct {
|
|
CompanyID uuid.UUID `json:"company_id"`
|
|
AverageScore float64 `json:"average_score"`
|
|
TotalReviews int64 `json:"total_reviews"`
|
|
}
|
|
|
|
// TopProduct aggregates seller performance per SKU.
|
|
type TopProduct struct {
|
|
ProductID uuid.UUID `db:"product_id" json:"product_id"`
|
|
Name string `db:"name" json:"name"`
|
|
TotalQuantity int64 `db:"total_quantity" json:"total_quantity"`
|
|
RevenueCents int64 `db:"revenue_cents" json:"revenue_cents"`
|
|
}
|
|
|
|
// SellerDashboard summarizes commercial metrics for sellers.
|
|
type SellerDashboard struct {
|
|
SellerID uuid.UUID `json:"seller_id"`
|
|
TotalSalesCents int64 `json:"total_sales_cents"`
|
|
OrdersCount int64 `json:"orders_count"`
|
|
TopProducts []TopProduct `json:"top_products"`
|
|
LowStockAlerts []Product `json:"low_stock_alerts"`
|
|
}
|
|
|
|
// AdminDashboard surfaces platform-wide KPIs.
|
|
type AdminDashboard struct {
|
|
GMVCents int64 `json:"gmv_cents"`
|
|
NewCompanies int64 `json:"new_companies"`
|
|
WindowStartAt time.Time `json:"window_start_at"`
|
|
}
|
|
|
|
// CompanyDocument represents a KYC/KYB document (CNPJ card, Permit).
|
|
type CompanyDocument struct {
|
|
ID uuid.UUID `db:"id" json:"id"`
|
|
CompanyID uuid.UUID `db:"company_id" json:"company_id"`
|
|
Type string `db:"type" json:"type"` // CNPJ, PERMIT, IDENTITY
|
|
URL string `db:"url" json:"url"`
|
|
Status string `db:"status" json:"status"` // PENDING, APPROVED, REJECTED
|
|
RejectionReason string `db:"rejection_reason" json:"rejection_reason,omitempty"`
|
|
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
|
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
|
}
|
|
|
|
// LedgerEntry represents an immutable financial record.
|
|
type LedgerEntry struct {
|
|
ID uuid.UUID `db:"id" json:"id"`
|
|
CompanyID uuid.UUID `db:"company_id" json:"company_id"`
|
|
AmountCents int64 `db:"amount_cents" json:"amount_cents"`
|
|
Type string `db:"type" json:"type"` // SALE, FEE, WITHDRAWAL, REFUND
|
|
Description string `db:"description" json:"description"`
|
|
ReferenceID *uuid.UUID `db:"reference_id" json:"reference_id,omitempty"`
|
|
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
|
}
|
|
|
|
// Withdrawal represents a payout request.
|
|
type Withdrawal struct {
|
|
ID uuid.UUID `db:"id" json:"id"`
|
|
CompanyID uuid.UUID `db:"company_id" json:"company_id"`
|
|
AmountCents int64 `db:"amount_cents" json:"amount_cents"`
|
|
Status string `db:"status" json:"status"` // PENDING, APPROVED, PAID, REJECTED
|
|
BankAccountInfo string `db:"bank_account_info" json:"bank_account_info"`
|
|
TransactionID string `db:"transaction_id" json:"transaction_id,omitempty"`
|
|
RejectionReason string `db:"rejection_reason" json:"rejection_reason,omitempty"`
|
|
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
|
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
|
}
|