OrderController.java 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. package com.cyksj.web.controller.payment;
  2. import cn.hutool.core.util.StrUtil;
  3. import cn.hutool.extra.qrcode.QrCodeUtil;
  4. import cn.hutool.extra.qrcode.QrConfig;
  5. import com.alipay.api.response.AlipayFundTransCommonQueryResponse;
  6. import com.baomidou.mybatisplus.core.toolkit.Wrappers;
  7. import com.cyksj.common.annotation.Log;
  8. import com.cyksj.common.constant.Constant;
  9. import com.cyksj.common.exception.BusinessRuntimeException;
  10. import com.cyksj.common.util.IoKit;
  11. import com.cyksj.common.util.Jsons;
  12. import com.cyksj.common.util.Xmls;
  13. import com.cyksj.config.zfb.BaseZfbConfig;
  14. import com.cyksj.config.zfb.ZfbProductCode;
  15. import com.cyksj.dto.Result;
  16. import com.cyksj.enums.BusinessType;
  17. import com.cyksj.enums.GatewayApiCode;
  18. import com.cyksj.enums.GatewayResponse;
  19. import com.cyksj.mapper.OrderDonMapper;
  20. import com.cyksj.mapper.OrderDonWaybillMapper;
  21. import com.cyksj.mapper.UserMapper;
  22. import com.cyksj.mapper.channel.UserPayEquipmentAvailableBenefitsMapper;
  23. import com.cyksj.mapper.market.task.UserBindDetailMapper;
  24. import com.cyksj.model.dto.AliPayParams;
  25. import com.cyksj.model.dto.H5JsPayParams;
  26. import com.cyksj.model.entity.*;
  27. import com.cyksj.model.manage.views.OrderDonView;
  28. import com.cyksj.model.request.AlipayOrderDonReq;
  29. import com.cyksj.model.request.OrderPayRequest;
  30. import com.cyksj.model.request.WxOrderRefundReq;
  31. import com.cyksj.model.request.ZfbOrderRefundReq;
  32. import com.cyksj.model.response.AliPayTradeStatus;
  33. import com.cyksj.model.views.GoodsDonSkuView;
  34. import com.cyksj.model.views.OrderCommentView;
  35. import com.cyksj.service.order.OrderDonService;
  36. import com.cyksj.service.user.UserService;
  37. import com.cyksj.web.util.StpUserUtil;
  38. import com.ejlchina.searcher.BeanSearcher;
  39. import com.ejlchina.searcher.SearchResult;
  40. import com.ejlchina.searcher.param.Operator;
  41. import com.ejlchina.searcher.util.MapUtils;
  42. import lombok.extern.slf4j.Slf4j;
  43. import org.apache.commons.lang3.StringUtils;
  44. import org.springframework.beans.factory.annotation.Autowired;
  45. import org.springframework.validation.annotation.Validated;
  46. import org.springframework.web.bind.annotation.*;
  47. import javax.annotation.Resource;
  48. import javax.servlet.http.HttpServletRequest;
  49. import javax.servlet.http.HttpServletResponse;
  50. import java.io.OutputStream;
  51. import java.util.HashMap;
  52. import java.util.List;
  53. import java.util.Map;
  54. import java.util.Set;
  55. import java.util.stream.Collectors;
  56. /**
  57. * @author chan
  58. * @date 2021/10/11 下午3:50
  59. */
  60. @Slf4j
  61. @RequestMapping("/applets/order")
  62. @RestController
  63. public class OrderController {
  64. @Autowired
  65. private OrderDonService orderDonService;
  66. @Resource
  67. private BeanSearcher beanSearcher;
  68. @Resource
  69. private HttpServletRequest request;
  70. @Autowired
  71. private OrderDonMapper orderDonMapper;
  72. @Autowired
  73. private UserBindDetailMapper userBindDetailMapper;
  74. @Autowired
  75. private UserMapper userMapper;
  76. @Autowired
  77. private UserPayEquipmentAvailableBenefitsMapper availableBenefitsMapper;
  78. @Autowired
  79. private OrderDonWaybillMapper waybillMapper;
  80. @Autowired
  81. private UserService userService;
  82. /**
  83. * 支付
  84. * @author chan
  85. * @date 2021-10-11 下午4:56
  86. */
  87. @PostMapping("/post/submit")
  88. public Result<OrderDon> submit(@Validated @RequestBody OrderPayRequest payRequest) throws Exception {
  89. final String methodName = "吊起微信支付";
  90. if (payRequest.getIsNoLogin() == null || !payRequest.getIsNoLogin()) {
  91. payRequest.setUserId(StpUserUtil.getLoginIdAsLong());
  92. }
  93. log.info("{}[start] params:{}",methodName,payRequest);
  94. OrderDon orderDon = orderDonService.submit(payRequest);
  95. return GatewayResponse.SUCCESS.newBuilder().toResult(orderDon);
  96. }
  97. /**
  98. * 支付
  99. * @author chan
  100. * @date 2021-10-11 下午4:56
  101. */
  102. @PostMapping("/post/pay/{orderId}")
  103. public Result<H5JsPayParams> pay(@PathVariable Long orderId) throws Exception {
  104. final String methodName = "吊起微信支付";
  105. log.info("{}[start] orderId:{}",methodName,orderId);
  106. H5JsPayParams payParams = orderDonService.pay(orderId, "JSAPI");
  107. return GatewayResponse.SUCCESS.newBuilder().toResult(payParams);
  108. }
  109. /**
  110. * 调用生成订单之后
  111. * 微信网页预下单获取交易链接生成二维码
  112. */
  113. @PostMapping("/get/wx/orderQrCode/{orderId}")
  114. public Result<String> createUnifiedOrderQr(@PathVariable Long orderId) throws Exception {
  115. //预下单
  116. H5JsPayParams payParams = orderDonService.wxPcWebPay(orderId, "NATIVE");
  117. //获取二维码链接code_url
  118. String codeUrl = payParams.getCodeUrl();
  119. QrConfig qrConfig = new QrConfig(300, 300);
  120. return GatewayResponse.SUCCESS.newBuilder().toResult(QrCodeUtil.generateAsBase64(codeUrl, qrConfig, "png"));
  121. }
  122. /**
  123. * 微信订单退款
  124. */
  125. @PostMapping("/wx/refund")
  126. @Log(module = "订单管理/微信退款", businessType = BusinessType.PUT, isSaveRequestData = true)
  127. public Result<String> wxRefund(@RequestBody @Validated WxOrderRefundReq wxOrderRefundReq) throws Exception {
  128. return orderDonService.wxRefund(wxOrderRefundReq);
  129. }
  130. /**
  131. * 微信退款回调
  132. */
  133. @PostMapping("/wx/refund/notify")
  134. public void wxRefundNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
  135. String xml = IoKit.toString(request.getInputStream());
  136. log.info("=== 退款成功的回调: \n {}", xml);
  137. // 解析xml
  138. Map<String, String> map = Xmls.toMap(xml);
  139. // 退款失败
  140. if (!StrUtil.equals("SUCCESS", map.get("return_code"))) {
  141. throw BusinessRuntimeException.getInstance("退款失败.");
  142. }
  143. orderDonService.wxRefundNotify(map);
  144. String toWechatXmlResponse = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
  145. OutputStream out = null;
  146. try {
  147. out = response.getOutputStream();
  148. IoKit.write(toWechatXmlResponse, out);
  149. } catch (Throwable e) {
  150. throw BusinessRuntimeException.getInstance(e == null ? null : e.getMessage());
  151. } finally {
  152. IoKit.close(out);
  153. }
  154. }
  155. /**
  156. * 微信支付回调
  157. * @author chan
  158. * @date 2021-10-11 下午5:42
  159. */
  160. @PostMapping("/prepay/notify")
  161. public void prepayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
  162. String xml = IoKit.toString(request.getInputStream());
  163. log.info("=== 基金会分发支付成功的回调: \n {}", xml);
  164. // 解析xml
  165. Map<String, String> map = Xmls.toMap(xml);
  166. // 支付失败
  167. if (!StringUtils.equals("SUCCESS", map.get("return_code")) || !StringUtils.equals("SUCCESS", map.get("result_code"))) {
  168. throw BusinessRuntimeException.getInstance("支付失败.");
  169. }
  170. orderDonService.prepayNotify(map);
  171. String toWeChatXmlResponse = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
  172. OutputStream out = null;
  173. try {
  174. out = response.getOutputStream();
  175. IoKit.write(toWeChatXmlResponse, out);
  176. } catch (Exception e) {
  177. throw BusinessRuntimeException.getInstance(e,e.getMessage());
  178. } finally {
  179. IoKit.close(out);
  180. }
  181. }
  182. /**
  183. * pc端微信支付回调
  184. * @author chan
  185. * @date 2021-10-11 下午5:42
  186. */
  187. @PostMapping("/pc/prepay/notify")
  188. public void pcPrepayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
  189. String xml = IoKit.toString(request.getInputStream());
  190. log.info("=== 微信pc端分发支付成功的回调: \n {}", xml);
  191. // 解析xml
  192. Map<String, String> map = Xmls.toMap(xml);
  193. // 支付失败
  194. if (!StringUtils.equals("SUCCESS", map.get("return_code")) || !StringUtils.equals("SUCCESS", map.get("result_code"))) {
  195. throw BusinessRuntimeException.getInstance("支付失败.");
  196. }
  197. orderDonService.prepayNotify(map);
  198. log.info("pc端微信支付回调修改订单状态成功");
  199. String toWeChatXmlResponse = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
  200. OutputStream out = null;
  201. try {
  202. out = response.getOutputStream();
  203. IoKit.write(toWeChatXmlResponse, out);
  204. } catch (Exception e) {
  205. throw BusinessRuntimeException.getInstance(e,e.getMessage());
  206. } finally {
  207. IoKit.close(out);
  208. }
  209. }
  210. /**
  211. * 支付宝表单支付
  212. * 支付宝调起支付宝表单
  213. */
  214. @PostMapping("/post/pay/zfb")
  215. @Deprecated
  216. public Result<String> aliPay(@RequestBody @Validated AlipayOrderDonReq re) throws Exception {
  217. Long orderId = re.getOrderId();
  218. String returnUrl = re.getReturnUrl();
  219. AliPayParams aliPayParams = orderDonService.aliPay(orderId, returnUrl, ZfbProductCode.MOBILE_WEB.getProductCode(), null);
  220. // response.setContentType("text/html;charset=" + BaseZfbConfig.charset);
  221. //直接将完整的表单html输出到页面
  222. // response.getWriter().write(aliPayParams.getBody());
  223. // response.getWriter().flush();
  224. // response.getWriter().close();
  225. return GatewayResponse.SUCCESS.newBuilder().toResult(aliPayParams.getBody());
  226. }
  227. /**
  228. * 支付宝web支付
  229. * pc网页内嵌二维码
  230. */
  231. @PostMapping("/get/zfb/orderQrCode")
  232. public Result<String> zfbWebQrCode(@RequestBody @Validated AlipayOrderDonReq re) throws Exception {
  233. Long orderId = re.getOrderId();
  234. String returnUrl = re.getReturnUrl();
  235. AliPayParams aliPayParams = orderDonService.aliPay(orderId, returnUrl, ZfbProductCode.PC_WEB.getProductCode(), BaseZfbConfig.qrPayMode_orderCode);
  236. // response.setContentType("text/html;charset=" + BaseZfbConfig.charset);
  237. //直接将完整的表单html输出到页面
  238. // response.getWriter().write(aliPayParams.getBody());
  239. // response.getWriter().flush();
  240. // response.getWriter().close();
  241. return GatewayResponse.SUCCESS.newBuilder().toResult(aliPayParams.getBody());
  242. }
  243. /**
  244. * 支付宝web支付
  245. * pc网页跳转二维码
  246. */
  247. @PostMapping("/get/zfb/orderRedirect")
  248. public Result<String> zfbWebRedirectQrCode(@RequestBody @Validated AlipayOrderDonReq re) throws Exception {
  249. Long orderId = re.getOrderId();
  250. String returnUrl = re.getReturnUrl();
  251. AliPayParams aliPayParams = orderDonService.aliPay(orderId, returnUrl, ZfbProductCode.PC_WEB.getProductCode(), BaseZfbConfig.qrPayMode_redirect);
  252. return GatewayResponse.SUCCESS.newBuilder().toResult(aliPayParams.getBody());
  253. }
  254. /**
  255. * 支付宝退款
  256. */
  257. @PostMapping("/zfb/refund")
  258. @Log(module = "订单管理/支付宝退款", businessType = BusinessType.PUT, isSaveRequestData = true)
  259. public Result<String> zfbOrderRefund(@RequestBody @Validated ZfbOrderRefundReq zfbOrderRefundReq) throws Exception {
  260. return orderDonService.zfbRefund(zfbOrderRefundReq);
  261. }
  262. /**
  263. * 支付宝回调
  264. */
  265. @PostMapping("/prepay/zfb/notify")
  266. public String aliPayNotify(HttpServletRequest request) throws Exception {
  267. ////将异步通知中收到的所有参数都存放到map中
  268. Map<String, String> params = convertRequestParamsToMap(request);
  269. String tradeStatus = params.get("trade_status");
  270. String orderNo = params.get("out_trade_no");
  271. if (AliPayTradeStatus.TRADE_SUCCESS.getStatus().equals(tradeStatus) || AliPayTradeStatus.TRADE_FINISHED.getStatus().equals(tradeStatus)) {
  272. log.info("支付宝商家订单号orderNo:{},status:{}开始回调", orderNo, tradeStatus);
  273. orderDonService.aliPayNotify(params);
  274. } else {
  275. log.error("支付宝回调 error 状态不符合 成功或完成 status:{} ,orderNo:{}", tradeStatus, orderNo);
  276. return "fail";
  277. }
  278. return "success";
  279. }
  280. /**
  281. * 支付宝转账
  282. */
  283. // @PostMapping("/zfb/transfer/accounts")
  284. // @NoSubmit
  285. // public Result<String> zfbTransferAccounts(@RequestBody @Validated TransferAccountsReq transferAccountsReq) throws Exception {
  286. // long userId = StpUserUtil.getLoginIdAsLong();
  287. // transferAccountsReq.setUserId(userId);
  288. // orderDonService.transferAccounts(transferAccountsReq);
  289. // return GatewayResponse.SUCCESS.newBuilder().toResult("转账成功");
  290. // }
  291. /**
  292. * 查询支付宝转账状态
  293. */
  294. @GetMapping("/zfb/transfer/status")
  295. public Result<String> getTransFerStatusByTid(String translationId) throws Exception {
  296. AlipayFundTransCommonQueryResponse response = orderDonService.getTransFerStatusByTid(translationId);
  297. if (response.isSuccess()) {
  298. if (!Constant.SUCCESS.equals(response.getStatus())) {
  299. return GatewayResponse.SUCCESS.newBuilder().toResult(response.getFailReason());
  300. }
  301. return GatewayResponse.SUCCESS.newBuilder().toResult("该红包已转账成功");
  302. }
  303. return GatewayResponse.SUCCESS.newBuilder().toResult(response.getSubMsg());
  304. }
  305. /**
  306. * 获取订单列表
  307. */
  308. @GetMapping("/get")
  309. public Result<SearchResult<OrderDonView>> list(){
  310. long userId = StpUserUtil.getLoginIdAsLong();
  311. List<Long> userIds = userService.getRelationUserIdList(userId, null);
  312. SearchResult<OrderDonView> search = beanSearcher.search(OrderDonView.class, MapUtils.flatBuilder(request.getParameterMap())
  313. .field(OrderDonView::getUserId, userIds).op(Operator.InList)
  314. .orderBy(OrderDonView::getId).desc()
  315. .build());
  316. search.getDataList().forEach(data->{
  317. Integer count = availableBenefitsMapper.selectCount(Wrappers.lambdaQuery(UserPayEquipmentAvailableBenefits.class)
  318. .eq(UserPayEquipmentAvailableBenefits::getRealOrderId, data.getId())
  319. .eq(UserPayEquipmentAvailableBenefits::getDeleted, true));
  320. data.setIsHasBenefits(count > 0 ? true : false);
  321. if (data.getIsBenefits() != null && data.getIsBenefits()) {
  322. String benefitsList = data.getBenefitsList();
  323. if (StrUtil.isNotBlank(benefitsList)) {
  324. try {
  325. List<Long> skuIds = Jsons.parseList(benefitsList, GoodsDonSku.class).stream().map(GoodsDonSku::getId).collect(Collectors.toList());
  326. data.setBenefitsViews(beanSearcher.searchAll(GoodsDonSkuView.class, MapUtils.builder().field(GoodsDonSkuView::getSkuId, skuIds).op(Operator.InList).build()));
  327. } catch (Exception e) {
  328. }
  329. }
  330. }
  331. data.setWaybill(waybillMapper.selectOne(Wrappers.lambdaQuery(OrderDonWaybill.class).eq(OrderDonWaybill::getOrderId, data.getId()).last("limit 1")));
  332. });
  333. return GatewayResponse.SUCCESS.newBuilder().toResult(search);
  334. }
  335. /**
  336. * 获取订单详情
  337. */
  338. @GetMapping("/get/{orderId}")
  339. public Result<OrderDetailView> detail(@PathVariable Long orderId, Boolean isNoLogin) {
  340. Long userId = null;
  341. if (isNoLogin == null || !isNoLogin) {
  342. userId = StpUserUtil.getLoginIdAsLong();
  343. }
  344. OrderDetailView detail = orderDonService.getDetail(orderId, userId);
  345. return GatewayResponse.SUCCESS.newBuilder().toResult(detail);
  346. }
  347. /**
  348. * 取消订单
  349. */
  350. @GetMapping("/get/close/{orderId}")
  351. public Result<String> closeOrder(@PathVariable Long orderId){
  352. orderDonService.closeOrder(orderId);
  353. return GatewayResponse.SUCCESS.newBuilder().toResult();
  354. }
  355. @GetMapping("/get/order/status/{orderId}")
  356. public Result<OrderDonView> getOrderStatusById(@PathVariable Long orderId) {
  357. if (orderId < 1) {
  358. throw BusinessRuntimeException.getInstance("订单不存在");
  359. }
  360. OrderDonView orderDonView = orderDonMapper.getOrderDetail(orderId);
  361. if (orderDonView == null) {
  362. throw BusinessRuntimeException.getInstance("订单不存在");
  363. }
  364. return GatewayResponse.SUCCESS.newBuilder().toResult(orderDonView);
  365. }
  366. @PostMapping("/get/noLogin/order")
  367. public Result<List<OrderDonView>> getSearchResult(@RequestBody List<Long> orderIds) {
  368. List<OrderDonView> orderDonViews = beanSearcher.searchAll(OrderDonView.class, MapUtils.builder()
  369. .field(OrderDonView::getId, orderIds).op(Operator.InList)
  370. .orderBy(OrderDonView::getId).desc().build());
  371. return GatewayResponse.SUCCESS.newBuilder().toResult(orderDonViews);
  372. }
  373. /**
  374. * 平台评论列表
  375. */
  376. @GetMapping("/get/orderComment")
  377. public Result<SearchResult<OrderCommentView>> getOrderCommentView() {
  378. SearchResult<OrderCommentView> search = beanSearcher.search(OrderCommentView.class, MapUtils.flatBuilder(request.getParameterMap()).build());
  379. return GatewayResponse.SUCCESS.newBuilder().toResult(search);
  380. }
  381. /**
  382. * 电脑端手机号注册 购买车票是否绑定了微信用户
  383. */
  384. @GetMapping("/isBindWx")
  385. public Result<Boolean> isBindWx() {
  386. Long userId = StpUserUtil.getLoginIdAsLong();
  387. User user = userMapper.selectById(userId);
  388. if (user == null) {
  389. throw BusinessRuntimeException.getGatewayApiCode(GatewayApiCode.CMS_TOKEN_VALID);
  390. }
  391. if (StrUtil.isEmpty(user.getLoginPhone())) {
  392. return GatewayResponse.SUCCESS.newBuilder().toResult(true);
  393. }
  394. UserBindDetail userBindDetail = userBindDetailMapper.selectOne(Wrappers.lambdaQuery(UserBindDetail.class)
  395. .eq(UserBindDetail::getPhone, user.getLoginPhone()));
  396. if (userBindDetail == null) {
  397. return GatewayResponse.SUCCESS.newBuilder().toResult(false);
  398. }
  399. return GatewayResponse.SUCCESS.newBuilder().toResult(true);
  400. }
  401. /**
  402. * 是否绑定了邮箱或手机号
  403. */
  404. @GetMapping("/isBind")
  405. public Result<Boolean> isBindPhoneOrEmail() {
  406. Long userId = StpUserUtil.getLoginIdAsLong();
  407. User user = userMapper.selectById(userId);
  408. if (user == null) {
  409. throw BusinessRuntimeException.getGatewayApiCode(GatewayApiCode.CMS_TOKEN_VALID);
  410. }
  411. if (StrUtil.isEmpty(user.getOpenId())) {
  412. return GatewayResponse.SUCCESS.newBuilder().toResult(true);
  413. }
  414. UserBindDetail userBindDetail = userBindDetailMapper.selectOne(Wrappers.lambdaQuery(UserBindDetail.class)
  415. .eq(UserBindDetail::getUserId, userId));
  416. if (userBindDetail == null) {
  417. return GatewayResponse.SUCCESS.newBuilder().toResult(false);
  418. }
  419. return GatewayResponse.SUCCESS.newBuilder().toResult(true);
  420. }
  421. /**
  422. * 获取支付宝回调参数
  423. */
  424. private static Map<String, String> convertRequestParamsToMap(HttpServletRequest request) {
  425. Map<String, String> retMap = new HashMap<>();
  426. Set<Map.Entry<String, String[]>> entrySet = request.getParameterMap().entrySet();
  427. for (Map.Entry<String, String[]> entry : entrySet) {
  428. String name = entry.getKey();
  429. String[] values = entry.getValue();
  430. int valLen = values.length;
  431. if (valLen == 1) {
  432. retMap.put(name, values[0]);
  433. } else if (valLen > 1) {
  434. StringBuilder sb = new StringBuilder();
  435. for (String val : values) {
  436. sb.append(",").append(val);
  437. }
  438. retMap.put(name, sb.substring(1));
  439. } else {
  440. retMap.put(name, "");
  441. }
  442. }
  443. return retMap;
  444. }
  445. }