order.go 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892
  1. package controllers
  2. import (
  3. "encoding/json"
  4. "eta/eta_mini_crm_ht/models"
  5. "eta/eta_mini_crm_ht/models/request"
  6. "eta/eta_mini_crm_ht/models/response"
  7. "eta/eta_mini_crm_ht/utils"
  8. "fmt"
  9. "github.com/google/uuid"
  10. "github.com/rdlucklib/rdluck_tools/paging"
  11. "github.com/xuri/excelize/v2"
  12. "math/rand"
  13. "net/http"
  14. "net/url"
  15. "strconv"
  16. "strings"
  17. "sync"
  18. "time"
  19. )
  20. var (
  21. productCols = map[string]utils.ExcelColMapping{
  22. "A": {"订单编号", "OrderID"},
  23. "B": {"姓名", "RealName"},
  24. "C": {"手机号", "Mobile"},
  25. "D": {"商品名称", "ProductName"},
  26. "E": {"商品类型", "ProductType"},
  27. "F": {"商品价格", "Price"},
  28. "G": {"有效期", "ValidDate"},
  29. "H": {"订单状态", "Status"},
  30. "I": {"支付渠道", "PaymentWay"},
  31. "J": {"支付金额", "TotalAmount"},
  32. "K": {"售后状态", "RefundStatus"},
  33. "L": {"付款时间", "PaymentTime"},
  34. "M": {"下单时间", "CreatedTime"},
  35. }
  36. tradeCols = map[string]utils.ExcelColMapping{
  37. "A": {"支付订单", "TransactionId"},
  38. "B": {"订单编号", "OrderID"},
  39. "C": {"姓名", "RealName"},
  40. "D": {"手机号", "Mobile"},
  41. "E": {"商品名称", "ProductName"},
  42. "F": {"支付金额", "Amount"},
  43. "G": {"支付状态", "PaymentStatus"},
  44. "H": {"支付渠道", "PaymentWay"},
  45. "I": {"支付账号", "PaymentAccount"},
  46. "J": {"收款方", "MerchantId"},
  47. "K": {"完成支付时间", "DealTime"},
  48. "L": {"创建时间", "CreatedTime"},
  49. }
  50. refundCols = map[string]utils.ExcelColMapping{
  51. "A": {"退款订单", "TransactionId"},
  52. "B": {"订单编号", "OrderID"},
  53. "C": {"姓名", "RealName"},
  54. "D": {"手机号", "Mobile"},
  55. "E": {"退款金额", "Amount"},
  56. "F": {"退回账号", "PaymentAccount"},
  57. "G": {"退款状态", "PaymentStatus"},
  58. "H": {"完成退款时间", "DealTime"},
  59. "I": {"创建时间", "CreatedTime"},
  60. }
  61. ProductOrderStatus = map[models.OrderStatus]string{
  62. "pending": "待支付",
  63. "processing": "支付中",
  64. "paid": "已支付",
  65. "closed": "已关闭",
  66. "refund": "售后",
  67. }
  68. TradeOrderStatus = map[models.PaymentStatus]string{
  69. "pending": "待支付",
  70. "failed": "支付失败",
  71. "done": "支付成功",
  72. }
  73. RefundOrderStatus = map[models.PaymentStatus]string{
  74. "pending": "退款中",
  75. "failed": "退款失败",
  76. "done": "退款成功",
  77. }
  78. RefundStatusMap = map[models.RefundStatus]string{
  79. "pending": "待退款",
  80. "processing": "退款中",
  81. "failed": "退款失败",
  82. "success": "退款成功",
  83. "canceled": "已取消",
  84. }
  85. ProductTypeMap = map[models.MerchantProductType]string{
  86. "report": "报告",
  87. "video": "视频",
  88. "audio": "音频",
  89. "package": "套餐",
  90. }
  91. PaymentWayMap = map[models.PaymentWay]string{
  92. "wechat": "微信",
  93. "alipay": "支付宝",
  94. }
  95. )
  96. type OrderController struct {
  97. BaseAuthController
  98. }
  99. // ProductOrderList
  100. // @Title 商品订单列表
  101. // @Description 商品订单列表
  102. // @Param PageSize query int true "每页数据条数"
  103. // @Param CurrentIndex query int true "当前页页码,从1开始"
  104. // @Param ClassifyIds query string true "二级分类id,可多选用英文,隔开"
  105. // @Param KeyWord query string true "报告标题/创建人"
  106. // @Param SortType query string true "排序方式"
  107. // @Success 200 {object} models.ReportAuthorResp
  108. // @router /productOrderList [get]
  109. func (this *OrderController) ProductOrderList() {
  110. br := new(models.BaseResponse).Init()
  111. defer func() {
  112. this.Data["json"] = br
  113. this.ServeJSON()
  114. }()
  115. pageSize, _ := this.GetInt("PageSize")
  116. currentIndex, _ := this.GetInt("CurrentIndex")
  117. sortType := this.GetString("SortType")
  118. KeyWord := this.GetString("KeyWord")
  119. TemplateUserId, _ := this.GetInt("TemplateUserId", 0)
  120. PaymentDate := this.GetString("PaymentDate")
  121. PaymentWay := this.GetString("PaymentWay")
  122. CreatedDate := this.GetString("CreatedDate")
  123. ProductType := this.GetString("ProductType")
  124. RefundStatus := this.GetString("RefundStatus")
  125. OrderStatus := this.GetString("OrderStatus")
  126. var condition string
  127. if pageSize <= 0 {
  128. pageSize = utils.PageSize20
  129. }
  130. if currentIndex <= 0 {
  131. currentIndex = 1
  132. }
  133. if KeyWord != "" {
  134. condition += " AND (product_name like '%" + KeyWord + "%' or real_name like '%" + KeyWord + "%'or order_id like '%" + KeyWord + "%' or mobile like '%" + KeyWord + "%')"
  135. }
  136. sortCondition := " ORDER BY created_time "
  137. if sortType == "" {
  138. sortType = "DESC"
  139. }
  140. if CreatedDate != "" {
  141. condition += " AND Date(created_time) = '" + CreatedDate + "'"
  142. }
  143. if PaymentDate != "" {
  144. condition += " AND Date(payment_time) = '" + PaymentDate + "'"
  145. }
  146. if PaymentWay != "" {
  147. condition += " AND payment_way='" + PaymentWay + "'"
  148. }
  149. if TemplateUserId > 0 {
  150. condition += fmt.Sprintf(" AND template_user_id=%d", TemplateUserId)
  151. }
  152. if OrderStatus != "" {
  153. switch OrderStatus {
  154. case "pending":
  155. condition += " AND status='pending'"
  156. case "paid":
  157. condition += " AND status='paid'"
  158. case "closed":
  159. condition += " AND status='closed'"
  160. case "refund":
  161. condition += " AND status='refund'"
  162. if RefundStatus != "" {
  163. switch RefundStatus {
  164. case "pending":
  165. condition += " AND refund_status='pending'"
  166. case "processing":
  167. condition += " AND refund_status='processing'"
  168. case "failed":
  169. condition += " AND refund_status='failed'"
  170. case "success":
  171. condition += " AND refund_status='success'"
  172. }
  173. }
  174. default:
  175. br.Msg = "无效的订单状态"
  176. br.ErrMsg = "无效的订单状态:" + OrderStatus
  177. return
  178. }
  179. }
  180. if ProductType != "" {
  181. switch ProductType {
  182. case "report":
  183. condition += " AND product_type='" + string(models.ProductReport) + "'"
  184. case "audio":
  185. condition += " AND product_type='" + string(models.ProductAudio) + "'"
  186. case "video":
  187. condition += " AND product_type='" + string(models.ProductVideo) + "'"
  188. case "package":
  189. condition += " AND product_type='" + string(models.ProductPackage) + "'"
  190. default:
  191. br.Msg = "无效的产品类型"
  192. br.ErrMsg = "无效的产品类型:" + ProductType
  193. return
  194. }
  195. }
  196. sortCondition = sortCondition + sortType
  197. total, err := models.GetProductOrderCountByCondition(condition)
  198. if err != nil {
  199. br.Msg = "获取商品列表失败"
  200. br.ErrMsg = "获取商品列表失败,Err:" + err.Error()
  201. return
  202. }
  203. startSize := utils.StartIndex(currentIndex, pageSize)
  204. List, err := models.GetProductOrderByCondition(condition, sortCondition, startSize, pageSize)
  205. if err != nil {
  206. br.Msg = "获取商品列表失败"
  207. br.ErrMsg = "获取商品列表失败,Err:" + err.Error()
  208. return
  209. }
  210. var ListView []*models.ProductOrderView
  211. var wg sync.WaitGroup
  212. wg.Add(len(List))
  213. for _, orderItem := range List {
  214. go func(orderItem *models.ProductOrder) {
  215. defer wg.Done()
  216. view := &models.ProductOrderView{
  217. OrderID: orderItem.OrderId,
  218. RealName: orderItem.RealName,
  219. Mobile: fmt.Sprintf("+%s %s", orderItem.AreaCode, orderItem.Mobile),
  220. ProductType: ProductTypeMap[orderItem.ProductType],
  221. ProductName: orderItem.ProductName,
  222. TotalAmount: fmt.Sprintf("¥%s", orderItem.TotalAmount),
  223. TradeNO: orderItem.TradeNo,
  224. RefundAmount: orderItem.RefundAmount,
  225. RefundTradeId: orderItem.RefundTradeId,
  226. PaymentWay: PaymentWayMap[orderItem.PaymentWay],
  227. PaymentTime: orderItem.PaymentTime.Format(time.DateTime),
  228. Status: ProductOrderStatus[orderItem.Status],
  229. RefundStatus: RefundStatusMap[orderItem.RefundStatus],
  230. Remark: orderItem.Remark,
  231. CreatedTime: orderItem.CreatedTime.Format(time.DateTime),
  232. }
  233. if orderItem.TradeNo != "" {
  234. view.PaymentTime = orderItem.PaymentTime.Format(time.DateTime)
  235. tradeOrder, tradeErr := models.GetTradeOrderByNo(orderItem.TradeNo)
  236. if tradeErr != nil {
  237. utils.FileLog.Error("获取支付订单失败,支付订单号:" + orderItem.TradeNo + ",err:" + tradeErr.Error())
  238. } else {
  239. view.PaymentAmount = fmt.Sprintf("¥%s", tradeOrder.Amount)
  240. }
  241. }
  242. if orderItem.Status == models.OrderStatusPaid {
  243. access, accessErr := models.GetAccess(orderItem.ProductId, orderItem.TemplateUserId)
  244. if accessErr != nil {
  245. utils.FileLog.Error("获取用户订阅记录失败,templateUserId:" + string(rune(orderItem.TemplateUserId)) + "productId:" + string(rune(orderItem.ProductId)) + ",err:" + accessErr.Error())
  246. } else {
  247. if access.ProductType == models.ProductPackage {
  248. view.ValidDuration = fmt.Sprintf("%s~%s", access.BeginDate.Format(time.DateOnly), access.EndDate.Format(time.DateOnly))
  249. } else {
  250. view.ValidDuration = "永久有效"
  251. }
  252. }
  253. }
  254. if orderItem.Status == models.OrderStatusRefund && orderItem.RefundStatus == models.RefundStatusSuccess {
  255. view.RefundFinishTime = orderItem.RefundFinishTime.Format(time.DateTime)
  256. }
  257. ListView = append(ListView, view)
  258. }(orderItem)
  259. }
  260. wg.Wait()
  261. page := paging.GetPaging(currentIndex, pageSize, total)
  262. resp := new(response.ProductOrderListResp)
  263. resp.List = ListView
  264. resp.Paging = page
  265. br.Ret = 200
  266. br.Success = true
  267. br.Data = resp
  268. br.Msg = "获取成功"
  269. }
  270. // TradeOrderList
  271. // @Title 支付订单列表
  272. // @Description 支付订单列表
  273. // @Param PageSize query int true "每页数据条数"
  274. // @Param CurrentIndex query int true "当前页页码,从1开始"
  275. // @Param ClassifyIds query string true "二级分类id,可多选用英文,隔开"
  276. // @Param KeyWord query string true "报告标题/创建人"
  277. // @Param SortType query string true "排序方式"
  278. // @Success 200 {object} models.ReportAuthorResp
  279. // @router /tradeOrderList [get]
  280. func (this *OrderController) TradeOrderList() {
  281. br := new(models.BaseResponse).Init()
  282. defer func() {
  283. this.Data["json"] = br
  284. this.ServeJSON()
  285. }()
  286. pageSize, _ := this.GetInt("PageSize")
  287. currentIndex, _ := this.GetInt("CurrentIndex")
  288. sortType := this.GetString("SortType")
  289. KeyWord := this.GetString("KeyWord")
  290. DealDate := this.GetString("DealDate")
  291. PaymentWay := this.GetString("PaymentWay")
  292. CreatedDate := this.GetString("CreatedDate")
  293. OrderStatus := this.GetString("OrderStatus")
  294. IsRefund, _ := this.GetBool("IsRefund", false)
  295. var condition string
  296. if pageSize <= 0 {
  297. pageSize = utils.PageSize20
  298. }
  299. if currentIndex <= 0 {
  300. currentIndex = 1
  301. }
  302. if IsRefund {
  303. condition += " AND payment_type ='" + string(models.PaymentTypeRefund) + "'"
  304. } else {
  305. condition += " AND payment_type ='" + string(models.PaymentTypePay) + "'"
  306. }
  307. if KeyWord != "" {
  308. condition += " AND (product_name like '%" + KeyWord + "%' or real_name like '%" + KeyWord + "%' or product_order_id like '%" + KeyWord + "%' or mobile like '%" + KeyWord + "%')"
  309. }
  310. sortCondition := " ORDER BY created_time "
  311. if sortType == "" {
  312. sortType = "DESC"
  313. }
  314. if CreatedDate != "" {
  315. condition += " AND Date(created_time) = '" + CreatedDate + "'"
  316. }
  317. if DealDate != "" {
  318. condition += " AND Date(deal_time) = '" + DealDate + "'"
  319. }
  320. if PaymentWay != "" {
  321. condition += " AND payment_way='" + PaymentWay + "'"
  322. }
  323. if OrderStatus != "" {
  324. switch OrderStatus {
  325. case "pending":
  326. condition += " AND payment_status='pending'"
  327. case "done":
  328. condition += " AND payment_status='done'"
  329. case "failed":
  330. condition += " AND payment_status='failed'"
  331. default:
  332. br.Msg = "无效的支付订单状态"
  333. br.ErrMsg = "无效的支付订单状态:" + OrderStatus
  334. return
  335. }
  336. }
  337. sortCondition = sortCondition + sortType
  338. total, err := models.GetTradeOrderCountByCondition(condition)
  339. if err != nil {
  340. br.Msg = "获取支付明细列表失败"
  341. br.ErrMsg = "获取支付明细列表失败,Err:" + err.Error()
  342. return
  343. }
  344. startSize := utils.StartIndex(currentIndex, pageSize)
  345. List, err := models.GetTradeOrderByCondition(condition, sortCondition, startSize, pageSize)
  346. if err != nil {
  347. br.Msg = "获取支付明细列表失败"
  348. br.ErrMsg = "获取支付明细列表失败,Err:" + err.Error()
  349. return
  350. }
  351. var ListView []*models.TradeOrderView
  352. var wg sync.WaitGroup
  353. wg.Add(len(List))
  354. for i := 0; i < len(List); i++ {
  355. go func(order *models.TradeOrder) {
  356. defer wg.Done()
  357. view := &models.TradeOrderView{
  358. RealName: order.RealName,
  359. Mobile: fmt.Sprintf("+%s %s", order.AreaCode, order.Mobile),
  360. ProductName: order.ProductName,
  361. Amount: fmt.Sprintf("¥%s", order.Amount),
  362. TransactionID: order.TransactionId,
  363. ProductOrderID: order.ProductOrderId,
  364. PaymentWay: PaymentWayMap[order.PaymentWay],
  365. PaymentAccount: order.PaymentAccount,
  366. MerchantID: order.MerchantId,
  367. CreatedTime: order.CreatedTime.Format(time.DateTime),
  368. }
  369. if order.PaymentStatus == models.PaymentStatusDone {
  370. view.DealTime = order.DealTime.Format(time.DateTime)
  371. }
  372. if IsRefund {
  373. view.PaymentStatus = RefundOrderStatus[order.PaymentStatus]
  374. } else {
  375. view.PaymentStatus = TradeOrderStatus[order.PaymentStatus]
  376. }
  377. ListView = append(ListView, view)
  378. }(List[i])
  379. }
  380. wg.Wait()
  381. page := paging.GetPaging(currentIndex, pageSize, total)
  382. resp := new(response.TradeOrderListResp)
  383. resp.List = ListView
  384. resp.Paging = page
  385. br.Ret = 200
  386. br.Success = true
  387. br.Data = resp
  388. br.Msg = "获取成功"
  389. }
  390. // ExportProductOrder
  391. // @Title 临时用户列表
  392. // @Description 临时用户列表
  393. // @Param PageSize query int true "每页数据条数"
  394. // @Param CurrentIndex query int true "当前页页码,从1开始"
  395. // @Param Keyword query string false "手机号"
  396. // @Param SortParam query string false "排序字段参数,用来排序的字段, 枚举值:0:注册时间,1:阅读数,2:最近一次阅读时间"
  397. // @Param SortType query string true "如何排序,是正序还是倒序,0:倒序,1:正序"
  398. // @Success 200 {object} response.TemplateUserListResp
  399. // @router /productOrder/export [get]
  400. func (this *OrderController) ExportProductOrder() {
  401. br := new(models.BaseResponse).Init()
  402. defer func() {
  403. this.Data["json"] = br
  404. this.ServeJSON()
  405. }()
  406. pageSize, _ := this.GetInt("PageSize")
  407. currentIndex, _ := this.GetInt("CurrentIndex")
  408. sortType := this.GetString("SortType")
  409. KeyWord := this.GetString("KeyWord")
  410. PaymentDate := this.GetString("PaymentDate")
  411. PaymentWay := this.GetString("PaymentWay")
  412. CreatedDate := this.GetString("CreatedDate")
  413. ProductType := this.GetString("ProductType")
  414. RefundStatus := this.GetString("RefundStatus")
  415. OrderStatus := this.GetString("OrderStatus")
  416. var condition string
  417. if pageSize <= 0 {
  418. pageSize = utils.PageSize20
  419. }
  420. if currentIndex <= 0 {
  421. currentIndex = 1
  422. }
  423. if KeyWord != "" {
  424. condition += " AND (product_name like '%" + KeyWord + "%' or real_name like '%" + KeyWord + "%' order_id like '%" + KeyWord + "%' or mobile like '%" + KeyWord + "%')"
  425. }
  426. sortCondition := " ORDER BY created_time "
  427. if sortType == "" {
  428. sortType = "DESC"
  429. }
  430. if CreatedDate != "" {
  431. condition += " AND Date(created_time) = '" + CreatedDate + "'"
  432. }
  433. if PaymentDate != "" {
  434. condition += " AND Date(payment_time) = '" + PaymentDate + "'"
  435. }
  436. if PaymentWay != "" {
  437. condition += " AND payment_way='" + PaymentWay + "'"
  438. }
  439. if OrderStatus != "" {
  440. switch OrderStatus {
  441. case "pending":
  442. condition += " AND status='pending'"
  443. case "paid":
  444. condition += " AND status='paid'"
  445. case "closed":
  446. condition += " AND status='closed'"
  447. case "refund":
  448. condition += " AND status='refund'"
  449. if RefundStatus != "" {
  450. switch RefundStatus {
  451. case "pending":
  452. condition += " AND refund_status='pending'"
  453. case "processing":
  454. condition += " AND refund_status='processing'"
  455. case "failed":
  456. condition += " AND refund_status='failed'"
  457. case "success":
  458. condition += " AND refund_status='success'"
  459. }
  460. }
  461. default:
  462. br.Msg = "无效的订单状态"
  463. br.ErrMsg = "无效的订单状态:" + OrderStatus
  464. return
  465. }
  466. }
  467. if ProductType != "" {
  468. switch ProductType {
  469. case "report":
  470. condition += " AND product_type='" + string(models.ProductReport) + "'"
  471. case "audio":
  472. condition += " AND product_type='" + string(models.ProductAudio) + "'"
  473. case "video":
  474. condition += " AND product_type='" + string(models.ProductVideo) + "'"
  475. case "package":
  476. condition += " AND product_type='" + string(models.ProductPackage) + "'"
  477. default:
  478. br.Msg = "无效的产品类型"
  479. br.ErrMsg = "无效的产品类型:" + ProductType
  480. return
  481. }
  482. }
  483. sortCondition = sortCondition + sortType
  484. List, err := models.GetProductOrderListByCondition(condition, sortCondition)
  485. if err != nil {
  486. br.Msg = "导出商品订单失败"
  487. br.ErrMsg = "导出商品订单失败,Err:" + err.Error()
  488. return
  489. }
  490. var ListView []*models.ProductOrderView
  491. var wg sync.WaitGroup
  492. wg.Add(len(List))
  493. for _, orderItem := range List {
  494. go func(orderItem *models.ProductOrder) {
  495. defer func() {
  496. wg.Done()
  497. }()
  498. view := &models.ProductOrderView{
  499. OrderID: orderItem.OrderId,
  500. RealName: orderItem.RealName,
  501. Mobile: fmt.Sprintf("+%s %s", orderItem.AreaCode, orderItem.Mobile),
  502. ProductType: ProductTypeMap[orderItem.ProductType],
  503. ProductName: orderItem.ProductName,
  504. TotalAmount: fmt.Sprintf("¥%s", orderItem.TotalAmount),
  505. TradeNO: orderItem.TradeNo,
  506. RefundAmount: orderItem.RefundAmount,
  507. RefundTradeId: orderItem.RefundTradeId,
  508. PaymentWay: PaymentWayMap[orderItem.PaymentWay],
  509. PaymentTime: orderItem.PaymentTime.Format(time.DateTime),
  510. Status: ProductOrderStatus[orderItem.Status],
  511. RefundStatus: RefundStatusMap[orderItem.RefundStatus],
  512. Remark: orderItem.Remark,
  513. CreatedTime: orderItem.CreatedTime.Format(time.DateTime),
  514. }
  515. if orderItem.TradeNo != "" {
  516. view.PaymentTime = orderItem.PaymentTime.Format(time.DateTime)
  517. tradeOrder, tradeErr := models.GetTradeOrderByNo(orderItem.TradeNo)
  518. if tradeErr != nil {
  519. utils.FileLog.Error("获取支付订单失败,支付订单号:" + orderItem.TradeNo + ",err:" + tradeErr.Error())
  520. } else {
  521. view.PaymentAmount = fmt.Sprintf("¥%s", tradeOrder.Amount)
  522. }
  523. }
  524. if orderItem.Status == models.OrderStatusPaid {
  525. access, accessErr := models.GetAccess(orderItem.ProductId, orderItem.TemplateUserId)
  526. if accessErr != nil {
  527. utils.FileLog.Error("获取用户订阅记录失败,templateUserId:" + string(rune(orderItem.TemplateUserId)) + "productId:" + string(rune(orderItem.ProductId)) + ",err:" + accessErr.Error())
  528. } else {
  529. if access.ProductType == models.ProductPackage {
  530. view.ValidDuration = fmt.Sprintf("%s~%s", access.BeginDate.Format(time.DateOnly), access.EndDate.Format(time.DateOnly))
  531. } else {
  532. view.ValidDuration = "永久有效"
  533. }
  534. }
  535. }
  536. if orderItem.Status == models.OrderStatusRefund && orderItem.RefundStatus == models.RefundStatusSuccess {
  537. view.RefundFinishTime = orderItem.RefundFinishTime.Format(time.DateTime)
  538. }
  539. ListView = append(ListView, view)
  540. }(orderItem)
  541. }
  542. wg.Wait()
  543. year, month, day := time.Now().Date()
  544. yearStr := strconv.Itoa(year)[2:]
  545. fileName := fmt.Sprintf("商品订单%s.%d.%d.xlsx", yearStr, month, day)
  546. file, err := utils.ExportExcel("商品订单", productCols, ListView)
  547. _ = this.downloadExcelFile(file, fileName)
  548. br.Ret = 200
  549. br.Success = true
  550. br.Msg = "下载成功"
  551. }
  552. // ExportTradeOrder
  553. // @Title 临时用户列表
  554. // @Description 临时用户列表
  555. // @Param PageSize query int true "每页数据条数"
  556. // @Param CurrentIndex query int true "当前页页码,从1开始"
  557. // @Param Keyword query string false "手机号"
  558. // @Param SortParam query string false "排序字段参数,用来排序的字段, 枚举值:0:注册时间,1:阅读数,2:最近一次阅读时间"
  559. // @Param SortType query string true "如何排序,是正序还是倒序,0:倒序,1:正序"
  560. // @Success 200 {object} response.TemplateUserListResp
  561. // @router /tradeOrder/export [get]
  562. func (this *OrderController) ExportTradeOrder() {
  563. br := new(models.BaseResponse).Init()
  564. defer func() {
  565. this.Data["json"] = br
  566. this.ServeJSON()
  567. }()
  568. pageSize, _ := this.GetInt("PageSize")
  569. currentIndex, _ := this.GetInt("CurrentIndex")
  570. sortType := this.GetString("SortType")
  571. KeyWord := this.GetString("KeyWord")
  572. DealDate := this.GetString("DealDate")
  573. PaymentWay := this.GetString("PaymentWay")
  574. CreatedDate := this.GetString("CreatedDate")
  575. OrderStatus := this.GetString("OrderStatus")
  576. IsRefund, _ := this.GetBool("IsRefund", false)
  577. var condition string
  578. if pageSize <= 0 {
  579. pageSize = utils.PageSize20
  580. }
  581. if currentIndex <= 0 {
  582. currentIndex = 1
  583. }
  584. if IsRefund {
  585. condition += " AND payment_type ='" + string(models.PaymentTypeRefund) + "'"
  586. } else {
  587. condition += " AND payment_type ='" + string(models.PaymentTypePay) + "'"
  588. }
  589. if KeyWord != "" {
  590. condition += " AND (product_name like '%" + KeyWord + "%' or real_name like '%" + KeyWord + "%' or product_order_id like '%" + KeyWord + "%' or mobile like '%" + KeyWord + "%')"
  591. }
  592. sortCondition := " ORDER BY created_time "
  593. if sortType == "" {
  594. sortType = "DESC"
  595. }
  596. if CreatedDate != "" {
  597. condition += " AND Date(created_time) = '" + CreatedDate + "'"
  598. }
  599. if DealDate != "" {
  600. condition += " AND Date(deal_time) = '" + DealDate + "'"
  601. }
  602. if PaymentWay != "" {
  603. condition += " AND payment_way='" + PaymentWay + "'"
  604. }
  605. if OrderStatus != "" {
  606. switch OrderStatus {
  607. case "pending":
  608. condition += " AND payment_status='pending'"
  609. case "done":
  610. condition += " AND payment_status='done'"
  611. case "failed":
  612. condition += " AND payment_status='failed'"
  613. default:
  614. br.Msg = "无效的支付订单状态"
  615. br.ErrMsg = "无效的支付订单状态:" + OrderStatus
  616. return
  617. }
  618. }
  619. sortCondition = sortCondition + sortType
  620. List, err := models.GetTradeOrderListByCondition(condition, sortCondition)
  621. if err != nil {
  622. br.Msg = "获取支付明细列表失败"
  623. br.ErrMsg = "获取支付明细列表失败,Err:" + err.Error()
  624. return
  625. }
  626. var ListView []models.TradeOrderView
  627. var wg sync.WaitGroup
  628. wg.Add(len(List))
  629. for i := 0; i < len(List); i++ {
  630. go func(order *models.TradeOrder) {
  631. defer wg.Done()
  632. view := models.TradeOrderView{
  633. RealName: order.RealName,
  634. Mobile: fmt.Sprintf("+%s %s", order.AreaCode, order.Mobile),
  635. ProductName: order.ProductName,
  636. Amount: fmt.Sprintf("¥%s", order.Amount),
  637. TransactionID: order.TransactionId,
  638. ProductOrderID: order.ProductOrderId,
  639. PaymentWay: PaymentWayMap[order.PaymentWay],
  640. PaymentAccount: order.PaymentAccount,
  641. MerchantID: order.MerchantId,
  642. CreatedTime: order.CreatedTime.Format(time.DateTime),
  643. }
  644. if order.PaymentStatus == models.PaymentStatusDone {
  645. view.DealTime = order.DealTime.Format(time.DateTime)
  646. }
  647. if IsRefund {
  648. view.PaymentStatus = RefundOrderStatus[order.PaymentStatus]
  649. } else {
  650. view.PaymentStatus = TradeOrderStatus[order.PaymentStatus]
  651. }
  652. ListView = append(ListView, view)
  653. }(List[i])
  654. }
  655. wg.Wait()
  656. year, month, day := time.Now().Date()
  657. yearStr := strconv.Itoa(year)[2:]
  658. if IsRefund {
  659. fileName := fmt.Sprintf("退款明细%s.%d.%d.xlsx", yearStr, month, day)
  660. file, _ := utils.ExportExcel("退款明细", refundCols, ListView)
  661. _ = this.downloadExcelFile(file, fileName)
  662. } else {
  663. fileName := fmt.Sprintf("支付明细%s.%d.%d.xlsx", yearStr, month, day)
  664. file, _ := utils.ExportExcel("支付明细", tradeCols, ListView)
  665. _ = this.downloadExcelFile(file, fileName)
  666. }
  667. br.Ret = 200
  668. br.Success = true
  669. br.Msg = "下载成功"
  670. }
  671. // encodeChineseFilename 将中文文件名编码为 ISO-8859-1
  672. func (this *OrderController) downloadExcelFile(file *excelize.File, filename string) (err error) {
  673. // 对文件名进行 ISO-8859-1 编码
  674. fn := url.QueryEscape(filename)
  675. if filename == fn {
  676. fn = "filename=" + fn
  677. } else {
  678. fn = "filename=" + filename + "; filename*=utf-8''" + fn
  679. }
  680. this.Ctx.ResponseWriter.Header().Set("Access-Control-Expose-Headers", "Content-Disposition")
  681. this.Ctx.ResponseWriter.Header().Set("Content-Disposition", "attachment; "+fn)
  682. this.Ctx.ResponseWriter.Header().Set("Content-Description", "File Transfer")
  683. this.Ctx.ResponseWriter.Header().Set("Content-Type", "application/octet-stream")
  684. this.Ctx.ResponseWriter.Header().Set("Content-Transfer-Encoding", "binary")
  685. this.Ctx.ResponseWriter.Header().Set("Expires", "0")
  686. this.Ctx.ResponseWriter.Header().Set("Cache-Control", "must-revalidate")
  687. this.Ctx.ResponseWriter.Header().Set("Pragma", "public")
  688. this.Ctx.ResponseWriter.Header().Set("File-Name", filename)
  689. // 写入文件
  690. if err = file.Write(this.Ctx.ResponseWriter); err != nil {
  691. utils.FileLog.Error("导出excel文件失败:", err)
  692. http.Error(this.Ctx.ResponseWriter, "导出excel文件失败", http.StatusInternalServerError)
  693. }
  694. return
  695. }
  696. // Refund
  697. // @Title 退款
  698. // @Description 退款
  699. // @Param PageSize query int true "每页数据条数"
  700. // @Param CurrentIndex query int true "当前页页码,从1开始"
  701. // @Param ClassifyIds query string true "二级分类id,可多选用英文,隔开"
  702. // @Param KeyWord query string true "报告标题/创建人"
  703. // @Param SortType query string true "排序方式"
  704. // @Success 200 {object} models.ReportAuthorResp
  705. // @router /refund [post]
  706. func (this *OrderController) Refund() {
  707. br := new(models.BaseResponse).Init()
  708. defer func() {
  709. this.Data["json"] = br
  710. this.ServeJSON()
  711. }()
  712. var req request.RefundReq
  713. if err := json.Unmarshal(this.Ctx.Input.RequestBody, &req); err != nil {
  714. br.Msg = "参数解析失败"
  715. br.ErrMsg = "参数解析失败,Err:" + err.Error()
  716. return
  717. }
  718. if req.ProductOrderNo == "" {
  719. br.Msg = "商品订单号不能为空"
  720. br.ErrMsg = "商品订单号不能为空"
  721. return
  722. }
  723. productOrder, err := models.GetProductOrderByID(req.ProductOrderNo)
  724. if err != nil {
  725. br.Msg = "获取商品订单失败"
  726. br.ErrMsg = "获取商品订单失败,err:" + err.Error()
  727. return
  728. }
  729. if productOrder.Status == models.OrderStatusPending {
  730. br.Msg = "退款失败,"
  731. br.ErrMsg = "退款失败,退款状态异常,当前订单已关闭"
  732. return
  733. }
  734. if productOrder.Status == models.OrderStatusRefund && productOrder.RefundStatus != models.RefundStatusFailed {
  735. br.Msg = "退款失败,"
  736. br.ErrMsg = "退款失败,当前订单退款处理中"
  737. return
  738. }
  739. tradeOrder, err := models.GetTradeOrderByNo(productOrder.TradeNo)
  740. if err != nil {
  741. br.Msg = "退款失败,获取原订单失败"
  742. br.ErrMsg = "退款失败,获取原订单失败,err:" + err.Error()
  743. return
  744. }
  745. if tradeOrder.PaymentType != models.PaymentTypePay {
  746. br.Msg = "退款失败,原订单非支付订单"
  747. br.ErrMsg = "退款失败,原订单非支付订单"
  748. return
  749. }
  750. if tradeOrder.PaymentStatus != models.PaymentStatusDone {
  751. br.Msg = "退款失败,原订单未完成支付"
  752. br.ErrMsg = "退款失败,原订单未完成支付"
  753. return
  754. }
  755. uuidStr := strings.ReplaceAll(uuid.New().String(), "-", "")
  756. key := fmt.Sprintf("refund_lock_%s", productOrder.OrderId)
  757. defer func() {
  758. utils.ReleaseLock(key, uuidStr)
  759. }()
  760. if utils.AcquireLock(key, 10, uuidStr) {
  761. aa := GenerateProductOrderNo()
  762. refundOrder := &models.TradeOrder{
  763. TransactionId: aa,
  764. OrgTransactionId: productOrder.TradeNo,
  765. ProductOrderId: productOrder.OrderId,
  766. PaymentAccount: tradeOrder.PaymentAccount,
  767. PaymentWay: tradeOrder.PaymentWay,
  768. ProductName: productOrder.ProductName,
  769. Mobile: productOrder.Mobile,
  770. AreaCode: productOrder.AreaCode,
  771. RealName: productOrder.RealName,
  772. Amount: tradeOrder.Amount,
  773. Currency: tradeOrder.Currency,
  774. UserId: tradeOrder.UserId,
  775. TemplateUserId: tradeOrder.TemplateUserId,
  776. PaymentType: models.PaymentTypeRefund,
  777. PaymentStatus: models.PaymentStatusPending,
  778. CreatedTime: time.Now(),
  779. }
  780. productOrder.RefundStatus = models.RefundStatusProcessing
  781. productOrder.Status = models.OrderStatusRefund
  782. productOrder.RefundTradeId = refundOrder.TransactionId
  783. productOrder.Remark = req.Remark
  784. productOrder.RefundAmount = tradeOrder.Amount
  785. err = refundOrder.Refund(productOrder)
  786. if err != nil {
  787. br.Msg = "退款失败"
  788. br.ErrMsg = "退款失败,,Err:" + err.Error()
  789. return
  790. }
  791. refundflow := models.RefundDealFlow{
  792. ProductOrderNo: productOrder.OrderId,
  793. RefundOrderNo: refundOrder.TransactionId,
  794. OperatorUserId: this.SysUser.SysUserId,
  795. CreatedTime: time.Now(),
  796. }
  797. //增加一条退款流水
  798. _ = refundflow.Insert()
  799. br.Ret = 200
  800. br.Success = true
  801. br.Msg = "退款处理成功"
  802. } else {
  803. br.Msg = "退款失败,当前订单正在退款中"
  804. br.ErrMsg = "退款失败,当前订单正在退款中"
  805. return
  806. }
  807. }
  808. func GenerateProductOrderNo() string {
  809. timestamp := time.Now().UnixNano() / 1000000 // 毫秒级时间戳
  810. // 生成随机数
  811. rand.New(rand.NewSource(time.Now().UnixNano()))
  812. randomPart := rand.Intn(999999)
  813. // 格式化订单号
  814. orderNumber := fmt.Sprintf("R%d%06d", timestamp, randomPart)
  815. return orderNumber
  816. }
  817. // RefundDetail
  818. // @Title 退款详情
  819. // @Description 退款详情
  820. // @Param PageSize query int true "每页数据条数"
  821. // @Param CurrentIndex query int true "当前页页码,从1开始"
  822. // @Param ClassifyIds query string true "二级分类id,可多选用英文,隔开"
  823. // @Param KeyWord query string true "报告标题/创建人"
  824. // @Param SortType query string true "排序方式"
  825. // @Success 200 {object} models.ReportAuthorResp
  826. // @router /refundDetail [get]
  827. func (this *OrderController) RefundDetail() {
  828. br := new(models.BaseResponse).Init()
  829. defer func() {
  830. this.Data["json"] = br
  831. this.ServeJSON()
  832. }()
  833. ProductOrderNo := this.GetString("ProductOrderNo")
  834. if ProductOrderNo == "" {
  835. br.Msg = "商品订单号不能为空"
  836. br.ErrMsg = "商品订单号不能为空"
  837. return
  838. }
  839. productOrder, err := models.GetProductOrderByID(ProductOrderNo)
  840. if err != nil {
  841. br.Msg = "获取商品订单失败"
  842. br.ErrMsg = "获取商品订单失败,err:" + err.Error()
  843. return
  844. }
  845. if productOrder.Status != models.OrderStatusRefund && productOrder.RefundStatus != models.RefundStatusSuccess {
  846. br.Msg = "当前订单未完成退款"
  847. br.ErrMsg = "当前订单未完成退款"
  848. return
  849. }
  850. refundOrder, err := models.GetTradeOrderByNo(productOrder.RefundTradeId)
  851. if err != nil {
  852. br.Msg = "获取退款订单失败"
  853. br.ErrMsg = "获取退款订单失败,err:" + err.Error()
  854. return
  855. }
  856. refundResp := response.RefundResp{
  857. Account: refundOrder.PaymentAccount,
  858. RealName: productOrder.RealName,
  859. RefundAmount: productOrder.RefundAmount,
  860. RefundFinishTime: productOrder.RefundFinishTime.Format(time.DateTime),
  861. Remark: productOrder.Remark,
  862. }
  863. br.Ret = 200
  864. br.Success = true
  865. br.Data = refundResp
  866. br.Msg = "退款详情获取成功"
  867. return
  868. }