|
@ -5,77 +5,199 @@ |
|
|
*/ |
|
|
*/ |
|
|
package com.shop.cereshop.admin.pay.xs.impl; |
|
|
package com.shop.cereshop.admin.pay.xs.impl; |
|
|
|
|
|
|
|
|
import com.alipay.api.AlipayClient; |
|
|
|
|
|
import com.alipay.api.DefaultAlipayClient; |
|
|
|
|
|
import com.alipay.api.domain.AlipayTradeRefundApplyModel; |
|
|
|
|
|
import com.alipay.api.request.AlipayTradeRefundRequest; |
|
|
|
|
|
import com.alipay.api.response.AlipayTradeRefundResponse; |
|
|
|
|
|
import com.shop.cereshop.admin.pay.alipay.service.AliPayService; |
|
|
|
|
|
import com.shop.cereshop.commons.config.AlipayConfig; |
|
|
|
|
|
|
|
|
import cn.hutool.core.util.StrUtil; |
|
|
|
|
|
import com.alibaba.fastjson.JSONArray; |
|
|
|
|
|
import com.alibaba.fastjson.JSONObject; |
|
|
|
|
|
import com.alibaba.fastjson.TypeReference; |
|
|
|
|
|
import com.alibaba.fastjson.parser.Feature; |
|
|
|
|
|
import com.google.gson.Gson; |
|
|
|
|
|
import com.shop.cereshop.admin.dao.order.CereOrderProductDAO; |
|
|
|
|
|
import com.shop.cereshop.admin.dao.order.CereShopOrderDAO; |
|
|
|
|
|
import com.shop.cereshop.admin.dao.shop.CereShopBankDAO; |
|
|
|
|
|
import com.shop.cereshop.admin.pay.xs.XsPayService; |
|
|
|
|
|
import com.shop.cereshop.admin.service.shop.CerePlatformShopService; |
|
|
|
|
|
import com.shop.cereshop.commons.config.XspayConfig; |
|
|
import com.shop.cereshop.commons.constant.CoReturnFormat; |
|
|
import com.shop.cereshop.commons.constant.CoReturnFormat; |
|
|
import com.shop.cereshop.commons.constant.WxPayEnum; |
|
|
import com.shop.cereshop.commons.constant.WxPayEnum; |
|
|
|
|
|
import com.shop.cereshop.commons.domain.order.CereOrderParent; |
|
|
|
|
|
import com.shop.cereshop.commons.domain.order.CereOrderProduct; |
|
|
|
|
|
import com.shop.cereshop.commons.domain.order.CereShopOrder; |
|
|
|
|
|
import com.shop.cereshop.commons.domain.shop.CerePlatformShop; |
|
|
import com.shop.cereshop.commons.exception.CoBusinessException; |
|
|
import com.shop.cereshop.commons.exception.CoBusinessException; |
|
|
|
|
|
import com.shop.cereshop.commons.utils.EmptyUtils; |
|
|
|
|
|
import com.shop.cereshop.commons.utils.StringUtils; |
|
|
|
|
|
import com.shop.cereshop.commons.utils.xspay.CommonUtils; |
|
|
|
|
|
import com.shop.cereshop.commons.utils.xspay.XsPayUtils; |
|
|
import lombok.extern.slf4j.Slf4j; |
|
|
import lombok.extern.slf4j.Slf4j; |
|
|
|
|
|
import org.springframework.beans.factory.annotation.Autowired; |
|
|
import org.springframework.stereotype.Service; |
|
|
import org.springframework.stereotype.Service; |
|
|
|
|
|
|
|
|
import java.math.BigDecimal; |
|
|
import java.math.BigDecimal; |
|
|
import java.util.HashMap; |
|
|
|
|
|
import java.util.Map; |
|
|
|
|
|
|
|
|
import java.util.*; |
|
|
|
|
|
import java.util.stream.Collectors; |
|
|
|
|
|
|
|
|
@Service |
|
|
@Service |
|
|
@Slf4j(topic = "XsPayServiceImpl") |
|
|
@Slf4j(topic = "XsPayServiceImpl") |
|
|
public class XsPayServiceImpl implements AliPayService { |
|
|
|
|
|
|
|
|
public class XsPayServiceImpl implements XsPayService { |
|
|
|
|
|
|
|
|
|
|
|
private static final String SHARE_REFUND_SER_CODE = "101022"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Autowired |
|
|
|
|
|
private CereShopOrderDAO cereShopOrderDAO; |
|
|
|
|
|
|
|
|
|
|
|
@Autowired |
|
|
|
|
|
private CereOrderProductDAO cereOrderProductDAO; |
|
|
|
|
|
|
|
|
|
|
|
@Autowired |
|
|
|
|
|
private CerePlatformShopService cerePlatformShopservice; |
|
|
|
|
|
|
|
|
|
|
|
@Autowired |
|
|
|
|
|
private CereShopBankDAO cereShopBankDAO; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//售后退款中需要仲裁的售后退款 |
|
|
@Override |
|
|
@Override |
|
|
public Map<String, String> refund(String transactionId, String outRefundNo, BigDecimal total, BigDecimal refund) throws CoBusinessException, Exception { |
|
|
|
|
|
Map<String, String> result = new HashMap<>(); |
|
|
|
|
|
|
|
|
public Map<String, String> refund(String orderFormId, String outTradeNo, String transactionId, String outRefundNo, BigDecimal total, BigDecimal refund) throws CoBusinessException, Exception { |
|
|
|
|
|
Map<String, Object> contentMap = build22ContentMap(orderFormId, outRefundNo, outTradeNo, transactionId, refund, XspayConfig.BUSINESS_RETURN_NOTICE_URL); |
|
|
|
|
|
String respMsg = XsPayUtils.requestByXs(SHARE_REFUND_SER_CODE, contentMap); |
|
|
|
|
|
|
|
|
|
|
|
if(StrUtil.isNotBlank(respMsg)){ |
|
|
|
|
|
try { |
|
|
|
|
|
//解析响应报文并验签 |
|
|
|
|
|
CommonUtils.verifySignRespMsg(SHARE_REFUND_SER_CODE,respMsg); |
|
|
|
|
|
|
|
|
AlipayClient client = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID, AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.SIGNTYPE); |
|
|
|
|
|
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest(); |
|
|
|
|
|
//request.setNotifyUrl(AlipayConfig.REFUND_NOTIFY_URL); |
|
|
|
|
|
AlipayTradeRefundApplyModel model = new AlipayTradeRefundApplyModel(); |
|
|
|
|
|
//model.setOutTradeNo(outTradeNo); |
|
|
|
|
|
model.setTradeNo(transactionId); |
|
|
|
|
|
model.setRefundAmount(refund.toString()); |
|
|
|
|
|
request.setBizModel(model); |
|
|
|
|
|
|
|
|
|
|
|
AlipayTradeRefundResponse response = client.execute(request); |
|
|
|
|
|
if (response.isSuccess()) { |
|
|
|
|
|
//这里只是申请退款,兼容微信的返回 |
|
|
|
|
|
|
|
|
LinkedHashMap<String,String> responseMap = JSONObject.parseObject(respMsg,new TypeReference<LinkedHashMap<String,String>>(){}, Feature.OrderedField ); |
|
|
|
|
|
String resMsg = responseMap.get("msg"); |
|
|
|
|
|
String responeMsg = new String(Base64.getDecoder().decode(resMsg)); |
|
|
|
|
|
JSONObject jsonObject = JSONObject.parseObject(responeMsg); |
|
|
|
|
|
JSONObject content = jsonObject.getJSONObject("content"); |
|
|
|
|
|
String status = content.getString("status"); |
|
|
|
|
|
//2成功 3失败 |
|
|
|
|
|
if(StringUtils.equals(status, "1")) { |
|
|
|
|
|
Map<String, String> result = new HashMap<>(); |
|
|
result.put("return_msg", WxPayEnum.REFUND_SUCCESS.getCode()); |
|
|
result.put("return_msg", WxPayEnum.REFUND_SUCCESS.getCode()); |
|
|
result.put("return_code", WxPayEnum.REFUND_OK.getCode()); |
|
|
result.put("return_code", WxPayEnum.REFUND_OK.getCode()); |
|
|
|
|
|
return result; |
|
|
|
|
|
} |
|
|
|
|
|
} catch (CoBusinessException e) { |
|
|
|
|
|
if(StringUtils.equals(e.getCode(), "0005")){ |
|
|
|
|
|
throw new CoBusinessException(CoReturnFormat.APPLY_REFUND_FAILED_LATER,"支付系统正在处理,请支付5分钟后再申请退款", ""); |
|
|
}else { |
|
|
}else { |
|
|
log.error("alipay refund failed: subCode = {}, subMsg = {}", response.getSubCode(), response.getSubMsg()); |
|
|
|
|
|
throw new CoBusinessException(CoReturnFormat.APPLY_REFUND_FAILED); |
|
|
|
|
|
|
|
|
throw e; |
|
|
} |
|
|
} |
|
|
return result; |
|
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
//支付方式为B2C、B2B、H5,成功响应时respMsg为html页面代码 |
|
|
|
|
|
if(respMsg.contains("toNativePayIndexForm")){ |
|
|
|
|
|
log.info("【" + SHARE_REFUND_SER_CODE + "】接口-响应报文-HTML代码无需验签"); |
|
|
|
|
|
}else{ |
|
|
|
|
|
e.printStackTrace(); |
|
|
|
|
|
} |
|
|
|
|
|
throw new CoBusinessException("10000","退款出错", ""); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
return null; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//保证金退款 |
|
|
|
|
|
//TODO 待开发 |
|
|
@Override |
|
|
@Override |
|
|
public Map<String, String> refundBond(String transactionId, String outRefundNo, BigDecimal total, BigDecimal refund) throws CoBusinessException, Exception { |
|
|
public Map<String, String> refundBond(String transactionId, String outRefundNo, BigDecimal total, BigDecimal refund) throws CoBusinessException, Exception { |
|
|
Map<String, String> result = new HashMap<>(); |
|
|
|
|
|
|
|
|
throw new CoBusinessException("10000","新生通道保证金退款功能待开发", ""); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private Map<String,Object> build22ContentMap(String orderFormId, String merOrderId, String oldMerOrderId, String dealId, BigDecimal money, String noticeUrl) throws CoBusinessException { |
|
|
|
|
|
List<CereShopOrder> orderList = null; |
|
|
|
|
|
|
|
|
|
|
|
String cereOrderFormId = orderFormId; |
|
|
|
|
|
String[] split = orderFormId.split("-"); |
|
|
|
|
|
if(!EmptyUtils.isEmpty(split)) { |
|
|
|
|
|
cereOrderFormId = split[0]; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//查询是否为父订单编号 |
|
|
|
|
|
CereOrderParent parent = cereShopOrderDAO.findByParentFormid(cereOrderFormId); |
|
|
|
|
|
if (parent != null) { |
|
|
|
|
|
//查询所有子订单数据 |
|
|
|
|
|
orderList = cereShopOrderDAO.findByParentId(parent.getParentId()); |
|
|
|
|
|
|
|
|
AlipayClient client = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID, AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.SIGNTYPE); |
|
|
|
|
|
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest(); |
|
|
|
|
|
//request.setNotifyUrl(AlipayConfig.REFUND_NOTIFY_URL); |
|
|
|
|
|
AlipayTradeRefundApplyModel model = new AlipayTradeRefundApplyModel(); |
|
|
|
|
|
//model.setOutTradeNo(outTradeNo); |
|
|
|
|
|
model.setTradeNo(transactionId); |
|
|
|
|
|
model.setRefundAmount(refund.toString()); |
|
|
|
|
|
request.setBizModel(model); |
|
|
|
|
|
|
|
|
|
|
|
AlipayTradeRefundResponse response = client.execute(request); |
|
|
|
|
|
if (response.isSuccess()) { |
|
|
|
|
|
//这里只是申请退款,兼容微信的返回 |
|
|
|
|
|
result.put("return_msg", WxPayEnum.REFUND_SUCCESS.getCode()); |
|
|
|
|
|
result.put("return_code", WxPayEnum.REFUND_OK.getCode()); |
|
|
|
|
|
result.put("out_trade_no", response.getOutTradeNo()); |
|
|
|
|
|
result.put("transaction_id", response.getTradeNo()); |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
log.error("alipay refundBond failed: subCode = {}, subMsg = {}", response.getSubCode(), response.getSubMsg()); |
|
|
|
|
|
throw new CoBusinessException(CoReturnFormat.APPLY_REFUND_FAILED); |
|
|
|
|
|
|
|
|
//子订单支付回调 |
|
|
|
|
|
orderList = cereShopOrderDAO.findByFormid(cereOrderFormId); |
|
|
} |
|
|
} |
|
|
return result; |
|
|
|
|
|
|
|
|
//这里理论上只会有一个子订单,如果出现多个说明出错了 |
|
|
|
|
|
if(orderList.size() != 1){ |
|
|
|
|
|
throw new CoBusinessException("10000","订单查找出错", ""); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
List<CereOrderProduct> cereOrderProductList = cereOrderProductDAO.findByOrderIds(orderList.stream().map(CereShopOrder::getOrderId).collect(Collectors.toList())); |
|
|
|
|
|
log.info("cereOrderProductList:" + new Gson().toJson(cereOrderProductList)); |
|
|
|
|
|
|
|
|
|
|
|
List<Long> shopIdList = orderList.stream().map(CereShopOrder::getShopId).distinct().collect(Collectors.toList()); |
|
|
|
|
|
List<CerePlatformShop> cerePlatformShopList = cerePlatformShopservice.getByIdList(shopIdList); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Map<String, Object> contentMap = new LinkedHashMap<>(); |
|
|
|
|
|
log.info("orderFormid:" + orderFormId); |
|
|
|
|
|
contentMap.put("merOrderId", merOrderId); |
|
|
|
|
|
//oldMerOrderId 对应 101004、101005接口中merOrderId |
|
|
|
|
|
contentMap.put("oldMerOrderId", oldMerOrderId); |
|
|
|
|
|
//oldDealId 对应 101004、101005接口响应参数中dealId |
|
|
|
|
|
// contentMap.put("oldDealId", dealId); |
|
|
|
|
|
contentMap.put("oldSubOrderId", orderList.get(0).getOrderFormid()); |
|
|
|
|
|
JSONArray jsonArray = build22SubMerchantOrderDetails(orderList, cereOrderProductList, cerePlatformShopList); |
|
|
|
|
|
if(jsonArray != null) { |
|
|
|
|
|
contentMap.put("shareRefundDetail", JSONArray.toJSONString(jsonArray)); |
|
|
|
|
|
} |
|
|
|
|
|
contentMap.put("currency", "CNY"); |
|
|
|
|
|
contentMap.put("noticeUrl", noticeUrl); |
|
|
|
|
|
|
|
|
|
|
|
return contentMap; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 构建分账明细 |
|
|
|
|
|
* @return |
|
|
|
|
|
*/ |
|
|
|
|
|
private static JSONArray build22SubMerchantOrderDetails(List<CereShopOrder> orderList, |
|
|
|
|
|
List<CereOrderProduct> cereOrderProductList, |
|
|
|
|
|
List<CerePlatformShop> cerePlatformShopList){ |
|
|
|
|
|
if(cereOrderProductList.isEmpty()){ |
|
|
|
|
|
return null; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
JSONArray detailArray1 = new JSONArray(); |
|
|
|
|
|
|
|
|
|
|
|
for (CereShopOrder cereShopOrder : orderList) { |
|
|
|
|
|
CerePlatformShop cerePlatformShop = cerePlatformShopList.stream().filter(item -> |
|
|
|
|
|
item.getShopId().equals(cereShopOrder.getShopId())).findFirst().orElse(null); |
|
|
|
|
|
List<CereOrderProduct> orderProductList = cereOrderProductList.stream().filter(item -> item.getOrderId().equals(cereShopOrder.getOrderId())).collect(Collectors.toList()); |
|
|
|
|
|
for (CereOrderProduct cereOrderProduct : orderProductList) { |
|
|
|
|
|
//子订单1 明细1 |
|
|
|
|
|
JSONObject detail1 = new JSONObject(); |
|
|
|
|
|
detail1.put("shareDetailId", "" + cereOrderProduct.getOrderId() + cereOrderProduct.getOrderProductId()); |
|
|
|
|
|
detail1.put("shareParId", cerePlatformShop.getXsPayId()); |
|
|
|
|
|
//这里是否需要减去用积分抵扣金额 |
|
|
|
|
|
detail1.put("shareRefundAmount", |
|
|
|
|
|
cereOrderProduct.getActualPrice().add(cereOrderProduct.getLogisticsPrice()) |
|
|
|
|
|
.subtract(cereOrderProduct.getUseCreditAmount()) |
|
|
|
|
|
.subtract(cereOrderProduct.getPlatformCommission()) |
|
|
|
|
|
.multiply(BigDecimal.valueOf(100)).intValue() |
|
|
|
|
|
); |
|
|
|
|
|
// detail1.put("settleCurCode","CNY"); |
|
|
|
|
|
detailArray1.add(detail1); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
JSONObject detail2 = new JSONObject(); |
|
|
|
|
|
detail2.put("shareDetailId", "platformCommission-" + cereShopOrder.getOrderId()); |
|
|
|
|
|
detail2.put("shareParId", XspayConfig.MER_CODE); |
|
|
|
|
|
detail2.put("shareRefundAmount", cereShopOrder.getPlatformCommission().multiply(BigDecimal.valueOf(100)).intValue()); |
|
|
|
|
|
// detail2.put("settleCurCode","CNY"); |
|
|
|
|
|
detailArray1.add(detail2); |
|
|
|
|
|
} |
|
|
|
|
|
return detailArray1; |
|
|
|
|
|
} |
|
|
} |
|
|
} |