135 lines
4.1 KiB
Go
135 lines
4.1 KiB
Go
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) {
|
||
// 找不到錢包存不存在
|
||
wStatus, err := w.HasAvailableBalance(ctx)
|
||
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)
|
||
//}
|
||
|
||
if _, err := w.InitializeWallets(ctx, tx.Brand); err != nil {
|
||
return err
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
use.markWalletAsExisting(uidAsset)
|
||
}
|
||
|
||
_, err := w.GetBalancesForUpdate(ctx, []wallet.Types{wallet.TypeAvailable})
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
return nil
|
||
}
|
||
}
|
||
|
||
// withSubAvailable 減少用戶可用餘額
|
||
func (use *WalletUseCase) withSubAvailable() walletActionOption {
|
||
return func(_ context.Context, tx *usecase.WalletTransferRequest, w repository.UserWalletService) error {
|
||
if err := w.DecreaseBalance(wallet.TypeAvailable, tx.ReferenceOrderID, tx.Amount); err != nil {
|
||
if errors.Is(err, repository.ErrBalanceInsufficient) {
|
||
// todo 錯誤要看怎麼給(餘額不足)
|
||
return fmt.Errorf("balance insufficient")
|
||
}
|
||
|
||
return err
|
||
}
|
||
|
||
return nil
|
||
}
|
||
}
|
||
|
||
// 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
|
||
// }
|
||
//}
|