This commit is contained in:
JNG 2026-02-03 16:46:57 +08:00
parent bb9c22e1aa
commit 0802c372b0
2 changed files with 181 additions and 12 deletions

View File

@ -3387,6 +3387,7 @@ type AddInfo struct {
Num int32 `protobuf:"varint,2,opt,name=num,proto3" json:"num"` Num int32 `protobuf:"varint,2,opt,name=num,proto3" json:"num"`
ValueAddUUID string `protobuf:"bytes,3,opt,name=valueAddUUID,proto3" json:"valueAddUUID"` ValueAddUUID string `protobuf:"bytes,3,opt,name=valueAddUUID,proto3" json:"valueAddUUID"`
EquityType int32 `protobuf:"varint,4,opt,name=equityType,proto3" json:"equityType"` EquityType int32 `protobuf:"varint,4,opt,name=equityType,proto3" json:"equityType"`
ServiceType int32 `protobuf:"varint,5,opt,name=serviceType,proto3" json:"serviceType"`
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@ -3449,6 +3450,13 @@ func (x *AddInfo) GetEquityType() int32 {
return 0 return 0
} }
func (x *AddInfo) GetServiceType() int32 {
if x != nil {
return x.ServiceType
}
return 0
}
type OrderAddRecord struct { type OrderAddRecord struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
BundleUuid string `protobuf:"bytes,1,opt,name=bundleUuid,proto3" json:"bundleUuid"` BundleUuid string `protobuf:"bytes,1,opt,name=bundleUuid,proto3" json:"bundleUuid"`
@ -16196,14 +16204,15 @@ const file_pb_bundle_proto_rawDesc = "" +
"\baddInfos\x18' \x03(\v2\x0f.bundle.AddInfoR\baddInfos\x12 \n" + "\baddInfos\x18' \x03(\v2\x0f.bundle.AddInfoR\baddInfos\x12 \n" +
"\vreSignature\x18( \x01(\x05R\vreSignature\x12\"\n" + "\vreSignature\x18( \x01(\x05R\vreSignature\x12\"\n" +
"\fpurchaseType\x18) \x01(\x04R\fpurchaseType\x12*\n" + "\fpurchaseType\x18) \x01(\x04R\fpurchaseType\x12*\n" +
"\x10renewalOrderUUID\x18* \x01(\tR\x10renewalOrderUUID\"y\n" + "\x10renewalOrderUUID\x18* \x01(\tR\x10renewalOrderUUID\"\x9b\x01\n" +
"\aAddInfo\x12\x18\n" + "\aAddInfo\x12\x18\n" +
"\aorderNo\x18\x01 \x01(\tR\aorderNo\x12\x10\n" + "\aorderNo\x18\x01 \x01(\tR\aorderNo\x12\x10\n" +
"\x03num\x18\x02 \x01(\x05R\x03num\x12\"\n" + "\x03num\x18\x02 \x01(\x05R\x03num\x12\"\n" +
"\fvalueAddUUID\x18\x03 \x01(\tR\fvalueAddUUID\x12\x1e\n" + "\fvalueAddUUID\x18\x03 \x01(\tR\fvalueAddUUID\x12\x1e\n" +
"\n" + "\n" +
"equityType\x18\x04 \x01(\x05R\n" + "equityType\x18\x04 \x01(\x05R\n" +
"equityType\"\xdd\x03\n" + "equityType\x12 \n" +
"\vserviceType\x18\x05 \x01(\x05R\vserviceType\"\xdd\x03\n" +
"\x0eOrderAddRecord\x12\x1e\n" + "\x0eOrderAddRecord\x12\x1e\n" +
"\n" + "\n" +
"bundleUuid\x18\x01 \x01(\tR\n" + "bundleUuid\x18\x01 \x01(\tR\n" +

View File

@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"fonchain-fiee/api/accountFiee" "fonchain-fiee/api/accountFiee"
"fonchain-fiee/api/bundle" "fonchain-fiee/api/bundle"
castProto "fonchain-fiee/api/cast"
"fonchain-fiee/api/order" "fonchain-fiee/api/order"
"fonchain-fiee/api/payment" "fonchain-fiee/api/payment"
"fonchain-fiee/pkg/cache" "fonchain-fiee/pkg/cache"
@ -602,6 +603,20 @@ func AntomWebhook(c *gin.Context) {
} }
fmt.Println("resp.Status:", resp.Status) fmt.Println("resp.Status:", resp.Status)
if resp.Status == "paid" { if resp.Status == "paid" {
//添加余额
orderLimit, err := service.BundleProvider.OrderListByOrderNo(context.Background(), &bundle.OrderInfoByOrderNoRequest{
OrderNo: resp.OutTradeNo,
})
if err != nil {
service.Error(c, err)
return
}
//获取上一笔订单信息:如果没有查询到代表首次购买 需要判断异常情况
lastOrderInfo, _ := service.BundleProvider.OrderRecordsDetail(context.Background(), &bundle.OrderRecordsDetailRequest{
CustomerID: strconv.FormatUint(orderLimit.UserId, 10),
Status: 2,
})
//支付成功 //支付成功
_, updateStatusErr := service.BundleProvider.UpdateOrderRecordByOrderNo(context.Background(), &bundle.OrderRecord{ _, updateStatusErr := service.BundleProvider.UpdateOrderRecordByOrderNo(context.Background(), &bundle.OrderRecord{
OrderNo: resp.OutTradeNo, OrderNo: resp.OutTradeNo,
@ -625,14 +640,6 @@ func AntomWebhook(c *gin.Context) {
return return
} }
//添加余额
orderLimit, err := service.BundleProvider.OrderListByOrderNo(context.Background(), &bundle.OrderInfoByOrderNoRequest{
OrderNo: resp.OutTradeNo,
})
if err != nil {
service.Error(c, err)
return
}
//购买套餐 //购买套餐
switch orderLimit.Type { switch orderLimit.Type {
case common.OrderTypePackage: case common.OrderTypePackage:
@ -698,9 +705,9 @@ func AntomWebhook(c *gin.Context) {
service.Error(c, err) service.Error(c, err)
return return
} }
if orderLimit.PurchaseType == 1 { // 处理媒体账号绑定逻辑
handleMediaAccountBinding(orderLimit.UserId, orderLimit.PurchaseType, int(orderLimit.AccountNumber), lastOrderInfo)
}
} }
service.Success(c) service.Success(c)
} }
@ -763,3 +770,156 @@ func HomePageRoll(c *gin.Context) {
service.Success(c, roll) service.Success(c, roll)
return return
} }
// MediaAccount 媒体账号信息
type MediaAccount struct {
UUID string
PlatformID uint32
}
// handleMediaAccountBinding 处理媒体账号绑定逻辑(统一解绑方法)
// userId: 用户ID
// purchaseType: 购买类型(新购/续费)
// currentAccountNum: 本次购买的账号数
// lastOrderInfo: 上次订单信息
func handleMediaAccountBinding(userId uint64, purchaseType int32, currentAccountNum int, lastOrderInfo *bundle.OrderRecordsDetailResponse) {
// 1. 获取用户的媒体账号列表
MediaList, err := service.CastProvider.MediaUserList(context.Background(), &castProto.MediaUserListReq{
Page: 1,
PageSize: 999,
ArtistUuid: strconv.FormatUint(userId, 10),
})
if err != nil {
logger.Warnf("Failed to get media list for user %d: %v", userId, err)
return
}
if MediaList == nil || len(MediaList.Data) == 0 {
logger.Infof("No media accounts found for user %d", userId)
return
}
// 2. 收集过期的媒体账号信息包含平台ID
var expiredAccounts []MediaAccount
for _, media := range MediaList.Data {
if media.Expired == 1 {
expiredAccounts = append(expiredAccounts, MediaAccount{
UUID: media.MediaAccountUuid,
PlatformID: media.PlatformID,
})
}
}
if len(expiredAccounts) == 0 {
logger.Infof("No expired media accounts found for user %d", userId)
return
}
// 3. 判断是否首次购买
isFirstPurchase := lastOrderInfo == nil || lastOrderInfo.OrderRecord == nil || len(lastOrderInfo.OrderRecord.AddInfos) == 0
// 4. 根据购买类型处理解绑逻辑
var accountsToUnbind []string
if purchaseType == common.NewPurchaseOrder {
// 新购订单
if isFirstPurchase {
logger.Infof("First time purchase for user %d, no need to unbind accounts", userId)
return
}
// 非首次购买的新购:解绑所有过期账号
for _, account := range expiredAccounts {
accountsToUnbind = append(accountsToUnbind, account.UUID)
}
logger.Infof("New purchase for user %d, will unbind all %d expired accounts", userId, len(accountsToUnbind))
} else if purchaseType == common.RenewalOrder {
// 续费订单
if isFirstPurchase {
logger.Infof("No previous order found for renewal user %d, no need to unbind accounts", userId)
return
}
// 获取上次购买的账号数
var lastAccountNum int
for _, addInfo := range lastOrderInfo.OrderRecord.AddInfos {
if addInfo.ServiceType == 4 { // ServiceType 4 表示账号服务
lastAccountNum += int(addInfo.Num)
}
}
logger.Infof("Renewal order for user %d: current=%d, last=%d, expired=%d",
userId, currentAccountNum, lastAccountNum, len(expiredAccounts))
// 如果当前购买数量 >= 上次购买数量,不需要解绑
if currentAccountNum >= lastAccountNum {
logger.Infof("No need to unbind accounts for renewal user %d: current(%d) >= last(%d)",
userId, currentAccountNum, lastAccountNum)
return
}
// 当前购买数量 < 上次购买数量,按优先级解绑差额部分
needUnbindCount := lastAccountNum - currentAccountNum
// 定义平台优先级(数字越小优先级越高,优先保留)
// TikTok(1) > DM(4) > Bluesky(5) > Instagram(3) > YouTube(2)
platformPriority := map[uint32]int{
1: 1, // TikTok - 最高优先级,最后解绑
4: 2, // DM
5: 3, // Bluesky
3: 4, // Instagram
2: 5, // YouTube - 最低优先级,最先解绑
}
// 按优先级排序(优先级低的排在前面,先解绑)
sortedAccounts := make([]MediaAccount, len(expiredAccounts))
copy(sortedAccounts, expiredAccounts)
for i := 0; i < len(sortedAccounts)-1; i++ {
for j := 0; j < len(sortedAccounts)-i-1; j++ {
priority1 := platformPriority[sortedAccounts[j].PlatformID]
priority2 := platformPriority[sortedAccounts[j+1].PlatformID]
if priority1 == 0 {
priority1 = 999
}
if priority2 == 0 {
priority2 = 999
}
// 降序排列:优先级数字大的排在前面(先解绑)
if priority1 < priority2 {
sortedAccounts[j], sortedAccounts[j+1] = sortedAccounts[j+1], sortedAccounts[j]
}
}
}
// 取前needUnbindCount个账号进行解绑
if needUnbindCount > len(sortedAccounts) {
needUnbindCount = len(sortedAccounts)
}
for i := 0; i < needUnbindCount; i++ {
accountsToUnbind = append(accountsToUnbind, sortedAccounts[i].UUID)
}
logger.Infof("Renewal downgrade for user %d, will unbind %d accounts by priority", userId, len(accountsToUnbind))
}
// 5. 执行解绑操作
if len(accountsToUnbind) > 0 {
successCount := 0
failCount := 0
for _, accountUUID := range accountsToUnbind {
if _, err := service.CastProvider.UpdateMediaAccInfo(context.Background(), &castProto.UpdateMediaAccInfoReq{
MediaAccountUuid: accountUUID,
Expired: 2,
ExpiredSource: castProto.ExpiredMediaSourceENUM_UpdateMediaSource_CHARGE,
}); err != nil {
logger.Errorf("Failed to unbind account %s for user %d: %v", accountUUID, userId, err)
failCount++
} else {
successCount++
}
}
logger.Infof("Unbind completed for user %d: success=%d, fail=%d", userId, successCount, failCount)
}
}