merchant.active.config.go 25 KB

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