merchant.active.config.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872
  1. package shanghu
  2. import (
  3. "duoduo/apis/common"
  4. "duoduo/apis/pdd"
  5. "duoduo/apis/shanghu/models"
  6. "duoduo/models/shanghu"
  7. "duoduo/tools"
  8. "duoduo/tools/app"
  9. "encoding/base64"
  10. "encoding/json"
  11. "errors"
  12. "fmt"
  13. "github.com/gin-gonic/gin"
  14. "github.com/go-pay/gopay"
  15. "github.com/go-pay/gopay/wechat"
  16. "github.com/shopspring/decimal"
  17. "math/rand"
  18. "net/http"
  19. "strconv"
  20. "time"
  21. )
  22. // 一个活动对应一个抽奖,一个抽奖对应多个奖品
  23. // 一个活动对应多个拼团,一个拼团对应一个张主图,一个拼团对应多个商品(多个商品是为了核销)
  24. func ActiveConfigCreate(c *gin.Context) {
  25. var inData models.CreateActiveConfigRequest
  26. var sqlData shanghu.MerchantActiveConfig
  27. var drawProduct shanghu.MerchantActiveDrawProduct
  28. err := c.ShouldBindJSON(&inData)
  29. if err != nil {
  30. app.Error(c, 400, err, err.Error())
  31. return
  32. }
  33. if inData.DrawMode != 0 {
  34. if len(inData.DrawId) <= 0 {
  35. app.Error(c, 500, errors.New("奖品未配置"), "奖品未配置")
  36. return
  37. }
  38. //校验总概率 总概率相加不能大于100
  39. drawList, _, err := drawProduct.GetDrawProductListById(inData.DrawId)
  40. if err != nil {
  41. app.Error(c, 500, err, err.Error())
  42. return
  43. }
  44. sumOdds := 0
  45. for _, v := range drawList {
  46. sumOdds = sumOdds + v.DrawOdds
  47. }
  48. if sumOdds != 100 {
  49. app.Error(c, 500, errors.New("配置的总中奖率不满100%"), "配置的总中奖率不满100%")
  50. return
  51. }
  52. }
  53. if inData.GroupBuyMode == 0 && inData.DrawMode == 0 {
  54. app.Error(c, 500, errors.New("请选择抽奖与开团"), "请选择抽奖与开团")
  55. return
  56. }
  57. sqlData.ActivityEndTime, err = tools.TimeToInt64(inData.ActivityEndTime, "2006-01-02")
  58. if err != nil {
  59. app.Error(c, 400, err, err.Error())
  60. return
  61. }
  62. sqlData.ActivityStartTime, err = tools.TimeToInt64(inData.ActivityStartTime, "2006-01-02")
  63. if err != nil {
  64. app.Error(c, 400, err, err.Error())
  65. return
  66. }
  67. //必中校验
  68. //if inData.DrawOneBiZhong > 0 {
  69. // var checkBZ shanghu.MerchantActiveDrawProduct
  70. // checkBZ.ID = inData.DrawOneBiZhong
  71. // bZInfo, err := checkBZ.GetDrawProductById()
  72. // if err != nil {
  73. // app.Error(c, 500, err, err.Error())
  74. // return
  75. // }
  76. //
  77. // if !bZInfo.IsPrize { //
  78. // app.Error(c, 500, err, err.Error())
  79. // return
  80. // }
  81. //}
  82. sqlData.ActiveName = inData.ActiveName
  83. sqlData.MerchantOpenID = inData.MerchantOpenID
  84. sqlData.CreatedAt = time.Now()
  85. sqlData.UpdatedAt = time.Now()
  86. sqlData.ConfigMode = 1
  87. sqlData.DrawOneBiZhong = inData.DrawOneBiZhong
  88. sqlData.DrawMode = inData.DrawMode
  89. sqlData.GroupBuyMode = inData.GroupBuyMode
  90. sqlData.GroupBuyUrl = inData.GroupBuyUrl
  91. sqlData.GroupBuy = `{}`
  92. sqlData.DrawProduct = `{}`
  93. sqlData.BackgroundImage = inData.BackgroundImage
  94. configData, err := sqlData.Create()
  95. if err != nil {
  96. app.Error(c, 500, err, err.Error())
  97. return
  98. }
  99. for _, v := range inData.DrawId {
  100. var drawData shanghu.MerchantActiveDrawProduct
  101. drawData.ActiveConfigID = configData.ID
  102. err = drawData.UpdateConfigId(v)
  103. if err != nil {
  104. app.Error(c, 500, err, err.Error())
  105. return
  106. }
  107. }
  108. for _, v := range inData.GroupBuyId {
  109. var groupBuy shanghu.MerchantActiveGroupBuy
  110. groupBuy.ActiveConfigID = configData.ID
  111. err = groupBuy.UpdateConfigId(v)
  112. if err != nil {
  113. app.Error(c, 500, err, err.Error())
  114. return
  115. }
  116. }
  117. app.OK(c, nil, app.Success)
  118. }
  119. // 活动配置信息
  120. func ActiveConfigInfo(c *gin.Context) {
  121. var inData models.ActiveConfigRequest
  122. var sqlData shanghu.MerchantActiveConfig
  123. var outData models.ActiveConfigReply
  124. var drawInfoSql shanghu.MerchantActiveDrawProduct
  125. var groupBuy shanghu.MerchantActiveGroupBuy
  126. var merchant shanghu.Merchant
  127. err := c.ShouldBindJSON(&inData)
  128. if err != nil {
  129. app.Error(c, 400, err, err.Error())
  130. return
  131. }
  132. sqlData.MerchantOpenID = inData.MerchantOpenID
  133. sqlData.ID = inData.ActiveConfigId
  134. configInfo, err := sqlData.GetConfigInfoById()
  135. if err != nil {
  136. app.Error(c, 500, err, err.Error())
  137. return
  138. }
  139. outData.GroupBuyMode = configInfo.GroupBuyMode
  140. outData.DrawMode = configInfo.DrawMode
  141. outData.GroupBuyUrl = configInfo.GroupBuyUrl
  142. outData.DrawOneBiZhong = configInfo.DrawOneBiZhong
  143. outData.ActivityEndTime = tools.TimeToStr(configInfo.ActivityEndTime)
  144. outData.ActivityStartTime = tools.TimeToStr(configInfo.ActivityStartTime)
  145. outData.ActiveName = configInfo.ActiveName
  146. outData.BackgroundImage = configInfo.BackgroundImage
  147. //中奖商品
  148. drawInfoSql.ActiveConfigID = configInfo.ID
  149. drawInfo, _, err := drawInfoSql.GetDrawProductList()
  150. if err != nil {
  151. app.Error(c, 500, err, err.Error())
  152. return
  153. }
  154. for _, v := range drawInfo {
  155. var drawProduct models.DrawProduct
  156. drawProduct.DrawProductName = v.DrawProductName
  157. drawProduct.DrawUrl = v.DrawUrl
  158. drawProduct.DrawOdds = v.DrawOdds
  159. drawProduct.IsPrize = v.IsPrize
  160. drawProduct.TotalStock = v.TotalStock
  161. drawProduct.Stock = v.Stock
  162. outData.DrawProduct = append(outData.DrawProduct, drawProduct)
  163. }
  164. // 查询拼团列表
  165. groupBuy.ActiveConfigID = configInfo.ID
  166. groupBuyInfoList, _, err := groupBuy.GetGroupBuyList()
  167. if err != nil {
  168. app.Error(c, 500, err, err.Error())
  169. return
  170. }
  171. for _, v := range groupBuyInfoList {
  172. var groupBuyInfo models.DrawGroupBuy
  173. var groupBuyProject shanghu.MerchantActiveGroupByProject
  174. groupBuyInfo.GroupBuyName = v.GroupBuyName
  175. groupBuyInfo.GroupBuyMode = v.GroupBuyMode
  176. groupBuyInfo.GroupBuyUrl = v.GroupBuyUrl
  177. groupBuyInfo.GroupBuyThreeNum = v.GroupBuyThreeNum
  178. groupBuyInfo.GroupBuyThreePrice = v.GroupBuyThreePrice
  179. groupBuyInfo.GroupBuyFourNum = v.GroupBuyFourNum
  180. groupBuyInfo.GroupBuyFourPrice = v.GroupBuyFourPrice
  181. groupBuyInfo.GroupBuyTwoNum = v.GroupBuyTwoNum
  182. groupBuyInfo.GroupBuyTwoPrice = v.GroupBuyTwoPrice
  183. groupBuyInfo.GroupBuyOneNum = v.GroupBuyOneNum
  184. groupBuyInfo.GroupBuyOnePrice = v.GroupBuyOnePrice
  185. groupBuyInfo.MerchantOpenID = v.MerchantOpenID
  186. groupBuyInfo.OriginalPrice = v.OriginalPrice
  187. groupBuyInfo.RebateRate = v.RebateRate
  188. groupBuyInfo.MaxRebatePrice = v.GroupBuyOnePrice.Mul(decimal.NewFromInt32(int32(v.RebateRate)).Div(decimal.NewFromInt32(100)))
  189. groupBuyProject.GroupBuyID = v.ID
  190. projectList, _, err := groupBuyProject.GetGroupBuyProjectList()
  191. if err != nil {
  192. app.Error(c, 500, err, err.Error())
  193. return
  194. }
  195. for _, v := range projectList {
  196. var groupBuyProjectInfo models.GroupBuyProject
  197. groupBuyProjectInfo.ProjectName = v.ProjectName
  198. groupBuyProjectInfo.CancelNum = v.CancelNum
  199. groupBuyInfo.GroupBuyProject = append(groupBuyInfo.GroupBuyProject, groupBuyProjectInfo)
  200. }
  201. outData.DrawGroupBuy = append(outData.DrawGroupBuy, groupBuyInfo)
  202. }
  203. merchant.OpenId = inData.MerchantOpenID
  204. merchantInfo, err := merchant.GetMerchant()
  205. if err != nil {
  206. app.Error(c, 500, err, err.Error())
  207. return
  208. }
  209. outData.MerchantName = merchantInfo.MerchantName
  210. app.OK(c, outData, app.Success)
  211. }
  212. // whxy
  213. func UpdateActiveConfigWHXY(c *gin.Context) {
  214. var inData models.ActiveConfigWHXYRequest
  215. var sqlData shanghu.MerchantActiveConfig
  216. var whxy []models.WHXYStr
  217. err := c.ShouldBindJSON(&inData)
  218. if err != nil {
  219. app.Error(c, 400, err, err.Error())
  220. return
  221. }
  222. err = json.Unmarshal([]byte(inData.WHXY), &whxy)
  223. if err != nil {
  224. app.Error(c, 400, err, err.Error())
  225. return
  226. }
  227. for i := 0; i < len(whxy); i++ {
  228. if !whxy[i].Y.IsZero() {
  229. sqlData.W = whxy[i].W.String()
  230. sqlData.X = whxy[i].X.String()
  231. sqlData.Y = whxy[i].Y.String()
  232. sqlData.H = whxy[i].H.String()
  233. }
  234. }
  235. sqlData.ID = inData.ActiveConfigId
  236. err = sqlData.UpdateMerchantWHXY()
  237. if err != nil {
  238. app.Error(c, 400, err, err.Error())
  239. return
  240. }
  241. app.OK(c, nil, app.Success)
  242. }
  243. // 活动列表
  244. func ActiveConfigList(c *gin.Context) {
  245. var inData models.ActiveConfigListRequest
  246. var sqlData shanghu.MerchantActiveConfig
  247. var outData []models.ActiveConfigListReply
  248. err := c.ShouldBindJSON(&inData)
  249. if err != nil {
  250. app.Error(c, 400, err, err.Error())
  251. return
  252. }
  253. sqlData.MerchantOpenID = inData.OpenId
  254. var pageSize = 10
  255. var pageIndex = 1
  256. if inData.PageSize != 0 {
  257. pageSize = inData.PageSize
  258. }
  259. if inData.PageIndex != 0 {
  260. pageIndex = inData.PageIndex
  261. }
  262. activeConfigList, count, err := sqlData.GetActiveConfigList(pageSize, pageIndex)
  263. if err != nil {
  264. app.Error(c, 500, err, err.Error())
  265. return
  266. }
  267. for _, v := range activeConfigList {
  268. var activeConfig models.ActiveConfigListReply
  269. activeConfig.ID = v.ID
  270. activeConfig.ActivityStart = tools.TimeToStr(v.ActivityStartTime)
  271. activeConfig.ActivityEnd = tools.TimeToStr(v.ActivityEndTime)
  272. activeConfig.ActiveName = v.ActiveName
  273. activeConfig.CreatedAt = v.CreatedAt.Format(time.DateTime)
  274. outData = append(outData, activeConfig)
  275. }
  276. app.PageOK(c, outData, count, pageIndex, pageSize, app.Success)
  277. }
  278. // 抽奖
  279. func Draw(c *gin.Context) {
  280. var inData models.DrawRequest
  281. var sqlData shanghu.MerchantActiveConfig
  282. var drawNumSql shanghu.ClientActiveDrawNum
  283. var draw shanghu.ClientActiveDrawLog
  284. var outData models.DrawReply
  285. err := c.ShouldBindJSON(&inData)
  286. if err != nil {
  287. app.Error(c, 400, err, err.Error())
  288. return
  289. }
  290. // 校验抽奖次数
  291. drawNumSql.ActiveConfigID = inData.ActiveConfigID
  292. drawNumSql.ClientOpenID = inData.ClientOpenID
  293. drawNum, err := drawNumSql.GetDrawNum()
  294. if err != nil {
  295. app.Error(c, 500, err, err.Error())
  296. return
  297. }
  298. //校验数量
  299. draw.ActiveConfigID = inData.ActiveConfigID
  300. draw.ClientOpenID = inData.ClientOpenID
  301. clientDrawNum, err := draw.GetClientActiveDrawLogNum()
  302. if err != nil {
  303. app.Error(c, 500, err, err.Error())
  304. return
  305. }
  306. if drawNum+1 < clientDrawNum {
  307. app.Error(c, 500, errors.New("抽奖次数用完"), "抽奖次数用完")
  308. return
  309. }
  310. // 先校验是否有必中抽奖
  311. sqlData.ID = inData.ActiveConfigID
  312. config, err := sqlData.GetConfigInfoById()
  313. if err != nil {
  314. app.Error(c, 500, err, err.Error())
  315. return
  316. }
  317. if config.DrawOneBiZhong > 0 {
  318. // 必中抽奖需要产看中奖记录是否中过,没有中过直接中,中过了走正常的中奖概率
  319. var drawConfig shanghu.ClientActiveDrawLog
  320. drawConfig.ActiveConfigID = inData.ActiveConfigID
  321. drawConfig.ClientOpenID = inData.ClientOpenID
  322. drawConfig.DrawProductID = config.DrawOneBiZhong
  323. count, err := drawConfig.GetClientActiveDrawLogByBiZHong()
  324. if err != nil {
  325. app.Error(c, 500, err, err.Error())
  326. return
  327. }
  328. // 为0直接中奖 写中奖记录并且返回 查询中奖
  329. if count == 0 {
  330. //var draw shanghu.ClientActiveDrawLog
  331. var drawProduct shanghu.MerchantActiveDrawProduct
  332. drawProduct.ID = config.DrawOneBiZhong
  333. drawProductInfo, err := drawProduct.GetDrawProductById()
  334. if err != nil {
  335. app.Error(c, 500, err, err.Error())
  336. return
  337. }
  338. if drawProductInfo.ActiveConfigID != inData.ActiveConfigID {
  339. app.Error(c, 500, errors.New("必中配置活动不一致"), "必中配置活动不一致")
  340. return
  341. }
  342. if drawProductInfo.Stock <= 0 {
  343. app.Error(c, 500, errors.New("库存不足"), "库存不足")
  344. return
  345. }
  346. fmt.Println(drawProductInfo)
  347. //新建log 减库存
  348. err = subStockAddLog(drawProductInfo, inData.ClientOpenID)
  349. if err != nil {
  350. app.Error(c, 500, err, err.Error())
  351. return
  352. }
  353. //draw.DrawProductID = config.DrawOneBiZhong
  354. //draw.ActiveConfigID = inData.ActiveConfigID
  355. //draw.ClientOpenID = inData.ClientOpenID
  356. //
  357. //if drawProductInfo.IsPrize {
  358. // draw.IsPrize = models.NotClaimed //未兑奖 必中一定是要能兑奖的。
  359. //} else {
  360. // draw.IsPrize = models.NotWon //未中奖
  361. //}
  362. //
  363. //draw.CreatedAt = time.Now()
  364. //draw.UpdatedAt = time.Now()
  365. //_, err = draw.Create() //创建完成
  366. //if err != nil {
  367. // app.Error(c, 500, err, err.Error())
  368. // return
  369. //}
  370. outData.DrawProductName = drawProductInfo.DrawProductName
  371. outData.DrawUrl = drawProductInfo.DrawUrl
  372. outData.ID = config.DrawOneBiZhong
  373. app.OK(c, outData, app.Success)
  374. return
  375. }
  376. }
  377. var drawProductList shanghu.MerchantActiveDrawProduct
  378. var prizeList []Prize
  379. drawProductList.ActiveConfigID = inData.ActiveConfigID
  380. drawProductInfo, _, err := drawProductList.GetDrawProductListByActiveId()
  381. if err != nil {
  382. app.Error(c, 500, err, err.Error())
  383. return
  384. }
  385. for _, v := range drawProductInfo {
  386. var prize Prize
  387. if v.Stock <= 0 {
  388. continue
  389. }
  390. prize.Name = v.DrawProductName
  391. prize.ID = v.ID
  392. prize.Weight = v.DrawOdds
  393. prize.InitStock = v.TotalStock
  394. prize.Stock = v.Stock
  395. prizeList = append(prizeList, prize)
  396. }
  397. //fmt.Println(prizeList)
  398. // 创建抽奖实例
  399. lottery := NewLottery(prizeList)
  400. // 执行1次抽奖
  401. results, err := lottery.Draw(1)
  402. if err != nil {
  403. app.Error(c, 500, err, err.Error())
  404. return
  405. }
  406. fmt.Println(results)
  407. var drawProduct shanghu.MerchantActiveDrawProduct
  408. for _, v := range drawProductInfo {
  409. if results[0].ID == v.ID {
  410. outData.ID = v.ID
  411. outData.DrawUrl = v.DrawUrl
  412. outData.DrawProductName = v.DrawProductName
  413. drawProduct = v
  414. break
  415. }
  416. }
  417. //库存减一 并且新增记录
  418. err = subStockAddLog(drawProduct, inData.ClientOpenID)
  419. if err != nil {
  420. app.Error(c, 500, err, err.Error())
  421. return
  422. }
  423. app.OK(c, outData, app.Success)
  424. }
  425. type Prize struct {
  426. ID int64 // 奖品ID
  427. Name string // 奖品名称
  428. Weight int // 权重
  429. Stock int // 库存数量
  430. InitStock int // 初始库存(用于展示)
  431. }
  432. // 带权重和库存的抽奖
  433. type Lottery struct {
  434. Prizes []Prize
  435. TotalWeight int
  436. }
  437. func NewLottery(prizes []Prize) *Lottery {
  438. totalWeight := 0
  439. for _, prize := range prizes {
  440. totalWeight += prize.Weight
  441. }
  442. // 深拷贝奖品列表并初始化初始库存
  443. prizeCopy := make([]Prize, len(prizes))
  444. for i, p := range prizes {
  445. prizeCopy[i] = p
  446. prizeCopy[i].InitStock = p.Stock
  447. }
  448. return &Lottery{
  449. Prizes: prizeCopy,
  450. TotalWeight: totalWeight,
  451. }
  452. }
  453. func (l *Lottery) Draw(times int) ([]Prize, error) {
  454. // 检查总库存是否足够
  455. totalStock := 0
  456. for _, prize := range l.Prizes {
  457. totalStock += prize.Stock
  458. }
  459. if totalStock < times {
  460. return nil, fmt.Errorf("剩余总库存(%d)不足以支持%d次抽奖", totalStock, times)
  461. }
  462. rand.Seed(time.Now().UnixNano())
  463. results := make([]Prize, 0, times)
  464. for i := 0; i < times; i++ {
  465. // 如果没有可用奖品了就停止
  466. if l.TotalWeight <= 0 {
  467. break
  468. }
  469. randNum := rand.Intn(l.TotalWeight)
  470. currentWeight := 0
  471. for j := range l.Prizes {
  472. if l.Prizes[j].Stock <= 0 {
  473. continue
  474. }
  475. currentWeight += l.Prizes[j].Weight
  476. if randNum < currentWeight {
  477. // 中奖
  478. results = append(results, l.Prizes[j])
  479. // 减少库存
  480. l.Prizes[j].Stock--
  481. // 如果库存耗尽,更新总权重
  482. if l.Prizes[j].Stock == 0 {
  483. l.TotalWeight -= l.Prizes[j].Weight
  484. }
  485. break
  486. }
  487. }
  488. }
  489. return results, nil
  490. }
  491. // 新建记录,减库存
  492. func subStockAddLog(drawProductInfo shanghu.MerchantActiveDrawProduct, clientOpenId string) error {
  493. var draw shanghu.ClientActiveDrawLog
  494. //var drawProduct shanghu.MerchantActiveDrawProduct
  495. if drawProductInfo.Stock <= 0 {
  496. return errors.New("库存不足")
  497. }
  498. //减库存
  499. err := drawProductInfo.SubStock()
  500. if err != nil {
  501. return err
  502. }
  503. // 新建记录
  504. draw.DrawProductID = drawProductInfo.ID
  505. draw.ActiveConfigID = drawProductInfo.ActiveConfigID
  506. draw.ClientOpenID = clientOpenId
  507. if drawProductInfo.IsPrize {
  508. draw.IsPrize = models.NotClaimed //未兑奖 必中一定是要能兑奖的。
  509. } else {
  510. draw.IsPrize = models.NotWon //未中奖
  511. }
  512. draw.CreatedAt = time.Now()
  513. draw.UpdatedAt = time.Now()
  514. _, err = draw.Create() //创建完成
  515. if err != nil {
  516. return err
  517. }
  518. return nil
  519. }
  520. func GetClientActiveQR(c *gin.Context) {
  521. var inData models.ClientActiveQRRequest
  522. //var sqlData shanghu.MerchantClientCard
  523. var outData models.ClientCardQRReply
  524. var qr models.QRRequest
  525. var getQR models.GetQRRequest
  526. err := c.ShouldBindJSON(&inData)
  527. if err != nil {
  528. app.Error(c, 400, err, err.Error())
  529. return
  530. }
  531. // sqlData.ID = inData.ActiveConfigId
  532. val, err := pdd.DuoDuoGet("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=wx8595c589dd736486&secret=668f87d2bc24199688e53ee8a88434b8")
  533. if err != nil {
  534. app.Error(c, 500, err, err.Error())
  535. return
  536. }
  537. err = tools.JsonUnmarshal(val, &outData)
  538. if err != nil {
  539. app.Error(c, 500, err, err.Error())
  540. return
  541. }
  542. if outData.AccessToken == "" {
  543. app.Error(c, 500, err, "token error")
  544. return
  545. }
  546. url := "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + outData.AccessToken
  547. qr.CheckPath = true
  548. qr.Page = "pages/home/home"
  549. qr.EnvVersion = "release"
  550. qr.Scene = strconv.FormatInt(inData.ActiveConfigId, 10)
  551. data, err := json.Marshal(&qr)
  552. if err != nil {
  553. app.Error(c, 500, err, err.Error())
  554. return
  555. }
  556. reply, err := common.Post(data, url)
  557. if err != nil {
  558. app.Error(c, 500, err, err.Error())
  559. return
  560. }
  561. //err = json.Unmarshal(reply, &getQR)
  562. //if err != nil {
  563. // app.Error(c, 500, err, err.Error())
  564. // return
  565. //}
  566. if getQR.Errcode != 0 {
  567. app.Error(c, 500, err, getQR.Errmsg)
  568. return
  569. }
  570. //fmt.Println(string(reply))
  571. encoded := base64.StdEncoding.EncodeToString(reply)
  572. app.OK(c, encoded, app.Success)
  573. }
  574. func GroupByUnifiedOrder(c *gin.Context) {
  575. var inData models.GroupBuyUnifiedOrderRequest
  576. var sqlData shanghu.ClientActivePayTrans
  577. var activeConfig shanghu.MerchantActiveConfig
  578. var outData models.GroupBuyUnifiedOrderReply
  579. err := c.ShouldBindJSON(&inData)
  580. if err != nil {
  581. app.Error(c, 400, err, err.Error())
  582. return
  583. }
  584. //校验活动id
  585. activeConfig.ID = inData.ActiveConfigId
  586. activeConfigInfo, err := activeConfig.GetConfigInfoById()
  587. if err != nil {
  588. app.Error(c, 400, err, err.Error())
  589. return
  590. }
  591. if activeConfigInfo.DrawMode != 1 { //虚拟开团
  592. app.Error(c, 500, errors.New("非虚拟开团,不允许下单"), "非虚拟开团,不允许下单.")
  593. return
  594. }
  595. if inData.ClientOpenId == "" {
  596. app.OK(c, nil, app.Success)
  597. return
  598. }
  599. //校验 防止同一笔记录存在
  600. sqlData.RequestID = inData.RequestId
  601. if sqlData.GetRequestNum() > 0 {
  602. app.Error(c, 400, errors.New("交易已存在"), "交易已存在")
  603. return
  604. }
  605. //校验金额
  606. //检查微信相关参数
  607. if !inData.Amount.GreaterThan(decimal.NewFromInt(0)) {
  608. app.Error(c, 400, errors.New("amount:金额必须大于0"), "amount:金额必须大于0")
  609. return
  610. }
  611. if inData.Amount.Round(2).String() != inData.Amount.String() {
  612. app.Error(c, 400, errors.New("total_fee:金额最多只能保留两位小数"), "total_fee:金额最多只能保留两位小数")
  613. return
  614. }
  615. //创建支付记录
  616. sqlData.ClientOpenID = inData.ClientOpenId
  617. sqlData.RequestID = inData.RequestId
  618. sqlData.CreatedAt = time.Now()
  619. sqlData.UpdatedAt = time.Now()
  620. sqlData.Amount = inData.Amount
  621. sqlData.OutTradeNo = strconv.FormatInt(inData.ActiveConfigId, 10) + strconv.FormatInt(time.Now().UnixNano(), 10)
  622. sqlData.Status = 1 //未支付
  623. sqlData.ActiveConfigID = inData.ActiveConfigId
  624. sqlData.InvitationCode = inData.InvitationCode
  625. _, err = sqlData.Create()
  626. if err != nil {
  627. app.Error(c, 400, err, "创建支付失败")
  628. return
  629. }
  630. fmt.Println(sqlData.OutTradeNo)
  631. bm := make(gopay.BodyMap)
  632. bm.Set("nonce_str", common.GetRandomString(32))
  633. bm.Set("body", "商户卡")
  634. bm.Set("out_trade_no", sqlData.OutTradeNo)
  635. bm.Set("total_fee", inData.Amount.Mul(decimal.NewFromInt(100)).IntPart())
  636. bm.Set("spbill_create_ip", "127.0.0.1")
  637. bm.Set("notify_url", "https://tao1024.com/v1/client/pay/callback")
  638. bm.Set("device_info", "WEB")
  639. bm.Set("trade_type", "JSAPI")
  640. bm.Set("sign_type", wechat.SignType_MD5)
  641. bm.Set("openid", inData.ClientOpenId)
  642. client := NewWechatService()
  643. //请求支付下单,成功后得到结果
  644. wxResp, err := client.UnifiedOrder(c, bm)
  645. if err != nil {
  646. app.Error(c, 400, err, "下单失败")
  647. return
  648. }
  649. if wxResp.ReturnCode != "SUCCESS" {
  650. app.Error(c, 400, errors.New(wxResp.ReturnMsg), "下单失败")
  651. return
  652. }
  653. if wxResp.ResultCode != "SUCCESS" {
  654. app.Error(c, 400, errors.New(wxResp.ErrCode+"--"+wxResp.ErrCodeDes), "下单失败")
  655. return
  656. }
  657. timestamp := strconv.FormatInt(time.Now().Unix(), 10)
  658. pac := "prepay_id=" + wxResp.PrepayId
  659. paySign := wechat.GetMiniPaySign("wx8595c589dd736486", wxResp.NonceStr, pac, wechat.SignType_MD5, timestamp, "33c424fAa69942086f82A003e283E9C8")
  660. outData.Timestamp = timestamp
  661. outData.NonceStr = wxResp.NonceStr
  662. outData.Package = pac
  663. outData.PaySign = paySign
  664. outData.SignType = wechat.SignType_MD5
  665. //merchant, count, err := sqlData.GetOpenIdList(pageSize, pageIndex)
  666. //if err != nil {
  667. // app.Error(c, 500, err, err.Error())
  668. // return
  669. //}
  670. app.OK(c, outData, app.Success)
  671. }
  672. func Pay(c *gin.Context) {
  673. // 获取参数
  674. //
  675. }
  676. func ActivePayCallBack(c *gin.Context) {
  677. var payLog shanghu.ActivePayCallbackLog
  678. var payTrans shanghu.ClientActivePayTrans
  679. wxNotify, err := wechat.ParseNotifyToBodyMap(c.Request)
  680. if err != nil {
  681. c.XML(http.StatusOK, failResp)
  682. return
  683. }
  684. //通知回调log
  685. payLog.CallBackLog = wxNotify.JsonBody()
  686. payLog.ThirdTradeNo = wxNotify.Get("transaction_id")
  687. payLog.OutTradeNo = wxNotify.Get("out_trade_no")
  688. payLog.CreatedAt = time.Now()
  689. payLog.UpdatedAt = time.Now()
  690. _, err = payLog.Create()
  691. if err != nil {
  692. c.XML(http.StatusOK, failResp)
  693. return
  694. }
  695. if wxNotify.Get("return_code") != "SUCCESS" || wxNotify.Get("result_code") != "SUCCESS" {
  696. payLog.ErrLog = "微信返回错误:" + wxNotify.Get("return_code") + "--" + wxNotify.Get("result_code")
  697. payLog.UpdateMerchant()
  698. c.XML(http.StatusOK, failResp)
  699. return
  700. }
  701. //校验金额
  702. payTrans.OutTradeNo = wxNotify.Get("out_trade_no")
  703. payTransInfo, err := payTrans.GetPayTransByTradeNo()
  704. if err != nil {
  705. payLog.ErrLog = "查询交易信息错误:" + " err=" + err.Error()
  706. payLog.UpdateMerchant()
  707. c.XML(http.StatusOK, failResp)
  708. return
  709. }
  710. // 判断金额与支付流水是否一致
  711. totalFee, err := decimal.NewFromString(wxNotify.Get("total_fee"))
  712. if err != nil {
  713. payLog.ErrLog = "解析总金额报错:" + "err=" + err.Error()
  714. payLog.UpdateMerchant()
  715. c.XML(http.StatusOK, failResp)
  716. return
  717. }
  718. if !totalFee.Equal(payTransInfo.Amount.Mul(decimal.NewFromInt(100))) {
  719. payLog.ErrLog = "验证金额报错:total_fee=" + wxNotify.Get("total_fee") + " amount=" + payTransInfo.Amount.String()
  720. payLog.UpdateMerchant()
  721. c.XML(http.StatusOK, failResp)
  722. return
  723. }
  724. // 解析支付时间
  725. timeEnd, err := time.ParseInLocation("20060102150405", wxNotify.Get("time_end"), tools.TimeLocation)
  726. if err != nil {
  727. payLog.ErrLog = "付款时间解析出错:err=" + err.Error()
  728. payLog.UpdateMerchant()
  729. c.XML(http.StatusOK, failResp)
  730. return
  731. }
  732. payTrans.ThirdTradeNo = wxNotify.Get("transaction_id")
  733. payTrans.Status = 2 //支付成功
  734. payTrans.PayTime = timeEnd
  735. payTrans.AccountStatus = 1 //未分账
  736. err = payTrans.UpdatePayTransByTradeNo()
  737. if err != nil {
  738. payLog.ErrLog = "更新支付状态失败:err=" + err.Error()
  739. payLog.UpdateMerchant()
  740. c.XML(http.StatusOK, failResp)
  741. return
  742. }
  743. c.XML(http.StatusOK, successResp)
  744. }