package cn.lili.modules.payment.kit.plugin.alipay; import cn.hutool.core.net.URLDecoder; import cn.hutool.core.net.URLEncoder; import cn.hutool.json.JSONUtil; import cn.lili.common.context.ThreadContextHolder; import cn.lili.common.enums.ResultCode; import cn.lili.common.enums.ResultUtil; import cn.lili.common.exception.ServiceException; import cn.lili.common.properties.ApiProperties; import cn.lili.common.properties.DomainProperties; import cn.lili.common.utils.BeanUtil; import cn.lili.common.utils.SnowFlake; import cn.lili.common.utils.StringUtils; import cn.lili.common.vo.ResultMessage; import cn.lili.modules.payment.entity.RefundLog; import cn.lili.modules.payment.entity.enums.PaymentMethodEnum; import cn.lili.modules.payment.kit.CashierSupport; import cn.lili.modules.payment.kit.Payment; import cn.lili.modules.payment.kit.dto.PayParam; import cn.lili.modules.payment.kit.dto.PaymentSuccessParams; import cn.lili.modules.payment.kit.params.dto.CashierParam; import cn.lili.modules.payment.service.PaymentService; import cn.lili.modules.payment.service.RefundLogService; import cn.lili.modules.system.entity.dos.Setting; import cn.lili.modules.system.entity.dto.payment.AlipayPaymentSetting; import cn.lili.modules.system.entity.enums.SettingEnum; import cn.lili.modules.system.service.SettingService; import cn.lili.modules.wallet.entity.dos.MemberWithdrawApply; import cn.lili.modules.wallet.entity.dto.TransferResultDTO; import com.alibaba.fastjson.JSONObject; import com.alipay.api.AlipayApiException; import com.alipay.api.domain.*; import com.alipay.api.internal.util.AlipaySignature; import com.alipay.api.response.AlipayFundTransUniTransferResponse; import com.alipay.api.response.AlipayTradeRefundResponse; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.nio.charset.StandardCharsets; import java.util.Map; /** * 支付宝支付 * * @author Chopper * @since 2020/12/17 09:55 */ @Slf4j @Component public class AliPayPlugin implements Payment { /** * 支付日志 */ @Autowired private PaymentService paymentService; /** * 退款日志 */ @Autowired private RefundLogService refundLogService; /** * 收银台 */ @Autowired private CashierSupport cashierSupport; /** * 设置 */ @Autowired private SettingService settingService; /** * 域名配置 */ @Autowired private DomainProperties domainProperties; @Override public ResultMessage h5pay(HttpServletRequest request, HttpServletResponse response, PayParam payParam) { CashierParam cashierParam = cashierSupport.cashierParam(payParam); AlipayPaymentSetting alipayPaymentSetting = alipayPaymentSetting(); //请求订单编号 String outTradeNo = SnowFlake.getIdStr(); //准备支付参数 AlipayTradeWapPayModel payModel = new AlipayTradeWapPayModel(); payModel.setBody(cashierParam.getTitle()); payModel.setSubject(cashierParam.getDetail()); payModel.setTotalAmount(cashierParam.getPrice() + ""); //回传数据 payModel.setPassbackParams(URLEncoder.createAll().encode(BeanUtil.formatKeyValuePair(payParam), StandardCharsets.UTF_8)); //3分钟超时 payModel.setTimeoutExpress("3m"); payModel.setOutTradeNo(outTradeNo); payModel.setProductCode("QUICK_WAP_PAY"); try { log.info("支付宝H5支付:{}", JSONUtil.toJsonStr(payModel)); AliPayRequest.wapPay(response, payModel, callbackUrl(alipayPaymentSetting.getCallbackUrl(), PaymentMethodEnum.ALIPAY), notifyUrl(alipayPaymentSetting.getCallbackUrl(), PaymentMethodEnum.ALIPAY)); } catch (Exception e) { log.error("H5支付异常", e); throw new ServiceException(ResultCode.ALIPAY_EXCEPTION); } return null; } @Override public ResultMessage jsApiPay(HttpServletRequest request, PayParam payParam) { throw new ServiceException(ResultCode.PAY_NOT_SUPPORT); } @Override public ResultMessage appPay(HttpServletRequest request, PayParam payParam) { try { CashierParam cashierParam = cashierSupport.cashierParam(payParam); AlipayPaymentSetting alipayPaymentSetting = alipayPaymentSetting(); //请求订单编号 String outTradeNo = SnowFlake.getIdStr(); AlipayTradeAppPayModel payModel = new AlipayTradeAppPayModel(); payModel.setBody(cashierParam.getTitle()); payModel.setSubject(cashierParam.getDetail()); payModel.setTotalAmount(cashierParam.getPrice() + ""); //3分钟超时 payModel.setTimeoutExpress("3m"); //回传数据 payModel.setPassbackParams(URLEncoder.createAll().encode(BeanUtil.formatKeyValuePair(payParam), StandardCharsets.UTF_8)); payModel.setOutTradeNo(outTradeNo); payModel.setProductCode("QUICK_MSECURITY_PAY"); log.info("支付宝APP支付:{}", payModel); String orderInfo = AliPayRequest.appPayToResponse(payModel, notifyUrl(alipayPaymentSetting.getCallbackUrl(), PaymentMethodEnum.ALIPAY)).getBody(); log.info("支付宝APP支付返回内容:{}", orderInfo); return ResultUtil.data(orderInfo); } catch (AlipayApiException e) { log.error("支付宝支付异常:", e); throw new ServiceException(ResultCode.ALIPAY_EXCEPTION); } catch (Exception e) { log.error("支付业务异常:", e); throw new ServiceException(ResultCode.PAY_ERROR); } } @Override public ResultMessage nativePay(HttpServletRequest request, PayParam payParam) { try { CashierParam cashierParam = cashierSupport.cashierParam(payParam); AlipayPaymentSetting alipayPaymentSetting = alipayPaymentSetting(); AlipayTradePrecreateModel payModel = new AlipayTradePrecreateModel(); //请求订单编号 String outTradeNo = SnowFlake.getIdStr(); payModel.setBody(cashierParam.getTitle()); payModel.setSubject(cashierParam.getDetail()); payModel.setTotalAmount(cashierParam.getPrice() + ""); //回传数据 payModel.setPassbackParams(URLEncoder.createAll().encode(BeanUtil.formatKeyValuePair(payParam), StandardCharsets.UTF_8)); payModel.setTimeoutExpress("3m"); payModel.setOutTradeNo(outTradeNo); log.info("支付宝扫码:{}", payModel); String resultStr = AliPayRequest.tradePrecreatePayToResponse(payModel, notifyUrl(alipayPaymentSetting.getCallbackUrl(), PaymentMethodEnum.ALIPAY)).getBody(); log.info("支付宝扫码交互返回:{}", resultStr); JSONObject jsonObject = JSONObject.parseObject(resultStr); return ResultUtil.data(jsonObject.getJSONObject("alipay_trade_precreate_response").getString("qr_code")); } catch (Exception e) { log.error("支付业务异常:", e); throw new ServiceException(ResultCode.PAY_ERROR); } } @Override public void refund(RefundLog refundLog) { AlipayTradeRefundModel model = new AlipayTradeRefundModel(); //这里取支付回调时返回的流水 if (StringUtils.isNotEmpty(refundLog.getPaymentReceivableNo())) { model.setTradeNo(refundLog.getPaymentReceivableNo()); } else { throw new ServiceException(ResultCode.ALIPAY_PARAMS_EXCEPTION); } model.setRefundAmount(refundLog.getTotalAmount() + ""); model.setRefundReason(refundLog.getRefundReason()); model.setOutRequestNo(refundLog.getOutOrderNo()); //交互退款 try { AlipayTradeRefundResponse alipayTradeRefundResponse = AliPayApi.tradeRefundToResponse(model); log.error("支付宝退款,参数:{},支付宝响应:{}", JSONUtil.toJsonStr(model), JSONUtil.toJsonStr(alipayTradeRefundResponse)); if (alipayTradeRefundResponse.isSuccess()) { refundLog.setIsRefund(true); refundLog.setReceivableNo(refundLog.getOutOrderNo()); } else { refundLog.setErrorMessage(String.format("错误码:%s,错误原因:%s", alipayTradeRefundResponse.getSubCode(), alipayTradeRefundResponse.getSubMsg())); } refundLogService.save(refundLog); } catch (Exception e) { log.error("支付退款异常:", e); throw new ServiceException(ResultCode.PAY_ERROR); } } @Override public void refundNotify(HttpServletRequest request) { //不需要实现 } @Override public void callBack(HttpServletRequest request) { log.info("支付同步回调:"); checkPaymentResult(request); } @Override public void notify(HttpServletRequest request) { verifyNotify(request); log.info("支付异步通知:"); } /** * 支付宝提现 * 文档地址:https://opendocs.alipay.com/open/02byuo?scene=ca56bca529e64125a2786703c6192d41&ref=api * * @param memberWithdrawApply 会员提现申请 */ @Override public TransferResultDTO transfer(MemberWithdrawApply memberWithdrawApply) { AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel(); model.setOutBizNo(SnowFlake.createStr("T")); model.setRemark("用户提现"); model.setBusinessParams("{\"payer_show_name_use_alias\":\"true\"}"); model.setBizScene("DIRECT_TRANSFER"); Participant payeeInfo = new Participant(); payeeInfo.setIdentity(memberWithdrawApply.getConnectNumber()); payeeInfo.setIdentityType("ALIPAY_LOGON_ID"); payeeInfo.setName(memberWithdrawApply.getRealName()); model.setPayeeInfo(payeeInfo); model.setTransAmount(memberWithdrawApply.getApplyMoney().toString()); model.setProductCode("TRANS_ACCOUNT_NO_PWD"); model.setOrderTitle("用户提现"); //交互退款 try { AlipayFundTransUniTransferResponse alipayFundTransUniTransferResponse = AliPayApi.uniTransferToResponse(model, null); log.error("支付宝退款,参数:{},支付宝响应:{}", JSONUtil.toJsonStr(model), JSONUtil.toJsonStr(alipayFundTransUniTransferResponse)); if (alipayFundTransUniTransferResponse.isSuccess()) { return TransferResultDTO.builder().result(true).build(); } else { log.error(alipayFundTransUniTransferResponse.getSubMsg()); return TransferResultDTO.builder().result(false).response(alipayFundTransUniTransferResponse.getSubMsg()).build(); } } catch (Exception e) { log.error("用户提现异常:", e); return TransferResultDTO.builder().result(false).response(e.getMessage()).build(); } } /** * 验证支付结果 * * @param request 请求 */ private void checkPaymentResult(HttpServletRequest request) { try { AlipayPaymentSetting alipayPaymentSetting = alipayPaymentSetting(); //获取支付宝反馈信息 Map map = AliPayApi.toMap(request); log.info("同步回调:{}", JSONUtil.toJsonStr(map)); boolean verifyResult = AlipaySignature.rsaCertCheckV1(map, alipayPaymentSetting.getAlipayPublicCertPath(), "UTF-8", "RSA2"); if (verifyResult) { log.info("支付回调通知:支付成功-参数:{}", map); } else { log.info("支付回调通知:支付失败-参数:{}", map); } ThreadContextHolder.getHttpResponse().sendRedirect(domainProperties.getWap() + "/pages/order/myOrder?status=0"); } catch (Exception e) { log.error("支付回调同步通知异常", e); } } /** * 验证支付结果 * * @param request */ private void verifyNotify(HttpServletRequest request) { try { AlipayPaymentSetting alipayPaymentSetting = alipayPaymentSetting(); //获取支付宝反馈信息 Map map = AliPayApi.toMap(request); log.info("支付回调响应:{}", JSONUtil.toJsonStr(map)); boolean verifyResult = AlipaySignature.rsaCertCheckV1(map, alipayPaymentSetting.getAlipayPublicCertPath(), "UTF-8", "RSA2"); //支付完成判定 if (!"TRADE_FINISHED".equals(map.get("trade_status")) && !"TRADE_SUCCESS".equals(map.get("trade_status"))) { return; } String payParamStr = map.get("passback_params"); String payParamJson = URLDecoder.decode(payParamStr, StandardCharsets.UTF_8); PayParam payParam = BeanUtil.formatKeyValuePair(payParamJson, new PayParam()); if (verifyResult) { String tradeNo = map.get("trade_no"); Double totalAmount = Double.parseDouble(map.get("total_amount")); PaymentSuccessParams paymentSuccessParams = new PaymentSuccessParams(PaymentMethodEnum.ALIPAY.name(), tradeNo, totalAmount, payParam); paymentService.success(paymentSuccessParams); log.info("支付回调通知:支付成功-参数:{},回调参数:{}", map, payParam); } else { log.info("支付回调通知:支付失败-参数:{}", map); } } catch (AlipayApiException e) { log.error("支付回调通知异常", e); } } /** * 获取支付宝配置 * * @return */ private AlipayPaymentSetting alipayPaymentSetting() { Setting setting = settingService.get(SettingEnum.ALIPAY_PAYMENT.name()); if (setting != null) { return JSONUtil.toBean(setting.getSettingValue(), AlipayPaymentSetting.class); } throw new ServiceException(ResultCode.ALIPAY_NOT_SETTING); } }