forked from jeequan/jeepay
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request jeequan#4 in SOUNDPAYMENT/xxpay from feature/refun…
…d to master * commit '01b9e56e61ed23e4e8450221654742b13ec7fdf5': 修改MCH_REFUND_NOTIFY_QUEUE_NAME 为 mch.refund.notify.queue springboot版更新列表 1.添加退款支持 2.添加支付添加商户通知 3.添加商户通知手动发送接口 4.添加logback日志
- Loading branch information
Showing
28 changed files
with
1,948 additions
and
97 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
76 changes: 76 additions & 0 deletions
76
xxpay4spring-boot/src/main/java/org/xxpay/boot/ctrl/ManualSendNotifyController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package org.xxpay.boot.ctrl; | ||
|
||
import java.io.IOException; | ||
import java.util.Map; | ||
|
||
import javax.servlet.ServletException; | ||
import javax.servlet.http.HttpServletRequest; | ||
|
||
import org.apache.commons.lang3.StringUtils; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.ResponseBody; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import org.xxpay.boot.service.impl.MchInfoServiceImpl; | ||
import org.xxpay.boot.service.mq.Mq4PayNotify; | ||
import org.xxpay.boot.service.mq.Mq4RefundNotify; | ||
import org.xxpay.common.constant.PayConstant; | ||
import org.xxpay.common.util.MyLog; | ||
import org.xxpay.common.util.XXPayUtil; | ||
import org.xxpay.dal.dao.model.MchNotify; | ||
|
||
import com.alibaba.fastjson.JSON; | ||
|
||
/** | ||
* @Description: 手动发送通知 | ||
* @author dingzhiwei [email protected] | ||
* @date 2017-07-05 | ||
* @version V1.0 | ||
* @Copyright: www.xxpay.org | ||
*/ | ||
@RestController | ||
public class ManualSendNotifyController { | ||
|
||
private static final MyLog _log = MyLog.getLog(ManualSendNotifyController.class); | ||
|
||
@Autowired | ||
private Mq4PayNotify mq4PayNotify; | ||
|
||
@Autowired | ||
private Mq4RefundNotify mq4RefundNotify; | ||
|
||
@Autowired | ||
private MchInfoServiceImpl mchInfoServiceImpl; | ||
|
||
/** | ||
* 统一手动发送通知 | ||
* @param request | ||
* @param orderId | ||
* @return | ||
* @throws ServletException | ||
* @throws IOException | ||
*/ | ||
@RequestMapping("/manual/send/notify") | ||
@ResponseBody | ||
public String manualSendNotify(HttpServletRequest request, String orderId, Long count) throws ServletException, IOException { | ||
_log.info("====== 开始手动发送通知 ======"); | ||
MchNotify mchNotify = mchInfoServiceImpl.baseSelectMchNotify(orderId); | ||
if (mchNotify == null) { | ||
return XXPayUtil.makeRetFail(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_FAIL, "商户通知不存在", null, null)); | ||
} | ||
if(StringUtils.isBlank(mchNotify.getNotifyUrl())){ | ||
return XXPayUtil.makeRetFail(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_FAIL, "商户通知NotiryUrl不能为空", null, null)); | ||
} | ||
Map notifyUrlMap = JSON.parseObject(mchNotify.getNotifyUrl()); | ||
notifyUrlMap.put("count", (count-2) < 0 ? 0 : (count-2)); | ||
if(PayConstant.MCH_NOTIFY_TYPE_PAY.equals(mchNotify.getOrderType())) { | ||
mq4PayNotify.send(notifyUrlMap.toString()); | ||
} | ||
if(PayConstant.MCH_NOTIFY_TYPE_REFUND.equals(mchNotify.getOrderType())) { | ||
mq4RefundNotify.send(notifyUrlMap.toString()); | ||
} | ||
_log.info("====== 完成手动发送通知 ======"); | ||
return XXPayUtil.makeRetFail(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_SUCCESS, "手动通知发送成功", null, null)); | ||
} | ||
|
||
} |
228 changes: 228 additions & 0 deletions
228
xxpay4spring-boot/src/main/java/org/xxpay/boot/ctrl/RefundOrderController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,228 @@ | ||
package org.xxpay.boot.ctrl; | ||
|
||
import java.util.Map; | ||
|
||
import org.apache.commons.lang3.StringUtils; | ||
import org.apache.commons.lang3.math.NumberUtils; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RequestParam; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import org.xxpay.boot.service.IMchInfoService; | ||
import org.xxpay.boot.service.IPayChannelService; | ||
import org.xxpay.boot.service.IPayOrderService; | ||
import org.xxpay.boot.service.IRefundOrderService; | ||
import org.xxpay.common.constant.PayConstant; | ||
import org.xxpay.common.util.MyLog; | ||
import org.xxpay.common.util.MySeq; | ||
import org.xxpay.common.util.XXPayUtil; | ||
|
||
import com.alibaba.fastjson.JSONObject; | ||
|
||
/** | ||
* @Description: 订单退款 | ||
* @author dingzhiwei [email protected] | ||
* @date 2017-10-30 | ||
* @version V1.0 | ||
* @Copyright: www.xxpay.org | ||
*/ | ||
@RestController | ||
public class RefundOrderController { | ||
|
||
private final MyLog _log = MyLog.getLog(RefundOrderController.class); | ||
|
||
@Autowired | ||
private IRefundOrderService refundOrderService; | ||
|
||
@Autowired | ||
private IPayOrderService payOrderService; | ||
|
||
@Autowired | ||
private IPayChannelService payChannelService; | ||
|
||
@Autowired | ||
private IMchInfoService mchInfoService; | ||
|
||
/** | ||
* 统一退款接口: | ||
* 1)先验证接口参数以及签名信息 | ||
* 2)验证通过创建退款订单 | ||
* 3)根据商户选择渠道,调用退款服务进行退单 | ||
* 4)返回退单数据 | ||
* @param params | ||
* @return | ||
*/ | ||
@RequestMapping(value = "/api/refund/create_order") | ||
public String payOrder(@RequestParam String params) { | ||
_log.info("###### 开始接收商户统一退款请求 ######"); | ||
String logPrefix = "【商户统一退款】"; | ||
try { | ||
JSONObject po = JSONObject.parseObject(params); | ||
JSONObject refundContext = new JSONObject(); | ||
JSONObject refundOrder = null; | ||
// 验证参数有效性 | ||
Object object = validateParams(po, refundContext); | ||
if (object instanceof String) { | ||
_log.info("{}参数校验不通过:{}", logPrefix, object); | ||
return XXPayUtil.makeRetFail(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_FAIL, object.toString(), null, null)); | ||
} | ||
if (object instanceof JSONObject) refundOrder = (JSONObject) object; | ||
if(refundOrder == null) return XXPayUtil.makeRetFail(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_FAIL, "支付中心退款失败", null, null)); | ||
int result = refundOrderService.createRefundOrder(refundOrder); | ||
_log.info("{}创建退款订单,结果:{}", logPrefix, result); | ||
if(result != 1) { | ||
return XXPayUtil.makeRetFail(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_FAIL, "创建退款订单失败", null, null)); | ||
} | ||
// 发送异步退款消息 | ||
String refundOrderId = refundOrder.getString("refundOrderId"); | ||
String channelName = refundContext.getString("channelName"); | ||
refundOrderService.sendRefundNotify(refundOrderId, channelName); | ||
_log.info("{}发送退款任务完成,transOrderId={}", logPrefix, refundOrderId); | ||
|
||
Map<String, Object> map = XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_SUCCESS, "", PayConstant.RETURN_VALUE_SUCCESS, null); | ||
map.put("refundOrderId", refundOrder.getString("refundOrderId")); | ||
return XXPayUtil.makeRetData(map, refundContext.getString("resKey")); | ||
}catch (Exception e) { | ||
_log.error(e, ""); | ||
return XXPayUtil.makeRetFail(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_FAIL, "支付中心系统异常", null, null)); | ||
} | ||
} | ||
|
||
/** | ||
* 验证创建订单请求参数,参数通过返回JSONObject对象,否则返回错误文本信息 | ||
* @param params | ||
* @return | ||
*/ | ||
private Object validateParams(JSONObject params, JSONObject refundContext) { | ||
// 验证请求参数,参数有问题返回错误提示 | ||
String errorMessage; | ||
// 退款参数 | ||
String mchId = params.getString("mchId"); // 商户ID | ||
String payOrderId = params.getString("payOrderId"); // 支付订单号 | ||
String mchOrderNo = params.getString("mchOrderNo"); // 商户支付单号 | ||
String mchRefundNo = params.getString("mchRefundNo"); // 商户退款单号 | ||
String channelId = params.getString("channelId"); // 渠道ID | ||
String amount = params.getString("amount"); // 退款金额(单位分) | ||
String currency = params.getString("currency"); // 币种 | ||
String clientIp = params.getString("clientIp"); // 客户端IP | ||
String device = params.getString("device"); // 设备 | ||
String extra = params.getString("extra"); // 特定渠道发起时额外参数 | ||
String param1 = params.getString("param1"); // 扩展参数1 | ||
String param2 = params.getString("param2"); // 扩展参数2 | ||
String notifyUrl = params.getString("notifyUrl"); // 退款结果回调URL | ||
String sign = params.getString("sign"); // 签名 | ||
String channelUser = params.getString("channelUser"); // 渠道用户标识,如微信openId,支付宝账号 | ||
String userName = params.getString("userName"); // 用户姓名 | ||
String remarkInfo = params.getString("remarkInfo"); // 备注 | ||
// 验证请求参数有效性(必选项) | ||
if(StringUtils.isBlank(mchId)) { | ||
errorMessage = "request params[mchId] error."; | ||
return errorMessage; | ||
} | ||
if(StringUtils.isBlank(payOrderId) && StringUtils.isBlank(mchOrderNo)) { | ||
errorMessage = "request params[payOrderId,mchOrderNo] error."; | ||
return errorMessage; | ||
} | ||
if(StringUtils.isBlank(mchRefundNo)) { | ||
errorMessage = "request params[mchRefundNo] error."; | ||
return errorMessage; | ||
} | ||
if(StringUtils.isBlank(channelId)) { | ||
errorMessage = "request params[channelId] error."; | ||
return errorMessage; | ||
} | ||
if(!NumberUtils.isNumber(amount)) { | ||
errorMessage = "request params[amount] error."; | ||
return errorMessage; | ||
} | ||
if(StringUtils.isBlank(currency)) { | ||
errorMessage = "request params[currency] error."; | ||
return errorMessage; | ||
} | ||
if(StringUtils.isBlank(notifyUrl)) { | ||
errorMessage = "request params[notifyUrl] error."; | ||
return errorMessage; | ||
} | ||
if(StringUtils.isBlank(channelUser)) { | ||
errorMessage = "request params[channelUser] error."; | ||
return errorMessage; | ||
} | ||
|
||
// 签名信息 | ||
if (StringUtils.isEmpty(sign)) { | ||
errorMessage = "request params[sign] error."; | ||
return errorMessage; | ||
} | ||
|
||
// 查询商户信息 | ||
JSONObject mchInfo = mchInfoService.getByMchId(mchId); | ||
if(mchInfo == null) { | ||
errorMessage = "Can't found mchInfo[mchId="+mchId+"] record in db."; | ||
return errorMessage; | ||
} | ||
if(mchInfo.getByte("state") != 1) { | ||
errorMessage = "mchInfo not available [mchId="+mchId+"] record in db."; | ||
return errorMessage; | ||
} | ||
|
||
String reqKey = mchInfo.getString("reqKey"); | ||
if (StringUtils.isBlank(reqKey)) { | ||
errorMessage = "reqKey is null[mchId="+mchId+"] record in db."; | ||
return errorMessage; | ||
} | ||
refundContext.put("resKey", mchInfo.getString("resKey")); | ||
|
||
// 查询商户对应的支付渠道 | ||
JSONObject payChannel = payChannelService.getByMchIdAndChannelId(mchId, channelId); | ||
if(payChannel == null) { | ||
errorMessage = "Can't found payChannel[channelId="+channelId+",mchId="+mchId+"] record in db."; | ||
return errorMessage; | ||
} | ||
if(payChannel.getByte("state") != 1) { | ||
errorMessage = "channel not available [channelId="+channelId+",mchId="+mchId+"]"; | ||
return errorMessage; | ||
} | ||
refundContext.put("channelName", payChannel.getString("channelName")); | ||
|
||
// 验证签名数据 | ||
boolean verifyFlag = XXPayUtil.verifyPaySign(params, reqKey); | ||
if(!verifyFlag) { | ||
errorMessage = "Verify XX refund sign failed."; | ||
return errorMessage; | ||
} | ||
|
||
// 验证支付订单是否存在 | ||
JSONObject payOrder = payOrderService.query(mchId, payOrderId, mchOrderNo, "false"); | ||
if(payOrder == null) { | ||
errorMessage = "payOrder is not exist."; | ||
return errorMessage; | ||
} | ||
|
||
String channelPayOrderNo = payOrder.getString("channelOrderNo"); // 渠道测支付单号 | ||
Long payAmount = payOrder.getLong("amount"); | ||
|
||
// 验证参数通过,返回JSONObject对象 | ||
JSONObject refundOrder = new JSONObject(); | ||
refundOrder.put("refundOrderId", MySeq.getRefund()); | ||
refundOrder.put("payOrderId", payOrderId); | ||
refundOrder.put("channelPayOrderNo", channelPayOrderNo); | ||
refundOrder.put("mchId", mchId); | ||
refundOrder.put("mchRefundNo", mchRefundNo); | ||
refundOrder.put("channelId", channelId); | ||
refundOrder.put("refundAmount", Long.parseLong(amount)); // 退款金额 | ||
refundOrder.put("payAmount", payAmount); // 退款金额 | ||
refundOrder.put("currency", currency); | ||
refundOrder.put("clientIp", clientIp); | ||
refundOrder.put("device", device); | ||
refundOrder.put("channelUser", channelUser); | ||
refundOrder.put("userName", userName); | ||
refundOrder.put("remarkInfo", remarkInfo); | ||
refundOrder.put("extra", extra); | ||
refundOrder.put("channelMchId", payChannel.getString("channelMchId")); | ||
refundOrder.put("param1", param1); | ||
refundOrder.put("param2", param2); | ||
refundOrder.put("notifyUrl", notifyUrl); | ||
return refundOrder; | ||
} | ||
|
||
} |
Oops, something went wrong.