package com.example.demo.serviceImpl.cash; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.example.demo.domain.DTO.*; 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.*; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestTemplate; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.math.BigDecimal; import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.*; /** * @program: gold-java * @ClassName BankServiceImpl * @description: * @author: Double * @create: 2025−11-21 10:46 * @Version 1.0 **/ @Service @Slf4j public class BankServiceImpl implements BankService { @Autowired private CashCollectionMapper cashCollectionMapper; // 第三方API地址 private static final String API_URL = "https://gateway.pa-sys.com/v1.1/reconciliation/519e26b2-8145-418c-b3e7-c1e88e52b946/settlement"; // 签名密钥 private static final String SECRET = "8987d1b8-1d82-4b15-af06-828d0b12076f"; // 注入RestTemplate用于HTTP请求(需在Spring配置类中定义) private final RestTemplate restTemplate; public BankServiceImpl(RestTemplate restTemplate) { this.restTemplate = restTemplate; } //payment银行接口(单个) @Override public Result getPayment(BankDTO bankDTO) { try { // 1. 准备参数 String settlementDate = bankDTO.getTime(); // 从BankDTO对象获取time作为settlement_date String network = "FPS"; // 固定值 // 2. 生成签名 Map params = new TreeMap<>(); // 按key升序排序 params.put("settlement_date", settlementDate); params.put("network", network); String signSource = buildQueryString(params) + SECRET; String sign = sha512(signSource); // 3. 构建form-data请求参数 MultiValueMap formData = new LinkedMultiValueMap<>(); formData.add("settlement_date", settlementDate); formData.add("network", network); formData.add("sign", sign); // 4. 发送HTTP POST请求(优化:显式设置multipart/form-data的字符集) HttpHeaders headers = new HttpHeaders(); // 补充charset=UTF-8,避免部分服务器对编码敏感 headers.setContentType(new MediaType("multipart", "form-data", StandardCharsets.UTF_8)); HttpEntity> requestEntity = new HttpEntity<>(formData, headers); // 调用第三方API(使用配置好SSL协议的RestTemplate) ResponseEntity response = restTemplate.exchange( API_URL, HttpMethod.POST, requestEntity, String.class ); if (response.getStatusCode().is2xxSuccessful()) { String responseBody = response.getBody(); log.info("第三方API响应: {}", responseBody); // 解析JSON获取payload.transactions数组 JSONObject jsonObject = JSON.parseObject(responseBody); JSONArray transactions = jsonObject.getJSONObject("payload").getJSONArray("transactions"); // 创建BankDTO并设置paymentDTOList BankVO bankVO = new BankVO(); List paymentDTOList; try { paymentDTOList = transactions.toJavaList(PaymentDTO.class); } catch (Exception e) { log.error("解析JSON响应时发生错误: {}", e.getMessage(), e); return Result.error("payment当天无数据请切换日期"); } bankVO.setPaymentDTOList(paymentDTOList); // 获取订单号 String orderNo = bankDTO.getOrderNo(); // 如果订单号不为空,则进行匹配查找 if (orderNo != null && !orderNo.isEmpty()) { boolean found = false; for (PaymentDTO paymentDTO : paymentDTOList) { if (orderNo.equals(paymentDTO.getMerchant_reference())) { SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); paymentDTO.setTime(sdf.parse(bankDTO.getTime())); 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("港币HKD"); bankVO.setPaymentDTO(paymentDTO); found = true; break; } } // 如果没有找到匹配的订单号,返回提示信息 if (!found) { log.info("当前日期 {} 该订单号 {} 未查到", settlementDate, orderNo); // 可以根据业务需求进行相应处理,比如抛出异常或设置特定标识 return Result.error("payment当前日期 " + settlementDate + " 该订单号 " + orderNo + " 未查到"); } } CashCollection cashCollection = cashCollectionMapper.selectByGoldCoinOrderCode(orderNo); if (cashCollection == null) { return Result.error("金币系统当前日期 " + settlementDate + " 该订单号 " + orderNo + " 未查到"); } else { cashCollectionMapper.updateByGoldCoinOrderCodeByPayment(bankVO.getPaymentDTO()); } return Result.success(bankVO); } else { throw new RuntimeException("API请求失败,状态码: " + response.getStatusCodeValue()); } } catch (Exception e) { log.error("payment银行接口处理失败", e); throw new RuntimeException("处理失败: " + e.getMessage()); } } //payment银行接口(批量) @Override public Result paymentAuto(BankDTO bankDTO) { try { // 1. 准备参数 String settlementDate = bankDTO.getTime(); // 从BankDTO对象获取time作为settlement_date String network = "FPS"; // 固定值 // 2. 生成签名 Map params = new TreeMap<>(); // 按key升序排序 params.put("settlement_date", settlementDate); params.put("network", network); String signSource = buildQueryString(params) + SECRET; String sign = sha512(signSource); // 3. 构建form-data请求参数 MultiValueMap formData = new LinkedMultiValueMap<>(); formData.add("settlement_date", settlementDate); formData.add("network", network); formData.add("sign", sign); // 4. 发送HTTP POST请求(优化:显式设置multipart/form-data的字符集) HttpHeaders headers = new HttpHeaders(); // 补充charset=UTF-8,避免部分服务器对编码敏感 headers.setContentType(new MediaType("multipart", "form-data", StandardCharsets.UTF_8)); HttpEntity> requestEntity = new HttpEntity<>(formData, headers); // 调用第三方API(使用配置好SSL协议的RestTemplate) ResponseEntity response = restTemplate.exchange( API_URL, HttpMethod.POST, requestEntity, String.class ); if (response.getStatusCode().is2xxSuccessful()) { String responseBody = response.getBody(); log.info("第三方API响应: {}", responseBody); // 解析JSON获取payload.transactions数组 JSONObject jsonObject = JSON.parseObject(responseBody); JSONArray transactions = jsonObject.getJSONObject("payload").getJSONArray("transactions"); // 创建BankVO并设置paymentDTOList BankVO bankVO = new BankVO(); List paymentDTOList; try { paymentDTOList = transactions.toJavaList(PaymentDTO.class); } catch (Exception e) { log.error("解析JSON响应时发生错误: {}", e.getMessage(), e); return Result.error("payment当天无数据请切换日期"); } bankVO.setPaymentDTOList(paymentDTOList); // 收集处理信息 List messages = new ArrayList<>(); // 对paymentDTOList中的每个元素进行处理 List 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("港币HKD"); // 获取订单号 String orderNo = paymentDTO.getMerchant_reference(); List orderNoList = cashCollectionMapper.selectStripeList(); // 检查当前订单号是否在列表中 if (orderNoList.contains(orderNo)) { cashCollectionMapper.updateByGoldCoinOrderCodeByPayment(paymentDTO); processedPayments.add(paymentDTO); log.info("成功处理订单: {}", orderNo); messages.add("成功处理订单: " + orderNo); } else { log.warn("金币系统中未找到订单: {}", orderNo); messages.add("金币系统中未找到订单: " + orderNo); } } catch (Exception e) { messages.add("处理单个支付记录时发生错误: " + paymentDTO.getMerchant_reference() + ",错误信息: " + e.getMessage()); log.error("处理单个支付记录时发生错误: {}", paymentDTO.getMerchant_reference(), e); } } // 设置处理成功的支付列表 bankVO.setPaymentDTOList(processedPayments); bankVO.setMessage(messages); return Result.success(bankVO); } else { throw new RuntimeException("API请求失败,状态码: " + response.getStatusCodeValue()); } } catch (Exception e) { log.error("payment银行接口处理失败", e); throw new RuntimeException("处理失败: " + e.getMessage()); } } //stripe银行接口(批量) @Override public Result stripeAuto(BankDTO bankDTO) { try { // 设置Stripe API密钥 Stripe.apiKey = "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"; if (bankDTO.getSum() <= 0) { return Result.error("最大条数不能小于等于0"); } // 收集处理信息 List messages = new ArrayList<>(); // 从Stripe获取最近的收费记录(最多200条) List allCharges = new ArrayList<>(); String startingAfter = null; int totalLimit = bankDTO.getSum(); // 目标获取条数 int pageSize = 100; // 单次最大获取条数 do { // 计算当前页需查询的条数(最后一页可能不足100条) int currentPageSize = Math.min(pageSize, totalLimit - allCharges.size()); if (currentPageSize <= 0) { break; // 已获取足够条数,停止 } Long startTime = LocalDate.parse(bankDTO.getStartTime(), DateTimeFormatter.ofPattern("yyyyMMdd")).atStartOfDay(ZoneId.of("Asia/Shanghai")).toEpochSecond(); Long endTime = LocalDate.parse(bankDTO.getEndTime(), DateTimeFormatter.ofPattern("yyyyMMdd")).atStartOfDay(ZoneId.of("Asia/Shanghai")).toEpochSecond(); ChargeListParams.Created createdCondition = ChargeListParams.Created.builder() .setGte(startTime) // 大于等于开始时间 .setLt(endTime) // 小于结束时间 .build(); ChargeListParams params = ChargeListParams.builder() .setLimit((long) currentPageSize) .setStartingAfter(startingAfter) .setCreated(createdCondition) // 加入时间筛选 .build(); try { // 执行分页查询 ChargeCollection charges = Charge.list(params); List 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); // 创建StripeDTO列表用于存储所有处理后的数据 List stripeDTOList = new ArrayList<>(); // 处理每一条Stripe数据 for (Charge charge : allCharges) { try { // 获取charge对应的余额交易ID String balanceTransactionId = charge.getBalanceTransaction(); // 通过余额交易ID获取详细信息 BalanceTransaction balanceTransaction = BalanceTransaction.retrieve(balanceTransactionId); // 创建StripeDTO对象并填充所需数据点 StripeDTO stripeDTO = new StripeDTO(); // 从metadata中获取订单号 if (charge.getMetadata() != null) { stripeDTO.setOrderNo(charge.getMetadata().get("order_no")); } // 设置余额交易ID stripeDTO.setBalanceTransaction(charge.getBalanceTransaction()); // 设置付款币种和金额(来自charge) stripeDTO.setCurrency(charge.getCurrency().toUpperCase()); stripeDTO.setAmount(String.valueOf(balanceTransaction.getAmount())); // 设置收款币种(来自charge) stripeDTO.setChargeCurrency(charge.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); } // 添加到列表中 stripeDTOList.add(stripeDTO); // 如果订单号存在,且在selectStripeList返回的列表中,则更新数据库中的记录 if (stripeDTO.getOrderNo() != null && !stripeDTO.getOrderNo().isEmpty()) { // 获取需要处理的订单号列表 List orderNoList = cashCollectionMapper.selectStripeList(); // 检查当前订单号是否在列表中 if (orderNoList.contains(stripeDTO.getOrderNo())) { cashCollectionMapper.updateByGoldCoinOrderCodeByStripe(stripeDTO); } } messages.add("成功处理订单: " + stripeDTO.getOrderNo()); } catch (Exception e) { log.error("处理Stripe数据失败,chargeId: " + charge.getId(), e); // 继续处理其他数据,不中断整个流程 } } // 创建响应VO对象 BankVO bankVO = new BankVO(); bankVO.setStripeDTOList(stripeDTOList); bankVO.setMessage(messages); return Result.success(bankVO); } catch (Exception e) { log.error("stripe银行接口处理失败", e); throw new RuntimeException("处理失败: " + e.getMessage()); } } //stripe银行接口(单个) @Override public Result getStripe(BankDTO bankDTO) throws StripeException { try { // 设置Stripe API密钥 Stripe.apiKey = "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"; // 方式一:通过订单号查找最近数据 String orderNo = bankDTO.getOrderNo(); if (bankDTO.getSum() <= 0) { return Result.error("最大条数不能小于等于0"); } // 从Stripe获取最近的收费记录(最多200条) List allCharges = new ArrayList<>(); String startingAfter = null; int totalLimit = bankDTO.getSum(); // 目标获取条数 int pageSize = 100; // 单次最大获取条数 do { // 计算当前页需查询的条数(最后一页可能不足100条) int currentPageSize = Math.min(pageSize, totalLimit - allCharges.size()); if (currentPageSize <= 0) { break; // 已获取足够条数,停止 } Long startTime = LocalDate.parse(bankDTO.getStartTime(), DateTimeFormatter.ofPattern("yyyyMMdd")).atStartOfDay(ZoneId.of("Asia/Shanghai")).toEpochSecond(); Long endTime = LocalDate.parse(bankDTO.getEndTime(), DateTimeFormatter.ofPattern("yyyyMMdd")).atStartOfDay(ZoneId.of("Asia/Shanghai")).toEpochSecond(); ChargeListParams.Created createdCondition = ChargeListParams.Created.builder() .setGte(startTime) // 大于等于开始时间 .setLt(endTime) // 小于结束时间 .build(); ChargeListParams params = ChargeListParams.builder() .setLimit((long) currentPageSize) .setStartingAfter(startingAfter) .setCreated(createdCondition) // 加入时间筛选 .build(); try { // 执行分页查询 ChargeCollection charges = Charge.list(params); List 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; System.out.println(allCharges); 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 + " 的支付记录"); } // 获取匹配到的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和来自balanceTransaction) stripeDTO.setCurrency(matchedCharge.getCurrency().toUpperCase()); stripeDTO.setAmount(String.valueOf(balanceTransaction.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()); } } //firstdata银行接口(批量) @Override public Result firstdataAuto(BankDTO bankDTO) { // 获取需要处理的订单号列表 List orderNoList = cashCollectionMapper.selectFirstdataList(); // 存储处理结果的列表 List results = new ArrayList<>(); // 对每个订单执行getFirstdata方法 for (String orderNo : orderNoList) { // 创建一个新的BankDTO实例,设置订单号 BankDTO dto = new BankDTO(); dto.setOrderNo(orderNo); // 调用getFirstdata方法处理单个订单 Result result = getFirstdata(dto); results.add(result); } // 返回处理结果列表 return Result.success(results); } //firstdata银行接口(单个) @Override public Result getFirstdata(BankDTO bankDTO) { try { CashCollection cashCollection = cashCollectionMapper.selectByBankCode(bankDTO.getOrderNo()); if (cashCollection == null) { return Result.error("金币系统当前日期 " + " 该银行订单号 " + bankDTO.getOrderNo() + " 未查到"); } // 获取签名参数 FirstdataRequestDTO firstdataRequestDTO = generatePaymentAsiaSignature(); // 构建请求URL,使用bankDTO中的orderNo String orderNo = bankDTO.getOrderNo(); String url = "https://prod.api.firstdata.com/gateway/v2/payments/" + orderNo + "?storeId=4530056594"; // 使用RestTemplate发送GET请求 HttpHeaders headers = new HttpHeaders(); headers.set("accept", "application/json"); headers.set("Client-Request-Id", String.valueOf(firstdataRequestDTO.getClientRequestId())); headers.set("Api-Key", firstdataRequestDTO.getKey()); headers.set("Timestamp", String.valueOf(firstdataRequestDTO.getTime())); headers.set("Message-Signature", firstdataRequestDTO.getHmacBase64()); headers.set("User-Agent", "Apifox/1.0.0 (https://apifox.com)"); headers.set("Content-Type", "application/json"); headers.set("Host", "prod.api.firstdata.com"); headers.set("Connection", "keep-alive"); HttpEntity entity = new HttpEntity<>(headers); ResponseEntity response = restTemplate.exchange( url, HttpMethod.GET, entity, String.class ); // 解析响应数据 // API返回的是对象格式,需要先解析为JSONObject JSONObject jsonObject = JSON.parseObject(response.getBody()); // 创建BankVO对象并设置数据 BankVO bankVO = new BankVO(); List message = new ArrayList<>(); // 检查jsonObject是否为空或者是否包含错误信息 if (jsonObject != null && !jsonObject.isEmpty()) { // 提取需要的字段 String country = jsonObject.getString("country"); String orderId = jsonObject.getString("orderId"); // 提取currency和total JSONObject transactionAmount = jsonObject.getJSONObject("transactionAmount"); String currency = transactionAmount != null ? transactionAmount.getString("currency") : null; Integer total = transactionAmount != null ? transactionAmount.getInteger("total") : null; // 创建FirstdataDTO对象并存储数据 FirstdataDTO firstdataDTO = new FirstdataDTO(); firstdataDTO.setCountry(country); firstdataDTO.setOrderId(orderId); firstdataDTO.setCurrency(currency); firstdataDTO.setTotal(total); // 根据要求设置amount为永久金币×100 Integer amount = cashCollection.getPermanentGold(); firstdataDTO.setAmount(amount); // 根据国家计算fee double feeValue; if ("Singapore".equals(country)) { // 新加坡:amount的值×百分之2.8加上20保留整数四舍五入 feeValue = Math.round(amount * 0.028 + 20); } else { // 其他国家:amount的值×百分之3加20 feeValue = Math.round(amount * 0.03 + 20); } firstdataDTO.setFee((int) feeValue); // net的值为amount减去fee firstdataDTO.setNet(amount - (int) feeValue); // 将firstdataDTO存入bankVO bankVO.setFirstdataDTO(firstdataDTO); // 创建一个简单的Map来存储提取的数据 Map extractedData = new HashMap<>(); extractedData.put("country", country); extractedData.put("orderId", orderId); extractedData.put("currency", currency); extractedData.put("total", total); extractedData.put("amount", amount); extractedData.put("fee", (int) feeValue); extractedData.put("net", amount - (int) feeValue); extractedData.put("success", true); // 添加成功标识 // 将提取的数据转换为JSON字符串并添加到message列表 message.add(JSON.toJSONString(extractedData, true)); // 将message存入bankVO bankVO.setMessage(message); cashCollectionMapper.updateByGoldCoinOrderCodeByFirstdata(bankVO.getFirstdataDTO()); return Result.success(bankVO); } else { // 没有数据时也添加失败标识 Map emptyData = new HashMap<>(); emptyData.put("success", false); emptyData.put("message", "No data found"); message.add(JSON.toJSONString(emptyData, true)); // 将message存入bankVO bankVO.setMessage(message); return Result.error("No data found"); } } catch (Exception e) { log.error("Firstdata银行接口调用失败", e); // 在异常情况下也构建包含错误信息的message BankVO bankVO = new BankVO(); List message = new ArrayList<>(); Map errorData = new HashMap<>(); errorData.put("success", false); errorData.put("error", e.getMessage()); message.add(JSON.toJSONString(errorData, true)); bankVO.setMessage(message); return Result.error("Firstdata银行接口调用失败: " + e.getMessage()); } } //IPAY银行接口(批量) @Override public Result ipayAuto(BankDTO bankDTO) { // 获取需要处理的订单号列表 List cashCollections = cashCollectionMapper.selectIpayList(); BankVO bankVO = new BankVO(); List message = new ArrayList<>(); // 对每个订单执行getFirstdata方法 for (CashCollection cashCollection : cashCollections) { // 创建一个新的BankDTO实例,设置订单号 Ipay88DTO ipay88DTO = new Ipay88DTO(); ipay88DTO.setOrderNo(cashCollection.getOrderCode()); // 将double先转为int再转为string double amountDouble = cashCollection.getPermanentGold() * 3.18; int amountInt = (int) amountDouble; ipay88DTO.setAmount(String.valueOf(amountInt)); double feeDouble = cashCollection.getPermanentGold() * 3.18 * 0.0085; int feeInt = (int) feeDouble; ipay88DTO.setFee(String.valueOf(feeInt)); double netDouble = cashCollection.getPermanentGold() * 3.18 - cashCollection.getPermanentGold() * 3.18 * 0.0085; int netInt = (int) netDouble; ipay88DTO.setNet(String.valueOf(netInt)); cashCollectionMapper.updateByGoldCoinOrderCodeByIpay88(ipay88DTO); // 构建成功消息 Map successData = new HashMap<>(); successData.put("success", true); successData.put("orderNo", ipay88DTO.getOrderNo()); successData.put("amount", ipay88DTO.getAmount()); successData.put("fee", ipay88DTO.getFee()); successData.put("net", ipay88DTO.getNet()); message.add(JSON.toJSONString(successData, true)); } // 将message存入bankVO bankVO.setMessage(message); // 返回处理结果列表 return Result.success(bankVO); } // 银行自动处理接口(每天早上6点执行) @Scheduled(cron = "0 53 10 * * ?") @Override public Result bankAuto() { try { // 生成昨天的日期,格式为yyyyMMdd DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd"); LocalDate sevenDayAgo = LocalDate.now().minusDays(7); String sevenDayAgoStr = sevenDayAgo.format(formatter); LocalDate sixDayAgo = LocalDate.now().minusDays(6); String sixDayAgoStr = sixDayAgo.format(formatter); LocalDate fiveDayAgo = LocalDate.now().minusDays(5); String fiveDayAgoStr = fiveDayAgo.format(formatter); LocalDate fourDayAgo = LocalDate.now().minusDays(4); String fourDayAgoStr = fourDayAgo.format(formatter); LocalDate threeDayAgo = LocalDate.now().minusDays(3); String threeDayAgoStr = threeDayAgo.format(formatter); LocalDate twoDayAgo = LocalDate.now().minusDays(2); String twoDayAgoStr = twoDayAgo.format(formatter); LocalDate oneDayAgo = LocalDate.now().minusDays(1); String oneDayAgoStr = oneDayAgo.format(formatter); LocalDate today = LocalDate.now(); String todayStr = today.format(formatter); // 创建BankDTO实例并设置时间 BankDTO dto = new BankDTO(); dto.setStartTime(fiveDayAgoStr); dto.setEndTime(todayStr); dto.setTime(sixDayAgoStr); dto.setSum(1000); // 依次调用各个自动处理方法 Result paymentResult = paymentAuto(dto); Result stripeResult = stripeAuto(dto); Result firstdataResult = firstdataAuto(dto); Result ipayResult = ipayAuto(dto); // 创建响应VO对象并收集处理结果 BankVO bankVO = new BankVO(); List messages = new ArrayList<>(); // 收集各方法的处理结果信息 messages.add("Payment Auto Result: " + (paymentResult != null ? paymentResult.toString() : "null")); messages.add("Stripe Auto Result: " + (stripeResult != null ? stripeResult.toString() : "null")); messages.add("Firstdata Auto Result: " + (firstdataResult != null ? firstdataResult.toString() : "null")); messages.add("Ipay Auto Result: " + (ipayResult != null ? ipayResult.toString() : "null")); bankVO.setMessage(messages); return Result.success(bankVO); } catch (Exception e) { log.error("bankAuto执行失败", e); return Result.error("bankAuto执行失败: " + e.getMessage()); } } /** * 生成PaymentAsia API所需的签名 * * @return 签名字符串 */ public FirstdataRequestDTO generatePaymentAsiaSignature() { try { String key = "3E04ZUCKFmQKrW0uoBa89QKIJWYoU9OX"; String secret = "ZLtBPgfMIT4HXg25SoVuCyUQZ6GtSv9UFmDmYaoVSKS"; // 生成ClientRequestId(1-10000000的随机数) long clientRequestId = new Random().nextInt(10000000) + 1; // 获取当前时间戳(毫秒) long time = System.currentTimeMillis(); // 构造原始签名数据 String rawSignature = key + clientRequestId + time; // 计算HMAC-SHA256 Mac sha256Hmac = Mac.getInstance("HmacSHA256"); SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"); sha256Hmac.init(secretKey); byte[] hmacBytes = sha256Hmac.doFinal(rawSignature.getBytes(StandardCharsets.UTF_8)); // 转换为Base64编码 String hmacBase64 = Base64.getEncoder().encodeToString(hmacBytes); // 赋值给DTO FirstdataRequestDTO firstdataRequestDTO = new FirstdataRequestDTO(); firstdataRequestDTO.setKey(key); firstdataRequestDTO.setSecret(secret); firstdataRequestDTO.setClientRequestId(clientRequestId); firstdataRequestDTO.setTime(time); firstdataRequestDTO.setHmacBase64(hmacBase64); // Base64编码并返回签名 return firstdataRequestDTO; } catch (Exception e) { throw new RuntimeException("生成PaymentAsia签名失败", e); } } /** * http_build_query的查询字符串(key=value&key=value) */ private String buildQueryString(Map params) { StringBuilder sb = new StringBuilder(); for (Map.Entry 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'); } hexStr.append(hex); } return hexStr.toString(); } }