package com.kk.wechat.service;
import com.kk.api.response.PayNotifyResponse;
import com.kk.api.service.InternalPayService;
import com.kk.platform.enums.PayException;
import com.kk.platform.enums.PayStatus;
import com.kk.platform.enums.TradeTypeCode;
import com.kk.platform.model.PayChannel;
import com.kk.platform.model.PayOrder;
import com.kk.platform.service.PayOrderService;
import com.kk.util.DateUtil;
import com.kk.util.SignUtils;
import com.kk.utils.WebPropertiesUtil;
import com.kk.wechat.client.WechatPayClient;
import com.kk.wechat.exception.WechatPayException;
import com.kk.wechat.model.WechatPayPrePayModel;
import com.kk.wechat.model.WechatPayQueryModel;
import com.kk.wechat.model.WechatPayTradeStatus;
import com.kk.wechat.request.WechatPayPrePayRequest;
import com.kk.wechat.request.WechatPayQueryRequest;
import com.kk.wechat.response.ResultCode;
import com.kk.wechat.response.WechatPayPayNotifyResponse;
import com.kk.wechat.response.WechatPayPrePayResponse;
import com.kk.wechat.response.WechatPayQueryResponse;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@Service
public class WechatPayService implements InternalPayService {
private Log logger = LogFactory.getLog(this.getClass());
// 通知url必须为直接可访问的url,不能携带参数
private String notifyUrl = WebPropertiesUtil.getInstance().getValue("wechat.pay.notify.url");
@Autowired
private PayOrderService payOrderService;
/**
* 扫码支付,网页支付,app支付 统一下单接口
* <p/>
* 微信扫码支付,使用模式二。
*
* @return
*/
@Override
public Object pay(PayChannel payChannel, PayOrder order) {
// 订单刚创建,需要 到微信支付 统一下单,获取支付凭据
if (order.getStatus() == PayStatus.CREATE_PAYMENT.getValue()) {
WechatPayClient client = new WechatPayClient(payChannel.getAppId(), payChannel.getMchId(), payChannel.getApiKey());
WechatPayPrePayRequest request = new WechatPayPrePayRequest();
// model中 appId,sign,mchId,nonceStr 在WechatClient中设置
WechatPayPrePayModel model = new WechatPayPrePayModel();
model.setOutTradeNo(order.getPayOrderNo());
model.setSpbillCreateIp(order.getUserIp());
model.setBody(order.getSubject());
model.setDetail(order.getDetail());
model.setTimeStart(order.getStartTime());
model.setTimeExpire(order.getExpireTime());
model.setTotalFee(order.getPayAmount());
model.setNotifyUrl(notifyUrl);
model.setTradeType(order.getTradeType().toString());
if (TradeTypeCode.WAP == order.getTradeTypeCodeEnum()) {
model.setTradeType(TradeTypeCode.JSAPI.toString());
}
model.setOpenId(order.getOpenId());
request.setModel(model);
// 统一下单
WechatPayPrePayResponse response;
try {
response = client.execute(request);
} catch (WechatPayException e) {
// 支付失败
logger.error(e.getMessage(), e);
order.setStatus(PayStatus.CREATE_PAYMENT_FAIL.getValue());
order.setErrorMsg(e.getErrMsg());
order.setErrorCode(e.getErrCode());
payOrderService.updateStatus(order.getId(), PayStatus.CREATE_PAYMENT_FAIL.getValue(), e.getErrCode(), e.getErrMsg());
throw new PayException(e.getErrMsg());
}
if (response.isSuccess()) {
order.setStatus(PayStatus.CREATE_PAYMENT_SUCCESS.getValue());
order.setCodeUrl(response.getCodeUrl());
order.setPrePayId(response.getPrepayId());
payOrderService.updatePayRequest(order.getId(), response.getPrepayId(), response.getCodeUrl());
} else {
order.setStatus(PayStatus.CREATE_PAYMENT_FAIL.getValue());
order.setErrorCode(response.getErrCode());
order.setErrorMsg(response.getErrCodeDes());
payOrderService.updateStatus(order.getId(), PayStatus.CREATE_PAYMENT_FAIL.getValue(), response.getErrCode(), response.getErrCodeDes());
throw new PayException(response.getErrCodeDes());
}
}
// 如果已经下过单,则直接返回
if (order.getStatus() != PayStatus.CREATE_PAYMENT_SUCCESS.getValue()) {
throw new PayException("订单状态异常");
}
switch (order.getTradeTypeCodeEnum()) {
case NATIVE: {
return order.getCodeUrl();
}
case WAP: {
return getWapPayMap(payChannel, order);
}
case APP: {
return getAppPayMap(payChannel, order);
}
}
throw new PayException("交易类型不存在");
}
// https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_5
// 需要在 微信开放平台创建app,设置秘钥和package。
private Map<String, String> getAppPayMap(PayChannel payChannel, PayOrder order) {
Map<String, String> data = new HashMap<String, String>();
data.put("appid", payChannel.getAppId());
data.put("partnerid", payChannel.getMchId());
data.put("prepayid", order.getPrePayId());
data.put("package", "Sign=WXPay");
data.put("noncestr", RandomStringUtils.random(32, true, true));
data.put("timestamp", (System.currentTimeMillis() / 1000 + ""));
data.put("sign", SignUtils.md5(data, payChannel.getApiKey()));
return data;
}
// https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6
private Map<String, String> getWapPayMap(PayChannel payChannel, PayOrder order) {
Map<String, String> data = new HashMap<String, String>();
data.put("appId", payChannel.getAppId());
data.put("timeStamp", System.currentTimeMillis() + "");
data.put("nonceStr", RandomStringUtils.random(32, true, true));
data.put("signType", "MD5");
data.put("package", "prepay_id=" + order.getPrePayId());
data.put("paySign", SignUtils.md5(data, payChannel.getApiKey())); // 计算sign
return data;
}
@Override
public String getOutTradeNo(String notify) {
try {
Document doc = DocumentHelper.parseText(notify);
Element root = doc.getRootElement();
Element element = root.element("out_trade_no");
if (element == null) {
return null;
}
return element.getText();
} catch (DocumentException e) {
logger.error(e.getMessage(), e);
return null;
}
}
@Override
public PayNotifyResponse parse(PayChannel channel, PayOrder order, String notify) {
WechatPayClient client = new WechatPayClient(channel.getApiKey());
WechatPayPayNotifyResponse response = null;
try {
// 解析的时候 会校验签名
response = client.parse(WechatPayPayNotifyResponse.class, notify);
} catch (WechatPayException e) {
logger.error(e.getMessage(), e);
return new PayNotifyResponse(ResultCode.FAIL.getValue(), ResultCode.FAIL.getValue());
}
PayNotifyResponse notifyResponse = new PayNotifyResponse();
notifyResponse.setTradePayNo(order.getTradePayNo()); // 业务方支付订单号
notifyResponse.setPayAmount(order.getPayAmount());
notifyResponse.setExtra(order.getExtra());
notifyResponse.setMerchantId(order.getMerchantId());
notifyResponse.setPayOrderNo(order.getPayOrderNo());
if (response.isSuccess()) {
setOrderPaySuccess(order, response.getOpenId(), response.getTimeEnd(), response.getTransactionId());
notifyResponse.setCode(ResultCode.SUCCESS.getValue());
notifyResponse.setMsg(ResultCode.SUCCESS.getValue());
notifyResponse.setStatus(ResultCode.SUCCESS.getValue());
notifyResponse.setPayTime(DateUtil.defaultTime(order.getPayTime()));
} else {
order.setStatus(PayStatus.PAY_FAIL.getValue());
order.setErrorCode(response.getErrCode());
order.setErrorMsg(response.getErrCodeDes());
payOrderService.updateStatus(order.getId(), PayStatus.PAY_FAIL.getValue(), response.getErrCode(), response.getErrCodeDes());
notifyResponse.setCode(ResultCode.FAIL.getValue());
notifyResponse.setMsg(response.getErrCodeDes());
notifyResponse.setStatus(ResultCode.FAIL.getValue());
}
return notifyResponse;
}
// 订单支付成功, 设置payOrder状态
private void setOrderPaySuccess(PayOrder order, String openId, Date payTime, String transactionId) {
order.setStatus(PayStatus.PAY_SUCCESS.getValue());
order.setOpenId(openId);
order.setPayTime(payTime);
order.setPayId(transactionId);
payOrderService.updatePayOrder(order);
}
@Override
public boolean synchronize(PayChannel payChannel, PayOrder order) {
WechatPayClient client = new WechatPayClient(payChannel.getAppId(), payChannel.getMchId(), payChannel.getApiKey());
WechatPayQueryRequest request = new WechatPayQueryRequest();
WechatPayQueryModel model = new WechatPayQueryModel();
model.setOutTradeNo(order.getPayOrderNo());
model.setTransactionId(order.getPayId());
request.setModel(model);
// 统一下单
WechatPayQueryResponse response = null;
try {
response = client.execute(request);
} catch (WechatPayException e) {
// 支付失败
logger.error(e.getMessage(), e);
throw new RuntimeException(e.getMessage());
}
//如果订单 还在 待支付状态
if (PayStatus.CREATE_PAYMENT.getValue() == order.getStatus()
|| PayStatus.CREATE_PAYMENT_SUCCESS.getValue() == order.getStatus()
|| PayStatus.PAY_CHECKING.getValue() == order.getStatus()) {
switch (response.getTradeState()) {
case SUCCESS: {
setOrderPaySuccess(order, response.getOpenId(), response.getTimeEnd(), response.getTransactionId());
return true;
}
case REVOKED: // 已撤销(刷卡支付)
case CLOSED:
case PAYERROR: {
payOrderService.updateStatus(order.getId(), PayStatus.PAY_CLOSE.getValue(), null, null);
return true;
}
case NOTPAY: {
Date now = new Date();
if (now.after(order.getExpireTime())) {
payOrderService.updateStatus(order.getId(), PayStatus.PAY_CLOSE.getValue(), null, null);
return true;
} else {
return false;
}
}
// USERPAYING 支付中,不处理
}
} else if (PayStatus.PAY_SUCCESS.getValue() == order.getStatus()) {
// 订单已支付成功,判断是否有退款信息
if (WechatPayTradeStatus.REFUND == response.getTradeState()) {
payOrderService.updateStatus(order.getId(), PayStatus.REFUND_SUCCESS.getValue(), null, null);
return true;
}
}
return false;
}
}