order.go 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893
  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 + "%' 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. productOrder, pdErr := models.GetProductOrderByID(order.ProductOrderId)
  358. if pdErr != nil {
  359. utils.FileLog.Error("获取商品订单信息失败,Err:" + pdErr.Error())
  360. }
  361. view := &models.TradeOrderView{
  362. RealName: productOrder.RealName,
  363. Mobile: fmt.Sprintf("+%s %s", productOrder.AreaCode, productOrder.Mobile),
  364. ProductName: productOrder.ProductName,
  365. Amount: fmt.Sprintf("¥%s", order.Amount),
  366. TransactionID: order.TransactionId,
  367. ProductOrderID: order.ProductOrderId,
  368. PaymentWay: PaymentWayMap[order.PaymentWay],
  369. PaymentAccount: order.PaymentAccount,
  370. MerchantID: order.MerchantId,
  371. CreatedTime: order.CreatedTime.Format(time.DateTime),
  372. }
  373. if order.PaymentStatus == models.PaymentStatusDone {
  374. view.DealTime = order.DealTime.Format(time.DateTime)
  375. }
  376. if IsRefund {
  377. view.PaymentStatus = RefundOrderStatus[order.PaymentStatus]
  378. } else {
  379. view.PaymentStatus = TradeOrderStatus[order.PaymentStatus]
  380. }
  381. ListView = append(ListView, view)
  382. }(List[i])
  383. }
  384. wg.Wait()
  385. page := paging.GetPaging(currentIndex, pageSize, total)
  386. resp := new(response.TradeOrderListResp)
  387. resp.List = ListView
  388. resp.Paging = page
  389. br.Ret = 200
  390. br.Success = true
  391. br.Data = resp
  392. br.Msg = "获取成功"
  393. }
  394. // ExportProductOrder
  395. // @Title 临时用户列表
  396. // @Description 临时用户列表
  397. // @Param PageSize query int true "每页数据条数"
  398. // @Param CurrentIndex query int true "当前页页码,从1开始"
  399. // @Param Keyword query string false "手机号"
  400. // @Param SortParam query string false "排序字段参数,用来排序的字段, 枚举值:0:注册时间,1:阅读数,2:最近一次阅读时间"
  401. // @Param SortType query string true "如何排序,是正序还是倒序,0:倒序,1:正序"
  402. // @Success 200 {object} response.TemplateUserListResp
  403. // @router /productOrder/export [get]
  404. func (this *OrderController) ExportProductOrder() {
  405. br := new(models.BaseResponse).Init()
  406. defer func() {
  407. this.Data["json"] = br
  408. this.ServeJSON()
  409. }()
  410. pageSize, _ := this.GetInt("PageSize")
  411. currentIndex, _ := this.GetInt("CurrentIndex")
  412. sortType := this.GetString("SortType")
  413. KeyWord := this.GetString("KeyWord")
  414. PaymentDate := this.GetString("PaymentDate")
  415. PaymentWay := this.GetString("PaymentWay")
  416. CreatedDate := this.GetString("CreatedDate")
  417. ProductType := this.GetString("ProductType")
  418. RefundStatus := this.GetString("RefundStatus")
  419. OrderStatus := this.GetString("OrderStatus")
  420. var condition string
  421. if pageSize <= 0 {
  422. pageSize = utils.PageSize20
  423. }
  424. if currentIndex <= 0 {
  425. currentIndex = 1
  426. }
  427. if KeyWord != "" {
  428. condition += " AND (product_name like '%" + KeyWord + "%' or real_name like '%" + KeyWord + "%' order_id like '%" + KeyWord + "%' or mobile like '%" + KeyWord + "%')"
  429. }
  430. sortCondition := " ORDER BY created_time "
  431. if sortType == "" {
  432. sortType = "DESC"
  433. }
  434. if CreatedDate != "" {
  435. condition += " AND Date(created_time) = '" + CreatedDate + "'"
  436. }
  437. if PaymentDate != "" {
  438. condition += " AND Date(payment_time) = '" + PaymentDate + "'"
  439. }
  440. if PaymentWay != "" {
  441. condition += " AND payment_way='" + PaymentWay + "'"
  442. }
  443. if OrderStatus != "" {
  444. switch OrderStatus {
  445. case "pending":
  446. condition += " AND status='pending'"
  447. case "paid":
  448. condition += " AND status='paid'"
  449. case "closed":
  450. condition += " AND status='closed'"
  451. case "refund":
  452. condition += " AND status='refund'"
  453. if RefundStatus != "" {
  454. switch RefundStatus {
  455. case "pending":
  456. condition += " AND refund_status='pending'"
  457. case "processing":
  458. condition += " AND refund_status='processing'"
  459. case "failed":
  460. condition += " AND refund_status='failed'"
  461. case "success":
  462. condition += " AND refund_status='success'"
  463. }
  464. }
  465. default:
  466. br.Msg = "无效的订单状态"
  467. br.ErrMsg = "无效的订单状态:" + OrderStatus
  468. return
  469. }
  470. }
  471. if ProductType != "" {
  472. switch ProductType {
  473. case "report":
  474. condition += " AND product_type='" + string(models.ProductReport) + "'"
  475. case "audio":
  476. condition += " AND product_type='" + string(models.ProductAudio) + "'"
  477. case "video":
  478. condition += " AND product_type='" + string(models.ProductVideo) + "'"
  479. case "package":
  480. condition += " AND product_type='" + string(models.ProductPackage) + "'"
  481. default:
  482. br.Msg = "无效的产品类型"
  483. br.ErrMsg = "无效的产品类型:" + ProductType
  484. return
  485. }
  486. }
  487. sortCondition = sortCondition + sortType
  488. List, err := models.GetProductOrderListByCondition(condition, sortCondition)
  489. if err != nil {
  490. br.Msg = "导出商品订单失败"
  491. br.ErrMsg = "导出商品订单失败,Err:" + err.Error()
  492. return
  493. }
  494. var ListView []*models.ProductOrderView
  495. var wg sync.WaitGroup
  496. for _, orderItem := range List {
  497. go func(orderItem *models.ProductOrder) {
  498. defer wg.Done()
  499. view := &models.ProductOrderView{
  500. OrderID: orderItem.OrderId,
  501. RealName: orderItem.RealName,
  502. Mobile: fmt.Sprintf("+%s %s", orderItem.AreaCode, orderItem.Mobile),
  503. ProductType: ProductTypeMap[orderItem.ProductType],
  504. ProductName: orderItem.ProductName,
  505. TotalAmount: fmt.Sprintf("¥%s", orderItem.TotalAmount),
  506. TradeNO: orderItem.TradeNo,
  507. RefundAmount: orderItem.RefundAmount,
  508. RefundTradeId: orderItem.RefundTradeId,
  509. PaymentWay: PaymentWayMap[orderItem.PaymentWay],
  510. PaymentTime: orderItem.PaymentTime.Format(time.DateTime),
  511. Status: ProductOrderStatus[orderItem.Status],
  512. RefundStatus: RefundStatusMap[orderItem.RefundStatus],
  513. Remark: orderItem.Remark,
  514. CreatedTime: orderItem.CreatedTime.Format(time.DateTime),
  515. }
  516. if orderItem.TradeNo != "" {
  517. view.PaymentTime = orderItem.PaymentTime.Format(time.DateTime)
  518. tradeOrder, tradeErr := models.GetTradeOrderByNo(orderItem.TradeNo)
  519. if tradeErr != nil {
  520. utils.FileLog.Error("获取支付订单失败,支付订单号:" + orderItem.TradeNo + ",err:" + tradeErr.Error())
  521. } else {
  522. view.PaymentAmount = fmt.Sprintf("¥%s", tradeOrder.Amount)
  523. }
  524. }
  525. if orderItem.Status == models.OrderStatusPaid {
  526. access, accessErr := models.GetAccess(orderItem.ProductId, orderItem.TemplateUserId)
  527. if accessErr != nil {
  528. utils.FileLog.Error("获取用户订阅记录失败,templateUserId:" + string(rune(orderItem.TemplateUserId)) + "productId:" + string(rune(orderItem.ProductId)) + ",err:" + accessErr.Error())
  529. } else {
  530. if access.ProductType == models.ProductPackage {
  531. view.ValidDuration = fmt.Sprintf("%s~%s", access.BeginDate.Format(time.DateOnly), access.EndDate.Format(time.DateOnly))
  532. } else {
  533. view.ValidDuration = "永久有效"
  534. }
  535. }
  536. }
  537. if orderItem.Status == models.OrderStatusRefund && orderItem.RefundStatus == models.RefundStatusSuccess {
  538. view.RefundFinishTime = orderItem.RefundFinishTime.Format(time.DateTime)
  539. }
  540. ListView = append(ListView, view)
  541. }(orderItem)
  542. }
  543. wg.Wait()
  544. year, month, day := time.Now().Date()
  545. yearStr := strconv.Itoa(year)[2:]
  546. fileName := fmt.Sprintf("商品订单%s.%d.%d.xlsx", yearStr, month, day)
  547. file, err := utils.ExportExcel("商品订单", productCols, ListView)
  548. _ = this.downloadExcelFile(file, fileName)
  549. br.Ret = 200
  550. br.Success = true
  551. br.Msg = "下载成功"
  552. }
  553. // ExportTradeOrder
  554. // @Title 临时用户列表
  555. // @Description 临时用户列表
  556. // @Param PageSize query int true "每页数据条数"
  557. // @Param CurrentIndex query int true "当前页页码,从1开始"
  558. // @Param Keyword query string false "手机号"
  559. // @Param SortParam query string false "排序字段参数,用来排序的字段, 枚举值:0:注册时间,1:阅读数,2:最近一次阅读时间"
  560. // @Param SortType query string true "如何排序,是正序还是倒序,0:倒序,1:正序"
  561. // @Success 200 {object} response.TemplateUserListResp
  562. // @router /tradeOrder/export [get]
  563. func (this *OrderController) ExportTradeOrder() {
  564. br := new(models.BaseResponse).Init()
  565. defer func() {
  566. this.Data["json"] = br
  567. this.ServeJSON()
  568. }()
  569. pageSize, _ := this.GetInt("PageSize")
  570. currentIndex, _ := this.GetInt("CurrentIndex")
  571. sortType := this.GetString("SortType")
  572. KeyWord := this.GetString("KeyWord")
  573. DealDate := this.GetString("DealDate")
  574. PaymentWay := this.GetString("PaymentWay")
  575. CreatedDate := this.GetString("CreatedDate")
  576. OrderStatus := this.GetString("OrderStatus")
  577. IsRefund, _ := this.GetBool("IsRefund", false)
  578. var condition string
  579. if pageSize <= 0 {
  580. pageSize = utils.PageSize20
  581. }
  582. if currentIndex <= 0 {
  583. currentIndex = 1
  584. }
  585. if IsRefund {
  586. condition += " AND payment_type ='" + string(models.PaymentTypeRefund) + "'"
  587. } else {
  588. condition += " AND payment_type ='" + string(models.PaymentTypePay) + "'"
  589. }
  590. if KeyWord != "" {
  591. condition += " AND (product_name like '%" + KeyWord + "%' or real_name like '%" + KeyWord + "%' order_id like '%" + KeyWord + "%' or mobile like '%" + KeyWord + "%')"
  592. }
  593. sortCondition := " ORDER BY created_time "
  594. if sortType == "" {
  595. sortType = "DESC"
  596. }
  597. if CreatedDate != "" {
  598. condition += " AND Date(created_time) = '" + CreatedDate + "'"
  599. }
  600. if DealDate != "" {
  601. condition += " AND Date(deal_time) = '" + DealDate + "'"
  602. }
  603. if PaymentWay != "" {
  604. condition += " AND payment_way='" + PaymentWay + "'"
  605. }
  606. if OrderStatus != "" {
  607. switch OrderStatus {
  608. case "pending":
  609. condition += " AND payment_status='pending'"
  610. case "done":
  611. condition += " AND payment_status='done'"
  612. case "failed":
  613. condition += " AND payment_status='failed'"
  614. default:
  615. br.Msg = "无效的支付订单状态"
  616. br.ErrMsg = "无效的支付订单状态:" + OrderStatus
  617. return
  618. }
  619. }
  620. sortCondition = sortCondition + sortType
  621. List, err := models.GetTradeOrderListByCondition(condition, sortCondition)
  622. if err != nil {
  623. br.Msg = "获取支付明细列表失败"
  624. br.ErrMsg = "获取支付明细列表失败,Err:" + err.Error()
  625. return
  626. }
  627. var ListView []models.TradeOrderView
  628. var wg sync.WaitGroup
  629. wg.Add(len(List))
  630. for i := 0; i < len(List); i++ {
  631. go func(order *models.TradeOrder) {
  632. defer wg.Done()
  633. productOrder, pdErr := models.GetProductOrderByID(order.ProductOrderId)
  634. if pdErr != nil {
  635. utils.FileLog.Error("获取商品订单信息失败,Err:" + pdErr.Error())
  636. }
  637. view := models.TradeOrderView{
  638. RealName: productOrder.RealName,
  639. Mobile: fmt.Sprintf("+%s %s", productOrder.AreaCode, productOrder.Mobile),
  640. ProductName: productOrder.ProductName,
  641. Amount: fmt.Sprintf("¥%s", order.Amount),
  642. TransactionID: order.TransactionId,
  643. ProductOrderID: order.ProductOrderId,
  644. PaymentWay: PaymentWayMap[order.PaymentWay],
  645. PaymentAccount: order.PaymentAccount,
  646. MerchantID: order.MerchantId,
  647. CreatedTime: order.CreatedTime.Format(time.DateTime),
  648. }
  649. if order.PaymentStatus == models.PaymentStatusDone {
  650. view.DealTime = order.DealTime.Format(time.DateTime)
  651. }
  652. if IsRefund {
  653. view.PaymentStatus = RefundOrderStatus[order.PaymentStatus]
  654. } else {
  655. view.PaymentStatus = TradeOrderStatus[order.PaymentStatus]
  656. }
  657. ListView = append(ListView, view)
  658. }(List[i])
  659. }
  660. wg.Wait()
  661. year, month, day := time.Now().Date()
  662. yearStr := strconv.Itoa(year)[2:]
  663. if IsRefund {
  664. fileName := fmt.Sprintf("退款明细%s.%d.%d.xlsx", yearStr, month, day)
  665. file, _ := utils.ExportExcel("退款明细", refundCols, ListView)
  666. _ = this.downloadExcelFile(file, fileName)
  667. } else {
  668. fileName := fmt.Sprintf("支付明细%s.%d.%d.xlsx", yearStr, month, day)
  669. file, _ := utils.ExportExcel("支付明细", tradeCols, ListView)
  670. _ = this.downloadExcelFile(file, fileName)
  671. }
  672. br.Ret = 200
  673. br.Success = true
  674. br.Msg = "下载成功"
  675. }
  676. // encodeChineseFilename 将中文文件名编码为 ISO-8859-1
  677. func (this *OrderController) downloadExcelFile(file *excelize.File, filename string) (err error) {
  678. // 对文件名进行 ISO-8859-1 编码
  679. fn := url.QueryEscape(filename)
  680. if filename == fn {
  681. fn = "filename=" + fn
  682. } else {
  683. fn = "filename=" + filename + "; filename*=utf-8''" + fn
  684. }
  685. this.Ctx.ResponseWriter.Header().Set("Access-Control-Expose-Headers", "Content-Disposition")
  686. this.Ctx.ResponseWriter.Header().Set("Content-Disposition", "attachment; "+fn)
  687. this.Ctx.ResponseWriter.Header().Set("Content-Description", "File Transfer")
  688. this.Ctx.ResponseWriter.Header().Set("Content-Type", "application/octet-stream")
  689. this.Ctx.ResponseWriter.Header().Set("Content-Transfer-Encoding", "binary")
  690. this.Ctx.ResponseWriter.Header().Set("Expires", "0")
  691. this.Ctx.ResponseWriter.Header().Set("Cache-Control", "must-revalidate")
  692. this.Ctx.ResponseWriter.Header().Set("Pragma", "public")
  693. this.Ctx.ResponseWriter.Header().Set("File-Name", filename)
  694. // 写入文件
  695. if err = file.Write(this.Ctx.ResponseWriter); err != nil {
  696. utils.FileLog.Error("导出excel文件失败:", err)
  697. http.Error(this.Ctx.ResponseWriter, "导出excel文件失败", http.StatusInternalServerError)
  698. }
  699. return
  700. }
  701. // Refund
  702. // @Title 退款
  703. // @Description 退款
  704. // @Param PageSize query int true "每页数据条数"
  705. // @Param CurrentIndex query int true "当前页页码,从1开始"
  706. // @Param ClassifyIds query string true "二级分类id,可多选用英文,隔开"
  707. // @Param KeyWord query string true "报告标题/创建人"
  708. // @Param SortType query string true "排序方式"
  709. // @Success 200 {object} models.ReportAuthorResp
  710. // @router /refund [post]
  711. func (this *OrderController) Refund() {
  712. br := new(models.BaseResponse).Init()
  713. defer func() {
  714. this.Data["json"] = br
  715. this.ServeJSON()
  716. }()
  717. var req request.RefundReq
  718. if err := json.Unmarshal(this.Ctx.Input.RequestBody, &req); err != nil {
  719. br.Msg = "参数解析失败"
  720. br.ErrMsg = "参数解析失败,Err:" + err.Error()
  721. return
  722. }
  723. if req.ProductOrderNo == "" {
  724. br.Msg = "商品订单号不能为空"
  725. br.ErrMsg = "商品订单号不能为空"
  726. return
  727. }
  728. productOrder, err := models.GetProductOrderByID(req.ProductOrderNo)
  729. if err != nil {
  730. br.Msg = "获取商品订单失败"
  731. br.ErrMsg = "获取商品订单失败,err:" + err.Error()
  732. return
  733. }
  734. if productOrder.Status == models.OrderStatusPending {
  735. br.Msg = "退款失败,"
  736. br.ErrMsg = "退款失败,退款状态异常,当前订单已关闭"
  737. return
  738. }
  739. if productOrder.Status == models.OrderStatusRefund && productOrder.RefundStatus != models.RefundStatusFailed {
  740. br.Msg = "退款失败,"
  741. br.ErrMsg = "退款失败,当前订单退款处理中"
  742. return
  743. }
  744. tradeOrder, err := models.GetTradeOrderByNo(productOrder.TradeNo)
  745. if err != nil {
  746. br.Msg = "退款失败,获取原订单失败"
  747. br.ErrMsg = "退款失败,获取原订单失败,err:" + err.Error()
  748. return
  749. }
  750. if tradeOrder.PaymentType != models.PaymentTypePay {
  751. br.Msg = "退款失败,原订单非支付订单"
  752. br.ErrMsg = "退款失败,原订单非支付订单"
  753. return
  754. }
  755. if tradeOrder.PaymentStatus != models.PaymentStatusDone {
  756. br.Msg = "退款失败,原订单未完成支付"
  757. br.ErrMsg = "退款失败,原订单未完成支付"
  758. return
  759. }
  760. uuidStr := strings.ReplaceAll(uuid.New().String(), "-", "")
  761. key := fmt.Sprintf("refund_lock_%s", productOrder.OrderId)
  762. defer func() {
  763. utils.ReleaseLock(key, uuidStr)
  764. }()
  765. if utils.AcquireLock(key, 10, uuidStr) {
  766. aa := GenerateProductOrderNo()
  767. refundOrder := &models.TradeOrder{
  768. TransactionId: aa,
  769. OrgTransactionId: productOrder.TradeNo,
  770. ProductOrderId: productOrder.OrderId,
  771. PaymentAccount: tradeOrder.PaymentAccount,
  772. PaymentWay: tradeOrder.PaymentWay,
  773. Amount: tradeOrder.Amount,
  774. Currency: tradeOrder.Currency,
  775. UserId: tradeOrder.UserId,
  776. TemplateUserId: tradeOrder.TemplateUserId,
  777. PaymentType: models.PaymentTypeRefund,
  778. PaymentStatus: models.PaymentStatusPending,
  779. CreatedTime: time.Now(),
  780. }
  781. productOrder.RefundStatus = models.RefundStatusProcessing
  782. productOrder.Status = models.OrderStatusRefund
  783. productOrder.RefundTradeId = refundOrder.TransactionId
  784. productOrder.Remark = req.Remark
  785. productOrder.RefundAmount = tradeOrder.Amount
  786. err = refundOrder.Refund(productOrder)
  787. if err != nil {
  788. br.Msg = "退款失败"
  789. br.ErrMsg = "退款失败,,Err:" + err.Error()
  790. return
  791. }
  792. refundflow := models.RefundDealFlow{
  793. ProductOrderNo: productOrder.OrderId,
  794. RefundOrderNo: refundOrder.TransactionId,
  795. OperatorUserId: this.SysUser.SysUserId,
  796. CreatedTime: time.Now(),
  797. }
  798. //增加一条退款流水
  799. _ = refundflow.Insert()
  800. br.Ret = 200
  801. br.Success = true
  802. br.Msg = "退款处理成功"
  803. } else {
  804. br.Msg = "退款失败,当前订单正在退款中"
  805. br.ErrMsg = "退款失败,当前订单正在退款中"
  806. return
  807. }
  808. }
  809. func GenerateProductOrderNo() string {
  810. timestamp := time.Now().UnixNano() / 1000000 // 毫秒级时间戳
  811. // 生成随机数
  812. rand.New(rand.NewSource(time.Now().UnixNano()))
  813. randomPart := rand.Intn(999999)
  814. // 格式化订单号
  815. orderNumber := fmt.Sprintf("R%d%06d", timestamp, randomPart)
  816. return orderNumber
  817. }
  818. // RefundDetail
  819. // @Title 退款详情
  820. // @Description 退款详情
  821. // @Param PageSize query int true "每页数据条数"
  822. // @Param CurrentIndex query int true "当前页页码,从1开始"
  823. // @Param ClassifyIds query string true "二级分类id,可多选用英文,隔开"
  824. // @Param KeyWord query string true "报告标题/创建人"
  825. // @Param SortType query string true "排序方式"
  826. // @Success 200 {object} models.ReportAuthorResp
  827. // @router /refundDetail [get]
  828. func (this *OrderController) RefundDetail() {
  829. br := new(models.BaseResponse).Init()
  830. defer func() {
  831. this.Data["json"] = br
  832. this.ServeJSON()
  833. }()
  834. ProductOrderNo := this.GetString("ProductOrderNo")
  835. if ProductOrderNo == "" {
  836. br.Msg = "商品订单号不能为空"
  837. br.ErrMsg = "商品订单号不能为空"
  838. return
  839. }
  840. productOrder, err := models.GetProductOrderByID(ProductOrderNo)
  841. if err != nil {
  842. br.Msg = "获取商品订单失败"
  843. br.ErrMsg = "获取商品订单失败,err:" + err.Error()
  844. return
  845. }
  846. if productOrder.Status != models.OrderStatusRefund && productOrder.RefundStatus != models.RefundStatusSuccess {
  847. br.Msg = "当前订单未完成退款"
  848. br.ErrMsg = "当前订单未完成退款"
  849. return
  850. }
  851. refundOrder, err := models.GetTradeOrderByNo(productOrder.RefundTradeId)
  852. if err != nil {
  853. br.Msg = "获取退款订单失败"
  854. br.ErrMsg = "获取退款订单失败,err:" + err.Error()
  855. return
  856. }
  857. refundResp := response.RefundResp{
  858. Account: refundOrder.PaymentAccount,
  859. RealName: productOrder.RealName,
  860. RefundAmount: productOrder.RefundAmount,
  861. RefundFinishTime: productOrder.RefundFinishTime.Format(time.DateTime),
  862. Remark: productOrder.Remark,
  863. }
  864. br.Ret = 200
  865. br.Success = true
  866. br.Data = refundResp
  867. br.Msg = "退款详情获取成功"
  868. return
  869. }