fix: restore missing interface methods and cleanup syntax in usecase.go and postgres.go

This commit is contained in:
Tiago Ribeiro 2026-03-09 09:23:32 -03:00
parent 5464678ae5
commit fa9ddbdeef
2 changed files with 133 additions and 126 deletions

View file

@ -1607,6 +1607,8 @@ func (r *Repository) CreateAddress(ctx context.Context, address *domain.Address)
_, err := r.db.NamedExecContext(ctx, query, address) _, err := r.db.NamedExecContext(ctx, query, address)
return err return err
}
func (r *Repository) ListAddresses(ctx context.Context, entityID uuid.UUID) ([]domain.Address, error) { func (r *Repository) ListAddresses(ctx context.Context, entityID uuid.UUID) ([]domain.Address, error) {
var addresses []domain.Address var addresses []domain.Address
query := `SELECT id, entity_id, title, zip_code, street, number, complement, district, city, state, latitude, longitude, created_at, updated_at FROM addresses WHERE entity_id = $1 ORDER BY created_at DESC` query := `SELECT id, entity_id, title, zip_code, street, number, complement, district, city, state, latitude, longitude, created_at, updated_at FROM addresses WHERE entity_id = $1 ORDER BY created_at DESC`
@ -1620,10 +1622,6 @@ func (r *Repository) ListAllAddresses(ctx context.Context) ([]domain.Address, er
err := r.db.SelectContext(ctx, &addresses, query) err := r.db.SelectContext(ctx, &addresses, query)
return addresses, err return addresses, err
} }
// If no rows, SelectContext returns nil error but empty slice if initialized, or maybe error?
// sqlx returns error if slice is empty? No, SelectContext handles empty result by returning empty slice usually.
return addresses, err
}
func (r *Repository) GetAddress(ctx context.Context, id uuid.UUID) (*domain.Address, error) { func (r *Repository) GetAddress(ctx context.Context, id uuid.UUID) (*domain.Address, error) {
var addr domain.Address var addr domain.Address

View file

@ -1,107 +1,107 @@
package usecase package usecase
import ( import (
"context" "context"
"time" "time"
"github.com/gofrs/uuid/v5" "github.com/gofrs/uuid/v5"
"github.com/saveinmed/backend-go/internal/domain" "github.com/saveinmed/backend-go/internal/domain"
"github.com/saveinmed/backend-go/internal/infrastructure/mapbox" "github.com/saveinmed/backend-go/internal/infrastructure/mapbox"
"github.com/saveinmed/backend-go/internal/infrastructure/notifications" "github.com/saveinmed/backend-go/internal/infrastructure/notifications"
) )
// Repository defines the persistence contract for all core entities. // Repository defines the persistence contract for all core entities.
// Implementations live in internal/repository/postgres/.
type Repository interface { type Repository interface {
CreateCompany(ctx context.Context, company *domain.Company) error CreateCompany(ctx context.Context, company *domain.Company) error
ListCompanies(ctx context.Context, filter domain.CompanyFilter) ([]domain.Company, int64, error) ListCompanies(ctx context.Context, filter domain.CompanyFilter) ([]domain.Company, int64, 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 DeleteCompany(ctx context.Context, id uuid.UUID) error
CreateProduct(ctx context.Context, product *domain.Product) error CreateProduct(ctx context.Context, product *domain.Product) error
BatchCreateProducts(ctx context.Context, products []domain.Product) error BatchCreateProducts(ctx context.Context, products []domain.Product) error
ListProducts(ctx context.Context, filter domain.ProductFilter) ([]domain.Product, int64, error) ListProducts(ctx context.Context, filter domain.ProductFilter) ([]domain.Product, int64, error)
SearchProducts(ctx context.Context, filter domain.ProductSearchFilter) ([]domain.ProductWithDistance, int64, error) SearchProducts(ctx context.Context, filter domain.ProductSearchFilter) ([]domain.ProductWithDistance, int64, error)
ListRecords(ctx context.Context, filter domain.RecordSearchFilter) ([]domain.Product, int64, error) ListRecords(ctx context.Context, filter domain.RecordSearchFilter) ([]domain.Product, int64, 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 UpdateProduct(ctx context.Context, product *domain.Product) error
DeleteProduct(ctx context.Context, id uuid.UUID) 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, int64, error) ListInventory(ctx context.Context, filter domain.InventoryFilter) ([]domain.InventoryItem, int64, error)
CreateInventoryItem(ctx context.Context, item *domain.InventoryItem) error CreateInventoryItem(ctx context.Context, item *domain.InventoryItem) error
GetInventoryItem(ctx context.Context, id uuid.UUID) (*domain.InventoryItem, error) GetInventoryItem(ctx context.Context, id uuid.UUID) (*domain.InventoryItem, error)
UpdateInventoryItem(ctx context.Context, item *domain.InventoryItem) error UpdateInventoryItem(ctx context.Context, item *domain.InventoryItem) error
CreateOrder(ctx context.Context, order *domain.Order) error CreateOrder(ctx context.Context, order *domain.Order) error
ListOrders(ctx context.Context, filter domain.OrderFilter) ([]domain.Order, int64, error) ListOrders(ctx context.Context, filter domain.OrderFilter) ([]domain.Order, int64, 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 DeleteOrder(ctx context.Context, id uuid.UUID) error
UpdateOrderItems(ctx context.Context, orderID uuid.UUID, items []domain.OrderItem, totalCents int64) error UpdateOrderItems(ctx context.Context, orderID uuid.UUID, items []domain.OrderItem, totalCents int64) 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)
CreateUser(ctx context.Context, user *domain.User) error CreateUser(ctx context.Context, user *domain.User) error
ListUsers(ctx context.Context, filter domain.UserFilter) ([]domain.User, int64, error) ListUsers(ctx context.Context, filter domain.UserFilter) ([]domain.User, int64, error)
GetUser(ctx context.Context, id uuid.UUID) (*domain.User, error) GetUser(ctx context.Context, id uuid.UUID) (*domain.User, error)
GetUserByUsername(ctx context.Context, username string) (*domain.User, error) GetUserByUsername(ctx context.Context, username string) (*domain.User, error)
GetUserByEmail(ctx context.Context, email string) (*domain.User, error) GetUserByEmail(ctx context.Context, email string) (*domain.User, error)
UpdateUser(ctx context.Context, user *domain.User) error UpdateUser(ctx context.Context, user *domain.User) error
DeleteUser(ctx context.Context, id uuid.UUID) error DeleteUser(ctx context.Context, id uuid.UUID) error
AddCartItem(ctx context.Context, item *domain.CartItem) (*domain.CartItem, error) AddCartItem(ctx context.Context, item *domain.CartItem) (*domain.CartItem, error)
ListCartItems(ctx context.Context, buyerID uuid.UUID) ([]domain.CartItem, error) ListCartItems(ctx context.Context, buyerID uuid.UUID) ([]domain.CartItem, error)
DeleteCartItem(ctx context.Context, id uuid.UUID, buyerID uuid.UUID) error DeleteCartItem(ctx context.Context, id uuid.UUID, buyerID uuid.UUID) error
DeleteCartItemByProduct(ctx context.Context, buyerID, productID uuid.UUID) error DeleteCartItemByProduct(ctx context.Context, buyerID, productID uuid.UUID) error
ClearCart(ctx context.Context, buyerID uuid.UUID) error ClearCart(ctx context.Context, buyerID uuid.UUID) error
ReplaceCart(ctx context.Context, buyerID uuid.UUID, items []domain.CartItem) error ReplaceCart(ctx context.Context, buyerID uuid.UUID, items []domain.CartItem) error
CreateReview(ctx context.Context, review *domain.Review) error CreateReview(ctx context.Context, review *domain.Review) error
GetCompanyRating(ctx context.Context, companyID uuid.UUID) (*domain.CompanyRating, error) GetCompanyRating(ctx context.Context, companyID uuid.UUID) (*domain.CompanyRating, error)
ListReviews(ctx context.Context, filter domain.ReviewFilter) ([]domain.Review, int64, error) ListReviews(ctx context.Context, filter domain.ReviewFilter) ([]domain.Review, int64, error)
SellerDashboard(ctx context.Context, sellerID uuid.UUID) (*domain.SellerDashboard, error) SellerDashboard(ctx context.Context, sellerID uuid.UUID) (*domain.SellerDashboard, error)
AdminDashboard(ctx context.Context, since time.Time) (*domain.AdminDashboard, error) AdminDashboard(ctx context.Context, since time.Time) (*domain.AdminDashboard, error)
GetShippingSettings(ctx context.Context, vendorID uuid.UUID) (*domain.ShippingSettings, error) GetShippingSettings(ctx context.Context, vendorID uuid.UUID) (*domain.ShippingSettings, error)
UpsertShippingSettings(ctx context.Context, settings *domain.ShippingSettings) error UpsertShippingSettings(ctx context.Context, settings *domain.ShippingSettings) error
ListShipments(ctx context.Context, filter domain.ShipmentFilter) ([]domain.Shipment, int64, error) ListShipments(ctx context.Context, filter domain.ShipmentFilter) ([]domain.Shipment, int64, error)
CreateDocument(ctx context.Context, doc *domain.CompanyDocument) error CreateDocument(ctx context.Context, doc *domain.CompanyDocument) error
ListDocuments(ctx context.Context, companyID uuid.UUID) ([]domain.CompanyDocument, error) ListDocuments(ctx context.Context, companyID uuid.UUID) ([]domain.CompanyDocument, error)
RecordLedgerEntry(ctx context.Context, entry *domain.LedgerEntry) error RecordLedgerEntry(ctx context.Context, entry *domain.LedgerEntry) error
GetLedger(ctx context.Context, companyID uuid.UUID, limit, offset int) ([]domain.LedgerEntry, int64, error) GetLedger(ctx context.Context, companyID uuid.UUID, limit, offset int) ([]domain.LedgerEntry, int64, error)
GetBalance(ctx context.Context, companyID uuid.UUID) (int64, error) GetBalance(ctx context.Context, companyID uuid.UUID) (int64, error)
CreateWithdrawal(ctx context.Context, withdrawal *domain.Withdrawal) error CreateWithdrawal(ctx context.Context, withdrawal *domain.Withdrawal) error
ListWithdrawals(ctx context.Context, companyID uuid.UUID) ([]domain.Withdrawal, error) ListWithdrawals(ctx context.Context, companyID uuid.UUID) ([]domain.Withdrawal, error)
// Stock Reservations // Stock Reservations
ReserveStock(ctx context.Context, res *domain.StockReservation) error ReserveStock(ctx context.Context, res *domain.StockReservation) error
CompleteReservation(ctx context.Context, reservationID uuid.UUID) error CompleteReservation(ctx context.Context, reservationID uuid.UUID) error
ExpireReservations(ctx context.Context) error ExpireReservations(ctx context.Context) error
GetActiveReservations(ctx context.Context, inventoryItemID uuid.UUID) (int64, error) GetActiveReservations(ctx context.Context, inventoryItemID uuid.UUID) (int64, error)
GetPaymentGatewayConfig(ctx context.Context, provider string) (*domain.PaymentGatewayConfig, error)UpsertPaymentGatewayConfig(ctx context.Context, config *domain.PaymentGatewayConfig) error GetPaymentGatewayConfig(ctx context.Context, provider string) (*domain.PaymentGatewayConfig, error)
GetSellerPaymentAccount(ctx context.Context, sellerID uuid.UUID) (*domain.SellerPaymentAccount, error) UpsertPaymentGatewayConfig(ctx context.Context, config *domain.PaymentGatewayConfig) error
UpsertSellerPaymentAccount(ctx context.Context, account *domain.SellerPaymentAccount) error GetSellerPaymentAccount(ctx context.Context, sellerID uuid.UUID) (*domain.SellerPaymentAccount, error)
UpsertSellerPaymentAccount(ctx context.Context, account *domain.SellerPaymentAccount) error
CreateAddress(ctx context.Context, address *domain.Address) error CreateAddress(ctx context.Context, address *domain.Address) error
ListAddresses(ctx context.Context, entityID uuid.UUID) ([]domain.Address, error) ListAddresses(ctx context.Context, entityID uuid.UUID) ([]domain.Address, error)
GetAddress(ctx context.Context, id uuid.UUID) (*domain.Address, error) ListAllAddresses(ctx context.Context) ([]domain.Address, error)
UpdateAddress(ctx context.Context, address *domain.Address) error GetAddress(ctx context.Context, id uuid.UUID) (*domain.Address, error)
DeleteAddress(ctx context.Context, id uuid.UUID) error UpdateAddress(ctx context.Context, address *domain.Address) error
ListAllAddresses(ctx context.Context) ([]domain.Address, error) DeleteAddress(ctx context.Context, id uuid.UUID) error
GeocodeAllAddresses(ctx context.Context) (int, error) GeocodeAllAddresses(ctx context.Context) (int, error)
StartStockCleanupWorker(ctx context.Context)
ListManufacturers(ctx context.Context) ([]string, error) ListManufacturers(ctx context.Context) ([]string, error)
ListCategories(ctx context.Context) ([]string, error) ListCategories(ctx context.Context) ([]string, error)
GetProductByEAN(ctx context.Context, ean string) (*domain.Product, error) GetProductByEAN(ctx context.Context, ean string) (*domain.Product, error)
} }
// PaymentGateway abstracts the payment provider (Mercado Pago, Asaas, etc.). // PaymentGateway abstracts the payment provider (Mercado Pago, Asaas, etc.).
// Implementations live in internal/infrastructure/payments/.
type PaymentGateway interface { type PaymentGateway interface {
CreatePreference(ctx context.Context, order *domain.Order, payer *domain.User, sellerAcc *domain.SellerPaymentAccount) (*domain.PaymentPreference, error) CreatePreference(ctx context.Context, order *domain.Order, payer *domain.User, sellerAcc *domain.SellerPaymentAccount) (*domain.PaymentPreference, error)
CreatePayment(ctx context.Context, order *domain.Order, token, issuerID, paymentMethodID string, installments int, payer *domain.User, sellerAcc *domain.SellerPaymentAccount) (*domain.PaymentResult, error) CreatePayment(ctx context.Context, order *domain.Order, token, issuerID, paymentMethodID string, installments int, payer *domain.User, sellerAcc *domain.SellerPaymentAccount) (*domain.PaymentResult, error)
@ -109,61 +109,70 @@ type PaymentGateway interface {
CreateBoletoPayment(ctx context.Context, order *domain.Order, payer *domain.User) (*domain.BoletoPaymentResult, error) CreateBoletoPayment(ctx context.Context, order *domain.Order, payer *domain.User) (*domain.BoletoPaymentResult, error)
GetPaymentStatus(ctx context.Context, paymentID string) (*domain.PaymentWebhookEvent, error) GetPaymentStatus(ctx context.Context, paymentID string) (*domain.PaymentWebhookEvent, error)
} }
// Service orchestrates all business use cases. // Service orchestrates all business use cases.
// Methods are split across domain-specific files in this package:
// - auth_usecase.go authentication, JWT, password reset
// - company_usecase.go company registration, KYC, shipping options
// - product_usecase.go catalogue, inventory management
// - order_usecase.go order lifecycle and state machine
// - shipping_usecase.go shipping calculation and configuration
// - cart_usecase.go cart operations and B2B discounts
// - payment_usecase.go payment preferences and webhook handling
// - review_usecase.go buyer reviews and ratings
// - user_usecase.go user CRUD
// - address_usecase.go address management
// - dashboard_usecase.go seller and admin KPI dashboards
type Service struct { type Service struct {
repo Repository repo Repository
pay PaymentGateway pay PaymentGateway
mapbox *mapbox.Client mapbox *mapbox.Client
notify notifications.NotificationService notify notifications.NotificationService
marketplaceCommission float64 marketplaceCommission float64
buyerFeeRate float64 buyerFeeRate float64
jwtSecret []byte jwtSecret []byte
tokenTTL time.Duration tokenTTL time.Duration
passwordPepper string passwordPepper string
} }
const ( const (
// passwordResetTTL is the validity window for password-reset JWTs. // passwordResetTTL is the validity window for password-reset JWTs.
passwordResetTTL = 30 * time.Minute passwordResetTTL = 30 * time.Minute
) )
// NewService wires all dependencies and returns a ready-to-use Service. // NewService wires all dependencies and returns a ready-to-use Service.
func NewService( func NewService(
repo Repository, repo Repository,
pg PaymentGateway, pg PaymentGateway,
mb *mapbox.Client, mb *mapbox.Client,
notify notifications.NotificationService, notify notifications.NotificationService,
commission, buyerFeeRate float64, commission, buyerFeeRate float64,
jwtSecret string, jwtSecret string,
tokenTTL time.Duration, tokenTTL time.Duration,
pepper string, pepper string,
) *Service { ) *Service {
return &Service{ return &Service{
repo: repo, repo: repo,
pay: pg, pay: pg,
mapbox: mb, mapbox: mb,
notify: notify, notify: notify,
marketplaceCommission: commission, marketplaceCommission: commission,
buyerFeeRate: buyerFeeRate, buyerFeeRate: buyerFeeRate,
jwtSecret: []byte(jwtSecret), jwtSecret: []byte(jwtSecret),
tokenTTL: tokenTTL, tokenTTL: tokenTTL,
passwordPepper: pepper, passwordPepper: pepper,
} }
} }
// GetNotificationService exposes the notification service for push handlers. // GetNotificationService exposes the notification service for push handlers.
func (s *Service) GetNotificationService() notifications.NotificationService { func (s *Service) GetNotificationService() notifications.NotificationService {
return s.notify return s.notify
}
// DeleteAddress handles address removal logic.
func (s *Service) DeleteAddress(ctx context.Context, id uuid.UUID) error {
return s.repo.DeleteAddress(ctx, id)
}
// ListManufacturers returns manufacturers from the repo.
func (s *Service) ListManufacturers(ctx context.Context) ([]string, error) {
return s.repo.ListManufacturers(ctx)
}
// ListCategories returns categories from the repo.
func (s *Service) ListCategories(ctx context.Context) ([]string, error) {
return s.repo.ListCategories(ctx)
}
// GetProductByEAN finds a product by its EAN code.
func (s *Service) GetProductByEAN(ctx context.Context, ean string) (*domain.Product, error) {
return s.repo.GetProductByEAN(ctx, ean)
} }