package com.cyksj.web.controller.payment; import cn.hutool.core.util.StrUtil; import cn.hutool.extra.qrcode.QrCodeUtil; import cn.hutool.extra.qrcode.QrConfig; import com.alipay.api.response.AlipayFundTransCommonQueryResponse; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.cyksj.common.annotation.Log; import com.cyksj.common.constant.Constant; import com.cyksj.common.exception.BusinessRuntimeException; import com.cyksj.common.util.IoKit; import com.cyksj.common.util.Jsons; import com.cyksj.common.util.Xmls; import com.cyksj.config.zfb.BaseZfbConfig; import com.cyksj.config.zfb.ZfbProductCode; import com.cyksj.dto.Result; import com.cyksj.enums.BusinessType; import com.cyksj.enums.GatewayApiCode; import com.cyksj.enums.GatewayResponse; import com.cyksj.mapper.OrderDonMapper; import com.cyksj.mapper.OrderDonWaybillMapper; import com.cyksj.mapper.UserMapper; import com.cyksj.mapper.channel.UserPayEquipmentAvailableBenefitsMapper; import com.cyksj.mapper.market.task.UserBindDetailMapper; import com.cyksj.model.dto.AliPayParams; import com.cyksj.model.dto.H5JsPayParams; import com.cyksj.model.entity.*; import com.cyksj.model.manage.views.OrderDonView; import com.cyksj.model.request.AlipayOrderDonReq; import com.cyksj.model.request.OrderPayRequest; import com.cyksj.model.request.WxOrderRefundReq; import com.cyksj.model.request.ZfbOrderRefundReq; import com.cyksj.model.response.AliPayTradeStatus; import com.cyksj.model.views.GoodsDonSkuView; import com.cyksj.model.views.OrderCommentView; import com.cyksj.service.order.OrderDonService; import com.cyksj.service.user.UserService; import com.cyksj.web.util.StpUserUtil; import com.ejlchina.searcher.BeanSearcher; import com.ejlchina.searcher.SearchResult; import com.ejlchina.searcher.param.Operator; import com.ejlchina.searcher.util.MapUtils; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.OutputStream; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; /** * @author chan * @date 2021/10/11 下午3:50 */ @Slf4j @RequestMapping("/applets/order") @RestController public class OrderController { @Autowired private OrderDonService orderDonService; @Resource private BeanSearcher beanSearcher; @Resource private HttpServletRequest request; @Autowired private OrderDonMapper orderDonMapper; @Autowired private UserBindDetailMapper userBindDetailMapper; @Autowired private UserMapper userMapper; @Autowired private UserPayEquipmentAvailableBenefitsMapper availableBenefitsMapper; @Autowired private OrderDonWaybillMapper waybillMapper; @Autowired private UserService userService; /** * 支付 * @author chan * @date 2021-10-11 下午4:56 */ @PostMapping("/post/submit") public Result submit(@Validated @RequestBody OrderPayRequest payRequest) throws Exception { final String methodName = "吊起微信支付"; if (payRequest.getIsNoLogin() == null || !payRequest.getIsNoLogin()) { payRequest.setUserId(StpUserUtil.getLoginIdAsLong()); } log.info("{}[start] params:{}",methodName,payRequest); OrderDon orderDon = orderDonService.submit(payRequest); return GatewayResponse.SUCCESS.newBuilder().toResult(orderDon); } /** * 支付 * @author chan * @date 2021-10-11 下午4:56 */ @PostMapping("/post/pay/{orderId}") public Result pay(@PathVariable Long orderId) throws Exception { final String methodName = "吊起微信支付"; log.info("{}[start] orderId:{}",methodName,orderId); H5JsPayParams payParams = orderDonService.pay(orderId, "JSAPI"); return GatewayResponse.SUCCESS.newBuilder().toResult(payParams); } /** * 调用生成订单之后 * 微信网页预下单获取交易链接生成二维码 */ @PostMapping("/get/wx/orderQrCode/{orderId}") public Result createUnifiedOrderQr(@PathVariable Long orderId) throws Exception { //预下单 H5JsPayParams payParams = orderDonService.wxPcWebPay(orderId, "NATIVE"); //获取二维码链接code_url String codeUrl = payParams.getCodeUrl(); QrConfig qrConfig = new QrConfig(300, 300); return GatewayResponse.SUCCESS.newBuilder().toResult(QrCodeUtil.generateAsBase64(codeUrl, qrConfig, "png")); } /** * 微信订单退款 */ @PostMapping("/wx/refund") @Log(module = "订单管理/微信退款", businessType = BusinessType.PUT, isSaveRequestData = true) public Result wxRefund(@RequestBody @Validated WxOrderRefundReq wxOrderRefundReq) throws Exception { return orderDonService.wxRefund(wxOrderRefundReq); } /** * 微信退款回调 */ @PostMapping("/wx/refund/notify") public void wxRefundNotify(HttpServletRequest request, HttpServletResponse response) throws Exception { String xml = IoKit.toString(request.getInputStream()); log.info("=== 退款成功的回调: \n {}", xml); // 解析xml Map map = Xmls.toMap(xml); // 退款失败 if (!StrUtil.equals("SUCCESS", map.get("return_code"))) { throw BusinessRuntimeException.getInstance("退款失败."); } orderDonService.wxRefundNotify(map); String toWechatXmlResponse = ""; OutputStream out = null; try { out = response.getOutputStream(); IoKit.write(toWechatXmlResponse, out); } catch (Throwable e) { throw BusinessRuntimeException.getInstance(e == null ? null : e.getMessage()); } finally { IoKit.close(out); } } /** * 微信支付回调 * @author chan * @date 2021-10-11 下午5:42 */ @PostMapping("/prepay/notify") public void prepayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception { String xml = IoKit.toString(request.getInputStream()); log.info("=== 基金会分发支付成功的回调: \n {}", xml); // 解析xml Map map = Xmls.toMap(xml); // 支付失败 if (!StringUtils.equals("SUCCESS", map.get("return_code")) || !StringUtils.equals("SUCCESS", map.get("result_code"))) { throw BusinessRuntimeException.getInstance("支付失败."); } orderDonService.prepayNotify(map); String toWeChatXmlResponse = ""; OutputStream out = null; try { out = response.getOutputStream(); IoKit.write(toWeChatXmlResponse, out); } catch (Exception e) { throw BusinessRuntimeException.getInstance(e,e.getMessage()); } finally { IoKit.close(out); } } /** * pc端微信支付回调 * @author chan * @date 2021-10-11 下午5:42 */ @PostMapping("/pc/prepay/notify") public void pcPrepayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception { String xml = IoKit.toString(request.getInputStream()); log.info("=== 微信pc端分发支付成功的回调: \n {}", xml); // 解析xml Map map = Xmls.toMap(xml); // 支付失败 if (!StringUtils.equals("SUCCESS", map.get("return_code")) || !StringUtils.equals("SUCCESS", map.get("result_code"))) { throw BusinessRuntimeException.getInstance("支付失败."); } orderDonService.prepayNotify(map); log.info("pc端微信支付回调修改订单状态成功"); String toWeChatXmlResponse = ""; OutputStream out = null; try { out = response.getOutputStream(); IoKit.write(toWeChatXmlResponse, out); } catch (Exception e) { throw BusinessRuntimeException.getInstance(e,e.getMessage()); } finally { IoKit.close(out); } } /** * 支付宝表单支付 * 支付宝调起支付宝表单 */ @PostMapping("/post/pay/zfb") @Deprecated public Result aliPay(@RequestBody @Validated AlipayOrderDonReq re) throws Exception { Long orderId = re.getOrderId(); String returnUrl = re.getReturnUrl(); AliPayParams aliPayParams = orderDonService.aliPay(orderId, returnUrl, ZfbProductCode.MOBILE_WEB.getProductCode(), null); // response.setContentType("text/html;charset=" + BaseZfbConfig.charset); //直接将完整的表单html输出到页面 // response.getWriter().write(aliPayParams.getBody()); // response.getWriter().flush(); // response.getWriter().close(); return GatewayResponse.SUCCESS.newBuilder().toResult(aliPayParams.getBody()); } /** * 支付宝web支付 * pc网页内嵌二维码 */ @PostMapping("/get/zfb/orderQrCode") public Result zfbWebQrCode(@RequestBody @Validated AlipayOrderDonReq re) throws Exception { Long orderId = re.getOrderId(); String returnUrl = re.getReturnUrl(); AliPayParams aliPayParams = orderDonService.aliPay(orderId, returnUrl, ZfbProductCode.PC_WEB.getProductCode(), BaseZfbConfig.qrPayMode_orderCode); // response.setContentType("text/html;charset=" + BaseZfbConfig.charset); //直接将完整的表单html输出到页面 // response.getWriter().write(aliPayParams.getBody()); // response.getWriter().flush(); // response.getWriter().close(); return GatewayResponse.SUCCESS.newBuilder().toResult(aliPayParams.getBody()); } /** * 支付宝web支付 * pc网页跳转二维码 */ @PostMapping("/get/zfb/orderRedirect") public Result zfbWebRedirectQrCode(@RequestBody @Validated AlipayOrderDonReq re) throws Exception { Long orderId = re.getOrderId(); String returnUrl = re.getReturnUrl(); AliPayParams aliPayParams = orderDonService.aliPay(orderId, returnUrl, ZfbProductCode.PC_WEB.getProductCode(), BaseZfbConfig.qrPayMode_redirect); return GatewayResponse.SUCCESS.newBuilder().toResult(aliPayParams.getBody()); } /** * 支付宝退款 */ @PostMapping("/zfb/refund") @Log(module = "订单管理/支付宝退款", businessType = BusinessType.PUT, isSaveRequestData = true) public Result zfbOrderRefund(@RequestBody @Validated ZfbOrderRefundReq zfbOrderRefundReq) throws Exception { return orderDonService.zfbRefund(zfbOrderRefundReq); } /** * 支付宝回调 */ @PostMapping("/prepay/zfb/notify") public String aliPayNotify(HttpServletRequest request) throws Exception { ////将异步通知中收到的所有参数都存放到map中 Map params = convertRequestParamsToMap(request); String tradeStatus = params.get("trade_status"); String orderNo = params.get("out_trade_no"); if (AliPayTradeStatus.TRADE_SUCCESS.getStatus().equals(tradeStatus) || AliPayTradeStatus.TRADE_FINISHED.getStatus().equals(tradeStatus)) { log.info("支付宝商家订单号orderNo:{},status:{}开始回调", orderNo, tradeStatus); orderDonService.aliPayNotify(params); } else { log.error("支付宝回调 error 状态不符合 成功或完成 status:{} ,orderNo:{}", tradeStatus, orderNo); return "fail"; } return "success"; } /** * 支付宝转账 */ // @PostMapping("/zfb/transfer/accounts") // @NoSubmit // public Result zfbTransferAccounts(@RequestBody @Validated TransferAccountsReq transferAccountsReq) throws Exception { // long userId = StpUserUtil.getLoginIdAsLong(); // transferAccountsReq.setUserId(userId); // orderDonService.transferAccounts(transferAccountsReq); // return GatewayResponse.SUCCESS.newBuilder().toResult("转账成功"); // } /** * 查询支付宝转账状态 */ @GetMapping("/zfb/transfer/status") public Result getTransFerStatusByTid(String translationId) throws Exception { AlipayFundTransCommonQueryResponse response = orderDonService.getTransFerStatusByTid(translationId); if (response.isSuccess()) { if (!Constant.SUCCESS.equals(response.getStatus())) { return GatewayResponse.SUCCESS.newBuilder().toResult(response.getFailReason()); } return GatewayResponse.SUCCESS.newBuilder().toResult("该红包已转账成功"); } return GatewayResponse.SUCCESS.newBuilder().toResult(response.getSubMsg()); } /** * 获取订单列表 */ @GetMapping("/get") public Result> list(){ long userId = StpUserUtil.getLoginIdAsLong(); List userIds = userService.getRelationUserIdList(userId, null); SearchResult search = beanSearcher.search(OrderDonView.class, MapUtils.flatBuilder(request.getParameterMap()) .field(OrderDonView::getUserId, userIds).op(Operator.InList) .orderBy(OrderDonView::getId).desc() .build()); search.getDataList().forEach(data->{ Integer count = availableBenefitsMapper.selectCount(Wrappers.lambdaQuery(UserPayEquipmentAvailableBenefits.class) .eq(UserPayEquipmentAvailableBenefits::getRealOrderId, data.getId()) .eq(UserPayEquipmentAvailableBenefits::getDeleted, true)); data.setIsHasBenefits(count > 0 ? true : false); if (data.getIsBenefits() != null && data.getIsBenefits()) { String benefitsList = data.getBenefitsList(); if (StrUtil.isNotBlank(benefitsList)) { try { List skuIds = Jsons.parseList(benefitsList, GoodsDonSku.class).stream().map(GoodsDonSku::getId).collect(Collectors.toList()); data.setBenefitsViews(beanSearcher.searchAll(GoodsDonSkuView.class, MapUtils.builder().field(GoodsDonSkuView::getSkuId, skuIds).op(Operator.InList).build())); } catch (Exception e) { } } } data.setWaybill(waybillMapper.selectOne(Wrappers.lambdaQuery(OrderDonWaybill.class).eq(OrderDonWaybill::getOrderId, data.getId()).last("limit 1"))); }); return GatewayResponse.SUCCESS.newBuilder().toResult(search); } /** * 获取订单详情 */ @GetMapping("/get/{orderId}") public Result detail(@PathVariable Long orderId, Boolean isNoLogin) { Long userId = null; if (isNoLogin == null || !isNoLogin) { userId = StpUserUtil.getLoginIdAsLong(); } OrderDetailView detail = orderDonService.getDetail(orderId, userId); return GatewayResponse.SUCCESS.newBuilder().toResult(detail); } /** * 取消订单 */ @GetMapping("/get/close/{orderId}") public Result closeOrder(@PathVariable Long orderId){ orderDonService.closeOrder(orderId); return GatewayResponse.SUCCESS.newBuilder().toResult(); } @GetMapping("/get/order/status/{orderId}") public Result getOrderStatusById(@PathVariable Long orderId) { if (orderId < 1) { throw BusinessRuntimeException.getInstance("订单不存在"); } OrderDonView orderDonView = orderDonMapper.getOrderDetail(orderId); if (orderDonView == null) { throw BusinessRuntimeException.getInstance("订单不存在"); } return GatewayResponse.SUCCESS.newBuilder().toResult(orderDonView); } @PostMapping("/get/noLogin/order") public Result> getSearchResult(@RequestBody List orderIds) { List orderDonViews = beanSearcher.searchAll(OrderDonView.class, MapUtils.builder() .field(OrderDonView::getId, orderIds).op(Operator.InList) .orderBy(OrderDonView::getId).desc().build()); return GatewayResponse.SUCCESS.newBuilder().toResult(orderDonViews); } /** * 平台评论列表 */ @GetMapping("/get/orderComment") public Result> getOrderCommentView() { SearchResult search = beanSearcher.search(OrderCommentView.class, MapUtils.flatBuilder(request.getParameterMap()).build()); return GatewayResponse.SUCCESS.newBuilder().toResult(search); } /** * 电脑端手机号注册 购买车票是否绑定了微信用户 */ @GetMapping("/isBindWx") public Result isBindWx() { Long userId = StpUserUtil.getLoginIdAsLong(); User user = userMapper.selectById(userId); if (user == null) { throw BusinessRuntimeException.getGatewayApiCode(GatewayApiCode.CMS_TOKEN_VALID); } if (StrUtil.isEmpty(user.getLoginPhone())) { return GatewayResponse.SUCCESS.newBuilder().toResult(true); } UserBindDetail userBindDetail = userBindDetailMapper.selectOne(Wrappers.lambdaQuery(UserBindDetail.class) .eq(UserBindDetail::getPhone, user.getLoginPhone())); if (userBindDetail == null) { return GatewayResponse.SUCCESS.newBuilder().toResult(false); } return GatewayResponse.SUCCESS.newBuilder().toResult(true); } /** * 是否绑定了邮箱或手机号 */ @GetMapping("/isBind") public Result isBindPhoneOrEmail() { Long userId = StpUserUtil.getLoginIdAsLong(); User user = userMapper.selectById(userId); if (user == null) { throw BusinessRuntimeException.getGatewayApiCode(GatewayApiCode.CMS_TOKEN_VALID); } if (StrUtil.isEmpty(user.getOpenId())) { return GatewayResponse.SUCCESS.newBuilder().toResult(true); } UserBindDetail userBindDetail = userBindDetailMapper.selectOne(Wrappers.lambdaQuery(UserBindDetail.class) .eq(UserBindDetail::getUserId, userId)); if (userBindDetail == null) { return GatewayResponse.SUCCESS.newBuilder().toResult(false); } return GatewayResponse.SUCCESS.newBuilder().toResult(true); } /** * 获取支付宝回调参数 */ private static Map convertRequestParamsToMap(HttpServletRequest request) { Map retMap = new HashMap<>(); Set> entrySet = request.getParameterMap().entrySet(); for (Map.Entry entry : entrySet) { String name = entry.getKey(); String[] values = entry.getValue(); int valLen = values.length; if (valLen == 1) { retMap.put(name, values[0]); } else if (valLen > 1) { StringBuilder sb = new StringBuilder(); for (String val : values) { sb.append(",").append(val); } retMap.put(name, sb.substring(1)); } else { retMap.put(name, ""); } } return retMap; } }