@@ -0,0 +1,84 @@ | |||
package com.iformall.domain.po; | |||
import com.baomidou.mybatisplus.annotation.TableField; | |||
import com.baomidou.mybatisplus.annotation.TableName; | |||
import com.iformall.domain.po.base.TenantEntity; | |||
import lombok.Data; | |||
import lombok.EqualsAndHashCode; | |||
import lombok.ToString; | |||
import java.math.BigDecimal; | |||
import java.util.Date; | |||
@TableName(value = "product_order_refund") | |||
@Data | |||
@ToString(callSuper = true) | |||
@EqualsAndHashCode(callSuper = true) | |||
public class ProductOrderRefund extends TenantEntity { | |||
protected Long id; | |||
@io.swagger.annotations.ApiModelProperty(value="系统订单号",name="orderId") | |||
private Long orderId; | |||
@io.swagger.annotations.ApiModelProperty(value="系统订单号",name="orderNumber") | |||
private String orderNumber; | |||
@io.swagger.annotations.ApiModelProperty(value="EnumProject",name="projectType") | |||
private Integer projectType; | |||
@io.swagger.annotations.ApiModelProperty(value = "EnumProductOrderPayVendor", name = "payVendor") | |||
private Integer payVendor; | |||
@io.swagger.annotations.ApiModelProperty(value="用户id",name="userId") | |||
private Long userId; | |||
@io.swagger.annotations.ApiModelProperty(value="支付id",name="payId") | |||
private Long payId; | |||
@io.swagger.annotations.ApiModelProperty(value="第三方订单号",name="transactionId") | |||
private String transactionId; | |||
@io.swagger.annotations.ApiModelProperty(value="订单金额(分)",name="payAmount") | |||
private Integer payAmount; | |||
@io.swagger.annotations.ApiModelProperty(value="退款金额(分)",name="refundAmount") | |||
private Integer refundAmount; | |||
@io.swagger.annotations.ApiModelProperty(value="EnumRefundOrderStatus",name="refundOrderStatus") | |||
private Integer refundOrderStatus; | |||
@io.swagger.annotations.ApiModelProperty(value="失败原因",name="failReason") | |||
private String failReason; | |||
@io.swagger.annotations.ApiModelProperty(value="",name="refundId") | |||
private String refundId; | |||
@io.swagger.annotations.ApiModelProperty(value="退款原因",name="refundReason") | |||
private String refundReason; | |||
@io.swagger.annotations.ApiModelProperty(value="退款补充原因",name="refundDescription") | |||
private String refundDescription; | |||
@io.swagger.annotations.ApiModelProperty(value="创建时间",name="createDate") | |||
private Date createDate; | |||
@io.swagger.annotations.ApiModelProperty(value="更新时间",name="updateDate") | |||
private Date updateDate; | |||
@TableField(exist = false) | |||
private String payAmountStr; | |||
public String getPayAmountStr() { | |||
return payAmount != null ? new BigDecimal(payAmount).divide(new BigDecimal(100)).toPlainString() : payAmountStr; | |||
} | |||
@TableField(exist = false) | |||
private String refundAmountStr; | |||
public String getRefundAmountStr() { | |||
return refundAmount != null ? new BigDecimal(refundAmount).divide(new BigDecimal(100)).toPlainString() : refundAmountStr; | |||
} | |||
@TableField(exist = false) | |||
private Date startDate; | |||
@TableField(exist = false) | |||
private Date endDate; | |||
} |
@@ -0,0 +1,39 @@ | |||
package com.iformall.enums; | |||
/** | |||
* | |||
*/ | |||
public enum EnumRefundOrderStatus { | |||
REFUND_WAIT(0, "退款中"), | |||
REFUND_REQ_SUCCESS(1, "退款申请成功"), | |||
REFUND_REQ_FAIL(2, "退款申请失败"), | |||
REFUND_REQ_AGREE(3, "同意退款"), | |||
REFUND_SUCCESS(4, "退款成功"), | |||
REFUND_FAIL(5, "退款失败"), | |||
; | |||
public static EnumRefundOrderStatus getEnum(Integer code) { | |||
for (EnumRefundOrderStatus value : values()) { | |||
if (value.getCode().equals(code)) { | |||
return value; | |||
} | |||
} | |||
return null; | |||
} | |||
private Integer code; | |||
private String message; | |||
EnumRefundOrderStatus(Integer code, String message) { | |||
this.code = code; | |||
this.message = message; | |||
} | |||
public Integer getCode() { | |||
return code; | |||
} | |||
public String getMessage() { | |||
return message; | |||
} | |||
} |
@@ -0,0 +1,15 @@ | |||
package com.iformall.mapper; | |||
import com.iformall.common.CommonMapper; | |||
import com.iformall.domain.po.ProductOrderPay; | |||
import com.iformall.domain.po.ProductOrderRefund; | |||
import org.apache.ibatis.annotations.Param; | |||
import java.util.List; | |||
public interface ProductOrderRefundMapper extends CommonMapper<ProductOrderRefund, Long> { | |||
List<ProductOrderRefund> findList(ProductOrderRefund record); | |||
int orderRefundUpdStatus(ProductOrderRefund record); | |||
} |
@@ -0,0 +1,31 @@ | |||
package com.iformall.service; | |||
import com.github.pagehelper.PageInfo; | |||
import com.iformall.common.ResultData; | |||
import com.iformall.domain.po.ProductOrderPay; | |||
import com.iformall.domain.po.ProductOrderRefund; | |||
import com.iformall.domain.po.WxAppinfo; | |||
import com.iformall.domain.po.WxPayAccount; | |||
import com.iformall.enums.EnumProductOrderPayVendor; | |||
import com.iformall.service.pay.service.pay.PayAdapterService; | |||
import com.iformall.service.pay.service.pay.entity.PayQueryAdapterResult; | |||
public interface ProductOrderRefundService { | |||
/** | |||
* 根据实体查询分页列表 | |||
* | |||
* @param record | |||
* @param pageIndex | |||
* @param pageSize | |||
* @return | |||
*/ | |||
PageInfo<ProductOrderRefund> listAsPage(ProductOrderRefund record, Integer pageIndex, Integer pageSize); | |||
void saveOrUpdate(ProductOrderRefund record); | |||
ProductOrderRefund getById(Long id); | |||
void handleRefund(ProductOrderPay orderPay); | |||
} |
@@ -17,6 +17,7 @@ import com.iformall.service.pay.PayServiceFactory; | |||
import com.iformall.service.pay.service.pay.PayAdapterService; | |||
import com.iformall.service.pay.service.pay.entity.PayAdapterResult; | |||
import com.iformall.service.pay.service.pay.entity.PayQueryAdapterResult; | |||
import com.iformall.service.pay.service.refund.RefundPayAdapterService; | |||
import com.iformall.utils.DateUtils; | |||
import com.iformall.utils.RedisLock; | |||
import lombok.extern.slf4j.Slf4j; | |||
@@ -58,6 +59,9 @@ public class ProductOrderPayServiceImpl implements ProductOrderPayService { | |||
@Autowired | |||
WxPayAccountService wxPayAccountService; | |||
@Autowired | |||
ProductOrderRefundService productOrderRefundService; | |||
@Autowired | |||
PayServiceFactory payServiceFactory; | |||
@@ -246,8 +250,7 @@ public class ProductOrderPayServiceImpl implements ProductOrderPayService { | |||
if(EnumPayOrderStatus.ORDER_STATUS_REFUND_WAIT.getCode().equals(productOrderPay.getPayOrderStatus())){ | |||
logger.info("当前订单异常支付,退款处理"); | |||
//todo 退款 | |||
productOrderRefundService.handleRefund(productOrderPay); | |||
return; | |||
} | |||
@@ -0,0 +1,122 @@ | |||
package com.iformall.service.impl; | |||
import com.github.pagehelper.PageHelper; | |||
import com.github.pagehelper.PageInfo; | |||
import com.iformall.common.ErrorCode; | |||
import com.iformall.common.IdWorker; | |||
import com.iformall.common.ResultData; | |||
import com.iformall.domain.po.*; | |||
import com.iformall.enums.*; | |||
import com.iformall.exception.MallinkException; | |||
import com.iformall.mapper.*; | |||
import com.iformall.service.*; | |||
import com.iformall.service.pay.PayServiceFactory; | |||
import com.iformall.service.pay.service.pay.PayAdapterService; | |||
import com.iformall.service.pay.service.pay.entity.PayAdapterResult; | |||
import com.iformall.service.pay.service.pay.entity.PayQueryAdapterResult; | |||
import com.iformall.service.pay.service.refund.RefundPayAdapterService; | |||
import com.iformall.service.pay.service.refund.entity.RefundAdapterResult; | |||
import com.iformall.utils.RedisLock; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.springframework.aop.framework.AopContext; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
import org.springframework.stereotype.Service; | |||
import org.springframework.transaction.annotation.Propagation; | |||
import org.springframework.transaction.annotation.Transactional; | |||
import java.util.Date; | |||
@Service | |||
@Slf4j | |||
public class ProductOrderRefundServiceImpl implements ProductOrderRefundService { | |||
private final Logger logger = LoggerFactory.getLogger(this.getClass()); | |||
@Autowired | |||
ProductOrderRefundMapper productOrderRefundMapper; | |||
@Autowired | |||
ProductOrderPayMapper productOrderPayMapper; | |||
@Autowired | |||
PayServiceFactory payServiceFactory; | |||
@Autowired | |||
WxAppinfoService wxAppinfoService; | |||
@Autowired | |||
WxPayAccountService wxPayAccountService; | |||
@Override | |||
public PageInfo<ProductOrderRefund> listAsPage(ProductOrderRefund record, Integer pageIndex, Integer pageSize) { | |||
return PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> productOrderRefundMapper.findList(record)); | |||
} | |||
@Override | |||
public void saveOrUpdate(ProductOrderRefund record) { | |||
Date now = new Date(); | |||
if (record.getId() == null) { | |||
final IdWorker idWorker = IdWorker.get(); | |||
record.setId(idWorker.nextId()); | |||
record.setCreateDate(now); | |||
record.setUpdateDate(now); | |||
productOrderRefundMapper.insert(record); | |||
} else { | |||
record.setUpdateDate(now); | |||
productOrderRefundMapper.updateById(record); | |||
} | |||
} | |||
@Override | |||
public ProductOrderRefund getById(Long id) { | |||
return productOrderRefundMapper.selectById(id); | |||
} | |||
@Override | |||
public void handleRefund(ProductOrderPay orderPay) { | |||
String refundReason = "重复支付退款"; | |||
Date now = new Date(); | |||
ProductOrderRefund record = new ProductOrderRefund(); | |||
final IdWorker idWorker = IdWorker.get(); | |||
record.setId(idWorker.nextId()); | |||
record.setOrderId(orderPay.getOrderId()); | |||
record.setOrderNumber(orderPay.getOrderNumber()); | |||
record.setProjectType(orderPay.getProjectType()); | |||
record.setPayVendor(orderPay.getPayVendor()); | |||
record.setUserId(orderPay.getUserId()); | |||
record.setPayId(orderPay.getId()); | |||
record.setTransactionId(orderPay.getTransactionId()); | |||
record.setPayAmount(orderPay.getPayAmount()); | |||
record.setRefundAmount(orderPay.getPayAmount()); | |||
record.setRefundOrderStatus(EnumRefundOrderStatus.REFUND_WAIT.getCode()); | |||
record.setRefundReason(refundReason); | |||
record.setCreateDate(now); | |||
record.setUpdateDate(now); | |||
productOrderRefundMapper.insert(record); | |||
RefundPayAdapterService refundPayAdapterService = payServiceFactory.getRefundPayAdapterService(record.getPayVendor()); | |||
EnumProductOrderPayVendor payVendorEnum = EnumProductOrderPayVendor.getEnum(record.getPayVendor()); | |||
WxAppinfo appinfo = wxAppinfoService.getProjectCAppInfoFromRedis(record.getProjectType(), payVendorEnum.getPlat()); | |||
WxPayAccount payAccount = wxPayAccountService.getByIdFromRedis(appinfo.getPayId()); | |||
RefundAdapterResult refund = refundPayAdapterService.refund(appinfo, payAccount, record); | |||
if(refund.isSuccess()){ | |||
ProductOrderRefund orderRefundUpd = new ProductOrderRefund(); | |||
orderRefundUpd.setId(record.getId()); | |||
orderRefundUpd.setRefundId(refund.getRefundId()); | |||
orderRefundUpd.setRefundOrderStatus(EnumRefundOrderStatus.REFUND_REQ_SUCCESS.getCode()); | |||
productOrderRefundMapper.updateById(orderRefundUpd); | |||
ProductOrderPay orderPayUpd = new ProductOrderPay(); | |||
orderPayUpd.setId(orderPay.getId()); | |||
orderPayUpd.setPayOrderStatus(EnumPayOrderStatus.ORDER_STATUS_PENDING_REFUND.getCode()); | |||
productOrderPayMapper.orderPayUpdStatus(orderPayUpd); | |||
} | |||
} | |||
} |
@@ -6,6 +6,7 @@ import com.iformall.enums.EnumAppPlat; | |||
import com.iformall.enums.EnumPayVersion; | |||
import com.iformall.enums.EnumProductOrderPayVendor; | |||
import com.iformall.service.pay.service.pay.wx.v3.nativePay.WxNativePayV3AdapterService; | |||
import com.iformall.service.pay.service.refund.ali.AliRefundAdapterService; | |||
import com.iformall.service.pay.service.refund.douyin.TtRefundAdapterService; | |||
import com.iformall.service.pay.service.refund.wx.v2.WxRefundAdapterService; | |||
import com.iformall.service.pay.service.refund.wx.v3.WxRefundV3AdapterService; | |||
@@ -50,6 +51,7 @@ public class PayServiceFactory { | |||
private Map<String,PayAdapterService> payVendorServiceMap = null; | |||
private Map<String,PayShareAdapterService> payVendorShareMap = null; | |||
private Map<String,RefundPayAdapterService> payVendorRefundMap = null; | |||
private Map<String,PayAdapterService> platQrcodeMap = null; | |||
private Map<String,PayAdapterService> platMsgMap = null; | |||
@@ -92,6 +94,8 @@ public class PayServiceFactory { | |||
@Autowired | |||
TtRefundAdapterService ttRefundService; | |||
@Autowired | |||
AliRefundAdapterService aliRefundService; | |||
@Autowired | |||
WxCashOutQYFKAdapterService wxCashOutService; | |||
@@ -235,6 +239,18 @@ public class PayServiceFactory { | |||
} | |||
return refundMap; | |||
} | |||
private Map<String,RefundPayAdapterService> getPayVendorRefundMap(){ | |||
if (null == payVendorRefundMap ) { | |||
payVendorRefundMap = new ConcurrentHashMap<String, RefundPayAdapterService>(); | |||
payVendorRefundMap.put(EnumProductOrderPayVendor.PAY_WAY_WECHAT.getCode()+"_", wxRefundV3AdapterService); | |||
payVendorRefundMap.put(EnumProductOrderPayVendor.PAY_WAY_WECHAT_NATIVE.getCode()+"_", wxRefundV3AdapterService); | |||
payVendorRefundMap.put(EnumProductOrderPayVendor.PAY_WAY_ALIPAY.getCode()+"_", aliRefundService); | |||
// payVendorRefundMap.put(EnumProductOrderPayVendor.PAY_WAY_ALIPAY_WAP.getCode()+"_",); | |||
payVendorRefundMap.put(EnumProductOrderPayVendor.PAY_WAY_TT.getCode()+"_",ttRefundService); | |||
} | |||
return payVendorRefundMap; | |||
} | |||
private Map<String,CashOutAdapterService> getCashOutMap() { | |||
if (null == cashoutMap ) { | |||
@@ -334,6 +350,14 @@ public class PayServiceFactory { | |||
} | |||
return refundService; | |||
} | |||
public RefundPayAdapterService getRefundPayAdapterService(Integer payVendor) throws MallinkException{ | |||
RefundPayAdapterService refundService = getPayVendorRefundMap().get(payVendor+"_"); | |||
if (null == refundService) { | |||
throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(),"payWay["+payVendor+"] 退款service未找到"); | |||
} | |||
return refundService; | |||
} | |||
public CashOutAdapterService getCashOutAdapterService(Integer type,Integer payVersion)throws MallinkException { | |||
CashOutAdapterService cashOutService = getCashOutMap().get(type+"_"+payVersion); | |||
@@ -2,10 +2,7 @@ package com.iformall.service.pay.service.refund; | |||
import java.util.Map; | |||
import com.iformall.domain.po.WxAppinfo; | |||
import com.iformall.domain.po.WxPayAccount; | |||
import com.iformall.domain.po.WxPayOrder; | |||
import com.iformall.domain.po.WxRefundOrder; | |||
import com.iformall.domain.po.*; | |||
import com.iformall.enums.EnumPayType; | |||
import com.iformall.enums.EnumPayWay; | |||
import com.iformall.service.pay.service.refund.entity.RefundAdapterResult; | |||
@@ -23,6 +20,8 @@ public interface RefundPayAdapterService { | |||
* @return | |||
*/ | |||
public RefundAdapterResult refund(WxPayAccount payAccount,WxAppinfo appInfo,WxRefundOrder record,WxPayOrder payOrder,Long orderId,EnumPayType payType); | |||
public RefundAdapterResult refund(WxAppinfo appInfo, WxPayAccount payAccount, ProductOrderRefund orderRefund); | |||
/** | |||
* API查询退款 | |||
@@ -32,6 +31,8 @@ public interface RefundPayAdapterService { | |||
* @return | |||
*/ | |||
public RefundAdapterResult queryRefund(WxAppinfo appInfo,WxPayAccount payAccount, WxRefundOrder record); | |||
public RefundAdapterResult queryRefund(WxAppinfo appInfo,WxPayAccount payAccount, ProductOrderRefund orderRefund); | |||
/** | |||
* 平台方 异步通知 | |||
@@ -0,0 +1,199 @@ | |||
package com.iformall.service.pay.service.refund.ali; | |||
import com.alibaba.fastjson.JSON; | |||
import com.alibaba.fastjson.JSONObject; | |||
import com.alipay.api.AlipayApiException; | |||
import com.alipay.api.AlipayClient; | |||
import com.alipay.api.request.AlipayTradeFastpayRefundQueryRequest; | |||
import com.alipay.api.request.AlipayTradeRefundRequest; | |||
import com.alipay.api.response.AlipayTradeFastpayRefundQueryResponse; | |||
import com.alipay.api.response.AlipayTradeRefundResponse; | |||
import com.iformall.common.ErrorCode; | |||
import com.iformall.domain.po.*; | |||
import com.iformall.douyin.pay.TtPayService; | |||
import com.iformall.douyin.pay.exception.TtPayException; | |||
import com.iformall.douyin.payv2.request.TtPayRefundQueryV2Request; | |||
import com.iformall.douyin.payv2.request.TtPayRefundV2Request; | |||
import com.iformall.douyin.payv2.result.TtPayRefundQueryV2Result; | |||
import com.iformall.douyin.payv2.result.TtPayRefundV2Result; | |||
import com.iformall.enums.EnumPayType; | |||
import com.iformall.enums.EnumPayWay; | |||
import com.iformall.enums.EnumRefundOrderStatus; | |||
import com.iformall.enums.EnumRefundStatus; | |||
import com.iformall.exception.MallinkException; | |||
import com.iformall.mapper.WxPayOrderMapper; | |||
import com.iformall.mapper.WxRefundOrderMapper; | |||
import com.iformall.service.WxAppinfoService; | |||
import com.iformall.service.WxOrderService; | |||
import com.iformall.service.WxPayAccountService; | |||
import com.iformall.service.pay.service.refund.RefundPayAdapterService; | |||
import com.iformall.service.pay.service.refund.entity.RefundAdapterResult; | |||
import com.iformall.service.pay.service.refund.entity.RefundNotifyAdapterResult; | |||
import com.iformall.utils.Constant; | |||
import com.iformall.utils.MaUtil; | |||
import com.iformall.utils.XmlUtil; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.apache.commons.lang3.StringUtils; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
import org.springframework.stereotype.Service; | |||
import java.util.*; | |||
@Slf4j | |||
@Service | |||
public class AliRefundAdapterService implements RefundPayAdapterService{ | |||
@Autowired | |||
MaUtil maUtil; | |||
/** | |||
* 做为分账的扩展数据 | |||
* @param | |||
* @return | |||
*/ | |||
protected String getCpExtra(WxRefundOrder record) { | |||
Map<String,String> map = new HashMap<>(); | |||
map.put("tenantId",record.getTenantId()); | |||
return JSON.toJSONString(map); | |||
} | |||
@Override | |||
public RefundAdapterResult refund(WxPayAccount payAccount,WxAppinfo appInfo,WxRefundOrder record,WxPayOrder payOrder,Long orderId,EnumPayType payType) { | |||
return null; | |||
} | |||
@Override | |||
public RefundAdapterResult refund(WxAppinfo appInfo, WxPayAccount payAccount, ProductOrderRefund orderRefund) { | |||
AlipayClient aliPayClient = maUtil.getAliPayClient(appInfo, payAccount); | |||
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest(); | |||
JSONObject bizContent = new JSONObject(); | |||
bizContent.put("out_trade_no", orderRefund.getOrderNumber()); | |||
bizContent.put("refund_amount", orderRefund.getRefundAmountStr()); | |||
bizContent.put("refund_reason", orderRefund.getRefundDescription()); | |||
bizContent.put("out_request_no", orderRefund.getId().toString()); | |||
//// 返回参数选项,按需传入 | |||
//JSONArray queryOptions = new JSONArray(); | |||
//queryOptions.add("refund_detail_item_list"); | |||
//bizContent.put("query_options", queryOptions); | |||
request.setBizContent(bizContent.toString()); | |||
try { | |||
AlipayTradeRefundResponse response = aliPayClient.execute(request); | |||
if(response.isSuccess()){ | |||
if("10000".equals(response.getCode())){ | |||
RefundAdapterResult refundAdapterResult = new RefundAdapterResult(); | |||
refundAdapterResult.setSuccess(true); | |||
refundAdapterResult.setCode(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode()); | |||
refundAdapterResult.setData(response); | |||
return refundAdapterResult; | |||
} | |||
} | |||
return new RefundAdapterResult(false,EnumRefundStatus.REFUND_REQ_FAIL.getCode(),response.getMsg(),response); | |||
} catch (AlipayApiException e) { | |||
log.error("支付宝退款失败{}"+e.getMessage()); | |||
e.printStackTrace(); | |||
return new RefundAdapterResult(false,EnumRefundStatus.REFUND_REQ_FAIL.getCode(),EnumRefundStatus.REFUND_REQ_FAIL.getMessage(),null); | |||
} | |||
} | |||
@Override | |||
public RefundAdapterResult queryRefund(WxAppinfo appInfo,WxPayAccount payAccount, WxRefundOrder record) { | |||
return null; | |||
} | |||
@Override | |||
public RefundAdapterResult queryRefund(WxAppinfo appInfo, WxPayAccount payAccount, ProductOrderRefund orderRefund) { | |||
AlipayClient aliPayClient = maUtil.getAliPayClient(appInfo, payAccount); | |||
AlipayTradeFastpayRefundQueryRequest request = new AlipayTradeFastpayRefundQueryRequest(); | |||
JSONObject bizContent = new JSONObject(); | |||
bizContent.put("out_trade_no", orderRefund.getOrderNumber()); | |||
bizContent.put("out_request_no", orderRefund.getId()); | |||
//// 返回参数选项,按需传入 | |||
//JSONArray queryOptions = new JSONArray(); | |||
//queryOptions.add("refund_detail_item_list"); | |||
//bizContent.put("query_options", queryOptions); | |||
request.setBizContent(bizContent.toString()); | |||
try { | |||
AlipayTradeFastpayRefundQueryResponse response = aliPayClient.execute(request); | |||
if(response.isSuccess()){ | |||
if("REFUND_SUCCESS".equals(response.getRefundStatus())){ | |||
return new RefundAdapterResult(true, EnumRefundOrderStatus.REFUND_SUCCESS.getCode(),"退款成功",response); | |||
} | |||
return new RefundAdapterResult(false,EnumRefundOrderStatus.REFUND_FAIL.getCode(),"退款失败",response); | |||
} | |||
} catch (AlipayApiException e) { | |||
e.printStackTrace(); | |||
log.error("查询支付宝退款结果失败"+e.getMessage()); | |||
throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(),e.getMessage()); | |||
} | |||
throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR); | |||
} | |||
@Autowired | |||
WxAppinfoService wxAppinfoService; | |||
@Autowired | |||
WxPayAccountService wxPayAccountService; | |||
@Autowired | |||
WxPayOrderMapper wxPayOrderMapper; | |||
@Autowired | |||
WxRefundOrderMapper wxRefundOrderMapper; | |||
private RefundNotifyAdapterResult notifyErrorResult(String msg) { | |||
SortedMap resultMap = new TreeMap(); | |||
resultMap.put("return_code", "FAIL"); | |||
resultMap.put("return_msg", msg); | |||
return new RefundNotifyAdapterResult(false,ErrorCode.REFUND_ORDER_ERROR.getCode(),msg,XmlUtil.getRequestXml(resultMap)); | |||
} | |||
private RefundNotifyAdapterResult notifySuccessResult(String transactionId,String refundId,WxRefundOrder refundOrder) { | |||
SortedMap resultMap = new TreeMap(); | |||
resultMap.put("return_code", "SUCCESS"); | |||
resultMap.put("return_msg", "OK"); | |||
return new RefundNotifyAdapterResult(transactionId, refundId,refundOrder,XmlUtil.getRequestXml(resultMap)); | |||
} | |||
@Override | |||
public RefundNotifyAdapterResult notify(Map<String, String> paramMap, EnumPayWay payWay) { | |||
log.info("TtRefundAdapterService notify{}"+paramMap); | |||
String tenantId = paramMap.get("tenantId"); | |||
/** | |||
* | |||
*/ | |||
String refundno = paramMap.get("cp_refundno"); | |||
Long refundOrderId = Long.valueOf(refundno); | |||
WxRefundOrder refundOrder = wxRefundOrderMapper.selectById(refundOrderId); | |||
String appId = paramMap.get("appid"); | |||
WxAppinfo appinfo = wxAppinfoService.getByAppIdFromRedis(appId,tenantId); | |||
if (appinfo == null) { | |||
log.error("未找到appid信息:" + appId); | |||
throw new MallinkException(ErrorCode.APP_ID_NOT_FOUND); | |||
} | |||
WxPayAccount payAccount = wxPayAccountService.getByIdFromRedis(appinfo.getPayId()); | |||
if (payAccount == null) { | |||
log.error("未找到mch_id信息:" + appId); | |||
throw new MallinkException(ErrorCode.MCH_INFO_NOT_FOUND); | |||
} | |||
if (!"SUCCESS".equals(paramMap.get("status"))) { | |||
log.error("notify refund, wxpay status not success, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); | |||
return notifyErrorResult("订单状态码非SUCCESS"); | |||
} | |||
// 验证退款金额 | |||
if (!paramMap.get("refund_amount").equals(refundOrder.getRefundFee().toString())) { | |||
log.error("notify refund, wxpay check refund_fee is invalid, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); | |||
return notifyErrorResult("退款总金额不一致"); | |||
} | |||
log.info("notify refund, wxpay checksign success, paramMap:{}, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); | |||
return notifySuccessResult(refundOrder.getPayOrderNo(), paramMap.get("cp_refundno"), refundOrder); | |||
} | |||
} |
@@ -16,6 +16,7 @@ import com.iformall.douyin.payv2.result.TtPayRefundQueryV2Result; | |||
import com.iformall.douyin.payv2.result.TtPayRefundV2Result; | |||
import com.iformall.enums.EnumPayType; | |||
import com.iformall.enums.EnumPayWay; | |||
import com.iformall.enums.EnumRefundOrderStatus; | |||
import com.iformall.enums.EnumRefundStatus; | |||
import com.iformall.exception.MallinkException; | |||
import com.iformall.mapper.WxPayAccountMapper; | |||
@@ -121,7 +122,33 @@ public class TtRefundAdapterService implements RefundPayAdapterService{ | |||
// } | |||
} | |||
@Override | |||
@Override | |||
public RefundAdapterResult refund(WxAppinfo appInfo, WxPayAccount payAccount, ProductOrderRefund orderRefund) { | |||
CreateRefund createRefund = new CreateRefund(); | |||
createRefund.setAppId(appInfo.getAppId()); | |||
createRefund.setSalt(payAccount.getApiKey()); | |||
createRefund.setOutOrderNo(orderRefund.getOrderNumber()); | |||
createRefund.setOutRefundNo(orderRefund.getId().toString()); | |||
createRefund.setReason(orderRefund.getRefundReason()); | |||
createRefund.setRefundAmount(orderRefund.getRefundAmount()); | |||
CreateRefundResult refund = DouYinPayHelper.createRefund(createRefund); | |||
if(refund.isSuccess()){ | |||
RefundAdapterResult refundAdapterResult = new RefundAdapterResult(); | |||
refundAdapterResult.setSuccess(true); | |||
refundAdapterResult.setCode(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode()); | |||
refundAdapterResult.setRefundId(refund.getRefundNo()); | |||
refundAdapterResult.setData(refund); | |||
return refundAdapterResult; | |||
}else{ | |||
return new RefundAdapterResult(false,EnumRefundStatus.REFUND_REQ_FAIL.getCode(),refund.getMsg(),refund); | |||
} | |||
} | |||
@Override | |||
public RefundAdapterResult queryRefund(WxAppinfo appInfo,WxPayAccount payAccount, WxRefundOrder record) { | |||
try { | |||
TtPayService ttPayService = maUtil.getTtPayService(appInfo, payAccount); | |||
@@ -146,20 +173,23 @@ public class TtRefundAdapterService implements RefundPayAdapterService{ | |||
throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(),"查询状态异常"); | |||
} | |||
// QueryRefundResult queryRefundResult = DouYinPayHelper.refundQuery(appInfo.getAppId(), payAccount.getApiKey(), String.valueOf(record.getId()), null); | |||
// if(queryRefundResult != null){ | |||
// if("SUCCESS".equals(queryRefundResult.getRefundStatus())){ | |||
// return new RefundAdapterResult(true,0,"退款",queryRefundResult); | |||
// }else{ | |||
// return new RefundAdapterResult(false,ErrorCode.REFUND_ORDER_ERROR.getCode(),"退款失败",queryRefundResult); | |||
// } | |||
// }else{ | |||
// throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR); | |||
// } | |||
} | |||
@Autowired | |||
@Override | |||
public RefundAdapterResult queryRefund(WxAppinfo appInfo, WxPayAccount payAccount, ProductOrderRefund orderRefund) { | |||
QueryRefundResult queryRefundResult = DouYinPayHelper.refundQuery(appInfo.getAppId(), payAccount.getApiKey(), String.valueOf(orderRefund.getId()), null); | |||
if(queryRefundResult != null){ | |||
if("SUCCESS".equals(queryRefundResult.getRefundStatus())){ | |||
return new RefundAdapterResult(true, EnumRefundOrderStatus.REFUND_SUCCESS.getCode(),"退款成功",queryRefundResult); | |||
}else{ | |||
return new RefundAdapterResult(false,EnumRefundOrderStatus.REFUND_FAIL.getCode(),"退款失败",queryRefundResult); | |||
} | |||
}else{ | |||
throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR); | |||
} | |||
} | |||
@Autowired | |||
WxAppinfoService wxAppinfoService; | |||
@Autowired | |||
WxPayAccountService wxPayAccountService; | |||
@@ -8,6 +8,7 @@ public class RefundAdapterResult implements Serializable{ | |||
private Integer code; | |||
private String msg; | |||
private Object data; | |||
private String refundId; | |||
public RefundAdapterResult() { | |||
@@ -48,4 +49,11 @@ public class RefundAdapterResult implements Serializable{ | |||
this.code = code; | |||
} | |||
public String getRefundId() { | |||
return refundId; | |||
} | |||
public void setRefundId(String refundId) { | |||
this.refundId = refundId; | |||
} | |||
} |
@@ -5,6 +5,7 @@ import java.util.Map; | |||
import java.util.SortedMap; | |||
import java.util.TreeMap; | |||
import com.iformall.domain.po.*; | |||
import org.apache.commons.lang3.StringUtils; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
import org.springframework.stereotype.Service; | |||
@@ -14,10 +15,6 @@ import com.alibaba.fastjson.JSONObject; | |||
import com.iformall.common.ErrorCode; | |||
import com.iformall.common.Result; | |||
import com.iformall.common.ResultData; | |||
import com.iformall.domain.po.WxAppinfo; | |||
import com.iformall.domain.po.WxPayAccount; | |||
import com.iformall.domain.po.WxPayOrder; | |||
import com.iformall.domain.po.WxRefundOrder; | |||
import com.iformall.enums.EnumPayMode; | |||
import com.iformall.enums.EnumPayType; | |||
import com.iformall.enums.EnumPayWay; | |||
@@ -408,7 +405,12 @@ public class WxRefundAdapterService implements RefundPayAdapterService{ | |||
} | |||
} | |||
@Override | |||
@Override | |||
public RefundAdapterResult refund(WxAppinfo appInfo, WxPayAccount payAccount, ProductOrderRefund orderRefund) { | |||
return null; | |||
} | |||
@Override | |||
public RefundAdapterResult queryRefund(WxAppinfo appInfo,WxPayAccount payAccount, WxRefundOrder record) { | |||
if (payAccount.getType() == EnumPayMode.MCH.getCode()) { | |||
Map<String, String> paramMap = WxPayment.buildWeappRefundQueryMap( | |||
@@ -503,7 +505,12 @@ public class WxRefundAdapterService implements RefundPayAdapterService{ | |||
} | |||
} | |||
@Autowired | |||
@Override | |||
public RefundAdapterResult queryRefund(WxAppinfo appInfo, WxPayAccount payAccount, ProductOrderRefund orderRefund) { | |||
return null; | |||
} | |||
@Autowired | |||
WxAppinfoMapper wxAppinfoMapper; | |||
@Autowired | |||
WxPayAccountMapper wxPayAccountMapper; | |||
@@ -7,6 +7,8 @@ import java.util.Map; | |||
import java.util.SortedMap; | |||
import java.util.TreeMap; | |||
import com.iformall.domain.po.*; | |||
import com.iformall.enums.*; | |||
import org.apache.commons.lang3.StringUtils; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
import org.springframework.context.annotation.Lazy; | |||
@@ -19,16 +21,6 @@ import com.github.binarywang.wxpay.service.WxPayService; | |||
import com.iformall.common.ErrorCode; | |||
import com.iformall.common.Result; | |||
import com.iformall.common.ResultData; | |||
import com.iformall.domain.po.WxAppinfo; | |||
import com.iformall.domain.po.WxOrder; | |||
import com.iformall.domain.po.WxPayAccount; | |||
import com.iformall.domain.po.WxPayOrder; | |||
import com.iformall.domain.po.WxRefundOrder; | |||
import com.iformall.enums.EnumPayMchType; | |||
import com.iformall.enums.EnumPayMode; | |||
import com.iformall.enums.EnumPayType; | |||
import com.iformall.enums.EnumPayWay; | |||
import com.iformall.enums.EnumRefundStatus; | |||
import com.iformall.exception.MallinkException; | |||
import com.iformall.mapper.WxAppinfoMapper; | |||
import com.iformall.mapper.WxPayAccountMapper; | |||
@@ -59,10 +51,6 @@ import lombok.extern.slf4j.Slf4j; | |||
@Slf4j | |||
@Service | |||
public class WxRefundV3AdapterService implements RefundPayAdapterService{ | |||
@Autowired | |||
MaUtil maUtil; | |||
@Lazy | |||
@Autowired | |||
@@ -71,6 +59,10 @@ public class WxRefundV3AdapterService implements RefundPayAdapterService{ | |||
@Lazy | |||
@Autowired | |||
WxPayAccountService wxPayAccountService; | |||
@Autowired | |||
MaUtil maUtil; | |||
private V3PayRefundReq getReq(WxPayAccount payAccount,WxAppinfo appInfo,WxRefundOrder record,WxPayOrder payOrder,Long orderId,EnumPayType payType) { | |||
V3PayRefundReq req = new V3PayRefundReq(); | |||
@@ -160,6 +152,42 @@ public class WxRefundV3AdapterService implements RefundPayAdapterService{ | |||
return getResultFromSp(response, record, payOrder); | |||
} | |||
@Override | |||
public RefundAdapterResult refund(WxAppinfo appInfo, WxPayAccount payAccount, ProductOrderRefund orderRefund) { | |||
WxPayService payService = maUtil.getWxPayServiceBySelfModel(appInfo, payAccount); | |||
V3PayRefundReq req = new V3PayRefundReq(); | |||
req.setOut_trade_no(orderRefund.getOrderNumber()); | |||
req.setOut_refund_no(orderRefund.getId().toString()); | |||
req.setReason(orderRefund.getFailReason()); | |||
V3PayRefundAmountReq amount = new V3PayRefundAmountReq(); | |||
amount.setRefund(orderRefund.getRefundAmount()); | |||
amount.setTotal(orderRefund.getPayAmount()); | |||
req.setAmount(amount); | |||
String response = null; | |||
try { | |||
try { | |||
response = WxPayV3.payCommonRefund(payService, req); | |||
}catch(WxPayException e) { | |||
log.error("weixin pay v3 refund error. " ,e); | |||
throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), e.getCustomErrorMsg()); | |||
} | |||
} catch (Exception e) { | |||
log.error("退款异常: " + e.getMessage()); | |||
throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), "退款异常"); | |||
} | |||
JSONObject resp = JSON.parseObject(response); | |||
RefundAdapterResult result = new RefundAdapterResult(); | |||
result.setSuccess(true); | |||
result.setCode(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode()); | |||
result.setRefundId(resp.getString("refund_id")); | |||
result.setData(resp); | |||
return result; | |||
} | |||
@Override | |||
public RefundAdapterResult queryRefund(WxAppinfo appInfo,WxPayAccount payAccount, WxRefundOrder record) { | |||
// 服务商模式 | |||
@@ -192,6 +220,37 @@ public class WxRefundV3AdapterService implements RefundPayAdapterService{ | |||
} | |||
} | |||
@Override | |||
public RefundAdapterResult queryRefund(WxAppinfo appInfo, WxPayAccount payAccount, ProductOrderRefund orderRefund) { | |||
WxPayService payService = maUtil.getWxPayServiceBySelfModel(appInfo, payAccount); | |||
String response = null; | |||
try { | |||
try { | |||
response = WxPayV3.payCommonRefundQuery(payService, String.valueOf(orderRefund.getId())); | |||
}catch(WxPayException e) { | |||
log.error("weixin pay v3 query refund error " ,e); | |||
throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), e.getCustomErrorMsg()); | |||
} | |||
JSONObject result = JSON.parseObject(response); | |||
String refund_status_0 = result.getString("status"); | |||
if("SUCCESS".equals(refund_status_0)){ | |||
return new RefundAdapterResult(true, EnumRefundOrderStatus.REFUND_SUCCESS.getCode(),"退款成功",result); | |||
}else if("CLOSED".equals(refund_status_0)){ | |||
return new RefundAdapterResult(false,EnumRefundOrderStatus.REFUND_FAIL.getCode(),"退款关闭,指商户发起退款失败的情况",result); | |||
}else if("PROCESSING".equals(refund_status_0)){ | |||
return new RefundAdapterResult(false,EnumRefundOrderStatus.REFUND_REQ_SUCCESS.getCode(),"退款中",result); | |||
}else if("ABNORMAL".equals(refund_status_0)){ | |||
return new RefundAdapterResult(false,EnumRefundOrderStatus.REFUND_FAIL.getCode(), | |||
"退款异常,退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败。",result); | |||
}else{ | |||
throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(),"查询状态异常 非法状态"); | |||
} | |||
} catch (Exception e) { | |||
log.error("退款异常: " + e.getMessage()); | |||
throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), "退款异常"); | |||
} | |||
} | |||
@Autowired | |||
WxAppinfoMapper wxAppinfoMapper; | |||
@Autowired | |||
@@ -89,7 +89,7 @@ | |||
</if> | |||
<if test=" null != statusS "> | |||
and `order_status` in | |||
and `pay_order_status` in | |||
<foreach collection="statusS" index="index" item="sItem" open="(" separator="," close=")"> | |||
#{sItem} | |||
</foreach> | |||
@@ -0,0 +1,146 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | |||
<mapper namespace="com.iformall.mapper.ProductOrderRefundMapper"> | |||
<resultMap id="BaseResultMap" type="com.iformall.domain.po.ProductOrderRefund"> | |||
<id column="id" jdbcType="BIGINT" property="id"/> | |||
<result column="tenant_id" jdbcType="VARCHAR" property="tenantId"/> | |||
<result column="parent_tenant_id" jdbcType="VARCHAR" property="parentTenantId" /> | |||
<result column="order_id" jdbcType="BIGINT" property="orderId"/> | |||
<result column="order_number" jdbcType="VARCHAR" property="orderNumber"/> | |||
<result column="project_type" jdbcType="TINYINT" property="projectType"/> | |||
<result column="pay_vendor" jdbcType="TINYINT" property="payVendor" /> | |||
<result column="user_id" jdbcType="BIGINT" property="userId"/> | |||
<result column="pay_id" jdbcType="BIGINT" property="payId"/> | |||
<result column="transaction_id" jdbcType="VARCHAR" property="transactionId"/> | |||
<result column="pay_amount" jdbcType="INTEGER" property="payAmount"/> | |||
<result column="refund_amount" jdbcType="INTEGER" property="refundAmount"/> | |||
<result column="refund_order_status" jdbcType="INTEGER" property="refundOrderStatus"/> | |||
<result column="fail_reason" jdbcType="VARCHAR" property="failReason"/> | |||
<result column="refund_id" jdbcType="VARCHAR" property="refundId"/> | |||
<result column="refund_reason" jdbcType="VARCHAR" property="refundReason"/> | |||
<result column="refund_description" jdbcType="VARCHAR" property="refundDescription"/> | |||
<result column="create_date" jdbcType="TIMESTAMP" property="createDate"/> | |||
<result column="update_date" jdbcType="TIMESTAMP" property="updateDate"/> | |||
</resultMap> | |||
<sql id="allColumns"> | |||
`id`,`tenant_id`,`parent_tenant_id`,`order_id`,`order_number`,`project_type`,`pay_vendor`, | |||
`user_id`,`pay_id`,`transaction_id`,`pay_amount`, | |||
`refund_amount`,`refund_order_status`,`fail_reason`,`refund_id`,`refund_reason`,`refund_description` | |||
`create_date`,`update_date` | |||
</sql> | |||
<sql id="dynamicWhereConditions"> | |||
where 1 = 1 | |||
<if test=" null != id "> | |||
and `id` = #{id} | |||
</if> | |||
<if test=" null != tenantId and '' != tenantId"> | |||
and `tenant_id` = #{tenantId} | |||
</if> | |||
<if test=" null != parentTenantId and '' != parentTenantId"> | |||
and `parent_tenant_id` = #{parentTenantId} | |||
</if> | |||
<if test=" null != orderId "> | |||
and `order_id` = #{orderId} | |||
</if> | |||
<if test=" null != orderNumber "> | |||
and `order_number` = #{orderNumber} | |||
</if> | |||
<if test=" null != projectType "> and `project_type` = #{projectType} </if> | |||
<if test=" null != payVendor "> and `pay_vendor` = #{payVendor} </if> | |||
<if test=" null != userId "> | |||
and `user_id` = #{userId} | |||
</if> | |||
<if test=" null != payId "> | |||
and `pay_id` = #{payId} | |||
</if> | |||
<if test=" null != transactionId "> | |||
and `transaction_id` = #{transactionId} | |||
</if> | |||
<if test=" null != refundOrderStatus "> | |||
and `refund_order_status` = #{refundOrderStatus} | |||
</if> | |||
<if test=" null != startDate "> | |||
and `create_date` >= #{startDate} | |||
</if> | |||
<if test=" null != endDate"> | |||
and `create_date` <= #{endDate} | |||
</if> | |||
<if test=" null != statusS "> | |||
and `refund_order_status` in | |||
<foreach collection="statusS" index="index" item="sItem" open="(" separator="," close=")"> | |||
#{sItem} | |||
</foreach> | |||
</if> | |||
<if test=" null != ids "> | |||
and id in | |||
<foreach collection="ids" index="index" item="idItem" open="(" separator="," close=")"> | |||
#{idItem} | |||
</foreach> | |||
</if> | |||
<if test=" null != sortColumns">order by ${sortColumns}</if> | |||
</sql> | |||
<select id="findList" parameterType="com.iformall.domain.po.ProductOrderPay" resultMap="BaseResultMap"> | |||
select | |||
<include refid="allColumns"/> | |||
from product_order_pay | |||
<include refid="dynamicWhereConditions"/> | |||
</select> | |||
<update id="orderPayUpdStatus" parameterType="com.iformall.domain.po.ProductOrderPay"> | |||
update product_order_pay | |||
set `pay_order_status` = #{payOrderStatus} | |||
,`update_date` = #{updateDate} | |||
<if test=" null != openId"> | |||
,`open_id` = #{openId} | |||
</if> | |||
<if test=" null != transactionId"> | |||
,`transaction_id` = #{transactionId} | |||
</if> | |||
<if test=" null != payTime"> | |||
,`pay_time` = #{payTime} | |||
</if> | |||
<if test=" null != payWay"> | |||
,`pay_way` = #{payWay} | |||
</if> | |||
where id = #{id} | |||
and `pay_order_status` != #{payOrderStatus} | |||
<if test=" null != isOrderStatus"> | |||
and `pay_order_status` = #{isOrderStatus} | |||
</if> | |||
</update> | |||
<select id="selectByOrder" parameterType="java.util.HashMap" resultMap="BaseResultMap"> | |||
select | |||
<include refid="allColumns"/> | |||
from product_order_pay | |||
where `order_id` = #{orderId} | |||
and `pay_vendor` = #{payVendor} | |||
</select> | |||
<update id="orderPayUpdStatus" parameterType="java.util.HashMap"> | |||
update product_order_pay | |||
set `pay_order_status` = #{payOrderStatus} | |||
,`update_date` = now() | |||
where `order_id` = #{orderId} | |||
</update> | |||
</mapper> |