merchant.active.config.go 25 KB

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