Compare commits
3 Commits
996cd27fcb
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 837900462a | |||
| 1a5cffa2cc | |||
| 73c6cf9844 |
@ -752,7 +752,7 @@ func (e SmsPhone) OpenWeakUp(c *gin.Context) {
|
|||||||
// 手动续费
|
// 手动续费
|
||||||
func (e SmsPhone) ManualRenewal(c *gin.Context) {
|
func (e SmsPhone) ManualRenewal(c *gin.Context) {
|
||||||
req := dto.ManualRenewalReq{}
|
req := dto.ManualRenewalReq{}
|
||||||
s := service.SmsPhone{}
|
s := service.SmsRenewalLog{}
|
||||||
|
|
||||||
err := e.MakeContext(c).
|
err := e.MakeContext(c).
|
||||||
MakeOrm().
|
MakeOrm().
|
||||||
|
|||||||
@ -12,6 +12,8 @@ import (
|
|||||||
"go-admin/app/admin/service"
|
"go-admin/app/admin/service"
|
||||||
"go-admin/app/admin/service/dto"
|
"go-admin/app/admin/service/dto"
|
||||||
"go-admin/common/actions"
|
"go-admin/common/actions"
|
||||||
|
"go-admin/common/middleware"
|
||||||
|
"go-admin/common/statuscode"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SmsRenewalLog struct {
|
type SmsRenewalLog struct {
|
||||||
@ -190,3 +192,70 @@ func (e SmsRenewalLog) Delete(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
e.OK(req.GetId(), "删除成功")
|
e.OK(req.GetId(), "删除成功")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 手动扣费
|
||||||
|
func (e SmsRenewalLog) ManualDeduct(c *gin.Context) {
|
||||||
|
req := dto.ManualDeductReq{}
|
||||||
|
s := service.SmsRenewalLog{}
|
||||||
|
|
||||||
|
err := e.MakeContext(c).
|
||||||
|
MakeOrm().
|
||||||
|
Bind(&req).
|
||||||
|
MakeService(&s.Service).
|
||||||
|
Errors
|
||||||
|
if err != nil {
|
||||||
|
e.Logger.Error(err)
|
||||||
|
e.Error(500, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
userId, err := middleware.GetUserIdByApiKey(c)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Logger.Error("获取用户id失败", err)
|
||||||
|
e.Error(statuscode.Unauthorized, nil, statuscode.GetMsg(statuscode.Unauthorized, "en"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, code := s.ManualDeduct(&req, userId)
|
||||||
|
if code != statuscode.Success {
|
||||||
|
e.Logger.Error(statuscode.GetMsg(code, "en"))
|
||||||
|
e.Error(code, nil, statuscode.GetMsg(code, "en"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e.OK(result, "success")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取详情根据tradeOrderNo
|
||||||
|
func (e *SmsRenewalLog) GetByTradeOrderNo(c *gin.Context) {
|
||||||
|
req := dto.ManualDeductDetailReq{}
|
||||||
|
s := service.SmsRenewalLog{}
|
||||||
|
err := e.MakeContext(c).
|
||||||
|
MakeOrm().
|
||||||
|
Bind(&req).
|
||||||
|
MakeService(&s.Service).
|
||||||
|
Errors
|
||||||
|
if err != nil {
|
||||||
|
e.Logger.Error(err)
|
||||||
|
e.Error(500, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
userId, err := middleware.GetUserIdByApiKey(c)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Logger.Error("获取用户id失败", err)
|
||||||
|
e.Error(statuscode.Unauthorized, nil, statuscode.GetMsg(statuscode.Unauthorized, "en"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, code := s.GetRenewalDetailByTradeOrderNo(&req, userId)
|
||||||
|
if code != statuscode.Success {
|
||||||
|
e.Logger.Error(statuscode.GetMsg(code, "en"))
|
||||||
|
e.Error(code, nil, statuscode.GetMsg(code, "en"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e.OK(result, "success")
|
||||||
|
}
|
||||||
|
|||||||
@ -30,6 +30,7 @@ type SmsPhone struct {
|
|||||||
Price decimal.Decimal `json:"price" gorm:"type:decimal(10,2);comment:价格"`
|
Price decimal.Decimal `json:"price" gorm:"type:decimal(10,2);comment:价格"`
|
||||||
AutoRenewal int `json:"autoRenewal" gorm:"type:tinyint;comment:是否自动续费 1-自动续费 2-手动续费"`
|
AutoRenewal int `json:"autoRenewal" gorm:"type:tinyint;comment:是否自动续费 1-自动续费 2-手动续费"`
|
||||||
Remark string `json:"remark" gorm:"type:varchar(255);comment:备注"`
|
Remark string `json:"remark" gorm:"type:varchar(255);comment:备注"`
|
||||||
|
BillingCycleId string `json:"billingCycleId" gorm:"type:varchar(50);comment:手动续费id"`
|
||||||
PlatformName string `json:"platformName" gorm:"-"`
|
PlatformName string `json:"platformName" gorm:"-"`
|
||||||
models.ModelTime
|
models.ModelTime
|
||||||
models.ControlBy
|
models.ControlBy
|
||||||
|
|||||||
@ -11,15 +11,24 @@ import (
|
|||||||
type SmsRenewalLog struct {
|
type SmsRenewalLog struct {
|
||||||
models.Model
|
models.Model
|
||||||
|
|
||||||
PhoneId int `json:"phoneId" gorm:"type:bigint;comment:号码id"`
|
PhoneId int `json:"phoneId" gorm:"type:bigint;comment:号码id"`
|
||||||
Phone string `json:"phone" gorm:"type:varchar(50);comment:号码"`
|
Phone string `json:"phone" gorm:"type:varchar(50);comment:号码"`
|
||||||
Type int `json:"type" gorm:"type:tinyint;comment:类型 0-长效 1-短效"`
|
PayOrderNo string `json:"payOrderNo" gorm:"type:varchar(50);comment:本平台支付订单号"`
|
||||||
Category int `json:"category" gorm:"type:tinyint;comment:类别 1-购买号码 2-续费号码"`
|
TradeOrderNo string `json:"tradeOrderNo" gorm:"type:varchar(50);comment:交易订单号"`
|
||||||
UserId int `json:"userId" gorm:"type:bigint;comment:用户id"`
|
Status int `json:"status" gorm:"type:tinyint;comment:状态 1-处理中(冻结) 2-成功 3-失败(解冻)"`
|
||||||
Amount decimal.Decimal `json:"amount" gorm:"type:decimal(10,2);comment:扣费金额"`
|
Type int `json:"type" gorm:"type:tinyint;comment:类型 0-长效 1-短效"`
|
||||||
BeforeTime time.Time `json:"beforeTime" gorm:"type:datetime;comment:续费前过期时间"`
|
Category int `json:"category" gorm:"type:tinyint;comment:类别 1-购买号码 2-续费号码"`
|
||||||
Period int `json:"period" gorm:"type:int;comment:时间段"`
|
UserId int `json:"userId" gorm:"type:bigint;comment:用户id"`
|
||||||
Username string `json:"username" gorm:"->"`
|
Amount decimal.Decimal `json:"amount" gorm:"type:decimal(10,2);comment:扣费金额"`
|
||||||
|
BeforeTime time.Time `json:"beforeTime" gorm:"type:datetime;comment:续费前过期时间"`
|
||||||
|
TargetTime *time.Time `json:"targetTime" gorm:"type:datetime;comment:续费目标过期时间"`
|
||||||
|
Period int `json:"period" gorm:"type:int;comment:时间段"`
|
||||||
|
Remark string `json:"remark" gorm:"type:varchar(255);comment:备注"`
|
||||||
|
Username string `json:"username" gorm:"->"`
|
||||||
|
PlatformCode string `json:"platformCode" gorm:"->"`
|
||||||
|
ApiKey string `json:"apiKey" gorm:"->"`
|
||||||
|
BillingCycleId string `json:"billingCycleId" gorm:"->"`
|
||||||
|
ActivationId string `json:"activationId" gorm:"->"`
|
||||||
models.ModelTime
|
models.ModelTime
|
||||||
models.ControlBy
|
models.ControlBy
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,8 +5,8 @@ import (
|
|||||||
jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
|
jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
|
||||||
|
|
||||||
"go-admin/app/admin/apis"
|
"go-admin/app/admin/apis"
|
||||||
"go-admin/common/middleware"
|
|
||||||
"go-admin/common/actions"
|
"go-admin/common/actions"
|
||||||
|
"go-admin/common/middleware"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -16,6 +16,14 @@ func init() {
|
|||||||
// registerSmsRenewalLogRouter
|
// registerSmsRenewalLogRouter
|
||||||
func registerSmsRenewalLogRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
|
func registerSmsRenewalLogRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
|
||||||
api := apis.SmsRenewalLog{}
|
api := apis.SmsRenewalLog{}
|
||||||
|
r1 := v1.Group("sms-renewal-log").Use(middleware.FrontedAuth)
|
||||||
|
{
|
||||||
|
// 手动扣费续期
|
||||||
|
r1.POST("manual-deduct", api.ManualDeduct)
|
||||||
|
//根据交易订单号获取续期详情
|
||||||
|
r1.GET("detail-byorderno", api.GetByTradeOrderNo)
|
||||||
|
}
|
||||||
|
|
||||||
r := v1.Group("/sms-renewal-log").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
|
r := v1.Group("/sms-renewal-log").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
|
||||||
{
|
{
|
||||||
r.GET("", actions.PermissionAction(), api.GetPage)
|
r.GET("", actions.PermissionAction(), api.GetPage)
|
||||||
|
|||||||
@ -14,8 +14,10 @@ type SmsPhoneGetPageReq struct {
|
|||||||
dto.Pagination `search:"-"`
|
dto.Pagination `search:"-"`
|
||||||
Service string `form:"service" search:"type:exact;column:service;table:sms_phone" comment:"sms 服务"`
|
Service string `form:"service" search:"type:exact;column:service;table:sms_phone" comment:"sms 服务"`
|
||||||
PlatformCode string `form:"platformCode" search:"type:exact;column:platform_code;table:sms_phone" comment:"平台code"`
|
PlatformCode string `form:"platformCode" search:"type:exact;column:platform_code;table:sms_phone" comment:"平台code"`
|
||||||
ServiceCode string `form:"serviceCode" search:"type:exact;column:service_code;table:sms_phone" comment:"服务code"`
|
ServiceCode string `form:"serviceCode" search:"type:contains;column:service_code;table:sms_phone" comment:"服务code"`
|
||||||
|
Phone string `form:"phone" search:"type:contains;column:phone;table:sms_phone" comment:"号码"`
|
||||||
Type int `form:"type" search:"-" comment:"类型 0-短效 1-长效"`
|
Type int `form:"type" search:"-" comment:"类型 0-短效 1-长效"`
|
||||||
|
IsActived int `form:"isActived" search:"-" comment:"是否可用"`
|
||||||
SmsPhoneOrder
|
SmsPhoneOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,12 +194,13 @@ type SmsPhoneCleanMyPhoneReq struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SmsPhoneGetPhoneResp struct {
|
type SmsPhoneGetPhoneResp struct {
|
||||||
Phone string `json:"phone"`
|
Phone string `json:"phone"`
|
||||||
EndAt *time.Time `json:"endTime"`
|
EndAt *time.Time `json:"endTime"`
|
||||||
StartTime *time.Time `json:"-" comment:"唤醒后单次接码开始时间"`
|
StartTime *time.Time `json:"-" comment:"唤醒后单次接码开始时间"`
|
||||||
EndTime *time.Time `json:"-" comment:"唤醒后单次接码过期时间"`
|
EndTime *time.Time `json:"-" comment:"唤醒后单次接码过期时间"`
|
||||||
MessageId string `json:"-" comment:"消息id"`
|
MessageId string `json:"-" comment:"消息id"`
|
||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
|
BillingCycleId string `json:"billingCycleId" comment:"续租id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DaisysmsPriceResp struct {
|
type DaisysmsPriceResp struct {
|
||||||
@ -235,4 +238,23 @@ type BatchCancelAbnormalNumberReq struct {
|
|||||||
|
|
||||||
type ManualRenewalReq struct {
|
type ManualRenewalReq struct {
|
||||||
ActivationIds []string `json:"activationIds" comment:"激活码id"`
|
ActivationIds []string `json:"activationIds" comment:"激活码id"`
|
||||||
|
TradeOrderNo string `json:"tradeOrderNo" comment:"交易订单号"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 手动续期回调请求
|
||||||
|
type ManualRenewCallBackReq struct {
|
||||||
|
TradeOrderNo string `json:"tradeOrderNo" comment:"交易订单号"`
|
||||||
|
PayOrderNo string `json:"payOrderNo" comment:"本平台支付订单号"`
|
||||||
|
Status int `json:"status" comment:"状态 1-处理中 2-失败 3-回滚 4-成功"`
|
||||||
|
Remark string `json:"remark" comment:"备注"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取号码响应
|
||||||
|
type SmsPhoneGetNumberResp struct {
|
||||||
|
ActivationId string `json:"activationId" comment:"激活码id"`
|
||||||
|
Phone string `json:"phone" comment:"号码"`
|
||||||
|
ExpireTime *time.Time `json:"expireTime" comment:"过期时间"`
|
||||||
|
StartTime *time.Time `json:"startTime" comment:"唤醒后单次接码开始时间"`
|
||||||
|
EndTime *time.Time `json:"endTime" comment:"唤醒后单次接码过期时间"`
|
||||||
|
BillingCycleId string `json:"billingCycleId" comment:"续租id"`
|
||||||
}
|
}
|
||||||
|
|||||||
@ -112,17 +112,41 @@ func (s *SmsRenewalLogDeleteReq) GetId() interface{} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SmsRenewalLogResp struct {
|
type SmsRenewalLogResp struct {
|
||||||
Id int `json:"id" comment:"主键id"` // 主键id
|
Id int `json:"id" comment:"主键id"` // 主键id
|
||||||
PhoneId int `json:"phoneId" comment:"号码id"`
|
PhoneId int `json:"phoneId" comment:"号码id"`
|
||||||
Phone string `json:"phone" comment:"电话号码"`
|
Phone string `json:"phone" comment:"电话号码"`
|
||||||
Type int `json:"type" comment:"类型 0-长效 1-短效"`
|
TradeOrderNo string `json:"tradeOrderNo" comment:"交易订单号"`
|
||||||
Category int `json:"category" comment:"类别 1-购买 2-续期"`
|
PayOrderNo string `json:"payOrderNo" comment:"支付订单号"`
|
||||||
UserId int `json:"userId" comment:"用户id"`
|
Type int `json:"type" comment:"类型 0-长效 1-短效"`
|
||||||
Amount decimal.Decimal `json:"amount" comment:"扣费金额"`
|
Category int `json:"category" comment:"类别 1-购买 2-续期"`
|
||||||
BeforeTime time.Time `json:"beforeTime" comment:"续费前过期时间"`
|
UserId int `json:"userId" comment:"用户id"`
|
||||||
Period int `json:"period" comment:"时间(天)"`
|
Amount decimal.Decimal `json:"amount" comment:"扣费金额"`
|
||||||
CreatedAt time.Time `json:"createdAt" comment:"创建时间"`
|
BeforeTime time.Time `json:"beforeTime" comment:"续费前过期时间"`
|
||||||
|
Period int `json:"period" comment:"时间(天)"`
|
||||||
|
CreatedAt time.Time `json:"createdAt" comment:"创建时间"`
|
||||||
|
Status int `json:"status" comment:"状态 1-预扣费 2-成功 3-失败"`
|
||||||
// UpdatedAt time.Time `json:"updatedAt" comment:"更新时间"`
|
// UpdatedAt time.Time `json:"updatedAt" comment:"更新时间"`
|
||||||
// DeletedAt time.Time `json:"deletedAt" comment:"删除时间"`
|
// DeletedAt time.Time `json:"deletedAt" comment:"删除时间"`
|
||||||
UserName string `json:"username" comment:"用户名"`
|
UserName string `json:"username" comment:"用户名"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 手动扣费
|
||||||
|
type ManualDeductReq struct {
|
||||||
|
ActivationId string `json:"activationId" comment:"激活id"`
|
||||||
|
TradeOrderNo string `json:"tradeOrderNo" comment:"交易订单号"`
|
||||||
|
BeginTime time.Time `json:"beginTime" comment:"开始时间"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ManualDeductResp struct {
|
||||||
|
ActivationId string `json:"activationId" comment:"激活id"`
|
||||||
|
TradeOrderNo string `json:"tradeOrderNo" comment:"交易订单号"`
|
||||||
|
PayOrderNo string `json:"payOrderNo" comment:"支付订单号"`
|
||||||
|
BeginTime time.Time `json:"beginTime" comment:"开始时间"`
|
||||||
|
EndTime *time.Time `json:"endTime" comment:"结束时间"`
|
||||||
|
Status int `json:"status" comment:"状态 1-预扣费 2-成功 3-失败"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 续费详情
|
||||||
|
type ManualDeductDetailReq struct {
|
||||||
|
TradeOrderNo string `json:"tradeOrderNo" comment:"交易订单号"`
|
||||||
|
}
|
||||||
|
|||||||
@ -160,16 +160,17 @@ type VerificationDTO struct {
|
|||||||
|
|
||||||
// 长效详情
|
// 长效详情
|
||||||
type VerificationRentalDetailResp struct {
|
type VerificationRentalDetailResp struct {
|
||||||
Number string `json:"number"`
|
Number string `json:"number"`
|
||||||
SMS TextVerifiedResp `json:"sms"`
|
SMS TextVerifiedResp `json:"sms"`
|
||||||
Calls TextVerifiedResp `json:"calls"`
|
Calls TextVerifiedResp `json:"calls"`
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Sale TextVerifiedResp `json:"sale"`
|
Sale TextVerifiedResp `json:"sale"`
|
||||||
SaleId string `json:"saleId"`
|
SaleId string `json:"saleId"`
|
||||||
ServiceName string `json:"serviceName"`
|
BillingCycleId string `json:"billingCycleId" comment:"续租id"`
|
||||||
State string `json:"state"`
|
ServiceName string `json:"serviceName"`
|
||||||
AlwaysOn bool `json:"alwaysOn"`
|
State string `json:"state"`
|
||||||
|
AlwaysOn bool `json:"alwaysOn"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 包含可执行标志 + 链接
|
// 包含可执行标志 + 链接
|
||||||
@ -221,6 +222,38 @@ type TextVerifiedGetNumbersResp struct {
|
|||||||
Data []VerificationDTO `json:"data"`
|
Data []VerificationDTO `json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TextVerifiedGetRentalListResp struct {
|
||||||
|
HasNext bool `json:"hasNext" comment:"是否有下一页"`
|
||||||
|
Links TextVerifiedGetNumbersLinksResp `json:"links"`
|
||||||
|
Data []VerificationRentalDetailResp `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
type TextVerifiedGetNumbersLinksResp struct {
|
type TextVerifiedGetNumbersLinksResp struct {
|
||||||
Next *TextVerifiedResp `json:"next"`
|
Next *TextVerifiedResp `json:"next"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TextVerifiedManualRenewalResp struct {
|
||||||
|
CreatedAt time.Time `json:"createdAt" comment:"创建时间"`
|
||||||
|
Id string `json:"id" comment:"id"`
|
||||||
|
ExcludeRentals []TextVerifiedManualRenewalRental `json:"excludeRentals" comment:"排除的长效详情"`
|
||||||
|
IncludeRentals []TextVerifiedManualRenewalRental `json:"includeRentals" comment:"包含的长效详情"`
|
||||||
|
IsPaidFor bool `json:"isPaidFor" comment:"是否已支付"`
|
||||||
|
TotalCost decimal.Decimal `json:"totalCost" comment:"总费用"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TextVerifiedManualRenewalRental struct {
|
||||||
|
Number string `json:"number" comment:"号码"`
|
||||||
|
Rental TextVerifiedResp `json:"rental" comment:"长效详情"`
|
||||||
|
RenewalCost decimal.Decimal `json:"renewalCost" comment:"续费费用"`
|
||||||
|
ServiceName string `json:"serviceName" comment:"服务名称"`
|
||||||
|
AlreadyRenewed bool `json:"alreadyRenewed" comment:"是否已续费"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 续费周期详情
|
||||||
|
type TextVerifiedGetBillingCycleResp struct {
|
||||||
|
Id string `json:"id" comment:"id"`
|
||||||
|
RenewedThrough time.Time `json:"renewedThrough" comment:"已续费到"`
|
||||||
|
BillingCycleEndsAt time.Time `json:"billingCycleEndsAt" comment:"计费周期结束时间"`
|
||||||
|
NextAutoRenewAttempt time.Time `json:"nextAutoRenewAttempt" comment:"下次自动续费时间"`
|
||||||
|
State string `json:"state" comment:"是否激活 active"`
|
||||||
|
}
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import (
|
|||||||
cDto "go-admin/common/dto"
|
cDto "go-admin/common/dto"
|
||||||
"go-admin/common/global"
|
"go-admin/common/global"
|
||||||
"go-admin/common/statuscode"
|
"go-admin/common/statuscode"
|
||||||
|
"go-admin/utils/utility"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SmsPhone struct {
|
type SmsPhone struct {
|
||||||
@ -24,7 +25,7 @@ type SmsPhone struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// open-API 获取电话号码
|
// open-API 获取电话号码
|
||||||
func (e SmsPhone) OpenGetNumber(req *dto.GetNumberReq, userId int) (dto.OpenGetNumberResp, int) {
|
func (e *SmsPhone) OpenGetNumber(req *dto.GetNumberReq, userId int) (dto.OpenGetNumberResp, int) {
|
||||||
resp := dto.OpenGetNumberResp{}
|
resp := dto.OpenGetNumberResp{}
|
||||||
balanceService := MemberBalance{Service: e.Service}
|
balanceService := MemberBalance{Service: e.Service}
|
||||||
balance, smsPhone, i := e.DoGetNumber(&balanceService, req, userId)
|
balance, smsPhone, i := e.DoGetNumber(&balanceService, req, userId)
|
||||||
@ -321,7 +322,7 @@ func (e *SmsPhone) DoGetNumber(balanceService *MemberBalance, req *dto.GetNumber
|
|||||||
}
|
}
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
activationId, phone, code, expireTime, startTime, endTime, apiInfo := e.GetNumberManage(req.PlatformCode, req.Type, req.ServiceCode, price, req.Period)
|
numberResp, code, apiInfo := e.GetNumberManage(req.PlatformCode, req.Type, req.ServiceCode, price, req.Period)
|
||||||
|
|
||||||
if code != statuscode.Success {
|
if code != statuscode.Success {
|
||||||
return decimal.Decimal{}, models.SmsPhone{}, code
|
return decimal.Decimal{}, models.SmsPhone{}, code
|
||||||
@ -329,24 +330,25 @@ func (e *SmsPhone) DoGetNumber(balanceService *MemberBalance, req *dto.GetNumber
|
|||||||
|
|
||||||
smsPhone := models.SmsPhone{}
|
smsPhone := models.SmsPhone{}
|
||||||
smsPhone.PlatformCode = req.PlatformCode
|
smsPhone.PlatformCode = req.PlatformCode
|
||||||
smsPhone.Phone = phone
|
smsPhone.Phone = numberResp.Phone
|
||||||
smsPhone.UserId = userId
|
smsPhone.UserId = userId
|
||||||
smsPhone.Service = serviceItem.Name
|
smsPhone.Service = serviceItem.Name
|
||||||
smsPhone.ServiceCode = req.ServiceCode
|
smsPhone.ServiceCode = req.ServiceCode
|
||||||
smsPhone.Type = req.Type
|
smsPhone.Type = req.Type
|
||||||
smsPhone.Period = req.Period
|
smsPhone.Period = req.Period
|
||||||
smsPhone.ActivationId = activationId
|
smsPhone.ActivationId = numberResp.ActivationId
|
||||||
smsPhone.MessageId = activationId
|
smsPhone.MessageId = numberResp.ActivationId
|
||||||
smsPhone.NewActivationId = activationId
|
smsPhone.NewActivationId = numberResp.ActivationId
|
||||||
smsPhone.Actived = 1
|
smsPhone.Actived = 1
|
||||||
smsPhone.StartTime = startTime
|
smsPhone.StartTime = numberResp.StartTime
|
||||||
smsPhone.EndTime = endTime
|
smsPhone.EndTime = numberResp.EndTime
|
||||||
smsPhone.ApiKey = apiInfo.ApiKey
|
smsPhone.ApiKey = apiInfo.ApiKey
|
||||||
|
smsPhone.BillingCycleId = numberResp.BillingCycleId
|
||||||
smsPhone.Price = price
|
smsPhone.Price = price
|
||||||
|
|
||||||
if req.Type == 1 {
|
if req.Type == 1 {
|
||||||
if expireTime != nil {
|
if numberResp.ExpireTime != nil {
|
||||||
smsPhone.ExpireTime = expireTime
|
smsPhone.ExpireTime = numberResp.ExpireTime
|
||||||
} else {
|
} else {
|
||||||
days := req.Period * 30
|
days := req.Period * 30
|
||||||
now = now.AddDate(0, 0, days)
|
now = now.AddDate(0, 0, days)
|
||||||
@ -358,8 +360,8 @@ func (e *SmsPhone) DoGetNumber(balanceService *MemberBalance, req *dto.GetNumber
|
|||||||
smsPhone.Actived = 2
|
smsPhone.Actived = 2
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if expireTime != nil {
|
if numberResp.ExpireTime != nil {
|
||||||
smsPhone.ExpireTime = expireTime
|
smsPhone.ExpireTime = numberResp.ExpireTime
|
||||||
} else {
|
} else {
|
||||||
now = now.Add(time.Minute * time.Duration(serviceItem.ExpirationMinutes))
|
now = now.Add(time.Minute * time.Duration(serviceItem.ExpirationMinutes))
|
||||||
smsPhone.ExpireTime = &now
|
smsPhone.ExpireTime = &now
|
||||||
@ -400,6 +402,7 @@ func (e *SmsPhone) DoGetNumber(balanceService *MemberBalance, req *dto.GetNumber
|
|||||||
|
|
||||||
log := models.SmsRenewalLog{}
|
log := models.SmsRenewalLog{}
|
||||||
log.PhoneId = smsPhone.Id
|
log.PhoneId = smsPhone.Id
|
||||||
|
log.PayOrderNo = utility.GenerateTraceID()
|
||||||
log.Phone = smsPhone.Phone
|
log.Phone = smsPhone.Phone
|
||||||
log.Type = smsPhone.Type
|
log.Type = smsPhone.Type
|
||||||
log.Category = 1
|
log.Category = 1
|
||||||
@ -407,6 +410,8 @@ func (e *SmsPhone) DoGetNumber(balanceService *MemberBalance, req *dto.GetNumber
|
|||||||
log.Amount = price
|
log.Amount = price
|
||||||
log.BeforeTime = time.Now()
|
log.BeforeTime = time.Now()
|
||||||
log.Period = req.Period * 30
|
log.Period = req.Period * 30
|
||||||
|
log.Status = 2
|
||||||
|
log.TargetTime = smsPhone.ExpireTime
|
||||||
|
|
||||||
if err := e.Orm.Save(&log).Error; err != nil {
|
if err := e.Orm.Save(&log).Error; err != nil {
|
||||||
e.Log.Errorf("保存短信续费日志失败,phone_id:%d, %s", smsPhone.Id, err)
|
e.Log.Errorf("保存短信续费日志失败,phone_id:%d, %s", smsPhone.Id, err)
|
||||||
@ -423,31 +428,44 @@ func (e *SmsPhone) DoGetNumber(balanceService *MemberBalance, req *dto.GetNumber
|
|||||||
// *startTime 长效号码单次接码开始使用(textverified有用)
|
// *startTime 长效号码单次接码开始使用(textverified有用)
|
||||||
// *endTime 长效号码单次接码过期时间(textverified有用)
|
// *endTime 长效号码单次接码过期时间(textverified有用)
|
||||||
func (e *SmsPhone) GetNumberManage(platformCode string, typ int, serviceCode string,
|
func (e *SmsPhone) GetNumberManage(platformCode string, typ int, serviceCode string,
|
||||||
price decimal.Decimal, period int) (string, string, int, *time.Time, *time.Time, *time.Time, *dto.SmsPlatformKeyQueueDto) {
|
price decimal.Decimal, period int) (dto.SmsPhoneGetNumberResp, int, *dto.SmsPlatformKeyQueueDto) {
|
||||||
smsPlatformKeyRedis := NewSmsPlatformKeyRedis(e.Orm, e.Log)
|
smsPlatformKeyRedis := NewSmsPlatformKeyRedis(e.Orm, e.Log)
|
||||||
queue, err := smsPlatformKeyRedis.GetRoundRobinKey(platformCode)
|
queue, err := smsPlatformKeyRedis.GetRoundRobinKey(platformCode)
|
||||||
|
result := dto.SmsPhoneGetNumberResp{}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.Log.Errorf("获取短信平台队列失败, %s", err)
|
e.Log.Errorf("获取短信平台队列失败, %s", err)
|
||||||
return "", "", statuscode.ServerError, nil, nil, nil, queue
|
return result, statuscode.ServerError, queue
|
||||||
}
|
}
|
||||||
|
|
||||||
switch platformCode {
|
switch platformCode {
|
||||||
case global.SmsPlatformDaisysms:
|
case global.SmsPlatformDaisysms:
|
||||||
service := SmsDaisysms{Service: e.Service}
|
service := SmsDaisysms{Service: e.Service}
|
||||||
activationId, phone, code := service.GetNumberForApi(queue, typ, serviceCode, price, period)
|
activationId, phone, code := service.GetNumberForApi(queue, typ, serviceCode, price, period)
|
||||||
|
result.ActivationId = strconv.Itoa(activationId)
|
||||||
|
result.Phone = phone
|
||||||
|
result.ExpireTime = nil
|
||||||
|
result.StartTime = nil
|
||||||
|
result.EndTime = nil
|
||||||
|
|
||||||
return strconv.Itoa(activationId), phone, code, nil, nil, nil, queue
|
return result, code, queue
|
||||||
case global.SmsPlatformTextVerified:
|
case global.SmsPlatformTextVerified:
|
||||||
service := SmsTextVerified{Service: e.Service}
|
service := SmsTextVerified{Service: e.Service}
|
||||||
resp, code := service.GetNumberAndWakeUp(typ, serviceCode, price, period, queue)
|
resp, code := service.GetNumberAndWakeUp(typ, serviceCode, price, period, queue)
|
||||||
|
result.ActivationId = resp.Id
|
||||||
|
result.Phone = resp.Phone
|
||||||
|
result.ExpireTime = resp.EndAt
|
||||||
|
result.StartTime = resp.StartTime
|
||||||
|
result.EndTime = resp.EndTime
|
||||||
|
result.BillingCycleId = resp.BillingCycleId
|
||||||
|
|
||||||
if code != statuscode.Success {
|
if code != statuscode.Success {
|
||||||
return "", "", code, nil, resp.StartTime, resp.EndTime, queue
|
return result, code, queue
|
||||||
}
|
}
|
||||||
|
|
||||||
return resp.Id, resp.Phone, code, resp.EndAt, resp.StartTime, resp.EndTime, queue
|
return result, code, queue
|
||||||
default:
|
default:
|
||||||
return "", "", statuscode.SmsPlatformUnavailable, nil, nil, nil, queue
|
return result, statuscode.SmsPlatformUnavailable, queue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -587,217 +605,6 @@ func (e *SmsPhone) GetCodeManage(platformCode string, messageId string, typ int,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AutoRenewal 自动续期处理
|
|
||||||
// 处理即将到期的长期号码自动续费逻辑
|
|
||||||
func (e *SmsPhone) AutoRenewal() error {
|
|
||||||
// 获取24小时内到期的自动续费号码
|
|
||||||
expiredPhones, err := e.getExpiredPhones()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取服务配置映射
|
|
||||||
serviceMap, premiumMap, err := e.getRenewalConfigs()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理每个到期号码
|
|
||||||
for _, phone := range expiredPhones {
|
|
||||||
if err := e.processPhoneRenewal(phone, serviceMap, premiumMap); err != nil {
|
|
||||||
e.Log.Errorf("处理号码续费失败 [PhoneID: %d]: %v", phone.Id, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 手动续费
|
|
||||||
func (e *SmsPhone) ManualRenewal(activationIds []string) ([]string, error) {
|
|
||||||
if len(activationIds) == 0 {
|
|
||||||
return nil, errors.New("activationIds 不能为空")
|
|
||||||
}
|
|
||||||
|
|
||||||
var errorIds []string
|
|
||||||
var expiredPhones []models.SmsPhone
|
|
||||||
|
|
||||||
// 查询所有到期号码
|
|
||||||
if err := e.Orm.Model(&models.SmsPhone{}).
|
|
||||||
Where("activation_id IN ? and expire_time < ?", activationIds, time.Now()).
|
|
||||||
Find(&expiredPhones).Error; err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取服务配置映射
|
|
||||||
serviceMap, premiumMap, err := e.getRenewalConfigs()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理每个到期号码
|
|
||||||
for _, phone := range expiredPhones {
|
|
||||||
if err := e.processPhoneRenewal(phone, serviceMap, premiumMap); err != nil {
|
|
||||||
e.Log.Errorf("处理号码续费失败 [PhoneID: %d]: %v", phone.Id, err)
|
|
||||||
errorIds = append(errorIds, fmt.Sprintf("处理号码续费失败 [PhoneID: %d]: %v", phone.Id, err))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return errorIds, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getExpiredPhones 获取即将到期的自动续费号码
|
|
||||||
func (e *SmsPhone) getExpiredPhones() ([]models.SmsPhone, error) {
|
|
||||||
var phones []models.SmsPhone
|
|
||||||
startTime := time.Now().Add(-24 * time.Hour)
|
|
||||||
endTime := time.Now().Add(24 * time.Hour)
|
|
||||||
|
|
||||||
err := e.Orm.Model(&models.SmsPhone{}).
|
|
||||||
Where("auto_renewal = 1 AND type = 1 AND actived = 2 AND expire_time >= ? AND expire_time < ?", startTime, endTime).
|
|
||||||
Find(&phones).Error
|
|
||||||
|
|
||||||
return phones, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// getRenewalConfigs 获取续费相关配置
|
|
||||||
func (e *SmsPhone) getRenewalConfigs() (map[string]models.SmsServices, map[string]dto.GetSysConfigByKEYForServiceResp, error) {
|
|
||||||
smsServices := SmsServices{Service: e.Service}
|
|
||||||
serviceMap := smsServices.GetMapAll()
|
|
||||||
|
|
||||||
configService := SysConfig{Service: e.Service}
|
|
||||||
configKeys := []string{"renew_number_premium_daisysms", "renew_number_premium_textverified"}
|
|
||||||
premiumMap, err := configService.GetMapByKeys(configKeys)
|
|
||||||
|
|
||||||
return serviceMap, premiumMap, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// processPhoneRenewal 处理单个号码的续费
|
|
||||||
func (e *SmsPhone) processPhoneRenewal(phone models.SmsPhone, serviceMap map[string]models.SmsServices, premiumMap map[string]dto.GetSysConfigByKEYForServiceResp) error {
|
|
||||||
// 获取服务价格
|
|
||||||
service, exists := serviceMap[phone.PlatformCode+"_"+phone.ServiceCode]
|
|
||||||
if !exists {
|
|
||||||
return errors.New("服务不存在")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算续费价格
|
|
||||||
renewalPrice := e.calculateRenewalPrice(service.LongPrice, phone.PlatformCode, premiumMap)
|
|
||||||
if renewalPrice.IsZero() {
|
|
||||||
return errors.New("续费价格计算失败")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建续费日志
|
|
||||||
renewLog := e.createRenewalLog(phone, renewalPrice)
|
|
||||||
|
|
||||||
// 执行续费事务
|
|
||||||
return e.executeRenewalTransaction(phone, renewalPrice, renewLog)
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculateRenewalPrice 计算续费价格
|
|
||||||
func (e *SmsPhone) calculateRenewalPrice(basePrice decimal.Decimal, platformCode string, premiumMap map[string]dto.GetSysConfigByKEYForServiceResp) decimal.Decimal {
|
|
||||||
percent := decimal.NewFromInt(1)
|
|
||||||
|
|
||||||
var configKey string
|
|
||||||
switch platformCode {
|
|
||||||
case global.SmsPlatformDaisysms:
|
|
||||||
configKey = "renew_number_premium_daisysms"
|
|
||||||
case global.SmsPlatformTextVerified:
|
|
||||||
configKey = "renew_number_premium_textverified"
|
|
||||||
default:
|
|
||||||
return basePrice
|
|
||||||
}
|
|
||||||
|
|
||||||
if config, exists := premiumMap[configKey]; exists {
|
|
||||||
if val, err := decimal.NewFromString(config.ConfigValue); err == nil && val.Cmp(decimal.Zero) > 0 {
|
|
||||||
percent = decimal.NewFromInt(100).Add(val).Div(decimal.NewFromInt(100))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return basePrice.Mul(percent).Truncate(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// createRenewalLog 创建续费日志
|
|
||||||
func (e *SmsPhone) createRenewalLog(phone models.SmsPhone, amount decimal.Decimal) models.SmsRenewalLog {
|
|
||||||
return models.SmsRenewalLog{
|
|
||||||
UserId: phone.UserId,
|
|
||||||
Phone: phone.Phone,
|
|
||||||
Category: 2,
|
|
||||||
PhoneId: phone.Id,
|
|
||||||
Type: phone.Type,
|
|
||||||
Amount: amount,
|
|
||||||
BeforeTime: *phone.ExpireTime,
|
|
||||||
Period: 30,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// executeRenewalTransaction 执行续费事务
|
|
||||||
func (e *SmsPhone) executeRenewalTransaction(phone models.SmsPhone, price decimal.Decimal, renewLog models.SmsRenewalLog) error {
|
|
||||||
err := e.Orm.Transaction(func(tx *gorm.DB) error {
|
|
||||||
// 扣除余额
|
|
||||||
result := tx.Exec("UPDATE member_balance SET balance = balance - ? WHERE user_id = ? AND balance >= ?", price, phone.UserId, price)
|
|
||||||
if result.Error != nil {
|
|
||||||
return result.Error
|
|
||||||
}
|
|
||||||
if result.RowsAffected == 0 {
|
|
||||||
return errors.New("余额不足")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建续费日志
|
|
||||||
if err := tx.Create(&renewLog).Error; err != nil {
|
|
||||||
return errors.New("创建续费日志失败")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新到期时间
|
|
||||||
newExpireTime := phone.ExpireTime.AddDate(0, 0, 30)
|
|
||||||
params := map[string]interface{}{
|
|
||||||
"expire_time": newExpireTime,
|
|
||||||
"remark": "",
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := tx.Model(&models.SmsPhone{}).Where("id = ?", phone.Id).
|
|
||||||
Updates(params).Error; err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil && err.Error() == "余额不足" {
|
|
||||||
return e.handleInsufficientBalance(phone)
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// handleInsufficientBalance 处理余额不足情况
|
|
||||||
func (e *SmsPhone) handleInsufficientBalance(phone models.SmsPhone) error {
|
|
||||||
params := map[string]interface{}{
|
|
||||||
"auto_renewal": 2,
|
|
||||||
"remark": "余额不足,取消自动续费",
|
|
||||||
}
|
|
||||||
// 取消自动续费
|
|
||||||
if err := e.Orm.Model(&models.SmsPhone{}).
|
|
||||||
Where("id = ?", phone.Id).
|
|
||||||
Updates(params).Error; err != nil {
|
|
||||||
e.Log.Errorf("余额不足,取消自动续费失败: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 调用平台取消续费接口
|
|
||||||
code := e.ChangeAutoRenewManage(phone.PlatformCode, phone.ApiKey, phone.ActivationId, false)
|
|
||||||
if code != statuscode.Success {
|
|
||||||
params["auto_renewal"] = 1
|
|
||||||
params["remark"] = ""
|
|
||||||
// 如果平台取消失败,恢复自动续费状态
|
|
||||||
if err := e.Orm.Model(&models.SmsPhone{}).
|
|
||||||
Where("id = ?", phone.Id).
|
|
||||||
Updates(params).Error; err != nil {
|
|
||||||
e.Log.Errorf("恢复自动续费状态失败: %v", err)
|
|
||||||
}
|
|
||||||
e.Log.Errorf("平台取消自动续费失败,状态码: %d", code)
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors.New("余额不足")
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChangeAutoRenew 修改自动续期
|
// ChangeAutoRenew 修改自动续期
|
||||||
func (e *SmsPhone) ChangeAutoRenew(req *dto.SmsPhoneChangeAutoRenewReq, userId int) int {
|
func (e *SmsPhone) ChangeAutoRenew(req *dto.SmsPhoneChangeAutoRenewReq, userId int) int {
|
||||||
var data models.SmsPhone
|
var data models.SmsPhone
|
||||||
@ -825,8 +632,9 @@ func (e *SmsPhone) ChangeAutoRenew(req *dto.SmsPhoneChangeAutoRenewReq, userId i
|
|||||||
configService := SysConfig{Service: e.Service}
|
configService := SysConfig{Service: e.Service}
|
||||||
configKeys := []string{"renew_number_premium_daisysms", "renew_number_premium_textverified"}
|
configKeys := []string{"renew_number_premium_daisysms", "renew_number_premium_textverified"}
|
||||||
premiumMap, _ := configService.GetMapByKeys(configKeys)
|
premiumMap, _ := configService.GetMapByKeys(configKeys)
|
||||||
|
renewalService := SmsRenewalLog{Service: e.Service}
|
||||||
|
|
||||||
price := e.calculateRenewalPrice(serviceItem.LongPrice, serviceItem.PlatformCode, premiumMap)
|
price := renewalService.calculateRenewalPrice(serviceItem.LongPrice, serviceItem.PlatformCode, premiumMap)
|
||||||
|
|
||||||
if balance.Cmp(price) < 0 {
|
if balance.Cmp(price) < 0 {
|
||||||
return statuscode.BalanceNotEnough
|
return statuscode.BalanceNotEnough
|
||||||
@ -917,12 +725,20 @@ func (e *SmsPhone) GetPage(c *dto.SmsPhoneGetPageReq, p *actions.DataPermission,
|
|||||||
var err error
|
var err error
|
||||||
var data models.SmsPhone
|
var data models.SmsPhone
|
||||||
|
|
||||||
err = e.Orm.Model(&data).
|
query := e.Orm.Model(&data).
|
||||||
Scopes(
|
Scopes(
|
||||||
cDto.MakeCondition(c.GetNeedSearch()),
|
cDto.MakeCondition(c.GetNeedSearch()),
|
||||||
cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
|
cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
|
||||||
actions.Permission(data.TableName(), p),
|
actions.Permission(data.TableName(), p),
|
||||||
).
|
)
|
||||||
|
|
||||||
|
switch c.IsActived {
|
||||||
|
case 1:
|
||||||
|
query = query.Where("expire_time > ?", time.Now())
|
||||||
|
case 2:
|
||||||
|
query = query.Where("expire_time < ?", time.Now())
|
||||||
|
}
|
||||||
|
err = query.
|
||||||
Find(list).Limit(-1).Offset(-1).
|
Find(list).Limit(-1).Offset(-1).
|
||||||
Count(count).Error
|
Count(count).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1035,3 +851,71 @@ func (e *SmsPhone) DeleteExpired() error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 同步手动续费id
|
||||||
|
func (e *SmsPhone) SyncBilingCycleId() error {
|
||||||
|
var logs []models.SmsPhone
|
||||||
|
logMap := map[string]models.SmsPhone{}
|
||||||
|
if err := e.Orm.Model(&models.SmsPhone{}).Where("billing_cycle_id = '' or billing_cycle_id is null").Find(&logs).Error; err != nil {
|
||||||
|
e.Log.Errorf("查询手动续费id为空的记录失败 err:%v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range logs {
|
||||||
|
logMap[item.ActivationId] = item
|
||||||
|
}
|
||||||
|
|
||||||
|
textVerifiedService := SmsTextVerified{Service: e.Service}
|
||||||
|
smsPlatformKeyRedis := NewSmsPlatformKeyRedis(e.Orm, e.Log)
|
||||||
|
apiInfo, err := smsPlatformKeyRedis.GetApiInfo(global.SmsPlatformTextVerified, "ZQ0swXnsaPpeGdwa3c7gT9U9I1Oh9WoDHx0amuYovvaHuqd5u6B4NBBUSUBjR")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("获取平台密钥失败: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = e.syncLoop("", textVerifiedService, apiInfo, logMap)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *SmsPhone) syncLoop(nextUrl string, textVerifiedService SmsTextVerified, apiInfo dto.SmsPlatformKeyQueueDto, logMap map[string]models.SmsPhone) (dto.TextVerifiedGetRentalListResp, error) {
|
||||||
|
if len(logMap) == 0 {
|
||||||
|
return dto.TextVerifiedGetRentalListResp{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
rentalList, err := textVerifiedService.GetRentalList(nextUrl, &apiInfo)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("获取平台密钥失败: %v", err)
|
||||||
|
return dto.TextVerifiedGetRentalListResp{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, log := range rentalList.Data {
|
||||||
|
if log.BillingCycleId == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if item, ok := logMap[log.ID]; ok {
|
||||||
|
if err1 := e.Orm.Model(&models.SmsPhone{}).Where("activation_id = ?", item.ActivationId).Update("billing_cycle_id", log.BillingCycleId).Error; err1 != nil {
|
||||||
|
e.Log.Errorf("更新手动续费id失败 err:%v", err1)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(logMap, item.ActivationId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rentalList.HasNext {
|
||||||
|
time.Sleep(150 * time.Millisecond)
|
||||||
|
rentalList, err = e.syncLoop(rentalList.Links.Next.Href, textVerifiedService, apiInfo, logMap)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("同步续费id失败 err:%v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rentalList, nil
|
||||||
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import (
|
|||||||
"go-admin/app/admin/service/dto"
|
"go-admin/app/admin/service/dto"
|
||||||
"go-admin/common/global"
|
"go-admin/common/global"
|
||||||
"go-admin/common/statuscode"
|
"go-admin/common/statuscode"
|
||||||
|
"go-admin/utils/utility"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/go-admin-team/go-admin-core/logger"
|
"github.com/go-admin-team/go-admin-core/logger"
|
||||||
@ -63,3 +64,31 @@ func TestGetPrices(t *testing.T) {
|
|||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSyncRenewalLogs(t *testing.T) {
|
||||||
|
db := initSetting()
|
||||||
|
|
||||||
|
service := SmsPhone{}
|
||||||
|
service.Orm = db
|
||||||
|
service.Log = logger.NewHelper(logger.DefaultLogger)
|
||||||
|
|
||||||
|
if err := service.SyncBilingCycleId(); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestManualRenewal(t *testing.T) {
|
||||||
|
db := initSetting()
|
||||||
|
|
||||||
|
service := SmsRenewalLog{}
|
||||||
|
service.Orm = db
|
||||||
|
service.Log = logger.NewHelper(logger.DefaultLogger)
|
||||||
|
activationId := "lr_01K5DP71G06SFX84S7W99D61F9"
|
||||||
|
|
||||||
|
if _, err := service.ManualDeduct(&dto.ManualDeductReq{
|
||||||
|
ActivationId: activationId,
|
||||||
|
TradeOrderNo: utility.GenerateTraceID(),
|
||||||
|
}, 1); err != statuscode.Success {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import (
|
|||||||
"go-admin/app/admin/service/dto"
|
"go-admin/app/admin/service/dto"
|
||||||
"go-admin/config"
|
"go-admin/config"
|
||||||
"go-admin/utils/redishelper"
|
"go-admin/utils/redishelper"
|
||||||
|
"go-admin/utils/utility"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/go-admin-team/go-admin-core/logger"
|
"github.com/go-admin-team/go-admin-core/logger"
|
||||||
@ -13,7 +14,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func initSetting() *gorm.DB {
|
func initSetting() *gorm.DB {
|
||||||
dsn := "root:123456@tcp(127.0.0.1:3306)/proxy_server?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms"
|
dsn := "root:123456@tcp(127.0.0.1:3306)/proxy_server_prod?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms"
|
||||||
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||||
sdk.Runtime.SetDb("default", db)
|
sdk.Runtime.SetDb("default", db)
|
||||||
// config.ExtConfig.
|
// config.ExtConfig.
|
||||||
@ -25,6 +26,7 @@ func initSetting() *gorm.DB {
|
|||||||
redishelper.InitDefaultRedis("127.0.0.1:6379", "", 4)
|
redishelper.InitDefaultRedis("127.0.0.1:6379", "", 4)
|
||||||
redishelper.InitLockRedisConn("127.0.0.1:6379", "", "4")
|
redishelper.InitLockRedisConn("127.0.0.1:6379", "", "4")
|
||||||
|
|
||||||
|
utility.InitSnowflake()
|
||||||
return db
|
return db
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,14 +2,21 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-admin-team/go-admin-core/logger"
|
||||||
"github.com/go-admin-team/go-admin-core/sdk/service"
|
"github.com/go-admin-team/go-admin-core/sdk/service"
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
|
||||||
"go-admin/app/admin/models"
|
"go-admin/app/admin/models"
|
||||||
"go-admin/app/admin/service/dto"
|
"go-admin/app/admin/service/dto"
|
||||||
"go-admin/common/actions"
|
"go-admin/common/actions"
|
||||||
cDto "go-admin/common/dto"
|
cDto "go-admin/common/dto"
|
||||||
|
"go-admin/common/global"
|
||||||
|
"go-admin/common/statuscode"
|
||||||
|
"go-admin/utils/utility"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SmsRenewalLog struct {
|
type SmsRenewalLog struct {
|
||||||
@ -42,15 +49,18 @@ func (e *SmsRenewalLog) GetPage(c *dto.SmsRenewalLogGetPageReq, p *actions.DataP
|
|||||||
|
|
||||||
for _, v := range datas {
|
for _, v := range datas {
|
||||||
*list = append(*list, dto.SmsRenewalLogResp{
|
*list = append(*list, dto.SmsRenewalLogResp{
|
||||||
Id: v.Id,
|
Id: v.Id,
|
||||||
UserId: v.UserId,
|
UserId: v.UserId,
|
||||||
Category: v.Category,
|
Category: v.Category,
|
||||||
Phone: v.Phone,
|
Phone: v.Phone,
|
||||||
Amount: v.Amount,
|
Amount: v.Amount,
|
||||||
BeforeTime: v.BeforeTime,
|
BeforeTime: v.BeforeTime,
|
||||||
Period: v.Period,
|
Period: v.Period,
|
||||||
CreatedAt: v.CreatedAt,
|
CreatedAt: v.CreatedAt,
|
||||||
UserName: v.Username,
|
UserName: v.Username,
|
||||||
|
TradeOrderNo: v.TradeOrderNo,
|
||||||
|
PayOrderNo: v.PayOrderNo,
|
||||||
|
Status: v.Status,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -127,3 +137,551 @@ func (e *SmsRenewalLog) Remove(d *dto.SmsRenewalLogDeleteReq, p *actions.DataPer
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 手动扣费
|
||||||
|
func (e *SmsRenewalLog) ManualDeduct(req *dto.ManualDeductReq, userId int) (dto.ManualDeductResp, int) {
|
||||||
|
var entity models.SmsPhone
|
||||||
|
var result dto.ManualDeductResp
|
||||||
|
phoneService := SmsPhone{}
|
||||||
|
phoneService.Orm = e.Orm
|
||||||
|
phoneService.Log = e.Log
|
||||||
|
|
||||||
|
if err := e.Orm.Model(&entity).
|
||||||
|
Where("activation_id =?", req.ActivationId).
|
||||||
|
First(&entity).Error; err != nil {
|
||||||
|
e.Log.Errorf("获取短信号码失败, %s", err)
|
||||||
|
return result, statuscode.SmsNotExisted
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取服务配置映射
|
||||||
|
serviceMap, premiumMap, err := phoneService.getRenewalConfigs()
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("获取短信服务配置失败, %s", err)
|
||||||
|
return result, statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
var count int64
|
||||||
|
|
||||||
|
if err := e.Orm.Model(&models.SmsRenewalLog{}).
|
||||||
|
Where("phone_id = ? AND status = 1", entity.Id).
|
||||||
|
Count(&count).Error; err != nil {
|
||||||
|
e.Log.Errorf("查询号码续费记录失败 [PhoneID: %d]: %v", entity.Id, err)
|
||||||
|
return result, statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
if count > 0 {
|
||||||
|
return result, statuscode.SmsRenewalLogExisted
|
||||||
|
}
|
||||||
|
|
||||||
|
if renewLog, err := e.processPhoneRenewal(entity, serviceMap, premiumMap, req.TradeOrderNo, false); err != nil {
|
||||||
|
e.Log.Errorf("处理号码续费失败 [PhoneID: %d 续费订单号:%s]: %v", entity.Id, renewLog.PayOrderNo, err)
|
||||||
|
return result, statuscode.ServerError
|
||||||
|
} else {
|
||||||
|
result.ActivationId = req.ActivationId
|
||||||
|
result.TradeOrderNo = renewLog.TradeOrderNo
|
||||||
|
result.PayOrderNo = renewLog.PayOrderNo
|
||||||
|
result.BeginTime = req.BeginTime
|
||||||
|
result.EndTime = renewLog.TargetTime
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, statuscode.Success
|
||||||
|
}
|
||||||
|
|
||||||
|
// 续期详情
|
||||||
|
func (e *SmsRenewalLog) GetRenewalDetailByTradeOrderNo(req *dto.ManualDeductDetailReq, userId int) (dto.ManualDeductResp, int) {
|
||||||
|
var entity models.SmsRenewalLog
|
||||||
|
result := dto.ManualDeductResp{}
|
||||||
|
|
||||||
|
if err := e.Orm.Model(entity).
|
||||||
|
Joins("LEFT JOIN sms_phone s on s.id = sms_renewal_log.phone_id").
|
||||||
|
Where("sms_renewal_log.trade_order_no =? and sms_renewal_log.user_id =?", req.TradeOrderNo, userId).
|
||||||
|
Select("sms_renewal_log.*, s.activation_id").
|
||||||
|
First(&entity).Error; err != nil {
|
||||||
|
e.Log.Errorf("获取续费记录失败, %s", err)
|
||||||
|
return result, statuscode.SmsNotExisted
|
||||||
|
}
|
||||||
|
|
||||||
|
result.ActivationId = entity.ActivationId
|
||||||
|
result.TradeOrderNo = entity.TradeOrderNo
|
||||||
|
result.PayOrderNo = entity.PayOrderNo
|
||||||
|
result.BeginTime = entity.BeforeTime
|
||||||
|
result.EndTime = entity.TargetTime
|
||||||
|
|
||||||
|
return result, statuscode.Success
|
||||||
|
}
|
||||||
|
|
||||||
|
// AutoRenewal 自动续期处理
|
||||||
|
// 处理即将到期的长期号码自动续费逻辑
|
||||||
|
func (e *SmsRenewalLog) AutoRenewal() error {
|
||||||
|
if err := e.JudgeRenewalLogStatus(); err != nil {
|
||||||
|
e.Log.Errorf("处理预扣费记录失败 %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取24小时内到期的自动续费号码
|
||||||
|
phoneService := SmsPhone{}
|
||||||
|
phoneService.Orm = e.Orm
|
||||||
|
phoneService.Log = e.Log
|
||||||
|
expiredPhones, err := e.getExpiredPhones()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取服务配置映射
|
||||||
|
serviceMap, premiumMap, err := phoneService.getRenewalConfigs()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理每个到期号码
|
||||||
|
for _, phone := range expiredPhones {
|
||||||
|
if renewLog, err := e.processPhoneRenewal(phone, serviceMap, premiumMap, "", false); err != nil {
|
||||||
|
e.Log.Errorf("处理号码续费失败 [PhoneID: %d 续费订单号:%s]: %v", phone.Id, renewLog.PayOrderNo, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 手动续费(处理到期号码)
|
||||||
|
func (e *SmsRenewalLog) ManualRenewal(activationIds []string) ([]string, error) {
|
||||||
|
if len(activationIds) == 0 {
|
||||||
|
return nil, errors.New("activationIds 不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
var errorIds []string
|
||||||
|
var expiredPhones []models.SmsPhone
|
||||||
|
phoneService := SmsPhone{}
|
||||||
|
phoneService.Orm = e.Orm
|
||||||
|
phoneService.Log = e.Log
|
||||||
|
// 查询所有到期号码
|
||||||
|
if err := e.Orm.Model(&models.SmsPhone{}).
|
||||||
|
Where("activation_id IN ? ", activationIds). //expire_time < ? time.Now()
|
||||||
|
Find(&expiredPhones).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取服务配置映射
|
||||||
|
serviceMap, premiumMap, err := phoneService.getRenewalConfigs()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理每个到期号码
|
||||||
|
for _, phone := range expiredPhones {
|
||||||
|
if renewLog, err := e.processPhoneRenewal(phone, serviceMap, premiumMap, "", true); err != nil {
|
||||||
|
e.Log.Errorf("处理号码续费失败 [PhoneID: %d 续费订单号:%s]: %v", phone.Id, renewLog.PayOrderNo, err)
|
||||||
|
errorIds = append(errorIds, fmt.Sprintf("处理号码续费失败 [PhoneID: %d]: %v", phone.Id, err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errorIds, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getExpiredPhones 获取即将到期的自动续费号码
|
||||||
|
func (e *SmsRenewalLog) getExpiredPhones() ([]models.SmsPhone, error) {
|
||||||
|
var phones []models.SmsPhone
|
||||||
|
startTime := time.Now().Add(-24 * time.Hour)
|
||||||
|
endTime := time.Now().Add(24 * time.Hour)
|
||||||
|
|
||||||
|
notExistsQuery := e.Orm.Model(&models.SmsRenewalLog{}).
|
||||||
|
Select("1").
|
||||||
|
Where("sms_renewal_log.phone_id = sms_phone.id AND sms_renewal_log.status in (1,2) AND status = 1")
|
||||||
|
|
||||||
|
err := e.Orm.Model(&models.SmsPhone{}).
|
||||||
|
Where("auto_renewal = 1 AND type = 1 AND actived = 2 AND expire_time >= ? AND expire_time < ?", startTime, endTime).
|
||||||
|
Where("NOT EXISTS (?)", notExistsQuery).
|
||||||
|
Find(&phones).Error
|
||||||
|
|
||||||
|
return phones, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取预扣除的记录
|
||||||
|
func (e *SmsRenewalLog) GetLockRenewalLogs() ([]models.SmsRenewalLog, error) {
|
||||||
|
var logs []models.SmsRenewalLog
|
||||||
|
err := e.Orm.Model(&models.SmsRenewalLog{}).
|
||||||
|
Joins("left join sms_phone s on s.id = sms_renewal_log.phone_id").
|
||||||
|
Where("sms_renewal_log.status = 1").
|
||||||
|
Select("sms_renewal_log.*, s.platform_code,s.api_key,s.billing_cycle_id").
|
||||||
|
Find(&logs).Error
|
||||||
|
return logs, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断续费是否成功
|
||||||
|
func (e *SmsRenewalLog) JudgeRenewalLogStatus() error {
|
||||||
|
logs, err := e.GetLockRenewalLogs()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
smsPlatformKeyRedis := NewSmsPlatformKeyRedis(e.Orm, e.Log)
|
||||||
|
textVerifiedService := SmsTextVerified{Service: e.Service}
|
||||||
|
|
||||||
|
for _, item := range logs {
|
||||||
|
switch item.PlatformCode {
|
||||||
|
case global.SmsPlatformTextVerified:
|
||||||
|
apiInfo, err := smsPlatformKeyRedis.GetApiInfo(item.PlatformCode, item.ApiKey)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("获取短信平台密钥失败 [PlatformCode: %s]: %v", item.PlatformCode, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cycleInfo, err := textVerifiedService.GetBillingCycle(item.BillingCycleId, &apiInfo)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("获取短信平台密钥失败 [PlatformCode: %s]: %v", item.PlatformCode, err)
|
||||||
|
|
||||||
|
if errors.Is(err, LogNotFund) {
|
||||||
|
if err := e.rollbackRenewalLog(item.Id); err != nil {
|
||||||
|
e.Log.Errorf("回滚续费记录失败 [RenewalLogID: %d]: %v", item.Id, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
startTime := item.BeforeTime.UTC().Truncate(24 * time.Hour)
|
||||||
|
endTime := cycleInfo.RenewedThrough.Truncate(24 * time.Hour)
|
||||||
|
// 续费成功
|
||||||
|
if startTime.Before(endTime) {
|
||||||
|
if err := e.confirmPayment(item.PhoneId, item.Id); err != nil {
|
||||||
|
e.Log.Errorf("更新续费记录状态失败 [RenewalLogID: %d]: %v", item.Id, err)
|
||||||
|
}
|
||||||
|
} else if item.BeforeTime.Before(time.Now()) {
|
||||||
|
if err := e.rollbackRenewalLog(item.Id); err != nil {
|
||||||
|
e.Log.Errorf("回滚续费记录失败 [RenewalLogID: %d]: %v", item.Id, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case global.SmsPlatformDaisysms:
|
||||||
|
//没有手动续费只能 在到期前直接扣费
|
||||||
|
timeDuration := time.Since(item.BeforeTime)
|
||||||
|
|
||||||
|
if timeDuration < 24*time.Hour {
|
||||||
|
if err := e.confirmPayment(item.PhoneId, item.Id); err != nil {
|
||||||
|
e.Log.Errorf("更新续费记录状态失败 [RenewalLogID: %d]: %v", item.Id, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
e.Log.Errorf("不支持的短信平台 %s 续费id:%d", item.PlatformCode, item.Id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getRenewalConfigs 获取续费相关配置
|
||||||
|
func (e *SmsPhone) getRenewalConfigs() (map[string]models.SmsServices, map[string]dto.GetSysConfigByKEYForServiceResp, error) {
|
||||||
|
smsServices := SmsServices{Service: e.Service}
|
||||||
|
serviceMap := smsServices.GetMapAll()
|
||||||
|
|
||||||
|
configService := SysConfig{Service: e.Service}
|
||||||
|
configKeys := []string{"renew_number_premium_daisysms", "renew_number_premium_textverified"}
|
||||||
|
premiumMap, err := configService.GetMapByKeys(configKeys)
|
||||||
|
|
||||||
|
return serviceMap, premiumMap, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// processPhoneRenewal 处理单个号码的续费
|
||||||
|
// tradeOrderNo 交易订单号
|
||||||
|
func (e *SmsRenewalLog) processPhoneRenewal(phone models.SmsPhone, serviceMap map[string]models.SmsServices,
|
||||||
|
premiumMap map[string]dto.GetSysConfigByKEYForServiceResp, tradeOrderNo string, admin bool) (models.SmsRenewalLog, error) {
|
||||||
|
var renewLog models.SmsRenewalLog
|
||||||
|
smsPlatformKeyRedis := NewSmsPlatformKeyRedis(e.Orm, e.Log)
|
||||||
|
apiInfo, err := smsPlatformKeyRedis.GetApiInfo(phone.PlatformCode, phone.ApiKey)
|
||||||
|
if err != nil {
|
||||||
|
return renewLog, fmt.Errorf("获取短信平台密钥失败 [PlatformCode: %s]: %v", phone.PlatformCode, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
//续期id为空 重新获取
|
||||||
|
if phone.BillingCycleId == "" {
|
||||||
|
switch phone.PlatformCode {
|
||||||
|
case global.SmsPlatformTextVerified:
|
||||||
|
//可以手动续费
|
||||||
|
textVerifiedService := SmsTextVerified{Service: e.Service}
|
||||||
|
detail, code := textVerifiedService.GetRentalDetail(phone.ActivationId, &apiInfo)
|
||||||
|
|
||||||
|
if code != statuscode.Success {
|
||||||
|
logger.Errorf("获取短信验证码续费详情失败 [ActivationID: %s]: %v", phone.ActivationId, code)
|
||||||
|
return renewLog, fmt.Errorf("获取短信验证码续费详情失败 [ActivationID: %s]: %v", phone.ActivationId, code)
|
||||||
|
}
|
||||||
|
|
||||||
|
phone.BillingCycleId = detail.BillingCycleId
|
||||||
|
case global.SmsPlatformDaisysms:
|
||||||
|
//只有自动续费的 用定时服务查询状态
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取服务价格
|
||||||
|
service, exists := serviceMap[phone.PlatformCode+"_"+phone.ServiceCode]
|
||||||
|
if !exists {
|
||||||
|
return renewLog, errors.New("服务不存在")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算续费价格
|
||||||
|
renewalPrice := e.calculateRenewalPrice(service.LongPrice, phone.PlatformCode, premiumMap)
|
||||||
|
if renewalPrice.IsZero() {
|
||||||
|
return renewLog, errors.New("续费价格计算失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建续费日志
|
||||||
|
renewLog = e.createRenewalLog(phone, renewalPrice, tradeOrderNo)
|
||||||
|
|
||||||
|
// 执行续费事务
|
||||||
|
if err := e.executeRenewalTransaction(phone, renewalPrice, &renewLog, &apiInfo, admin); err != nil {
|
||||||
|
return renewLog, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return renewLog, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculateRenewalPrice 计算续费价格
|
||||||
|
func (e *SmsRenewalLog) calculateRenewalPrice(basePrice decimal.Decimal, platformCode string, premiumMap map[string]dto.GetSysConfigByKEYForServiceResp) decimal.Decimal {
|
||||||
|
percent := decimal.NewFromInt(1)
|
||||||
|
|
||||||
|
var configKey string
|
||||||
|
switch platformCode {
|
||||||
|
case global.SmsPlatformDaisysms:
|
||||||
|
configKey = "renew_number_premium_daisysms"
|
||||||
|
case global.SmsPlatformTextVerified:
|
||||||
|
configKey = "renew_number_premium_textverified"
|
||||||
|
default:
|
||||||
|
return basePrice
|
||||||
|
}
|
||||||
|
|
||||||
|
if config, exists := premiumMap[configKey]; exists {
|
||||||
|
if val, err := decimal.NewFromString(config.ConfigValue); err == nil && val.Cmp(decimal.Zero) > 0 {
|
||||||
|
percent = decimal.NewFromInt(100).Add(val).Div(decimal.NewFromInt(100))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return basePrice.Mul(percent).Truncate(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// createRenewalLog 创建续费日志
|
||||||
|
// tradeOrderNo 交易订单号
|
||||||
|
func (e *SmsRenewalLog) createRenewalLog(phone models.SmsPhone, amount decimal.Decimal, tradeOrderNo string) models.SmsRenewalLog {
|
||||||
|
targetTime := phone.ExpireTime.AddDate(0, 0, 30)
|
||||||
|
|
||||||
|
return models.SmsRenewalLog{
|
||||||
|
UserId: phone.UserId,
|
||||||
|
TradeOrderNo: tradeOrderNo,
|
||||||
|
PayOrderNo: utility.GenerateTraceID(),
|
||||||
|
Phone: phone.Phone,
|
||||||
|
Category: 2,
|
||||||
|
PhoneId: phone.Id,
|
||||||
|
Type: phone.Type,
|
||||||
|
Amount: amount,
|
||||||
|
BeforeTime: *phone.ExpireTime,
|
||||||
|
TargetTime: &targetTime,
|
||||||
|
Period: 30,
|
||||||
|
Status: 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// executeRenewalTransaction 执行续费事务
|
||||||
|
func (e *SmsRenewalLog) executeRenewalTransaction(phone models.SmsPhone, price decimal.Decimal,
|
||||||
|
renewLog *models.SmsRenewalLog, apiInfo *dto.SmsPlatformKeyQueueDto, isAdmin bool) error {
|
||||||
|
err := e.Orm.Transaction(func(tx *gorm.DB) error {
|
||||||
|
// 扣除余额
|
||||||
|
result := tx.Exec("UPDATE member_balance SET balance = balance - ? WHERE user_id = ? AND balance >= ?", price, phone.UserId, price)
|
||||||
|
if result.Error != nil {
|
||||||
|
return result.Error
|
||||||
|
}
|
||||||
|
if result.RowsAffected == 0 {
|
||||||
|
return errors.New("余额不足")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建续费日志
|
||||||
|
if err := tx.Create(renewLog).Error; err != nil {
|
||||||
|
return errors.New("创建续费日志失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil && err.Error() == "余额不足" && phone.ExpireTime.Before(time.Now()) {
|
||||||
|
return e.handleInsufficientBalance(phone)
|
||||||
|
}
|
||||||
|
|
||||||
|
//是否是管理员处理
|
||||||
|
if isAdmin {
|
||||||
|
if err1 := e.confirmPayment(phone.Id, renewLog.Id); err1 != nil {
|
||||||
|
logger.Errorf("确认扣款失败 [PhoneID: %d, RenewalLogID: %d]: %v", phone.Id, renewLog.Id, err1)
|
||||||
|
return err1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch phone.PlatformCode {
|
||||||
|
case global.SmsPlatformTextVerified:
|
||||||
|
//可以手动续费
|
||||||
|
textVerifiedService := SmsTextVerified{Service: e.Service}
|
||||||
|
|
||||||
|
code := textVerifiedService.ManualRenewal(phone.BillingCycleId, apiInfo)
|
||||||
|
|
||||||
|
// 没有需要续费的号码 重新设置可自动续费之后再试一次
|
||||||
|
if code == statuscode.NothingToRenew {
|
||||||
|
if renewCode := textVerifiedService.Renew(phone.ActivationId, true, apiInfo); renewCode == statuscode.Success {
|
||||||
|
code = textVerifiedService.ManualRenewal(phone.BillingCycleId, apiInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if code == statuscode.Success {
|
||||||
|
if err1 := e.confirmPayment(phone.Id, renewLog.Id); err1 != nil {
|
||||||
|
logger.Errorf("确认扣款失败 [PhoneID: %d, RenewalLogID: %d]: %v", phone.Id, renewLog.Id, err1)
|
||||||
|
return err1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err1 := e.rollbackRenewalLog(renewLog.Id); err1 != nil {
|
||||||
|
logger.Errorf("回滚续费日志状态失败,续费日志ID: %d, 错误: %v", renewLog.Id, err1)
|
||||||
|
return err1
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("手动续费失败 [BillingCycleID: %s]: %v", phone.BillingCycleId, code)
|
||||||
|
}
|
||||||
|
case global.SmsPlatformDaisysms:
|
||||||
|
//只有自动续费的 用定时服务查询状态
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确认扣款成功
|
||||||
|
func (e *SmsRenewalLog) confirmPayment(phoneId int, renewalLogId int) error {
|
||||||
|
var renewLog models.SmsRenewalLog
|
||||||
|
if err := e.Orm.Where("id = ?", renewalLogId).First(&renewLog).Error; err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
// 事务ID不存在:这是致命错误,平台A必须有此记录才能Confirm
|
||||||
|
e.Log.Errorf("Confirm失败: 找不到续费记录ID %s 的续费日志", renewalLogId)
|
||||||
|
return errors.New("事务记录不存在,无法确认支付")
|
||||||
|
}
|
||||||
|
return fmt.Errorf("查询续费日志失败: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查幂等性
|
||||||
|
if renewLog.Status == 2 { // 状态 2: 扣费成功
|
||||||
|
// 幂等性成功:已经被 Confirm 过了,直接返回成功,不需重复操作
|
||||||
|
e.Log.Warnf("Confirm重复调用: 续费ID %s 已是成功状态", renewalLogId)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 流程错误检查:不能对已取消或失败的事务执行 Confirm
|
||||||
|
if renewLog.Status != 1 { // 状态 1: 预扣中/冻结
|
||||||
|
// 理论上不该发生。说明平台 B 的调用时序错误。
|
||||||
|
e.Log.Errorf("Confirm失败: 续费ID %s 状态为 %d,无法执行确认支付", renewalLogId, renewLog.Status)
|
||||||
|
return errors.New("事务状态不正确,无法确认支付")
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.Orm.Transaction(func(tx *gorm.DB) error {
|
||||||
|
|
||||||
|
// 1. 查找并更新续费日志状态 (状态 2: 扣费成功)
|
||||||
|
result := tx.Model(&models.SmsRenewalLog{}).
|
||||||
|
Where("id = ? AND status = ?", renewalLogId, 1). // 必须是预扣中状态
|
||||||
|
Update("status", 2)
|
||||||
|
|
||||||
|
if result.RowsAffected == 0 {
|
||||||
|
return errors.New("续费日志状态不正确或已处理")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. **更新到期时间** (只有在 Confirm 阶段才能更新)
|
||||||
|
var phone models.SmsPhone
|
||||||
|
if err := tx.Model(&models.SmsPhone{}).Where("id = ?", phoneId).First(&phone).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var targetTime time.Time
|
||||||
|
if renewLog.TargetTime != nil {
|
||||||
|
targetTime = *renewLog.TargetTime
|
||||||
|
} else {
|
||||||
|
targetTime = phone.ExpireTime.AddDate(0, 0, 30)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tx.Model(&phone).Update("expire_time", targetTime).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil // TCC Confirm 成功
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// rollbackRenewalLog 回滚续费日志状态
|
||||||
|
func (e *SmsRenewalLog) rollbackRenewalLog(renewLogId int) error {
|
||||||
|
var renewLog models.SmsRenewalLog
|
||||||
|
if err := e.Orm.Where("id = ?", renewLogId).First(&renewLog).Error; err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
e.Log.Errorf("回滚失败: 找不到续费记录ID %d", renewLogId)
|
||||||
|
return errors.New("事务记录不存在,无法回滚")
|
||||||
|
}
|
||||||
|
return fmt.Errorf("查询续费日志失败: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 幂等性检查:如果已经处于回滚状态,直接返回成功
|
||||||
|
if renewLog.Status == 3 {
|
||||||
|
e.Log.Warnf("回滚重复调用: 续费ID %d 已是回滚状态 (Status=3)", renewLogId)
|
||||||
|
return nil // 幂等性成功
|
||||||
|
}
|
||||||
|
|
||||||
|
// 流程检查:如果已经是成功扣费状态,不能执行普通回滚
|
||||||
|
if renewLog.Status == 2 {
|
||||||
|
e.Log.Errorf("回滚失败: 续费ID %d 已是成功扣费状态 (Status=2)", renewLogId)
|
||||||
|
return errors.New("事务已确认支付,无法执行取消回滚")
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.Orm.Transaction(func(tx *gorm.DB) error {
|
||||||
|
// 1. 更新续费日志状态 (状态 1: 预扣中/冻结)
|
||||||
|
result := tx.Model(&models.SmsRenewalLog{}).
|
||||||
|
Where("id = ? AND status = ?", renewLogId, 1). // 必须是扣费成功状态
|
||||||
|
Update("status", 3)
|
||||||
|
if result.Error != nil {
|
||||||
|
logger.Errorf("回滚续费日志状态失败,续费日志ID: %d, 错误: %v", renewLogId, result.Error)
|
||||||
|
return result.Error
|
||||||
|
}
|
||||||
|
if result.RowsAffected == 0 {
|
||||||
|
logger.Errorf("回滚续费日志状态失败,续费日志ID: %d", renewLogId)
|
||||||
|
return errors.New("续费日志状态不正确或已处理")
|
||||||
|
}
|
||||||
|
|
||||||
|
result = tx.Exec("UPDATE member_balance SET balance = balance + ? WHERE user_id = ? ", renewLog.Amount, renewLog.UserId)
|
||||||
|
if result.Error != nil {
|
||||||
|
logger.Errorf("回滚续费日志状态失败,续费日志ID: %d, 错误: %v", renewLogId, result.Error)
|
||||||
|
return result.Error
|
||||||
|
}
|
||||||
|
if result.RowsAffected == 0 {
|
||||||
|
return errors.New("余额不足")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleInsufficientBalance 处理余额不足情况
|
||||||
|
func (e *SmsRenewalLog) handleInsufficientBalance(phone models.SmsPhone) error {
|
||||||
|
params := map[string]interface{}{
|
||||||
|
"auto_renewal": 2,
|
||||||
|
"remark": "余额不足,取消自动续费",
|
||||||
|
}
|
||||||
|
// 取消自动续费
|
||||||
|
if err := e.Orm.Model(&models.SmsPhone{}).
|
||||||
|
Where("id = ?", phone.Id).
|
||||||
|
Updates(params).Error; err != nil {
|
||||||
|
e.Log.Errorf("余额不足,取消自动续费失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
phoneService := SmsPhone{}
|
||||||
|
phoneService.Orm = e.Orm
|
||||||
|
phoneService.Log = e.Log
|
||||||
|
// 调用平台取消续费接口
|
||||||
|
code := phoneService.ChangeAutoRenewManage(phone.PlatformCode, phone.ApiKey, phone.ActivationId, false)
|
||||||
|
if code != statuscode.Success {
|
||||||
|
params["auto_renewal"] = 1
|
||||||
|
params["remark"] = ""
|
||||||
|
// 如果平台取消失败,恢复自动续费状态
|
||||||
|
if err := e.Orm.Model(&models.SmsPhone{}).
|
||||||
|
Where("id = ?", phone.Id).
|
||||||
|
Updates(params).Error; err != nil {
|
||||||
|
e.Log.Errorf("恢复自动续费状态失败: %v", err)
|
||||||
|
}
|
||||||
|
e.Log.Errorf("平台取消自动续费失败,状态码: %d", code)
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors.New("余额不足")
|
||||||
|
}
|
||||||
|
|||||||
@ -29,6 +29,32 @@ type SmsTextVerified struct {
|
|||||||
service.Service
|
service.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 错误
|
||||||
|
var (
|
||||||
|
LogNotFund = errors.New("记录不存在")
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
loginUrl = "/api/pub/v2/auth"
|
||||||
|
getAreas = "/api/pub/v2/area-codes"
|
||||||
|
getServices = "/api/pub/v2/services"
|
||||||
|
createRental = "/api/pub/v2/reservations/rental" //长效收码
|
||||||
|
createVerification = "/api/pub/v2/verifications" //单次收码
|
||||||
|
cancelVerification = "/api/pub/v2/verifications/%s/cancel" //取消收码
|
||||||
|
cancelRental = "/api/pub/v2/reservations/rental/renewable/%s/refund" //取消长效号码
|
||||||
|
wakeUp = "/api/pub/v2/wake-requests" //唤醒号码
|
||||||
|
rentalPrice = "/api/pub/v2/pricing/rentals" //长效收码价格
|
||||||
|
verificationPrice = "/api/pub/v2/pricing/verifications" //单次收码价格
|
||||||
|
rentalDetail = "/api/pub/v2/reservations/rental/renewable/%s" //长效号码详情
|
||||||
|
renewRental = "/api/pub/v2/reservations/rental/renewable/%s/renew" //长效续期
|
||||||
|
updateRentalRenewStatus = "/api/pub/v2/reservations/rental/renewable/%s" // 更改续租状态
|
||||||
|
getSmsCode = "/api/pub/v2/sms?reservationId=%s&reservationType=%s" //获取短信验证码
|
||||||
|
getNumbers = "/api/pub/v2/reservations/rental/renewable" //获取长效号码列表 Get
|
||||||
|
manualRenewal = "/api/pub/v2/billing-cycles/%s/renew" //手动续期 POST
|
||||||
|
getBillingCycles = "/api/pub/v2/billing-cycles/%s" //获取计费周期详情 GET
|
||||||
|
rentalList = "/api/pub/v2/reservations/rental/renewable" //长效号码列表
|
||||||
|
)
|
||||||
|
|
||||||
// 获取收到的验证码
|
// 获取收到的验证码
|
||||||
// messageId 短效或长效号码的ID
|
// messageId 短效或长效号码的ID
|
||||||
// typ 0-短效 1-长效
|
// typ 0-短效 1-长效
|
||||||
@ -143,24 +169,6 @@ func (e SmsTextVerified) GetCode(messageId string, typ int, userId int, service,
|
|||||||
return parsedCode, http.StatusOK
|
return parsedCode, http.StatusOK
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
loginUrl = "/api/pub/v2/auth"
|
|
||||||
getAreas = "/api/pub/v2/area-codes"
|
|
||||||
getServices = "/api/pub/v2/services"
|
|
||||||
createRental = "/api/pub/v2/reservations/rental" //长效收码
|
|
||||||
createVerification = "/api/pub/v2/verifications" //单次收码
|
|
||||||
cancelVerification = "/api/pub/v2/verifications/%s/cancel" //取消收码
|
|
||||||
cancelRental = "/api/pub/v2/reservations/rental/renewable/%s/refund" //取消长效号码
|
|
||||||
wakeUp = "/api/pub/v2/wake-requests" //唤醒号码
|
|
||||||
rentalPrice = "/api/pub/v2/pricing/rentals" //长效收码价格
|
|
||||||
verificationPrice = "/api/pub/v2/pricing/verifications" //单次收码价格
|
|
||||||
rentalDetail = "/api/pub/v2/reservations/rental/renewable/%s" //长效号码详情
|
|
||||||
renewRental = "/api/pub/v2/reservations/rental/renewable/%s/renew" //长效续期
|
|
||||||
updateRentalRenewStatus = "/api/pub/v2/reservations/rental/renewable/%s" // 更改续租状态
|
|
||||||
getSmsCode = "/api/pub/v2/sms?reservationId=%s&reservationType=%s" //获取短信验证码
|
|
||||||
getNumbers = "/api/pub/v2/reservations/rental/renewable" //获取长效号码列表 Get
|
|
||||||
)
|
|
||||||
|
|
||||||
var idPattern = regexp.MustCompile(`^[a-zA-Z0-9_]{28}$`)
|
var idPattern = regexp.MustCompile(`^[a-zA-Z0-9_]{28}$`)
|
||||||
|
|
||||||
// 获取授权失败
|
// 获取授权失败
|
||||||
@ -469,6 +477,7 @@ func (e *SmsTextVerified) GetNumberForApi(typ int, serviceCode string, price dec
|
|||||||
}
|
}
|
||||||
|
|
||||||
result.Phone = "1" + detail.Number
|
result.Phone = "1" + detail.Number
|
||||||
|
result.BillingCycleId = detail.BillingCycleId
|
||||||
endTime := resp.UpdatedAt.AddDate(0, 0, 30)
|
endTime := resp.UpdatedAt.AddDate(0, 0, 30)
|
||||||
result.EndAt = &(endTime) // 30天后过期
|
result.EndAt = &(endTime) // 30天后过期
|
||||||
|
|
||||||
@ -940,6 +949,41 @@ func (e *SmsTextVerified) Renew(activationId string, status bool, apiInfo *dto.S
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 手动续期
|
||||||
|
// 续费id
|
||||||
|
func (e *SmsTextVerified) ManualRenewal(bilingCycleId string, apiInfo *dto.SmsPlatformKeyQueueDto) int {
|
||||||
|
url := fmt.Sprintf(manualRenewal, bilingCycleId)
|
||||||
|
|
||||||
|
client, code := e.GetTextVerifiedAuthClient(apiInfo)
|
||||||
|
|
||||||
|
if code != statuscode.Success {
|
||||||
|
e.Log.Errorf("获取长效续期失败 %d", code)
|
||||||
|
return statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
headers := map[string]string{
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
mapData := dto.TextVerifiedManualRenewalResp{}
|
||||||
|
statuCode, err := client.Post(url, nil, headers, &mapData)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("修改长效续期状态失败 %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if statuCode >= 200 && statuCode < 300 {
|
||||||
|
return statuscode.Success
|
||||||
|
} else {
|
||||||
|
e.Log.Errorf("修改长效续期状态失败 %d", statuCode)
|
||||||
|
// 没有需要续费的号码 重新设置可自动续费之后再试一次
|
||||||
|
if statuCode == 400 && strings.Contains(err.Error(), "Nothing to renew") {
|
||||||
|
return statuscode.NothingToRenew
|
||||||
|
}
|
||||||
|
|
||||||
|
return statuscode.ServerError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 重新初始化短信记录
|
// 重新初始化短信记录
|
||||||
func (e *SmsTextVerified) InitSmsLogs() error {
|
func (e *SmsTextVerified) InitSmsLogs() error {
|
||||||
// 获取平台密钥信息
|
// 获取平台密钥信息
|
||||||
@ -1124,3 +1168,70 @@ func getIdByUrl(URLString string) string {
|
|||||||
func isValidID(s string) bool {
|
func isValidID(s string) bool {
|
||||||
return idPattern.MatchString(s)
|
return idPattern.MatchString(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取长效租赁号码列表
|
||||||
|
// next 分页url
|
||||||
|
func (e *SmsTextVerified) GetRentalList(next string, apiInfo *dto.SmsPlatformKeyQueueDto) (dto.TextVerifiedGetRentalListResp, error) {
|
||||||
|
var result dto.TextVerifiedGetRentalListResp
|
||||||
|
|
||||||
|
client, code := e.GetTextVerifiedAuthClient(apiInfo)
|
||||||
|
if code != statuscode.Success {
|
||||||
|
e.Log.Errorf("获取长效号码列表失败 %d", code)
|
||||||
|
return result, fmt.Errorf("获取长效号码列表失败 %d", code)
|
||||||
|
}
|
||||||
|
|
||||||
|
if next == "" {
|
||||||
|
next = rentalList
|
||||||
|
} else {
|
||||||
|
client.BaseURL = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := dto.TextVerifiedGetRentalListResp{}
|
||||||
|
statusCode, err := client.Get(next, map[string]string{}, &resp)
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("获取长效号码列表失败 %v", err)
|
||||||
|
return result, fmt.Errorf("获取长效号码列表失败 %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if statusCode == http.StatusOK {
|
||||||
|
result = resp
|
||||||
|
return result, nil
|
||||||
|
} else if statusCode == http.StatusUnauthorized {
|
||||||
|
return e.GetRentalList(next, apiInfo)
|
||||||
|
} else {
|
||||||
|
e.Log.Errorf("获取长效号码列表失败 %d", statusCode)
|
||||||
|
return result, fmt.Errorf("获取长效号码列表失败 %d", statusCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取续费周期详情
|
||||||
|
func (e *SmsTextVerified) GetBillingCycle(billingCycleId string, apiInfo *dto.SmsPlatformKeyQueueDto) (dto.TextVerifiedGetBillingCycleResp, error) {
|
||||||
|
var result dto.TextVerifiedGetBillingCycleResp
|
||||||
|
|
||||||
|
client, code := e.GetTextVerifiedAuthClient(apiInfo)
|
||||||
|
if code != statuscode.Success {
|
||||||
|
e.Log.Errorf("获取计费周期详情失败 %d", code)
|
||||||
|
return result, fmt.Errorf("获取计费周期详情失败 %d", code)
|
||||||
|
}
|
||||||
|
|
||||||
|
next := fmt.Sprintf(getBillingCycles, billingCycleId)
|
||||||
|
|
||||||
|
resp := dto.TextVerifiedGetBillingCycleResp{}
|
||||||
|
statusCode, err := client.Get(next, map[string]string{}, &resp)
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("获取计费周期详情失败 %v", err)
|
||||||
|
return result, fmt.Errorf("获取计费周期详情失败 %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if statusCode >= http.StatusOK && statusCode < http.StatusMultipleChoices {
|
||||||
|
result = resp
|
||||||
|
return result, nil
|
||||||
|
} else if statusCode == http.StatusUnauthorized {
|
||||||
|
return e.GetBillingCycle(billingCycleId, apiInfo)
|
||||||
|
} else if statusCode == http.StatusNotFound {
|
||||||
|
return result, LogNotFund
|
||||||
|
} else {
|
||||||
|
e.Log.Errorf("获取计费周期详情失败 %d", statusCode)
|
||||||
|
return result, fmt.Errorf("获取计费周期详情失败 %d", statusCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -37,7 +37,7 @@ func (j RenewalJob) Exec(args interface{}) error {
|
|||||||
|
|
||||||
// 定时短信续期任务
|
// 定时短信续期任务
|
||||||
func (j SmsRenewalJob) Exec(args interface{}) error {
|
func (j SmsRenewalJob) Exec(args interface{}) error {
|
||||||
smsPhoneService := service.SmsPhone{}
|
smsPhoneService := service.SmsRenewalLog{}
|
||||||
smsPhoneService.Orm = GetDb()
|
smsPhoneService.Orm = GetDb()
|
||||||
smsPhoneService.Log = logger.NewHelper(logger.DefaultLogger)
|
smsPhoneService.Log = logger.NewHelper(logger.DefaultLogger)
|
||||||
|
|
||||||
|
|||||||
@ -23,7 +23,7 @@ func TestTrxJob(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func initSetting() {
|
func initSetting() {
|
||||||
dsn := "root:123456@tcp(127.0.0.1:3306)/proxy_server?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms"
|
dsn := "root:123456@tcp(127.0.0.1:3306)/proxy_server_prod?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms"
|
||||||
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||||
sdk.Runtime.SetDb("default", db)
|
sdk.Runtime.SetDb("default", db)
|
||||||
config.ExtConfig.TrxGridUrl = "https://api.trongrid.io"
|
config.ExtConfig.TrxGridUrl = "https://api.trongrid.io"
|
||||||
|
|||||||
@ -42,6 +42,7 @@ var StatusCodeZh = map[int]string{
|
|||||||
SmsOutOfStockOrUnavailable: "短信验证码_缺货或服务不可用",
|
SmsOutOfStockOrUnavailable: "短信验证码_缺货或服务不可用",
|
||||||
SmsRentalRefundNotPermitted: "短信验证码_租赁退款不允许",
|
SmsRentalRefundNotPermitted: "短信验证码_租赁退款不允许",
|
||||||
SmsRentalCantRenew: "短信验证码_无法续期",
|
SmsRentalCantRenew: "短信验证码_无法续期",
|
||||||
|
SmsRenewalLogExisted: "短信验证码_重复续期",
|
||||||
}
|
}
|
||||||
|
|
||||||
var StatusCodeEn = map[int]string{
|
var StatusCodeEn = map[int]string{
|
||||||
@ -76,6 +77,7 @@ var StatusCodeEn = map[int]string{
|
|||||||
SmsOutOfStockOrUnavailable: "sms out of stock or unavailable",
|
SmsOutOfStockOrUnavailable: "sms out of stock or unavailable",
|
||||||
SmsRentalRefundNotPermitted: "sms rental refund not permitted",
|
SmsRentalRefundNotPermitted: "sms rental refund not permitted",
|
||||||
SmsRentalCantRenew: "sms rental can not renewal",
|
SmsRentalCantRenew: "sms rental can not renewal",
|
||||||
|
SmsRenewalLogExisted: "sms renewal log existed",
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMsg 获取状态码对应的消息
|
// GetMsg 获取状态码对应的消息
|
||||||
@ -109,7 +111,8 @@ const (
|
|||||||
AccountOrPasswordError = 10003
|
AccountOrPasswordError = 10003
|
||||||
//密码不一致
|
//密码不一致
|
||||||
PassWordNotMatch = 10004
|
PassWordNotMatch = 10004
|
||||||
|
// 没有需要续费的号码 重新设置可自动续费之后再试一次
|
||||||
|
NothingToRenew = 11005
|
||||||
//
|
//
|
||||||
ServerError = 500
|
ServerError = 500
|
||||||
|
|
||||||
@ -165,4 +168,6 @@ const (
|
|||||||
SmsRentalRefundNotPermitted = 20025
|
SmsRentalRefundNotPermitted = 20025
|
||||||
// 短信-无法续期
|
// 短信-无法续期
|
||||||
SmsRentalCantRenew = 20026
|
SmsRentalCantRenew = 20026
|
||||||
|
// 短信-重复续期
|
||||||
|
SmsRenewalLogExisted = 20028
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user