package com.yz.commons.settlement.channel.ali;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
@Slf4j
@Service("ALI_APP_PAY")
public class AliAppPay implements PayFacade {
private final ApplicationProperties applicationProperties;
private final ChargeOrderRepository chargeOrderRepository;
private final PayAccountConfigRepository payAccountConfigRepository;
private final StringRedisTemplate stringRedisTemplate;
private final PackagePayAccountRepository packagePayAccountRepository;
private final PackageInfoRepository packageInfoRepository;
private final NotifyUtil notifyUtil;
/**
* 账号缓存key
*/
private final String configKey = "pay_config";
public AliAppPay (ApplicationProperties applicationProperties, ChargeOrderRepository chargeOrderRepository,
PayAccountConfigRepository payAccountConfigRepository, StringRedisTemplate stringRedisTemplate,
PackagePayAccountRepository packagePayAccountRepository, NotifyUtil notifyUtil, PackageInfoRepository packageInfoRepository) {
this.applicationProperties = applicationProperties;
this.chargeOrderRepository = chargeOrderRepository;
this.payAccountConfigRepository = payAccountConfigRepository;
this.stringRedisTemplate = stringRedisTemplate;
this.packagePayAccountRepository = packagePayAccountRepository;
this.notifyUtil = notifyUtil;
this.packageInfoRepository = packageInfoRepository;
}
/**
* 支付宝订单统一下单
* @param payPreParam
* @return
*/
@Override
public PayPreResult unifiedOrder(PayPreParam payPreParam) {
PayPreResult payPreResult = new PayPreResult();
payPreResult.setOrderNo(payPreParam.getOrderNo());
payPreResult.setOrderStatus(GoldFlowStatus.SUCCESS);
payPreResult.setPayChannel(payPreParam.getPayChannelCode());
PayAccountConfig payAccountConfig = payPreParam.getPayAccountConfig();
String orderNo = payPreParam.getOrderNo();
AttachParam attachParam = payPreParam.getAttachParam();
String body = attachParam.getBody();
// 分, 需要转换成元
Long orderAmount = payPreParam.getOrderAmount();
String amount = new BigDecimal(orderAmount).divide(new BigDecimal("100")).toString();
//1 实例化客户端
AlipayClient alipayClient = getAlipayClient(payAccountConfig);
//2 实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
//3 SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setSubject(body);
model.setOutTradeNo(orderNo);
// 超时时间十五分钟
model.setTimeoutExpress("15m");
model.setTotalAmount(amount);
model.setProductCode("QUICK_MSECURITY_PAY");
request.setBizModel(model);
request.setNotifyUrl(notifyUtil.getNotifyUrl(payPreParam.getAttachParam().getPackageName(), ChargeOrderType.ALI_APP_PAY));
try {
//这里和普通的接口调用不同,使用的是sdkExecute
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
payPreResult.setPayInfo(response.getBody());
} catch (AlipayApiException e) {
e.printStackTrace();
payPreResult.setOrderStatus(GoldFlowStatus.REJECT);
payPreResult.setPayInfo("");
}
return payPreResult;
}
/**
* 订单查询
* @param payQueryParam
* @return
*/
@Override
public PayQueryResult orderQuery(PayQueryParam payQueryParam) {
PayQueryResult payQueryResult = new PayQueryResult();
payQueryResult.setOrderStatus(GoldFlowStatus.PROCESSING);
payQueryResult.setPayMsg("请求状态未知");
String orderNo = payQueryParam.getOrderNo();
PayAccountConfig payAccountConfig = payQueryParam.getPayAccountConfig();
AlipayClient alipayClient = getAlipayClient(payAccountConfig);
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
request.setBizContent("{\"out_trade_no\": " + orderNo + "}");
try {
AlipayTradeQueryResponse response = alipayClient.execute(request);
if (response.isSuccess()) {
String tradeStatus = response.getTradeStatus();
if ("TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus)){
payQueryResult.setOrderStatus(GoldFlowStatus.SUCCESS);
} else if ("TRADE_CLOSED".equals(tradeStatus)) {
payQueryResult.setOrderStatus(GoldFlowStatus.REJECT);
}
}
} catch (AlipayApiException e) {
e.printStackTrace();
}
return payQueryResult;
}
/**
* 支付宝回调
* @param verifyParam
* @return
*/
@Override
public VerifyResult orderVerify(VerifyParam verifyParam) {
VerifyResult verifyResult = new VerifyResult();
verifyResult.setOrderStatus(GoldFlowStatus.PROCESSING);
verifyResult.setResponseStr("failure");
Map<String, Object> parameterMap = verifyParam.getParameterMap();
Map<String,String> newMap = mapConvert(parameterMap);
String orderNo = newMap.get("out_trade_no");
ChargeOrder repository = chargeOrderRepository.findByOrderNo(orderNo);
String aliPublicKey = getAliPublicKey(repository.getPackageName(), repository.getCtype());
verifyResult.setOrderNo(orderNo);
try {
boolean isVerfied = AlipaySignature.rsaCheckV1(newMap, aliPublicKey, "UTF-8", SystemContants.ALI_SIGN_TYPE);
if (isVerfied) {
// 延签成功
String orderStatus = newMap.get("trade_status");
if ("TRADE_SUCCESS".equals(orderStatus) || "TRADE_FINISHED".equals(orderStatus)){
verifyResult.setOrderStatus(GoldFlowStatus.SUCCESS);
verifyResult.setResponseStr("success");
// 支付包订单金额为元,转化成分
String totalAmount = newMap.get("total_amount");
Long orderAmount = new BigDecimal(totalAmount).multiply(new BigDecimal("100")).longValue();
verifyResult.setOrderAmount(orderAmount);
} else if ("TRADE_CLOSED".equals(orderStatus)){
verifyResult.setOrderStatus(GoldFlowStatus.REJECT);
verifyResult.setResponseStr("success");
}
} else {
log.error("ali order verify check sign append error : {}", orderNo);
}
} catch (AlipayApiException e) {
e.printStackTrace();
}
return verifyResult;
}
private AlipayClient getAlipayClient(PayAccountConfig payAccountConfig){
AlipayClient alipayClient = new DefaultAlipayClient(applicationProperties.getPay().getAliAppPayUrl(),
payAccountConfig.getAppId(),
payAccountConfig.getAliPrivateKey(),
"json", "UTF-8",
payAccountConfig.getAliPublicKey(),
SystemContants.ALI_SIGN_TYPE);
return alipayClient;
}
/**
* 转换Map
* @param map
* @return
*/
private static Map<String, String> mapConvert(Map<String , Object> map){
Map<String, String> resultMap = new HashMap<>();
for (String key : map.keySet()) {
resultMap.put(key, map.get(key)+"");
}
return resultMap;
}
private String getAliPublicKey(String packageName, String plant) {
PayAccountConfig payAccountConfig;
Object configObj = stringRedisTemplate.opsForHash().get(configKey, packageName + "." + plant);
if (null != configObj) {
payAccountConfig = JSONObject.parseObject(configObj.toString(), PayAccountConfig.class);
return payAccountConfig.getAliPublicKey();
} else {
PackageInfo packageInfo = packageInfoRepository.findByPackageName(packageName);
PackagePayAccount packagePayAccount = packagePayAccountRepository.findByPackageIdAndPlant(packageInfo.getId(), plant);
Optional<PayAccountConfig> optional = payAccountConfigRepository.findById(packagePayAccount.getAccountId());
payAccountConfig = optional.get();
payAccountConfig.setPlant(plant);
payAccountConfig.setPackageName(packageName);
return payAccountConfig.getAliPublicKey();
}
}
}