diff --git a/pkg/domain/repository/wallet.go b/pkg/domain/repository/wallet.go index 0517051..068e93d 100644 --- a/pkg/domain/repository/wallet.go +++ b/pkg/domain/repository/wallet.go @@ -90,6 +90,8 @@ type UserWalletService interface { GetOrderBalance(ctx context.Context, orderID string) (entity.Transaction, error) // GetOrderBalanceForUpdate 查詢某筆交易(訂單),詳情寫入本地暫存 (FOR UPDATE) GetOrderBalanceForUpdate(ctx context.Context, orderID string) (entity.Transaction, error) + // AddOrderBalance order 加入本地塊曲中 + AddOrderBalance(ctx context.Context, orderID string, amount decimal.Decimal) error // ClearCache 清空本地所有暫存 ClearCache() } diff --git a/pkg/usecase/wallet.go b/pkg/usecase/wallet.go index d84ef93..578528f 100644 --- a/pkg/usecase/wallet.go +++ b/pkg/usecase/wallet.go @@ -232,9 +232,24 @@ func (use *WalletUseCase) AppendFreeze(ctx context.Context, tx usecase.WalletTra }) } +// UnFreeze 解凍 +// 1. 新增一筆解凍交易 +// 2. 減少order餘額 +// 3. 錢包減少凍結餘額 +// 4. 錢包變化新增一筆減少凍結餘額資料 func (use *WalletUseCase) UnFreeze(ctx context.Context, tx usecase.WalletTransferRequest) error { - //TODO implement me - panic("implement me") + // 確認錢包新增或減少的餘額是否正確 + if !tx.Amount.IsPositive() { + return errs.InvalidRange("failed to get correct amount") + } + + tx.TxType = wallet.UnFreeze + + return use.ProcessTransaction(ctx, tx, userWalletFlow{ + UID: tx.FromUID, + Asset: tx.Asset, + Actions: []walletActionOption{use.withSubOrder(nil), use.withLockFreeze(), use.withSubFreeze()}, + }) } func (use *WalletUseCase) RollbackFreeze(ctx context.Context, tx usecase.WalletTransferRequest) error { diff --git a/pkg/usecase/wallet_tx_option.go b/pkg/usecase/wallet_tx_option.go index db638a4..d863114 100644 --- a/pkg/usecase/wallet_tx_option.go +++ b/pkg/usecase/wallet_tx_option.go @@ -1,6 +1,7 @@ package usecase import ( + "code.30cm.net/digimon/app-cloudep-wallet-service/pkg/domain/entity" "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" @@ -187,6 +188,67 @@ func (use *WalletUseCase) withAppendFreeze() walletActionOption { } } +func (use *WalletUseCase) withSubOrder(fTx func(*usecase.WalletTransferRequest, entity.Transaction)) walletActionOption { + return func(ctx context.Context, tx *usecase.WalletTransferRequest, w repository.UserWalletService) error { + order, err := w.GetOrderBalance(ctx, tx.ReferenceOrderID) + if err != nil { + return err + } + + // 檢查order wallet 餘額<=0 + if !order.Amount.IsPositive() { + return err + } + + // 以id來做lock更可以確保只lock到該筆,而不會因為index關係lock到多筆導致死鎖 + // 而且先不lock把資料先拉出來判斷餘額是否足夠,在不足夠時可以直接return而不用lock減少開銷 + order, err = w.GetOrderBalanceForUpdate(ctx, order.OrderID) + if err != nil { + return err + } + + tx.Asset = order.Asset + tx.FromUID = order.UID + + //// 解凍BusinessType,必須跟建立凍結訂單的BusinessType一致 + //if tx.Business != domain.SystemTransferCommissionBusinessTypeBusinessName { + // // 只有系統劃轉會有轉入錢包不同的狀況 + // tx.BusinessType = domain.BusinessTypeToString(order.BusinessType) + //} + + if fTx != nil { + fTx(tx, order) + } + + if err := w.AddOrderBalance(ctx, order.OrderID, tx.Amount.Neg()); err != nil { + return err + } + + return nil + } +} + +func (use *WalletUseCase) withLockFreeze() walletActionOption { + return func(ctx context.Context, tx *usecase.WalletTransferRequest, w repository.UserWalletService) error { + _, err := w.GetBalancesForUpdate(ctx, []wallet.Types{wallet.TypeFreeze}) + if err != nil { + return err + } + + return nil + } +} + +func (use *WalletUseCase) withSubFreeze() walletActionOption { + return func(ctx context.Context, tx *usecase.WalletTransferRequest, w repository.UserWalletService) error { + if err := w.DecreaseBalance(wallet.TypeFreeze, tx.ReferenceOrderID, tx.Amount); err != nil { + return err + } + + return nil + } +} + //// withSubFreeze 減少用戶凍結餘額 //func (use *WalletUseCase) withSubFreeze() walletActionOption { // return func(_ context.Context, tx *usecase.Transaction, wallet repository.UserWallet) error {