yxh
7 天以前 b1f41c066b0b7c38faffddbfe73b9be8d0bd508e
ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceFundtaxServiceImpl.java
@@ -3,131 +3,298 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.tax.VatTaxUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.project.domain.ServiceFund;
import com.ruoyi.project.domain.ServiceFunddetail;
import com.ruoyi.project.domain.ServiceFundtax;
import com.ruoyi.project.domain.vo.FundTaxVO;
import com.ruoyi.project.domain.vo.TaxMoneyByItemEO;
import com.ruoyi.project.domain.vo.TaxMoneySumEO;
import com.ruoyi.project.mapper.ServiceFundMapper;
import com.ruoyi.project.mapper.ServiceFunddetailMapper;
import com.ruoyi.project.mapper.ServiceFundtaxMapper;
import com.ruoyi.project.service.IServiceFundService;
import com.ruoyi.project.service.IServiceFunddetailService;
import com.ruoyi.project.service.IServiceFundtaxService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
/**
 * 专家费用算税申请主Service业务层处理
 *
 *
 * @author ruoyi
 * @date 2024-03-13
 */
@Slf4j
@Service
public class ServiceFundtaxServiceImpl extends ServiceImpl<ServiceFundtaxMapper, ServiceFundtax> implements IServiceFundtaxService
{
public class ServiceFundtaxServiceImpl extends ServiceImpl<ServiceFundtaxMapper, ServiceFundtax> implements IServiceFundtaxService {
    @Autowired
    private ServiceFunddetailMapper serviceFunddetailMapper;
    @Autowired
    private IServiceFunddetailService serviceFunddetailService;
    @Autowired
    private IServiceFundService serviceFundService;
    @Autowired
    private ServiceFundtaxMapper serviceFundtaxMapper;
    @Autowired
    private ServiceFundMapper serviceFundMapper;
    /**
     * 查询专家费用算税申请主列表
     *
     *
     * @param serviceFundtax 专家费用算税申请主
     * @return 专家费用算税申请主
     */
    @Override
    public List<ServiceFundtax> queryList(ServiceFundtax serviceFundtax) {
        LambdaQueryWrapper<ServiceFundtax> wrappers = Wrappers.lambdaQuery();
        if (StringUtils.isNotBlank(serviceFundtax.getApplyno())){
            wrappers.eq(ServiceFundtax::getApplyno ,serviceFundtax.getApplyno());
        if (StringUtils.isNotBlank(serviceFundtax.getApplyno())) {
            wrappers.eq(ServiceFundtax::getApplyno, serviceFundtax.getApplyno());
        }
        if (serviceFundtax.getTaxedtime() != null){
            wrappers.eq(ServiceFundtax::getTaxedtime ,serviceFundtax.getTaxedtime());
        if (serviceFundtax.getTaxedtime() != null) {
            wrappers.eq(ServiceFundtax::getTaxedtime, serviceFundtax.getTaxedtime());
        }
        if (StringUtils.isNotBlank(serviceFundtax.getUserno())){
            wrappers.eq(ServiceFundtax::getUserno ,serviceFundtax.getUserno());
        if (StringUtils.isNotBlank(serviceFundtax.getUserno())) {
            wrappers.eq(ServiceFundtax::getUserno, serviceFundtax.getUserno());
        }
        if (StringUtils.isNotBlank(serviceFundtax.getUsername())){
            wrappers.like(ServiceFundtax::getUsername ,serviceFundtax.getUsername());
        if (StringUtils.isNotBlank(serviceFundtax.getUsername())) {
            wrappers.like(ServiceFundtax::getUsername, serviceFundtax.getUsername());
        }
        if (StringUtils.isNotBlank(serviceFundtax.getDeptmentno())){
            wrappers.eq(ServiceFundtax::getDeptmentno ,serviceFundtax.getDeptmentno());
        if (StringUtils.isNotBlank(serviceFundtax.getDeptmentno())) {
            wrappers.eq(ServiceFundtax::getDeptmentno, serviceFundtax.getDeptmentno());
        }
        if (StringUtils.isNotBlank(serviceFundtax.getDeptmentname())){
            wrappers.like(ServiceFundtax::getDeptmentname ,serviceFundtax.getDeptmentname());
        if (StringUtils.isNotBlank(serviceFundtax.getDeptmentname())) {
            wrappers.like(ServiceFundtax::getDeptmentname, serviceFundtax.getDeptmentname());
        }
        if (StringUtils.isNotBlank(serviceFundtax.getManagerno())){
            wrappers.eq(ServiceFundtax::getManagerno ,serviceFundtax.getManagerno());
        if (StringUtils.isNotBlank(serviceFundtax.getManagerno())) {
            wrappers.eq(ServiceFundtax::getManagerno, serviceFundtax.getManagerno());
        }
        if (StringUtils.isNotBlank(serviceFundtax.getManagername())){
            wrappers.like(ServiceFundtax::getManagername ,serviceFundtax.getManagername());
        if (StringUtils.isNotBlank(serviceFundtax.getManagername())) {
            wrappers.like(ServiceFundtax::getManagername, serviceFundtax.getManagername());
        }
        if (serviceFundtax.getPretaxamount() != null){
            wrappers.eq(ServiceFundtax::getPretaxamount ,serviceFundtax.getPretaxamount());
        if (serviceFundtax.getPretaxamount() != null) {
            wrappers.eq(ServiceFundtax::getPretaxamount, serviceFundtax.getPretaxamount());
        }
        if (serviceFundtax.getTaxedamount() != null){
            wrappers.eq(ServiceFundtax::getTaxedamount ,serviceFundtax.getTaxedamount());
        if (serviceFundtax.getTaxedamount() != null) {
            wrappers.eq(ServiceFundtax::getTaxedamount, serviceFundtax.getTaxedamount());
        }
        if (serviceFundtax.getTaxamount() != null){
            wrappers.eq(ServiceFundtax::getTaxamount ,serviceFundtax.getTaxamount());
        if (serviceFundtax.getTaxamount() != null) {
            wrappers.eq(ServiceFundtax::getTaxamount, serviceFundtax.getTaxamount());
        }
        if (serviceFundtax.getMedicalcost() != null){
            wrappers.eq(ServiceFundtax::getMedicalcost ,serviceFundtax.getMedicalcost());
        if (serviceFundtax.getIstax() != null) {
            wrappers.eq(ServiceFundtax::getIstax, serviceFundtax.getIstax());
        }
        if (serviceFundtax.getBodymaintaincost() != null){
            wrappers.eq(ServiceFundtax::getBodymaintaincost ,serviceFundtax.getBodymaintaincost());
        if (serviceFundtax.getMedicalcost() != null) {
            wrappers.eq(ServiceFundtax::getMedicalcost, serviceFundtax.getMedicalcost());
        }
        if (serviceFundtax.getOrgangaincost() != null){
            wrappers.eq(ServiceFundtax::getOrgangaincost ,serviceFundtax.getOrgangaincost());
        if (serviceFundtax.getBodymaintaincost() != null) {
            wrappers.eq(ServiceFundtax::getBodymaintaincost, serviceFundtax.getBodymaintaincost());
        }
        if (serviceFundtax.getOrganmaintaincost() != null){
            wrappers.eq(ServiceFundtax::getOrganmaintaincost ,serviceFundtax.getOrganmaintaincost());
        if (serviceFundtax.getOrgangaincost() != null) {
            wrappers.eq(ServiceFundtax::getOrgangaincost, serviceFundtax.getOrgangaincost());
        }
        if (StringUtils.isNotBlank(serviceFundtax.getRemark())){
            wrappers.eq(ServiceFundtax::getRemark ,serviceFundtax.getRemark());
        if (serviceFundtax.getOrganmaintaincost() != null) {
            wrappers.eq(ServiceFundtax::getOrganmaintaincost, serviceFundtax.getOrganmaintaincost());
        }
        if (serviceFundtax.getRecordstatus() != null){
            wrappers.eq(ServiceFundtax::getRecordstatus ,serviceFundtax.getRecordstatus());
        if (StringUtils.isNotBlank(serviceFundtax.getRemark())) {
            wrappers.eq(ServiceFundtax::getRemark, serviceFundtax.getRemark());
        }
        if (serviceFundtax.getCheckstatus() != null){
            wrappers.eq(ServiceFundtax::getCheckstatus ,serviceFundtax.getCheckstatus());
        if (serviceFundtax.getRecordstatus() != null) {
            wrappers.eq(ServiceFundtax::getRecordstatus, serviceFundtax.getRecordstatus());
        }
        if (serviceFundtax.getFlowlevel() != null){
            wrappers.eq(ServiceFundtax::getFlowlevel ,serviceFundtax.getFlowlevel());
        if (serviceFundtax.getCheckstatus() != null) {
            wrappers.eq(ServiceFundtax::getCheckstatus, serviceFundtax.getCheckstatus());
        }
        if (serviceFundtax.getBackflowlevel() != null){
            wrappers.eq(ServiceFundtax::getBackflowlevel ,serviceFundtax.getBackflowlevel());
        if (serviceFundtax.getFlowlevel() != null) {
            wrappers.eq(ServiceFundtax::getFlowlevel, serviceFundtax.getFlowlevel());
        }
        if (StringUtils.isNotBlank(serviceFundtax.getIsdistribute())){
            wrappers.eq(ServiceFundtax::getIsdistribute ,serviceFundtax.getIsdistribute());
        if (serviceFundtax.getBackflowlevel() != null) {
            wrappers.eq(ServiceFundtax::getBackflowlevel, serviceFundtax.getBackflowlevel());
        }
        if (StringUtils.isNotBlank(serviceFundtax.getRiqi())){
            wrappers.eq(ServiceFundtax::getRiqi ,serviceFundtax.getRiqi());
        if (StringUtils.isNotBlank(serviceFundtax.getIsdistribute())) {
            wrappers.eq(ServiceFundtax::getIsdistribute, serviceFundtax.getIsdistribute());
        }
        if (StringUtils.isNotBlank(serviceFundtax.getOpochecker())){
            wrappers.eq(ServiceFundtax::getOpochecker ,serviceFundtax.getOpochecker());
        if (StringUtils.isNotBlank(serviceFundtax.getRiqi())) {
            wrappers.eq(ServiceFundtax::getRiqi, serviceFundtax.getRiqi());
        }
        if (StringUtils.isNotBlank(serviceFundtax.getFinvicepresident())){
            wrappers.eq(ServiceFundtax::getFinvicepresident ,serviceFundtax.getFinvicepresident());
        if (StringUtils.isNotBlank(serviceFundtax.getOpochecker())) {
            wrappers.eq(ServiceFundtax::getOpochecker, serviceFundtax.getOpochecker());
        }
        if (StringUtils.isNotBlank(serviceFundtax.getBusvicepresident())){
            wrappers.eq(ServiceFundtax::getBusvicepresident ,serviceFundtax.getBusvicepresident());
        if (StringUtils.isNotBlank(serviceFundtax.getFinvicepresident())) {
            wrappers.eq(ServiceFundtax::getFinvicepresident, serviceFundtax.getFinvicepresident());
        }
        if (StringUtils.isNotBlank(serviceFundtax.getPresident())){
            wrappers.eq(ServiceFundtax::getPresident ,serviceFundtax.getPresident());
        if (StringUtils.isNotBlank(serviceFundtax.getBusvicepresident())) {
            wrappers.eq(ServiceFundtax::getBusvicepresident, serviceFundtax.getBusvicepresident());
        }
        if (StringUtils.isNotBlank(serviceFundtax.getOfficedirector())){
            wrappers.eq(ServiceFundtax::getOfficedirector ,serviceFundtax.getOfficedirector());
        if (StringUtils.isNotBlank(serviceFundtax.getPresident())) {
            wrappers.eq(ServiceFundtax::getPresident, serviceFundtax.getPresident());
        }
        if (StringUtils.isNotBlank(serviceFundtax.getFinancedirector())){
            wrappers.eq(ServiceFundtax::getFinancedirector ,serviceFundtax.getFinancedirector());
        if (StringUtils.isNotBlank(serviceFundtax.getOfficedirector())) {
            wrappers.eq(ServiceFundtax::getOfficedirector, serviceFundtax.getOfficedirector());
        }
        if (StringUtils.isNotBlank(serviceFundtax.getFinancechecher())){
            wrappers.eq(ServiceFundtax::getFinancechecher ,serviceFundtax.getFinancechecher());
        if (StringUtils.isNotBlank(serviceFundtax.getFinancedirector())) {
            wrappers.eq(ServiceFundtax::getFinancedirector, serviceFundtax.getFinancedirector());
        }
        if (StringUtils.isNotBlank(serviceFundtax.getUploadflag())){
            wrappers.eq(ServiceFundtax::getUploadflag ,serviceFundtax.getUploadflag());
        if (StringUtils.isNotBlank(serviceFundtax.getFinancechecher())) {
            wrappers.eq(ServiceFundtax::getFinancechecher, serviceFundtax.getFinancechecher());
        }
        if (serviceFundtax.getUploadtime() != null){
            wrappers.eq(ServiceFundtax::getUploadtime ,serviceFundtax.getUploadtime());
        if (StringUtils.isNotBlank(serviceFundtax.getUploadflag())) {
            wrappers.eq(ServiceFundtax::getUploadflag, serviceFundtax.getUploadflag());
        }
        if (StringUtils.isNotBlank(serviceFundtax.getUpdownremark())){
            wrappers.eq(ServiceFundtax::getUpdownremark ,serviceFundtax.getUpdownremark());
        if (serviceFundtax.getUploadtime() != null) {
            wrappers.eq(ServiceFundtax::getUploadtime, serviceFundtax.getUploadtime());
        }
        if (StringUtils.isNotBlank(serviceFundtax.getUpdownremark())) {
            wrappers.eq(ServiceFundtax::getUpdownremark, serviceFundtax.getUpdownremark());
        }
        wrappers.orderByDesc(ServiceFundtax::getCreateTime);
        return this.list(wrappers);
    }
    @Override
    public Integer getMaxFundTaxId() {
        return serviceFundtaxMapper.getMaxFundTaxId();
    }
    /**
     * 批量算税主入口
     * 1. 校验参数
     * 2. 只允许最新批次算税
     * 3. 对当前批次 service_fundtax 加行锁,防并发重复算税
     * 4. 查询本批次所有 ServiceFund(按 id 升序),并重置 istax
     * 5. 预查询本月所有身份证号的累计金额,缓存到 Map
     * 6. 校验当月是否存在历史口径(v1)算税记录,防止新旧口径混算
     * 7. 遍历每个 ServiceFund 逐单算税,汇总后回写 service_fundtax
     * <p>
     * 整批在一个事务内完成:任一条失败则整批回滚,不会出现半批数据。
     *
     * @param fundTaxVO 批次算税参数
     * @return 是否算税成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean batchFundTax(FundTaxVO fundTaxVO) {
        log.info("批量算税的fundTaxVO入参为:{}", fundTaxVO);
        // 1. 校验参数
        if (fundTaxVO.getFundTaxId() == null) {
            throw new BaseException("分批算税出问题了,请检查后再进行计算");
        }
        // 2. 只允许最新批次算税
        if (fundTaxVO.getAddOrupdate() == 1) {
            Integer maxFundTaxId = serviceFundtaxMapper.getMaxFundTaxId();
            log.info("批量算税的maxFundTaxId为:{}", maxFundTaxId);
            if (maxFundTaxId == null || !fundTaxVO.getFundTaxId().equals(Long.valueOf(maxFundTaxId))) {
                throw new BaseException("该批数据不能算税");
            }
        }
        // 3. 对当前批次汇总单加行锁(事务内有效),防止并发重复算税
        ServiceFundtax fundtax = serviceFundtaxMapper.selectByIdForUpdate(fundTaxVO.getFundTaxId());
        if (fundtax == null) {
            throw new BaseException("未找到算税汇总单,ID=" + fundTaxVO.getFundTaxId());
        }
        // 4. 查询本批次所有 ServiceFund(按 id 升序)
        ServiceFund serviceFund = new ServiceFund();
        serviceFund.setFundTaxId(fundTaxVO.getFundTaxId());
        serviceFund.setDel_flag(0);
        List<ServiceFund> serviceFunds = serviceFundService.selectServiceFundList(serviceFund);
        if (CollectionUtils.isEmpty(serviceFunds)) {
            log.warn("未查询到相关ServiceFund,fundTaxId={}", fundTaxVO.getFundTaxId());
            return false;
        }
        // 重置本批 istax 与算税时间,使本月累计查询不会重复计入本批
        for (ServiceFund serviceFund1 : serviceFunds) {
            serviceFundMapper.updateFundIsTexById(serviceFund1.getId(), 0L);
        }
        // 按 id 升序排序,保证处理顺序一致
        serviceFunds.sort(Comparator.comparing(ServiceFund::getId));
        // 5. 预查询本月所有身份证号的累计金额,缓存到 Map,提升后续算税效率
        Date taxTime = new Date();
        Date firstDay = Date.from(LocalDate.now().with(TemporalAdjusters.firstDayOfMonth()).atStartOfDay(ZoneId.systemDefault()).toInstant());
        TaxMoneyByItemEO taxMoneyVO = new TaxMoneyByItemEO();
        taxMoneyVO.setFirstDay(firstDay);
        taxMoneyVO.setTaxTime(taxTime);
        Map<String, TaxMoneySumEO> tempTaxSumMap = new HashMap<>();
        List<TaxMoneySumEO> taxSum = serviceFunddetailMapper.getTaxSum(taxMoneyVO);
        if (CollectionUtils.isNotEmpty(taxSum)) {
            for (TaxMoneySumEO taxMoneySumEO : taxSum) {
                tempTaxSumMap.put(taxMoneySumEO.getIDCardNo(), taxMoneySumEO);
                // 6. 当月已存在的历史口径(v1)记录会让累计基数新旧混算,直接阻止
                if (taxMoneySumEO.getV1Count() != null && taxMoneySumEO.getV1Count() > 0) {
                    throw new BaseException("当月已存在旧口径(v1)算税记录,为避免新旧口径混算,"
                            + "本月请继续使用旧口径或从下个月起再按新口径算税。人员身份证号:"
                            + taxMoneySumEO.getIDCardNo());
                }
            }
        }
        // 7. 遍历每个 ServiceFund,逐单算税并汇总
        BigDecimal pretaxTotal = BigDecimal.ZERO;
        BigDecimal vatTotal = BigDecimal.ZERO;
        BigDecimal cityTaxTotal = BigDecimal.ZERO;
        BigDecimal laborPretaxTotal = BigDecimal.ZERO;
        BigDecimal taxTotal = BigDecimal.ZERO;
        BigDecimal taxedTotal = BigDecimal.ZERO;
        for (ServiceFund serviceFund1 : serviceFunds) {
            ServiceFunddetail serviceFunddetail = new ServiceFunddetail();
            serviceFunddetail.setFundid(serviceFund1.getId());
            List<ServiceFunddetail> serviceFunddetails = serviceFunddetailMapper.selectServiceFunddetailList(serviceFunddetail);
            if (CollectionUtils.isEmpty(serviceFunddetails)) {
                throw new BaseException("单据没有可算税的明细,单据ID=" + serviceFund1.getId()
                        + ",捐献案例=" + serviceFund1.getDonorname());
            }
            // 传入累计金额缓存与统一算税时间
            serviceFunddetailService.calculateTax(serviceFunddetails, tempTaxSumMap, taxTime);
            for (ServiceFunddetail detail : serviceFunddetails) {
                pretaxTotal = pretaxTotal.add(toMoney(detail.getAmount()));
                vatTotal = vatTotal.add(toMoney(detail.getVatAmount()));
                cityTaxTotal = cityTaxTotal.add(toMoney(detail.getCityTaxAmount()));
                laborPretaxTotal = laborPretaxTotal.add(toMoney(detail.getLaborPretaxAmount()));
                taxTotal = taxTotal.add(toMoney(detail.getTaxamount()));
                taxedTotal = taxedTotal.add(toMoney(detail.getTaxedamount()));
            }
        }
        // 8. 回写汇总单 service_fundtax(6 个金额 + 算税状态 + 版本)
        ServiceFundtax updateFundtax = new ServiceFundtax();
        updateFundtax.setId(fundTaxVO.getFundTaxId());
        updateFundtax.setPretaxamount(VatTaxUtils.roundMoney(pretaxTotal));
        updateFundtax.setVatAmount(VatTaxUtils.roundMoney(vatTotal));
        updateFundtax.setCityTaxAmount(VatTaxUtils.roundMoney(cityTaxTotal));
        updateFundtax.setLaborPretaxAmount(VatTaxUtils.roundMoney(laborPretaxTotal));
        updateFundtax.setTaxamount(VatTaxUtils.roundMoney(taxTotal));
        updateFundtax.setTaxMoney(VatTaxUtils.roundMoney(taxTotal));
        updateFundtax.setTaxedamount(VatTaxUtils.roundMoney(taxedTotal));
        updateFundtax.setTaxVersion(VatTaxUtils.TAX_VERSION_V2);
        updateFundtax.setIstax(1);
        updateFundtax.setTaxedtime(taxTime);
        serviceFundtaxMapper.updateById(updateFundtax);
        log.info("批量算税完成,fundTaxId={},税前={},增值税={},城建税={},劳务税前={},劳务个税={},劳务税后={}",
                fundTaxVO.getFundTaxId(), pretaxTotal, vatTotal, cityTaxTotal, laborPretaxTotal, taxTotal, taxedTotal);
        return true;
    }
    /**
     * null 安全的金额转换
     */
    private static BigDecimal toMoney(Double value) {
        return value == null ? BigDecimal.ZERO : BigDecimal.valueOf(value);
    }
}