32 changed files with 1279 additions and 337 deletions
@ -0,0 +1,30 @@ |
|||||
|
package com.bnyer.pay.bo; |
||||
|
|
||||
|
import lombok.Getter; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
import lombok.Setter; |
||||
|
|
||||
|
/** |
||||
|
* @author :WXC |
||||
|
* @Date :2023/05/05 |
||||
|
* @description : |
||||
|
*/ |
||||
|
@Getter |
||||
|
@Setter |
||||
|
@NoArgsConstructor |
||||
|
public class QueryOrderBo { |
||||
|
|
||||
|
/** |
||||
|
* 支付类型:wxpay/alipay/kspay/dypay |
||||
|
*/ |
||||
|
private String payType; |
||||
|
/** |
||||
|
* 交易类型 1--JSAPI支付(小程序appId支付)、2--Native支付、3--app支付,4--JSAPI支付(公众号appId支付)5--H5支付,微信支付必填 |
||||
|
*/ |
||||
|
private String tradeType; |
||||
|
/** |
||||
|
* 支付单号 |
||||
|
*/ |
||||
|
private String payId; |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,49 @@ |
|||||
|
package com.bnyer.pay.controller; |
||||
|
|
||||
|
import com.bnyer.common.core.domain.R; |
||||
|
import com.bnyer.pay.dto.InOrderDto; |
||||
|
import com.bnyer.pay.dto.QueryOrderDto; |
||||
|
import com.bnyer.pay.service.UnifiedPayService; |
||||
|
import com.bnyer.pay.vo.QueryOrderVo; |
||||
|
import com.bnyer.pay.vo.ThirdInOrderVo; |
||||
|
import io.swagger.annotations.Api; |
||||
|
import io.swagger.v3.oas.annotations.Operation; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.web.bind.annotation.PostMapping; |
||||
|
import org.springframework.web.bind.annotation.RequestBody; |
||||
|
import org.springframework.web.bind.annotation.RequestMapping; |
||||
|
import org.springframework.web.bind.annotation.RestController; |
||||
|
|
||||
|
import javax.servlet.http.HttpServletRequest; |
||||
|
import javax.validation.Valid; |
||||
|
|
||||
|
/** |
||||
|
* @author :WXC |
||||
|
* @Date :2023/05/05 |
||||
|
* @description : |
||||
|
*/ |
||||
|
@Api(value = "统一支付相关接口",tags = "统一支付相关接口") |
||||
|
@RestController |
||||
|
@RequestMapping("/unified") |
||||
|
@Slf4j |
||||
|
public class UnifiedPayController { |
||||
|
|
||||
|
@Autowired |
||||
|
private UnifiedPayService unifiedPayService; |
||||
|
|
||||
|
@PostMapping("/inOrder") |
||||
|
@Operation(summary = "统一下单,并生成支付订单" , description = "生成支付订单,返回前端支付所需参数") |
||||
|
public R<ThirdInOrderVo> inOrder(@Valid @RequestBody InOrderDto dto, HttpServletRequest request){ |
||||
|
ThirdInOrderVo thirdInOrderVo = unifiedPayService.inOrder(dto,request); |
||||
|
return R.ok(thirdInOrderVo); |
||||
|
} |
||||
|
|
||||
|
@PostMapping("/queryOrder") |
||||
|
@Operation(summary = "统一订单查询" , description = "订单查询,查询支付结果") |
||||
|
public R<QueryOrderVo> queryOrder(@Valid @RequestBody QueryOrderDto dto){ |
||||
|
QueryOrderVo queryOrderVo = unifiedPayService.queryOrder(dto); |
||||
|
return R.ok(queryOrderVo); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -1,39 +1,87 @@ |
|||||
package com.bnyer.pay.dto; |
package com.bnyer.pay.dto; |
||||
|
|
||||
import com.bnyer.common.core.annotation.CustomParamsValidation; |
import com.baomidou.mybatisplus.annotation.TableField; |
||||
import io.swagger.annotations.ApiModelProperty; |
import io.swagger.annotations.ApiModelProperty; |
||||
|
import lombok.AllArgsConstructor; |
||||
import lombok.Getter; |
import lombok.Getter; |
||||
import lombok.NoArgsConstructor; |
import lombok.NoArgsConstructor; |
||||
import lombok.Setter; |
import lombok.Setter; |
||||
|
|
||||
import javax.validation.constraints.NotBlank; |
import java.math.BigDecimal; |
||||
|
import java.util.Date; |
||||
|
|
||||
/** |
/** |
||||
* @author :WXC |
* @author :WXC |
||||
* @Date :2023/04/03 |
* @Date :2023/05/05 |
||||
* @description : |
* @description : |
||||
*/ |
*/ |
||||
@Getter |
@Getter |
||||
@Setter |
@Setter |
||||
@NoArgsConstructor |
@NoArgsConstructor |
||||
|
@AllArgsConstructor |
||||
public class AddPayInfoDto { |
public class AddPayInfoDto { |
||||
|
|
||||
@NotBlank(message = "业务主订单号不能为空") |
@ApiModelProperty(value="支付单号(内部生成)") |
||||
@ApiModelProperty(value="业务主订单号:关联内部业务订单表",required = true) |
private String payId; |
||||
|
|
||||
|
@ApiModelProperty(value="业务主订单号:关联内部业务订单表") |
||||
private String orderNo; |
private String orderNo; |
||||
|
|
||||
@NotBlank(message = "支付场景不能为空") |
@ApiModelProperty(value="支付状态:1000未支付;1001支付成功 ;1002支付失败") |
||||
@ApiModelProperty(value="支付场景:1.会员充值",required = true) |
private Integer payStatus; |
||||
private Integer sceneCode; |
|
||||
|
@ApiModelProperty(value="单笔对账状态:1001 对账成功") |
||||
|
private Integer singleStatus; |
||||
|
|
||||
@NotBlank(message = "支付类型不能为空") |
@ApiModelProperty(value="单笔对账时间") |
||||
@ApiModelProperty(value="支付类型:wxpay/alipay",required = true) |
private Date singleTime; |
||||
|
|
||||
|
@ApiModelProperty(value="支付类型:wxpay/alipay/kspay/dypay") |
||||
private String payType; |
private String payType; |
||||
|
|
||||
@ApiModelProperty(value="交易类型 1--JSAPI支付(小程序appId支付)、2--Native支付、3--app支付,4--JSAPI支付(公众号appId支付)5--H5支付,微信支付必填",example = "1") |
@ApiModelProperty(value="支付渠道:wxpay/alipay") |
||||
@CustomParamsValidation(range = "1",message = "交易类型暂时只支持JSAPI") |
private String payChannel; |
||||
|
|
||||
|
@ApiModelProperty(value = "交易类型:JSAPI等") |
||||
private String tradeType; |
private String tradeType; |
||||
|
|
||||
|
@ApiModelProperty(value="支付单号(第三方返回)") |
||||
|
private String payNo; |
||||
|
|
||||
|
@ApiModelProperty(value="用户侧订单号(第三方返回)") |
||||
|
private String tradeNo; |
||||
|
|
||||
|
@ApiModelProperty(value="appid") |
||||
|
private String appid; |
||||
|
|
||||
|
@ApiModelProperty(value="商品标题") |
||||
|
private String goodsSubject; |
||||
|
|
||||
|
@ApiModelProperty(value="商品描述") |
||||
|
private String goodsDesc; |
||||
|
|
||||
|
@ApiModelProperty(value="支付金额,单位元") |
||||
|
private BigDecimal payAmount; |
||||
|
|
||||
|
@ApiModelProperty(value="支付时间") |
||||
|
private Date payTime; |
||||
|
|
||||
|
@ApiModelProperty(value="支付场景:1.会员充值") |
||||
|
private Integer sceneCode; |
||||
|
|
||||
|
@ApiModelProperty(value="用户ip") |
||||
|
private String ip; |
||||
|
|
||||
|
@ApiModelProperty(value="调用第三方下单返回") |
||||
|
private String thirdCode; |
||||
|
|
||||
|
@ApiModelProperty(value="调用第三方下单返回") |
||||
|
private String thirdMsg; |
||||
|
|
||||
|
@ApiModelProperty(value="调用第三方下单返回") |
||||
|
private String thirdNo; |
||||
|
|
||||
@ApiModelProperty(value="备注") |
@ApiModelProperty(value="备注") |
||||
private String remark; |
private String remark; |
||||
|
|
||||
} |
} |
||||
|
|||||
@ -0,0 +1,39 @@ |
|||||
|
package com.bnyer.pay.dto; |
||||
|
|
||||
|
import com.bnyer.common.core.annotation.CustomParamsValidation; |
||||
|
import io.swagger.annotations.ApiModelProperty; |
||||
|
import lombok.Getter; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
import lombok.Setter; |
||||
|
|
||||
|
import javax.validation.constraints.NotBlank; |
||||
|
|
||||
|
/** |
||||
|
* @author :WXC |
||||
|
* @Date :2023/04/03 |
||||
|
* @description : |
||||
|
*/ |
||||
|
@Getter |
||||
|
@Setter |
||||
|
@NoArgsConstructor |
||||
|
public class InOrderDto { |
||||
|
|
||||
|
@NotBlank(message = "业务主订单号不能为空") |
||||
|
@ApiModelProperty(value="业务主订单号:关联内部业务订单表",required = true) |
||||
|
private String orderNo; |
||||
|
|
||||
|
@NotBlank(message = "支付场景不能为空") |
||||
|
@ApiModelProperty(value="支付场景:1.会员充值",required = true) |
||||
|
private Integer sceneCode; |
||||
|
|
||||
|
@NotBlank(message = "支付类型不能为空") |
||||
|
@ApiModelProperty(value="支付类型:wxpay/alipay",required = true) |
||||
|
private String payType; |
||||
|
|
||||
|
@ApiModelProperty(value="交易类型 1--JSAPI支付(小程序appId支付)、2--Native支付、3--app支付,4--JSAPI支付(公众号appId支付)5--H5支付,微信支付必填",example = "1") |
||||
|
@CustomParamsValidation(range = "1",message = "交易类型暂时只支持JSAPI") |
||||
|
private String tradeType; |
||||
|
|
||||
|
@ApiModelProperty(value="备注") |
||||
|
private String remark; |
||||
|
} |
||||
@ -0,0 +1,33 @@ |
|||||
|
package com.bnyer.pay.dto; |
||||
|
|
||||
|
import com.bnyer.common.core.annotation.CustomParamsValidation; |
||||
|
import io.swagger.annotations.ApiModelProperty; |
||||
|
import lombok.Getter; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
import lombok.Setter; |
||||
|
|
||||
|
import javax.validation.constraints.NotBlank; |
||||
|
|
||||
|
/** |
||||
|
* @author :WXC |
||||
|
* @Date :2023/05/05 |
||||
|
* @description : |
||||
|
*/ |
||||
|
@Getter |
||||
|
@Setter |
||||
|
@NoArgsConstructor |
||||
|
public class QueryOrderDto { |
||||
|
|
||||
|
@NotBlank(message = "支付类型不能为空") |
||||
|
@ApiModelProperty(value="支付类型:wxpay/alipay/kspay/dypay",required = true) |
||||
|
private String payType; |
||||
|
|
||||
|
@ApiModelProperty(value="交易类型 1--JSAPI支付(小程序appId支付)、2--Native支付、3--app支付,4--JSAPI支付(公众号appId支付)5--H5支付,微信支付必填",example = "1") |
||||
|
@CustomParamsValidation(range = "1",message = "交易类型暂时只支持JSAPI") |
||||
|
private String tradeType; |
||||
|
|
||||
|
@NotBlank(message = "支付单号不能为空") |
||||
|
@ApiModelProperty(value="支付单号",required = true) |
||||
|
private String payId; |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
package com.bnyer.pay.enums; |
||||
|
|
||||
|
import com.bnyer.common.core.enums.EnumPayStatus; |
||||
|
import com.bnyer.common.core.exception.ServiceException; |
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Getter; |
||||
|
|
||||
|
import java.util.Objects; |
||||
|
|
||||
|
/** |
||||
|
* @author :WXC |
||||
|
* @Date :2023/05/05 |
||||
|
* @description : |
||||
|
*/ |
||||
|
@Getter |
||||
|
@AllArgsConstructor |
||||
|
public enum EnumDyPayStatus { |
||||
|
|
||||
|
PROCESSING("PROCESSING",EnumPayStatus.NO_PAY), |
||||
|
SUCCESS("SUCCESS",EnumPayStatus.SUCCESS), |
||||
|
FAIL("FAIL",EnumPayStatus.FAILS), |
||||
|
TIMEOUT("TIMEOUT",EnumPayStatus.FAILS), |
||||
|
; |
||||
|
private final String status; |
||||
|
|
||||
|
private final EnumPayStatus enumPayStatus; |
||||
|
|
||||
|
public static EnumPayStatus getEnumPayStatusByStatus(String status) { |
||||
|
for (EnumDyPayStatus s : EnumDyPayStatus.values()) { |
||||
|
if (Objects.equals(status, s.getStatus())) { |
||||
|
return s.getEnumPayStatus(); |
||||
|
} |
||||
|
} |
||||
|
throw new ServiceException("status 未匹配上对应的支付状态"); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
package com.bnyer.pay.enums; |
||||
|
|
||||
|
import com.bnyer.common.core.enums.EnumPayStatus; |
||||
|
import com.bnyer.common.core.exception.ServiceException; |
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Getter; |
||||
|
|
||||
|
import java.util.Objects; |
||||
|
|
||||
|
/** |
||||
|
* @author :WXC |
||||
|
* @Date :2023/05/05 |
||||
|
* @description : |
||||
|
*/ |
||||
|
@Getter |
||||
|
@AllArgsConstructor |
||||
|
public enum EnumKsPayStatus { |
||||
|
|
||||
|
PROCESSING("PROCESSING",EnumPayStatus.NO_PAY), |
||||
|
SUCCESS("SUCCESS",EnumPayStatus.SUCCESS), |
||||
|
FAILED("FAILED",EnumPayStatus.FAILS), |
||||
|
TIMEOUT("TIMEOUT",EnumPayStatus.FAILS), |
||||
|
; |
||||
|
private final String status; |
||||
|
|
||||
|
private final EnumPayStatus enumPayStatus; |
||||
|
|
||||
|
public static EnumPayStatus getEnumPayStatusByStatus(String status) { |
||||
|
for (EnumKsPayStatus s : EnumKsPayStatus.values()) { |
||||
|
if (Objects.equals(status, s.getStatus())) { |
||||
|
return s.getEnumPayStatus(); |
||||
|
} |
||||
|
} |
||||
|
throw new ServiceException("status 未匹配上对应的支付状态"); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
package com.bnyer.pay.enums; |
||||
|
|
||||
|
import com.bnyer.common.core.enums.EnumPayStatus; |
||||
|
import com.bnyer.common.core.exception.ServiceException; |
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Getter; |
||||
|
|
||||
|
import java.util.Objects; |
||||
|
|
||||
|
/** |
||||
|
* @author :WXC |
||||
|
* @Date :2023/05/05 |
||||
|
* @description : |
||||
|
*/ |
||||
|
@Getter |
||||
|
@AllArgsConstructor |
||||
|
public enum EnumWxPayStatus { |
||||
|
|
||||
|
NOT_PAY("NOTPAY",EnumPayStatus.NO_PAY), |
||||
|
USER_PAYING("USERPAYING",EnumPayStatus.NO_PAY), |
||||
|
SUCCESS("SUCCESS",EnumPayStatus.SUCCESS), |
||||
|
PAY_ERROR("PAYERROR",EnumPayStatus.FAILS), |
||||
|
; |
||||
|
private final String status; |
||||
|
|
||||
|
private final EnumPayStatus enumPayStatus; |
||||
|
|
||||
|
public static EnumPayStatus getEnumPayStatusByStatus(String status) { |
||||
|
for (EnumWxPayStatus s : EnumWxPayStatus.values()) { |
||||
|
if (Objects.equals(status, s.getStatus())) { |
||||
|
return s.getEnumPayStatus(); |
||||
|
} |
||||
|
} |
||||
|
throw new ServiceException("status 未匹配上对应的支付状态"); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,31 @@ |
|||||
|
package com.bnyer.pay.service; |
||||
|
|
||||
|
import com.bnyer.pay.dto.InOrderDto; |
||||
|
import com.bnyer.pay.dto.QueryOrderDto; |
||||
|
import com.bnyer.pay.vo.QueryOrderVo; |
||||
|
import com.bnyer.pay.vo.ThirdInOrderVo; |
||||
|
|
||||
|
import javax.servlet.http.HttpServletRequest; |
||||
|
|
||||
|
/** |
||||
|
* @author :WXC |
||||
|
* @Date :2023/05/05 |
||||
|
* @description : |
||||
|
*/ |
||||
|
public interface UnifiedPayService { |
||||
|
|
||||
|
/** |
||||
|
* 统一下单,并生成支付订单 |
||||
|
* @param dto |
||||
|
* @param request |
||||
|
* @return |
||||
|
*/ |
||||
|
ThirdInOrderVo inOrder(InOrderDto dto, HttpServletRequest request); |
||||
|
|
||||
|
/** |
||||
|
* 统一订单查询 |
||||
|
* @param dto |
||||
|
* @return |
||||
|
*/ |
||||
|
QueryOrderVo queryOrder(QueryOrderDto dto); |
||||
|
} |
||||
@ -0,0 +1,209 @@ |
|||||
|
package com.bnyer.pay.service.impl; |
||||
|
|
||||
|
import com.bnyer.common.core.domain.R; |
||||
|
import com.bnyer.common.core.enums.EnumPayStatus; |
||||
|
import com.bnyer.common.core.enums.EnumPayType; |
||||
|
import com.bnyer.common.core.enums.EnumSceneCode; |
||||
|
import com.bnyer.common.core.enums.EnumUserClientType; |
||||
|
import com.bnyer.common.core.exception.ServiceException; |
||||
|
import com.bnyer.common.core.utils.OrderUtil; |
||||
|
import com.bnyer.common.core.utils.bean.EntityConvertUtil; |
||||
|
import com.bnyer.common.core.utils.ip.IpUtils; |
||||
|
import com.bnyer.order.api.dto.QueryVipOrderDto; |
||||
|
import com.bnyer.order.api.remote.RemoteVipOrderService; |
||||
|
import com.bnyer.order.api.vo.VipOrderVo; |
||||
|
import com.bnyer.pay.bo.QueryOrderBo; |
||||
|
import com.bnyer.pay.bo.UnifiedOrderBo; |
||||
|
import com.bnyer.pay.constant.KSPayConstants; |
||||
|
import com.bnyer.pay.design.factory.PayFactory; |
||||
|
import com.bnyer.pay.design.strategy.IPayStrategy; |
||||
|
import com.bnyer.pay.dto.AddPayInfoDto; |
||||
|
import com.bnyer.pay.dto.InOrderDto; |
||||
|
import com.bnyer.pay.dto.QueryOrderDto; |
||||
|
import com.bnyer.pay.enums.EnumDyPayStatus; |
||||
|
import com.bnyer.pay.enums.EnumKsPayStatus; |
||||
|
import com.bnyer.pay.enums.EnumWxPayStatus; |
||||
|
import com.bnyer.pay.service.PayInfoService; |
||||
|
import com.bnyer.pay.service.UnifiedPayService; |
||||
|
import com.bnyer.pay.vo.QueryOrderVo; |
||||
|
import com.bnyer.pay.vo.ThirdInOrderVo; |
||||
|
import com.bnyer.pay.vo.PayInfoDetailsVo; |
||||
|
import com.bnyer.pay.vo.ThirdQueryOrderVo; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
import javax.servlet.http.HttpServletRequest; |
||||
|
import java.math.BigDecimal; |
||||
|
import java.util.Date; |
||||
|
import java.util.List; |
||||
|
import java.util.Objects; |
||||
|
|
||||
|
/** |
||||
|
* @author :WXC |
||||
|
* @Date :2023/05/05 |
||||
|
* @description : |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@Service |
||||
|
public class UnifiedPayServiceImpl implements UnifiedPayService { |
||||
|
|
||||
|
@Autowired |
||||
|
private PayInfoService payInfoService; |
||||
|
|
||||
|
@Autowired |
||||
|
private RemoteVipOrderService remoteVipOrderService; |
||||
|
|
||||
|
/** |
||||
|
* 统一下单,并生成支付订单 |
||||
|
* @param dto |
||||
|
* @param request |
||||
|
* @return |
||||
|
*/ |
||||
|
@Override |
||||
|
public ThirdInOrderVo inOrder(InOrderDto dto, HttpServletRequest request) { |
||||
|
//支付金额
|
||||
|
String payAmount = ""; |
||||
|
//商品类型:快手支付需要
|
||||
|
int goodsType; |
||||
|
//payId
|
||||
|
String payId; |
||||
|
EnumSceneCode enumSceneCode = EnumSceneCode.getSceneCodeByCode(dto.getSceneCode()); |
||||
|
switch (enumSceneCode){ |
||||
|
//会员充值场景
|
||||
|
case VIP_RECHARGE: |
||||
|
QueryVipOrderDto queryVipOrderDto = new QueryVipOrderDto(); |
||||
|
queryVipOrderDto.setOrderNo(dto.getOrderNo()); |
||||
|
//查询会员业务订单信息
|
||||
|
R<List<VipOrderVo>> vipOrderVoListR = remoteVipOrderService.getVipOrderList(queryVipOrderDto); |
||||
|
if (!vipOrderVoListR.isSuccess()){ |
||||
|
throw new ServiceException(vipOrderVoListR.getMsg()); |
||||
|
} |
||||
|
VipOrderVo vipOrderVo = vipOrderVoListR.getData().get(0); |
||||
|
payAmount = vipOrderVo.getPayAmount().toString(); |
||||
|
goodsType = KSPayConstants.GOODS_TYPE_VIP; |
||||
|
payId = OrderUtil.getOrderNo("RV",new Date(), EnumUserClientType.getCodeByType(vipOrderVo.getUserClientType()) |
||||
|
,String.valueOf(vipOrderVo.getUserId())); |
||||
|
break; |
||||
|
default: |
||||
|
throw new ServiceException("sceneCode未匹配上对应支付场景"); |
||||
|
} |
||||
|
//构建统一下单请求实体
|
||||
|
UnifiedOrderBo unifiedOrderBo = buildUnifiedOrderDto(dto, goodsType,payAmount,payId, request); |
||||
|
//下单,获取第三方返回信息
|
||||
|
IPayStrategy payStrategy = PayFactory.getInstance().getConcreteStrategy(dto.getPayType()); |
||||
|
if (Objects.isNull(payStrategy)){ |
||||
|
throw new ServiceException("暂不支持该支付方式"); |
||||
|
} |
||||
|
ThirdInOrderVo thirdInOrderVo = payStrategy.unifiedOrder(unifiedOrderBo); |
||||
|
//构建支付订单完成入库
|
||||
|
AddPayInfoDto addPayInfoDto = buildPayInfo(thirdInOrderVo, unifiedOrderBo,dto); |
||||
|
payInfoService.addPayInfo(addPayInfoDto); |
||||
|
return thirdInOrderVo; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 构建支付订单 |
||||
|
* |
||||
|
* @param thirdInOrderVo |
||||
|
* @param unifiedOrderBo |
||||
|
* @param dto |
||||
|
* @return |
||||
|
*/ |
||||
|
private AddPayInfoDto buildPayInfo(ThirdInOrderVo thirdInOrderVo, UnifiedOrderBo unifiedOrderBo, InOrderDto dto) { |
||||
|
AddPayInfoDto addPayInfoDto = new AddPayInfoDto(); |
||||
|
addPayInfoDto.setOrderNo(dto.getOrderNo()); |
||||
|
addPayInfoDto.setSceneCode(dto.getSceneCode()); |
||||
|
addPayInfoDto.setRemark(dto.getRemark()); |
||||
|
addPayInfoDto.setPayType(dto.getPayType()); |
||||
|
addPayInfoDto.setPayId(unifiedOrderBo.getPayId()); |
||||
|
addPayInfoDto.setPayAmount(new BigDecimal(unifiedOrderBo.getPayAmount())); |
||||
|
addPayInfoDto.setAppid(thirdInOrderVo.getAppid()); |
||||
|
addPayInfoDto.setGoodsSubject(unifiedOrderBo.getGoodsSubject()); |
||||
|
addPayInfoDto.setGoodsDesc(unifiedOrderBo.getGoodsDesc()); |
||||
|
addPayInfoDto.setThirdNo(thirdInOrderVo.getPrepayid()); |
||||
|
addPayInfoDto.setIp(unifiedOrderBo.getIp()); |
||||
|
return addPayInfoDto; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 构建统一下单请求实体 |
||||
|
* |
||||
|
* @param dto 入参 |
||||
|
* @param goodsType 商品类型 |
||||
|
* @param payAmount 不同支付场景下的支付金额 |
||||
|
* @param payId 内部系统支付单号 |
||||
|
* @param request 请求request用于获取ip地址 |
||||
|
* @return |
||||
|
*/ |
||||
|
private UnifiedOrderBo buildUnifiedOrderDto(InOrderDto dto, int goodsType, String payAmount, String payId, HttpServletRequest request) { |
||||
|
//当前时间
|
||||
|
Date currDate = new Date(); |
||||
|
//ip地址
|
||||
|
String ip = IpUtils.getIpAddr(request); |
||||
|
UnifiedOrderBo unifiedOrderBo = EntityConvertUtil.copy(dto, UnifiedOrderBo.class); |
||||
|
unifiedOrderBo.setPayId(payId); |
||||
|
unifiedOrderBo.setIp(ip); |
||||
|
unifiedOrderBo.setCurrDate(currDate); |
||||
|
unifiedOrderBo.setPayAmount(payAmount); |
||||
|
unifiedOrderBo.setGoodsType(goodsType); |
||||
|
return unifiedOrderBo; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 统一订单查询 |
||||
|
* @param dto |
||||
|
* @return |
||||
|
*/ |
||||
|
@Override |
||||
|
public QueryOrderVo queryOrder(QueryOrderDto dto) { |
||||
|
//先查询系统支付单是否已经完成支付,如果因为延迟导致没有及时同步,在调用第三方接口查询支付状态返回
|
||||
|
PayInfoDetailsVo payInfoDetailsVo = payInfoService.queryOrder(dto.getPayId()); |
||||
|
Integer payStatus = payInfoDetailsVo.getPayStatus(); |
||||
|
EnumPayStatus enumPayStatus = EnumPayStatus.getEnumPayStatusByStatus(payStatus); |
||||
|
if (EnumPayStatus.NO_PAY != enumPayStatus){ |
||||
|
QueryOrderVo queryOrderVo = new QueryOrderVo(); |
||||
|
queryOrderVo.setPayId(dto.getPayId()); |
||||
|
queryOrderVo.setPayStatus(enumPayStatus.getStatus()); |
||||
|
return queryOrderVo; |
||||
|
} |
||||
|
//获取第三方订单信息
|
||||
|
IPayStrategy strategy = PayFactory.getInstance().getConcreteStrategy(dto.getPayType()); |
||||
|
if (Objects.isNull(strategy)){ |
||||
|
throw new ServiceException("暂不支持该支付方式"); |
||||
|
} |
||||
|
//构建统一订单查询实体
|
||||
|
QueryOrderBo queryOrderBo = EntityConvertUtil.copy(dto, QueryOrderBo.class); |
||||
|
ThirdQueryOrderVo thirdQueryOrderVo = strategy.queryOrder(queryOrderBo); |
||||
|
QueryOrderVo queryOrderVo = new QueryOrderVo(); |
||||
|
queryOrderVo.setPayId(dto.getPayId()); |
||||
|
queryOrderVo.setPayStatus(getPayStatus(dto.getPayType(), thirdQueryOrderVo.getPayStatus())); |
||||
|
return queryOrderVo; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 通过第三方系统支付状态构建业务系统对应支付状态 |
||||
|
* @param payType |
||||
|
* @param thirdPayStatus |
||||
|
* @return |
||||
|
*/ |
||||
|
private Integer getPayStatus(String payType,String thirdPayStatus){ |
||||
|
EnumPayType enumPayType = EnumPayType.getEnumPayTypeByType(payType); |
||||
|
switch (enumPayType){ |
||||
|
case KS_PAY: |
||||
|
EnumPayStatus enumPayStatusKs = EnumKsPayStatus.getEnumPayStatusByStatus(thirdPayStatus); |
||||
|
return enumPayStatusKs.getStatus(); |
||||
|
case WX_PAY: |
||||
|
EnumPayStatus enumPayStatusWx = EnumWxPayStatus.getEnumPayStatusByStatus(thirdPayStatus); |
||||
|
return enumPayStatusWx.getStatus(); |
||||
|
case DY_PAY: |
||||
|
EnumPayStatus enumPayStatusDy = EnumDyPayStatus.getEnumPayStatusByStatus(thirdPayStatus); |
||||
|
return enumPayStatusDy.getStatus(); |
||||
|
case ALI_PAY: |
||||
|
|
||||
|
default: |
||||
|
throw new ServiceException("payType 参数参数传递错误"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,131 @@ |
|||||
|
package com.bnyer.pay.utils; |
||||
|
|
||||
|
|
||||
|
import org.apache.commons.lang3.StringUtils; |
||||
|
|
||||
|
import java.math.BigDecimal; |
||||
|
import java.text.DecimalFormat; |
||||
|
|
||||
|
public class MoneyUtil { |
||||
|
|
||||
|
/** |
||||
|
* 费用:元TO元 |
||||
|
* 四舍五入,保留2位小数 |
||||
|
* 正常情况用不到,但是如果传入的不合规范的超长小数点,则需要规范小数:例如12.26999999999998 |
||||
|
* @param yuan |
||||
|
* @return |
||||
|
*/ |
||||
|
public static String yuanToYuan(String yuan){ |
||||
|
return yuanToYuan(yuan,false); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 费用:元TO元 |
||||
|
* 四舍五入,保留2位小数 |
||||
|
* 正常情况用不到,但是如果传入的不合规范的超长小数点,则需要规范小数:例如12.26999999999998 |
||||
|
* @param yuan |
||||
|
* @param returnZeroFlag |
||||
|
* @return |
||||
|
*/ |
||||
|
public static String yuanToYuan(String yuan,boolean returnZeroFlag){ |
||||
|
String ret = "0"; |
||||
|
if(StringUtils.isNotBlank(yuan)){ |
||||
|
try{ |
||||
|
DecimalFormat df = new DecimalFormat("0.00"); |
||||
|
ret = df.format(Float.valueOf(yuan)); |
||||
|
}catch(Exception e){} |
||||
|
}else{ |
||||
|
if(returnZeroFlag) {//空的时候是否返回0
|
||||
|
return ret; |
||||
|
}else{ |
||||
|
return yuan; |
||||
|
} |
||||
|
} |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 费用:元TO分 |
||||
|
* @return |
||||
|
*/ |
||||
|
public static String yuanToFen(String yuan){ |
||||
|
return yuanToFen(yuan,false); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* |
||||
|
* @param yuan |
||||
|
* @param returnZeroFlag 入参空的是或否是否返回0 |
||||
|
* @return |
||||
|
*/ |
||||
|
public static String yuanToFen(String yuan,boolean returnZeroFlag){ |
||||
|
String ret = "0"; |
||||
|
if(StringUtils.isNotBlank(yuan)){ |
||||
|
try{ |
||||
|
|
||||
|
BigDecimal res = new BigDecimal(yuan).multiply(new BigDecimal(100)); |
||||
|
DecimalFormat df = new DecimalFormat("0"); |
||||
|
ret = df.format(res.doubleValue()); |
||||
|
}catch(Exception e){} |
||||
|
}else{ |
||||
|
if(returnZeroFlag) {//空的时候是否返回0
|
||||
|
return ret; |
||||
|
}else{ |
||||
|
return yuan; |
||||
|
} |
||||
|
} |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 费用:分TO元 |
||||
|
* 格式化0.00 表示:比如结果0.50 |
||||
|
* #.00表示:比如.50 |
||||
|
* @param fen |
||||
|
* @return |
||||
|
*/ |
||||
|
public static String fenToYuan(String fen){ |
||||
|
return fenToYuan(fen,false); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 费用:分TO元 |
||||
|
* 格式化0.00 表示:比如结果0.50 |
||||
|
* #.00表示:比如.50 |
||||
|
* @param fen |
||||
|
* @param returnZeroFlag |
||||
|
* @return |
||||
|
*/ |
||||
|
public static String fenToYuan(String fen,boolean returnZeroFlag){ |
||||
|
String ret = "0.00"; |
||||
|
if(StringUtils.isNotBlank(fen)){ |
||||
|
try{ |
||||
|
BigDecimal res = new BigDecimal(fen).divide(new BigDecimal(100)); |
||||
|
DecimalFormat df = new DecimalFormat("0.00"); |
||||
|
ret = df.format(res.doubleValue()); |
||||
|
|
||||
|
}catch(Exception e){} |
||||
|
}else{ |
||||
|
if(returnZeroFlag){//空的时候是否返回0
|
||||
|
return ret; |
||||
|
}else{ |
||||
|
return fen; |
||||
|
} |
||||
|
} |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
public static void main(String[] args) { |
||||
|
|
||||
|
String[] yuans = new String[]{ |
||||
|
"1.01","12.09","123.08","1234.11","12345.99","123456.11","1234567.98","12345678.02","123456789.01","1234567890.55","12345678901.99" |
||||
|
}; |
||||
|
for(String yuan : yuans){ |
||||
|
String fen = yuanToFen(yuan); |
||||
|
System.out.println(yuan+"元转分"+fen); |
||||
|
System.out.println(fen+"分转元"+fenToYuan(fen)); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
package com.bnyer.pay.vo; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Getter; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
import lombok.Setter; |
||||
|
|
||||
|
/** |
||||
|
* @author :WXC |
||||
|
* @Date :2023/05/05 |
||||
|
* @description : |
||||
|
*/ |
||||
|
@Getter |
||||
|
@Setter |
||||
|
@NoArgsConstructor |
||||
|
@AllArgsConstructor |
||||
|
public class PayInfoDetailsVo extends PayInfoVo { |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,86 @@ |
|||||
|
package com.bnyer.pay.vo; |
||||
|
|
||||
|
import io.swagger.annotations.ApiModelProperty; |
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Getter; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
import lombok.Setter; |
||||
|
|
||||
|
import java.math.BigDecimal; |
||||
|
import java.util.Date; |
||||
|
|
||||
|
/** |
||||
|
* @author :WXC |
||||
|
* @Date :2023/05/05 |
||||
|
* @description : |
||||
|
*/ |
||||
|
@Getter |
||||
|
@Setter |
||||
|
@NoArgsConstructor |
||||
|
@AllArgsConstructor |
||||
|
public class PayInfoVo { |
||||
|
|
||||
|
@ApiModelProperty(value="支付单号(内部生成)") |
||||
|
private String payId; |
||||
|
|
||||
|
@ApiModelProperty(value="业务主订单号:关联内部业务订单表") |
||||
|
private String orderNo; |
||||
|
|
||||
|
@ApiModelProperty(value="支付状态:1000未支付;1001支付成功 ;1002支付失败") |
||||
|
private Integer payStatus; |
||||
|
|
||||
|
@ApiModelProperty(value="单笔对账状态:1001 对账成功") |
||||
|
private Integer singleStatus; |
||||
|
|
||||
|
@ApiModelProperty(value="单笔对账时间") |
||||
|
private Date singleTime; |
||||
|
|
||||
|
@ApiModelProperty(value="支付类型:wxpay/alipay/kspay/dypay") |
||||
|
private String payType; |
||||
|
|
||||
|
@ApiModelProperty(value="支付渠道:wxpay/alipay") |
||||
|
private String payChannel; |
||||
|
|
||||
|
@ApiModelProperty(value = "交易类型:JSAPI等") |
||||
|
private String tradeType; |
||||
|
|
||||
|
@ApiModelProperty(value="支付单号(第三方返回)") |
||||
|
private String payNo; |
||||
|
|
||||
|
@ApiModelProperty(value="用户侧订单号(第三方返回)") |
||||
|
private String tradeNo; |
||||
|
|
||||
|
@ApiModelProperty(value="appid") |
||||
|
private String appid; |
||||
|
|
||||
|
@ApiModelProperty(value="商品标题") |
||||
|
private String goodsSubject; |
||||
|
|
||||
|
@ApiModelProperty(value="商品描述") |
||||
|
private String goodsDesc; |
||||
|
|
||||
|
@ApiModelProperty(value="支付金额,单位元") |
||||
|
private BigDecimal payAmount; |
||||
|
|
||||
|
@ApiModelProperty(value="支付时间") |
||||
|
private Date payTime; |
||||
|
|
||||
|
@ApiModelProperty(value="支付场景:1.会员充值") |
||||
|
private Integer sceneCode; |
||||
|
|
||||
|
@ApiModelProperty(value="用户ip") |
||||
|
private String ip; |
||||
|
|
||||
|
@ApiModelProperty(value="调用第三方下单返回") |
||||
|
private String thirdCode; |
||||
|
|
||||
|
@ApiModelProperty(value="调用第三方下单返回") |
||||
|
private String thirdMsg; |
||||
|
|
||||
|
@ApiModelProperty(value="调用第三方下单返回") |
||||
|
private String thirdNo; |
||||
|
|
||||
|
@ApiModelProperty(value="备注") |
||||
|
private String remark; |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
package com.bnyer.pay.vo; |
||||
|
|
||||
|
import io.swagger.annotations.ApiModelProperty; |
||||
|
import lombok.Getter; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
import lombok.Setter; |
||||
|
|
||||
|
/** |
||||
|
* @author :WXC |
||||
|
* @Date :2023/05/05 |
||||
|
* @description : |
||||
|
*/ |
||||
|
@Getter |
||||
|
@Setter |
||||
|
@NoArgsConstructor |
||||
|
public class QueryOrderVo { |
||||
|
@ApiModelProperty(value="内部支付单号") |
||||
|
private String payId; |
||||
|
|
||||
|
@ApiModelProperty(value = "支付状态:1000未支付;1001支付成功 ;1002支付失败") |
||||
|
private Integer payStatus; |
||||
|
} |
||||
@ -0,0 +1,42 @@ |
|||||
|
package com.bnyer.pay.vo; |
||||
|
|
||||
|
import lombok.Getter; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
import lombok.Setter; |
||||
|
|
||||
|
/** |
||||
|
* @author :WXC |
||||
|
* @Date :2023/05/05 |
||||
|
* @description : |
||||
|
*/ |
||||
|
@Getter |
||||
|
@Setter |
||||
|
@NoArgsConstructor |
||||
|
public class ThirdQueryOrderVo { |
||||
|
//开发者下单单号
|
||||
|
private String outOrderNo; |
||||
|
/** |
||||
|
* 快手取值:PROCESSING-处理中|SUCCESS-成功|FAILED-失败 TIMEOUT-超时 |
||||
|
* 抖音取值:SUCCESS:成功 TIMEOUT:超时未支付 PROCESSING:处理中 FAIL:失败 |
||||
|
* 微信取值:SUCCESS—支付成功,REFUND—转入退款,NOTPAY—未支付,CLOSED—已关闭,REVOKED—已撤销(刷卡支付),USERPAYING--用户支付中,PAYERROR--支付失败(其他原因,如银行返回失败) |
||||
|
* 支付宝取值: |
||||
|
*/ |
||||
|
private String payStatus; |
||||
|
//预下单用户支付金额:单位统一成元
|
||||
|
private String totalAmount; |
||||
|
//订单支付时间,统一处理为yyyy-MM-dd HH:mm:ss
|
||||
|
private String payTime; |
||||
|
//快手支付渠道。取值:UNKNOWN - 未知|WECHAT-微信 |ALIPAY-支付宝。(注:如果用户还未支付,这里返回的是UNKNOWN.)
|
||||
|
private String ksPayChannel; |
||||
|
//抖音支付渠道
|
||||
|
private Integer dyPayChannel; |
||||
|
//第三方平台订单号:抖音快手平台订单号
|
||||
|
private String thirdOrderNo; |
||||
|
//开发者回传的订单同步状态
|
||||
|
private String orderStatus; |
||||
|
//订单对应的用户openid
|
||||
|
private String openId; |
||||
|
//支付渠道侧的支付单号
|
||||
|
private String channelNo; |
||||
|
|
||||
|
} |
||||
Loading…
Reference in new issue