diff --git a/accompany-base/accompany-core/src/main/java/com/accompany/common/constant/Constant.java b/accompany-base/accompany-core/src/main/java/com/accompany/common/constant/Constant.java index 86f313991..eec540ed6 100644 --- a/accompany-base/accompany-core/src/main/java/com/accompany/common/constant/Constant.java +++ b/accompany-base/accompany-core/src/main/java/com/accompany/common/constant/Constant.java @@ -487,6 +487,8 @@ public class Constant { public static final String my_card = "MyCard"; // StartPay public static final String start_pay = "start_pay"; + // razer + public static final String razer = "razer"; } diff --git a/accompany-base/accompany-payment/accompany-payment-service/src/main/java/com/accompany/payment/razer/RazerPayConfig.java b/accompany-base/accompany-payment/accompany-payment-service/src/main/java/com/accompany/payment/razer/RazerPayConfig.java new file mode 100644 index 000000000..24fabc9c3 --- /dev/null +++ b/accompany-base/accompany-payment/accompany-payment-service/src/main/java/com/accompany/payment/razer/RazerPayConfig.java @@ -0,0 +1,17 @@ +package com.accompany.payment.razer; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties("razer") +@Data +public class RazerPayConfig { + private String createUrl;//下单url + private String returnUrl; + private String callbackUrl; + private String applicationCode; + private String secretKey; + +} diff --git a/accompany-base/accompany-payment/accompany-payment-service/src/main/java/com/accompany/payment/razer/RazerPayResDTO.java b/accompany-base/accompany-payment/accompany-payment-service/src/main/java/com/accompany/payment/razer/RazerPayResDTO.java new file mode 100644 index 000000000..8646da885 --- /dev/null +++ b/accompany-base/accompany-payment/accompany-payment-service/src/main/java/com/accompany/payment/razer/RazerPayResDTO.java @@ -0,0 +1,19 @@ +package com.accompany.payment.razer; + +import lombok.Data; + +@Data +public class RazerPayResDTO { + private String applicationCode; + private String referenceId; + private String version; + private Long amount; + private String currencyCode; + private String paymentId; + private String paymentUrl; + private String hashType; + private String signature; + private String paymentStatusCode; + private String paymentStatusDate; + private Long virtualCurrencyAmount; +} diff --git a/accompany-base/accompany-payment/accompany-payment-service/src/main/java/com/accompany/payment/razer/RazerPayService.java b/accompany-base/accompany-payment/accompany-payment-service/src/main/java/com/accompany/payment/razer/RazerPayService.java new file mode 100644 index 000000000..ba0f68dcc --- /dev/null +++ b/accompany-base/accompany-payment/accompany-payment-service/src/main/java/com/accompany/payment/razer/RazerPayService.java @@ -0,0 +1,100 @@ +package com.accompany.payment.razer; + +import com.accompany.common.utils.HttpUtils; +import com.accompany.payment.model.ChargeProd; +import com.accompany.payment.model.ChargeRecord; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.*; + +@Slf4j +@Service +public class RazerPayService { + + @Autowired + private RazerPayConfig razerPayConfig; + + public RazerPayResDTO createOrder(ChargeRecord chargeRecord, ChargeProd chargeProd, String successUrl) { + try { + Map formMap = new HashMap<>(); + String applicationCode = razerPayConfig.getApplicationCode(); + formMap.put("applicationCode", applicationCode); + String referenceId = chargeRecord.getChargeRecordId(); + formMap.put("referenceId", referenceId); + String version = "v1"; + formMap.put("version", version); + long amount = chargeRecord.getAmount(); + formMap.put("amount", String.valueOf(amount)); + String currencyCode = chargeProd.getLocalCurrencyCode(); + formMap.put("currencyCode", currencyCode); + String returnUrl = successUrl; + formMap.put("returnUrl", returnUrl); + String callbackUrl = razerPayConfig.getCallbackUrl(); + formMap.put("callbackUrl", callbackUrl); + Long customerId = chargeRecord.getUid(); + formMap.put("customerId", String.valueOf(customerId)); + String description = chargeProd.getChargeGoldNum() + "Gold"; + formMap.put("description", description); + + String hashType = "hmac-sha256"; + formMap.put("hashType", hashType); + if (!"razer".equals(chargeRecord.getPaymentType())){ + formMap.put("channelId",chargeRecord.getPaymentType()); + } + String signStr = formatMapToSignStr(formMap); + String signature = signature(signStr); + formMap.put("signature", signature); + Map headerMap = new HashMap<>(); + headerMap.put("Content-Type", "application/x-www-form-urlencoded"); + log.info("post :{}", JSON.toJSONString(formMap)); + String resultBody = HttpUtils.doPost(razerPayConfig.getCreateUrl(), formMap, headerMap); + log.info("RazerPayService.createOrder resultBody:{}", resultBody); + RazerPayResDTO result = JSONObject.parseObject(resultBody, RazerPayResDTO.class); + return result; + } catch (NoSuchAlgorithmException e) { + log.error("RazerPayService.createOrder:e:{}", e); + } catch (InvalidKeyException e) { + log.error("RazerPayService.createOrder:e:{}", e); + } catch (IOException e) { + log.error("RazerPayService.createOrder:e:{}", e); + } + return new RazerPayResDTO(); + } + + public String formatMapToSignStr(Map paramMap) { + Map tmpMap = paramMap; + List> infoIds = new ArrayList(tmpMap.entrySet()); + Collections.sort(infoIds, (Comparator) (o1, o2) -> (((Map.Entry) o1).getKey()).toString().compareTo(((Map.Entry) o2).getKey())); + StringBuffer buf = new StringBuffer(); + for (Map.Entry item : infoIds) { + if ((!StringUtils.isEmpty(item.getKey())) + && (!("signature".equals(item.getKey())))) { + buf.append(item.getValue()); + } + } + return buf.toString(); + } + + public String signature(String signStr) throws NoSuchAlgorithmException, InvalidKeyException { + Mac hmac = Mac.getInstance("HmacSHA256"); + SecretKeySpec keySpec = new SecretKeySpec(razerPayConfig.getSecretKey().getBytes(StandardCharsets.UTF_8), "HmacSHA256"); + hmac.init(keySpec); + byte[] hmacBytes = hmac.doFinal(signStr.getBytes(StandardCharsets.UTF_8)); + StringBuilder stringBuilder = new StringBuilder(); + for(byte b : hmacBytes) { + stringBuilder.append(String.format("%02x",b)); + } + return stringBuilder.toString(); + } +} diff --git a/accompany-base/accompany-payment/accompany-payment-service/src/main/java/com/accompany/payment/service/ChargeRecordService.java b/accompany-base/accompany-payment/accompany-payment-service/src/main/java/com/accompany/payment/service/ChargeRecordService.java index aa71c76bf..5d61f7d4b 100644 --- a/accompany-base/accompany-payment/accompany-payment-service/src/main/java/com/accompany/payment/service/ChargeRecordService.java +++ b/accompany-base/accompany-payment/accompany-payment-service/src/main/java/com/accompany/payment/service/ChargeRecordService.java @@ -33,6 +33,11 @@ public class ChargeRecordService extends BaseService { return chargeRecordMapper.selectByPrimaryKey(chargeRecordId); } + public void updateChargeRecord(ChargeRecord record) { + record.setUpdateTime(new Date()); + chargeRecordMapper.updateByPrimaryKey(record); + } + public List listChargeRecordByPingXXId(List pingxxIdList) { ChargeRecordExample example = new ChargeRecordExample(); example.createCriteria().andPingxxChargeIdIn(pingxxIdList); diff --git a/accompany-base/accompany-payment/accompany-payment-service/src/main/java/com/accompany/payment/strategy/RazerStrategy.java b/accompany-base/accompany-payment/accompany-payment-service/src/main/java/com/accompany/payment/strategy/RazerStrategy.java new file mode 100644 index 000000000..f4815eab4 --- /dev/null +++ b/accompany-base/accompany-payment/accompany-payment-service/src/main/java/com/accompany/payment/strategy/RazerStrategy.java @@ -0,0 +1,50 @@ +package com.accompany.payment.strategy; + +import com.accompany.common.constant.Constant; +import com.accompany.core.base.UidContextHolder; +import com.accompany.payment.annotation.PayChannelSupport; +import com.accompany.payment.constant.ChargeUserLimitConstant; +import com.accompany.payment.constant.PayConstant; +import com.accompany.payment.model.ChargeProd; +import com.accompany.payment.model.ChargeRecord; +import com.accompany.payment.payermax.PayermaxService; +import com.accompany.payment.payermax.dto.CreateOrderResDTO; +import com.accompany.payment.payermax.params.CreateOrderParams; +import com.accompany.payment.razer.RazerPayResDTO; +import com.accompany.payment.razer.RazerPayService; +import com.accompany.payment.service.ChargeUserLimitService; +import com.accompany.payment.utils.CommonPayUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.HashMap; +import java.util.Map; + +@Service +@PayChannelSupport(Constant.ChargeChannel.razer) +public class RazerStrategy extends AbstractPayStrategy { + + private final String SPILT_PREFIX = "-"; + + @Autowired + private ChargeUserLimitService chargeUserLimitService; + + @Autowired + private RazerPayService razerPayService; + + @Override + public Object pay(PayContext context) throws Exception { + chargeUserLimitService.chargeLimitCheck(UidContextHolder.get(), ChargeUserLimitConstant.LIMIT_TYPE_OF_H5); + ChargeRecord chargeRecord = context.getChargeRecord(); + ChargeProd chargeProd = context.getChargeProd(); + RazerPayResDTO orderRes = razerPayService.createOrder(chargeRecord, chargeProd, context.getSuccessUrl()); + chargeRecord.setPingxxChargeId(orderRes.getPaymentId()); + Map appMap = new HashMap<>(); + appMap.put(PayConstant.H5_PAY_URL_FIELD, orderRes.getPaymentUrl()); + appMap.put(PayConstant.H5_PAY_NICK_FIELD, context.getNick()); + appMap.put(PayConstant.H5_PAY_ERBANNO_FIELD, context.getErbanNo()); + return appMap; + } +} diff --git a/accompany-business/accompany-business-web/src/main/java/com/accompany/business/controller/apppay/RazerPayController.java b/accompany-business/accompany-business-web/src/main/java/com/accompany/business/controller/apppay/RazerPayController.java new file mode 100644 index 000000000..3a63747b9 --- /dev/null +++ b/accompany-business/accompany-business-web/src/main/java/com/accompany/business/controller/apppay/RazerPayController.java @@ -0,0 +1,104 @@ +package com.accompany.business.controller.apppay; + +import com.accompany.business.service.ChargeService; +import com.accompany.common.constant.Constant; +import com.accompany.common.status.BusiStatus; +import com.accompany.core.exception.ServiceException; +import com.accompany.payment.model.ChargeRecord; +import com.accompany.payment.razer.RazerPayService; +import com.accompany.payment.service.ChargeRecordService; +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + + +@RestController +@RequestMapping("/payment/razer") +@Slf4j +public class RazerPayController { + + @Autowired + private ChargeRecordService chargeRecordService; + @Autowired + private ChargeService chargeService; + @Autowired + private RazerPayService razerPayService; + + @RequestMapping(value = "/callback", method = RequestMethod.POST) + public void callback(HttpServletRequest request) throws NoSuchAlgorithmException, InvalidKeyException, ParseException { + log.info("handle razerPay notification:request:{}", JSONObject.toJSONString(request.getParameterMap())); + // 创建一个Map来存储请求参数 + Map params = new HashMap<>(); + // 获取所有参数名 + Enumeration paramNames = request.getParameterNames(); + while (paramNames.hasMoreElements()) { + String paramName = paramNames.nextElement(); + // 获取参数值 + String paramValue = request.getParameter(paramName); + // 将参数名和值放入Map中 + params.put(paramName, paramValue); + } + log.info("RazerPayController:params:{}", params); + String signStr = razerPayService.formatMapToSignStr(params); + String signature = razerPayService.signature(signStr); + String paramSignature = params.get("signature"); + if (!signature.equals(paramSignature)) { + log.info("RazerPayController:signatureError,signStr:{},signature:{},paramSignature:{}", signStr, signature, paramSignature); + throw new ServiceException(BusiStatus.SERVERBUSY); + } + String chargeRecordId = params.get("referenceId"); + ChargeRecord chargeRecordById = + chargeRecordService.getChargeRecordById(chargeRecordId); + if (chargeRecordById == null) { + log.info("RazerPayController empty charge, chargeId:{}", chargeRecordId); + return; + } + if (Constant.ChargeRecordStatus.finish.equals(chargeRecordById.getChargeStatus())) { + log.info("RazerPayController charge finish, chargeId:{}", chargeRecordId); + return; + } + if (!Constant.ChargeRecordStatus.create.equals(chargeRecordById.getChargeStatus())) { + log.info("RazerPayController charge_status fail, charge:{}", JSONObject.toJSONString(chargeRecordById)); + return; + } + String paymentStatusCode = params.get("paymentStatusCode"); + if ("00".equals(paymentStatusCode)) { + String amount = params.get("amount"); + String currencyCode = params.get("currencyCode"); + Long amountValue = Long.valueOf(amount); + if (!chargeRecordById.getAmount().equals(amountValue) || !chargeRecordById.getLocalCurrencyCode().equals(currencyCode)) { + log.info("RazerPayController amount fail, chargeRecordId:{},chargeAmount:{}, callBackAmound:{}", + chargeRecordId, chargeRecordById.getAmount(), amount); + return; + } + String paymentId = params.get("paymentId"); + + chargeRecordById.setLocalCurrencyCode(currencyCode); + chargeRecordById.setLocalAmount(amountValue); + + chargeRecordById.setPingxxChargeId(paymentId); + String paymentStatusDate = params.get("paymentStatusDate"); + chargeRecordById.setUpdateTime(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").parse(paymentStatusDate)); + + chargeService.updateAppPayData(chargeRecordById); + } else { + chargeRecordById.setChargeStatus(Constant.ChargeRecordStatus.error); + chargeRecordById.setChargeDesc(paymentStatusCode); + chargeRecordService.updateChargeRecord(chargeRecordById); + } + log.info("end handle razer alipay notification"); + } + +}