1增加接码过期时间
This commit is contained in:
		| @ -23,9 +23,13 @@ type SmsPhone struct { | ||||
| 	Code            string          `json:"code" gorm:"type:varchar(10);comment:验证码"` | ||||
| 	Status          int             `json:"status" gorm:"type:tinyint;comment:状态 1-等待验证码 2-已获取"` | ||||
| 	ExpireTime      *time.Time      `json:"expireTime" gorm:"type:datetime;comment:过期时间"` | ||||
| 	StartTime       *time.Time      `json:"startTime" gorm:"type:datetime;comment:开始时间"` | ||||
| 	EndTime         *time.Time      `json:"endTime" gorm:"type:datetime;comment:结束时间 单次接码结束时间"` | ||||
| 	Actived         int             `json:"actived" gorm:"type:tinyint;comment:是否激活(长期租赁如果第一次没接收到验证码 则不会激活号码) 1-未激活 2-已激活 3-已失效"` | ||||
| 	Price           decimal.Decimal `json:"price" gorm:"type:decimal(10,2);comment:价格"` | ||||
| 	AutoRenewal     int             `json:"autoRenewal" gorm:"type:tinyint;comment:是否自动续费 1-自动续费 2-手动续费"` | ||||
| 	Remark          string          `json:"remark" gorm:"type:varchar(255);comment:备注"` | ||||
| 	PlatformName    string          `json:"platformName" gorm:"-"` | ||||
| 	models.ModelTime | ||||
| 	models.ControlBy | ||||
| } | ||||
|  | ||||
| @ -10,7 +10,7 @@ type SmsReceiveLog struct { | ||||
| 	UserId      int    `json:"userId" gorm:"type:bigint;comment:用户id"` | ||||
| 	Service     string `json:"service" gorm:"type:varchar(30);comment:服务"` | ||||
| 	ServiceCode string `json:"serviceCode" gorm:"type:varchar(30);comment:服务code"` | ||||
| 	MessageId   int    `json:"messageId" gorm:"type:int;comment:短信id"` | ||||
| 	MessageId   string `json:"messageId" gorm:"type:int;comment:短信id"` | ||||
| 	Phone       string `json:"phone" gorm:"type:varchar(30);comment:号码"` | ||||
| 	Code        string `json:"code" gorm:"type:varchar(20);comment:验证码"` | ||||
| 	Status      int    `json:"status" gorm:"type:tinyint;comment:状态 0-等待验证码 1-成功 2-失败"` | ||||
|  | ||||
| @ -150,8 +150,10 @@ type WeakUpReq struct { | ||||
| } | ||||
|  | ||||
| type WeakUpResp struct { | ||||
| 	ActivationId string `json:"activationId" comment:"激活id"` | ||||
| 	MessageId    string `json:"messageId" commment:"消息id"` | ||||
| 	ActivationId string     `json:"activationId" comment:"激活id"` | ||||
| 	MessageId    string     `json:"messageId" commment:"消息id"` | ||||
| 	StartTime    *time.Time `json:"startTime" comment:"接码开始时间"` | ||||
| 	EndTime      *time.Time `json:"endTime" comment:"接码过期时间"` | ||||
| } | ||||
|  | ||||
| func (s *WeakUpReq) Validate() error { | ||||
| @ -190,9 +192,12 @@ type SmsPhoneCleanMyPhoneReq struct { | ||||
| } | ||||
|  | ||||
| type SmsPhoneGetPhoneResp struct { | ||||
| 	Phone string     `json:"phone"` | ||||
| 	EndAt *time.Time `json:"endTime"` | ||||
| 	Id    string     `json:"id"` | ||||
| 	Phone     string     `json:"phone"` | ||||
| 	EndAt     *time.Time `json:"endTime"` | ||||
| 	StartTime *time.Time `json:"-" comment:"唤醒后单次接码开始时间"` | ||||
| 	EndTime   *time.Time `json:"-" comment:"唤醒后单次接码过期时间"` | ||||
| 	MessageId string     `json:"-" comment:"消息id"` | ||||
| 	Id        string     `json:"id"` | ||||
| } | ||||
|  | ||||
| type DaisysmsPriceResp struct { | ||||
| @ -208,6 +213,8 @@ type OpenGetNumberResp struct { | ||||
| 	Number       string          `json:"number"` | ||||
| 	ActivationId string          `json:"activationId"` | ||||
| 	ExpireTime   *time.Time      `json:"expireTime"` | ||||
| 	StartTime    *time.Time      `json:"startTime"` | ||||
| 	EndTime      *time.Time      `json:"endTime"` | ||||
| } | ||||
|  | ||||
| type OpenWakeUpReq struct { | ||||
|  | ||||
| @ -212,3 +212,13 @@ type TextVerifiedSmsItemResp struct { | ||||
| 	ParsedCode string `json:"parsedCode"` | ||||
| 	Encrypted  bool   `json:"encrypted"` | ||||
| } | ||||
|  | ||||
| type TextVerifiedGetNumbersResp struct { | ||||
| 	HasNext bool                            `json:"hasNext" comment:"是否有下一页"` | ||||
| 	Links   TextVerifiedGetNumbersLinksResp `json:"links"` | ||||
| 	Data    []VerificationDTO               `json:"data"` | ||||
| } | ||||
|  | ||||
| type TextVerifiedGetNumbersLinksResp struct { | ||||
| 	Next *TextVerifiedResp `json:"next"` | ||||
| } | ||||
|  | ||||
| @ -115,7 +115,7 @@ func (e MemberRecharge) CustomRecharge(req *dto.MemberRechargeCustomRechargeReq, | ||||
| 		return errors.New("server error") | ||||
| 	} | ||||
|  | ||||
| 	cacheExpireDuration := time.Duration(orderExpireTime+1) * time.Minute | ||||
| 	cacheExpireDuration := time.Duration(orderExpireTime+10) * time.Minute | ||||
| 	key := fmt.Sprintf("pre_order:%s", amount) | ||||
| 	err = e.Orm.Transaction(func(tx *gorm.DB) error { | ||||
| 		if err1 := tx.Create(&data).Error; err1 != nil { | ||||
|  | ||||
| @ -36,6 +36,8 @@ func (e SmsPhone) OpenGetNumber(req *dto.GetNumberReq, userId int) (dto.OpenGetN | ||||
| 	resp.ActivationId = smsPhone.NewActivationId | ||||
| 	resp.ExpireTime = smsPhone.ExpireTime | ||||
| 	resp.Number = smsPhone.Phone | ||||
| 	resp.StartTime = smsPhone.StartTime | ||||
| 	resp.EndTime = smsPhone.EndTime | ||||
|  | ||||
| 	return resp, statuscode.Success | ||||
| } | ||||
| @ -64,7 +66,7 @@ func (e *SmsPhone) CancelNumber(req *dto.SmsPhoneCancelNumberReq, userId int) in | ||||
|  | ||||
| 		if code == statuscode.Success { | ||||
| 			err := e.Orm.Transaction(func(tx *gorm.DB) error { | ||||
| 				if err1 := e.Orm.Model(data).Updates(map[string]interface{}{"status": 3, "code": "", "actived": "3", "auto_renewal": 2}).Error; err1 != nil { | ||||
| 				if err1 := e.Orm.Model(data).Updates(map[string]interface{}{"status": 3, "code": "", "actived": "3", "auto_renewal": 2, "deleted_at": time.Now()}).Error; err1 != nil { | ||||
| 					e.Log.Errorf("更新短信号码失败, %s", err1) | ||||
| 					return err1 | ||||
| 				} | ||||
| @ -143,21 +145,27 @@ func (e *SmsPhone) WeakUp(req *dto.WeakUpReq, userId int, defult bool) (dto.Weak | ||||
| 	} | ||||
|  | ||||
| 	if smsPhone.Status != 1 || defult { | ||||
| 		newActivationId, messageId, code := e.WeakUpManage(&smsPhone) | ||||
| 		newActivationId, messageId, startTime, endTime, code := e.WeakUpManage(&smsPhone) | ||||
|  | ||||
| 		if code == statuscode.ServerError { | ||||
| 			return result, code | ||||
| 		} else if code == statuscode.Success { | ||||
| 			if err := e.Orm.Model(smsPhone).Updates(map[string]interface{}{"new_activation_id": newActivationId, "status": 1, "code": "", "message_id": messageId}).Error; err != nil { | ||||
| 			if err := e.Orm.Model(smsPhone). | ||||
| 				Updates(map[string]interface{}{ | ||||
| 					"new_activation_id": newActivationId, "status": 1, "code": "", | ||||
| 					"message_id": messageId, "start_time": startTime, "end_time": endTime}).Error; err != nil { | ||||
| 				e.Log.Errorf("更新短信号码失败, %s", err) | ||||
| 				return result, statuscode.ServerError | ||||
| 			} | ||||
|  | ||||
| 			result.ActivationId = newActivationId | ||||
| 			result.MessageId = messageId | ||||
| 			result.StartTime = startTime | ||||
| 			result.EndTime = endTime | ||||
| 		} else if code == statuscode.SmsLongNumWaitCode { | ||||
| 			e.Log.Info("无须唤醒") | ||||
| 			if err := e.Orm.Model(smsPhone).Updates(map[string]interface{}{"status": 1, "code": ""}).Error; err != nil { | ||||
| 			if err := e.Orm.Model(smsPhone). | ||||
| 				Updates(map[string]interface{}{"status": 1, "code": "", "start_time": startTime, "end_time": endTime}). | ||||
| 				Error; err != nil { | ||||
| 				e.Log.Errorf("更新短信号码失败, %s", err) | ||||
| 				return result, statuscode.ServerError | ||||
| 			} | ||||
| @ -171,18 +179,18 @@ func (e *SmsPhone) WeakUp(req *dto.WeakUpReq, userId int, defult bool) (dto.Weak | ||||
|  | ||||
| // 唤醒号码 | ||||
| // returns newActivationId,messageId, code | ||||
| func (e *SmsPhone) WeakUpManage(req *models.SmsPhone) (string, string, int) { | ||||
| func (e *SmsPhone) WeakUpManage(req *models.SmsPhone) (string, string, *time.Time, *time.Time, int) { | ||||
| 	switch req.PlatformCode { | ||||
| 	case global.SmsPlatformDaisysms: | ||||
| 		service := SmsDaisysms{Service: e.Service} | ||||
| 		id, code := service.getExtraActivation(req.ActivationId) | ||||
| 		return strconv.Itoa(id), "", code | ||||
| 		return strconv.Itoa(id), "", nil, nil, code | ||||
| 	case global.SmsPlatformTextVerified: | ||||
| 		service := SmsTextVerified{Service: e.Service} | ||||
|  | ||||
| 		return service.getExtraActivation(req.NewActivationId) | ||||
| 		resp, code := service.getExtraActivation(req.NewActivationId) | ||||
| 		return resp.ReservationId, resp.Id, resp.UsageWindowStart, resp.UsageWindowEnd, code | ||||
| 	default: | ||||
| 		return "", "", statuscode.SmsPlatformUnavailable | ||||
| 		return "", "", nil, nil, statuscode.SmsPlatformUnavailable | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -201,6 +209,17 @@ func (e *SmsPhone) GetMyPage(req *dto.SmsPhoneGetPageReq, userId int, phone *[]m | ||||
| 		return statuscode.ServerError | ||||
| 	} | ||||
|  | ||||
| 	dictService := SysDictData{} | ||||
| 	dictService.Orm = e.Orm | ||||
| 	dictService.Log = e.Log | ||||
| 	dictDatas, _ := dictService.GetMapByType("sms_platform") | ||||
|  | ||||
| 	for index := range *phone { | ||||
| 		if dict, ok := dictDatas[(*phone)[index].PlatformCode]; ok { | ||||
| 			(*phone)[index].PlatformName = dict.DictLabel | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return statuscode.Success | ||||
| } | ||||
|  | ||||
| @ -281,7 +300,7 @@ func (e *SmsPhone) DoGetNumber(balanceService *MemberBalance, req *dto.GetNumber | ||||
| 	} | ||||
|  | ||||
| 	now := time.Now() | ||||
| 	activationId, phone, code, expireTime := e.GetNumberManage(req.PlatformCode, req.Type, req.ServiceCode, price, req.Period) | ||||
| 	activationId, phone, code, expireTime, startTime, endTime := e.GetNumberManage(req.PlatformCode, req.Type, req.ServiceCode, price, req.Period) | ||||
|  | ||||
| 	if code != statuscode.Success { | ||||
| 		return decimal.Decimal{}, models.SmsPhone{}, code | ||||
| @ -299,6 +318,8 @@ func (e *SmsPhone) DoGetNumber(balanceService *MemberBalance, req *dto.GetNumber | ||||
| 	smsPhone.MessageId = activationId | ||||
| 	smsPhone.NewActivationId = activationId | ||||
| 	smsPhone.Actived = 1 | ||||
| 	smsPhone.StartTime = startTime | ||||
| 	smsPhone.EndTime = endTime | ||||
|  | ||||
| 	smsPhone.Price = price | ||||
| 	if req.Type == 1 { | ||||
| @ -310,6 +331,10 @@ func (e *SmsPhone) DoGetNumber(balanceService *MemberBalance, req *dto.GetNumber | ||||
| 			smsPhone.ExpireTime = &now | ||||
| 		} | ||||
|  | ||||
| 		//平台不允许取消 | ||||
| 		if req.PlatformCode == global.SmsPlatformTextVerified { | ||||
| 			smsPhone.Actived = 2 | ||||
| 		} | ||||
| 	} else { | ||||
| 		if expireTime != nil { | ||||
| 			smsPhone.ExpireTime = expireTime | ||||
| @ -355,24 +380,30 @@ func (e *SmsPhone) DoGetNumber(balanceService *MemberBalance, req *dto.GetNumber | ||||
| } | ||||
|  | ||||
| // 租赁号码 | ||||
| func (e *SmsPhone) GetNumberManage(platformCode string, typ int, serviceCode string, price decimal.Decimal, period int) (string, string, int, *time.Time) { | ||||
| // return activationId 激活id | ||||
| // phone 号码 | ||||
| // code 状态码 | ||||
| // *expirateTime 号码过期时间 | ||||
| // *startTime 长效号码单次接码开始使用(textverified有用) | ||||
| // *endTime 长效号码单次接码过期时间(textverified有用) | ||||
| func (e *SmsPhone) GetNumberManage(platformCode string, typ int, serviceCode string, price decimal.Decimal, period int) (string, string, int, *time.Time, *time.Time, *time.Time) { | ||||
| 	switch platformCode { | ||||
| 	case global.SmsPlatformDaisysms: | ||||
| 		service := SmsDaisysms{Service: e.Service} | ||||
| 		activationId, phone, code := service.GetNumberForApi(typ, serviceCode, price, period) | ||||
|  | ||||
| 		return strconv.Itoa(activationId), phone, code, nil | ||||
| 		return strconv.Itoa(activationId), phone, code, nil, nil, nil | ||||
| 	case global.SmsPlatformTextVerified: | ||||
| 		service := SmsTextVerified{Service: e.Service} | ||||
| 		resp, code := service.GetNumberForApi(typ, serviceCode, price, period) | ||||
| 		resp, code := service.GetNumberAndWakeUp(typ, serviceCode, price, period) | ||||
|  | ||||
| 		if code != statuscode.Success { | ||||
| 			return "", "", code, nil | ||||
| 			return "", "", code, nil, resp.StartTime, resp.EndTime | ||||
| 		} | ||||
|  | ||||
| 		return resp.Id, resp.Phone, code, resp.EndAt | ||||
| 		return resp.Id, resp.Phone, code, resp.EndAt, resp.StartTime, resp.EndTime | ||||
| 	default: | ||||
| 		return "", "", statuscode.SmsPlatformUnavailable, nil | ||||
| 		return "", "", statuscode.SmsPlatformUnavailable, nil, nil, nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -416,11 +447,17 @@ func (e *SmsPhone) SyncCodes() error { | ||||
| 	} | ||||
|  | ||||
| 	for _, item := range phones { | ||||
| 		code, codeStatus := e.GetCodeManage(item.PlatformCode, item.NewActivationId, item.Type, item.UpdatedAt.Unix()) | ||||
| 		code, codeStatus := e.GetCodeManage(item.PlatformCode, item.NewActivationId, | ||||
| 			item.Type, item.UserId, item.Service, item.ServiceCode) | ||||
|  | ||||
| 		if code == "" { | ||||
| 			expireTime := item.UpdatedAt.Add(time.Second * 150) | ||||
| 			if item.PlatformCode == global.SmsPlatformTextVerified && expireTime.Before(time.Now()) { | ||||
| 			var expireTime time.Time | ||||
|  | ||||
| 			if item.EndTime != nil { | ||||
| 				expireTime = *item.EndTime | ||||
| 			} | ||||
|  | ||||
| 			if (item.Status == 3 && item.Actived == 2) || (item.PlatformCode == global.SmsPlatformTextVerified && expireTime.Before(time.Now())) { | ||||
| 				if err := e.Orm.Model(&item).Updates(map[string]interface{}{"status": 3, "updated_at": time.Now()}).Error; err != nil { | ||||
| 					e.Log.Errorf("手机号一睡眠 %s", item.Phone) | ||||
| 				} | ||||
| @ -473,7 +510,7 @@ func (e *SmsPhone) SyncCodes() error { | ||||
| } | ||||
|  | ||||
| // 获取验证码 | ||||
| func (e *SmsPhone) GetCodeManage(platformCode string, messageId string, typ int, unixTime int64) (string, int) { | ||||
| func (e *SmsPhone) GetCodeManage(platformCode string, messageId string, typ int, userId int, smsService, serviceCode string) (string, int) { | ||||
| 	switch platformCode { | ||||
| 	case global.SmsPlatformDaisysms: | ||||
| 		service := SmsDaisysms{Service: e.Service} | ||||
| @ -481,98 +518,224 @@ func (e *SmsPhone) GetCodeManage(platformCode string, messageId string, typ int, | ||||
| 		return service.GetCodeForApi(messageId) | ||||
| 	case global.SmsPlatformTextVerified: | ||||
| 		service := SmsTextVerified{Service: e.Service} | ||||
| 		return service.GetCode(messageId, typ, unixTime) | ||||
| 		return service.GetCode(messageId, typ, userId, smsService, serviceCode) | ||||
| 	default: | ||||
| 		return "", statuscode.SmsPlatformUnavailable | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // 自动续期 | ||||
| func (e SmsServices) AutoRenewal() error { | ||||
| 	var datas []models.SmsPhone | ||||
| 	var data models.SmsPhone | ||||
| 	startTime := time.Now().Add(-24 * time.Hour) | ||||
| 	endTime := time.Now().Add(24 * time.Hour) | ||||
|  | ||||
| 	smsServices := SmsServices{Service: e.Service} | ||||
| 	serviceMap := smsServices.GetMapAll() | ||||
|  | ||||
| 	configService := SysConfig{Service: e.Service} | ||||
| 	mapDatas, _ := configService.GetMapByKeys([]string{"renew_number_premium_daisysms", "renew_number_premium_textverified"}) | ||||
|  | ||||
| 	if 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(&datas).Error; err != nil { | ||||
| // AutoRenewal 自动续期处理 | ||||
| // 处理即将到期的长期号码自动续费逻辑 | ||||
| func (e *SmsPhone) AutoRenewal() error { | ||||
| 	// 获取24小时内到期的自动续费号码 | ||||
| 	expiredPhones, err := e.getExpiredPhones() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	for _, item := range datas { | ||||
| 		percent := decimal.NewFromInt(1) | ||||
| 		price := decimal.Zero | ||||
| 	// 获取服务配置映射 | ||||
| 	serviceMap, premiumMap, err := e.getRenewalConfigs() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 		if service, ok := serviceMap[item.PlatformCode+"_"+item.ServiceCode]; !ok { | ||||
| 	// 处理每个到期号码 | ||||
| 	for _, phone := range expiredPhones { | ||||
| 		if err := e.processPhoneRenewal(phone, serviceMap, premiumMap); err != nil { | ||||
| 			e.Log.Errorf("处理号码续费失败 [PhoneID: %d]: %v", phone.Id, err) | ||||
| 			continue | ||||
| 		} else { | ||||
| 			price = service.LongPrice | ||||
| 			switch { | ||||
| 			case item.PlatformCode == global.SmsPlatformDaisysms: | ||||
| 				p, ok := mapDatas["renew_number_premium_daisysms"] | ||||
| 				val, _ := decimal.NewFromString(p.ConfigValue) | ||||
|  | ||||
| 				if ok && val.Cmp(decimal.Zero) > 0 { | ||||
| 					per := decimal.NewFromInt(100).Add(val) | ||||
| 					percent = per.Div(decimal.NewFromInt(100)).Truncate(2) | ||||
| 				} | ||||
| 			case item.PlatformCode == global.SmsPlatformTextVerified: | ||||
| 				p, ok := mapDatas["renew_number_premium_textverified"] | ||||
| 				val, _ := decimal.NewFromString(p.ConfigValue) | ||||
|  | ||||
| 				if ok && val.Cmp(decimal.Zero) > 0 { | ||||
| 					per := decimal.NewFromInt(100).Add(val) | ||||
| 					percent = per.Div(decimal.NewFromInt(100)).Truncate(2) | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			renewLog := models.SmsRenewalLog{} | ||||
| 			renewLog.UserId = item.UserId | ||||
| 			renewLog.PhoneId = item.Id | ||||
| 			renewLog.Type = item.Type | ||||
| 			renewLog.Amount = price.Mul(percent).Truncate(2) | ||||
| 			renewLog.BeforeTime = *item.ExpireTime | ||||
| 			renewLog.Period = 30 | ||||
|  | ||||
| 			if err := e.Orm.Transaction(func(tx *gorm.DB) error { | ||||
| 				db := tx.Exec("UPDATE member_balance set balance = balance - ? where user_id = ? and balance >= ?", price, item.UserId, price) | ||||
|  | ||||
| 				if db.Error != nil { | ||||
| 					return db.Error | ||||
| 				} | ||||
|  | ||||
| 				if db.RowsAffected == 0 { | ||||
| 					return errors.New("余额不足") | ||||
| 				} | ||||
|  | ||||
| 				if err1 := tx.Create(&renewLog).Error; err1 != nil { | ||||
|  | ||||
| 					return errors.New("创建续费日志失败") | ||||
| 				} | ||||
|  | ||||
| 				newExpireTime := item.ExpireTime.AddDate(0, 0, 30) | ||||
| 				if err1 := tx.Model(data).Where("id =?", item.Id).Update("expire_time", newExpireTime).Error; err1 != nil { | ||||
| 					return err1 | ||||
| 				} | ||||
| 				return nil | ||||
| 			}); err != nil { | ||||
| 				e.Log.Errorf("自动续期失败:%s", err.Error()) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return 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, | ||||
| 		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.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.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 修改自动续期 | ||||
| func (e *SmsPhone) ChangeAutoRenew(req *dto.SmsPhoneChangeAutoRenewReq, userId int) int { | ||||
| 	var data models.SmsPhone | ||||
|  | ||||
| 	if req.AutoRenew == 1 { | ||||
| 		smsServices := SmsServices{Service: e.Service} | ||||
| 		balanceService := MemberBalance{Service: e.Service} | ||||
| 		balance := balanceService.GetBalance(userId) | ||||
|  | ||||
| 		if err := e.Orm.Model(data).Where("id =? or activation_id =?", req.Id, req.ActivationId).First(&data).Error; err != nil { | ||||
| 			e.Log.Errorf("修改自动续期 数据不存在 id:%d err:%s", req.Id, err.Error()) | ||||
| 			return statuscode.SmsNotExisted | ||||
| 		} | ||||
|  | ||||
| 		if data.ExpireTime.Before(time.Now()) { | ||||
| 			return statuscode.SmsRentalCantRenew | ||||
| 		} | ||||
|  | ||||
| 		serviceItem, err := smsServices.GetByCode(data.PlatformCode, data.ServiceCode) | ||||
|  | ||||
| 		if err != nil { | ||||
| 			e.Log.Errorf("短信服务报错:%v", err) | ||||
| 			return statuscode.ServerError | ||||
| 		} | ||||
| 		configService := SysConfig{Service: e.Service} | ||||
| 		configKeys := []string{"renew_number_premium_daisysms", "renew_number_premium_textverified"} | ||||
| 		premiumMap, _ := configService.GetMapByKeys(configKeys) | ||||
|  | ||||
| 		price := e.calculateRenewalPrice(serviceItem.LongPrice, serviceItem.PlatformCode, premiumMap) | ||||
|  | ||||
| 		if balance.Cmp(price) < 0 { | ||||
| 			return statuscode.BalanceNotEnough | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if req.Id > 0 { | ||||
| 		if err := e.Orm.Model(data).Where("id =? and user_id =?", req.Id, userId).First(&data).Error; err != nil { | ||||
| 			e.Log.Errorf("修改自动续期 数据不存在 id:%d err:%s", req.Id, err.Error()) | ||||
|  | ||||
| @ -2,6 +2,7 @@ package service | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"strconv" | ||||
|  | ||||
| 	"github.com/go-admin-team/go-admin-core/sdk/service" | ||||
| 	"gorm.io/gorm" | ||||
| @ -38,7 +39,7 @@ func (e SmsReceiveLog) WebHook(req *dto.SmsReceiveWebHookReq) error { | ||||
| 			UserId:      phoneLog.UserId, | ||||
| 			Service:     phoneLog.Service, | ||||
| 			ServiceCode: phoneLog.ServiceCode, | ||||
| 			MessageId:   req.MessageID, | ||||
| 			MessageId:   strconv.Itoa(req.MessageID), | ||||
| 			Phone:       phoneLog.Phone, | ||||
| 			Code:        req.Code, | ||||
| 			Status:      2, | ||||
|  | ||||
| @ -13,7 +13,7 @@ import ( | ||||
| ) | ||||
|  | ||||
| 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{}) | ||||
| 	sdk.Runtime.SetDb("default", db) | ||||
| 	config.ExtConfig.TrxGridUrl = "https://api.trongrid.io" | ||||
|  | ||||
| @ -32,7 +32,7 @@ type SmsTextVerified struct { | ||||
| // 获取收到的验证码 | ||||
| // messageId 短效或长效号码的ID | ||||
| // typ 0-短效 1-长效 | ||||
| func (e SmsTextVerified) GetCode(messageId string, typ int, unixTime int64) (string, int) { | ||||
| func (e SmsTextVerified) GetCode(messageId string, typ int, userId int, service, serviceCode string) (string, int) { | ||||
| 	reservationType := "" | ||||
|  | ||||
| 	if typ == 0 { | ||||
| @ -58,23 +58,84 @@ func (e SmsTextVerified) GetCode(messageId string, typ int, unixTime int64) (str | ||||
| 		return "", statuscode.ServerError | ||||
| 	} | ||||
|  | ||||
| 	messageIds := []string{} | ||||
|  | ||||
| 	if len(resp.Data) > 0 { | ||||
| 		for _, v := range resp.Data { | ||||
| 			// 2. 解析时间字符串 | ||||
| 			// time.RFC3339Nano 是一个预定义的格式常量, | ||||
| 			// 它能够解析包含纳秒和时区信息的 ISO 8601 字符串。 | ||||
| 			messageIds = append(messageIds, v.Id) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if len(messageIds) > 0 { | ||||
| 		receiveLogs := make([]models.SmsReceiveLog, 0) | ||||
| 		receiveMaps := make(map[string]string, 0) | ||||
|  | ||||
| 		if err := e.Orm.Model(&models.SmsReceiveLog{}). | ||||
| 			Where("message_id in ?", messageIds). | ||||
| 			Select("message_id"). | ||||
| 			Find(&receiveLogs).Error; err != nil { | ||||
| 			e.Log.Errorf("获取短信接收记录失败, error: %v", err) | ||||
| 			return "", statuscode.ServerError | ||||
| 		} | ||||
|  | ||||
| 		for _, v := range receiveLogs { | ||||
| 			receiveMaps[v.MessageId] = v.MessageId | ||||
| 		} | ||||
|  | ||||
| 		// 查找最新验证码并存储所有新验证码 | ||||
| 		var latestSms *dto.TextVerifiedSmsItemResp | ||||
| 		var latestTime time.Time | ||||
| 		var newSmsData []dto.TextVerifiedSmsItemResp | ||||
|  | ||||
| 		// 遍历所有验证码数据 | ||||
| 		for _, v := range resp.Data { | ||||
| 			// 解析时间字符串 | ||||
| 			t, err := time.Parse(time.RFC3339Nano, v.CreatedAt) | ||||
| 			if err != nil { | ||||
| 				fmt.Println("时间解析失败:", err) | ||||
| 				e.Log.Errorf("时间解析失败: %v", err) | ||||
| 				continue | ||||
| 			} | ||||
|  | ||||
| 			// 3. 将解析后的 time.Time 对象转换为 Unix 时间戳 | ||||
| 			// t.Unix() 返回以秒为单位的整数时间戳 | ||||
| 			unixTimestamp := t.Unix() | ||||
| 			// 检查是否为新验证码(数据库中不存在) | ||||
| 			if _, ok := receiveMaps[v.Id]; !ok { | ||||
| 				newSmsData = append(newSmsData, v) | ||||
| 			} | ||||
|  | ||||
| 			if unixTimestamp >= unixTime { | ||||
| 				parsedCode = v.ParsedCode | ||||
| 				break | ||||
| 			// 选择最新的验证码(包括已存在的) | ||||
| 			if latestSms == nil || t.After(latestTime) { | ||||
| 				latestSms = &v | ||||
| 				latestTime = t | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// 批量保存所有新验证码到数据库 | ||||
| 		if len(newSmsData) > 0 { | ||||
| 			var receiveLogs []models.SmsReceiveLog | ||||
| 			for _, sms := range newSmsData { | ||||
| 				receiveLog := models.SmsReceiveLog{ | ||||
| 					UserId:      userId, | ||||
| 					Service:     service, | ||||
| 					ServiceCode: serviceCode, | ||||
| 					MessageId:   sms.Id, | ||||
| 					Phone:       "1" + sms.To, | ||||
| 					Code:        sms.ParsedCode, | ||||
| 					Status:      2, | ||||
| 				} | ||||
| 				receiveLogs = append(receiveLogs, receiveLog) | ||||
| 			} | ||||
|  | ||||
| 			// 批量插入数据库 | ||||
| 			if err := e.Orm.Create(&receiveLogs).Error; err != nil { | ||||
| 				e.Log.Errorf("批量创建短信接收记录失败, error: %v", err) | ||||
| 				return "", statuscode.ServerError | ||||
| 			} | ||||
|  | ||||
| 			e.Log.Infof("成功存储 %d 条新验证码记录", len(newSmsData)) | ||||
|  | ||||
| 			// 返回最新的验证码 | ||||
| 			if latestSms != nil { | ||||
| 				parsedCode = latestSms.ParsedCode | ||||
| 				e.Log.Infof("返回最新验证码: %s, messageId: %s, 时间: %s", parsedCode, latestSms.Id, latestSms.CreatedAt) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| @ -97,6 +158,7 @@ const ( | ||||
| 	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}$`) | ||||
| @ -284,12 +346,33 @@ func (e *SmsTextVerified) SyncPrices() error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // 获取号码并唤醒 | ||||
| func (e *SmsTextVerified) GetNumberAndWakeUp(tye int, serviceCode string, price decimal.Decimal, period int) (dto.SmsPhoneGetPhoneResp, int) { | ||||
| 	resp, code := e.GetNumberForApi(tye, serviceCode, price, period) | ||||
|  | ||||
| 	if code != statuscode.Success { | ||||
| 		return resp, code | ||||
| 	} | ||||
|  | ||||
| 	wakeUpResp, code := e.getExtraActivation(resp.Id) | ||||
|  | ||||
| 	if code != statuscode.Success { | ||||
| 		return resp, code | ||||
| 	} | ||||
|  | ||||
| 	resp.MessageId = wakeUpResp.Id | ||||
| 	resp.StartTime = wakeUpResp.UsageWindowStart | ||||
| 	resp.EndTime = wakeUpResp.UsageWindowEnd | ||||
|  | ||||
| 	return resp, code | ||||
| } | ||||
|  | ||||
| // 号码租赁 | ||||
| // getType 0-短效 1-长效 | ||||
| // service 服务code | ||||
| // maxPrice 最大价格 | ||||
| // period 时长(月=30天) | ||||
| func (e SmsTextVerified) GetNumberForApi(typ int, serviceCode string, price decimal.Decimal, period int) (dto.SmsPhoneGetPhoneResp, int) { | ||||
| func (e *SmsTextVerified) GetNumberForApi(typ int, serviceCode string, price decimal.Decimal, period int) (dto.SmsPhoneGetPhoneResp, int) { | ||||
| 	//这个平台的所有号码都是美国号码 默认国家代码都是 +1 | ||||
| 	var err error | ||||
| 	var createResp dto.TextVerifiedResp | ||||
| @ -477,12 +560,13 @@ func (e *SmsTextVerified) GetRentalDetail(id string) (dto.VerificationRentalDeta | ||||
| } | ||||
|  | ||||
| // 唤醒号码 | ||||
| // returns activationId,messageId, code | ||||
| func (e SmsTextVerified) getExtraActivation(id string) (string, string, int) { | ||||
| // returns activationId,messageId,startTime(可用开始时间),endTime(可用结束时间), code, | ||||
| func (e SmsTextVerified) getExtraActivation(id string) (dto.TextVerifiedWakeUpResp, int) { | ||||
| 	client, code := e.GetTextVerifiedAuthClient() | ||||
| 	result := dto.TextVerifiedWakeUpResp{} | ||||
|  | ||||
| 	if code != statuscode.Success { | ||||
| 		return "", "", code | ||||
| 		return result, code | ||||
| 	} | ||||
|  | ||||
| 	req := dto.TextVerifiedWakeUpReq{ | ||||
| @ -497,31 +581,35 @@ func (e SmsTextVerified) getExtraActivation(id string) (string, string, int) { | ||||
|  | ||||
| 	if err != nil { | ||||
| 		e.Log.Errorf("唤醒号码失败 id:%s error: %v", id, err) | ||||
| 		return "", "", statuscode.ServerError | ||||
| 		return result, statuscode.ServerError | ||||
| 	} else if status == http.StatusCreated || status == http.StatusOK { | ||||
| 		if resp.Method != "" && resp.Href != "" { | ||||
| 			bytes, err := e.doRequest(&resp) | ||||
|  | ||||
| 			if err != nil { | ||||
| 				e.Log.Errorf("唤醒号码失败 id:%s error: %v", id, err) | ||||
| 				return "", "", statuscode.ServerError | ||||
| 				return result, statuscode.ServerError | ||||
| 			} | ||||
|  | ||||
| 			detailResp := dto.TextVerifiedWakeUpResp{} | ||||
|  | ||||
| 			if err := sonic.Unmarshal(bytes, &detailResp); err != nil { | ||||
| 				e.Log.Errorf("唤醒号码反序列化失败 id:%s error: %v", id, err) | ||||
| 				return "", "", statuscode.ServerError | ||||
| 				return result, statuscode.ServerError | ||||
| 			} | ||||
|  | ||||
| 			return detailResp.ReservationId, detailResp.Id, statuscode.Success | ||||
| 			result.Id = detailResp.Id | ||||
| 			result.ReservationId = detailResp.ReservationId | ||||
| 			result.UsageWindowEnd = detailResp.UsageWindowEnd | ||||
| 			result.UsageWindowStart = detailResp.UsageWindowStart | ||||
| 			return result, statuscode.Success | ||||
| 		} else { | ||||
| 			e.Log.Errorf("唤醒号码失败 id:%s error: %v", id, err) | ||||
| 			return "", "", statuscode.ServerError | ||||
| 			return result, statuscode.ServerError | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return "", "", statuscode.ServerError | ||||
| 	return result, statuscode.ServerError | ||||
| } | ||||
|  | ||||
| // 获取价格 | ||||
| @ -826,7 +914,121 @@ func (e *SmsTextVerified) Renew(activationId string, status bool) int { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // 重新初始化短信记录 | ||||
| func (e *SmsTextVerified) InitSmsLogs() error { | ||||
| 	// phones, err := e.GetNumbers() | ||||
|  | ||||
| 	// if err != nil { | ||||
| 	// 	e.Log.Errorf("获取长效号码列表失败 %v", err) | ||||
| 	// 	return fmt.Errorf("获取长效号码列表失败 %v", err) | ||||
| 	// } | ||||
|  | ||||
| 	// numbers := make([]string, 0) | ||||
|  | ||||
| 	// for _, v := range phones { | ||||
| 	// 	numbers = append(numbers, v.Number) | ||||
| 	// } | ||||
|  | ||||
| 	phoneLogs, err := e.GetUserByNumber("textverified") | ||||
|  | ||||
| 	if err != nil { | ||||
| 		e.Log.Errorf("获取系统内号码记录失败 %v", err) | ||||
| 		return fmt.Errorf("获取系统内号码记录失败 %v", err) | ||||
| 	} | ||||
|  | ||||
| 	if len(phoneLogs) > 0 { | ||||
| 		for _, v := range phoneLogs { | ||||
| 			e.GetCode(v.ActivationId, v.Type, v.UserId, v.Service, v.ServiceCode) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // 根据电话号码获取系统内记录 | ||||
| func (e *SmsTextVerified) GetUserByNumber(platformCode string) ([]models.SmsPhone, error) { | ||||
| 	var result []models.SmsPhone | ||||
|  | ||||
| 	if err := e.Orm.Model(&models.SmsPhone{}).Where("platform_code = ?", platformCode).Find(&result).Error; err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return result, nil | ||||
| } | ||||
|  | ||||
| // 获取号码 | ||||
| func (e *SmsTextVerified) GetNumbers() ([]dto.VerificationDTO, error) { | ||||
| 	client, code := e.GetTextVerifiedAuthClient() | ||||
| 	result := make([]dto.VerificationDTO, 0) | ||||
|  | ||||
| 	if code != statuscode.Success { | ||||
| 		e.Log.Errorf("获取长效号码列表失败 %d", code) | ||||
| 		return result, fmt.Errorf("获取长效号码列表失败 %d", code) | ||||
| 	} | ||||
|  | ||||
| 	resp := dto.TextVerifiedGetNumbersResp{} | ||||
| 	statusCode, err := client.Get(getNumbers, map[string]string{}, resp) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		e.Log.Errorf("获取长效号码列表失败 %v", err) | ||||
| 		return result, fmt.Errorf("获取长效号码列表失败 %v", err) | ||||
| 	} | ||||
|  | ||||
| 	if statusCode == http.StatusOK { | ||||
| 		// 添加第一页数据 | ||||
| 		result = append(result, resp.Data...) | ||||
|  | ||||
| 		// 处理分页数据 | ||||
| 		if resp.HasNext { | ||||
| 			paginatedData, err := e.fetchPaginatedData(resp.Links.Next) | ||||
| 			if err != nil { | ||||
| 				return result, err | ||||
| 			} | ||||
| 			result = append(result, paginatedData...) | ||||
| 		} | ||||
|  | ||||
| 		return result, nil | ||||
| 	} else if statusCode == http.StatusUnauthorized { | ||||
| 		return e.GetNumbers() | ||||
| 	} else { | ||||
| 		e.Log.Errorf("获取长效号码列表失败 %d", statusCode) | ||||
| 		return result, fmt.Errorf("获取长效号码列表失败 %d", statusCode) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // 获取授权header头 | ||||
| // fetchPaginatedData 获取分页数据的通用方法 | ||||
| // 处理TextVerified API的分页响应,自动获取所有页面的数据 | ||||
| func (e *SmsTextVerified) fetchPaginatedData(nextLink *dto.TextVerifiedResp) ([]dto.VerificationDTO, error) { | ||||
| 	var result []dto.VerificationDTO | ||||
|  | ||||
| 	for nextLink != nil { | ||||
| 		nextData, err := e.doRequest(nextLink) | ||||
| 		if err != nil { | ||||
| 			e.Log.Errorf("获取分页数据失败: %v", err) | ||||
| 			return result, fmt.Errorf("获取分页数据失败: %v", err) | ||||
| 		} | ||||
|  | ||||
| 		nextResp := dto.TextVerifiedGetNumbersResp{} | ||||
| 		err = sonic.Unmarshal(nextData, &nextResp) | ||||
| 		if err != nil { | ||||
| 			e.Log.Errorf("解析分页数据失败: %v", err) | ||||
| 			return result, fmt.Errorf("解析分页数据失败: %v", err) | ||||
| 		} | ||||
|  | ||||
| 		result = append(result, nextResp.Data...) | ||||
|  | ||||
| 		// 检查是否还有下一页 | ||||
| 		if nextResp.HasNext { | ||||
| 			nextLink = nextResp.Links.Next | ||||
| 		} else { | ||||
| 			nextLink = nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return result, nil | ||||
| } | ||||
|  | ||||
| func (e *SmsTextVerified) GetAuthHeader() (map[string]string, error) { | ||||
| 	token, err := e.GetToken() | ||||
| 	if err != nil { | ||||
|  | ||||
| @ -51,3 +51,18 @@ func TestSyncTextVerifiedServices(t *testing.T) { | ||||
| 		t.Log("SyncTextVerifiedServices succeeded") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestInitSmsLogs(t *testing.T) { | ||||
| 	db := initSetting() | ||||
|  | ||||
| 	s := SmsTextVerified{} | ||||
| 	s.Orm = db | ||||
| 	s.Log = logger.NewHelper(logger.DefaultLogger) | ||||
|  | ||||
| 	err := s.InitSmsLogs() | ||||
| 	if err != nil { | ||||
| 		t.Errorf("InitSmsLogs failed: %v", err) | ||||
| 	} else { | ||||
| 		t.Log("InitSmsLogs succeeded") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -37,11 +37,11 @@ func (j RenewalJob) Exec(args interface{}) error { | ||||
|  | ||||
| // 定时短信续期任务 | ||||
| func (j SmsRenewalJob) Exec(args interface{}) error { | ||||
| 	smsService := service.SmsServices{} | ||||
| 	smsService.Orm = GetDb() | ||||
| 	smsService.Log = logger.NewHelper(logger.DefaultLogger) | ||||
| 	smsPhoneService := service.SmsPhone{} | ||||
| 	smsPhoneService.Orm = GetDb() | ||||
| 	smsPhoneService.Log = logger.NewHelper(logger.DefaultLogger) | ||||
|  | ||||
| 	return smsService.AutoRenewal() | ||||
| 	return smsPhoneService.AutoRenewal() | ||||
| } | ||||
|  | ||||
| // 过期任务 | ||||
|  | ||||
| @ -41,6 +41,7 @@ var StatusCodeZh = map[int]string{ | ||||
| 	SmsInvalidType:              "短信验证码_无效类型", | ||||
| 	SmsOutOfStockOrUnavailable:  "短信验证码_缺货或服务不可用", | ||||
| 	SmsRentalRefundNotPermitted: "短信验证码_租赁退款不允许", | ||||
| 	SmsRentalCantRenew:          "短信验证码_无法续期", | ||||
| } | ||||
|  | ||||
| var StatusCodeEn = map[int]string{ | ||||
| @ -74,6 +75,7 @@ var StatusCodeEn = map[int]string{ | ||||
| 	SmsInvalidType:              "sms type invalid", | ||||
| 	SmsOutOfStockOrUnavailable:  "sms out of stock or unavailable", | ||||
| 	SmsRentalRefundNotPermitted: "sms rental refund not permitted", | ||||
| 	SmsRentalCantRenew:          "sms rental can not renewal", | ||||
| } | ||||
|  | ||||
| // GetMsg 获取状态码对应的消息 | ||||
| @ -161,4 +163,6 @@ const ( | ||||
| 	SmsOutOfStockOrUnavailable = 20024 | ||||
| 	// 短信-租赁退款不允许 | ||||
| 	SmsRentalRefundNotPermitted = 20025 | ||||
| 	// 短信-无法续期 | ||||
| 	SmsRentalCantRenew = 20026 | ||||
| ) | ||||
|  | ||||
		Reference in New Issue
	
	Block a user