htfutures_account_controller.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. package web_hook
  2. import (
  3. "eta/eta_mini_ht_api/common/component/cache"
  4. logger "eta/eta_mini_ht_api/common/component/log"
  5. "eta/eta_mini_ht_api/common/exception"
  6. "eta/eta_mini_ht_api/controllers"
  7. userService "eta/eta_mini_ht_api/domian/user"
  8. accountService "eta/eta_mini_ht_api/service/user"
  9. "fmt"
  10. "golang.org/x/time/rate"
  11. "net/http"
  12. "strings"
  13. "sync"
  14. "time"
  15. )
  16. var (
  17. // 初始化限流器
  18. accountRateLimiter = NewThirdRateLimiter(rate.Every(1*time.Second), 1)
  19. rdServer = cache.GetInstance()
  20. )
  21. type ThirdRateLimiter struct {
  22. limiters sync.Map // 存储每个用户的限流器
  23. defaultLimiter *rate.Limiter // 默认限流器
  24. }
  25. func NewThirdRateLimiter(limit rate.Limit, burst int) *ThirdRateLimiter {
  26. return &ThirdRateLimiter{
  27. defaultLimiter: rate.NewLimiter(limit, burst),
  28. }
  29. }
  30. func (url *ThirdRateLimiter) Allow(idNo string) bool {
  31. if limiter, ok := url.limiters.Load(idNo); ok {
  32. return limiter.(*rate.Limiter).Allow()
  33. }
  34. // 创建新的限流器并存储
  35. newLimiter := rate.NewLimiter(url.defaultLimiter.Limit(), url.defaultLimiter.Burst())
  36. url.limiters.Store(idNo, newLimiter)
  37. return newLimiter.Allow()
  38. }
  39. // ThirdRateLimitFilter 回调接口限流
  40. func ThirdRateLimitFilter(idNo string) (code int) {
  41. if idNo == "" {
  42. code = http.StatusBadRequest
  43. return
  44. }
  45. if !accountRateLimiter.Allow(idNo) {
  46. code = http.StatusTooManyRequests
  47. return
  48. }
  49. code = http.StatusOK
  50. return
  51. }
  52. type HTFuturesAccountController struct {
  53. controllers.WebHookController
  54. }
  55. // // SyncCustomerRiskLevel 风险测评同步接口
  56. // // @Summary 风险测评同步接口
  57. // // @Description 风险测评同步接口
  58. // // @Success 200 {object} controllers.BaseResponse
  59. // // @router /riskLevel [post]
  60. //
  61. // func (h *UserController) SyncCustomerRiskLevel() {
  62. // controllers.Wrap(&h.BaseController, func() (result *controllers.WrapData, err error) {
  63. // result = h.InitWrapData("同步风险等级")
  64. // htConfig := config.GetConfig(contants.HT).(*config.HTBizConfig)
  65. // webhookRequest := new(WebhookRequest)
  66. // h.GetPostParams(webhookRequest)
  67. // privateKey, err := authUtils.ParsePrivateKey(htConfig.GetWebhookPrivateKey())
  68. // if err != nil {
  69. // err = exception.NewWithException(exception.SysError, err.Error())
  70. // logger.Error("解析私钥失败: %v", err)
  71. // h.FailedResult("解析私钥失败", result)
  72. // return
  73. // }
  74. // decodeData, err := authUtils.DecryptWithRSA(privateKey, webhookRequest.Data)
  75. // if err != nil {
  76. // err = exception.NewWithException(exception.SysError, err.Error())
  77. // logger.Error("解密请求体失败: %v", err)
  78. // h.FailedResult("解密请求体失败", result)
  79. // return
  80. // }
  81. // syncCustomerRiskLevelReq := new(SyncCustomerRiskLevelReq)
  82. // err = json.Unmarshal(decodeData, syncCustomerRiskLevelReq)
  83. // if err != nil {
  84. // err = exception.NewWithException(exception.SyncRiskError, err.Error())
  85. // logger.Error("解析请求体失败: %v", err)
  86. // h.FailedResult("解析请求体失败", result)
  87. // return
  88. // }
  89. // custInfo := syncCustomerRiskLevelReq.CustInfo
  90. // riskInfo := syncCustomerRiskLevelReq.RiskInfo
  91. // if custInfo.ClientName == "" {
  92. // err = exception.New(exception.SyncRiskError)
  93. // h.FailedResult("用户名字不能为空", result)
  94. // return
  95. // }
  96. // if custInfo.MobileTel == "" {
  97. // err = exception.New(exception.SyncRiskError)
  98. // h.FailedResult("手机号码不能为空", result)
  99. // return
  100. // }
  101. // if custInfo.IdNo == "" {
  102. // err = exception.New(exception.SyncRiskError)
  103. // h.FailedResult("身份证号不能为空", result)
  104. // return
  105. // }
  106. // //if !utils.IsValidIDCard(custInfo.IdNo) && !utils.IsValidOldIDCard(custInfo.IdNo) {
  107. // // err = exception.New(exception.SyncRiskError)
  108. // // h.FailedResult("身份证号不合法", result)
  109. // // return
  110. // //}
  111. // if riskInfo.CorpRiskLevel == "" {
  112. // err = exception.New(exception.SyncRiskError)
  113. // h.FailedResult("风险等级不能为空", result)
  114. // return
  115. // }
  116. // if riskInfo.CorpEndDate == "" {
  117. // err = exception.New(exception.SyncRiskError)
  118. // h.FailedResult("风险测评有效结束日期不能为空", result)
  119. // return
  120. // }
  121. // err = userService.UpdateRiskLevelInfo(userService.RiskLevelInfoDTO{
  122. // Name: custInfo.ClientName,
  123. // PhoneNumber: custInfo.MobileTel,
  124. // RiskLevel: riskInfo.CorpRiskLevel,
  125. // RiskValidEndDate: riskInfo.CorpEndDate,
  126. // })
  127. // if err != nil {
  128. // logger.ErrorWithTraceId(h.Ctx, err.Error())
  129. // h.FailedResult(err.Error(), result)
  130. // err = exception.New(exception.SyncRiskError)
  131. // return
  132. // }
  133. // logger.InfoWithTraceId(h.Ctx, err.Error())
  134. // result = h.InitWrapData("同步风险等级成功")
  135. // h.SuccessResult("success", syncCustomerRiskLevelReq, result)
  136. // return
  137. // })
  138. // }
  139. var (
  140. riskMappingMap = map[string]string{
  141. "0": "C1",
  142. "1": "C1",
  143. "2": "C2",
  144. "3": "C3",
  145. "4": "C4",
  146. "5": "C5",
  147. }
  148. )
  149. // SyncCustomerRiskLevel 风险测评同步接口
  150. // @Summary 风险测评同步接口
  151. // @Description 风险测评同步接口
  152. // @Success 200 {object} controllers.BaseResponse
  153. // @router /v1/syncRiskLevel/ [post]
  154. func (h *HTFuturesAccountController) SyncCustomerRiskLevel() {
  155. controllers.WrapWebhook(&h.WebHookController, func() (result *controllers.WrapData, err error) {
  156. result = h.InitWrapData("同步风险等级")
  157. syncCustomerRiskLevelReq := new(SyncCustomerRiskLevelReq)
  158. h.GetPostParams(syncCustomerRiskLevelReq)
  159. custInfo := syncCustomerRiskLevelReq.CustInfo
  160. riskInfo := syncCustomerRiskLevelReq.RiskInfo
  161. if custInfo.ClientName == "" {
  162. err = exception.New(exception.SyncRiskError)
  163. h.FailedResult("用户名字不能为空", result)
  164. return
  165. }
  166. if custInfo.DealMobileTel == "" {
  167. err = exception.New(exception.SyncRiskError)
  168. h.FailedResult("手机号码不能为空", result)
  169. return
  170. }
  171. if custInfo.IdNo == "" {
  172. err = exception.New(exception.SyncRiskError)
  173. h.FailedResult("身份证号不能为空", result)
  174. return
  175. }
  176. if custInfo.MobileTel != "" && custInfo.DealMobileTel != custInfo.MobileTel {
  177. err = exception.New(exception.SyncRiskError)
  178. h.FailedResult(fmt.Sprintf("柜台预留手机号码不一致,测评手机:%s,柜台预留手机:%s", custInfo.DealMobileTel, custInfo.MobileTel), result)
  179. return
  180. }
  181. if riskInfo.CorpRiskLevel == "" {
  182. err = exception.New(exception.SyncRiskError)
  183. h.FailedResult("风险等级不能为空", result)
  184. return
  185. }
  186. if riskInfo.CorpEndDate == "" {
  187. err = exception.New(exception.SyncRiskError)
  188. h.FailedResult("风险测评有效结束日期不能为空", result)
  189. return
  190. }
  191. riskEndDate, parseErr := time.Parse("20060102", riskInfo.CorpEndDate)
  192. if parseErr != nil {
  193. err = exception.New(exception.SyncRiskError)
  194. h.FailedResult("风险测评有效结束日期不合法["+riskInfo.CorpEndDate+"]", result)
  195. return
  196. }
  197. if risk, ok := riskMappingMap[riskInfo.CorpRiskLevel]; ok {
  198. riskInfo.CorpRiskLevel = risk
  199. } else {
  200. err = exception.New(exception.SyncRiskError)
  201. h.FailedResult(fmt.Sprintf("风险等级不合法,应答结果:%s", riskInfo.CorpRiskLevel), result)
  202. return
  203. }
  204. err = userService.UpdateRiskLevelInfo(userService.RiskLevelInfoDTO{
  205. Name: custInfo.ClientName,
  206. PhoneNumber: custInfo.DealMobileTel,
  207. RiskLevel: riskInfo.CorpRiskLevel,
  208. RiskValidEndDate: riskEndDate.Format(time.DateOnly),
  209. })
  210. if err != nil {
  211. logger.ErrorWithTraceId(h.Ctx, err.Error())
  212. h.FailedResult(err.Error(), result)
  213. err = exception.New(exception.SyncRiskError)
  214. return
  215. }
  216. result = h.InitWrapData("同步风险等级成功")
  217. h.SuccessResult("success", syncCustomerRiskLevelReq, result)
  218. return
  219. })
  220. }
  221. // SyncCustomerAccountInfo 开户信息同步接口
  222. // @Summary 开户信息同步接口
  223. // @Description 开户信息同步接口
  224. // @Success 200 {object} controllers.BaseResponse
  225. // @router /v1/syncAccountInfo/ [post]
  226. func (h *HTFuturesAccountController) SyncCustomerAccountInfo() {
  227. controllers.WrapWebhook(&h.WebHookController, func() (result *controllers.WrapData, err error) {
  228. result = h.InitWrapData("同步开户信息失败")
  229. syncCustomerRiskLevelReq := new(AccountOpenInfoReq)
  230. h.GetPostParams(syncCustomerRiskLevelReq)
  231. if ThirdRateLimitFilter(syncCustomerRiskLevelReq.IdNo) != 200 {
  232. err = exception.New(exception.TooManyRequest)
  233. h.FailedResult("接口请求太频繁,请稍后重试", result)
  234. return
  235. }
  236. //if syncCustomerRiskLevelReq.MobileTel != "" && syncCustomerRiskLevelReq.DealMobileTel != syncCustomerRiskLevelReq.MobileTel {
  237. // err = exception.New(exception.SyncRiskError)
  238. // h.FailedResult(fmt.Sprintf("柜台预留手机号码不一致,测评手机:%s,柜台预留手机:%s", syncCustomerRiskLevelReq.DealMobileTel, syncCustomerRiskLevelReq.MobileTel), result)
  239. // return
  240. //}
  241. if syncCustomerRiskLevelReq.ClientName == "" {
  242. err = exception.New(exception.SyncAccountStatusError)
  243. h.FailedResult("用户名字不能为空", result)
  244. return
  245. }
  246. if syncCustomerRiskLevelReq.MobileTel == "" {
  247. err = exception.New(exception.SyncAccountStatusError)
  248. h.FailedResult("手机号码不能为空", result)
  249. return
  250. }
  251. if _, ok := idKindMap[syncCustomerRiskLevelReq.IdKind]; !ok {
  252. err = exception.New(exception.SyncAccountStatusError)
  253. validIdKind := make([]string, 0)
  254. for _, v := range idKindMap {
  255. validIdKind = append(validIdKind, string(v))
  256. }
  257. h.FailedResult(fmt.Sprintf("证件类型不合法,当前只支持[%s]", strings.Join(validIdKind, ",")), result)
  258. return
  259. }
  260. if syncCustomerRiskLevelReq.IdNo == "" {
  261. err = exception.New(exception.SyncAccountStatusError)
  262. h.FailedResult("证号号码不能为空", result)
  263. return
  264. }
  265. idBeginDate, parseErr := time.Parse(time.DateOnly, syncCustomerRiskLevelReq.IdBeginDate)
  266. if parseErr != nil {
  267. err = exception.New(exception.SyncAccountStatusError)
  268. h.FailedResult("身份证有效开始时间不合法["+syncCustomerRiskLevelReq.IdBeginDate+"]", result)
  269. return
  270. }
  271. idEndDate, parseErr := time.Parse(time.DateOnly, syncCustomerRiskLevelReq.IdEndDate)
  272. if parseErr != nil {
  273. err = exception.New(exception.SyncAccountStatusError)
  274. h.FailedResult("身份证有效结束时间不合法["+syncCustomerRiskLevelReq.IdEndDate+"]", result)
  275. return
  276. }
  277. if idEndDate.Before(idBeginDate) {
  278. err = exception.New(exception.SyncAccountStatusError)
  279. h.FailedResult("身份证有效结束时间不合法,开始日期不能大于结束日期", result)
  280. return
  281. }
  282. err = accountService.UpdateUserAccountOpenStatus(accountService.AccountStatusDTO{
  283. MobileTel: syncCustomerRiskLevelReq.MobileTel,
  284. ClientName: syncCustomerRiskLevelReq.ClientName,
  285. IdKind: syncCustomerRiskLevelReq.IdKind,
  286. IdNo: syncCustomerRiskLevelReq.IdNo,
  287. IdBeginDate: idBeginDate,
  288. IdEndDate: idEndDate,
  289. AccountStatus: string(syncCustomerRiskLevelReq.AccountStatus),
  290. ErrorMessage: syncCustomerRiskLevelReq.ErrorMessage,
  291. })
  292. if err != nil {
  293. logger.ErrorWithTraceId(h.Ctx, err.Error())
  294. h.FailedResult(err.Error(), result)
  295. err = exception.New(exception.SyncAccountStatusError)
  296. return
  297. }
  298. result = h.InitWrapData("同步开户信息成功")
  299. h.SuccessResult("success", syncCustomerRiskLevelReq, result)
  300. return
  301. })
  302. }
  303. // SyncCustomerIDInfo 证件信息同步接口
  304. // @Summary证件信息同步接口
  305. // @Description 证件信息同步接口
  306. // @Success 200 {object} controllers.BaseResponse
  307. // @router /v1/syncIDInfo/ [post]
  308. func (h *HTFuturesAccountController) SyncCustomerIDInfo() {
  309. controllers.WrapWebhook(&h.WebHookController, func() (result *controllers.WrapData, err error) {
  310. result = h.InitWrapData("证件有效期更新失败")
  311. syncCustomerRiskLevelReq := new(IDInfoReq)
  312. h.GetPostParams(syncCustomerRiskLevelReq)
  313. if ThirdRateLimitFilter(syncCustomerRiskLevelReq.IdNo) != 200 {
  314. err = exception.New(exception.TooManyRequest)
  315. h.FailedResult("接口请求太频繁,请稍后重试", result)
  316. return
  317. }
  318. if syncCustomerRiskLevelReq.MobileTel == "" {
  319. err = exception.New(exception.SyncIdInfoError)
  320. h.FailedResult("手机号码不能为空", result)
  321. return
  322. }
  323. if _, ok := idKindMap[syncCustomerRiskLevelReq.IdKind]; !ok {
  324. err = exception.New(exception.SyncIdInfoError)
  325. validIdKind := make([]string, 0)
  326. for _, v := range idKindMap {
  327. validIdKind = append(validIdKind, string(v))
  328. }
  329. h.FailedResult(fmt.Sprintf("证件类型不合法,当前只支持[%s]", strings.Join(validIdKind, ",")), result)
  330. return
  331. }
  332. if syncCustomerRiskLevelReq.IdNo == "" {
  333. err = exception.New(exception.SyncIdInfoError)
  334. h.FailedResult("证号号码不能为空", result)
  335. return
  336. }
  337. idBeginDate, parseErr := time.Parse(time.DateOnly, syncCustomerRiskLevelReq.IdBeginDate)
  338. if parseErr != nil {
  339. err = exception.New(exception.SyncIdInfoError)
  340. h.FailedResult("身份证有效开始时间不合法["+syncCustomerRiskLevelReq.IdBeginDate+"]", result)
  341. return
  342. }
  343. idEndDate, parseErr := time.Parse(time.DateOnly, syncCustomerRiskLevelReq.IdEndDate)
  344. if parseErr != nil {
  345. err = exception.New(exception.SyncIdInfoError)
  346. h.FailedResult("身份证有效结束时间不合法["+syncCustomerRiskLevelReq.IdEndDate+"]", result)
  347. return
  348. }
  349. if idEndDate.Before(idBeginDate) {
  350. err = exception.New(exception.SyncIdInfoError)
  351. h.FailedResult("身份证有效结束时间不合法,开始日期不能大于结束日期", result)
  352. return
  353. }
  354. err = accountService.UpdateUserIDINFO(accountService.IDInfoDTO{
  355. MobileTel: syncCustomerRiskLevelReq.MobileTel,
  356. IdKind: syncCustomerRiskLevelReq.IdKind,
  357. IdNo: syncCustomerRiskLevelReq.IdNo,
  358. IdBeginDate: idBeginDate,
  359. IdEndDate: idEndDate,
  360. })
  361. if err != nil {
  362. logger.ErrorWithTraceId(h.Ctx, err.Error())
  363. h.FailedResult(err.Error(), result)
  364. err = exception.New(exception.SyncIdInfoError)
  365. return
  366. }
  367. result = h.InitWrapData("同步证件有效期信息成功")
  368. h.SuccessResult("success", syncCustomerRiskLevelReq, result)
  369. return
  370. })
  371. }
  372. type SyncCustomerRiskLevelReq struct {
  373. CustInfo CustInfo `json:"custInfo"`
  374. RiskInfo RiskInfo `json:"riskInfo"`
  375. }
  376. type CustInfo struct {
  377. MobileTel string `json:"mobile_tel"`
  378. DealMobileTel string `json:"deal_mobile_tel"`
  379. ClientName string `json:"client_name"`
  380. IdKind string `json:"id_kind"`
  381. IdNo string `json:"id_no"`
  382. }
  383. type RiskInfo struct {
  384. CorpBeginDate string `json:"corp_begin_date"`
  385. CorpEndDate string `json:"corp_end_date"`
  386. UserInvestTerm string `json:"user_invest_term"`
  387. UserInvestKind string `json:"user_invest_kind"`
  388. CorpRiskLevel string `json:"corp_risk_level"`
  389. }
  390. type SyncCustomerAccountInfoReq struct {
  391. CustInfo CustInfo `json:"custInfo"`
  392. RiskInfo RiskInfo `json:"riskInfo"`
  393. }
  394. type AccountStatus string
  395. type IdKind string
  396. var (
  397. accountStatusMap = map[string]AccountStatus{
  398. "success": AccountStatusOpenSuccess,
  399. "failed": AccountStatusOpenFailed,
  400. }
  401. idKindMap = map[int]IdKind{
  402. 1: Id,
  403. }
  404. )
  405. const (
  406. AccountStatusOpenSuccess AccountStatus = "success"
  407. AccountStatusOpenFailed AccountStatus = "failed"
  408. Id IdKind = "身份证"
  409. )
  410. type AccountOpenInfoReq struct {
  411. MobileTel string `json:"mobile_tel"`
  412. //DealMobileTel string `json:"deal_mobile_tel"`
  413. ClientName string `json:"client_name"`
  414. IdKind int `json:"id_kind"`
  415. IdNo string `json:"id_no"`
  416. AccountStatus AccountStatus `json:"account_status"`
  417. //ErrorCode int `json:"error_code"`
  418. IdBeginDate string `json:"id_begin_date"`
  419. IdEndDate string `json:"id_end_date"`
  420. ErrorMessage string `json:"error_message"`
  421. Timestamp int64 `json:"timestamp"`
  422. }
  423. type IDInfoReq struct {
  424. MobileTel string `json:"mobile_tel"`
  425. IdKind int `json:"id_kind"`
  426. IdNo string `json:"id_no"`
  427. IdBeginDate string `json:"id_begin_date"`
  428. IdEndDate string `json:"id_end_date"`
  429. }