package com.ishop.mobile.api;
|
|
import com.iplatform.base.ArgumentsConstants;
|
import com.iplatform.base.PlatformRuntimeException;
|
import com.iplatform.base.VariableConstants;
|
import com.iplatform.base.WechatConstants;
|
import com.iplatform.base.util.PlatformRSAUtils;
|
import com.ishop.merchant.Constants;
|
import com.ishop.merchant.OrderConstants;
|
import com.ishop.merchant.PayConstants;
|
import com.ishop.merchant.util.PayUtils;
|
import com.ishop.mobile.BaseApi;
|
import com.ishop.mobile.util.WechatUtils;
|
import com.ishop.model.po.EbOrder;
|
import com.ishop.model.po.EbUser;
|
import com.ishop.model.po.EbUserConfig;
|
import com.ishop.model.request.OrderPayRequest;
|
import com.ishop.model.response.OrderPayResultResponse;
|
import com.ishop.model.response.PayConfigResponse;
|
import com.ishop.model.vo.WechatOrderVo;
|
import com.ishop.model.vo.WxPayJsResultVo;
|
import com.ishop.model.wechat.AttachVo;
|
import com.ishop.model.wechat.CreateOrderH5SceneInfoDetailVo;
|
import com.ishop.model.wechat.CreateOrderH5SceneInfoVo;
|
import com.walker.infrastructure.utils.DateUtils;
|
import com.walker.infrastructure.utils.JsonUtils;
|
import com.walker.infrastructure.utils.MD5;
|
import com.walker.infrastructure.utils.StringUtils;
|
import com.walker.pay.Order;
|
import com.walker.pay.PayEngineManager;
|
import com.walker.pay.PayStatus;
|
import com.walker.pay.exception.OrderException;
|
import com.walker.pay.response.OrderStatusResponsePay;
|
import com.walker.pay.wechat.v2.H5ResponsePay;
|
import com.walker.web.ResponseValue;
|
import com.walker.web.WebUserAgent;
|
import com.walker.web.util.UUID;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMethod;
|
import org.springframework.web.bind.annotation.RestController;
|
|
import java.util.HashMap;
|
import java.util.Map;
|
|
@RestController
|
@RequestMapping("/front/pay")
|
public class PayApi extends BaseApi {
|
|
// 使用支付引擎完成微信等第三方支付工作。2023-08-10
|
private PayEngineManager payEngineManager;
|
|
@Autowired
|
public PayApi(PayEngineManager payEngineManager){
|
this.payEngineManager = payEngineManager;
|
}
|
|
/**
|
* 查询微信订单结果
|
* @param orderNo
|
* @return
|
* @date 2023-08-30
|
*/
|
@RequestMapping(value = "/query/wechat/pay/result/{orderNo}", method = RequestMethod.GET)
|
public ResponseValue searchWechatPayOrder(@PathVariable(value = "orderNo") String orderNo){
|
if(StringUtils.isEmpty(orderNo)){
|
return ResponseValue.error("orderNo必须输入");
|
}
|
EbOrder order = this.getOrderService().queryOrder(orderNo);
|
if(order == null){
|
return ResponseValue.error("订单不存在,orderId={}" + orderNo);
|
}
|
if (order.getCancelStatus() > OrderConstants.ORDER_CANCEL_STATUS_NORMAL) {
|
return ResponseValue.error("订单已取消");
|
}
|
OrderStatusResponsePay responsePay = this.payEngineManager.searchOrderStatus(String.valueOf(order.getId()));
|
if(responsePay == null){
|
logger.error("未查询到微信订单状态,orderNo = " + orderNo);
|
return ResponseValue.success(false);
|
}
|
if(!responsePay.getStatus()){
|
logger.error("查询微信订单状态失败:" + responsePay.getMessage());
|
return ResponseValue.success(false);
|
}
|
if(responsePay.getPayStatus() != PayStatus.Success){
|
logger.error("查询微信订单状态【未成功】:" + responsePay.getMessage());
|
return ResponseValue.success(false);
|
}
|
return ResponseValue.success(true);
|
}
|
|
/**
|
* 订单支付,发起预订单。
|
* @return
|
* @date 2023-07-12
|
*/
|
@RequestMapping(value = "/payment", method = RequestMethod.POST)
|
public ResponseValue payment(@RequestBody OrderPayRequest request){
|
if(request == null || StringUtils.isEmpty(request.getOrderNo())){
|
return ResponseValue.error("预订单信息不存在");
|
}
|
logger.debug("支付方式 = " + request.getPayType());
|
String orderNo = request.getOrderNo();
|
EbOrder order = this.getOrderService().queryOrder(orderNo);
|
if(order == null){
|
return ResponseValue.error("订单不存在");
|
}
|
if (order.getCancelStatus().intValue() > OrderConstants.ORDER_CANCEL_STATUS_NORMAL) {
|
return ResponseValue.error("订单已取消");
|
}
|
if (order.getPaid().intValue() == 1) {
|
return ResponseValue.error("订单已支付");
|
}
|
if (order.getStatus().intValue() > OrderConstants.ORDER_STATUS_WAIT_PAY) {
|
return ResponseValue.error("订单状态异常");
|
}
|
|
// 2023-09-09,检查商品是否虚拟商品,如果无需发货,直接修改订单状态为:已完成。
|
// boolean isAutoShippingDone = true;
|
// List<Long> productIds = this.getOrderService().queryOrderProductIds(orderNo);
|
// if(StringUtils.isEmptyList(productIds)){
|
// throw new IllegalStateException("未查询到订单明细商品,orderNo=" + orderNo);
|
// }
|
// int templateId = 0;
|
// for(long productId : productIds){
|
// templateId = this.getProductCache().get(productId).getTempId();
|
// if(templateId != Constants.SHIPPING_TEMPLATE_ID_NO_SEND){
|
// isAutoShippingDone = false;
|
// break;
|
// }
|
// }
|
|
// 余额支付
|
long userId = this.getCurrentUserId();
|
EbUser user = this.getUserRegCache().get(userId);
|
if (request.getPayType().equals(PayConstants.PAY_TYPE_YUE)) {
|
if(user.getNowMoney().doubleValue() < order.getPayPrice().doubleValue()){
|
return ResponseValue.error("账户余额不足");
|
}
|
if(!this.checkPayPass(request.getPayPass(), userId)){
|
return ResponseValue.error("支付密码错误");
|
}
|
}
|
|
OrderPayResultResponse response = new OrderPayResultResponse();
|
response.setOrderNo(order.getOrderNo());
|
response.setPayType(request.getPayType());
|
response.setPayChannel(request.getPayChannel());
|
|
// 根据支付类型进行校验,更换支付类型
|
EbOrder updateOrder = new EbOrder(order.getId());
|
updateOrder.setPayType(request.getPayType());
|
updateOrder.setPayChannel(request.getPayChannel());
|
updateOrder.setOrderNo(order.getOrderNo());
|
updateOrder.setUpdateTime(DateUtils.getDateTimeNumber());
|
logger.debug("当前支付渠道,payChannel = {}", request.getPayChannel());
|
|
// 余额支付
|
if (request.getPayType().equals(PayConstants.PAY_TYPE_YUE)) {
|
// 2023-09-09
|
if(PayUtils.isAutoShippingDone(orderNo)){
|
// 当余额支付是,虚拟商品自动完成订单,无需发货
|
updateOrder.setStatus(OrderConstants.ORDER_STATUS_COMPLETE);
|
logger.debug("虚拟商品,自动发货完成");
|
} else {
|
order.setStatus(OrderConstants.ORDER_STATUS_WAIT_SHIPPING);
|
}
|
this.getPayService().execPayYue(updateOrder, order.getPayPrice().doubleValue(), userId, VariableConstants.TOKEN_SECRET, user);
|
this.getUserRegCache().update(user); // 更新用户缓存
|
response.setStatus(true);
|
logger.debug("余额支付订单成功");
|
|
} else if (request.getPayType().equals(PayConstants.PAY_TYPE_WE_CHAT)) {
|
// 微信支付,调用微信预下单,返回拉起微信支付需要的信息
|
// String userOpenId = this.getCurrentUser().getWx_open_id();
|
// logger.debug("userOpenId={}", userOpenId);
|
//
|
// //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// // 2023-08-28 不知道为啥openId字符串会带双引号,
|
// // 目前没找到原因,先直接剔除,后面要找到(初步估计是redis取出来带的)
|
// //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// if(StringUtils.isNotEmpty(userOpenId) && userOpenId.indexOf("\"") >= 0){
|
// userOpenId = userOpenId.replaceAll("\"", StringUtils.EMPTY_STRING);
|
// }
|
// //~~~~~~~~~~~~~~~~~~~~~~~ end ~~~~~~~~~~~~~~~~~~~~~~
|
|
WxPayJsResultVo vo = null;
|
if(request.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_PUBLIC)
|
|| request.getPayChannel().equals(PayConstants.PAY_CHANNEL_H5)){
|
// 微信公众号、H5支付
|
String userOpenId = PayUtils.filterUserOpenId(this.getCurrentUser().getWx_open_id());
|
logger.debug("userOpenId={}", userOpenId);
|
if(StringUtils.isEmpty(userOpenId)){
|
return ResponseValue.error("您还未授权(绑定)微信登录,无法完成微信支付");
|
}
|
vo = this.wechatH5Order(order, userOpenId);
|
|
} else if (request.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_MINI)) {
|
// 微信小程序支付
|
String userMiniOpenId = PayUtils.filterUserOpenId(this.getCurrentUser().getWx_union_id());
|
logger.debug("userMiniOpenId={}", userMiniOpenId);
|
if(StringUtils.isEmpty(userMiniOpenId)){
|
return ResponseValue.error("您还未授权(绑定小程序)微信登录,无法完成微信支付");
|
}
|
vo = this.wechatMiniOrder(order, userMiniOpenId);
|
|
} else {
|
throw new UnsupportedOperationException("还未实现微信其他支付方式:" + request.getPayChannel());
|
}
|
response.setStatus(true);
|
response.setJsConfig(vo);
|
logger.debug("微信预下单成功");
|
|
} else if(request.getPayType().equals(PayConstants.PAY_TYPE_ALI_PAY)){
|
throw new UnsupportedOperationException("暂未实现支付宝支付");
|
|
} else {
|
throw new UnsupportedOperationException("不支持的支付方式:" + request.getPayType());
|
}
|
return ResponseValue.success(response);
|
}
|
|
private boolean checkPayPass(String payPass, long userId){
|
EbUserConfig config = this.getUserRegConfigCache().get(userId);
|
if(StringUtils.isEmpty(config.getPayPwd())){
|
throw new PlatformRuntimeException("用户尚未设置支付密码");
|
}
|
try{
|
String originPassword = PlatformRSAUtils.getAesDecryptValue(payPass);
|
if(this.matchesPassword(originPassword, config.getPayPwd())){
|
return true;
|
}
|
logger.error("支付密码输入错误,originPassword={}", originPassword);
|
return false;
|
|
} catch (Exception ex){
|
throw new PlatformRuntimeException("解析支付密码错误:" + ex.getMessage(), ex);
|
}
|
}
|
|
private WxPayJsResultVo wechatMiniOrder(EbOrder order, String userMiniOpenId){
|
String apiDomain = this.getArgumentVariable(Constants.CONFIG_KEY_API_URL).getStringValue();
|
String siteName = this.getArgumentVariable(Constants.CONFIG_KEY_SITE_NAME).getStringValue();
|
String signKey = this.getArgumentVariable(WechatConstants.WECHAT_PAY_MINI_KEY).getStringValue();
|
String attach = PayConstants.PAY_SERVICE_TYPE_ORDER + "," + order.getUid();
|
// final WebUserAgent webUserAgent = this.getCurrentWebUserAgent();
|
double payPriceFen = order.getPayPrice().doubleValue() * 100;
|
|
Order platformPayOrder = PayUtils.acquirePlatformOrderRoutineWechatV2((long)payPriceFen
|
, order.getId(), siteName, attach, "127.0.0.1", apiDomain + PayConstants.WX_PAY_NOTIFY_API_URI, userMiniOpenId);
|
return this.acquireWechatNormalPayResultVo(platformPayOrder, signKey);
|
}
|
|
private WxPayJsResultVo wechatH5Order(EbOrder order, String userOpenId){
|
String apiDomain = this.getArgumentVariable(Constants.CONFIG_KEY_API_URL).getStringValue();
|
String siteName = this.getArgumentVariable(Constants.CONFIG_KEY_SITE_NAME).getStringValue();
|
String signKey = this.getArgumentVariable(WechatConstants.WECHAT_PAY_PUBLIC_KEY).getStringValue();
|
String attach = PayConstants.PAY_SERVICE_TYPE_ORDER + "," + order.getUid();
|
// final WebUserAgent webUserAgent = this.getCurrentWebUserAgent();
|
double payPriceFen = order.getPayPrice().doubleValue() * 100;
|
|
// 2023-08-28 注意:这里使用 webUserAgent.getIp()总是导致签名报错,暂时ip不管。
|
Order platformPayOrder = PayUtils.acquirePlatformOrderH5WechatV2((long)payPriceFen
|
, order.getId(), siteName, attach, "127.0.0.1", apiDomain + PayConstants.WX_PAY_NOTIFY_API_URI, userOpenId);
|
// logger.debug(platformPayOrder.toString());
|
|
// H5ResponsePay responsePay = null;
|
// try {
|
// responsePay = (H5ResponsePay) this.payEngineManager.generatePrepareOrder(platformPayOrder);
|
// } catch (OrderException e) {
|
// throw new PlatformRuntimeException("发起微信预订单错误:" + e.getMessage() + ", orderId=" + e.getOrderId(), e);
|
// }
|
// if(!responsePay.getStatus()){
|
// throw new PlatformRuntimeException("微信支付H5订单返回错误:" + responsePay.getMessage(), null);
|
// }
|
//
|
// Map<String, String> map = new HashMap<>();
|
// map.put("appId", responsePay.getAppId());
|
// map.put("nonceStr", responsePay.getAppId());
|
// map.put("package", "prepay_id=" + responsePay.getPrepayId());
|
// map.put("signType", MD5.MD5_NAME);
|
// map.put("timeStamp", String.valueOf(System.currentTimeMillis()/1000));
|
//
|
// WxPayJsResultVo vo = new WxPayJsResultVo();
|
// vo.setAppId(responsePay.getAppId());
|
// vo.setNonceStr(responsePay.getAppId());
|
// vo.setPackages("prepay_id=" + responsePay.getPrepayId());
|
// vo.setSignType(MD5.MD5_NAME);
|
// vo.setTimeStamp(String.valueOf(System.currentTimeMillis()/1000));
|
// vo.setMwebUrl(responsePay.getCodeUrl());
|
// try {
|
// vo.setPaySign(WechatUtils.getSign(map, signKey));
|
// } catch (Exception e) {
|
// throw new PlatformRuntimeException("设置返回值签名错误:" + e.getMessage(), e);
|
// }
|
// return vo;
|
return this.acquireWechatNormalPayResultVo(platformPayOrder, signKey);
|
}
|
|
private WxPayJsResultVo acquireWechatNormalPayResultVo(Order platformPayOrder, String signKey){
|
H5ResponsePay responsePay = null;
|
try {
|
responsePay = (H5ResponsePay) this.payEngineManager.generatePrepareOrder(platformPayOrder);
|
} catch (OrderException e) {
|
throw new PlatformRuntimeException("发起微信预订单错误:" + e.getMessage() + ", orderId=" + e.getOrderId(), e);
|
}
|
if(!responsePay.getStatus()){
|
throw new PlatformRuntimeException("微信支付H5订单返回错误:" + responsePay.getMessage(), null);
|
}
|
|
Map<String, String> map = new HashMap<>();
|
map.put("appId", responsePay.getAppId());
|
map.put("nonceStr", responsePay.getAppId());
|
map.put("package", "prepay_id=" + responsePay.getPrepayId());
|
map.put("signType", MD5.MD5_NAME);
|
map.put("timeStamp", String.valueOf(System.currentTimeMillis()/1000));
|
|
WxPayJsResultVo vo = new WxPayJsResultVo();
|
vo.setAppId(responsePay.getAppId());
|
vo.setNonceStr(responsePay.getAppId());
|
vo.setPackages("prepay_id=" + responsePay.getPrepayId());
|
vo.setSignType(MD5.MD5_NAME);
|
vo.setTimeStamp(String.valueOf(System.currentTimeMillis()/1000));
|
vo.setMwebUrl(responsePay.getCodeUrl());
|
try {
|
vo.setPaySign(WechatUtils.getSign(map, signKey));
|
} catch (Exception e) {
|
throw new PlatformRuntimeException("设置返回值签名错误:" + e.getMessage(), e);
|
}
|
// order.setOutTradeNo(responsePay);
|
return vo;
|
}
|
|
@Deprecated
|
private WechatOrderVo acquireWechatOrderVo(EbOrder order, String openid) throws Exception{
|
WechatOrderVo vo = new WechatOrderVo();
|
final WebUserAgent webUserAgent = this.getCurrentWebUserAgent();
|
String domain = this.getArgumentVariable(Constants.CONFIG_KEY_SITE_URL).getStringValue();
|
String siteName = this.getArgumentVariable(Constants.CONFIG_KEY_SITE_NAME).getStringValue();
|
String apiDomain = this.getArgumentVariable(Constants.CONFIG_KEY_API_URL).getStringValue();
|
AttachVo attachVo = new AttachVo(PayConstants.PAY_SERVICE_TYPE_ORDER, order.getUid());
|
|
vo.setAppid(this.getArgumentVariable(WechatConstants.WECHAT_PUBLIC_APPID).getStringValue());
|
vo.setMch_id(this.getArgumentVariable(WechatConstants.WECHAT_PAY_PUBLIC_MCHID).getStringValue());
|
vo.setNonce_str(UUID.randomUUID().toString().replace("-", ""));
|
vo.setSign_type(MD5.MD5_NAME);
|
// 因商品名称在微信侧超长更换为网站名称
|
vo.setBody(siteName);
|
vo.setAttach(JsonUtils.objectToJsonString(attachVo));
|
vo.setOut_trade_no(order.getOrderNo()); // 系统订单号
|
double fenTotal = order.getPayPrice()*100; // 元转为分
|
vo.setTotal_fee((long)fenTotal);
|
vo.setSpbill_create_ip(webUserAgent.getIp());
|
vo.setNotify_url(apiDomain + PayConstants.WX_PAY_NOTIFY_API_URI);
|
switch (order.getPayChannel()) {
|
case PayConstants.PAY_CHANNEL_H5:
|
vo.setTrade_type(PayConstants.WX_PAY_TRADE_TYPE_H5);
|
vo.setOpenid(null);
|
break;
|
case PayConstants.PAY_CHANNEL_WECHAT_APP_IOS:
|
case PayConstants.PAY_CHANNEL_WECHAT_APP_ANDROID:
|
vo.setTrade_type(PayConstants.WX_PAY_TRADE_TYPE_APP);
|
vo.setOpenid(null);
|
break;
|
default:
|
vo.setTrade_type(PayConstants.WX_PAY_TRADE_TYPE_JS);
|
vo.setOpenid(openid);
|
}
|
|
CreateOrderH5SceneInfoVo createOrderH5SceneInfoVo = new CreateOrderH5SceneInfoVo(
|
new CreateOrderH5SceneInfoDetailVo(domain,siteName));
|
vo.setScene_info(JsonUtils.objectToJsonString(createOrderH5SceneInfoVo));
|
|
String voJson = JsonUtils.objectToJsonString(vo);
|
String sign = WechatUtils.getSign(voJson, this.getArgumentVariable(WechatConstants.WECHAT_PAY_PUBLIC_KEY).getStringValue());
|
vo.setSign(sign);
|
return vo;
|
}
|
|
/**
|
* 获取支付配置
|
* @return
|
*/
|
@RequestMapping(value = "/get/config", method = RequestMethod.GET)
|
public ResponseValue getPayConfig(){
|
String payWxOpen = this.getArgumentVariable(PayConstants.CONFIG_PAY_WECHAT_OPEN).getStringValue();
|
String yuePayStatus = this.getArgumentVariable(PayConstants.CONFIG_YUE_PAY_STATUS).getStringValue();
|
String aliPayStatus = this.getArgumentVariable(PayConstants.CONFIG_ALI_PAY_STATUS).getStringValue();
|
PayConfigResponse response = new PayConfigResponse();
|
response.setYuePayStatus(ArgumentsConstants.CONFIG_FORM_SWITCH_OPEN.equals(yuePayStatus));
|
response.setPayWechatOpen(ArgumentsConstants.CONFIG_FORM_SWITCH_OPEN.equals(payWxOpen));
|
response.setAliPayStatus(ArgumentsConstants.CONFIG_FORM_SWITCH_OPEN.equals(aliPayStatus));
|
if (ArgumentsConstants.CONFIG_FORM_SWITCH_OPEN.equals(yuePayStatus)) {
|
EbUser user = this.getCurrentEbUser();
|
response.setUserBalance(user.getNowMoney());
|
|
// 2023-08-07,是否存在支付密码
|
EbUserConfig config = this.getUserRegConfigCache().get(user.getId());
|
response.setPayPass(StringUtils.isNotEmpty(config.getPayPwd()));
|
}
|
return ResponseValue.success(response);
|
}
|
}
|