Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
163 lines
4.6 KiB
Go
163 lines
4.6 KiB
Go
package asset_wallet
|
||
|
||
import (
|
||
"context"
|
||
|
||
"github.com/break/junhong_cmp_fiber/internal/model/dto"
|
||
"github.com/break/junhong_cmp_fiber/internal/store/postgres"
|
||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||
"gorm.io/gorm"
|
||
)
|
||
|
||
// Service 资产钱包业务服务
|
||
// 负责管理端资产(卡/设备)钱包概况查询和流水列表查询
|
||
type Service struct {
|
||
assetWalletStore *postgres.AssetWalletStore
|
||
assetWalletTransactionStore *postgres.AssetWalletTransactionStore
|
||
}
|
||
|
||
// New 创建资产钱包服务实例
|
||
func New(assetWalletStore *postgres.AssetWalletStore, assetWalletTransactionStore *postgres.AssetWalletTransactionStore) *Service {
|
||
return &Service{
|
||
assetWalletStore: assetWalletStore,
|
||
assetWalletTransactionStore: assetWalletTransactionStore,
|
||
}
|
||
}
|
||
|
||
// GetWallet 查询资产钱包概况
|
||
// assetType 为 card 或 device,映射到 resourceType = iot_card 或 device
|
||
func (s *Service) GetWallet(ctx context.Context, assetType string, assetID uint) (*dto.AssetWalletResponse, error) {
|
||
resourceType, err := mapAssetTypeToResourceType(assetType)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
wallet, err := s.assetWalletStore.GetByResourceTypeAndID(ctx, resourceType, assetID)
|
||
if err != nil {
|
||
if err == gorm.ErrRecordNotFound {
|
||
return nil, errors.New(errors.CodeNotFound, "该资产暂无钱包记录")
|
||
}
|
||
return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询钱包失败")
|
||
}
|
||
|
||
statusText := walletStatusText(wallet.Status)
|
||
|
||
return &dto.AssetWalletResponse{
|
||
WalletID: wallet.ID,
|
||
ResourceType: wallet.ResourceType,
|
||
ResourceID: wallet.ResourceID,
|
||
Balance: wallet.Balance,
|
||
FrozenBalance: wallet.FrozenBalance,
|
||
AvailableBalance: wallet.Balance - wallet.FrozenBalance,
|
||
Currency: wallet.Currency,
|
||
Status: wallet.Status,
|
||
StatusText: statusText,
|
||
CreatedAt: wallet.CreatedAt,
|
||
UpdatedAt: wallet.UpdatedAt,
|
||
}, nil
|
||
}
|
||
|
||
// ListTransactions 查询资产钱包流水列表(分页)
|
||
func (s *Service) ListTransactions(ctx context.Context, assetType string, assetID uint, req *dto.AssetWalletTransactionListRequest) (*dto.AssetWalletTransactionListResponse, error) {
|
||
resourceType, err := mapAssetTypeToResourceType(assetType)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
page := req.Page
|
||
if page < 1 {
|
||
page = 1
|
||
}
|
||
pageSize := req.PageSize
|
||
if pageSize < 1 {
|
||
pageSize = 20
|
||
}
|
||
if pageSize > 100 {
|
||
pageSize = 100
|
||
}
|
||
offset := (page - 1) * pageSize
|
||
|
||
transactions, err := s.assetWalletTransactionStore.ListByResourceIDWithFilter(
|
||
ctx, resourceType, assetID, req.TransactionType, req.StartTime, req.EndTime, offset, pageSize,
|
||
)
|
||
if err != nil {
|
||
return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询流水列表失败")
|
||
}
|
||
|
||
total, err := s.assetWalletTransactionStore.CountByResourceIDWithFilter(
|
||
ctx, resourceType, assetID, req.TransactionType, req.StartTime, req.EndTime,
|
||
)
|
||
if err != nil {
|
||
return nil, errors.Wrap(errors.CodeDatabaseError, err, "统计流水数量失败")
|
||
}
|
||
|
||
list := make([]*dto.AssetWalletTransactionItem, 0, len(transactions))
|
||
for _, tx := range transactions {
|
||
list = append(list, &dto.AssetWalletTransactionItem{
|
||
ID: tx.ID,
|
||
TransactionType: tx.TransactionType,
|
||
TransactionTypeText: transactionTypeText(tx.TransactionType),
|
||
Amount: tx.Amount,
|
||
BalanceBefore: tx.BalanceBefore,
|
||
BalanceAfter: tx.BalanceAfter,
|
||
ReferenceType: tx.ReferenceType,
|
||
ReferenceNo: tx.ReferenceNo,
|
||
Remark: tx.Remark,
|
||
CreatedAt: tx.CreatedAt,
|
||
})
|
||
}
|
||
|
||
totalPages := int(total) / pageSize
|
||
if int(total)%pageSize > 0 {
|
||
totalPages++
|
||
}
|
||
|
||
return &dto.AssetWalletTransactionListResponse{
|
||
List: list,
|
||
Total: total,
|
||
Page: page,
|
||
PageSize: pageSize,
|
||
TotalPages: totalPages,
|
||
}, nil
|
||
}
|
||
|
||
// mapAssetTypeToResourceType 将路由参数 assetType(card/device)映射到数据库资源类型
|
||
func mapAssetTypeToResourceType(assetType string) (string, error) {
|
||
switch assetType {
|
||
case "card":
|
||
return "iot_card", nil
|
||
case "device":
|
||
return "device", nil
|
||
default:
|
||
return "", errors.New(errors.CodeInvalidParam, "无效的资产类型,仅支持 card 或 device")
|
||
}
|
||
}
|
||
|
||
// walletStatusText 翻译钱包状态文本
|
||
func walletStatusText(status int) string {
|
||
switch status {
|
||
case 1:
|
||
return "正常"
|
||
case 2:
|
||
return "冻结"
|
||
case 3:
|
||
return "关闭"
|
||
default:
|
||
return "未知"
|
||
}
|
||
}
|
||
|
||
// transactionTypeText 翻译交易类型文本
|
||
func transactionTypeText(transactionType string) string {
|
||
switch transactionType {
|
||
case "recharge":
|
||
return "充值"
|
||
case "deduct":
|
||
return "扣款"
|
||
case "refund":
|
||
return "退款"
|
||
default:
|
||
return transactionType
|
||
}
|
||
}
|