yuan
20 小时以前 fcccabc2af00c6f433210945566e24891efaf8fa
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -8,12 +8,20 @@
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.mapper.sales.AccountInvoiceApplicationMapper;
import com.ruoyi.account.mapper.sales.AccountSalesCollectionMapper;
import com.ruoyi.account.pojo.sales.AccountInvoiceApplication;
import com.ruoyi.account.pojo.sales.AccountSalesCollection;
import com.ruoyi.basic.enums.ApplicationTypeEnum;
import com.ruoyi.basic.enums.RecordTypeEnum;
import com.ruoyi.basic.mapper.CustomerMapper;
import com.ruoyi.basic.mapper.CustomerUserMapper;
import com.ruoyi.basic.mapper.ProductMapper;
import com.ruoyi.basic.mapper.ProductModelMapper;
import com.ruoyi.basic.pojo.Customer;
import com.ruoyi.basic.pojo.CustomerUser;
import com.ruoyi.basic.pojo.Product;
import com.ruoyi.basic.pojo.ProductModel;
import com.ruoyi.basic.utils.FileUtil;
import com.ruoyi.common.enums.FileNameType;
import com.ruoyi.common.enums.SaleEnum;
@@ -26,7 +34,9 @@
import com.ruoyi.framework.security.LoginUser;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.other.mapper.TempFileMapper;
import com.ruoyi.production.mapper.*;
import com.ruoyi.production.mapper.ProductionProductInputMapper;
import com.ruoyi.production.mapper.ProductionProductMainMapper;
import com.ruoyi.production.mapper.ProductionProductOutputMapper;
import com.ruoyi.production.service.ProductionProductMainService;
import com.ruoyi.project.system.domain.SysDept;
import com.ruoyi.project.system.domain.SysUser;
@@ -36,8 +46,14 @@
import com.ruoyi.purchase.mapper.PurchaseReturnOrderProductsMapper;
import com.ruoyi.quality.mapper.QualityInspectMapper;
import com.ruoyi.sales.dto.*;
import com.ruoyi.sales.mapper.*;
import com.ruoyi.sales.pojo.*;
import com.ruoyi.sales.mapper.CommonFileMapper;
import com.ruoyi.sales.mapper.SalesLedgerMapper;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
import com.ruoyi.sales.mapper.ShippingInfoMapper;
import com.ruoyi.sales.pojo.CommonFile;
import com.ruoyi.sales.pojo.SalesLedger;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import com.ruoyi.sales.pojo.ShippingInfo;
import com.ruoyi.sales.service.ISalesLedgerService;
import com.ruoyi.sales.vo.SalesLedgerVo;
import lombok.RequiredArgsConstructor;
@@ -50,7 +66,10 @@
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.web.multipart.MultipartFile;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import java.io.InputStream;
import java.lang.reflect.Field;
@@ -78,13 +97,17 @@
    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 static final String IMPORT_DEFAULT_VALUE = "/";
    /** 导入自动新增产品大类时挂载的顶级产品节点名称 */
    private static final String FINISHED_PRODUCT_NAME = "成品";
    private final SalesLedgerMapper salesLedgerMapper;
    private final CustomerMapper customerMapper;
    private final CustomerUserMapper customerUserMapper;
    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;
@@ -94,6 +117,8 @@
    private final QualityInspectMapper qualityInspectMapper;
    private final RedisTemplate<String, String> redisTemplate;
    private final FileUtil fileUtil;
    private final AccountInvoiceApplicationMapper accountInvoiceApplicationMapper;
    private final AccountSalesCollectionMapper accountSalesCollectionMapper;
    @Autowired
    private SysDeptMapper sysDeptMapper;
@@ -164,10 +189,6 @@
        productWrapper.eq(SalesLedgerProduct::getType, 1);
        List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(productWrapper);
        for (SalesLedgerProduct product : products) {
            product.setOriginalNoInvoiceNum(product.getNoInvoiceNum());
            // 提供临时未开票数,未开票金额供前段计算
            product.setTempnoInvoiceAmount(product.getNoInvoiceAmount());
            product.setTempNoInvoiceNum(product.getNoInvoiceNum());
            product.setRegister(SecurityUtils.getLoginUser().getUser().getNickName());
            product.setRegisterDate(LocalDateTime.now());
            // 发货信息
@@ -268,39 +289,37 @@
    @Override
    public List<MonthlyAmountDto> getAmountHalfYear(Integer type) {
        LocalDate now = LocalDate.now();
        List<MonthlyAmountDto> result = new ArrayList<>();
        for (int i = 5; i >= 0; i--) {
            YearMonth yearMonth = YearMonth.from(now.minusMonths(i));
            LocalDateTime startTime = yearMonth.atDay(1).atStartOfDay();
            LocalDateTime endTime = yearMonth.atEndOfMonth().atTime(23, 59, 59);
            //  回款金额
            LambdaQueryWrapper<ReceiptPayment> receiptPaymentQuery = new LambdaQueryWrapper<>();
            receiptPaymentQuery
                    .ge(ReceiptPayment::getCreateTime, startTime)
                    .le(ReceiptPayment::getCreateTime, endTime);
            List<ReceiptPayment> receiptPayments =
                    receiptPaymentMapper.selectList(receiptPaymentQuery);
            BigDecimal receiptAmount = receiptPayments.stream()
                    .map(ReceiptPayment::getReceiptPaymentAmount)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            LocalDate startTime = yearMonth.atDay(1);
            LocalDate endTime = yearMonth.atEndOfMonth();
            MonthlyAmountDto dto = new MonthlyAmountDto();
            dto.setMonth(yearMonth.format(DateTimeFormatter.ofPattern("yyyy-MM")));
            dto.setReceiptAmount(receiptAmount);
            dto.setInvoiceAmount(BigDecimal.ZERO);
            //回款金额
            List<AccountSalesCollection> accountSalesCollections = accountSalesCollectionMapper.selectList(new LambdaQueryWrapper<AccountSalesCollection>()
                    .between(AccountSalesCollection::getCollectionDate, startTime, endTime));
            BigDecimal totalIncome = Optional.of(
                    accountSalesCollections.stream()
                            .map(AccountSalesCollection::getCollectionAmount)
                            .filter(Objects::nonNull)
                            .reduce(BigDecimal.ZERO, BigDecimal::add)
            ).orElse(BigDecimal.ZERO);
            dto.setReceiptAmount(totalIncome);
            //开票金额
            List<AccountInvoiceApplication> accountInvoiceApplications = accountInvoiceApplicationMapper.selectList(new LambdaQueryWrapper<AccountInvoiceApplication>()
                            .eq(AccountInvoiceApplication::getStatus,1)
                    .between(AccountInvoiceApplication::getApplyDate, startTime, endTime));
            BigDecimal totalInvoiceAmount = Optional.of(
                    accountInvoiceApplications.stream()
                            .map(AccountInvoiceApplication::getInvoiceAmount)
                            .filter(Objects::nonNull)
                            .reduce(BigDecimal.ZERO, BigDecimal::add)
            ).orElse(BigDecimal.ZERO);
            dto.setInvoiceAmount(totalInvoiceAmount);
            result.add(dto);
        }
        return result;
    }
@@ -323,16 +342,13 @@
            if (CollectionUtils.isEmpty(salesLedgerImportDtoList)) return AjaxResult.error("销售台账数据为空!");
            List<SalesLedgerImportDto> salesLedgerProductImportDtoList = stringListMap.get("销售产品数据");
            if (CollectionUtils.isEmpty(salesLedgerProductImportDtoList)) return AjaxResult.error("销售产品数据为空!");
            // 客户数据
            List<Customer> customers = customerMapper.selectList(new LambdaQueryWrapper<Customer>().in(Customer::getCustomerName,
                    salesLedgerImportDtoList.stream().map(SalesLedgerImportDto::getCustomerName).collect(Collectors.toList())));
//            // 规格型号数据
//            List<ProductModel> productModels = productModelMapper.selectList(new LambdaQueryWrapper<ProductModel>().in(ProductModel::getModel,
//                    salesLedgerProductImportDtoList.stream().map(SalesLedgerImportDto::getSpecificationModel).collect(Collectors.toList())));
//            // 产品大类数据
//            List<Product> productList = productMapper.selectList(new LambdaQueryWrapper<Product>().in(Product::getProductName,
//                    salesLedgerProductImportDtoList.stream().map(SalesLedgerImportDto::getProductCategory).collect(Collectors.toList())));
            List<Map<String, Object>> list = productModelMapper.getProductAndModelList();
            // 客户数据 - 参考 listPage 查询私海客户(type = 0)
            // type = 0(私海客户)或者 type = 1(公海客户)且已被分配,并且是自己领用、自己创建或者共享给自己的客户
            // 客户不存在时自动新增并挂到自己名下,公海客户自动领用/共享给自己
            Long loginUserId = loginUser.getUser().getUserId();
            Map<String, Customer> customerCache = new HashMap<>();
            // 产品大类、规格型号缓存,key = 产品大类 + | + 规格型号,不存在时自动新增
            Map<String, ProductModel> productModelCache = new HashMap<>();
            // 录入人数据
            List<SysUser> sysUsers = sysUserMapper.selectList(new LambdaQueryWrapper<SysUser>().in(SysUser::getNickName,
                    salesLedgerImportDtoList.stream().map(SalesLedgerImportDto::getEntryPerson).collect(Collectors.toList())));
@@ -343,21 +359,22 @@
                if (salesLedger1 != null) {
                    continue;
                }
                // 判断业务员是否存在
                SysUser salesman = sysUserMapper.selectOne(new LambdaQueryWrapper<SysUser>()
                        .eq(SysUser::getNickName, salesLedgerImportDto.getSalesman()));
                if (salesman == null) {
                    throw new RuntimeException("业务员:" + salesLedgerImportDto.getSalesman() + "不存在!");
                }
                SalesLedger salesLedger = new SalesLedger();
                BeanUtils.copyProperties(salesLedgerImportDto, salesLedger);
                salesLedger.setExecutionDate(DateUtils.toLocalDate(salesLedgerImportDto.getExecutionDate()));
                salesLedger.setDeliveryDate(DateUtils.toLocalDate(salesLedgerImportDto.getDeliveryDate()));
                // 通过客户名称查询客户ID,客户合同号
                salesLedger.setCustomerId(customers.stream()
                        .filter(customer -> customer.getCustomerName().equals(salesLedger.getCustomerName()))
                        .findFirst()
                        .map(Customer::getId)
                        .orElse(null));
                salesLedger.setCustomerContractNo(customers.stream()
                        .filter(customer -> customer.getCustomerName().equals(salesLedger.getCustomerName()))
                        .findFirst()
                        .map(Customer::getTaxpayerIdentificationNumber)
                        .orElse(null));
                // 通过客户名称查询客户ID,客户合同号,客户不存在时自动新增
                Customer customer = resolveImportCustomer(salesLedger.getCustomerName(), loginUserId,
                        loginUser.getNickName(), customerCache);
                salesLedger.setCustomerId(customer.getId());
                salesLedger.setCustomerContractNo(customer.getTaxpayerIdentificationNumber());
                Long aLong = sysUsers.stream()
                        .filter(sysUser -> sysUser.getNickName().equals(salesLedger.getEntryPerson()))
                        .findFirst()
@@ -384,30 +401,20 @@
                    salesLedgerProduct.setSalesLedgerId(salesLedger.getId());
                    salesLedgerProduct.setType(1);
                    // 计算不含税总价
                    salesLedgerProduct.setTaxExclusiveTotalPrice(salesLedgerProduct.getTaxInclusiveTotalPrice().divide(new BigDecimal(1).add(salesLedgerProduct.getTaxRate().divide(new BigDecimal(100))), 2, RoundingMode.HALF_UP));
                    salesLedgerProduct.setNoInvoiceNum(salesLedgerProduct.getQuantity());
                    salesLedgerProduct.setNoInvoiceAmount(salesLedgerProduct.getTaxExclusiveTotalPrice());
                    list.stream()
                            .filter(map -> Objects.equals(map.get("productName"), salesLedgerProduct.getProductCategory()) && Objects.equals(map.get("model"), salesLedgerProduct.getSpecificationModel()))
                            .findFirst()
                            .ifPresent(map -> {
                                salesLedgerProduct.setProductModelId(Long.parseLong(map.get("modelId").toString()));
                                salesLedgerProduct.setProductId(Long.parseLong(map.get("id").toString()));
                            });
//                    salesLedgerProduct.setProductId(productList.stream()
//                            .filter(product -> product.getProductName().equals(salesLedgerProduct.getProductCategory()))
//                            .findFirst()
//                            .map(Product::getId)
//                            .orElse(null));
//                    salesLedgerProduct.setProductModelId(productModels.stream()
//                            .filter(productModel -> productModel.getModel().equals(salesLedgerProduct.getSpecificationModel()))
//                            .findFirst()
//                            .map(ProductModel::getId)
//                            .orElse(null));
                    salesLedgerProduct.setTaxExclusiveTotalPrice(salesLedgerProduct.getTaxInclusiveTotalPrice().divide(new BigDecimal(1).add(salesLedgerProduct.getTaxRate().divide(new BigDecimal(100))), 6, RoundingMode.HALF_UP));
                    // 校验产品规格是否存在,产品大类、规格型号不存在时自动新增
                    ProductModel productModel = resolveImportProductModel(salesLedgerProduct.getProductCategory(),
                            salesLedgerProduct.getSpecificationModel(), salesLedgerProduct.getUnit(), productModelCache);
                    salesLedgerProduct.setProductModelId(productModel.getId());
                    salesLedgerProduct.setProductId(productModel.getProductId());
                    // 规格型号为空时取产品大类,单位为空时取规格型号上的单位
                    salesLedgerProduct.setSpecificationModel(productModel.getModel());
                    if (StringUtils.isEmpty(salesLedgerProduct.getUnit())) {
                        salesLedgerProduct.setUnit(productModel.getUnit());
                    }
                    salesLedgerProduct.setRegister(loginUser.getNickName());
                    salesLedgerProduct.setRegisterDate(LocalDateTime.now());
                    salesLedgerProduct.setApproveStatus(0);
                    salesLedgerProduct.setPendingInvoiceTotal(salesLedgerProductImportDto.getTaxInclusiveTotalPrice());
                    salesLedgerProduct.setIsProduction(salesLedgerProductImportDto.getIsProduction() == 1);
                    salesLedgerProductMapper.insert(salesLedgerProduct);
                    // 添加生产数据
@@ -418,8 +425,191 @@
            return AjaxResult.success("导入成功");
        } catch (Exception e) {
            e.printStackTrace();
            // 导入过程中会自动新增客户、产品大类、规格型号,失败时需要回滚,避免残留脏数据
            if (TransactionSynchronizationManager.isActualTransactionActive()) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            }
            return AjaxResult.error("导入失败:" + e.getMessage());
        }
    }
    /**
     * 导入时获取客户,客户不存在则自动新增并挂到当前登录人名下
     * <p>
     * 1、当前登录人可用的客户(私海,或公海已分配且自己领用/创建/共享):直接使用;
     * 2、同名公海客户未分配:领用到自己名下;
     * 3、同名公海客户已分配给别人:共享给自己;
     * 4、同名客户在别人私海:报错,不新建;
     * 5、客户不存在:新增私海客户挂到自己名下,纳税人识别号、电话等信息填 "/"。
     */
    private Customer resolveImportCustomer(String customerName, Long loginUserId, String nickName,
                                           Map<String, Customer> customerCache) {
        String name = StringUtils.trim(customerName);
        if (StringUtils.isEmpty(name)) {
            throw new RuntimeException("客户名称不能为空!");
        }
        Customer cachedCustomer = customerCache.get(name);
        if (cachedCustomer != null) {
            return cachedCustomer;
        }
        // 当前登录人可用的客户
        Customer customer = customerMapper.selectOne(new QueryWrapper<Customer>()
                .eq("customer_name", name)
                .and(wrapper -> wrapper.eq("type", 0)
                        .or(wrapper2 -> wrapper2.eq("type", 1).eq("is_assigned", 1)))
                .and(wrapper -> wrapper.eq("usage_user", loginUserId)
                        .or(wrapper2 -> wrapper2.eq("create_user", loginUserId)
                                .or(wrapper3 -> wrapper3.exists("select 1 from customer_user cu where cu.customer_id = customer.id and cu.user_id = " + loginUserId))))
                .last("limit 1"));
        if (customer == null) {
            customer = claimOrCreateImportCustomer(name, loginUserId, nickName);
        }
        customerCache.put(name, customer);
        return customer;
    }
    /**
     * 同名客户不属于当前登录人时的处理:公海未分配的领用到自己名下,公海已分配的共享给自己,
     * 在别人私海的直接报错,都不存在则新增客户
     */
    private Customer claimOrCreateImportCustomer(String customerName, Long loginUserId, String nickName) {
        List<Customer> sameNameCustomers = customerMapper.selectList(new QueryWrapper<Customer>()
                .eq("customer_name", customerName)
                .orderByAsc("id"));
        // 公海未分配客户,领用到自己名下
        Optional<Customer> publicUnassigned = sameNameCustomers.stream()
                .filter(item -> Objects.equals(item.getType(), 1)
                        && (item.getIsAssigned() == null || item.getIsAssigned() == 0))
                .findFirst();
        if (publicUnassigned.isPresent()) {
            Customer customer = publicUnassigned.get();
            customer.setIsAssigned(1);
            customer.setUsageStatus(1L);
            customer.setUsageUser(loginUserId);
            customerMapper.updateById(customer);
            return customer;
        }
        // 公海已分配给别人的客户,共享给自己
        Optional<Customer> publicAssigned = sameNameCustomers.stream()
                .filter(item -> Objects.equals(item.getType(), 1) && Objects.equals(item.getIsAssigned(), 1))
                .findFirst();
        if (publicAssigned.isPresent()) {
            Customer customer = publicAssigned.get();
            CustomerUser customerUser = new CustomerUser();
            customerUser.setCustomerId(customer.getId());
            customerUser.setUserId(loginUserId);
            customerUserMapper.insert(customerUser);
            return customer;
        }
        // 剩下的都是别人的私海客户
        if (!sameNameCustomers.isEmpty()) {
            throw new RuntimeException("客户:" + customerName + "已在其他人私海中,无法导入!");
        }
        // 客户不存在,新增私海客户并挂到自己名下
        Customer customer = new Customer();
        customer.setCustomerName(customerName);
        customer.setCustomerType(IMPORT_DEFAULT_VALUE);
        customer.setTaxpayerIdentificationNumber(IMPORT_DEFAULT_VALUE);
        customer.setCompanyAddress(IMPORT_DEFAULT_VALUE);
        customer.setCompanyPhone(IMPORT_DEFAULT_VALUE);
        customer.setContactPerson(IMPORT_DEFAULT_VALUE);
        customer.setContactPhone(IMPORT_DEFAULT_VALUE);
        customer.setBasicBankAccount(IMPORT_DEFAULT_VALUE);
        customer.setBankAccount(IMPORT_DEFAULT_VALUE);
        customer.setBankCode(IMPORT_DEFAULT_VALUE);
        customer.setMaintainer(nickName);
        customer.setMaintenanceTime(new Date());
        // 私海客户,领用人为当前登录人
        customer.setType(0);
        customer.setIsAssigned(0);
        customer.setUsageStatus(1L);
        customer.setUsageUser(loginUserId);
        customerMapper.insert(customer);
        return customer;
    }
    /**
     * 导入时获取规格型号,产品大类、规格型号不存在则自动新增
     * <p>
     * 规格型号为空时取产品大类作为规格型号;产品大类不存在时挂到顶级"成品"节点下;
     * 新增规格型号时按"规格型号 + 规格ID + _ + 三位流水号"生成产品编码
     */
    private ProductModel resolveImportProductModel(String productCategory, String specificationModel, String unit,
                                                   Map<String, ProductModel> productModelCache) {
        String category = StringUtils.trim(productCategory);
        if (StringUtils.isEmpty(category)) {
            throw new RuntimeException("产品大类不能为空!");
        }
        // 规格型号为空时取产品大类当产品规格
        String model = StringUtils.trim(specificationModel);
        if (StringUtils.isEmpty(model)) {
            model = category;
        }
        String cacheKey = category + "|" + model;
        ProductModel cachedProductModel = productModelCache.get(cacheKey);
        if (cachedProductModel != null) {
            return cachedProductModel;
        }
        // 产品大类不存在则新增到顶级"成品"节点下
        Product product = productMapper.selectOne(new LambdaQueryWrapper<Product>()
                .eq(Product::getProductName, category)
                .orderByAsc(Product::getId)
                .last("limit 1"));
        if (product == null) {
            product = new Product();
            product.setParentId(getFinishedProductId());
            product.setProductName(category);
            productMapper.insert(product);
        }
        // 规格型号不存在则新增
        ProductModel productModel = productModelMapper.selectOne(new LambdaQueryWrapper<ProductModel>()
                .eq(ProductModel::getProductId, product.getId())
                .eq(ProductModel::getModel, model)
                .orderByAsc(ProductModel::getId)
                .last("limit 1"));
        if (productModel == null) {
            productModel = new ProductModel();
            productModel.setProductId(product.getId());
            productModel.setModel(model);
            productModel.setUnit(StringUtils.isEmpty(unit) ? IMPORT_DEFAULT_VALUE : StringUtils.trim(unit));
            productModelMapper.insert(productModel);
            // 产品编码依赖自增的规格ID,插入后再回填
            productModel.setProductCode(generateProductCode(productModel.getModel(), productModel.getId()));
            productModelMapper.updateById(productModel);
        }
        productModelCache.put(cacheKey, productModel);
        return productModel;
    }
    /**
     * 查询顶级"成品"产品节点(产品名称为成品且父ID为空)
     */
    private Long getFinishedProductId() {
        Product finishedProduct = productMapper.selectOne(new LambdaQueryWrapper<Product>()
                .eq(Product::getProductName, FINISHED_PRODUCT_NAME)
                .isNull(Product::getParentId)
                .orderByAsc(Product::getId)
                .last("limit 1"));
        if (finishedProduct == null) {
            throw new RuntimeException("产品档案中不存在顶级节点:" + FINISHED_PRODUCT_NAME + ",无法自动新增产品大类!");
        }
        return finishedProduct.getId();
    }
    /**
     * 生成产品编码,规则:规格型号 + 规格ID + _ + 三位流水号,编码已存在时流水号递增
     */
    private String generateProductCode(String model, Long productModelId) {
        String prefix = model + productModelId + "_";
        for (int sequence = 1; sequence < 1000; sequence++) {
            String productCode = prefix + String.format("%03d", sequence);
            Long count = productModelMapper.selectCount(new LambdaQueryWrapper<ProductModel>()
                    .eq(ProductModel::getProductCode, productCode));
            if (count == null || count == 0) {
                return productCode;
            }
        }
        throw new RuntimeException("规格型号:" + model + "的产品编码流水号已超出范围!");
    }
    @Override
@@ -441,11 +631,7 @@
            productWrapper.eq(SalesLedgerProduct::getType, 1);
            List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(productWrapper);
            for (SalesLedgerProduct product : products) {
                product.setOriginalNoInvoiceNum(product.getNoInvoiceNum());
                // 提供临时未开票数,未开票金额供前段计算
                product.setTempnoInvoiceAmount(product.getNoInvoiceAmount());
                product.setTempNoInvoiceNum(product.getNoInvoiceNum());
                product.setRegister(SecurityUtils.getLoginUser().getUser().getNickName());
               product.setRegister(SecurityUtils.getLoginUser().getUser().getNickName());
                product.setRegisterDate(LocalDateTime.now());
                // 发货信息
                ShippingInfo shippingInfo = shippingInfoMapper.selectOne(new LambdaQueryWrapper<ShippingInfo>()
@@ -520,11 +706,6 @@
        List<Integer> invoiceLedgerIds = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(invoiceLedgerIds)) {
            LambdaQueryWrapper<ReceiptPayment> wrapperTree = new LambdaQueryWrapper<>();
            wrapperTree.in(ReceiptPayment::getInvoiceLedgerId, invoiceLedgerIds);
            receiptPaymentMapper.delete(wrapperTree);
        }
        // 删除发货台账记录
        List<ShippingInfo> shippingInfos = shippingInfoMapper.selectList(new LambdaQueryWrapper<ShippingInfo>()
                .in(ShippingInfo::getSalesLedgerId, idList));
@@ -559,9 +740,16 @@
        SalesLedger salesLedger = convertToEntity(salesLedgerDto);
        salesLedger.setCustomerName(customer.getCustomerName());
        salesLedger.setTenantId(customer.getTenantId());
        // 录入人:如果未传则使用当前登录用户
        if (StringUtils.isEmpty(salesLedger.getEntryPerson())) {
            salesLedger.setEntryPerson(String.valueOf(SecurityUtils.getUserId()));
        }
        // 3. 新增或更新主表
        if (salesLedger.getId() == null) {
            String contractNo = generateSalesContractNo();
            String contractNo = salesLedger.getSalesContractNo();
            if (StringUtils.isEmpty(contractNo)) {
                contractNo = generateSalesContractNo(salesLedgerDto.getEntryDate());
            }
            salesLedger.setSalesContractNo(contractNo);
            salesLedgerMapper.insert(salesLedger);
        } else {
@@ -609,9 +797,6 @@
        if (!insertList.isEmpty()) {
            for (SalesLedgerProduct salesLedgerProduct : insertList) {
                salesLedgerProduct.setType(type.getCode());
                salesLedgerProduct.setNoInvoiceNum(salesLedgerProduct.getQuantity());
                salesLedgerProduct.setNoInvoiceAmount(salesLedgerProduct.getTaxInclusiveTotalPrice());
                salesLedgerProduct.setPendingInvoiceTotal(salesLedgerProduct.getTaxInclusiveTotalPrice());
                salesLedgerProductMapper.insert(salesLedgerProduct);
                // 添加生产数据
                salesLedgerProductServiceImpl.addProductionData(salesLedgerProduct);
@@ -626,8 +811,8 @@
    }
    @Transactional(readOnly = true)
    public String generateSalesContractNo() {
        LocalDate currentDate = LocalDate.now();
    public String generateSalesContractNo(Date entryDate) {
        LocalDate currentDate = entryDate != null ? DateUtils.toLocalDate(entryDate) : LocalDate.now();
        String datePart = currentDate.format(DateTimeFormatter.BASIC_ISO_DATE);
        String lockKey = LOCK_PREFIX + datePart;
        String lockValue = Thread.currentThread().getId() + "-" + System.nanoTime(); // 唯一标识锁持有者