realname.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. package service
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "net/url"
  7. "strconv"
  8. "time"
  9. "go-common/app/job/main/member/conf"
  10. "go-common/app/job/main/member/model"
  11. memmodel "go-common/app/service/main/member/model"
  12. "go-common/library/log"
  13. "go-common/library/net/ip"
  14. "github.com/pkg/errors"
  15. )
  16. // constrs for gender
  17. const (
  18. _genderMale = "male"
  19. _genderFemale = "female"
  20. )
  21. // realname alipay polling
  22. func (s *Service) realnamealipaycheckproc() {
  23. defer func() {
  24. if x := recover(); x != nil {
  25. log.Error("%+v", errors.WithStack(fmt.Errorf("service.realnamealipaycheckproc panic(%v)", x)))
  26. go s.realnamealipaycheckproc()
  27. log.Info("service.realnamealipaycheckproc recover")
  28. }
  29. }()
  30. for {
  31. var (
  32. to = time.Now()
  33. from = to.Add(-2 * time.Duration(conf.Conf.Biz.RealnameAlipayCheckTick))
  34. expiredTime = from
  35. startTime = expiredTime.AddDate(0, -1, 0)
  36. )
  37. log.Info("realname alipay check start from : %s , to : %s", from, to)
  38. s.realnameAlipayCheckHandler(context.Background(), from, to)
  39. // to = from
  40. // from = to.Add(-2 * time.Duration(conf.Conf.Biz.RealnameAlipayCheckTick))
  41. log.Info("realname alipay handle expired end startTime : %s , expiredTime : %s", startTime, expiredTime)
  42. s.realnameAlipayExpiredHandler(context.Background(), startTime, expiredTime)
  43. time.Sleep(time.Duration(conf.Conf.Biz.RealnameAlipayCheckTick))
  44. }
  45. }
  46. // realnameAlipayCheckHandler 轮询时间段 [from,to] 中,未完成阿里实名的实名申请
  47. func (s *Service) realnameAlipayCheckHandler(c context.Context, from, to time.Time) {
  48. if conf.Conf.Biz.RealnameAlipayCheckLimit <= 0 {
  49. log.Error("conf.Conf.Property.realnameAlipayCheckHandler [%d] <= 0", conf.Conf.Biz.RealnameAlipayCheckLimit)
  50. return
  51. }
  52. var (
  53. applys = make([]*model.RealnameAlipayApply, conf.Conf.Biz.RealnameAlipayCheckLimit)
  54. startID int64
  55. err error
  56. )
  57. for len(applys) >= conf.Conf.Biz.RealnameAlipayCheckLimit {
  58. if startID, applys, err = s.dao.RealnameAlipayApplyList(c, startID, model.RealnameApplyStatusPending, from, to, conf.Conf.Biz.RealnameAlipayCheckLimit); err != nil {
  59. log.Error("%+v", err)
  60. return
  61. }
  62. for _, apply := range applys {
  63. log.Info("Start check realname alipay apply mid (%d) bizno (%s)", apply.MID, apply.Bizno)
  64. if err = s.realnameAlipayConfirm(c, apply); err != nil {
  65. log.Error("%+v", err)
  66. continue
  67. }
  68. }
  69. }
  70. for len(applys) >= conf.Conf.Biz.RealnameAlipayCheckLimit {
  71. if startID, applys, err = s.dao.RealnameAlipayApplyList(c, startID, model.RealnameApplyStatusBack, from, to, conf.Conf.Biz.RealnameAlipayCheckLimit); err != nil {
  72. log.Error("%+v", err)
  73. return
  74. }
  75. for _, apply := range applys {
  76. log.Info("Start check realname alipay apply mid (%d) bizno (%s)", apply.MID, apply.Bizno)
  77. if err = s.realnameAlipayConfirm(c, apply); err != nil {
  78. log.Error("%+v", err)
  79. continue
  80. }
  81. }
  82. }
  83. }
  84. func (s *Service) realnameAlipayConfirm(c context.Context, apply *model.RealnameAlipayApply) (err error) {
  85. if apply.Bizno == "" {
  86. return
  87. }
  88. var (
  89. pass bool
  90. reason string
  91. )
  92. if pass, reason, err = s.alipayQuery(c, apply.Bizno); err != nil {
  93. return
  94. }
  95. // rpc call
  96. var (
  97. rpcConfirmArg = &memmodel.ArgRealnameAlipayConfirm{
  98. MID: apply.MID,
  99. Pass: pass,
  100. Reason: reason,
  101. }
  102. )
  103. if err = s.memrpc.RealnameAlipayConfirm(c, rpcConfirmArg); err != nil {
  104. return
  105. }
  106. log.Info("Succeed to confirm realname alipay with arg: %+v", rpcConfirmArg)
  107. if pass {
  108. expArg := &model.AddExp{
  109. Mid: apply.MID,
  110. IP: ip.InternalIP(),
  111. Ts: time.Now().Unix(),
  112. Event: "identify",
  113. }
  114. if expErr := s.addExp(context.TODO(), expArg); expErr != nil {
  115. log.Error("realname exp error(%+v) ", expErr)
  116. return
  117. }
  118. log.Info("realname exp success(%+v)", expArg)
  119. }
  120. return
  121. }
  122. func (s *Service) alipayQuery(c context.Context, bizno string) (pass bool, reason string, err error) {
  123. var (
  124. param url.Values
  125. biz struct {
  126. Bizno string `json:"biz_no"`
  127. }
  128. )
  129. biz.Bizno = bizno
  130. if param, err = s.alipayParam("zhima.customer.certification.query", biz, ""); err != nil {
  131. return
  132. }
  133. if pass, reason, err = s.dao.AlipayQuery(c, param); err != nil {
  134. return
  135. }
  136. return
  137. }
  138. // alipayParam 构造阿里请求param,biz为 biz_content struct
  139. func (s *Service) alipayParam(method string, biz interface{}, returnURL string) (p url.Values, err error) {
  140. var (
  141. sign string
  142. bizBytes []byte
  143. )
  144. if bizBytes, err = json.Marshal(biz); err != nil {
  145. err = errors.WithStack(err)
  146. return
  147. }
  148. p = url.Values{}
  149. p.Set("app_id", conf.Conf.Biz.RealnameAlipayAppID)
  150. p.Set("method", method)
  151. p.Set("charset", "utf-8")
  152. p.Set("sign_type", "RSA2")
  153. p.Set("timestamp", time.Now().Format("2006-01-02 15:04:05"))
  154. p.Set("version", "1.0")
  155. p.Set("biz_content", string(bizBytes))
  156. if returnURL != "" {
  157. p.Set("return_url", returnURL)
  158. }
  159. if sign, err = s.alipayCryptor.SignParam(p); err != nil {
  160. return
  161. }
  162. p.Set("sign", sign)
  163. return
  164. }
  165. // rejectExpiredRealnameAlipay 自动驳回超过两天还没有通过芝麻认证的实名认证
  166. func (s *Service) realnameAlipayExpiredHandler(c context.Context, startTime, expiredTime time.Time) {
  167. if conf.Conf.Biz.RealnameAlipayCheckLimit <= 0 {
  168. log.Error("conf.Conf.Property.realnameAlipayCheckHandler [%d] <= 0", conf.Conf.Biz.RealnameAlipayCheckLimit)
  169. return
  170. }
  171. var (
  172. applys []*model.RealnameAlipayApply
  173. startID int64
  174. err error
  175. )
  176. // 每次查询(一个月里)100条过期的未处理的位处理的芝麻认证数据,进行驳回
  177. for {
  178. log.Info("realname handle startID (%d)", startID)
  179. startID, applys, err = s.dao.RealnameAlipayApplyList(c, startID, model.RealnameApplyStatusPending, startTime, expiredTime, conf.Conf.Biz.RealnameAlipayCheckLimit)
  180. if err != nil {
  181. log.Error("realnameAlipayExpiredHandler search err(%+v)", err)
  182. return
  183. }
  184. // 没有查询到预期的过期数据,则停止循环,等待下一次检查
  185. if len(applys) == 0 {
  186. log.Error("realnameAlipayExpiredHandler search no row in result")
  187. return
  188. }
  189. // 循环驳回验证超时的芝麻认证
  190. for _, apply := range applys {
  191. log.Info("Start expire realname alipay apply mid (%d) bizno (%s)", apply.MID, apply.Bizno)
  192. var (
  193. rpcConfirmArg = &memmodel.ArgRealnameAlipayConfirm{
  194. MID: apply.MID,
  195. Pass: false,
  196. Reason: "超时自动驳回",
  197. }
  198. )
  199. if err = s.memrpc.RealnameAlipayConfirm(c, rpcConfirmArg); err != nil {
  200. log.Error("realnameAlipayExpiredHandler reject err(%+v)", err)
  201. continue
  202. }
  203. }
  204. time.Sleep(10 * time.Millisecond)
  205. }
  206. }
  207. // ParseIdentity to birthday and gender
  208. func ParseIdentity(id string) (birthday time.Time, gender string, err error) {
  209. var (
  210. ystr, mstr, dstr, gstr string
  211. y, m, d, g int
  212. )
  213. switch len(id) {
  214. case 15:
  215. ystr, mstr, dstr = "19"+id[6:8], id[8:10], id[10:12]
  216. gstr = id[14:15]
  217. case 18:
  218. ystr, mstr, dstr = id[6:10], id[10:12], id[12:14]
  219. gstr = id[16:17]
  220. default:
  221. err = errors.Errorf("identity id invalid : %s", id)
  222. return
  223. }
  224. if y, err = strconv.Atoi(ystr); err != nil {
  225. err = errors.WithStack(err)
  226. return
  227. }
  228. if m, err = strconv.Atoi(mstr); err != nil {
  229. err = errors.WithStack(err)
  230. return
  231. }
  232. if d, err = strconv.Atoi(dstr); err != nil {
  233. err = errors.WithStack(err)
  234. return
  235. }
  236. if g, err = strconv.Atoi(gstr); err != nil {
  237. err = errors.WithStack(err)
  238. return
  239. }
  240. birthday = time.Date(y, time.Month(m), d, 0, 0, 0, 0, time.Local)
  241. if g%2 == 1 {
  242. gender = _genderMale
  243. } else {
  244. gender = _genderFemale
  245. }
  246. return
  247. }