package com.by4cloud.platformx.business.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.by4cloud.platformx.admin.api.entity.SysDept; import com.by4cloud.platformx.admin.api.feign.RemoteDeptService; import com.by4cloud.platformx.business.entity.*; import com.by4cloud.platformx.business.invoice.service.BIPYsService; import com.by4cloud.platformx.business.mapper.BillingInfoMapper; import com.by4cloud.platformx.business.service.*; import com.by4cloud.platformx.business.vo.ContractOutBoundVo; import com.by4cloud.platformx.business.vo.InvoicePreviewVo; import com.by4cloud.platformx.common.core.util.R; import com.by4cloud.platformx.common.data.mybatis.BaseModel; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; /** * 开票信息 * * @author wjli * @date 2026-06-04 10:50:20 */ @Service @RequiredArgsConstructor public class BillingInfoServiceImpl extends ServiceImpl implements BillingInfoService { private final BillingInfoMapper billingInfoMapper; private final BusinessCustomerService businessCustomerService; private final ContractOutBoundService contractOutBoundService; private final ProductService productService; private final ContractSubjectMatterService contractSubjectMatterService; private final RemoteDeptService remoteDeptService; /* * 拼接开票数据 */ @Override public BillingInfo getInviceByContractId(InvoicePreviewVo previewVo,Contract contract,Integer doType) { Long contractId = previewVo.getContractId(); int showType = 0; // 0为拼接 1 为预览计算 if (previewVo.getContractOutBoundIds() != null && !previewVo.getContractOutBoundIds().isEmpty()) { showType = 1; } BillingInfo billingInfo = new BillingInfo(); billingInfo.setContractId(contractId); billingInfo.setContractName(contract.getContractName()); billingInfo.setContractNo(contract.getContractNo()); BusinessCustomer partA = businessCustomerService.getById(contract.getPartyAId()); if (partA != null) { billingInfo.setPartyA(partA.getCompanyName()); billingInfo.setCreditCodeA(partA.getCreditCode()); billingInfo.setBankAccountA(partA.getBankAccount()); billingInfo.setBankNameA(partA.getBankName()); } R r = remoteDeptService.getById(contract.getPartyBId()); SysDept dept = r.getData(); if (dept != null) { billingInfo.setPartyB(dept.getOrgName()); billingInfo.setCreditCodeB(dept.getOrgCode()); billingInfo.setBankAccountB(dept.getOrgBankAccount()); billingInfo.setBankNameB(dept.getOrgBank()); } if(doType==1) { if (billingInfo.getId() == null) { billingInfoMapper.insert(billingInfo); } } Long billingInfoId = billingInfo.getId(); LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); lambdaQueryWrapper.eq(ContractOutBound::getContractId, contract.getId()); lambdaQueryWrapper.eq(ContractOutBound::getInvoiceSatus, 0); if (showType == 1) { lambdaQueryWrapper.in(BaseModel::getId, previewVo.getContractOutBoundIds()); } lambdaQueryWrapper.orderByAsc(ContractOutBound::getOutBoundTime); List outBoundList = contractOutBoundService.list(lambdaQueryWrapper); if (outBoundList != null) { if (!outBoundList.isEmpty()) { List list = new ArrayList<>(); for (ContractOutBound outBound : outBoundList) { if(doType==1){ outBound.setInvoiceSatus(1); outBound.setSaleCreditId(billingInfoId); } ContractOutBoundVo vo = new ContractOutBoundVo(); BeanUtil.copyProperties(outBound, vo); Product product = productService.getOne(new LambdaQueryWrapper().eq(Product::getErpCode, outBound.getSubjectMatterCode()).last("limit 1")); Product productP = productService.getOne(new LambdaQueryWrapper().eq(Product::getId, product.getParentId()).last("limit 1")); if (product != null) { vo.setProductId(product.getId()); vo.setInvoiceName("*" + product.getTaxClass() + "*" + (productP != null ? productP.getProductName() : "") + "*"); vo.setTaxClass(product.getTaxClass()); vo.setTaxCode(product.getTaxCode()); vo.setTaxRate(product.getTaxRate()); } ContractSubjectMatter matter = contractSubjectMatterService.getOne(new LambdaQueryWrapper() .eq(ContractSubjectMatter::getContractId, contract.getId()) .eq(ContractSubjectMatter::getMaterialCode, outBound.getSubjectMatterCode()) .last("limit 1") ); if (matter != null) { vo.setSpecification(matter.getSpecification()); vo.setUnit(matter.getUnit()); vo.setUnitPrice(matter.getUnitPrice()); } list.add(vo); } billingInfo.setContractOutBoundList(list); if (showType == 1) { List result = getListGroupingByProductId(list); BigDecimal totalPriceAll = BigDecimal.ZERO; BigDecimal totalTaxAll = BigDecimal.ZERO; BigDecimal totalPriceNoTaxAll = BigDecimal.ZERO; for (ContractOutBoundVo outBoundVo : result) { outBoundVo.setTotalPrice(outBoundVo.getUnitPrice().multiply(outBoundVo.getOutBoundNum()).setScale(2, RoundingMode.HALF_UP)); totalPriceAll = totalPriceAll.add(outBoundVo.getTotalPrice()); outBoundVo.setTotalTax(getTaxAmount(outBoundVo.getTaxRate(), outBoundVo.getTotalPrice())); totalTaxAll = totalTaxAll.add(outBoundVo.getTotalTax()); outBoundVo.setTotalPriceNoTax(getNoTaxAmount(outBoundVo.getTaxRate(), outBoundVo.getTotalPrice())); totalPriceNoTaxAll = totalPriceNoTaxAll.add(outBoundVo.getTotalPriceNoTax()); } billingInfo.setTotalAmount(totalPriceAll); billingInfo.setTotalTax(totalTaxAll); billingInfo.setAmountNoTax(totalPriceNoTaxAll); billingInfo.setContractOutBoundList(result); if(billingInfoId != null){ billingInfoMapper.updateById(billingInfo); }else{ billingInfoMapper.insert(billingInfo); } } if(doType==1){ contractOutBoundService.updateBatchById(outBoundList); } } } return billingInfo; } private List getListGroupingByProductId(List list) { //提取productId List productIds = list.stream().map(ContractOutBoundVo::getProductId).collect(Collectors.toList()); //去重 List result = productIds.stream().distinct().collect(Collectors.toList()); List noRest = new ArrayList<>(); for(Long id : result){ ContractOutBoundVo newVo = new ContractOutBoundVo(); int times = 0; String obIds = ""; BigDecimal num = BigDecimal.ZERO; for(ContractOutBoundVo vo : list){ if(vo.getProductId().equals(id)){ times++; if(times == 1){ BeanUtil.copyProperties(vo,newVo); } num = num.add(vo.getOutBoundNum()); if(StrUtil.isEmpty(obIds)){ obIds = "" + vo.getId(); }else{ obIds += "," + vo.getId(); } } } newVo.setOutBoundNum(num); newVo.setContractOutBoundIds(obIds); noRest.add(newVo); } return noRest; } /* if (showType == 1) { //1.不含税金额=含税总额÷(1+税率) //2.税额=含税总额÷(1+税率)x税率 vo.setTotalPrice(vo.getUnitPrice().multiply(outBound.getOutBoundNum()).setScale(2, RoundingMode.HALF_UP)); vo.setTotalTax(getTaxAmount(vo.getTaxRate(), vo.getTotalPrice())); vo.setTotalPriceNoTax(getNoTaxAmount(vo.getTaxRate(), vo.getTotalPrice())); }*/ public BigDecimal getTaxAmount(double taxRate,BigDecimal totalPrice) { // 1、税率转BigDecimal并转为小数 13 → 0.13 BigDecimal taxPercent = BigDecimal.valueOf(taxRate).divide(new BigDecimal("100")); // 1+税率 BigDecimal rateSum = BigDecimal.ONE.add(taxPercent); // 不含税金额,保留2位、四舍五入 BigDecimal noTax = totalPrice.divide(rateSum, 2, RoundingMode.HALF_UP); // 税额 BigDecimal taxAmount = totalPrice.subtract(noTax); return taxAmount; } public BigDecimal getNoTaxAmount(double taxRate,BigDecimal totalPrice){ // 1、税率转BigDecimal并转为小数 13 → 0.13 BigDecimal taxPercent = BigDecimal.valueOf(taxRate).divide(new BigDecimal("100")); // 1+税率 BigDecimal rateSum = BigDecimal.ONE.add(taxPercent); // 不含税金额,保留2位、四舍五入 BigDecimal noTax = totalPrice.divide(rateSum, 2, RoundingMode.HALF_UP); // 税额 //BigDecimal taxAmount = totalPrice.subtract(noTax); return noTax; } }