diff --git a/accompany-base/accompany-payment/accompany-payment-sdk/src/main/java/com/accompany/payment/payermax/params/PayCallbackReqVo.java b/accompany-base/accompany-payment/accompany-payment-sdk/src/main/java/com/accompany/payment/payermax/params/PayCallbackReqVo.java index 1589e55f7..43fd37931 100644 --- a/accompany-base/accompany-payment/accompany-payment-sdk/src/main/java/com/accompany/payment/payermax/params/PayCallbackReqVo.java +++ b/accompany-base/accompany-payment/accompany-payment-sdk/src/main/java/com/accompany/payment/payermax/params/PayCallbackReqVo.java @@ -1,12 +1,9 @@ package com.accompany.payment.payermax.params; -import lombok.Data; - import java.io.IOException; -import java.io.Serializable; @lombok.Data -public class PayCallbackReqVo implements Serializable { +public class PayCallbackReqVo { /** * 商户app id */ @@ -38,7 +35,7 @@ public class PayCallbackReqVo implements Serializable { private String notifyType; @lombok.Data - public static class Order implements Serializable { + public class Order { /** * 渠道订单号 */ @@ -93,7 +90,7 @@ public class PayCallbackReqVo implements Serializable { private String tradeToken; @lombok.Data - public static class PaymentDetail implements Serializable { + public class PaymentDetail { /** * 卡信息 */ @@ -125,7 +122,7 @@ public class PayCallbackReqVo implements Serializable { /** * 交易状态:SUCCESS-支付成功,FAILED -支付失败,CLOSED-关单 */ - public static enum Status implements Serializable{ + public enum Status { CLOSED, FAILED, SUCCESS; public String toValue() { diff --git a/accompany-business/accompany-business-web/src/main/java/com/accompany/business/controller/apppay/PayermaxPayController.java b/accompany-business/accompany-business-web/src/main/java/com/accompany/business/controller/apppay/PayermaxPayController.java index 7bd2b6f25..527a477ba 100644 --- a/accompany-business/accompany-business-web/src/main/java/com/accompany/business/controller/apppay/PayermaxPayController.java +++ b/accompany-business/accompany-business-web/src/main/java/com/accompany/business/controller/apppay/PayermaxPayController.java @@ -1,30 +1,28 @@ package com.accompany.business.controller.apppay; import com.accompany.business.service.ChargeService; +import com.accompany.common.constant.Constant; import com.accompany.common.redis.RedisKey; +import com.accompany.common.result.BusiResult; import com.accompany.common.status.BusiStatus; +import com.accompany.common.utils.DateTimeUtil; import com.accompany.core.exception.ServiceException; import com.accompany.payment.constant.PayConstant; import com.accompany.payment.model.ChargeRecord; -import com.accompany.payment.payermax.config.PayermaxConfig; -import com.accompany.payment.payermax.params.PayCallbackReqVO; +import com.accompany.payment.payermax.params.PayCallbackReqVo; import com.accompany.payment.service.ChargeRecordService; -import com.accompany.payment.utils.PayermaxUtils; import com.alibaba.fastjson.JSONObject; +import com.payermax.sdk.client.DefaultPayermaxClient; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletRequest; import java.math.BigDecimal; -import java.util.Calendar; -import java.util.HashMap; -import java.util.Map; +import java.time.LocalDateTime; import java.util.concurrent.TimeUnit; /** @@ -43,100 +41,74 @@ public class PayermaxPayController { @Autowired private ChargeService chargeService; @Autowired - private PayermaxConfig payermaxConfig; - @Autowired private RedissonClient redissonClient; - private final static Integer TRADE_STATUS_SUCCESS = 1; - private final static Integer TRADE_STATUS_FAIL = 2; + @PostMapping("/callback") + public BusiResult callback(HttpServletRequest request, + @RequestBody PayCallbackReqVo payCallbackReqVo) { + String sign = request.getHeader("sign"); + String paramsString = JSONObject.toJSONString(payCallbackReqVo); + log.info("[payermax] 接受回调参数为:{}",paramsString); -// @RequestMapping(value = "/callback", method = RequestMethod.POST) -// public Map callback(@RequestBody PayCallbackReqVO payCallbackReqVO) { -// log.info("start handle payermax pay notification"); -// String paramsString = JSONObject.toJSONString(payCallbackReqVO); -// log.info("payermax接受回调参数为:{}",paramsString); -// Map map = new HashMap<>(); -// -// //1.1 Verify signature -// Map param = JSONObject.parseObject(paramsString, Map.class); -// //Use the test environment link: secretKey needs to be secretKey for the test environment -// //Use the production environment link: the secretKey needs to be secretKey for the production environment -// boolean result = PayermaxUtils.verifyForMD5(param, payCallbackReqVO.getSign(), payermaxConfig.getSecretKey()); -// -// if (!result) { -// //1.2 Verify signature failure -// //default response format without modify -// map.put("bizCode", "400"); -// map.put("message", "Signature verification failure"); -// return map; -// } -// -// String chargeRecordId = payCallbackReqVO.getOrderId(); -// -// if (!TRADE_STATUS_SUCCESS.equals(payCallbackReqVO.getStatus())) { -// log.warn("【payermax支付回调】订单 {} 支付状态不是成功,忽略。", chargeRecordId); -// map.put("bizCode", "0000"); -// map.put("message", "success"); -// return map; -// } -// -// String lockKey = RedisKey.lock_pay_callback_notify.getKey(chargeRecordId); -// RLock lock = redissonClient.getLock(lockKey); -// boolean isLocked = false; -// try { -// isLocked = lock.tryLock(5L, TimeUnit.SECONDS); -// if (!isLocked){ -// log.error("【payermax支付回调】加锁失败 chargeRecordId: {}", chargeRecordId); -// throw new ServiceException(BusiStatus.SERVER_BUSY); -// } -// -// ChargeRecord chargeRecord = chargeRecordService.getChargeRecordById(chargeRecordId); -// if (chargeRecord == null) { -// log.warn("【payermax支付回调】订单 {} 不存在", chargeRecordId); -// map.put("bizCode", "500"); -// map.put("message", "charge order not exsists"); -// return map; -// } -// if (StringUtils.isBlank(payCallbackReqVO.getCurrency()) || !payCallbackReqVO.getCurrency().equalsIgnoreCase(chargeRecord.getLocalCurrencyCode())) { -// log.warn("【payermax支付回调】回调的货币代码为空或与订单 {} 中的 {} 不匹配", chargeRecordId, chargeRecord.getLocalCurrencyCode()); -// map.put("bizCode", "500"); -// map.put("message", "charge currency error"); -// return map; -// } -// Long payAmount = new BigDecimal(payCallbackReqVO.getPayAmount()).multiply(PayConstant.HUNDRED).longValue(); -// // 校验金额 -// boolean validateAmount = payAmount.equals(chargeRecord.getLocalAmount()); -// if (!validateAmount) { -// log.warn("【payermax支付回调】订单 {} 金额 {} 校验失败", chargeRecordId, payAmount); -// map.put("bizCode", "500"); -// map.put("message", "total amount error"); -// return map; -// } -// chargeRecord.setCountry(payCallbackReqVO.getCountryCode()); -// chargeRecord.setLocalCurrencyCode(payCallbackReqVO.getPayCurrency()); -// chargeRecord.setLocalAmount(payAmount); -// -// chargeRecord.setPingxxChargeId(payCallbackReqVO.getTradeOrderNo()); -// chargeRecord.setUpdateTime(Calendar.getInstance().getTime()); -// -// chargeService.updateAppPayData(chargeRecord); -// -// //3 Return success -// //default response format without modify -// map.put("bizCode", "0000"); -// map.put("message", "success"); -// return map; -// } catch (Exception e) { -// //4 Return exception -// //default response format without modify -// map.put("bizCode", "500"); -// map.put("message", "Exception happened " + e.getMessage()); -// return map; -// } finally { -// if (isLocked || lock.isLocked()){ -// lock.unlock(); -// } -// } -// } + if (!DefaultPayermaxClient.getInstance().verifyNotification(paramsString, sign)) { + log.error("[payermax] 验签失败"); + return BusiResult.success(); + } + + PayCallbackReqVo.Order order = payCallbackReqVo.getData(); + String chargeRecordId = order.getOutTradeNo(); + + if (!PayCallbackReqVo.Status.SUCCESS.equals(order.getStatus())) { + log.warn("[payermax] 支付回调 订单 {} 支付状态不是成功,忽略。", chargeRecordId); + return BusiResult.success(); + } + + String lockKey = RedisKey.lock_pay_callback_notify.getKey(chargeRecordId); + RLock lock = redissonClient.getLock(lockKey); + boolean isLocked = false; + try { + isLocked = lock.tryLock(5L, TimeUnit.SECONDS); + if (!isLocked){ + log.error("[payermax] 支付回调 加锁失败 chargeRecordId: {}", chargeRecordId); + throw new ServiceException(BusiStatus.SERVER_BUSY); + } + + ChargeRecord chargeRecord = chargeRecordService.getChargeRecordById(chargeRecordId); + if (null == chargeRecord || !Constant.ChargeRecordStatus.create.equals(chargeRecord.getChargeStatus())) { + log.warn("[payermax] 支付回调 订单 {} 不存在", chargeRecordId); + return BusiResult.success(); + } + + if (StringUtils.isBlank(order.getCurrency()) || !order.getCurrency().equalsIgnoreCase(chargeRecord.getLocalCurrencyCode())) { + log.warn("[payermax] 支付回调 回调的货币代码为空或与订单 {} 中的 {} 不匹配", chargeRecordId, chargeRecord.getLocalCurrencyCode()); + return BusiResult.success(); + } + Long payAmount = BigDecimal.valueOf(order.getTotalAmount()).multiply(PayConstant.HUNDRED).longValue(); + // 校验金额 + boolean validateAmount = payAmount.equals(chargeRecord.getLocalAmount()); + if (!validateAmount) { + log.warn("[payermax] 支付回调 订单 {} 金额 {} 校验失败", chargeRecordId, payAmount); + return BusiResult.success(); + } + chargeRecord.setCountry(order.getCountry()); + chargeRecord.setLocalCurrencyCode(order.getCurrency()); + chargeRecord.setLocalAmount(payAmount); + + chargeRecord.setPingxxChargeId(order.getTradeToken()); + chargeRecord.setUpdateTime(DateTimeUtil.converLocalDateTimeToDate(LocalDateTime.parse(order.getCompleteTime()))); + + chargeService.updateAppPayData(chargeRecord); + + return BusiResult.success(); + } catch (Exception e) { + //todo log + log.error("{}", e); + return BusiResult.fail(BusiStatus.SERVERERROR); + } finally { + if (isLocked || lock.isLocked()){ + lock.unlock(); + } + } + } }