110 lines
4.0 KiB
Go
110 lines
4.0 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/google/uuid"
|
|
"gorm.io/gorm"
|
|
|
|
"apskel-pos-be/internal/entities"
|
|
)
|
|
|
|
// ErrWalletTransactionNotFound means the ledger row does not exist or belongs to
|
|
// another organization.
|
|
var ErrWalletTransactionNotFound = errors.New("wallet: transaction not found")
|
|
|
|
// WalletTraceRepository reads what tracing a ledger row lot by lot needs
|
|
// (docs/prd-point-coin.md F7, ยง8.1). Nothing here changes a balance.
|
|
type WalletTraceRepository interface {
|
|
// GetTransaction returns ErrWalletTransactionNotFound unless the row belongs to
|
|
// the organization.
|
|
GetTransaction(ctx context.Context, organizationID, id uuid.UUID) (*entities.WalletTransaction, error)
|
|
GetTransactions(ctx context.Context, ids []uuid.UUID) ([]entities.WalletTransaction, error)
|
|
// ListAllocations returns what a debit took from each lot, in the order it took.
|
|
ListAllocations(ctx context.Context, transactionID uuid.UUID) ([]entities.WalletLotAllocation, error)
|
|
// ListLotsBySource returns the lots a credit created, oldest first.
|
|
ListLotsBySource(ctx context.Context, transactionID uuid.UUID) ([]entities.WalletLot, error)
|
|
GetLots(ctx context.Context, ids []uuid.UUID) ([]entities.WalletLot, error)
|
|
CustomerNames(ctx context.Context, ids []uuid.UUID) (map[uuid.UUID]string, error)
|
|
}
|
|
|
|
type walletTraceRepository struct {
|
|
db *gorm.DB
|
|
names *walletAdminRepository
|
|
}
|
|
|
|
func NewWalletTraceRepository(db *gorm.DB) WalletTraceRepository {
|
|
return &walletTraceRepository{db: db, names: &walletAdminRepository{db: db}}
|
|
}
|
|
|
|
func (r *walletTraceRepository) GetTransaction(ctx context.Context, organizationID, id uuid.UUID) (*entities.WalletTransaction, error) {
|
|
var rows []entities.WalletTransaction
|
|
err := DBFromContext(ctx, r.db).WithContext(ctx).
|
|
Where("id = ? AND organization_id = ?", id, organizationID).
|
|
Limit(1).
|
|
Find(&rows).Error
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get wallet transaction: %w", err)
|
|
}
|
|
if len(rows) == 0 {
|
|
return nil, ErrWalletTransactionNotFound
|
|
}
|
|
return &rows[0], nil
|
|
}
|
|
|
|
func (r *walletTraceRepository) GetTransactions(ctx context.Context, ids []uuid.UUID) ([]entities.WalletTransaction, error) {
|
|
var rows []entities.WalletTransaction
|
|
if len(ids) == 0 {
|
|
return rows, nil
|
|
}
|
|
if err := DBFromContext(ctx, r.db).WithContext(ctx).Where("id IN ?", ids).Find(&rows).Error; err != nil {
|
|
return nil, fmt.Errorf("failed to get wallet transactions: %w", err)
|
|
}
|
|
return rows, nil
|
|
}
|
|
|
|
func (r *walletTraceRepository) ListAllocations(ctx context.Context, transactionID uuid.UUID) ([]entities.WalletLotAllocation, error) {
|
|
var rows []entities.WalletLotAllocation
|
|
// A debit draws in K9 order, so the lots' order is the order it took from them.
|
|
err := DBFromContext(ctx, r.db).WithContext(ctx).
|
|
Table("wallet_lot_allocations a").
|
|
Select("a.*").
|
|
Joins("JOIN wallet_lots l ON l.id = a.lot_id").
|
|
Where("a.transaction_id = ?", transactionID).
|
|
Order("l.expires_at NULLS LAST, l.created_at, l.id").
|
|
Scan(&rows).Error
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to list wallet lot allocations: %w", err)
|
|
}
|
|
return rows, nil
|
|
}
|
|
|
|
func (r *walletTraceRepository) ListLotsBySource(ctx context.Context, transactionID uuid.UUID) ([]entities.WalletLot, error) {
|
|
var lots []entities.WalletLot
|
|
err := DBFromContext(ctx, r.db).WithContext(ctx).
|
|
Where("source_transaction_id = ?", transactionID).
|
|
Order("created_at, id").
|
|
Find(&lots).Error
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to list wallet lots: %w", err)
|
|
}
|
|
return lots, nil
|
|
}
|
|
|
|
func (r *walletTraceRepository) GetLots(ctx context.Context, ids []uuid.UUID) ([]entities.WalletLot, error) {
|
|
var lots []entities.WalletLot
|
|
if len(ids) == 0 {
|
|
return lots, nil
|
|
}
|
|
if err := DBFromContext(ctx, r.db).WithContext(ctx).Where("id IN ?", ids).Find(&lots).Error; err != nil {
|
|
return nil, fmt.Errorf("failed to get wallet lots: %w", err)
|
|
}
|
|
return lots, nil
|
|
}
|
|
|
|
func (r *walletTraceRepository) CustomerNames(ctx context.Context, ids []uuid.UUID) (map[uuid.UUID]string, error) {
|
|
return r.names.CustomerNames(ctx, ids)
|
|
}
|