order.go 30 KB

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