钱包流水新增资产信息
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m59s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m59s
This commit is contained in:
@@ -5740,6 +5740,16 @@ components:
|
|||||||
amount:
|
amount:
|
||||||
description: 变动金额(分,正数为入账,负数为扣款)
|
description: 变动金额(分,正数为入账,负数为扣款)
|
||||||
type: integer
|
type: integer
|
||||||
|
asset_id:
|
||||||
|
description: 资产ID(仅套餐扣款流水有值)
|
||||||
|
minimum: 0
|
||||||
|
type: integer
|
||||||
|
asset_identifier:
|
||||||
|
description: 资产标识快照(ICCID、IMEI或虚拟号,仅套餐扣款流水有值)
|
||||||
|
type: string
|
||||||
|
asset_type:
|
||||||
|
description: 资产类型(iot_card:物联网卡, device:设备,仅套餐扣款流水有值)
|
||||||
|
type: string
|
||||||
balance_after:
|
balance_after:
|
||||||
description: 变动后余额(分)
|
description: 变动后余额(分)
|
||||||
type: integer
|
type: integer
|
||||||
|
|||||||
@@ -50,6 +50,9 @@ type AgentWalletTransaction struct {
|
|||||||
ReferenceType *string `gorm:"column:reference_type;type:varchar(50);comment:关联业务类型(order | commission | withdrawal | topup)" json:"reference_type,omitempty"`
|
ReferenceType *string `gorm:"column:reference_type;type:varchar(50);comment:关联业务类型(order | commission | withdrawal | topup)" json:"reference_type,omitempty"`
|
||||||
ReferenceID *uint `gorm:"column:reference_id;comment:关联业务ID" json:"reference_id,omitempty"`
|
ReferenceID *uint `gorm:"column:reference_id;comment:关联业务ID" json:"reference_id,omitempty"`
|
||||||
RelatedShopID *uint `gorm:"column:related_shop_id;comment:关联店铺ID(代购时记录下级店铺)" json:"related_shop_id,omitempty"`
|
RelatedShopID *uint `gorm:"column:related_shop_id;comment:关联店铺ID(代购时记录下级店铺)" json:"related_shop_id,omitempty"`
|
||||||
|
AssetType string `gorm:"column:asset_type;type:varchar(20);not null;default:'';comment:资产类型(iot_card-物联网卡 | device-设备)" json:"asset_type,omitempty"`
|
||||||
|
AssetID uint `gorm:"column:asset_id;not null;default:0;comment:资产ID快照(卡ID或设备ID)" json:"asset_id,omitempty"`
|
||||||
|
AssetIdentifier string `gorm:"column:asset_identifier;type:varchar(100);not null;default:'';comment:资产标识快照(ICCID、IMEI或虚拟号)" json:"asset_identifier,omitempty"`
|
||||||
Remark *string `gorm:"column:remark;type:text;comment:备注" json:"remark,omitempty"`
|
Remark *string `gorm:"column:remark;type:text;comment:备注" json:"remark,omitempty"`
|
||||||
Metadata *string `gorm:"column:metadata;type:jsonb;comment:扩展信息(如手续费、支付方式等)" json:"metadata,omitempty"`
|
Metadata *string `gorm:"column:metadata;type:jsonb;comment:扩展信息(如手续费、支付方式等)" json:"metadata,omitempty"`
|
||||||
Creator uint `gorm:"column:creator;not null;comment:创建人ID" json:"creator"`
|
Creator uint `gorm:"column:creator;not null;comment:创建人ID" json:"creator"`
|
||||||
|
|||||||
@@ -60,6 +60,9 @@ type MainWalletTransactionItem struct {
|
|||||||
Amount int64 `json:"amount" description:"变动金额(分,正数为入账,负数为扣款)"`
|
Amount int64 `json:"amount" description:"变动金额(分,正数为入账,负数为扣款)"`
|
||||||
BalanceBefore int64 `json:"balance_before" description:"变动前余额(分)"`
|
BalanceBefore int64 `json:"balance_before" description:"变动前余额(分)"`
|
||||||
BalanceAfter int64 `json:"balance_after" description:"变动后余额(分)"`
|
BalanceAfter int64 `json:"balance_after" description:"变动后余额(分)"`
|
||||||
|
AssetType string `json:"asset_type" description:"资产类型(iot_card:物联网卡, device:设备,仅套餐扣款流水有值)"`
|
||||||
|
AssetID uint `json:"asset_id" description:"资产ID(仅套餐扣款流水有值)"`
|
||||||
|
AssetIdentifier string `json:"asset_identifier" description:"资产标识快照(ICCID、IMEI或虚拟号,仅套餐扣款流水有值)"`
|
||||||
Remark string `json:"remark" description:"备注(可为空)"`
|
Remark string `json:"remark" description:"备注(可为空)"`
|
||||||
CreatedAt string `json:"created_at" description:"流水时间"`
|
CreatedAt string `json:"created_at" description:"流水时间"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -728,6 +728,7 @@ func (s *Service) CreateH5Order(ctx context.Context, req *dto.CreateOrderRequest
|
|||||||
BuyerID: orderBuyerID,
|
BuyerID: orderBuyerID,
|
||||||
IotCardID: req.IotCardID,
|
IotCardID: req.IotCardID,
|
||||||
DeviceID: req.DeviceID,
|
DeviceID: req.DeviceID,
|
||||||
|
AssetIdentifier: buildOrderAssetIdentifier(validationResult),
|
||||||
TotalAmount: totalAmount,
|
TotalAmount: totalAmount,
|
||||||
PaymentMethod: paymentMethod,
|
PaymentMethod: paymentMethod,
|
||||||
PaymentStatus: paymentStatus,
|
PaymentStatus: paymentStatus,
|
||||||
@@ -988,11 +989,11 @@ func (s *Service) getCostPrice(ctx context.Context, shopID uint, packageID uint)
|
|||||||
// ctx: 上下文
|
// ctx: 上下文
|
||||||
// tx: 事务对象
|
// tx: 事务对象
|
||||||
// wallet: 扣款前的钱包快照
|
// wallet: 扣款前的钱包快照
|
||||||
// orderID: 订单ID
|
// order: 订单快照
|
||||||
// amount: 扣款金额(正数)
|
// amount: 扣款金额(正数)
|
||||||
// purchaseRole: 订单角色
|
// purchaseRole: 订单角色
|
||||||
// relatedShopID: 关联店铺ID(代购场景填充下级店铺ID)
|
// relatedShopID: 关联店铺ID(代购场景填充下级店铺ID)
|
||||||
func (s *Service) createWalletTransaction(ctx context.Context, tx *gorm.DB, wallet *model.AgentWallet, orderID uint, amount int64, purchaseRole string, relatedShopID *uint) error {
|
func (s *Service) createWalletTransaction(ctx context.Context, tx *gorm.DB, wallet *model.AgentWallet, order *model.Order, amount int64, purchaseRole string, relatedShopID *uint) error {
|
||||||
var subtype *string
|
var subtype *string
|
||||||
remark := "购买套餐"
|
remark := "购买套餐"
|
||||||
if purchaseRole == "" {
|
if purchaseRole == "" {
|
||||||
@@ -1021,6 +1022,7 @@ func (s *Service) createWalletTransaction(ctx context.Context, tx *gorm.DB, wall
|
|||||||
}
|
}
|
||||||
|
|
||||||
userID := middleware.GetUserIDFromContext(ctx)
|
userID := middleware.GetUserIDFromContext(ctx)
|
||||||
|
assetType, assetID, assetIdentifier := buildAgentWalletTransactionAssetSnapshot(order)
|
||||||
|
|
||||||
// 创建钱包流水记录
|
// 创建钱包流水记录
|
||||||
transaction := &model.AgentWalletTransaction{
|
transaction := &model.AgentWalletTransaction{
|
||||||
@@ -1034,8 +1036,11 @@ func (s *Service) createWalletTransaction(ctx context.Context, tx *gorm.DB, wall
|
|||||||
BalanceAfter: wallet.Balance - amount,
|
BalanceAfter: wallet.Balance - amount,
|
||||||
Status: constants.TransactionStatusSuccess,
|
Status: constants.TransactionStatusSuccess,
|
||||||
ReferenceType: strPtr(constants.ReferenceTypeOrder),
|
ReferenceType: strPtr(constants.ReferenceTypeOrder),
|
||||||
ReferenceID: &orderID,
|
ReferenceID: &order.ID,
|
||||||
RelatedShopID: relatedShopID,
|
RelatedShopID: relatedShopID,
|
||||||
|
AssetType: assetType,
|
||||||
|
AssetID: assetID,
|
||||||
|
AssetIdentifier: assetIdentifier,
|
||||||
Remark: &remark,
|
Remark: &remark,
|
||||||
Creator: userID,
|
Creator: userID,
|
||||||
ShopIDTag: wallet.ShopIDTag,
|
ShopIDTag: wallet.ShopIDTag,
|
||||||
@@ -1049,6 +1054,51 @@ func (s *Service) createWalletTransaction(ctx context.Context, tx *gorm.DB, wall
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// buildAgentWalletTransactionAssetSnapshot 从订单中生成代理钱包扣款流水的资产快照。
|
||||||
|
func buildAgentWalletTransactionAssetSnapshot(order *model.Order) (string, uint, string) {
|
||||||
|
if order == nil {
|
||||||
|
return "", 0, ""
|
||||||
|
}
|
||||||
|
switch order.OrderType {
|
||||||
|
case model.OrderTypeSingleCard:
|
||||||
|
if order.IotCardID == nil {
|
||||||
|
return constants.AssetTypeIotCard, 0, order.AssetIdentifier
|
||||||
|
}
|
||||||
|
return constants.AssetTypeIotCard, *order.IotCardID, order.AssetIdentifier
|
||||||
|
case model.OrderTypeDevice:
|
||||||
|
if order.DeviceID == nil {
|
||||||
|
return constants.AssetTypeDevice, 0, order.AssetIdentifier
|
||||||
|
}
|
||||||
|
return constants.AssetTypeDevice, *order.DeviceID, order.AssetIdentifier
|
||||||
|
default:
|
||||||
|
return "", 0, order.AssetIdentifier
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildOrderAssetIdentifier 生成订单资产标识快照。
|
||||||
|
// 后台按标识下单时保留请求标识;按ID下单时用卡ICCID或设备IMEI/虚拟号兜底。
|
||||||
|
func buildOrderAssetIdentifier(result *purchase_validation.PurchaseValidationResult) string {
|
||||||
|
if result == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if result.Card != nil {
|
||||||
|
return result.Card.ICCID
|
||||||
|
}
|
||||||
|
if result.Device != nil {
|
||||||
|
return firstNonEmpty(result.Device.IMEI, result.Device.VirtualNo)
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func firstNonEmpty(values ...string) string {
|
||||||
|
for _, value := range values {
|
||||||
|
if value != "" {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
// strPtr 字符串指针辅助函数
|
// strPtr 字符串指针辅助函数
|
||||||
func strPtr(s string) *string {
|
func strPtr(s string) *string {
|
||||||
return &s
|
return &s
|
||||||
@@ -1113,7 +1163,7 @@ func (s *Service) createOrderWithWalletPayment(ctx context.Context, order *model
|
|||||||
if order.PurchaseRole == model.PurchaseRolePurchaseForSubordinate {
|
if order.PurchaseRole == model.PurchaseRolePurchaseForSubordinate {
|
||||||
relatedShopID = &buyerShopID
|
relatedShopID = &buyerShopID
|
||||||
}
|
}
|
||||||
if err := s.createWalletTransaction(ctx, tx, wallet, order.ID, actualAmount, order.PurchaseRole, relatedShopID); err != nil {
|
if err := s.createWalletTransaction(ctx, tx, wallet, order, actualAmount, order.PurchaseRole, relatedShopID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1593,7 +1643,7 @@ func (s *Service) WalletPay(ctx context.Context, orderID uint, buyerType string,
|
|||||||
return errors.New(errors.CodeInsufficientBalance, "余额不足或并发冲突")
|
return errors.New(errors.CodeInsufficientBalance, "余额不足或并发冲突")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.createWalletTransaction(ctx, tx, wallet, order.ID, order.TotalAmount, order.PurchaseRole, nil); err != nil {
|
if err := s.createWalletTransaction(ctx, tx, wallet, order, order.TotalAmount, order.PurchaseRole, nil); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -739,6 +739,9 @@ func (s *Service) ListMainWalletTransactions(ctx context.Context, shopID uint, r
|
|||||||
Amount: t.Amount,
|
Amount: t.Amount,
|
||||||
BalanceBefore: t.BalanceBefore,
|
BalanceBefore: t.BalanceBefore,
|
||||||
BalanceAfter: t.BalanceAfter,
|
BalanceAfter: t.BalanceAfter,
|
||||||
|
AssetType: t.AssetType,
|
||||||
|
AssetID: t.AssetID,
|
||||||
|
AssetIdentifier: t.AssetIdentifier,
|
||||||
Remark: remark,
|
Remark: remark,
|
||||||
CreatedAt: t.CreatedAt.Format("2006-01-02 15:04:05"),
|
CreatedAt: t.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
ALTER TABLE tb_agent_wallet_transaction
|
||||||
|
DROP COLUMN IF EXISTS asset_identifier,
|
||||||
|
DROP COLUMN IF EXISTS asset_id,
|
||||||
|
DROP COLUMN IF EXISTS asset_type;
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
-- 为代理钱包流水新增消费资产快照字段
|
||||||
|
-- 仅新产生的套餐扣款流水在消费发生时写入,存量历史流水不回填。
|
||||||
|
ALTER TABLE tb_agent_wallet_transaction
|
||||||
|
ADD COLUMN IF NOT EXISTS asset_type VARCHAR(20) NOT NULL DEFAULT '',
|
||||||
|
ADD COLUMN IF NOT EXISTS asset_id BIGINT NOT NULL DEFAULT 0,
|
||||||
|
ADD COLUMN IF NOT EXISTS asset_identifier VARCHAR(100) NOT NULL DEFAULT '';
|
||||||
|
|
||||||
|
COMMENT ON COLUMN tb_agent_wallet_transaction.asset_type IS '消费资产类型快照:iot_card-物联网卡 | device-设备';
|
||||||
|
COMMENT ON COLUMN tb_agent_wallet_transaction.asset_id IS '消费资产ID快照(卡ID或设备ID)';
|
||||||
|
COMMENT ON COLUMN tb_agent_wallet_transaction.asset_identifier IS '消费资产标识快照(ICCID、IMEI或虚拟号)';
|
||||||
Reference in New Issue
Block a user