htfutures_account_controller.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  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. type SyncCustomerRiskLevelReq struct {
  304. CustInfo CustInfo `json:"custInfo"`
  305. RiskInfo RiskInfo `json:"riskInfo"`
  306. }
  307. type CustInfo struct {
  308. MobileTel string `json:"mobile_tel"`
  309. DealMobileTel string `json:"deal_mobile_tel"`
  310. ClientName string `json:"client_name"`
  311. IdKind string `json:"id_kind"`
  312. IdNo string `json:"id_no"`
  313. }
  314. type RiskInfo struct {
  315. CorpBeginDate string `json:"corp_begin_date"`
  316. CorpEndDate string `json:"corp_end_date"`
  317. UserInvestTerm string `json:"user_invest_term"`
  318. UserInvestKind string `json:"user_invest_kind"`
  319. CorpRiskLevel string `json:"corp_risk_level"`
  320. }
  321. type SyncCustomerAccountInfoReq struct {
  322. CustInfo CustInfo `json:"custInfo"`
  323. RiskInfo RiskInfo `json:"riskInfo"`
  324. }
  325. type AccountStatus string
  326. type IdKind string
  327. var (
  328. accountStatusMap = map[string]AccountStatus{
  329. "success": AccountStatusOpenSuccess,
  330. "failed": AccountStatusOpenFailed,
  331. }
  332. idKindMap = map[int]IdKind{
  333. 1: Id,
  334. }
  335. )
  336. const (
  337. AccountStatusOpenSuccess AccountStatus = "success"
  338. AccountStatusOpenFailed AccountStatus = "failed"
  339. Id IdKind = "身份证"
  340. )
  341. type AccountOpenInfoReq struct {
  342. MobileTel string `json:"mobile_tel"`
  343. //DealMobileTel string `json:"deal_mobile_tel"`
  344. ClientName string `json:"client_name"`
  345. IdKind int `json:"id_kind"`
  346. IdNo string `json:"id_no"`
  347. AccountStatus AccountStatus `json:"account_status"`
  348. //ErrorCode int `json:"error_code"`
  349. IdBeginDate string `json:"id_begin_date"`
  350. IdEndDate string `json:"id_end_date"`
  351. ErrorMessage string `json:"error_message"`
  352. Timestamp int64 `json:"timestamp"`
  353. }