package com.ruoyi.im.service.impl;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.ruoyi.im.comm.Result;
|
import com.ruoyi.im.service.MedicalInsuranceAccountService;
|
import com.ruoyi.system.domain.MedicalInsuranceAccount;
|
import com.ruoyi.system.domain.MedicalInsuranceDailyClaim;
|
import com.ruoyi.system.mapper.MedicalInsuranceAccountMapper;
|
import com.ruoyi.system.mapper.MedicalInsuranceDailyClaimMapper;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.scheduling.annotation.Async;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.interceptor.TransactionAspectSupport;
|
|
import javax.xml.crypto.Data;
|
import java.math.BigDecimal;
|
import java.time.LocalDate;
|
import java.time.temporal.ChronoUnit;
|
import java.util.Date;
|
import java.util.List;
|
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.locks.ReentrantLock;
|
|
@Service
|
public class MedicalInsuranceAccountServiceImpl extends ServiceImpl<MedicalInsuranceAccountMapper, MedicalInsuranceAccount> implements MedicalInsuranceAccountService {
|
|
@Autowired
|
private MedicalInsuranceAccountMapper medicalInsuranceAccountMapper;
|
|
@Autowired
|
private MedicalInsuranceDailyClaimMapper medicalInsuranceDailyClaimMapper;
|
|
// 使用本地锁避免数据库锁竞争
|
private final ConcurrentHashMap<Integer, ReentrantLock> accountLocks = new ConcurrentHashMap<>();
|
|
@Override
|
public Result getInsuranceBenefit(Integer userId) {
|
synchronized (userId) {
|
// 获取账户本地锁
|
ReentrantLock accountLock = accountLocks.computeIfAbsent(userId, k -> new ReentrantLock());
|
accountLock.lock();
|
|
try {
|
MedicalInsuranceAccount account = medicalInsuranceAccountMapper.selectOne(new LambdaQueryWrapper<MedicalInsuranceAccount>()
|
.eq(MedicalInsuranceAccount::getUserId, userId)
|
.eq(MedicalInsuranceAccount::getAccountStatus, MedicalInsuranceAccount.AccountStatus.ACTIVE)
|
);
|
if (account == null) {
|
return Result.error("医保账户不存在");
|
}
|
|
// 检查账户状态
|
if (!"ACTIVE".equals(account.getAccountStatus().name())) {
|
return Result.error("保单已失效");
|
}
|
|
// 检查账户有效期
|
LocalDate now = LocalDate.now();
|
if (now.isBefore(account.getEffectiveDate()) ||
|
now.isAfter(account.getExpiryDate())) {
|
return Result.error("已过保单日期");
|
}
|
// 检查今天是否已经领取
|
LocalDate today = LocalDate.now();
|
Long todayCount = medicalInsuranceDailyClaimMapper.selectCount(new LambdaQueryWrapper<MedicalInsuranceDailyClaim>()
|
.eq(MedicalInsuranceDailyClaim::getUserId, userId)
|
.eq(MedicalInsuranceDailyClaim::getAccountId, account.getId())
|
.eq(MedicalInsuranceDailyClaim::getClaimDate, today)
|
);
|
if (todayCount > 0) {
|
return Result.error("今日已领取过金额");
|
}
|
|
if (account.getTotalQuota().compareTo(account.getAlreadyReceived()) == 0) {
|
return Result.error("你的保险额度已领取完!");
|
}
|
|
// 计算剩余天数
|
long remainingDays = ChronoUnit.DAYS.between(now, account.getExpiryDate()) + 1;
|
|
// 计算每日金额
|
BigDecimal dailyAmount = calculateDailyAmount(
|
account.getTotalQuota(), (int) remainingDays);
|
|
// 如果账户余额不足,则领取剩余全部金额
|
if (account.getAmountClaimed().compareTo(dailyAmount) < 0) {
|
dailyAmount = account.getAmountClaimed();
|
}
|
|
// 更新待领金额
|
account.setAmountClaimed(account.getAmountClaimed().subtract(dailyAmount));
|
|
// 更新已领取金额
|
BigDecimal currentAmountReceived = account.getAlreadyReceived() != null ?
|
account.getAlreadyReceived(): BigDecimal.ZERO;
|
account.setAlreadyReceived(currentAmountReceived.add(dailyAmount));
|
|
medicalInsuranceAccountMapper.updateById(account);
|
|
// 创建领取记录
|
MedicalInsuranceDailyClaim claim = new MedicalInsuranceDailyClaim();
|
claim.setAccountId(account.getId());
|
claim.setUserId(userId);
|
claim.setClaimDate(today);
|
claim.setClaimAmount(dailyAmount);
|
claim.setCreatedAt(new Date());
|
medicalInsuranceDailyClaimMapper.insert(claim);
|
return Result.success("领取成功");
|
}catch (Exception e){
|
e.printStackTrace();
|
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
|
log.error("领取保险金出错:"+e.getMessage());
|
}finally {
|
accountLock.unlock();
|
}
|
}
|
return Result.error("领取失败!");
|
}
|
|
@Override
|
public Result getReceiveStatus(Integer userId) {
|
MedicalInsuranceAccount account = medicalInsuranceAccountMapper.selectOne(new LambdaQueryWrapper<MedicalInsuranceAccount>()
|
.eq(MedicalInsuranceAccount::getUserId, userId)
|
.eq(MedicalInsuranceAccount::getAccountStatus, MedicalInsuranceAccount.AccountStatus.ACTIVE)
|
);
|
if (account == null) {
|
return Result.success(false);
|
}
|
// 检查账户状态
|
if (!"ACTIVE".equals(account.getAccountStatus().name())) {
|
return Result.success(false);
|
}
|
// 检查账户有效期
|
LocalDate now = LocalDate.now();
|
if (now.isBefore(account.getEffectiveDate()) ||
|
now.isAfter(account.getExpiryDate())) {
|
return Result.success(false);
|
}
|
// 检查今天是否已经领取
|
LocalDate today = LocalDate.now();
|
Long todayCount = medicalInsuranceDailyClaimMapper.selectCount(new LambdaQueryWrapper<MedicalInsuranceDailyClaim>()
|
.eq(MedicalInsuranceDailyClaim::getUserId, userId)
|
.eq(MedicalInsuranceDailyClaim::getAccountId, account.getId())
|
.eq(MedicalInsuranceDailyClaim::getClaimDate, today)
|
);
|
if (todayCount > 0) {
|
return Result.success(false);
|
}
|
return Result.success(true);
|
}
|
|
|
private BigDecimal calculateDailyAmount(BigDecimal totalAmount, int totalDays) {
|
if (totalDays <= 0) {
|
return BigDecimal.ZERO;
|
}
|
// 使用四舍五入到分位
|
return totalAmount.divide(new BigDecimal(totalDays), 2, BigDecimal.ROUND_DOWN);
|
}
|
}
|