178 lines
6.3 KiB
Java
178 lines
6.3 KiB
Java
package com.erp.example.seata;
|
||
|
||
import com.erp.example.seata.entity.Account;
|
||
import com.erp.example.seata.entity.TransactionLog;
|
||
import com.erp.example.seata.mapper.AccountMapper;
|
||
import com.erp.example.seata.mapper.TransactionLogMapper;
|
||
import org.slf4j.Logger;
|
||
import org.slf4j.LoggerFactory;
|
||
import org.springframework.beans.factory.annotation.Autowired;
|
||
import org.springframework.stereotype.Service;
|
||
import org.springframework.transaction.annotation.Transactional;
|
||
|
||
import java.math.BigDecimal;
|
||
import java.time.LocalDateTime;
|
||
import java.util.UUID;
|
||
|
||
/**
|
||
* 财务服务 - AT模式实现
|
||
*/
|
||
@Service
|
||
public class FinanceService {
|
||
|
||
private static final Logger log = LoggerFactory.getLogger(FinanceService.class);
|
||
|
||
@Autowired
|
||
private AccountMapper accountMapper;
|
||
|
||
@Autowired
|
||
private TransactionLogMapper transactionLogMapper;
|
||
|
||
/**
|
||
* 冻结资金
|
||
* AT模式自动记录前后镜像,异常时自动回滚
|
||
*/
|
||
@Transactional
|
||
public void freezeAmount(Long customerId, Long amount, String orderNo) {
|
||
log.info("冻结资金: 客户ID={}, 金额={}, 订单={}", customerId, amount, orderNo);
|
||
|
||
Account account = accountMapper.findByCustomerId(customerId);
|
||
if (account == null) {
|
||
throw new RuntimeException("账户不存在: " + customerId);
|
||
}
|
||
|
||
BigDecimal availableAmount = account.getBalance().subtract(account.getFrozenAmount());
|
||
BigDecimal freezeAmount = BigDecimal.valueOf(amount);
|
||
|
||
if (availableAmount.compareTo(freezeAmount) < 0) {
|
||
throw new RuntimeException("余额不足: 可用=" + availableAmount + ", 需要=" + freezeAmount);
|
||
}
|
||
|
||
// 冻结资金 = 增加冻结金额
|
||
account.setFrozenAmount(account.getFrozenAmount().add(freezeAmount));
|
||
accountMapper.update(account);
|
||
|
||
// 记录交易流水
|
||
TransactionLog txLog = new TransactionLog();
|
||
txLog.setTxNo("TX" + System.currentTimeMillis() + UUID.randomUUID().toString().substring(0, 8));
|
||
txLog.setOrderNo(orderNo);
|
||
txLog.setCustomerId(customerId);
|
||
txLog.setAmount(freezeAmount);
|
||
txLog.setType("FREEZE");
|
||
txLog.setStatus("SUCCESS");
|
||
txLog.setCreateTime(LocalDateTime.now());
|
||
transactionLogMapper.insert(txLog);
|
||
|
||
log.info("资金冻结成功: {}", account);
|
||
}
|
||
|
||
/**
|
||
* 解冻资金(取消冻结)
|
||
* 用于订单取消时回滚
|
||
*/
|
||
@Transactional
|
||
public void unfreezeAmount(Long customerId, Long amount, String orderNo) {
|
||
log.info("解冻资金: 客户ID={}, 金额={}, 订单={}", customerId, amount, orderNo);
|
||
|
||
Account account = accountMapper.findByCustomerId(customerId);
|
||
if (account == null) {
|
||
log.warn("账户不存在: {}", customerId);
|
||
return;
|
||
}
|
||
|
||
BigDecimal unfreezeAmount = BigDecimal.valueOf(amount);
|
||
BigDecimal actualUnfreeze = unfreezeAmount.min(account.getFrozenAmount());
|
||
|
||
// 解冻资金 = 减少冻结金额
|
||
account.setFrozenAmount(account.getFrozenAmount().subtract(actualUnfreeze));
|
||
accountMapper.update(account);
|
||
|
||
// 记录交易流水
|
||
TransactionLog txLog = new TransactionLog();
|
||
txLog.setTxNo("TX" + System.currentTimeMillis() + UUID.randomUUID().toString().substring(0, 8));
|
||
txLog.setOrderNo(orderNo);
|
||
txLog.setCustomerId(customerId);
|
||
txLog.setAmount(actualUnfreeze);
|
||
txLog.setType("UNFREEZE");
|
||
txLog.setStatus("SUCCESS");
|
||
txLog.setCreateTime(LocalDateTime.now());
|
||
transactionLogMapper.insert(txLog);
|
||
|
||
log.info("资金解冻成功: {}", account);
|
||
}
|
||
|
||
/**
|
||
* 消费资金(正式扣减)
|
||
* 订单支付成功后调用
|
||
*/
|
||
@Transactional
|
||
public void consumeAmount(Long customerId, Long amount, String orderNo) {
|
||
log.info("消费资金: 客户ID={}, 金额={}, 订单={}", customerId, amount, orderNo);
|
||
|
||
Account account = accountMapper.findByCustomerId(customerId);
|
||
if (account == null) {
|
||
throw new RuntimeException("账户不存在: " + customerId);
|
||
}
|
||
|
||
BigDecimal consumeAmount = BigDecimal.valueOf(amount);
|
||
|
||
// 消费资金 = 减少余额和冻结金额
|
||
account.setBalance(account.getBalance().subtract(consumeAmount));
|
||
account.setFrozenAmount(account.getFrozenAmount().subtract(consumeAmount));
|
||
accountMapper.update(account);
|
||
|
||
// 记录交易流水
|
||
TransactionLog txLog = new TransactionLog();
|
||
txLog.setTxNo("TX" + System.currentTimeMillis() + UUID.randomUUID().toString().substring(0, 8));
|
||
txLog.setOrderNo(orderNo);
|
||
txLog.setCustomerId(customerId);
|
||
txLog.setAmount(consumeAmount);
|
||
txLog.setType("CONSUME");
|
||
txLog.setStatus("SUCCESS");
|
||
txLog.setCreateTime(LocalDateTime.now());
|
||
transactionLogMapper.insert(txLog);
|
||
|
||
log.info("资金消费成功: {}", account);
|
||
}
|
||
|
||
/**
|
||
* 退款
|
||
* 订单取消或退款时调用
|
||
*/
|
||
@Transactional
|
||
public void refundAmount(Long customerId, Long amount, String orderNo) {
|
||
log.info("退款: 客户ID={}, 金额={}, 订单={}", customerId, amount, orderNo);
|
||
|
||
Account account = accountMapper.findByCustomerId(customerId);
|
||
if (account == null) {
|
||
throw new RuntimeException("账户不存在: " + customerId);
|
||
}
|
||
|
||
BigDecimal refundAmount = BigDecimal.valueOf(amount);
|
||
|
||
// 退款 = 增加余额
|
||
account.setBalance(account.getBalance().add(refundAmount));
|
||
accountMapper.update(account);
|
||
|
||
// 记录交易流水
|
||
TransactionLog txLog = new TransactionLog();
|
||
txLog.setTxNo("TX" + System.currentTimeMillis() + UUID.randomUUID().toString().substring(0, 8));
|
||
txLog.setOrderNo(orderNo);
|
||
txLog.setCustomerId(customerId);
|
||
txLog.setAmount(refundAmount);
|
||
txLog.setType("REFUND");
|
||
txLog.setStatus("SUCCESS");
|
||
txLog.setCreateTime(LocalDateTime.now());
|
||
transactionLogMapper.insert(txLog);
|
||
|
||
log.info("退款成功: {}", account);
|
||
}
|
||
|
||
/**
|
||
* 查询账户
|
||
*/
|
||
public Account findByCustomerId(Long customerId) {
|
||
return accountMapper.findByCustomerId(customerId);
|
||
}
|
||
}
|