| | |
| | | package com.ruoyi.sales.service.impl; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; |
| | |
| | | import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.ruoyi.account.pojo.AccountIncome; |
| | | import com.ruoyi.account.service.AccountIncomeService; |
| | | import com.ruoyi.aftersalesservice.pojo.AfterSalesService; |
| | | import com.ruoyi.basic.mapper.CustomerMapper; |
| | | import com.ruoyi.basic.mapper.ProductMapper; |
| | | import com.ruoyi.basic.mapper.ProductModelMapper; |
| | | import com.ruoyi.basic.pojo.Customer; |
| | | import com.ruoyi.common.enums.FileNameType; |
| | | import com.ruoyi.common.enums.SaleEnum; |
| | | import com.ruoyi.common.exception.base.BaseException; |
| | | import com.ruoyi.common.utils.DateUtils; |
| | | import com.ruoyi.common.utils.EnumUtil; |
| | | import com.ruoyi.common.utils.SecurityUtils; |
| | | import com.ruoyi.common.utils.StringUtils; |
| | | import com.ruoyi.common.utils.poi.ExcelUtil; |
| | |
| | | import com.ruoyi.other.mapper.TempFileMapper; |
| | | import com.ruoyi.other.pojo.TempFile; |
| | | import com.ruoyi.production.mapper.*; |
| | | import com.ruoyi.production.pojo.*; |
| | | import com.ruoyi.production.service.ProductionProductMainService; |
| | | import com.ruoyi.production.service.impl.ProductionProductMainServiceImpl; |
| | | import com.ruoyi.project.system.domain.SysDept; |
| | | import com.ruoyi.project.system.domain.SysUser; |
| | | import com.ruoyi.project.system.mapper.SysDeptMapper; |
| | | import com.ruoyi.project.system.mapper.SysUserMapper; |
| | | import com.ruoyi.purchase.dto.SimpleReturnOrderGroupDto; |
| | | import com.ruoyi.purchase.mapper.PurchaseReturnOrderProductsMapper; |
| | | import com.ruoyi.quality.mapper.QualityInspectMapper; |
| | | import com.ruoyi.quality.pojo.QualityInspect; |
| | | import com.ruoyi.sales.dto.*; |
| | | import com.ruoyi.sales.mapper.*; |
| | | import com.ruoyi.sales.pojo.*; |
| | | import com.ruoyi.sales.service.ISalesLedgerProductService; |
| | | import com.ruoyi.sales.service.ISalesLedgerService; |
| | | import com.ruoyi.sales.service.ReceiptPaymentService; |
| | | import lombok.RequiredArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.apache.commons.io.FilenameUtils; |
| | | import org.jetbrains.annotations.Nullable; |
| | | import org.springframework.beans.BeanUtils; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.beans.factory.annotation.Value; |
| | |
| | | @RequiredArgsConstructor |
| | | @Slf4j |
| | | public class SalesLedgerServiceImpl extends ServiceImpl<SalesLedgerMapper, SalesLedger> implements ISalesLedgerService { |
| | | private final AccountIncomeService accountIncomeService; |
| | | |
| | | private final SalesLedgerMapper salesLedgerMapper; |
| | | |
| | | private final CustomerMapper customerMapper; |
| | | |
| | | private final SalesLedgerProductMapper salesLedgerProductMapper; |
| | | private final SalesLedgerProductServiceImpl salesLedgerProductServiceImpl; |
| | | |
| | | private final CommonFileMapper commonFileMapper; |
| | | |
| | | private final TempFileMapper tempFileMapper; |
| | | |
| | | private final ReceiptPaymentMapper receiptPaymentMapper; |
| | | |
| | | private final ShippingInfoServiceImpl shippingInfoServiceImpl; |
| | | |
| | | private final CommonFileServiceImpl commonFileService; |
| | | |
| | | private final ShippingInfoMapper shippingInfoMapper; |
| | | |
| | | private final InvoiceLedgerMapper invoiceLedgerMapper; |
| | | |
| | | private final SalesLedgerSchedulingMapper salesLedgerSchedulingMapper; |
| | | |
| | | private final SalesLedgerWorkMapper salesLedgerWorkMapper; |
| | | |
| | | private final SalesLedgerProductionAccountingMapper salesLedgerProductionAccountingMapper; |
| | | |
| | | private final InvoiceRegistrationProductMapper invoiceRegistrationProductMapper; |
| | | |
| | | private final InvoiceRegistrationMapper invoiceRegistrationMapper; |
| | | |
| | | private final ProductOrderMapper productOrderMapper; |
| | | |
| | | private final ProcessRouteMapper processRouteMapper; |
| | | private final ProductProcessRouteMapper productProcessRouteMapper; |
| | | |
| | | private final ProcessRouteItemMapper processRouteItemMapper; |
| | | |
| | | private final ProductProcessRouteItemMapper productProcessRouteItemMapper; |
| | | |
| | | private final ProductWorkOrderMapper productWorkOrderMapper; |
| | | |
| | | private final ProductionProductMainMapper productionProductMainMapper; |
| | | |
| | | private final ProductionProductOutputMapper productionProductOutputMapper; |
| | | |
| | | private final ProductionProductInputMapper productionProductInputMapper; |
| | | |
| | | private final QualityInspectMapper qualityInspectMapper; |
| | | |
| | | @Autowired |
| | | private SysDeptMapper sysDeptMapper; |
| | | |
| | | @Value("${file.upload-dir}") |
| | | private String uploadDir; |
| | | |
| | | private static final String LOCK_PREFIX = "contract_no_lock:"; |
| | | private static final long LOCK_WAIT_TIMEOUT = 10; // 锁等待超时时间(秒) |
| | | private static final long LOCK_EXPIRE_TIME = 30; // 锁自动过期时间(秒) |
| | | |
| | | private final AccountIncomeService accountIncomeService; |
| | | private final SalesLedgerMapper salesLedgerMapper; |
| | | private final CustomerMapper customerMapper; |
| | | private final SalesLedgerProductMapper salesLedgerProductMapper; |
| | | private final SalesLedgerProductServiceImpl salesLedgerProductServiceImpl; |
| | | private final CommonFileMapper commonFileMapper; |
| | | private final TempFileMapper tempFileMapper; |
| | | private final ReceiptPaymentMapper receiptPaymentMapper; |
| | | private final ShippingInfoServiceImpl shippingInfoServiceImpl; |
| | | private final CommonFileServiceImpl commonFileService; |
| | | private final ShippingInfoMapper shippingInfoMapper; |
| | | private final InvoiceLedgerMapper invoiceLedgerMapper; |
| | | private final SalesLedgerSchedulingMapper salesLedgerSchedulingMapper; |
| | | private final SalesLedgerWorkMapper salesLedgerWorkMapper; |
| | | private final SalesLedgerProductionAccountingMapper salesLedgerProductionAccountingMapper; |
| | | private final InvoiceRegistrationProductMapper invoiceRegistrationProductMapper; |
| | | private final InvoiceRegistrationMapper invoiceRegistrationMapper; |
| | | private final ProductOrderMapper productOrderMapper; |
| | | private final ProcessRouteMapper processRouteMapper; |
| | | private final ProductProcessRouteMapper productProcessRouteMapper; |
| | | private final ProcessRouteItemMapper processRouteItemMapper; |
| | | private final ProductProcessRouteItemMapper productProcessRouteItemMapper; |
| | | private final ProductWorkOrderMapper productWorkOrderMapper; |
| | | private final ProductionProductMainMapper productionProductMainMapper; |
| | | private final ProductionProductOutputMapper productionProductOutputMapper; |
| | | private final ProductionProductInputMapper productionProductInputMapper; |
| | | private final QualityInspectMapper qualityInspectMapper; |
| | | private final RedisTemplate<String, String> redisTemplate; |
| | | @Autowired |
| | | private SysDeptMapper sysDeptMapper; |
| | | @Value("${file.upload-dir}") |
| | | private String uploadDir; |
| | | @Autowired |
| | | private ProductModelMapper productModelMapper; |
| | | |
| | |
| | | private ProductStructureMapper productStructureMapper; |
| | | @Autowired |
| | | private ProductionProductMainService productionProductMainService; |
| | | @Autowired |
| | | private PurchaseReturnOrderProductsMapper purchaseReturnOrderProductsMapper; |
| | | ; |
| | | @Autowired |
| | | private SysUserMapper sysUserMapper; |
| | | @Autowired |
| | | private ReceiptPaymentService receiptPaymentService; |
| | | |
| | | @Override |
| | | public List<SalesLedger> selectSalesLedgerList(SalesLedgerDto salesLedgerDto) { |
| | | return salesLedgerMapper.selectSalesLedgerList(salesLedgerDto); |
| | | } |
| | | |
| | | public List<SalesLedgerProduct> getSalesLedgerProductListByRelateId(Long relateId, SaleEnum type) { |
| | | LambdaQueryWrapper<SalesLedgerProduct> productWrapper = new LambdaQueryWrapper<>(); |
| | | productWrapper.eq(SalesLedgerProduct::getSalesLedgerId, relateId); |
| | | productWrapper.eq(SalesLedgerProduct::getType, type.getCode()); |
| | | return salesLedgerProductMapper.selectList(productWrapper); |
| | | } |
| | | |
| | | @Override |
| | | public List<SalesLedgerProduct> getSalesLedgerProductListByIds(@Nullable List<Long> relateIds, SaleEnum type) { |
| | | if (CollectionUtils.isEmpty(relateIds)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | LambdaQueryWrapper<SalesLedgerProduct> productWrapper = new LambdaQueryWrapper<>(); |
| | | productWrapper.in(SalesLedgerProduct::getId, relateIds); |
| | | productWrapper.eq(SalesLedgerProduct::getType, type.getCode()); |
| | | List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(productWrapper); |
| | | if (type.equals(SaleEnum.PURCHASE)) { |
| | | // 查询退货信息 |
| | | List<Long> productIds = salesLedgerProducts.stream().map(SalesLedgerProduct::getId).collect(Collectors.toList()); |
| | | List<SimpleReturnOrderGroupDto> groupListByProductIds = new ArrayList<>(); |
| | | if(CollectionUtils.isNotEmpty(productIds)){ |
| | | groupListByProductIds = purchaseReturnOrderProductsMapper.getReturnOrderGroupListByProductIds(productIds); |
| | | } |
| | | Map<Long, BigDecimal> returnOrderGroupDtoMap = groupListByProductIds.stream().collect(Collectors.toMap(SimpleReturnOrderGroupDto::getSalesLedgerProductId, SimpleReturnOrderGroupDto::getSumReturnQuantity)); |
| | | salesLedgerProducts.forEach(item -> { |
| | | BigDecimal returnQuality = returnOrderGroupDtoMap.getOrDefault(item.getId(), BigDecimal.ZERO); |
| | | item.setReturnQuality(returnQuality); |
| | | item.setAvailableQuality(item.getQuantity().subtract(returnQuality)); |
| | | }); |
| | | } |
| | | return salesLedgerProducts; |
| | | } |
| | | |
| | | @Override |
| | |
| | | return salesLedgerMapper.selectSalesLedgerListPage(page, salesLedgerDto); |
| | | } |
| | | |
| | | @Autowired |
| | | private SysUserMapper sysUserMapper; |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public AjaxResult importData(MultipartFile file) { |
| | |
| | | salesLedgerMapper.insert(salesLedger); |
| | | |
| | | |
| | | List<SalesLedgerProduct> insertedProducts = new ArrayList<>(); |
| | | for (SalesLedgerProductImportDto salesLedgerProductImportDto : salesLedgerProductImportDtos) { |
| | | SalesLedgerProduct salesLedgerProduct = new SalesLedgerProduct(); |
| | | BeanUtils.copyProperties(salesLedgerProductImportDto, salesLedgerProduct); |
| | |
| | | salesLedgerProduct.setApproveStatus(0); |
| | | salesLedgerProduct.setPendingInvoiceTotal(salesLedgerProductImportDto.getTaxInclusiveTotalPrice()); |
| | | salesLedgerProductMapper.insert(salesLedgerProduct); |
| | | insertedProducts.add(salesLedgerProduct); |
| | | // 添加生产数据 |
| | | salesLedgerProductServiceImpl.addProductionData(salesLedgerProduct); |
| | | } |
| | | // 导入时同样自动全额开票、自动全额回款 |
| | | autoInvoiceAndReceiptPayment(salesLedger, insertedProducts); |
| | | } |
| | | |
| | | return AjaxResult.success("导入成功"); |
| | |
| | | |
| | | @Override |
| | | public IPage<SalesLedgerDto> listSalesLedger(SalesLedgerDto salesLedgerDto, Page page) { |
| | | IPage<SalesLedgerDto> salesLedgerDtoIPage = salesLedgerMapper.listSalesLedger(page, salesLedgerDto); |
| | | IPage<SalesLedgerDto> salesLedgerDtoIPage = salesLedgerMapper.listSalesLedgerAndShipped(page, salesLedgerDto); |
| | | for (SalesLedgerDto salesLedger : salesLedgerDtoIPage.getRecords()) { |
| | | LambdaQueryWrapper<SalesLedgerProduct> productWrapper = new LambdaQueryWrapper<>(); |
| | | productWrapper.eq(SalesLedgerProduct::getSalesLedgerId, salesLedger.getId()); |
| | |
| | | .eq(ShippingInfo::getSalesLedgerProductId, product.getId()) |
| | | .orderByDesc(ShippingInfo::getCreateTime) |
| | | .last("limit 1")); |
| | | product.setShippingCarNumber(shippingInfo.getShippingCarNumber()); |
| | | product.setShippingDate(shippingInfo.getShippingDate()); |
| | | if (shippingInfo != null) { |
| | | product.setShippingStatus(shippingInfo.getStatus()); |
| | | |
| | | } |
| | | } |
| | | // 过滤只保留发货记录 |
| | | products = products.stream().filter(product -> "已发货".equals(product.getShippingStatus())).collect(Collectors.toList()); |
| | | if (!products.isEmpty()) { |
| | | salesLedger.setHasChildren(true); |
| | | salesLedger.setProductData(products); |
| | | } |
| | | } |
| | | |
| | | |
| | | return salesLedgerDtoIPage; |
| | | } |
| | | |
| | | |
| | | // 内部类用于存储聚合结果 |
| | | private static class GroupedCustomer { |
| | | private final Long customerId; |
| | | private final String customerName; |
| | | private BigDecimal totalAmount = BigDecimal.ZERO; |
| | | |
| | | public GroupedCustomer(Long customerId, String customerName) { |
| | | this.customerId = customerId; |
| | | this.customerName = customerName; |
| | | } |
| | | |
| | | public void addAmount(BigDecimal amount) { |
| | | if (amount != null) { |
| | | this.totalAmount = this.totalAmount.add(amount); |
| | | } |
| | | } |
| | | |
| | | public Long getCustomerId() { |
| | | return customerId; |
| | | } |
| | | |
| | | public String getCustomerName() { |
| | | return customerName; |
| | | } |
| | | |
| | | public BigDecimal getTotalAmount() { |
| | | return totalAmount; |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | if (CollectionUtils.isNotEmpty(invoiceLedgerIds)) { |
| | | LambdaQueryWrapper<ReceiptPayment> wrapperTree = new LambdaQueryWrapper<>(); |
| | | wrapperTree.in(ReceiptPayment::getInvoiceLedgerId, invoiceLedgerIds); |
| | | List<ReceiptPayment> receiptPayments = receiptPaymentMapper.selectList(wrapperTree); |
| | | // 同步删除回款对应的财务收入记录,避免产生孤儿数据 |
| | | if (CollectionUtils.isNotEmpty(receiptPayments)) { |
| | | List<Long> receiptPaymentIds = receiptPayments.stream() |
| | | .map(item -> item.getId().longValue()) |
| | | .collect(Collectors.toList()); |
| | | accountIncomeService.remove(new LambdaQueryWrapper<AccountIncome>() |
| | | .in(AccountIncome::getBusinessId, receiptPaymentIds) |
| | | .eq(AccountIncome::getBusinessType, 1)); |
| | | } |
| | | receiptPaymentMapper.delete(wrapperTree); |
| | | } |
| | | // 删除发货台账记录 |
| | |
| | | salesLedger.setCustomerName(customer.getCustomerName()); |
| | | salesLedger.setTenantId(customer.getTenantId()); |
| | | // 3. 新增或更新主表 |
| | | if (salesLedger.getId() == null) { |
| | | boolean isNew = salesLedger.getId() == null; |
| | | if (isNew) { |
| | | String contractNo = generateSalesContractNo(); |
| | | salesLedger.setSalesContractNo(contractNo); |
| | | salesLedgerMapper.insert(salesLedger); |
| | |
| | | // 4. 处理子表数据 |
| | | List<SalesLedgerProduct> productList = salesLedgerDto.getProductData(); |
| | | if (productList != null && !productList.isEmpty()) { |
| | | handleSalesLedgerProducts(salesLedger.getId(), productList, salesLedgerDto.getType()); |
| | | handleSalesLedgerProducts(salesLedger.getId(), productList, EnumUtil.fromCode(SaleEnum.class, salesLedgerDto.getType())); |
| | | updateMainContractAmount( |
| | | salesLedger.getId(), |
| | | productList, |
| | |
| | | if (salesLedgerDto.getTempFileIds() != null && !salesLedgerDto.getTempFileIds().isEmpty()) { |
| | | migrateTempFilesToFormal(salesLedger.getId(), salesLedgerDto.getTempFileIds()); |
| | | } |
| | | |
| | | // 6. 新增台账时自动全额开票、自动全额回款 |
| | | if (isNew && productList != null && !productList.isEmpty()) { |
| | | autoInvoiceAndReceiptPayment(salesLedger, productList); |
| | | } |
| | | return 1; |
| | | } catch (IOException e) { |
| | | throw new BaseException("文件迁移失败: " + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | // 文件迁移方法 |
| | | |
| | | /** |
| | | * 将临时文件迁移到正式目录 |
| | |
| | | } |
| | | } |
| | | |
| | | // 文件迁移方法 |
| | | |
| | | private void handleSalesLedgerProducts(Long salesLedgerId, List<SalesLedgerProduct> products, Integer type) { |
| | | @Override |
| | | public void handleSalesLedgerProducts(Long salesLedgerId, List<SalesLedgerProduct> products, SaleEnum type) { |
| | | // 按ID分组,区分新增和更新的记录 |
| | | Map<Boolean, List<SalesLedgerProduct>> partitionedProducts = products.stream() |
| | | .peek(p -> p.setSalesLedgerId(salesLedgerId)) |
| | |
| | | // 执行更新操作 |
| | | if (!updateList.isEmpty()) { |
| | | for (SalesLedgerProduct product : updateList) { |
| | | product.setType(type); |
| | | product.setType(type.getCode()); |
| | | salesLedgerProductMapper.updateById(product); |
| | | } |
| | | } |
| | | // 执行插入操作 |
| | | if (!insertList.isEmpty()) { |
| | | for (SalesLedgerProduct salesLedgerProduct : insertList) { |
| | | salesLedgerProduct.setType(type); |
| | | salesLedgerProduct.setType(type.getCode()); |
| | | salesLedgerProduct.setNoInvoiceNum(salesLedgerProduct.getQuantity()); |
| | | salesLedgerProduct.setNoInvoiceAmount(salesLedgerProduct.getTaxInclusiveTotalPrice()); |
| | | salesLedgerProduct.setPendingInvoiceTotal(salesLedgerProduct.getTaxInclusiveTotalPrice()); |
| | |
| | | salesLedgerProductServiceImpl.addProductionData(salesLedgerProduct); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 新增销售台账时自动全额开票、自动全额回款 |
| | | * <p> |
| | | * 1. 按合同全额自动生成开票登记(invoice_registration + invoice_registration_product + invoice_ledger); |
| | | * 2. 按开票全额自动生成回款登记(receipt_payment)及财务收入记录(account_income)。 |
| | | * |
| | | * @param salesLedger 销售台账主表(已入库) |
| | | * @param products 台账产品列表(已入库,含主键ID) |
| | | */ |
| | | private void autoInvoiceAndReceiptPayment(SalesLedger salesLedger, List<SalesLedgerProduct> products) { |
| | | // 仅处理销售类产品 |
| | | List<SalesLedgerProduct> saleProducts = products.stream() |
| | | .filter(Objects::nonNull) |
| | | .filter(p -> p.getId() != null) |
| | | .filter(p -> SaleEnum.SALE.getCode().equals(p.getType())) |
| | | .collect(Collectors.toList()); |
| | | if (CollectionUtils.isEmpty(saleProducts)) { |
| | | return; |
| | | } |
| | | |
| | | String register = SecurityUtils.getLoginUser().getUser().getNickName(); |
| | | |
| | | // 1. 自动开票:生成一张开票登记主表,覆盖该台账全部产品 |
| | | InvoiceRegistration invoiceRegistration = new InvoiceRegistration(); |
| | | invoiceRegistration.setSalesLedgerId(salesLedger.getId().intValue()); |
| | | invoiceRegistration.setSalesContractNo(salesLedger.getSalesContractNo()); |
| | | invoiceRegistration.setCustomerId(salesLedger.getCustomerId() == null ? null : salesLedger.getCustomerId().intValue()); |
| | | invoiceRegistration.setSalesman(salesLedger.getSalesman()); |
| | | invoiceRegistration.setProjectName(salesLedger.getProjectName()); |
| | | invoiceRegistrationMapper.insert(invoiceRegistration); |
| | | |
| | | List<ReceiptPayment> receiptPaymentList = new ArrayList<>(); |
| | | for (SalesLedgerProduct product : saleProducts) { |
| | | BigDecimal invoiceNum = product.getQuantity(); |
| | | BigDecimal invoiceAmount = product.getTaxInclusiveTotalPrice(); |
| | | // 数量或金额缺失时跳过,不阻断台账新增 |
| | | if (invoiceNum == null || invoiceAmount == null |
| | | || invoiceNum.compareTo(BigDecimal.ZERO) <= 0 |
| | | || invoiceAmount.compareTo(BigDecimal.ZERO) <= 0) { |
| | | continue; |
| | | } |
| | | |
| | | // 1.1 产品未开票数量/金额清零(全额开票) |
| | | salesLedgerProductMapper.update( |
| | | null, |
| | | new LambdaUpdateWrapper<SalesLedgerProduct>() |
| | | .eq(SalesLedgerProduct::getId, product.getId()) |
| | | .set(SalesLedgerProduct::getNoInvoiceNum, BigDecimal.ZERO) |
| | | .set(SalesLedgerProduct::getNoInvoiceAmount, BigDecimal.ZERO) |
| | | ); |
| | | |
| | | // 1.2 开票登记产品 |
| | | InvoiceRegistrationProduct invoiceRegistrationProduct = new InvoiceRegistrationProduct(); |
| | | BeanUtils.copyProperties(product, invoiceRegistrationProduct); |
| | | invoiceRegistrationProduct.setId(null); |
| | | invoiceRegistrationProduct.setSalesLedgerId(salesLedger.getId().intValue()); |
| | | invoiceRegistrationProduct.setInvoiceRegistrationId(invoiceRegistration.getId()); |
| | | invoiceRegistrationProduct.setSalesLedgerProductId(product.getId().intValue()); |
| | | invoiceRegistrationProduct.setInvoiceNum(invoiceNum); |
| | | invoiceRegistrationProduct.setInvoiceAmount(invoiceAmount); |
| | | invoiceRegistrationProduct.setNoInvoiceNum(BigDecimal.ZERO); |
| | | invoiceRegistrationProduct.setNoInvoiceAmount(BigDecimal.ZERO); |
| | | invoiceRegistrationProductMapper.insert(invoiceRegistrationProduct); |
| | | |
| | | // 1.3 开票台账(发票号自动生成) |
| | | InvoiceLedger invoiceLedger = new InvoiceLedger(); |
| | | invoiceLedger.setInvoiceDate(LocalDate.now()); |
| | | invoiceLedger.setInvoiceRegistrationProductId(invoiceRegistrationProduct.getId()); |
| | | invoiceLedger.setInvoiceTotal(invoiceAmount); |
| | | invoiceLedger.setInvoiceNo(generateAutoInvoiceNo(product.getId())); |
| | | invoiceLedger.setCreateUser(SecurityUtils.getUserId().intValue()); |
| | | invoiceLedger.setInvoicePerson(register); |
| | | invoiceLedgerMapper.insert(invoiceLedger); |
| | | |
| | | // 2. 组装自动回款记录(按开票全额回款) |
| | | ReceiptPayment receiptPayment = new ReceiptPayment(); |
| | | receiptPayment.setReceiptPaymentType("0"); |
| | | receiptPayment.setReceiptPaymentAmount(invoiceAmount); |
| | | receiptPayment.setRegistrant(register); |
| | | receiptPayment.setInvoiceLedgerId(invoiceLedger.getId()); |
| | | receiptPayment.setSalesLedgerId(salesLedger.getId()); |
| | | receiptPayment.setSalesLedgerProductId(product.getId()); |
| | | receiptPayment.setReceiptPaymentDate(LocalDate.now()); |
| | | receiptPaymentList.add(receiptPayment); |
| | | } |
| | | |
| | | // 3. 自动回款(内部同步更新产品回款金额并生成财务收入记录) |
| | | if (!receiptPaymentList.isEmpty()) { |
| | | receiptPaymentService.receiptPaymentSaveOrUpdate(receiptPaymentList); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 生成自动开票发票号 |
| | | * |
| | | * @param salesLedgerProductId 销售台账产品ID |
| | | * @return 自动发票号 |
| | | */ |
| | | private String generateAutoInvoiceNo(Long salesLedgerProductId) { |
| | | return "AUTO" + System.currentTimeMillis() + salesLedgerProductId; |
| | | } |
| | | |
| | | private SalesLedger convertToEntity(SalesLedgerDto dto) { |
| | |
| | | throw new RuntimeException("动态更新主表金额失败", e); |
| | | } |
| | | } |
| | | |
| | | // 内部类用于存储聚合结果 |
| | | private static class GroupedCustomer { |
| | | private final Long customerId; |
| | | private final String customerName; |
| | | private BigDecimal totalAmount = BigDecimal.ZERO; |
| | | |
| | | public GroupedCustomer(Long customerId, String customerName) { |
| | | this.customerId = customerId; |
| | | this.customerName = customerName; |
| | | } |
| | | |
| | | public void addAmount(BigDecimal amount) { |
| | | if (amount != null) { |
| | | this.totalAmount = this.totalAmount.add(amount); |
| | | } |
| | | } |
| | | |
| | | public Long getCustomerId() { |
| | | return customerId; |
| | | } |
| | | |
| | | public String getCustomerName() { |
| | | return customerName; |
| | | } |
| | | |
| | | public BigDecimal getTotalAmount() { |
| | | return totalAmount; |
| | | } |
| | | } |
| | | } |