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<BillingInfoMapper, BillingInfo> 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<SysDept> 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<ContractOutBound> 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<ContractOutBound> outBoundList = contractOutBoundService.list(lambdaQueryWrapper);
|
|
if (outBoundList != null) {
|
if (!outBoundList.isEmpty()) {
|
List<ContractOutBoundVo> 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<Product>().eq(Product::getErpCode, outBound.getSubjectMatterCode()).last("limit 1"));
|
Product productP = productService.getOne(new LambdaQueryWrapper<Product>().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<ContractSubjectMatter>()
|
.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<ContractOutBoundVo> 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<ContractOutBoundVo> getListGroupingByProductId(List<ContractOutBoundVo> list) {
|
//提取productId
|
List<Long> productIds = list.stream().map(ContractOutBoundVo::getProductId).collect(Collectors.toList());
|
//去重
|
List<Long> result = productIds.stream().distinct().collect(Collectors.toList());
|
List<ContractOutBoundVo> 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;
|
}
|
}
|