123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409 |
- package com.qxgmat.service.extend;
- import com.alibaba.fastjson.JSONObject;
- import com.nuliji.tools.AbstractService;
- import com.nuliji.tools.Tools;
- import com.nuliji.tools.exception.ParameterException;
- import com.nuliji.tools.exception.SystemException;
- import com.nuliji.tools.pay.PaySource;
- import com.nuliji.tools.pay.common.PayInfo;
- import com.nuliji.tools.pay.common.ResultInfo;
- import com.nuliji.tools.pay.data.PayRequestData;
- import com.nuliji.tools.pay.data.PayResponseData;
- import com.qxgmat.data.constants.enums.module.PayModule;
- import com.qxgmat.data.constants.enums.trade.PayChannel;
- import com.qxgmat.data.constants.enums.trade.PayType;
- import com.qxgmat.data.constants.enums.trade.TradeStatus;
- import com.qxgmat.data.dao.PayMapper;
- import com.qxgmat.data.dao.entity.Pay;
- import com.qxgmat.data.dao.entity.UserPay;
- import com.qxgmat.help.PayHelp;
- import com.qxgmat.service.inline.PayService;
- import com.qxgmat.service.inline.UserCourseService;
- import com.qxgmat.service.inline.UserPayService;
- import com.qxgmat.service.inline.UserServiceService;
- import com.qxgmat.util.annotation.Callback;
- import org.springframework.stereotype.Service;
- import javax.annotation.Resource;
- import javax.servlet.http.HttpServletRequest;
- import java.math.BigDecimal;
- import java.util.*;
- /**
- * Created by gaojie on 2017/11/13.
- */
- @Service
- public class TradeService extends AbstractService {
- @Resource
- private PayHelp payHelp;
- @Resource
- private PayMapper payMapper;
- @Resource
- private PayService payService;
- @Resource
- private UserServiceService userServiceService;
- @Resource
- private UserCourseService userCourseService;
- private Map<PayModule, Callback> payCallback = new HashMap<>();;
- @Resource
- private UserPayService userPayService;
- public interface Source {
- String WECHAT = "wechat";
- String ALIPAY = "alipay";
- }
- public static HashMap<PayChannel, String> channelMap = new HashMap<>();
- static{
- channelMap.put(PayChannel.ALIPAY_APP, Source.ALIPAY);
- channelMap.put(PayChannel.ALIPAY_QR, Source.ALIPAY);
- channelMap.put(PayChannel.WECHAT_APP, Source.WECHAT);
- channelMap.put(PayChannel.WECHAT_QR, Source.WECHAT);
- }
- public TradeService(){
- payCallback.put(PayModule.SERVICE, (obj)->{
- Pay pay = (Pay) obj;
- Integer userId = pay.getUserId();
- JSONObject extend = JSONObject.parseObject(pay.getModuleExtend());
- // 写入用户购买
- userPayService.add(UserPay.builder()
- .module(pay.getModule())
- .moduleExtend(extend)
- .isUse(0)
- .userId(userId).build());
- return true;
- });
- payCallback.put(PayModule.CLASS, (obj)->{
- Pay pay = (Pay) obj;
- Integer userId = pay.getUserId();
- JSONObject extend = JSONObject.parseObject(pay.getModuleExtend());
- // 写入用户购买
- userPayService.add(UserPay.builder()
- .module(pay.getModule())
- .moduleExtend(extend)
- .isUse(0)
- .userId(userId).build());
- return true;
- });
- payCallback.put(PayModule.DATA, (obj)->{
- Pay pay = (Pay) obj;
- Integer userId = pay.getUserId();
- JSONObject extend = JSONObject.parseObject(pay.getModuleExtend());
- // 写入用户购买
- userPayService.add(UserPay.builder()
- .module(pay.getModule())
- .moduleExtend(extend)
- .isUse(0)
- .userId(userId).build());
- // 直接绑定数据关系
- return true;
- });
- }
- /**
- * 对于用户的支付方式
- * @param userId
- * @param subject
- * @param body
- * @param module
- * @param moduleExtend
- * @param money
- * @param channel
- * @param request
- * @return
- */
- public PayResponseData pay(Integer userId, String subject, String body, String module, JSONObject moduleExtend, BigDecimal money, PayChannel channel, HttpServletRequest request) throws Exception {
- if(!payCallback.containsKey(module))
- throw new ParameterException("不支持的支付模块");
- PayRequestData data = new PayRequestData();
- data.subject = subject;
- data.body = body;
- data.channel = channel.key;
- data.money = money;
- String pid = preprocess(data);
- String clientIp = Tools.getClientIp(request);
- PayType payType = PayType.FromChannel(channel);
- Pay pay = payService.make(userId, payType == null ? "":payType.key, channel.key, money, module, moduleExtend.toJSONString(), pid, subject, body, clientIp);
- PayInfo info = process(pay, channel);
- PayResponseData payResponseData = new PayResponseData();
- payResponseData.payNo = pay.getNo();
- payResponseData.request = info.getRequest();
- payResponseData.status = info.getStatus();
- return payResponseData;
- }
- private PayInfo prepay(Pay pay){
- // 直接支付完成
- payService.payed(pay,new ResultInfo(), false);
- payed(pay);
- // 构建模拟支付信息
- PayInfo info = new PayInfo();
- info.setStatus("ok");
- return info;
- }
- public Pay payed(Pay pay){
- if(pay == null)
- throw new ParameterException("支付信息错误");
- if(pay.getTradeStatus() == TradeStatus.SUCCESS.index
- || pay.getTradeStatus() == TradeStatus.FINISH.index)
- return pay;
- if(pay.getTradeStatus() == TradeStatus.CANCEL.index
- || pay.getTradeStatus() == TradeStatus.CLOSE.index)
- throw new ParameterException("该支付无效");
- Callback callback = payCallback.get(pay.getModule());
- try {
- boolean r = callback.callback(pay);
- if (!r)
- throw new SystemException("支付回调失败");
- }catch (Exception e){
- throw new SystemException("支付回调失败", e);
- }
- return pay;
- }
- /**
- * 异步通知处理
- * @param channel
- * @param request
- * @return
- * @throws ParameterException
- * @throws SystemException
- */
- public ResultInfo notifyPay(PayChannel channel, HttpServletRequest request) throws ParameterException,SystemException, Exception{
- if(channel == null) throw new ParameterException(104, "第三方支付错误");
- PaySource paySource = getHandler(channel);
- return paySource.notifyTrade(request);
- }
- /**
- * 同步结果处理
- * @param channel
- * @param info
- * @return
- * @throws ParameterException
- * @throws SystemException
- */
- public ResultInfo returnPay(PayChannel channel, ResultInfo info) throws ParameterException,SystemException {
- if(channel == null) throw new ParameterException(104, "第三方支付错误");
- PaySource paySource = getHandler(channel);
- return paySource.returnTrade(info);
- }
- /**
- * 查询支付结果
- * @param pay
- * @return
- * @throws SystemException
- * @throws Exception
- */
- public ResultInfo query(Pay pay) throws SystemException, Exception{
- PaySource paySource = getHandler(PayChannel.ValueOf(pay.getChannel()));
- return paySource.getTrade(pay.getNo(), pay.getTransactionNo(), pay.getPid());
- }
- /**
- * 返回服务端结果
- * @param pay
- * @param info
- * @return
- * @throws SystemException
- */
- public String server(Pay pay, ResultInfo info) throws SystemException{
- PaySource paySource = getHandler(PayChannel.ValueOf(pay.getChannel()));
- if(paySource.validTrade(info, payService.getInfo(pay))){
- throw new SystemException(206, "支付校验错误");
- }
- if(pay.getMoney().equals(info.getMoney())){
- throw new SystemException(206, "支付金额错误");
- }
- analyse(pay, paySource, info);
- if(payService.isPayed(pay)){
- payed(pay);
- }
- return info.getMessage();
- }
- /**
- * 返回客户端处理结果
- * @param pay
- * @param info
- * @return
- * @throws SystemException
- * @throws ParameterException
- */
- public Pay client(Pay pay, ResultInfo info) throws SystemException, ParameterException{
- PaySource paySource = getHandler(PayChannel.ValueOf(pay.getChannel()));
- if(paySource.validTrade(info, payService.getInfo(pay))){
- throw new SystemException(206, "支付校验错误");
- }
- if(pay.getMoney().equals(info.getMoney())){
- throw new SystemException(206, "支付金额错误");
- }
- analyse(pay, paySource, info);
- if(Objects.equals(info.getStatus(), "system")) throw new SystemException(500, info.getMessage());
- if(payService.isPayed(pay)){
- return payed(pay);
- }else if(payService.isPaying(pay)){
- throw new SystemException(210, "支付中");
- }else{
- throw new SystemException(210, info.getMessage());
- }
- }
- /**
- * 支付预处理,校验支付请求
- * @param payRequest
- * @return
- * @throws ParameterException
- */
- public String preprocess(PayRequestData payRequest) throws ParameterException {
- if(payRequest.channel.isEmpty()) throw new ParameterException(103, "支付渠道为空");
- String source = getSource(PayChannel.ValueOf(payRequest.channel));
- if(source.isEmpty()) throw new ParameterException(104, "支付渠道错误");
- if(source.equals(Source.ALIPAY)) return payHelp.getAlipayPid();
- if(source.equals(Source.WECHAT)) return payHelp.getWechatPid();
- throw new ParameterException(104, "支付渠道错误");
- }
- /**
- * 发起支付
- * @param pay
- * @return
- * @throws SystemException
- * @throws Exception
- */
- public PayInfo process(Pay pay, PayChannel channel) throws SystemException, Exception {
- String notifyUrl = getNotifyUrl(channel);
- String subject = pay.getSubject();
- String payNo = pay.getNo();
- String body = pay.getBody();
- BigDecimal money = pay.getMoney();
- String pid = pay.getPid();
- PayInfo info = null;
- switch(channel){
- case ALIPAY_APP:
- info = payHelp.getAlipay().appTrade(payNo, pid, money, subject, body, notifyUrl, pay.getClientIp());
- break;
- case ALIPAY_QR:
- info = payHelp.getAlipay().preTrade(payNo, pid, money, subject, body, notifyUrl, pay.getClientIp());
- break;
- case WECHAT_APP:
- info = payHelp.getWechatPay().appTrade(payNo, pid, money, subject, body, notifyUrl, pay.getClientIp());
- break;
- case WECHAT_QR:
- info = payHelp.getWechatPay().preTrade(payNo, pid, money, subject, body, notifyUrl, pay.getClientIp());
- break;
- case WECHAT_JS:
- info = payHelp.getWechatPay().jsTrade(payNo, pid, money, subject, body, notifyUrl, pay.getClientIp());
- break;
- case OFFLINE:
- // 直接完成支付
- info = prepay(pay);
- default:
- throw new SystemException(204, "支付渠道错误方式:"+channel);
- }
- if(Objects.equals(info.getStatus(), "ok")) {
- payService.start(pay, info);
- } else {
- payService.system(pay, info);
- throw new SystemException(205, "支付调用错误");
- }
- return info;
- }
- /**
- * 同步处理支付记录
- * @param pay
- * @param paySource
- * @param info
- */
- private void analyse(Pay pay, PaySource paySource, ResultInfo info) throws SystemException {
- String status = info.getStatus();
- if(payService.isPayed(pay)){
- if(status.equals("error") || status.equals("close") || status.equals("cancel")){
- throw new SystemException(301, "支付异常:已支付,第三方未支付");
- }
- return ;
- }else if(payService.isInvalid(pay)){
- if(status.equals("success") || status.equals("finish")){
- throw new SystemException(301, "支付异常:已撤销或者关闭,第三方支付成功");
- }
- return ;
- }
- switch (status) {
- case "success":
- // 支付成功
- payService.payed(pay, info, false);
- break;
- case "finish":
- // 完成,无法撤销或者关闭
- payService.payed(pay, info, true);
- break;
- case "error":
- // 支付错误,需要关闭支付交易
- payService.error(pay, info);
- break;
- case "cancel":
- // 对方已撤销
- payService.cancel(pay, info);
- break;
- case "close":
- // 对方已经关闭
- payService.close(pay, info);
- break;
- case "system":
- // system 开发接口错误
- payService.system(pay, info);
- break;
- case "exception":
- // exception 支付流程异常
- payService.exception(pay, info);
- break;
- }
- }
- /**
- * 获取支付
- * @param channel
- * @return
- */
- private String getSource(PayChannel channel){
- return channelMap.get(channel);
- }
- /**
- * 获取渠道异步通知
- * @param channel
- * @return
- */
- private String getNotifyUrl(PayChannel channel){
- return payHelp.getNotifyUrl() + channel.key;
- }
- /**
- * 获取支付实例
- * @param channel
- * @return PaySource
- * @throws SystemException
- */
- private PaySource getHandler(PayChannel channel) throws SystemException {
- String source = getSource(channel);
- if(source.equals(Source.ALIPAY)) return payHelp.getAlipay();
- if(source.equals(Source.WECHAT)) return payHelp.getWechatPay();
- throw new SystemException(204, "支付支付渠道错误方式");
- }
- }
|