merchant.active.config.go 25 KB

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