diff --git a/ghy-common/src/main/java/com/ghy/common/adapay/AdapayService.java b/ghy-common/src/main/java/com/ghy/common/adapay/AdapayService.java index 82e4f35a..5bcdad17 100644 --- a/ghy-common/src/main/java/com/ghy/common/adapay/AdapayService.java +++ b/ghy-common/src/main/java/com/ghy/common/adapay/AdapayService.java @@ -1,8 +1,12 @@ package com.ghy.common.adapay; 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.model.Payment; +import com.huifu.adapay.model.Refund; import lombok.Setter; import lombok.extern.slf4j.Slf4j; @@ -19,15 +23,40 @@ public class AdapayService { AdapayProperties adapayProperties; /** - * @param callback 处理支付结果的回调接口 - * @param orderNo 订单号 - * @param payAmt 支付金额 - * @param goodsTittle 商品名称 - * @param goodsDesc 商品描述 + * 发起退款 + * 当您的业务需要发起退款时,可通过 Adapay 系统提供的创建 Refund对象 方法创建一个退款对象,资金会原路退回用户的支付宝或微信中。 + * 支持一次全额或多次部分退款,退款次数最多不超过10次。多次部分退款时,当前退款金额 + 已退款金额不能大于原支付金额。 + * 对于每次撤销交易,Adapay 都会通过 异步消息通知 告知结果。 + * 退款对象同步返回成功,表示Adapay受理成功,退款结果以异步通知为准。支持退款最长时间为178天, + * 若返回码是“order_id_not_exists 订单记录不存在”,既超过退款期限,无法退款成功。 + * + * @param callback [必填项]处理退款结果的回调接口 + * @param paymentId [必填项]支付确认对象的id + * @param refundOrderNo [必填项]订单号 + * @param refundAmt [必填项]退款金额,若退款金额小于原交易金额,则认为是部分退款,必须大于0,保留两位小数点,如0.10、100.05等 + * @return 同步返回一个 退款对象 + */ + public Map refund(RefundCallback callback, String paymentId, String refundOrderNo, String refundAmt) throws BaseAdaPayException { + Map 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 订单附加说明 + * @return 同步返回一个 支付对象 Payment */ public Map wxLitePay(PayCallback callback, String orderNo, String payAmt, String goodsTittle, String goodsDesc, String description) throws BaseAdaPayException { - Map paymentParams = new HashMap<>(10); + Map paymentParams = new HashMap<>(16); paymentParams.put("app_id", adapayProperties.getAppId()); paymentParams.put("notify_url", adapayProperties.getNotifyUrl()); paymentParams.put("order_no", orderNo); @@ -36,8 +65,29 @@ public class AdapayService { paymentParams.put("goods_title", goodsTittle); paymentParams.put("goods_desc", goodsDesc); paymentParams.put("description", description); - PayResultMapping.putCallback(orderNo, callback); + PayReplyMapping.putCallback(orderNo, callback); return Payment.create(paymentParams); } + /** + * 支付关单 + * 针对已经创建的 支付对象,您可以调用关单接口进行交易的关闭。调用此接口后,该用户订单将不再能支付成功。 对于关单功能的使用有如下规则: + * 1.存在关单记录,不能再次关单 + * 2.交易时间 1分钟 内无法关单成功 + * 3.正扫交易时间超过 2小时 无法关单成功 + * 4.支付宝正扫接口,如果用户没有扫码,订单不能关闭成功(二维码给用户展示,如果用户没有用手机去扫码,那这笔就不能关单; 如果用户扫过了的话(无需支付成功)就可以关单了)—-微信正扫无此条限制 + * 5.网银和快捷类交易都不支持关单操作 + * + * @param paymentId [必填项]由 Adapay 生成的支付对象 id + * @param reason 关单描述 + * @param expend 扩展域 + */ + public Map close(String paymentId, String reason, String expend) throws BaseAdaPayException { + Map paymentParams = new HashMap<>(4); + paymentParams.put("payment_id", paymentId); + paymentParams.put("reason", reason); + paymentParams.put("expend", expend); + return Payment.close(paymentParams); + } + } \ No newline at end of file diff --git a/ghy-common/src/main/java/com/ghy/common/adapay/callback/AdapayCallbackController.java b/ghy-common/src/main/java/com/ghy/common/adapay/callback/AdapayCallbackController.java index c5eebe74..92cd784f 100644 --- a/ghy-common/src/main/java/com/ghy/common/adapay/callback/AdapayCallbackController.java +++ b/ghy-common/src/main/java/com/ghy/common/adapay/callback/AdapayCallbackController.java @@ -1,6 +1,7 @@ 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.util.AdapaySign; import lombok.extern.slf4j.Slf4j; @@ -40,7 +41,11 @@ public class AdapayCallbackController { switch (type) { case "payment.succeeded": case "payment.failed": - PayResultMapping.putResult(event); + PayReplyMapping.putReply(event); + break; + case "payment.close.succeeded": + case "payment.close.failed": + RefundReplyMapping.putReply(event); break; default: log.warn("UNKNOWN EVENT TYPE [{}]", type); diff --git a/ghy-common/src/main/java/com/ghy/common/adapay/callback/Event.java b/ghy-common/src/main/java/com/ghy/common/adapay/callback/Event.java index 269d7949..eb065525 100644 --- a/ghy-common/src/main/java/com/ghy/common/adapay/callback/Event.java +++ b/ghy-common/src/main/java/com/ghy/common/adapay/callback/Event.java @@ -34,7 +34,8 @@ public class Event { */ private String type; /** - * 支付对象 + * Adapay回调接口传过来的数据,内容为JSON字符串 + * 不同的Event事件有不同的data */ private String data; } \ No newline at end of file diff --git a/ghy-common/src/main/java/com/ghy/common/adapay/callback/PayCallback.java b/ghy-common/src/main/java/com/ghy/common/adapay/callback/PayCallback.java index 35800b94..7a5bff90 100644 --- a/ghy-common/src/main/java/com/ghy/common/adapay/callback/PayCallback.java +++ b/ghy-common/src/main/java/com/ghy/common/adapay/callback/PayCallback.java @@ -1,6 +1,6 @@ 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 { - void onResponse(Payment payment); + void onReply(PayReply reply); } \ No newline at end of file diff --git a/ghy-common/src/main/java/com/ghy/common/adapay/callback/RefundCallback.java b/ghy-common/src/main/java/com/ghy/common/adapay/callback/RefundCallback.java new file mode 100644 index 00000000..899cabed --- /dev/null +++ b/ghy-common/src/main/java/com/ghy/common/adapay/callback/RefundCallback.java @@ -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); +} diff --git a/ghy-common/src/main/java/com/ghy/common/adapay/callback/model/PayReply.java b/ghy-common/src/main/java/com/ghy/common/adapay/callback/model/PayReply.java new file mode 100644 index 00000000..aa1a1604 --- /dev/null +++ b/ghy-common/src/main/java/com/ghy/common/adapay/callback/model/PayReply.java @@ -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; +} diff --git a/ghy-common/src/main/java/com/ghy/common/adapay/callback/model/RefundReply.java b/ghy-common/src/main/java/com/ghy/common/adapay/callback/model/RefundReply.java new file mode 100644 index 00000000..32b502c7 --- /dev/null +++ b/ghy-common/src/main/java/com/ghy/common/adapay/callback/model/RefundReply.java @@ -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; + +} diff --git a/ghy-common/src/main/java/com/ghy/common/adapay/PayResultMapping.java b/ghy-common/src/main/java/com/ghy/common/adapay/callback/reply/PayReplyMapping.java similarity index 78% rename from ghy-common/src/main/java/com/ghy/common/adapay/PayResultMapping.java rename to ghy-common/src/main/java/com/ghy/common/adapay/callback/reply/PayReplyMapping.java index 4b13ce03..65f9991b 100644 --- a/ghy-common/src/main/java/com/ghy/common/adapay/PayResultMapping.java +++ b/ghy-common/src/main/java/com/ghy/common/adapay/callback/reply/PayReplyMapping.java @@ -1,9 +1,9 @@ -package com.ghy.common.adapay; +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.PayCallback; -import com.huifu.adapay.model.Payment; +import com.ghy.common.adapay.callback.model.PayReply; import org.springframework.util.Assert; import java.util.concurrent.ConcurrentHashMap; @@ -13,7 +13,7 @@ import java.util.concurrent.ConcurrentHashMap; * * @author HH 2022/3/25 */ -public class PayResultMapping { +public class PayReplyMapping { /** * 临时保存支付结果 @@ -22,13 +22,13 @@ public class PayResultMapping { */ private final static ConcurrentHashMap PAY_RESULT_CALLBACK_MAP = new ConcurrentHashMap<>(1024); - public static void putResult(Event event) { + public static void putReply(Event event) { 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 !!!"); PayCallback callback = PAY_RESULT_CALLBACK_MAP.remove(payment.getOrderNo()); if (callback != null) { - callback.onResponse(payment); + callback.onReply(payment); } } diff --git a/ghy-common/src/main/java/com/ghy/common/adapay/callback/reply/RefundReplyMapping.java b/ghy-common/src/main/java/com/ghy/common/adapay/callback/reply/RefundReplyMapping.java new file mode 100644 index 00000000..68340a6a --- /dev/null +++ b/ghy-common/src/main/java/com/ghy/common/adapay/callback/reply/RefundReplyMapping.java @@ -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 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); + } +}