activity_service.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. package service
  2. import (
  3. "bytes"
  4. "database/sql"
  5. "encoding/json"
  6. "errors"
  7. "fmt"
  8. "io/ioutil"
  9. "log"
  10. "net/http"
  11. "strconv"
  12. "strings"
  13. "time"
  14. "xiaoniaokuaiyan.com/xiaoniao/config"
  15. "xiaoniaokuaiyan.com/xiaoniao/pay/wx"
  16. "gopkg.in/guregu/null.v3"
  17. "xiaoniaokuaiyan.com/xiaoniao/dal"
  18. "xiaoniaokuaiyan.com/xiaoniao/entity"
  19. "xiaoniaokuaiyan.com/xiaoniao/util"
  20. )
  21. type ActivityService struct {
  22. *WeixinService
  23. }
  24. func (srv *ActivityService) AddReporter(reporter *entity.ActReporter) (interface{}, error) {
  25. if !util.IsMobile(reporter.Mobile) {
  26. return nil, errors.New("wrong mobile phone number")
  27. }
  28. db := util.GetWriteSqlDB()
  29. reporter.CreatedAt = time.Now().Format("2006-01-02 15:04:05")
  30. strSql, mkv := util.GenerateInsertSqlFromStruct("t_activity_reporter", reporter)
  31. result, err := db.NamedExec(strSql, mkv)
  32. if err != nil {
  33. return nil, err
  34. }
  35. if ra, _ := result.RowsAffected(); ra <= 0 {
  36. return nil, errors.New("add failed")
  37. }
  38. return true, nil
  39. }
  40. func (srv *ActivityService) AddActInfo(item *entity.ActInfo) (interface{}, error) {
  41. db := util.GetWriteSqlDB()
  42. if strings.HasPrefix(item.Source, "-") {
  43. item.Source = item.Source[1:]
  44. strSql := "select count(*) from t_activity_info where mobile = ? and source = ?;"
  45. var tc int
  46. derr := db.Get(&tc, strSql, item.Mobile.String, item.Source)
  47. if derr != nil {
  48. return nil, derr
  49. }
  50. if tc > 0 {
  51. return nil, errors.New("1::already submit")
  52. }
  53. }
  54. var params = map[string]string{}
  55. if item.Extra.Valid && item.Extra.String != "" {
  56. err := json.Unmarshal([]byte(item.Extra.String), &params)
  57. if err != nil {
  58. return nil, err
  59. }
  60. }
  61. if item.Source == "medicine" || item.Source == "SendBack" || item.Source == "directbind" {
  62. smsSvc := &SMSService{
  63. ISMSCode: dal.DefaultSMSCodeDal,
  64. }
  65. _, err := smsSvc.ValidateCode(item.Mobile.String, params["vcode"], 8)
  66. if err != nil {
  67. return nil, errors.New("2::wrong validate code")
  68. }
  69. var bindTimes int
  70. var todayStr = time.Now().Format("2006-01-02")
  71. db.Get(&bindTimes, "SELECT count(distinct ex_code) from t_activity_info where mobile = ? and source =? and (created_at between ? and ?);", item.Mobile.String, item.Source, todayStr, todayStr+" 23:59:59")
  72. //20211127 从1 改成5
  73. if bindTimes >= 5 {
  74. return nil, errors.New("3::beyond binding times today")
  75. }
  76. }
  77. item.CreatedAt = time.Now().Format("2006-01-02 15:04:05")
  78. strSql, mkv := util.GenerateInsertSqlFromStruct("t_activity_info", item)
  79. result, err := db.NamedExec(strSql, mkv)
  80. if err != nil {
  81. return nil, err
  82. }
  83. if ra, _ := result.RowsAffected(); ra <= 0 {
  84. return nil, errors.New("add failed")
  85. }
  86. id, _ := result.LastInsertId()
  87. item.Id = int(id)
  88. //保存订单信息
  89. if item.Source == "medicine" || item.Source == "SendBack" {
  90. if !item.ExCode.Valid || item.ExCode.String == "" {
  91. //20220623 如果ExCode 是空,直接跳转结尾并且通知redis
  92. goto JUMP
  93. }
  94. var upItem = struct {
  95. CustomName string `db:"custom_name"`
  96. Mobile string `db:"mobile"`
  97. Age int `db:"age"`
  98. Birthday string `db:"birthday"`
  99. Gender string `db:"gender"`
  100. ExpressStatus string `db:"expressstatus"`
  101. }{}
  102. err = db.Get(&upItem, "select name as custom_name, gender, age, mobile,birthday, expressstatus from t_order t1 left join t_order_extra t2 on t1.id = t2.order_id where id = ?;", item.ExCode.String)
  103. if err != nil {
  104. //return nil, err
  105. //20220623 去除返回报错逻辑,直接跳转结尾并且通知redis
  106. goto JUMP
  107. }
  108. //20220520 修改生日逻辑
  109. var sqlResult sql.Result
  110. if _, ok := params["birthday"]; ok {
  111. btime, _ := time.Parse("2006-01-02", params["birthday"])
  112. age := time.Now().Year() - btime.Year()
  113. sqlResult, err = db.Exec("update t_order set name =?, gender =?, age =?, mobile =?, birthday =? where id = ?", item.CustomName.String, item.Gender.String, age, item.Mobile.String, params["birthday"], item.ExCode.String)
  114. if err != nil {
  115. } else if ra, _ := sqlResult.RowsAffected(); ra > 0 {
  116. go util.InsertMongo(item.ExCode.String, "回寄/活动", 1, map[string]interface{}{"name": item.CustomName.String, "gender": item.Gender.String, "age": age, "mobile": item.Mobile.String, "birthday": params["birthday"], "url": "/act/addinfo"})
  117. }
  118. } else {
  119. sqlResult, err = db.Exec("update t_order set name =?, mobile =? where id = ?", item.CustomName.String, item.Mobile.String, item.ExCode.String)
  120. if err != nil {
  121. } else if ra, _ := sqlResult.RowsAffected(); ra > 0 {
  122. go util.InsertMongo(item.ExCode.String, "回寄/活动", 1, map[string]interface{}{"name": item.CustomName.String, "mobile": item.Mobile.String, "url": "/act/addinfo"})
  123. }
  124. }
  125. //20220704 熠保项目 修改 blood_code
  126. sqlResult, _ = db.Exec("update t_order set blood_codes =? where id = ? and (trim(blood_codes)='' or blood_codes is null)", item.Address.String, item.ExCode.String)
  127. if ra, _ := sqlResult.RowsAffected(); ra > 0 {
  128. go util.InsertMongo(item.ExCode.String, "回寄/活动", 1, map[string]interface{}{"blood_codes": item.Address.String, "url": "/act/addinfo"})
  129. db.Exec("insert into t_activity_info(custom_name,age,gender,mobile,address,ex_code,source,created_at) values(?,?,?,?,?,?,'order_update',?);", upItem.CustomName, upItem.Age, upItem.Gender, upItem.Mobile, upItem.Birthday, item.ExCode.String, item.CreatedAt)
  130. }
  131. }
  132. JUMP:
  133. //推送消息
  134. msg := map[string]string{
  135. "user": "system",
  136. "oper": "add",
  137. "source": item.Source,
  138. }
  139. buf, _ := json.Marshal(msg)
  140. client := util.GetRedis()
  141. client.Publish("act-change", string(buf))
  142. return item, nil
  143. }
  144. func (srv *ActivityService) GetActInfo(mobile string, source string) (interface{}, error) {
  145. var strSql = "select * from t_activity_info where mobile = ? and source = ?;"
  146. if source == "BCODE" {
  147. return _getActInfoByBloodcode(mobile)
  148. } else if source == "fapiao" || source == "daneng" || source == "renbao" {
  149. return _getActInfoByExCode(mobile)
  150. }
  151. var infos = []entity.ActInfo{}
  152. db := util.GetSqlDB()
  153. err := db.Select(&infos, strSql, mobile, source)
  154. if err != nil {
  155. return nil, fmt.Errorf("failed to query actinfo: %v", err)
  156. }
  157. return infos, nil
  158. }
  159. func _getActInfoByBloodcode(bcode string) (interface{}, error) {
  160. strSql := "select * from t_activity_info where address = ? order by id desc;"
  161. var infos = []entity.ActInfo{}
  162. db := util.GetSqlDB()
  163. err := db.Select(&infos, strSql, bcode)
  164. if err != nil {
  165. return nil, fmt.Errorf("failed to query actinfo: %v", err)
  166. }
  167. return infos, nil
  168. }
  169. // qz add 添加按照excode 查询,20200810
  170. // qz add 添加人保 按照excode 查询 20210629
  171. func _getActInfoByExCode(exCode string) (interface{}, error) {
  172. strSql := "select * from t_activity_info where ex_code = ? order by id desc;"
  173. var infos = []entity.ActInfo{}
  174. db := util.GetSqlDB()
  175. err := db.Select(&infos, strSql, exCode)
  176. if err != nil {
  177. return nil, fmt.Errorf("failed to query actinfo: %v", err)
  178. }
  179. return infos, nil
  180. }
  181. func (src *ActivityService) UpdateActInfo(item *entity.ActInfo) (interface{}, error) {
  182. var params = map[string]string{}
  183. if item.Extra.Valid && item.Extra.String != "" {
  184. err := json.Unmarshal([]byte(item.Extra.String), &params)
  185. if err != nil {
  186. return nil, err
  187. }
  188. }
  189. if item.Source == "fapiao" || item.Source == "daneng" {
  190. smsSvc := &SMSService{
  191. ISMSCode: dal.DefaultSMSCodeDal,
  192. }
  193. _, err := smsSvc.ValidateCode(item.Mobile.String, params["vcode"], 9)
  194. if err != nil {
  195. return nil, errors.New("2::wrong validate code")
  196. }
  197. }
  198. var source = item.Source
  199. item.Source = ""
  200. strSql, mkv := util.GenerateUpdateSqlFromStruct("t_activity_info", item, fmt.Sprintf(" where id =%d", item.Id))
  201. db := util.GetWriteSqlDB()
  202. _, err := db.NamedExec(strSql, mkv)
  203. if err != nil {
  204. return nil, err
  205. }
  206. if source == "SendBack" && item.ExCode.Valid {
  207. return _updateSendBack(item)
  208. }
  209. return false, nil
  210. }
  211. //func _updateSendBack(item *entity.ActInfo) (interface{}, error) {
  212. // var params = map[string]string{}
  213. // if item.Extra.Valid && item.Extra.String != "" {
  214. // err := json.Unmarshal([]byte(item.Extra.String), &params)
  215. // if err != nil {
  216. // return nil, err
  217. // }
  218. // }
  219. // var expressStatus string
  220. // db := util.GetWriteSqlDB()
  221. // err := db.Get(&expressStatus, "select expressstatus from t_order_extra where order_id = ?;", item.ExCode.String)
  222. // if err != nil {
  223. // return nil, err
  224. // }
  225. // //20220518 外面source 给洗掉了,而且外面判断sendback了,所以这里去掉sendback判断
  226. // //if item.Source == "SendBack" && (expressStatus == "200" || expressStatus == "100") {
  227. // if expressStatus == "200" || expressStatus == "100" {
  228. // db.Exec("update t_order_extra set expressstatus='300', express_user=?, expressnumber_user=? where order_id = ?;", params["express"], params["expressno"], item.ExCode.String)
  229. // }
  230. // return true, nil
  231. //}
  232. func _updateSendBack(item *entity.ActInfo) (interface{}, error) {
  233. var params = map[string]string{}
  234. if item.Extra.Valid && item.Extra.String != "" {
  235. err := json.Unmarshal([]byte(item.Extra.String), &params)
  236. if err != nil {
  237. return nil, err
  238. }
  239. }
  240. var data struct {
  241. ExpressStatus string `db:"expressstatus"`
  242. ExpressTime null.String `db:"express_time"`
  243. }
  244. db := util.GetWriteSqlDB()
  245. err := db.Get(&data, "select expressstatus,express_time from t_order_extra where order_id = ?;", item.ExCode.String)
  246. if err != nil {
  247. return nil, err
  248. }
  249. //20220518 外面source 给洗掉了,而且外面判断sendback了,所以这里去掉sendback判断
  250. if data.ExpressStatus == "200" || data.ExpressStatus == "100" {
  251. //20220519 修改原来改成状态300 换成改为210 同时判断extra 里面是否有sendStartTime 更新到express_time 字段中
  252. db.Exec("update t_order_extra set expressstatus='210', express_user=?, expressnumber_user=? where order_id = ?;", params["express"], params["expressno"], item.ExCode.String)
  253. sst, ok := params["sendStartTime"]
  254. if !ok {
  255. sst = time.Now().Format("2006-01-02 15:04:05")
  256. }
  257. if !data.ExpressTime.Valid || data.ExpressTime.String == "" {
  258. db.Exec("update t_order_extra set express_time = ? where order_id = ?;", fmt.Sprintf("{\"setStartTime\": \"%s\"}", sst), item.ExCode.String)
  259. } else {
  260. _, err := db.Exec("update t_order_extra set express_time = JSON_SET(express_time,'$.setStartTime','"+sst+"') where order_id = ?;", item.ExCode.String)
  261. fmt.Println(err)
  262. }
  263. }
  264. return true, nil
  265. }
  266. func (srv *ActivityService) WithdrawActInfo(item *entity.ActInfo) (interface{}, error) {
  267. //根据id 获取信息
  268. var strSql = "select * from t_activity_info where id=? and source in ('fapiao','daneng') and status='500'"
  269. var infos = entity.ActInfo{}
  270. db := util.GetSqlDB()
  271. err := db.Get(&infos, strSql, item.Id)
  272. if err != nil {
  273. return nil, fmt.Errorf("1::failed to query actinfo: %v", err)
  274. }
  275. var params = map[string]string{}
  276. if infos.Extra.Valid && infos.Extra.String != "" {
  277. err := json.Unmarshal([]byte(infos.Extra.String), &params)
  278. if err != nil {
  279. return nil, err
  280. }
  281. }
  282. if params["openid"] == "" || params["price"] == "" {
  283. return nil, fmt.Errorf("2::none openid [%s], or price: [%s]", params["openid"], params["price"])
  284. }
  285. _, err = strconv.ParseInt(params["price"], 10, 64)
  286. if err != nil {
  287. return nil, fmt.Errorf("3::price: [%s] not real int ", params["price"])
  288. }
  289. strSql = "update t_activity_info set status = '600' where id = ? "
  290. tx := db.MustBegin()
  291. sqlResult, err := tx.Exec(strSql, item.Id)
  292. if err != nil {
  293. return false, err
  294. }
  295. if la, err := sqlResult.RowsAffected(); la <= 0 {
  296. return false, err
  297. }
  298. wxJsSdk := wx.NewJsSdk()
  299. weixin := wx.NewWeixin(wx.DefaultConfig["appid"], wx.DefaultConfig["secret"])
  300. nonceStr := wxJsSdk.GenerateNoncestr(32)
  301. billno := fmt.Sprintf("HB%s%s", time.Now().Format("20060102150405"), util.RandNumString(6))
  302. reqItem := map[string]string{
  303. "mch_id": wx.DefaultConfig["mch_id"],
  304. "nonce_str": nonceStr,
  305. "mch_billno": billno,
  306. "wxappid": wx.DefaultConfig["appid"],
  307. "send_name": "小鸟快验",
  308. "re_openid": params["openid"],
  309. "total_amount": params["price"],
  310. "total_num": "1",
  311. "wishing": "报销费用",
  312. "client_ip": "127.0.0.1",
  313. "act_name": "红包提现",
  314. "remark": "readpack",
  315. "scene_id": "PRODUCT_4",
  316. }
  317. sign := wxJsSdk.ComputePaySignature(reqItem, wx.DefaultConfig["apikey"])
  318. reqItem["sign"] = sign
  319. rel, err := weixin.SendRedpack(reqItem, wx.DefaultConfig["cert_file"], wx.DefaultConfig["key_file"])
  320. log.Println(rel)
  321. str := ""
  322. if err != nil {
  323. log.Println(err)
  324. str = err.Error()
  325. } else {
  326. arrayByte, _ := json.Marshal(rel)
  327. str = string(arrayByte)
  328. }
  329. if rel["return_code"] == "SUCCESS" && rel["result_code"] == "SUCCESS" {
  330. tx.Exec("insert into t_activity_withdraw_record(billno, money, activity_id,openid,result,is_success) values(?,?,?,?,?,1);", billno, params["price"], item.Id, params["openid"], str)
  331. //tx.Exec("insert into t_deliver_msg(deliver_user_id, title, content,created_at) values(?,?,?,?);", duId, "余额提取成功", fmt.Sprintf("您于%s成提取%d元,系统以微信红包的形式发送至您的微信账号,注意查收。", time.Now().Format("2006-01-02"), money/100), time.Now().Format("2006-01-02 15:04:05"))
  332. tx.Commit()
  333. } else {
  334. tx.Tx.Rollback()
  335. db.Exec("insert into t_activity_withdraw_record(billno, money, activity_id,openid,result,is_success) values(?,?,?,?,?,0);", billno, params["price"], item.Id, params["openid"], str)
  336. errCode := 0
  337. var errMsg string
  338. switch rel["err_code"] {
  339. case "NO_AUTH":
  340. errCode = 10
  341. errMsg = "发放失败,此请求可能存在风险,已被微信拦截"
  342. case "SENDNUM_LIMIT":
  343. errCode = 11
  344. errMsg = "该用户今日领取红包个数超过限制"
  345. case "ILLEGAL_APPID":
  346. errCode = 13
  347. errMsg = "非法appid,请确认是否为公众号的appid,不能为APP的appid"
  348. case "MONEY_LIMIT":
  349. errCode = 14
  350. errMsg = "红包金额发放限制"
  351. case "SEND_FAILED":
  352. errCode = 15
  353. errMsg = "红包发放失败,请更换单号再重试"
  354. case "FATAL_ERROR":
  355. errCode = 16
  356. errMsg = "openid和原始单参数不一致"
  357. case "CA_ERROR":
  358. errCode = 17
  359. errMsg = "商户API证书校验出错"
  360. case "SIGN_ERROR":
  361. errCode = 18
  362. errMsg = "签名错误"
  363. case "SYSTEMERROR":
  364. errCode = 19
  365. errMsg = "请求已受理,请稍后使用原单号查询发放结果"
  366. case "XML_ERROR":
  367. errCode = 20
  368. errMsg = "输入xml参数格式错误"
  369. case "FREQ_LIMIT":
  370. errCode = 21
  371. errMsg = "超过频率限制,请稍后再试"
  372. case "API_METHOD_CLOSED":
  373. errCode = 22
  374. errMsg = "你的商户号API发放方式已关闭,请联系管理员在商户平台开启"
  375. case "NOTENOUGH":
  376. errCode = 23
  377. errMsg = "帐号余额不足,请到商户平台充值后再重试"
  378. case "OPENID_ERROR":
  379. errCode = 24
  380. errMsg = "openid和appid不匹配"
  381. case "MSGAPPID_ERROR":
  382. errCode = 25
  383. errMsg = "触达消息给用户appid有误"
  384. case "ACCEPTMODE_ERROR":
  385. errCode = 26
  386. errMsg = "主、子商户号关系校验失败"
  387. case "PROCESSING":
  388. errCode = 27
  389. errMsg = "请求已受理,请稍后使用原单号查询发放结果"
  390. case "PARAM_ERROR":
  391. errCode = 28
  392. errMsg = "参数错误"
  393. case "SENDAMOUNT_LIMIT":
  394. errCode = 29
  395. errMsg = "您的商户号今日发放金额超过限制,如有需要请登录微信支付商户平台更改API安全配置"
  396. case "RCVDAMOUNT_LIMIT":
  397. errCode = 30
  398. errMsg = "该用户今日领取金额超过限制,如有需要请登录微信支付商户平台更改API安全配置"
  399. default:
  400. errCode = 4
  401. errMsg = fmt.Sprintf("failure withdraw , check db for more information with billno [%s]", billno)
  402. }
  403. return nil, fmt.Errorf("%d::[%s]", errCode, errMsg)
  404. //return false,nil
  405. }
  406. return true, nil
  407. }
  408. // 20220505 开票
  409. func (srv *ActivityService) AddInvoice(item *entity.ActInfo) (interface{}, error) {
  410. //todo 查询是否有开票item.excode
  411. count, err := GetInvoiceCount(item.ExCode.String)
  412. if err != nil || count > 0 {
  413. return nil, fmt.Errorf("1::already fapiao record")
  414. }
  415. url := config.IniConf.Section("server").Key("fapiaoapi").String()
  416. param := map[string]string{}
  417. err = json.Unmarshal([]byte(item.Extra.String), &param)
  418. if !item.Extra.Valid || err != nil {
  419. return nil, fmt.Errorf("2::data extra error")
  420. }
  421. param["order_id"] = item.ExCode.String
  422. db := util.GetSqlDB()
  423. var price int
  424. db.Get(&price, "select actual_payment from t_order where id = ?", item.ExCode.String)
  425. if price == 0 {
  426. return nil, fmt.Errorf("3::payment is 0")
  427. }
  428. param["price"] = strconv.FormatFloat(float64(price)/100, 'f', -1, 64)
  429. path := "/fp/send"
  430. b, err := json.Marshal(param)
  431. reader := bytes.NewReader(b)
  432. resp, err := http.Post(url+path, "application/json", reader)
  433. if err != nil {
  434. return nil, fmt.Errorf("4::send response error %s", err.Error())
  435. }
  436. r, err := ioutil.ReadAll(resp.Body)
  437. if err != nil {
  438. return nil, fmt.Errorf("5::response read error %s", err.Error())
  439. }
  440. defer resp.Body.Close()
  441. result := struct {
  442. Code int `json:"code"`
  443. Msg string `json:"msg"`
  444. }{}
  445. err = json.Unmarshal(r, &result)
  446. if err != nil || result.Code != 0 {
  447. return nil, fmt.Errorf("6::response Unmarshal error %s", string(r))
  448. }
  449. return "success", nil
  450. }
  451. // 20220505 获取开票
  452. func GetInvoiceCount(oid string) (int, error) {
  453. db := util.GetSqlDB()
  454. var count int
  455. //err:=db.Get(&count,"select count(1) from t_fapiao_trd where order_id = ? and status !=4",oid)
  456. //这里不做状态判断,如果提交过,不论成功失败,不可重复提交,后续问题交由财务或开发处理
  457. err := db.Get(&count, "select count(1) from t_fapiao_trd where order_id = ? ", oid)
  458. return count, err
  459. }
  460. func (srv *ActivityService) GetInvoice(oid string) ([]entity.ActInfo, error) {
  461. db := util.GetSqlDB()
  462. data := struct {
  463. Type string `json:"type"`
  464. Title string `json:"title"`
  465. Num string `json:"num"`
  466. Email string `json:"email"`
  467. }{}
  468. //20220524 防止之前开票过,这次又开票
  469. var strSql = "select * from t_activity_info where ex_code = ? and source = ?;"
  470. var infos = []entity.ActInfo{}
  471. db.Select(&infos, strSql, oid, "invoice")
  472. if len(infos) > 0 {
  473. return infos, nil
  474. }
  475. err := db.Get(&data, "select type,title,tax_num as num,email from t_fapiao_trd where order_id = ? order by created_at desc limit 1", oid)
  476. if err != nil {
  477. return nil, fmt.Errorf("failed to query invoice: %v", err)
  478. }
  479. b, _ := json.Marshal(data)
  480. return []entity.ActInfo{{
  481. ExCode: null.StringFrom(oid),
  482. Extra: null.StringFrom(string(b)),
  483. }}, nil
  484. }