支付关单 和 退款
This commit is contained in:
parent
3c07c9f5c6
commit
927a0ecc0b
|
|
@ -1,8 +1,12 @@
|
||||||
package com.ghy.common.adapay;
|
package com.ghy.common.adapay;
|
||||||
|
|
||||||
import com.ghy.common.adapay.callback.PayCallback;
|
import com.ghy.common.adapay.callback.PayCallback;
|
||||||
|
import com.ghy.common.adapay.callback.RefundCallback;
|
||||||
|
import com.ghy.common.adapay.callback.reply.PayReplyMapping;
|
||||||
|
import com.ghy.common.adapay.callback.reply.RefundReplyMapping;
|
||||||
import com.huifu.adapay.core.exception.BaseAdaPayException;
|
import com.huifu.adapay.core.exception.BaseAdaPayException;
|
||||||
import com.huifu.adapay.model.Payment;
|
import com.huifu.adapay.model.Payment;
|
||||||
|
import com.huifu.adapay.model.Refund;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
|
@ -19,15 +23,40 @@ public class AdapayService {
|
||||||
AdapayProperties adapayProperties;
|
AdapayProperties adapayProperties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param callback 处理支付结果的回调接口
|
* 发起退款
|
||||||
* @param orderNo 订单号
|
* 当您的业务需要发起退款时,可通过 Adapay 系统提供的创建 Refund对象 方法创建一个退款对象,资金会原路退回用户的支付宝或微信中。
|
||||||
* @param payAmt 支付金额
|
* 支持一次全额或多次部分退款,退款次数最多不超过10次。多次部分退款时,当前退款金额 + 已退款金额不能大于原支付金额。
|
||||||
* @param goodsTittle 商品名称
|
* 对于每次撤销交易,Adapay 都会通过 异步消息通知 告知结果。
|
||||||
* @param goodsDesc 商品描述
|
* 退款对象同步返回成功,表示Adapay受理成功,退款结果以异步通知为准。支持退款最长时间为178天,
|
||||||
|
* 若返回码是“order_id_not_exists 订单记录不存在”,既超过退款期限,无法退款成功。
|
||||||
|
*
|
||||||
|
* @param callback [必填项]处理退款结果的回调接口
|
||||||
|
* @param paymentId [必填项]支付确认对象的id
|
||||||
|
* @param refundOrderNo [必填项]订单号
|
||||||
|
* @param refundAmt [必填项]退款金额,若退款金额小于原交易金额,则认为是部分退款,必须大于0,保留两位小数点,如0.10、100.05等
|
||||||
|
* @return 同步返回一个 退款对象
|
||||||
|
*/
|
||||||
|
public Map<String, Object> refund(RefundCallback callback, String paymentId, String refundOrderNo, String refundAmt) throws BaseAdaPayException {
|
||||||
|
Map<String, Object> refundParams = new HashMap<>(4);
|
||||||
|
refundParams.put("refund_amt", refundAmt);
|
||||||
|
refundParams.put("refund_order_no", refundOrderNo);
|
||||||
|
RefundReplyMapping.putCallback(paymentId, callback);
|
||||||
|
return Refund.create(paymentId, refundParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信小程序支付
|
||||||
|
*
|
||||||
|
* @param callback [必填项]处理支付结果的回调接口
|
||||||
|
* @param orderNo [必填项]订单号
|
||||||
|
* @param payAmt [必填项]交易金额,必须大于0,保留两位小数点,如0.10、100.05等
|
||||||
|
* @param goodsTittle [必填项]商品名称
|
||||||
|
* @param goodsDesc [必填项]商品描述信息,微信小程序和微信公众号该字段最大长度42个字符
|
||||||
* @param description 订单附加说明
|
* @param description 订单附加说明
|
||||||
|
* @return 同步返回一个 支付对象 Payment
|
||||||
*/
|
*/
|
||||||
public Map<String, Object> wxLitePay(PayCallback callback, String orderNo, String payAmt, String goodsTittle, String goodsDesc, String description) throws BaseAdaPayException {
|
public Map<String, Object> wxLitePay(PayCallback callback, String orderNo, String payAmt, String goodsTittle, String goodsDesc, String description) throws BaseAdaPayException {
|
||||||
Map<String, Object> paymentParams = new HashMap<>(10);
|
Map<String, Object> paymentParams = new HashMap<>(16);
|
||||||
paymentParams.put("app_id", adapayProperties.getAppId());
|
paymentParams.put("app_id", adapayProperties.getAppId());
|
||||||
paymentParams.put("notify_url", adapayProperties.getNotifyUrl());
|
paymentParams.put("notify_url", adapayProperties.getNotifyUrl());
|
||||||
paymentParams.put("order_no", orderNo);
|
paymentParams.put("order_no", orderNo);
|
||||||
|
|
@ -36,8 +65,29 @@ public class AdapayService {
|
||||||
paymentParams.put("goods_title", goodsTittle);
|
paymentParams.put("goods_title", goodsTittle);
|
||||||
paymentParams.put("goods_desc", goodsDesc);
|
paymentParams.put("goods_desc", goodsDesc);
|
||||||
paymentParams.put("description", description);
|
paymentParams.put("description", description);
|
||||||
PayResultMapping.putCallback(orderNo, callback);
|
PayReplyMapping.putCallback(orderNo, callback);
|
||||||
return Payment.create(paymentParams);
|
return Payment.create(paymentParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付关单
|
||||||
|
* 针对已经创建的 支付对象,您可以调用关单接口进行交易的关闭。调用此接口后,该用户订单将不再能支付成功。 对于关单功能的使用有如下规则:
|
||||||
|
* 1.存在关单记录,不能再次关单
|
||||||
|
* 2.交易时间 1分钟 内无法关单成功
|
||||||
|
* 3.正扫交易时间超过 2小时 无法关单成功
|
||||||
|
* 4.支付宝正扫接口,如果用户没有扫码,订单不能关闭成功(二维码给用户展示,如果用户没有用手机去扫码,那这笔就不能关单; 如果用户扫过了的话(无需支付成功)就可以关单了)—-微信正扫无此条限制
|
||||||
|
* 5.网银和快捷类交易都不支持关单操作
|
||||||
|
*
|
||||||
|
* @param paymentId [必填项]由 Adapay 生成的支付对象 id
|
||||||
|
* @param reason 关单描述
|
||||||
|
* @param expend 扩展域
|
||||||
|
*/
|
||||||
|
public Map<String, Object> close(String paymentId, String reason, String expend) throws BaseAdaPayException {
|
||||||
|
Map<String, Object> paymentParams = new HashMap<>(4);
|
||||||
|
paymentParams.put("payment_id", paymentId);
|
||||||
|
paymentParams.put("reason", reason);
|
||||||
|
paymentParams.put("expend", expend);
|
||||||
|
return Payment.close(paymentParams);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package com.ghy.common.adapay.callback;
|
package com.ghy.common.adapay.callback;
|
||||||
|
|
||||||
import com.ghy.common.adapay.PayResultMapping;
|
import com.ghy.common.adapay.callback.reply.PayReplyMapping;
|
||||||
|
import com.ghy.common.adapay.callback.reply.RefundReplyMapping;
|
||||||
import com.huifu.adapay.core.AdapayCore;
|
import com.huifu.adapay.core.AdapayCore;
|
||||||
import com.huifu.adapay.core.util.AdapaySign;
|
import com.huifu.adapay.core.util.AdapaySign;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
@ -40,7 +41,11 @@ public class AdapayCallbackController {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "payment.succeeded":
|
case "payment.succeeded":
|
||||||
case "payment.failed":
|
case "payment.failed":
|
||||||
PayResultMapping.putResult(event);
|
PayReplyMapping.putReply(event);
|
||||||
|
break;
|
||||||
|
case "payment.close.succeeded":
|
||||||
|
case "payment.close.failed":
|
||||||
|
RefundReplyMapping.putReply(event);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
log.warn("UNKNOWN EVENT TYPE [{}]", type);
|
log.warn("UNKNOWN EVENT TYPE [{}]", type);
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,8 @@ public class Event {
|
||||||
*/
|
*/
|
||||||
private String type;
|
private String type;
|
||||||
/**
|
/**
|
||||||
* 支付对象
|
* Adapay回调接口传过来的数据,内容为JSON字符串
|
||||||
|
* 不同的Event事件有不同的data
|
||||||
*/
|
*/
|
||||||
private String data;
|
private String data;
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package com.ghy.common.adapay.callback;
|
package com.ghy.common.adapay.callback;
|
||||||
|
|
||||||
import com.huifu.adapay.model.Payment;
|
import com.ghy.common.adapay.callback.model.PayReply;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理支付结果的回调接口
|
* 处理支付结果的回调接口
|
||||||
|
|
@ -9,5 +9,5 @@ import com.huifu.adapay.model.Payment;
|
||||||
*/
|
*/
|
||||||
public interface PayCallback {
|
public interface PayCallback {
|
||||||
|
|
||||||
void onResponse(Payment payment);
|
void onReply(PayReply reply);
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.ghy.common.adapay.callback;
|
||||||
|
|
||||||
|
import com.ghy.common.adapay.callback.model.RefundReply;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理退款结果的回调接口
|
||||||
|
*
|
||||||
|
* @author HH 2022/3/29
|
||||||
|
*/
|
||||||
|
public interface RefundCallback {
|
||||||
|
|
||||||
|
void onReply(RefundReply reply);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
package com.ghy.common.adapay.callback.model;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付后Adapay回调接口传过来的数据
|
||||||
|
*
|
||||||
|
* @author HH 2022/3/29
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class PayReply {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返参,必填,由AdaPay生成的支付对象 ID
|
||||||
|
*/
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返参,必填,支付创建时的时间戳
|
||||||
|
*/
|
||||||
|
@JSONField(name = "created_time")
|
||||||
|
private Long createdTime;
|
||||||
|
/**
|
||||||
|
* 必填,订单号
|
||||||
|
*/
|
||||||
|
@JSONField(name = "order_no")
|
||||||
|
private String orderNo;
|
||||||
|
/**
|
||||||
|
* 是否测试模式
|
||||||
|
*/
|
||||||
|
@JSONField(name = "prod_mode")
|
||||||
|
private String prodMode;
|
||||||
|
/**
|
||||||
|
* 商户发起支付的应用id,不同的前端应用将无法使用该 Payment 对象完成支付
|
||||||
|
*/
|
||||||
|
@JSONField(name = "app_id")
|
||||||
|
private String appId;
|
||||||
|
/**
|
||||||
|
* 必填,支付渠道
|
||||||
|
*/
|
||||||
|
@JSONField(name = "pay_channel")
|
||||||
|
private String payChannel;
|
||||||
|
/**
|
||||||
|
* 必填,订单总金额(必须大于0),人民币为元。
|
||||||
|
*/
|
||||||
|
@JSONField(name = "pay_amt")
|
||||||
|
private String payAmt;
|
||||||
|
|
||||||
|
@JSONField(name = "fee_amt")
|
||||||
|
private String feeAmt;
|
||||||
|
/**
|
||||||
|
* 可临时用来查询支付订单状态的链接,此链接只具有比较短的有效期
|
||||||
|
*/
|
||||||
|
@JSONField(name = "query_url")
|
||||||
|
private String queryUrl;
|
||||||
|
/**
|
||||||
|
* 货币代码
|
||||||
|
*/
|
||||||
|
private String currency;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 交易状态
|
||||||
|
* pending 交易处理中
|
||||||
|
* succeeded 交易成功
|
||||||
|
* failed 交易失败
|
||||||
|
*/
|
||||||
|
private String status;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
package com.ghy.common.adapay.callback.model;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退款后Adapay回调接口传过来的数据
|
||||||
|
*
|
||||||
|
* @author HH 2022/3/29
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class RefundReply {
|
||||||
|
/**
|
||||||
|
* 退款目标支付对象 id
|
||||||
|
*/
|
||||||
|
@JSONField(name="payment_id")
|
||||||
|
private String paymentId;
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
@JSONField(name="created_time")
|
||||||
|
private String createdTime;
|
||||||
|
/**
|
||||||
|
* 错误码
|
||||||
|
*/
|
||||||
|
@JSONField(name="error_code")
|
||||||
|
private String errorCode;
|
||||||
|
/**
|
||||||
|
* 错误描述
|
||||||
|
*/
|
||||||
|
@JSONField(name="error_msg")
|
||||||
|
private String errorMsg;
|
||||||
|
/**
|
||||||
|
* 退款手续费,退款成功时有值
|
||||||
|
*/
|
||||||
|
@JSONField(name="fee_amt")
|
||||||
|
private String feeAmt;
|
||||||
|
/**
|
||||||
|
* 由 Adapay 生成的退款对象 id
|
||||||
|
*/
|
||||||
|
private String id;
|
||||||
|
/**
|
||||||
|
* 交易状态
|
||||||
|
* pending 交易处理中
|
||||||
|
* succeeded 交易成功
|
||||||
|
* failed 交易失败
|
||||||
|
*/
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
@JSONField(name="pay_amt")
|
||||||
|
private String payAmt;
|
||||||
|
/**
|
||||||
|
* 错误类型
|
||||||
|
*/
|
||||||
|
@JSONField(name="error_type")
|
||||||
|
private String errorType;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
package com.ghy.common.adapay;
|
package com.ghy.common.adapay.callback.reply;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.ghy.common.adapay.callback.Event;
|
import com.ghy.common.adapay.callback.Event;
|
||||||
import com.ghy.common.adapay.callback.PayCallback;
|
import com.ghy.common.adapay.callback.PayCallback;
|
||||||
import com.huifu.adapay.model.Payment;
|
import com.ghy.common.adapay.callback.model.PayReply;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
@ -13,7 +13,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||||
*
|
*
|
||||||
* @author HH 2022/3/25
|
* @author HH 2022/3/25
|
||||||
*/
|
*/
|
||||||
public class PayResultMapping {
|
public class PayReplyMapping {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 临时保存支付结果
|
* 临时保存支付结果
|
||||||
|
|
@ -22,13 +22,13 @@ public class PayResultMapping {
|
||||||
*/
|
*/
|
||||||
private final static ConcurrentHashMap<String, PayCallback> PAY_RESULT_CALLBACK_MAP = new ConcurrentHashMap<>(1024);
|
private final static ConcurrentHashMap<String, PayCallback> PAY_RESULT_CALLBACK_MAP = new ConcurrentHashMap<>(1024);
|
||||||
|
|
||||||
public static void putResult(Event event) {
|
public static void putReply(Event event) {
|
||||||
String data = event.getData();
|
String data = event.getData();
|
||||||
Payment payment = JSON.parseObject(data, Payment.class);
|
PayReply payment = JSON.parseObject(data, PayReply.class);
|
||||||
Assert.hasText(payment.getOrderNo(), "orderNo is blank !!!");
|
Assert.hasText(payment.getOrderNo(), "orderNo is blank !!!");
|
||||||
PayCallback callback = PAY_RESULT_CALLBACK_MAP.remove(payment.getOrderNo());
|
PayCallback callback = PAY_RESULT_CALLBACK_MAP.remove(payment.getOrderNo());
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
callback.onResponse(payment);
|
callback.onReply(payment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
package com.ghy.common.adapay.callback.reply;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.ghy.common.adapay.callback.Event;
|
||||||
|
import com.ghy.common.adapay.callback.RefundCallback;
|
||||||
|
import com.ghy.common.adapay.callback.model.RefundReply;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author HH 2022/3/29
|
||||||
|
*/
|
||||||
|
public class RefundReplyMapping {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 临时保存支付结果
|
||||||
|
* key: orderNo
|
||||||
|
* value: 处理支付结果的回调接口
|
||||||
|
*/
|
||||||
|
private final static ConcurrentHashMap<String, RefundCallback> PAY_RESULT_CALLBACK_MAP = new ConcurrentHashMap<>(1024);
|
||||||
|
|
||||||
|
public static void putReply(Event event) {
|
||||||
|
String data = event.getData();
|
||||||
|
RefundReply payment = JSON.parseObject(data, RefundReply.class);
|
||||||
|
Assert.hasText(payment.getPaymentId(), "paymentId is blank !!!");
|
||||||
|
RefundCallback callback = PAY_RESULT_CALLBACK_MAP.remove(payment.getPaymentId());
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onReply(payment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void putCallback(String paymentId, RefundCallback callback) {
|
||||||
|
Assert.hasText(paymentId, "paymentId is blank !!!");
|
||||||
|
Assert.notNull(callback, "RefundCallback is null !!!");
|
||||||
|
PAY_RESULT_CALLBACK_MAP.put(paymentId, callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue