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