|
|
|
@ -6,11 +6,18 @@ import com.alibaba.fastjson.JSONObject; |
|
|
|
import com.example.demo.Util.DateConvertUtil; |
|
|
|
import com.example.demo.domain.DTO.BankDTO; |
|
|
|
import com.example.demo.domain.DTO.PaymentDTO; |
|
|
|
import com.example.demo.domain.DTO.StripeDTO; |
|
|
|
import com.example.demo.domain.vo.cash.BankVO; |
|
|
|
import com.example.demo.domain.vo.cash.CashCollection; |
|
|
|
import com.example.demo.domain.vo.coin.Result; |
|
|
|
import com.example.demo.mapper.cash.CashCollectionMapper; |
|
|
|
import com.example.demo.service.cash.BankService; |
|
|
|
import com.stripe.Stripe; |
|
|
|
import com.stripe.exception.StripeException; |
|
|
|
import com.stripe.model.BalanceTransaction; |
|
|
|
import com.stripe.model.Charge; |
|
|
|
import com.stripe.model.ChargeCollection; |
|
|
|
import com.stripe.param.ChargeListParams; |
|
|
|
import lombok.extern.slf4j.Slf4j; |
|
|
|
import org.springframework.beans.factory.annotation.Autowired; |
|
|
|
import org.springframework.http.*; |
|
|
|
@ -19,14 +26,12 @@ import org.springframework.util.LinkedMultiValueMap; |
|
|
|
import org.springframework.util.MultiValueMap; |
|
|
|
import org.springframework.web.client.RestTemplate; |
|
|
|
|
|
|
|
import java.math.BigDecimal; |
|
|
|
import java.nio.charset.StandardCharsets; |
|
|
|
import java.security.MessageDigest; |
|
|
|
import java.security.NoSuchAlgorithmException; |
|
|
|
import java.text.SimpleDateFormat; |
|
|
|
import java.util.Date; |
|
|
|
import java.util.List; |
|
|
|
import java.util.Map; |
|
|
|
import java.util.TreeMap; |
|
|
|
import java.util.*; |
|
|
|
|
|
|
|
/** |
|
|
|
* @program: gold-java |
|
|
|
@ -113,9 +118,9 @@ public class BankServiceImpl implements BankService { |
|
|
|
if (orderNo.equals(paymentDTO.getMerchant_reference())) { |
|
|
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); |
|
|
|
paymentDTO.setTime(sdf.parse(bankDTO.getTime())); |
|
|
|
paymentDTO.setOrder_amount(paymentDTO.getOrder_amount()*100); |
|
|
|
paymentDTO.setCharge(paymentDTO.getCharge()*100); |
|
|
|
paymentDTO.setNet_amount(paymentDTO.getNet_amount()*100); |
|
|
|
paymentDTO.setOrder_amount(paymentDTO.getOrder_amount().multiply(BigDecimal.valueOf(100))); |
|
|
|
paymentDTO.setCharge(paymentDTO.getCharge().multiply(BigDecimal.valueOf(100))); |
|
|
|
paymentDTO.setNet_amount(paymentDTO.getNet_amount().multiply(BigDecimal.valueOf(100))); |
|
|
|
paymentDTO.setCurrency("2"); |
|
|
|
bankVO.setPaymentDTO(paymentDTO); |
|
|
|
found = true; |
|
|
|
@ -133,9 +138,8 @@ public class BankServiceImpl implements BankService { |
|
|
|
CashCollection cashCollection = cashCollectionMapper.selectByGoldCoinOrderCode(orderNo); |
|
|
|
if (cashCollection == null) { |
|
|
|
return Result.error("金币系统当前日期 " + settlementDate + " 该订单号 " + orderNo + " 未查到"); |
|
|
|
} |
|
|
|
else { |
|
|
|
cashCollectionMapper.updateByGoldCoinOrderCode(bankVO.getPaymentDTO()); |
|
|
|
} else { |
|
|
|
cashCollectionMapper.updateByGoldCoinOrderCodeByPayment(bankVO.getPaymentDTO()); |
|
|
|
} |
|
|
|
return Result.success(bankVO); |
|
|
|
} else { |
|
|
|
@ -191,10 +195,50 @@ public class BankServiceImpl implements BankService { |
|
|
|
JSONObject jsonObject = JSON.parseObject(responseBody); |
|
|
|
JSONArray transactions = jsonObject.getJSONObject("payload").getJSONArray("transactions"); |
|
|
|
|
|
|
|
// 创建BankDTO并设置paymentDTOList |
|
|
|
// 创建BankVO并设置paymentDTOList |
|
|
|
BankVO bankVO = new BankVO(); |
|
|
|
List<PaymentDTO> paymentDTOList = transactions.toJavaList(PaymentDTO.class); |
|
|
|
bankVO.setPaymentDTOList(paymentDTOList); |
|
|
|
// 收集处理信息 |
|
|
|
List<String> messages = new ArrayList<>(); |
|
|
|
// 对paymentDTOList中的每个元素进行处理 |
|
|
|
List<PaymentDTO> processedPayments = new ArrayList<>(); |
|
|
|
for (PaymentDTO paymentDTO : paymentDTOList) { |
|
|
|
try { |
|
|
|
|
|
|
|
// 格式化时间 |
|
|
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); |
|
|
|
paymentDTO.setTime(sdf.parse(settlementDate)); |
|
|
|
// 金额转换(假设原始数据是元为单位,需要转为分为单位) |
|
|
|
paymentDTO.setOrder_amount(paymentDTO.getOrder_amount().multiply(BigDecimal.valueOf(100))); |
|
|
|
paymentDTO.setCharge(paymentDTO.getCharge().multiply(BigDecimal.valueOf(100))); |
|
|
|
paymentDTO.setNet_amount(paymentDTO.getNet_amount().multiply(BigDecimal.valueOf(100))); |
|
|
|
// 设置货币代码 |
|
|
|
paymentDTO.setCurrency("2"); |
|
|
|
|
|
|
|
// 获取订单号 |
|
|
|
String orderNo = paymentDTO.getMerchant_reference(); |
|
|
|
|
|
|
|
// 查询金币系统中的订单 |
|
|
|
CashCollection cashCollection = cashCollectionMapper.selectByGoldCoinOrderCode(orderNo); |
|
|
|
if (cashCollection != null) { |
|
|
|
// 更新金币系统中的订单信息 |
|
|
|
cashCollectionMapper.updateByGoldCoinOrderCodeByPayment(paymentDTO); |
|
|
|
processedPayments.add(paymentDTO); |
|
|
|
log.info("成功处理订单: {}", orderNo); |
|
|
|
messages.add("成功处理订单: " + orderNo); |
|
|
|
} else { |
|
|
|
log.warn("金币系统中未找到订单: {}", orderNo); |
|
|
|
messages.add("金币系统中未找到订单: " + orderNo); |
|
|
|
} |
|
|
|
} catch (Exception e) { |
|
|
|
log.error("处理单个支付记录时发生错误: {}", paymentDTO.getMerchant_reference(), e); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 设置处理成功的支付列表 |
|
|
|
bankVO.setPaymentDTOList(processedPayments); |
|
|
|
bankVO.setMessage(messages); |
|
|
|
|
|
|
|
return Result.success(bankVO); |
|
|
|
} else { |
|
|
|
@ -210,44 +254,157 @@ public class BankServiceImpl implements BankService { |
|
|
|
//stripe银行接口(批量) |
|
|
|
@Override |
|
|
|
public Result stripeAuto(BankDTO bankDTO) { |
|
|
|
return Result.success(bankDTO); |
|
|
|
return Result.success(bankDTO); |
|
|
|
} |
|
|
|
|
|
|
|
//stripe银行接口(单个) |
|
|
|
@Override |
|
|
|
public Result getStripe(BankDTO bankDTO) { |
|
|
|
return Result.success(bankDTO); |
|
|
|
} |
|
|
|
public Result getStripe(BankDTO bankDTO) throws StripeException { |
|
|
|
try { |
|
|
|
// 设置Stripe API密钥 |
|
|
|
Stripe.apiKey = "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"; |
|
|
|
// 方式一:通过订单号查找最近数据 |
|
|
|
String orderNo = bankDTO.getOrderNo(); |
|
|
|
|
|
|
|
/** |
|
|
|
* http_build_query的查询字符串(key=value&key=value) |
|
|
|
*/ |
|
|
|
private String buildQueryString(Map<String, String> params) { |
|
|
|
StringBuilder sb = new StringBuilder(); |
|
|
|
for (Map.Entry<String, String> entry : params.entrySet()) { |
|
|
|
if (sb.length() > 0) { |
|
|
|
sb.append("&"); |
|
|
|
if (orderNo == null || orderNo.isEmpty()) { |
|
|
|
return Result.error("订单号为空"); |
|
|
|
} |
|
|
|
|
|
|
|
// 从Stripe获取最近的收费记录(最多200条) |
|
|
|
List<Charge> allCharges = new ArrayList<>(); |
|
|
|
String startingAfter = null; |
|
|
|
int totalLimit = 200; // 目标获取条数 |
|
|
|
int pageSize = 100; // 单次最大获取条数 |
|
|
|
|
|
|
|
do { |
|
|
|
// 计算当前页需查询的条数(最后一页可能不足100条) |
|
|
|
int currentPageSize = Math.min(pageSize, totalLimit - allCharges.size()); |
|
|
|
if (currentPageSize <= 0) { |
|
|
|
break; // 已获取足够条数,停止 |
|
|
|
} |
|
|
|
|
|
|
|
// 构建分页参数 |
|
|
|
ChargeListParams params = ChargeListParams.builder() |
|
|
|
.setLimit((long) currentPageSize) |
|
|
|
.setStartingAfter(startingAfter) |
|
|
|
.build(); |
|
|
|
|
|
|
|
try { |
|
|
|
// 执行分页查询 |
|
|
|
ChargeCollection charges = Charge.list(params); |
|
|
|
List<Charge> currentPageData = charges.getData(); |
|
|
|
allCharges.addAll(currentPageData); |
|
|
|
|
|
|
|
// 更新分页游标:若有下一页且未达200条,继续 |
|
|
|
boolean hasMore = charges.getHasMore() && allCharges.size() < totalLimit; |
|
|
|
startingAfter = hasMore ? currentPageData.get(currentPageData.size() - 1).getId() : null; |
|
|
|
|
|
|
|
} catch (StripeException e) { |
|
|
|
log.error("Stripe 分页查询失败:" + e.getMessage()); |
|
|
|
break; // 异常时停止查询,返回已获取的数据 |
|
|
|
} |
|
|
|
|
|
|
|
} while (startingAfter != null); |
|
|
|
|
|
|
|
// 在获取的所有记录中查找匹配订单号的记录 |
|
|
|
Charge matchedCharge = null; |
|
|
|
for (Charge charge : allCharges) { |
|
|
|
// 从metadata中获取订单号进行匹配 |
|
|
|
if (charge.getMetadata() != null) { |
|
|
|
String chargeOrderNo = charge.getMetadata().get("order_no"); |
|
|
|
if (chargeOrderNo != null && orderNo.equals(chargeOrderNo)) { |
|
|
|
matchedCharge = charge; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 如果未找到匹配的订单,返回错误信息 |
|
|
|
if (matchedCharge == null) { |
|
|
|
return Result.error("未找到订单号 " + orderNo + " 的支付记录"); |
|
|
|
} |
|
|
|
sb.append(entry.getKey()).append("=").append(entry.getValue()); |
|
|
|
|
|
|
|
// 获取匹配到的charge对应的余额交易ID |
|
|
|
String balanceTransactionId = matchedCharge.getBalanceTransaction(); |
|
|
|
|
|
|
|
// 通过余额交易ID获取详细信息 |
|
|
|
BalanceTransaction balanceTransaction = BalanceTransaction.retrieve(balanceTransactionId); |
|
|
|
|
|
|
|
// 创建StripeDTO对象并填充所需数据点 |
|
|
|
StripeDTO stripeDTO = new StripeDTO(); |
|
|
|
// 设置订单号 |
|
|
|
stripeDTO.setOrderNo(matchedCharge.getMetadata().get("order_no")); |
|
|
|
// 设置余额交易ID |
|
|
|
stripeDTO.setBalanceTransaction(matchedCharge.getBalanceTransaction()); |
|
|
|
|
|
|
|
// 设置付款币种和金额(来自charge) |
|
|
|
stripeDTO.setCurrency(matchedCharge.getCurrency().toUpperCase()); |
|
|
|
stripeDTO.setAmount(String.valueOf(matchedCharge.getAmount())); |
|
|
|
|
|
|
|
// 设置收款币种(来自charge) |
|
|
|
stripeDTO.setChargeCurrency(matchedCharge.getCurrency().toUpperCase()); |
|
|
|
|
|
|
|
// 设置到账金额和手续费(来自balanceTransaction) |
|
|
|
stripeDTO.setNet(String.valueOf(balanceTransaction.getNet())); |
|
|
|
stripeDTO.setFee(String.valueOf(balanceTransaction.getFee())); |
|
|
|
|
|
|
|
// 设置到账币种(来自balanceTransaction) |
|
|
|
stripeDTO.setCurrency(balanceTransaction.getCurrency().toUpperCase()); |
|
|
|
|
|
|
|
// 设置available_on日期 |
|
|
|
if (balanceTransaction.getAvailableOn() != null) { |
|
|
|
long availableOnInSeconds = balanceTransaction.getAvailableOn(); |
|
|
|
// 将Unix时间戳转换为Date对象 |
|
|
|
Date availableOnDate = new Date(availableOnInSeconds * 1000L); |
|
|
|
stripeDTO.setAvailableOn(availableOnDate); |
|
|
|
} |
|
|
|
|
|
|
|
// 创建响应VO对象 |
|
|
|
BankVO bankVO = new BankVO(); |
|
|
|
bankVO.setStripeDTO(stripeDTO); |
|
|
|
CashCollection cashCollection = cashCollectionMapper.selectByGoldCoinOrderCode(orderNo); |
|
|
|
if (cashCollection == null) { |
|
|
|
return Result.error("金币系统当前日期 " + " 该订单号 " + orderNo + " 未查到"); |
|
|
|
} else { |
|
|
|
cashCollectionMapper.updateByGoldCoinOrderCodeByStripe(bankVO.getStripeDTO()); |
|
|
|
} |
|
|
|
return Result.success(bankVO); |
|
|
|
} catch (Exception e) { |
|
|
|
log.error("stripe银行接口处理失败", e); |
|
|
|
throw new RuntimeException("处理失败: " + e.getMessage()); |
|
|
|
} |
|
|
|
return sb.toString(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* SHA512加密 |
|
|
|
*/ |
|
|
|
private String sha512(String content) throws NoSuchAlgorithmException { |
|
|
|
MessageDigest md = MessageDigest.getInstance("SHA-512"); |
|
|
|
byte[] bytes = md.digest(content.getBytes(StandardCharsets.UTF_8)); |
|
|
|
// 转换为十六进制字符串 |
|
|
|
StringBuilder hexStr = new StringBuilder(); |
|
|
|
for (byte b : bytes) { |
|
|
|
String hex = Integer.toHexString(0xff & b); |
|
|
|
if (hex.length() == 1) { |
|
|
|
hexStr.append('0'); |
|
|
|
} |
|
|
|
hexStr.append(hex); |
|
|
|
* http_build_query的查询字符串(key=value&key=value) |
|
|
|
*/ |
|
|
|
private String buildQueryString(Map<String, String> params) { |
|
|
|
StringBuilder sb = new StringBuilder(); |
|
|
|
for (Map.Entry<String, String> entry : params.entrySet()) { |
|
|
|
if (sb.length() > 0) { |
|
|
|
sb.append("&"); |
|
|
|
} |
|
|
|
sb.append(entry.getKey()).append("=").append(entry.getValue()); |
|
|
|
} |
|
|
|
return sb.toString(); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* SHA512加密 |
|
|
|
*/ |
|
|
|
private String sha512(String content) throws NoSuchAlgorithmException { |
|
|
|
MessageDigest md = MessageDigest.getInstance("SHA-512"); |
|
|
|
byte[] bytes = md.digest(content.getBytes(StandardCharsets.UTF_8)); |
|
|
|
// 转换为十六进制字符串 |
|
|
|
StringBuilder hexStr = new StringBuilder(); |
|
|
|
for (byte b : bytes) { |
|
|
|
String hex = Integer.toHexString(0xff & b); |
|
|
|
if (hex.length() == 1) { |
|
|
|
hexStr.append('0'); |
|
|
|
} |
|
|
|
return hexStr.toString(); |
|
|
|
hexStr.append(hex); |
|
|
|
} |
|
|
|
return hexStr.toString(); |
|
|
|
} |
|
|
|
} |