Compare commits
merge into: huangqizhen:master
huangqizhen:dev
huangqizhen:huangqizheng/feature-20250707173453-7.7bug修改
huangqizhen:huangqizheng/feature-20250708175155-7.8bug修复
huangqizhen:huangqizheng/feature-20250709163552-7.8导出传输对象修复
huangqizhen:huangqizheng/feature-20250710151401-数据同步完成
huangqizhen:huangqizheng/feature-20250714180618-数据同步
huangqizhen:huangqizheng/feature-20250715100115-非测试数据筛选
huangqizhen:huangqizheng/feature-20250717200321-优化导出
huangqizhen:huangqizheng/feature-20250718222252-导出修改完毕
huangqizhen:huangqizheng/feature-20250719105717-后端完毕
huangqizhen:huangqizheng/feature-20250721170818-后端周末修改
huangqizhen:huangqizheng/feature-20250722105318-BUG修改
huangqizhen:huangqizheng/feature-20250725144236-精简日志
huangqizhen:huangqizheng/feature-20250728134614-三期数据库配置
huangqizhen:huangqizheng/feature-20250731164458-地区部分修改以及导出的封装
huangqizhen:huangqizheng/feature-20250801114957-导出
huangqizhen:huangqizheng/feature-20250801180134-消费导出
huangqizhen:huangqizheng/feature-20250803175216-导出完毕
huangqizhen:huangqizheng/feature-20250804114811-打包配置
huangqizhen:huangqizheng/feature-20250805200446-配置修改及充值导出修改
huangqizhen:huangqizheng/feature-20250806120055-修复BUG
huangqizhen:huangqizheng/feature-20250808172612-bug修复
huangqizhen:huangqizheng/feature-20250809103653-修改配置导出重新上传
huangqizhen:huangqizheng/feature-20250809184038-研发部校验
huangqizhen:huangqizheng/feature-20251104113536-现金管理二期退款修改
huangqizhen:huangqizheng/feature-20251119150446-退款合并后
huangqizhen:huangqizheng/feature-20251203174217-冲刺计划
huangqizhen:huangqizheng/feature-20260106155423-红包修改
huangqizhen:lihuilin/hotfix-20250810160509-余额地区传参
huangqizhen:lihuilin/hotfix-20250815-审核默认更新时间
huangqizhen:lihuilin1015备份
huangqizhen:lijianlin/feature-20250623120104-工作台与审核
huangqizhen:lijianlin/feature-20250710152503-二期工作台与部分权限
huangqizhen:lijianlin/feature-20250728171217-三期金豆消费相关
huangqizhen:lijianlin/feature-202509231533026-现金管理-收款管理
huangqizhen:lijianlin/feature-20251104110749-现金管理二期
huangqizhen:lijianlin/feature-20251209-现金管理三期
huangqizhen:lijianlin/feature-20251211-fix
huangqizhen:master
huangqizhen:milestone-20250702-金币重构一期
huangqizhen:milestone-20250711-金币重构二期
huangqizhen:milestone-20250727-金币重构三期
huangqizhen:milestone-20251016-现金管理
huangqizhen:milestone-20251104-现金管理二期
huangqizhen:milestone-20251125-多语言
huangqizhen:milestone-20251203-冲刺计划
huangqizhen:milestone-20251205-消费
huangqizhen:milestone-20251209-多语言二期
huangqizhen:milestone-20251215-优化
huangqizhen:milestone-20251215-红包修改
huangqizhen:sunjiabei/feature-20250623130922-消费功能
huangqizhen:sunjiabei/feature-20250710132313-二期模块
huangqizhen:sunjiabei/feature-20250725135225-金币三期
huangqizhen:sunjiabei/feature-20250822111257-平台和商品id字段替换
huangqizhen:sunjiabei/feature-20250924164720-现金管理
huangqizhen:sunjiabei/feature-20251021102635-银行接口
huangqizhen:sunjiabei/feature-20251202094523-银行接口同步
huangqizhen:sunjiabei/feature-20251210111313-消费
huangqizhen:wangguorui/feature-20251125171605-现金管理多语言配置
huangqizhen:wangyetao/feature-20250628170337-汇率
huangqizhen:wangyetao/feature-20250715095107-地区数据权限
huangqizhen:yufenghao/feature-20251106105659-现金管理接口优化
huangqizhen:yufenghao1106
huangqizhen:工作流配置
pull from: huangqizhen:sunjiabei/feature-20251202094523-银行接口同步
huangqizhen:dev
huangqizhen:huangqizheng/feature-20250707173453-7.7bug修改
huangqizhen:huangqizheng/feature-20250708175155-7.8bug修复
huangqizhen:huangqizheng/feature-20250709163552-7.8导出传输对象修复
huangqizhen:huangqizheng/feature-20250710151401-数据同步完成
huangqizhen:huangqizheng/feature-20250714180618-数据同步
huangqizhen:huangqizheng/feature-20250715100115-非测试数据筛选
huangqizhen:huangqizheng/feature-20250717200321-优化导出
huangqizhen:huangqizheng/feature-20250718222252-导出修改完毕
huangqizhen:huangqizheng/feature-20250719105717-后端完毕
huangqizhen:huangqizheng/feature-20250721170818-后端周末修改
huangqizhen:huangqizheng/feature-20250722105318-BUG修改
huangqizhen:huangqizheng/feature-20250725144236-精简日志
huangqizhen:huangqizheng/feature-20250728134614-三期数据库配置
huangqizhen:huangqizheng/feature-20250731164458-地区部分修改以及导出的封装
huangqizhen:huangqizheng/feature-20250801114957-导出
huangqizhen:huangqizheng/feature-20250801180134-消费导出
huangqizhen:huangqizheng/feature-20250803175216-导出完毕
huangqizhen:huangqizheng/feature-20250804114811-打包配置
huangqizhen:huangqizheng/feature-20250805200446-配置修改及充值导出修改
huangqizhen:huangqizheng/feature-20250806120055-修复BUG
huangqizhen:huangqizheng/feature-20250808172612-bug修复
huangqizhen:huangqizheng/feature-20250809103653-修改配置导出重新上传
huangqizhen:huangqizheng/feature-20250809184038-研发部校验
huangqizhen:huangqizheng/feature-20251104113536-现金管理二期退款修改
huangqizhen:huangqizheng/feature-20251119150446-退款合并后
huangqizhen:huangqizheng/feature-20251203174217-冲刺计划
huangqizhen:huangqizheng/feature-20260106155423-红包修改
huangqizhen:lihuilin/hotfix-20250810160509-余额地区传参
huangqizhen:lihuilin/hotfix-20250815-审核默认更新时间
huangqizhen:lihuilin1015备份
huangqizhen:lijianlin/feature-20250623120104-工作台与审核
huangqizhen:lijianlin/feature-20250710152503-二期工作台与部分权限
huangqizhen:lijianlin/feature-20250728171217-三期金豆消费相关
huangqizhen:lijianlin/feature-202509231533026-现金管理-收款管理
huangqizhen:lijianlin/feature-20251104110749-现金管理二期
huangqizhen:lijianlin/feature-20251209-现金管理三期
huangqizhen:lijianlin/feature-20251211-fix
huangqizhen:master
huangqizhen:milestone-20250702-金币重构一期
huangqizhen:milestone-20250711-金币重构二期
huangqizhen:milestone-20250727-金币重构三期
huangqizhen:milestone-20251016-现金管理
huangqizhen:milestone-20251104-现金管理二期
huangqizhen:milestone-20251125-多语言
huangqizhen:milestone-20251203-冲刺计划
huangqizhen:milestone-20251205-消费
huangqizhen:milestone-20251209-多语言二期
huangqizhen:milestone-20251215-优化
huangqizhen:milestone-20251215-红包修改
huangqizhen:sunjiabei/feature-20250623130922-消费功能
huangqizhen:sunjiabei/feature-20250710132313-二期模块
huangqizhen:sunjiabei/feature-20250725135225-金币三期
huangqizhen:sunjiabei/feature-20250822111257-平台和商品id字段替换
huangqizhen:sunjiabei/feature-20250924164720-现金管理
huangqizhen:sunjiabei/feature-20251021102635-银行接口
huangqizhen:sunjiabei/feature-20251202094523-银行接口同步
huangqizhen:sunjiabei/feature-20251210111313-消费
huangqizhen:wangguorui/feature-20251125171605-现金管理多语言配置
huangqizhen:wangyetao/feature-20250628170337-汇率
huangqizhen:wangyetao/feature-20250715095107-地区数据权限
huangqizhen:yufenghao/feature-20251106105659-现金管理接口优化
huangqizhen:yufenghao1106
huangqizhen:工作流配置
20 Commits
master
...
sunjiabei/
13 changed files with 1324 additions and 19 deletions
-
16src/main/java/com/example/demo/controller/cash/Bank.java
-
118src/main/java/com/example/demo/controller/cash/BankController.java
-
33src/main/java/com/example/demo/domain/DTO/BankDTO.java
-
25src/main/java/com/example/demo/domain/DTO/FirstdataDTO.java
-
24src/main/java/com/example/demo/domain/DTO/FirstdataRequestDTO.java
-
26src/main/java/com/example/demo/domain/DTO/Ipay88DTO.java
-
37src/main/java/com/example/demo/domain/DTO/PaymentDTO.java
-
31src/main/java/com/example/demo/domain/DTO/StripeDTO.java
-
29src/main/java/com/example/demo/domain/vo/cash/BankVO.java
-
14src/main/java/com/example/demo/mapper/cash/CashCollectionMapper.java
-
41src/main/java/com/example/demo/service/cash/BankService.java
-
874src/main/java/com/example/demo/serviceImpl/cash/BankServiceImpl.java
-
75src/main/resources/cashMapper/CashCollectionMapper.xml
@ -1,16 +0,0 @@ |
|||||
package com.example.demo.controller.cash; |
|
||||
|
|
||||
/** |
|
||||
* @program: gold-java |
|
||||
* @ClassName Bank |
|
||||
* @description: |
|
||||
* @author: Double |
|
||||
* @create: 2025−11-17 13:31 |
|
||||
* @Version 1.0 |
|
||||
**/ |
|
||||
|
|
||||
public class Bank { |
|
||||
|
|
||||
|
|
||||
|
|
||||
} |
|
||||
@ -0,0 +1,118 @@ |
|||||
|
package com.example.demo.controller.cash; |
||||
|
|
||||
|
import com.example.demo.config.interfac.Log; |
||||
|
import com.example.demo.domain.DTO.BankDTO; |
||||
|
import com.example.demo.domain.vo.cash.BankVO; |
||||
|
import com.example.demo.domain.vo.coin.Result; |
||||
|
import com.example.demo.service.cash.BankService; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName Bank |
||||
|
* @description: |
||||
|
* @author: Double |
||||
|
* @create: 2025−11-17 13:31 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
|
||||
|
@RestController |
||||
|
@RequestMapping("/bank") |
||||
|
@RequiredArgsConstructor |
||||
|
@Slf4j |
||||
|
@CrossOrigin |
||||
|
public class BankController { |
||||
|
|
||||
|
@Autowired |
||||
|
private BankService bankService; |
||||
|
|
||||
|
//payment银行接口(批量) |
||||
|
@Log("payment银行接口(批量)") |
||||
|
@PostMapping("/paymentAuto") |
||||
|
public Result paymentAuto(@RequestBody BankDTO bankDTO) { |
||||
|
try { |
||||
|
return Result.success(bankService.paymentAuto(bankDTO)); |
||||
|
} catch (Exception e) { |
||||
|
return Result.error(e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//payment银行接口(单个) |
||||
|
@Log("payment银行接口(单个)") |
||||
|
@PostMapping("/getPayment") |
||||
|
public Result getPayment(@RequestBody BankDTO bankDTO) { |
||||
|
try { |
||||
|
if (bankDTO.getTime().isEmpty() || bankDTO.getOrderNo().isEmpty()) { |
||||
|
return Result.error("时间或订单号为空"); |
||||
|
} |
||||
|
return bankService.getPayment(bankDTO); |
||||
|
} catch (Exception e) { |
||||
|
return Result.error(e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//stripe银行接口(批量) |
||||
|
@Log("stripe银行接口(批量)") |
||||
|
@PostMapping("/stripeAuto") |
||||
|
public Result stripeAuto(@RequestBody BankDTO bankDTO) { |
||||
|
try { |
||||
|
return Result.success(bankService.stripeAuto(bankDTO)); |
||||
|
} catch (Exception e) { |
||||
|
return Result.error(e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//stripe银行接口(单个) |
||||
|
@Log("stripe银行接口(单个)") |
||||
|
@PostMapping("/getStripe") |
||||
|
public Result getStripe(@RequestBody BankDTO bankDTO) { |
||||
|
try { |
||||
|
if (bankDTO.getOrderNo().isEmpty()) { |
||||
|
return Result.error("订单号为空"); |
||||
|
} |
||||
|
return bankService.getStripe(bankDTO); |
||||
|
} catch (Exception e) { |
||||
|
return Result.error(e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//stripe银行接口(批量) |
||||
|
@Log("firstdata银行接口(批量)") |
||||
|
@PostMapping("/firstdataAuto") |
||||
|
public Result firstdataAuto(@RequestBody BankDTO bankDTO) { |
||||
|
try { |
||||
|
return Result.success(bankService.firstdataAuto(bankDTO)); |
||||
|
} catch (Exception e) { |
||||
|
return Result.error(e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//stripe银行接口(单个) |
||||
|
@Log("firstdata银行接口(单个)") |
||||
|
@PostMapping("/getFirstdata") |
||||
|
public Result getFirstdata(@RequestBody BankDTO bankDTO) { |
||||
|
try { |
||||
|
if (bankDTO.getOrderNo().isEmpty()) { |
||||
|
return Result.error("订单号为空"); |
||||
|
} |
||||
|
return bankService.getFirstdata(bankDTO); |
||||
|
} catch (Exception e) { |
||||
|
return Result.error(e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
//stripe银行接口(批量) |
||||
|
@Log("ipay银行接口(批量)") |
||||
|
@PostMapping("/ipayAuto") |
||||
|
public Result ipayAuto(@RequestBody BankDTO bankDTO) { |
||||
|
try { |
||||
|
return Result.success(bankService.ipayAuto(bankDTO)); |
||||
|
} catch (Exception e) { |
||||
|
return Result.error(e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,33 @@ |
|||||
|
package com.example.demo.domain.DTO; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName BankDTO |
||||
|
* @description: |
||||
|
* @author: Double |
||||
|
* @create: 2025−11-21 10:32 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
public class BankDTO { |
||||
|
//时间格式yyyyMMdd |
||||
|
private String time = ""; |
||||
|
//订单号 |
||||
|
private String orderNo = ""; |
||||
|
//交易ID |
||||
|
private String transactionId = ""; |
||||
|
//最大条数 |
||||
|
private int sum; |
||||
|
//开始时间 |
||||
|
private String startTime = ""; |
||||
|
//结束时间 |
||||
|
private String endTime = ""; |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
package com.example.demo.domain.DTO; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName FirstdataDTO |
||||
|
* @description: |
||||
|
* @author: Double |
||||
|
* @create: 2025−12-08 10:46 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
public class FirstdataDTO { |
||||
|
private String country; |
||||
|
private String orderId; |
||||
|
private String currency; |
||||
|
private Integer total; |
||||
|
private Integer amount; |
||||
|
private Integer fee; |
||||
|
private Integer net; |
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
package com.example.demo.domain.DTO; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName FirstdataRequestDTO |
||||
|
* @description: |
||||
|
* @author: Double |
||||
|
* @create: 2025−12-08 14:03 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
public class FirstdataRequestDTO { |
||||
|
String key; |
||||
|
String secret; |
||||
|
long clientRequestId; |
||||
|
long time ; |
||||
|
String hmacBase64; |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,26 @@ |
|||||
|
package com.example.demo.domain.DTO; |
||||
|
|
||||
|
import com.fasterxml.jackson.annotation.JsonFormat; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
import java.util.Date; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName Ipay88DTO |
||||
|
* @description: |
||||
|
* @author: Double |
||||
|
* @create: 2025−12-09 11:44 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
public class Ipay88DTO { |
||||
|
private String orderNo;//订单号 |
||||
|
private String currency;//货币 |
||||
|
private String amount;//金额 |
||||
|
private String fee;//手续费 |
||||
|
private String net;//净额 |
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
package com.example.demo.domain.DTO; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName PaymentDTO |
||||
|
* @description: |
||||
|
* @author: Double |
||||
|
* @create: 2025−11-21 10:42 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
import com.fasterxml.jackson.annotation.JsonFormat; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
import java.math.BigDecimal; |
||||
|
import java.util.Date; |
||||
|
|
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
public class PaymentDTO { |
||||
|
|
||||
|
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "Asia/Shanghai") |
||||
|
private Date time; |
||||
|
private String type; |
||||
|
private String provider; |
||||
|
private String request_reference; |
||||
|
private String merchant_reference; |
||||
|
private String provider_reference; |
||||
|
private String currency; |
||||
|
private BigDecimal order_amount; |
||||
|
private BigDecimal charge; |
||||
|
private BigDecimal net_amount; |
||||
|
private String status; |
||||
|
private String created_time; |
||||
|
private String completed_time; |
||||
|
} |
||||
@ -0,0 +1,31 @@ |
|||||
|
package com.example.demo.domain.DTO; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName StripeDTO |
||||
|
* @description: |
||||
|
* @author: Double |
||||
|
* @create: 2025−11-21 15:26 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
|
||||
|
import com.fasterxml.jackson.annotation.JsonFormat; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
import java.util.Date; |
||||
|
|
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
public class StripeDTO { |
||||
|
private String orderNo;//订单号 |
||||
|
private String balanceTransaction;//余额交易ID |
||||
|
private String currency;//货币 |
||||
|
private String amount;//金额 |
||||
|
private String fee;//手续费 |
||||
|
private String net;//净额 |
||||
|
private String chargeCurrency;//收款币种 |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "Asia/Shanghai") |
||||
|
private Date availableOn; |
||||
|
} |
||||
@ -0,0 +1,29 @@ |
|||||
|
package com.example.demo.domain.vo.cash; |
||||
|
|
||||
|
import com.example.demo.domain.DTO.FirstdataDTO; |
||||
|
import com.example.demo.domain.DTO.PaymentDTO; |
||||
|
import com.example.demo.domain.DTO.StripeDTO; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName BankVO |
||||
|
* @description: |
||||
|
* @author: Double |
||||
|
* @create: 2025−11-21 10:44 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
public class BankVO { |
||||
|
private List<PaymentDTO> paymentDTOList; |
||||
|
private PaymentDTO paymentDTO; |
||||
|
private List<StripeDTO> stripeDTOList; |
||||
|
private StripeDTO stripeDTO; |
||||
|
private FirstdataDTO firstdataDTO; |
||||
|
private List<String> message; |
||||
|
} |
||||
@ -0,0 +1,41 @@ |
|||||
|
package com.example.demo.service.cash; |
||||
|
|
||||
|
|
||||
|
import com.example.demo.domain.DTO.BankDTO; |
||||
|
import com.example.demo.domain.vo.cash.BankVO; |
||||
|
import com.example.demo.domain.vo.coin.Result; |
||||
|
import com.stripe.exception.StripeException; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName BankService |
||||
|
* @description: |
||||
|
* @author: Double |
||||
|
* @create: 2025−11-21 10:43 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
public interface BankService { |
||||
|
//payment银行接口(批量) |
||||
|
Result paymentAuto(BankDTO bankDTO); |
||||
|
|
||||
|
//payment银行接口(单个) |
||||
|
Result getPayment(BankDTO bankDTO); |
||||
|
|
||||
|
//stripe银行接口(批量) |
||||
|
Result stripeAuto(BankDTO bankDTO); |
||||
|
|
||||
|
//stripe银行接口(单个) |
||||
|
Result getStripe(BankDTO bankDTO) throws StripeException; |
||||
|
|
||||
|
//firstdata银行接口(批量) |
||||
|
Result firstdataAuto(BankDTO bankDTO); |
||||
|
|
||||
|
//firstdata银行接口(单个) |
||||
|
Result getFirstdata(BankDTO bankDTO); |
||||
|
|
||||
|
//firstdata银行接口(批量) |
||||
|
Result ipayAuto(BankDTO bankDTO); |
||||
|
//bank银行接口(批量) |
||||
|
Result bankAuto(); |
||||
|
} |
||||
@ -0,0 +1,874 @@ |
|||||
|
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<String, String> 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<String, String> 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<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(formData, headers); |
||||
|
|
||||
|
// 调用第三方API(使用配置好SSL协议的RestTemplate) |
||||
|
ResponseEntity<String> 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<PaymentDTO> 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()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public Result paymentAuto(BankDTO bankDTO) { |
||||
|
try { |
||||
|
// 1. 准备参数 |
||||
|
String settlementDate = bankDTO.getTime(); // 从BankDTO对象获取time作为settlement_date |
||||
|
String network = "FPS"; // 固定值 |
||||
|
// 2. 生成签名 |
||||
|
Map<String, String> 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<String, String> 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<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(formData, headers); |
||||
|
|
||||
|
// 调用第三方API(使用配置好SSL协议的RestTemplate) |
||||
|
ResponseEntity<String> 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"); |
||||
|
|
||||
|
// 添加非空校验 |
||||
|
if (transactions == null || transactions.isEmpty()) { |
||||
|
log.warn("transactions为空或无数据"); |
||||
|
return Result.error("payment当天无数据请切换日期"); |
||||
|
} |
||||
|
|
||||
|
// 创建BankVO并设置paymentDTOList |
||||
|
BankVO bankVO = new BankVO(); |
||||
|
List<PaymentDTO> paymentDTOList; |
||||
|
try { |
||||
|
paymentDTOList = transactions.toJavaList(PaymentDTO.class); |
||||
|
} catch (Exception e) { |
||||
|
log.error("解析JSON响应时发生错误: {}", e.getMessage(), e); |
||||
|
return Result.error("payment当天无数据请切换日期"); |
||||
|
} |
||||
|
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("港币HKD"); |
||||
|
|
||||
|
// 获取订单号 |
||||
|
String orderNo = paymentDTO.getMerchant_reference(); |
||||
|
|
||||
|
List<String> orderNoList = cashCollectionMapper.selectPaymentList(); |
||||
|
// 检查当前订单号是否在列表中 |
||||
|
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<String> messages = new ArrayList<>(); |
||||
|
// 从Stripe获取最近的收费记录(最多200条) |
||||
|
List<Charge> 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<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); |
||||
|
|
||||
|
// 创建StripeDTO列表用于存储所有处理后的数据 |
||||
|
List<StripeDTO> 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<String> 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<Charge> 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<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; |
||||
|
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<String> orderNoList = cashCollectionMapper.selectFirstdataList(); |
||||
|
|
||||
|
// 存储处理结果的列表 |
||||
|
List<Result> 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<String> entity = new HttpEntity<>(headers); |
||||
|
|
||||
|
ResponseEntity<String> response = restTemplate.exchange( |
||||
|
url, |
||||
|
HttpMethod.GET, |
||||
|
entity, |
||||
|
String.class |
||||
|
); |
||||
|
|
||||
|
// 解析响应数据 |
||||
|
// API返回的是对象格式,需要先解析为JSONObject |
||||
|
JSONObject jsonObject = JSON.parseObject(response.getBody()); |
||||
|
|
||||
|
// 创建BankVO对象并设置数据 |
||||
|
BankVO bankVO = new BankVO(); |
||||
|
List<String> 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<String, Object> 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<String, Object> 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<String> message = new ArrayList<>(); |
||||
|
Map<String, Object> 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<CashCollection> cashCollections = cashCollectionMapper.selectIpayList(); |
||||
|
BankVO bankVO = new BankVO(); |
||||
|
List<String> 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) Math.round(amountDouble); |
||||
|
ipay88DTO.setAmount(String.valueOf(amountInt)); |
||||
|
|
||||
|
double feeDouble = cashCollection.getPermanentGold() * 3.18 * 0.0085; |
||||
|
int feeInt = (int) Math.round(feeDouble); |
||||
|
ipay88DTO.setFee(String.valueOf(feeInt)); |
||||
|
|
||||
|
int netInt = amountInt-feeInt; |
||||
|
ipay88DTO.setNet(String.valueOf(netInt)); |
||||
|
cashCollectionMapper.updateByGoldCoinOrderCodeByIpay88(ipay88DTO); |
||||
|
// 构建成功消息 |
||||
|
Map<String, Object> 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 54 15 * * ?") |
||||
|
@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.setSum(1000); |
||||
|
|
||||
|
// 依次调用各个自动处理方法 |
||||
|
dto.setTime(oneDayAgoStr); |
||||
|
Result paymentOneDayResult = paymentAuto(dto); |
||||
|
dto.setTime(twoDayAgoStr); |
||||
|
Result paymentTwoDayResult = paymentAuto(dto); |
||||
|
dto.setTime(threeDayAgoStr); |
||||
|
Result paymentThreeDayResult = paymentAuto(dto); |
||||
|
dto.setTime(fourDayAgoStr); |
||||
|
Result paymentFourDayResult = paymentAuto(dto); |
||||
|
dto.setTime(fiveDayAgoStr); |
||||
|
Result paymentFiveDayResult = paymentAuto(dto); |
||||
|
dto.setTime(sixDayAgoStr); |
||||
|
Result paymentSixDayResult = paymentAuto(dto); |
||||
|
dto.setTime(sevenDayAgoStr); |
||||
|
Result paymentSevenDayResult = paymentAuto(dto); |
||||
|
Result stripeResult = stripeAuto(dto); |
||||
|
Result firstdataResult = firstdataAuto(dto); |
||||
|
Result ipayResult = ipayAuto(dto); |
||||
|
|
||||
|
// 创建响应VO对象并收集处理结果 |
||||
|
BankVO bankVO = new BankVO(); |
||||
|
List<String> messages = new ArrayList<>(); |
||||
|
|
||||
|
// 收集各方法的处理结果信息 |
||||
|
messages.add("Payment One Day Auto Result: " + (paymentOneDayResult != null ? paymentOneDayResult.toString() : "null")); |
||||
|
messages.add("Payment Two Day Auto Result: " + (paymentTwoDayResult != null ? paymentTwoDayResult.toString() : "null")); |
||||
|
messages.add("Payment Three Day Auto Result: " + (paymentThreeDayResult != null ? paymentThreeDayResult.toString() : "null")); |
||||
|
messages.add("Payment Four Day Auto Result: " + (paymentFourDayResult != null ? paymentFourDayResult.toString() : "null")); |
||||
|
messages.add("Payment Five Day Auto Result: " + (paymentFiveDayResult != null ? paymentFiveDayResult.toString() : "null")); |
||||
|
messages.add("Payment Six Day Auto Result: " + (paymentSixDayResult != null ? paymentSixDayResult.toString() : "null")); |
||||
|
messages.add("Payment Seven Day Auto Result: " + (paymentSevenDayResult != null ? paymentSevenDayResult.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<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'); |
||||
|
} |
||||
|
hexStr.append(hex); |
||||
|
} |
||||
|
return hexStr.toString(); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue