Files
junhong_cmp_fiber/internal/service/asset_wallet/service.go
huang 00dba42a63 feat(03.1-01): 补全 Gateway SyncDeviceInfoResp 缺失字段及 B 端 DeviceGatewayInfo DTO
- SyncDeviceInfoResp 新增 Rsrp/Rsrq/Sinr/WifiPassword/IPAddress/WANIP/LANIP/MaxClients/ConnectTime/Status/IMSI/ULStats/DLStats/LimitSpeed/SyncInterval 共 15 个字段
- asset_dto.go 新增 DeviceGatewayInfo B 端实时状态结构体(49 字段,全部含 description tag)
- AssetRealtimeStatusResponse 新增 DeviceRealtime *DeviceGatewayInfo 字段
- AssetResolveResponse 新增 5 个设备 DB 缓存字段(online_status/last_online_time/software_version/switch_mode/last_gateway_sync_at)
2026-03-28 13:17:52 +08:00

164 lines
4.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 {
// 暂无钱包记录属于正常业务状态(企业卡/未充值资产),返回 nil 而非错误
return nil, nil
}
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 将路由参数 assetTypecard/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
}
}