app-cloudep-wallet-service/pkg/usecase/wallet_tx_option.go

135 lines
4.1 KiB
Go
Raw Normal View History

2025-04-17 09:00:42 +00:00
package usecase
import (
"code.30cm.net/digimon/app-cloudep-wallet-service/pkg/domain/repository"
"code.30cm.net/digimon/app-cloudep-wallet-service/pkg/domain/usecase"
"code.30cm.net/digimon/app-cloudep-wallet-service/pkg/domain/wallet"
"context"
"errors"
"fmt"
)
type uidAssetKey struct {
uid string
asset string
}
// walletActionOption 表示一個「錢包操作函式」,可在錢包流程中插入自定義動作(例如:扣款、加值、凍結)
type walletActionOption func(
ctx context.Context,
tx *usecase.WalletTransferRequest,
wallet repository.UserWalletService,
) error
// withLockAvailable 鎖定用戶可用餘額
func (use *WalletUseCase) withLockAvailable() walletActionOption {
return func(ctx context.Context, tx *usecase.WalletTransferRequest, w repository.UserWalletService) error {
uidAsset := uidAssetKey{
uid: tx.FromUID,
asset: tx.Asset,
}
if !use.checkWalletExistence(uidAsset) {
// 找不到錢包存不存在
2025-04-18 09:10:40 +00:00
wStatus, err := w.HasAvailableBalance(ctx)
2025-04-17 09:00:42 +00:00
if err != nil {
return fmt.Errorf("failed to check wallet: %w", err)
}
// 錢包不存在要做新增
if !wStatus {
//// 是合約模擬交易或帳變且錢包不存在才建立錢包
//if !(tx.Business == wa.ContractSimulationBusinessTypeBusinessName || tx.BusinessType == domain.DistributionBusinessTypeBusinessName) {
// // 新增錢包有命中 UK 不需要額外上鎖
// return use.translateError(err)
//}
2025-04-18 09:10:40 +00:00
if _, err := w.InitializeWallets(ctx, tx.Brand); err != nil {
2025-04-17 09:00:42 +00:00
return err
}
return nil
}
use.markWalletAsExisting(uidAsset)
}
2025-04-18 09:10:40 +00:00
_, err := w.GetBalancesForUpdate(ctx, []wallet.Types{wallet.TypeAvailable})
2025-04-17 09:00:42 +00:00
if err != nil {
return err
}
return nil
}
}
2025-04-21 07:46:43 +00:00
// withSubAvailable 減少用戶可用餘額
2025-04-17 09:00:42 +00:00
func (use *WalletUseCase) withSubAvailable() walletActionOption {
return func(_ context.Context, tx *usecase.WalletTransferRequest, w repository.UserWalletService) error {
2025-04-18 09:10:40 +00:00
if err := w.DecreaseBalance(wallet.TypeAvailable, tx.ReferenceOrderID, tx.Amount); err != nil {
2025-04-17 09:00:42 +00:00
if errors.Is(err, repository.ErrBalanceInsufficient) {
// todo 錯誤要看怎麼給(餘額不足)
return fmt.Errorf("balance insufficient")
}
return err
}
return nil
}
}
2025-04-21 07:46:43 +00:00
// withAddAvailable 增加用戶可用餘額
func (use *WalletUseCase) withAddAvailable() walletActionOption {
return func(_ context.Context, tx *usecase.WalletTransferRequest, w repository.UserWalletService) error {
if err := w.IncreaseBalance(wallet.TypeAvailable, tx.ReferenceOrderID, tx.Amount); err != nil {
return err
}
return nil
}
}
// withAddFreeze 增加用戶凍結餘額
func (use *WalletUseCase) withAddFreeze() walletActionOption {
return func(_ context.Context, tx *usecase.WalletTransferRequest, w repository.UserWalletService) error {
if err := w.IncreaseBalance(wallet.TypeFreeze, tx.ReferenceOrderID, tx.Amount); err != nil {
return err
}
// 訂單可以做解凍解凍最大上限金額來自當初凍結金額所以在每一筆tx可以設定Balance
// 後續tx需要依據其他tx做交易時能有所依據
tx.PostTransferBalance = tx.Amount
return nil
}
}
//// WithAppendFreeze 追加用戶原凍結餘額
//func (use *WalletUseCase) withAppendFreeze() walletActionOption {
// return func(ctx context.Context, tx *usecase.WalletTransferRequest, w repository.UserWalletService) error {
// order, err := wallet.GetOrderBalance(ctx, tx.ReferenceOrderIDs)
// if err != nil {
// return use.translateError(err)
// }
//
// // 以id來做lock更可以確保只lock到該筆而不會因為index關係lock到多筆導致死鎖
// // 而且先不lock把資料先拉出來判斷餘額是否足夠在不足夠時可以直接return而不用lock減少開銷
// order, err = wallet.GetOrderBalanceXLock(ctx, order.ID)
// if err != nil {
// return use.translateError(err)
// }
//
// tx.Crypto = order.Crypto
// tx.UID = order.UID
//
// if err := wallet.AddOrder(order.ID, tx.Amount); err != nil {
// return use.translateError(err)
// }
//
// if err := wallet.AddFreeze(tx.BusinessType, tx.Amount); err != nil {
// return use.translateError(err)
// }
//
// return nil
// }
//}