liyong
6 天以前 f5ee8e7afb178179c1d1d078cf42fe33dc7607f9
Merge remote-tracking branch 'origin/dev_New_pro' into dev_New_pro

# Conflicts:
# src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
已修改14个文件
371 ■■■■■ 文件已修改
src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java 79 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/dto/SalesLedgerImportDto.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/dto/SalesLedgerProductImportDto.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/service/impl/StaffOnJobServiceImpl.java 185 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/dto/StockInRecordDto.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/dto/StockInventoryDto.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/dto/StockOutRecordDto.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/stock/StockInRecordMapper.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/stock/StockInventoryMapper.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/stock/StockOutRecordMapper.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/static/销售台账导入模板.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
@@ -291,8 +291,15 @@
                                            ProductionOrderBom orderBom,
                                            List<ProductionBomStructure> structureList,
                                            Long rootProductModelId) {
        // é‡æ–°æŸ¥è¯¢BOM结构,按子节点优先排序
        List<ProductionBomStructure> routingStructureList = this.list(
                Wrappers.<ProductionBomStructure>lambdaQuery()
                        .eq(ProductionBomStructure::getProductionOrderBomId, orderBom.getId())
                        .orderByDesc(ProductionBomStructure::getParentId)
                        .orderByAsc(ProductionBomStructure::getId));
        ProductionOrderRouting orderRouting = getOrCreateOrderRoutingSnapshot(productionOrderId, productionOrder, orderBom, rootProductModelId);
        List<ProductionOrderRoutingOperation> desiredOperationList = buildDesiredRoutingOperationList(structureList, rootProductModelId);
        List<ProductionOrderRoutingOperation> desiredOperationList = buildDesiredRoutingOperationList(routingStructureList, rootProductModelId);
        List<ProductionOrderRoutingOperation> existingOperationList = productionOrderRoutingOperationMapper.selectList(
                Wrappers.<ProductionOrderRoutingOperation>lambdaQuery()
                        .eq(ProductionOrderRoutingOperation::getOrderRoutingId, orderRouting.getId())
@@ -310,7 +317,7 @@
            if (matchedOperation == null) {
                matchedOperation = insertRoutingOperationSnapshot(orderRouting.getId(), productionOrderId, desiredOperation);
            } else {
                updateRoutingOperationSnapshotIfNecessary(desiredOperation, orderRouting.getId(), productionOrderId, matchedOperation);
                updateRoutingOperationSnapshotIfNecessary(matchedOperation, orderRouting.getId(), productionOrderId, desiredOperation);
            }
            finalOperationList.add(matchedOperation);
        }
@@ -381,14 +388,14 @@
        Map<Long, ProductionBomStructure> structureById = structureList.stream()
                .filter(item -> item != null && item.getId() != null)
                .collect(Collectors.toMap(ProductionBomStructure::getId, item -> item, (left, right) -> left));
        // æž„建父-子映射关系
        Map<Long, List<ProductionBomStructure>> treeMap = buildParentChildMap(structureList);
        // ä½¿ç”¨åŽåºéåŽ†æž„å»ºæ“ä½œåˆ—è¡¨ï¼ˆå…ˆå­åŽçˆ¶ï¼Œç¡®ä¿å·¥è‰ºè·¯çº¿é¡ºåºæ­£ç¡®ï¼‰
        Map<String, ProductionBomStructure> uniqueOperationMap = new LinkedHashMap<>();
        for (ProductionBomStructure bomStructure : structureList) {
            if (bomStructure == null || bomStructure.getTechnologyOperationId() == null) {
                continue;
            }
            Long outputProductModelId = resolveOutputProductModelId(resolveOperationOutputNode(bomStructure, structureById), rootProductModelId);
            uniqueOperationMap.putIfAbsent(buildBomOperationDedupKey(bomStructure, outputProductModelId), bomStructure);
        }
        buildOperationListPostOrder(null, treeMap, uniqueOperationMap, structureById, rootProductModelId);
        List<ProductionOrderRoutingOperation> desiredOperationList = new ArrayList<>();
        int dragSort = 1;
        for (ProductionBomStructure bomStructure : uniqueOperationMap.values()) {
@@ -405,6 +412,52 @@
            desiredOperationList.add(routingOperation);
        }
        return desiredOperationList;
    }
    private Map<Long, List<ProductionBomStructure>> buildParentChildMap(List<ProductionBomStructure> structureList) {
        Map<Long, List<ProductionBomStructure>> treeMap = new LinkedHashMap<>();
        Map<Long, Integer> childCountMap = new HashMap<>();
        // ç¬¬ä¸€éï¼šç»Ÿè®¡æ¯ä¸ªèŠ‚ç‚¹çš„å­èŠ‚ç‚¹æ•°é‡ï¼ŒåŒæ—¶æž„å»ºåˆå§‹æ˜ å°„
        for (ProductionBomStructure structure : structureList) {
            if (structure == null) continue;
            Long parentId = structure.getParentId();
            childCountMap.merge(parentId, 1, Integer::sum);  // ç»Ÿè®¡æ¯ä¸ªçˆ¶èŠ‚ç‚¹æœ‰å¤šå°‘ä¸ªå­èŠ‚ç‚¹
            treeMap.computeIfAbsent(parentId, k -> new ArrayList<>()).add(structure);
        }
        // ç¬¬äºŒéï¼šå¯¹æ¯ä¸ªçˆ¶èŠ‚ç‚¹ä¸‹çš„å­èŠ‚ç‚¹æŒ‰å­èŠ‚ç‚¹æ•°é‡å€’åºæŽ’åºï¼ˆæœ‰å­èŠ‚ç‚¹çš„ä¼˜å…ˆï¼‰
        for (Map.Entry<Long, List<ProductionBomStructure>> entry : treeMap.entrySet()) {
            List<ProductionBomStructure> children = entry.getValue();
            children.sort((a, b) -> {
                int countA = childCountMap.getOrDefault(a.getId(), 0);
                int countB = childCountMap.getOrDefault(b.getId(), 0);
                return Integer.compare(countB, countA);  // å­èŠ‚ç‚¹å¤šçš„æŽ’å‰é¢
            });
        }
        return treeMap;
    }
    private void buildOperationListPostOrder(Long parentId,
                                             Map<Long, List<ProductionBomStructure>> treeMap,
                                             Map<String, ProductionBomStructure> uniqueOperationMap,
                                             Map<Long, ProductionBomStructure> structureById,
                                             Long rootProductModelId) {
        List<ProductionBomStructure> children = treeMap.get(parentId);
        if (children == null || children.isEmpty()) {
            return;
        }
        for (ProductionBomStructure child : children) {
            // å…ˆé€’归处理子节点
            buildOperationListPostOrder(child.getId(), treeMap, uniqueOperationMap, structureById, rootProductModelId);
            // å†å¤„理当前节点
            if (child.getTechnologyOperationId() != null) {
                Long outputProductModelId = resolveOutputProductModelId(resolveOperationOutputNode(child, structureById), rootProductModelId);
                uniqueOperationMap.putIfAbsent(buildBomOperationDedupKey(child, outputProductModelId), child);
            }
        }
    }
    private Map<String, Deque<ProductionOrderRoutingOperation>> buildExistingRoutingOperationBucketMap(List<ProductionOrderRoutingOperation> existingOperationList) {
@@ -482,6 +535,12 @@
        if (!Objects.equals(currentOperation.getIsProduction(), desiredOperation.getIsProduction())) {
            update.setIsProduction(desiredOperation.getIsProduction());
            currentOperation.setIsProduction(desiredOperation.getIsProduction());
            changed = true;
        }
        // æ›´æ–° dragSort å­—段,确保工艺路线顺序正确
        if (!Objects.equals(currentOperation.getDragSort(), desiredOperation.getDragSort())) {
            update.setDragSort(desiredOperation.getDragSort());
            currentOperation.setDragSort(desiredOperation.getDragSort());
            changed = true;
        }
        if (!Objects.equals(currentOperation.getType(), desiredOperation.getType())) {
@@ -744,8 +803,8 @@
            return;
        }
        for (ProductionBomStructureDto node : source) {
            flattenTree(node.getChildren(), result);  // å…ˆé€’归添加子节点
            result.add(node);
            flattenTree(node.getChildren(), result);
        }
    }
src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java
@@ -126,6 +126,7 @@
            String text = inspectParams.stream().map(QualityInspectParam::getParameterItem).collect(Collectors.joining(","));
            qualityUnqualified.setDefectivePhenomena(text + "这些指标中存在不合格");//不合格现象
            qualityUnqualified.setInspectId(qualityInspect.getId());
            qualityUnqualified.setId(null);
            qualityUnqualifiedMapper.insert(qualityUnqualified);
        }
src/main/java/com/ruoyi/sales/dto/SalesLedgerImportDto.java
@@ -43,6 +43,10 @@
    @Excel(name = "签订日期", width = 30, dateFormat = "yyyy-MM-dd")
    private Date executionDate;
    @JsonFormat(pattern = "yyyy-MM-dd")
    @Excel(name = "交付日期", width = 30, dateFormat = "yyyy-MM-dd")
    private Date deliveryDate;
    @Schema(description = "付款方式")
    @Excel(name = "付款方式")
    private String paymentMethod;
src/main/java/com/ruoyi/sales/dto/SalesLedgerProductImportDto.java
@@ -73,6 +73,9 @@
    @Excel(name = "是否质检", readConverterExp = "0=否,1=是")
    private Boolean isChecked;
    /**
     * æ˜¯å¦ç”Ÿäº§
     */
    @Excel(name = "是否生产", readConverterExp = "0=否,1=是")
    private Integer isProduction;
}
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
@@ -285,6 +285,9 @@
     * åˆ é™¤ç”Ÿäº§è®¡åˆ’
     */
    public void deleteProductionData(List<Long> productIds) {
        if (CollectionUtils.isEmpty(productIds)) {
            return;
        }
        List<ProductionPlan> productionPlans = productionPlanMapper.selectList(
                new LambdaQueryWrapper<ProductionPlan>()
                        .in(ProductionPlan::getSalesLedgerProductId, productIds.stream().map(Long::intValue).collect(Collectors.toList())));
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -1,6 +1,7 @@
package com.ruoyi.sales.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
@@ -27,8 +28,9 @@
import com.ruoyi.framework.security.LoginUser;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.other.mapper.TempFileMapper;
import com.ruoyi.other.pojo.TempFile;
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;
@@ -44,7 +46,6 @@
import com.ruoyi.sales.vo.SalesLedgerVo;
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;
@@ -55,15 +56,10 @@
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
@@ -347,9 +343,17 @@
            if (CollectionUtils.isEmpty(salesLedgerImportDtoList)) return R.fail("销售台账数据为空!");
            List<SalesLedgerImportDto> salesLedgerProductImportDtoList = stringListMap.get("销售产品数据");
            if (CollectionUtils.isEmpty(salesLedgerProductImportDtoList)) return R.fail("销售产品数据为空!");
            // å®¢æˆ·æ•°æ®
            List<Customer> customers = customerMapper.selectList(new LambdaQueryWrapper<Customer>().in(Customer::getCustomerName,
                    salesLedgerImportDtoList.stream().map(SalesLedgerImportDto::getCustomerName).collect(Collectors.toList())));
            // å®¢æˆ·æ•°æ® - å‚考 listPage æŸ¥è¯¢ç§æµ·å®¢æˆ·ï¼ˆtype = 0)
            // type = 0(私海客户)或者 type = 1(公海客户)且已被分配,并且是自己领用、自己创建或者共享给自己的客户
            Long loginUserId = loginUser.getUser().getUserId();
            List<Customer> customers = customerMapper.selectList(new QueryWrapper<Customer>()
                    .in("customer_name", salesLedgerImportDtoList.stream()
                            .map(SalesLedgerImportDto::getCustomerName).collect(Collectors.toList()))
                    .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)))));
//            // è§„格型号数据
//            List<ProductModel> productModels = productModelMapper.selectList(new LambdaQueryWrapper<ProductModel>().in(ProductModel::getModel,
//                    salesLedgerProductImportDtoList.stream().map(SalesLedgerImportDto::getSpecificationModel).collect(Collectors.toList())));
@@ -370,17 +374,16 @@
                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()
                Optional<Customer> customerOptional = 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));
                        .findFirst();
                if (customerOptional.isEmpty()) {
                    throw new RuntimeException("客户:" + salesLedger.getCustomerName() + "不存在!或者非私海用户");
                }
                salesLedger.setCustomerId(customerOptional.get().getId());
                salesLedger.setCustomerContractNo(customerOptional.get().getTaxpayerIdentificationNumber());
                Long aLong = sysUsers.stream()
                        .filter(sysUser -> sysUser.getNickName().equals(salesLedger.getEntryPerson()))
                        .findFirst()
@@ -410,13 +413,16 @@
                    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 -> map.get("productName").equals(salesLedgerProduct.getProductCategory()) && map.get("model").equals(salesLedgerProduct.getSpecificationModel()))
                            .findFirst()
                            .ifPresent(map -> {
                                salesLedgerProduct.setProductModelId(Long.parseLong(map.get("modelId").toString()));
                                salesLedgerProduct.setProductId(Long.parseLong(map.get("id").toString()));
                            });
                    // æ ¡éªŒäº§å“è§„格是否存在
                    Optional<Map<String, Object>> productModelOptional = list.stream()
                            .filter(map -> Objects.equals(map.get("productName"), salesLedgerProduct.getProductCategory()) && Objects.equals(map.get("model"), salesLedgerProduct.getSpecificationModel()))
                            .findFirst();
                    if (productModelOptional.isEmpty()) {
                        throw new RuntimeException("产品大类:" + salesLedgerProduct.getProductCategory() + ",规格型号:" + salesLedgerProduct.getSpecificationModel() + "不存在!");
                    }
                    Map<String, Object> productModelMap = productModelOptional.get();
                    salesLedgerProduct.setProductModelId(Long.parseLong(productModelMap.get("modelId").toString()));
                    salesLedgerProduct.setProductId(Long.parseLong(productModelMap.get("id").toString()));
//                    salesLedgerProduct.setProductId(productList.stream()
//                            .filter(product -> product.getProductName().equals(salesLedgerProduct.getProductCategory()))
//                            .findFirst()
@@ -431,6 +437,7 @@
                    salesLedgerProduct.setRegisterDate(LocalDateTime.now());
                    salesLedgerProduct.setApproveStatus(0);
                    salesLedgerProduct.setPendingInvoiceTotal(salesLedgerProductImportDto.getTaxInclusiveTotalPrice());
                    salesLedgerProduct.setIsProduction(salesLedgerProductImportDto.getIsProduction() == 1);
                    salesLedgerProductMapper.insert(salesLedgerProduct);
                    // æ·»åŠ ç”Ÿäº§æ•°æ®
                    salesLedgerProductServiceImpl.addProductionData(salesLedgerProduct);
@@ -440,6 +447,7 @@
            return R.ok(null, "导入成功");
        } catch (Exception e) {
            e.printStackTrace();
            return R.fail("导入失败:" + e.getMessage());
        }
        return R.ok(null, "导入失败");
    }
src/main/java/com/ruoyi/staff/service/impl/StaffOnJobServiceImpl.java
@@ -1,12 +1,13 @@
package com.ruoyi.staff.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
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.common.exception.base.BaseException;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.dto.WordDateDto;
import com.ruoyi.project.system.domain.SysDept;
@@ -46,7 +47,7 @@
@RequiredArgsConstructor
@Service
public class StaffOnJobServiceImpl extends ServiceImpl<StaffOnJobMapper, StaffOnJob>  implements IStaffOnJobService {
public class StaffOnJobServiceImpl extends ServiceImpl<StaffOnJobMapper, StaffOnJob> implements IStaffOnJobService {
    private final StaffOnJobMapper staffOnJobMapper;
    private final SysDeptMapper sysDeptMapper;
@@ -64,22 +65,22 @@
    private final StaffEmergencyContactMapper staffEmergencyContactMapper;
    private final StaffEmergencyContactServiceImpl staffEmergencyContactServiceImpl;
    //在职员工台账分页查询
    // åœ¨èŒå‘˜å·¥å°è´¦åˆ†é¡µæŸ¥è¯¢
    @Override
    public IPage<StaffOnJobDto> staffOnJobListPage(Page page, StaffOnJob staffOnJob) {
        return staffOnJobMapper.staffOnJobListPage(page,staffOnJob);
        return staffOnJobMapper.staffOnJobListPage(page, staffOnJob);
    }
    //新增入职
    // æ–°å¢žå…¥èŒ
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int add(StaffOnJobDto staffOnJobPrams) {
        String[] ignoreProperties = {"id"};//排除id属性
        String[] ignoreProperties = { "id" };// æŽ’除id属性
        // åˆ¤æ–­ç¼–号是否存在
        List<StaffOnJob> staffOnJobs = staffOnJobMapper.selectList(Wrappers.<StaffOnJob>lambdaQuery().eq(StaffOnJob::getStaffNo, staffOnJobPrams.getStaffNo()));
        if (staffOnJobs != null && !staffOnJobs.isEmpty()){
            throw new BaseException("编号为"+staffOnJobPrams.getStaffNo()+"的员工已经存在,无法新增!!!");
        List<StaffOnJob> staffOnJobs = staffOnJobMapper.selectList(
                Wrappers.<StaffOnJob>lambdaQuery().eq(StaffOnJob::getStaffNo, staffOnJobPrams.getStaffNo()));
        if (staffOnJobs != null && !staffOnJobs.isEmpty()) {
            throw new BaseException("编号为" + staffOnJobPrams.getStaffNo() + "的员工已经存在,无法新增!!!");
        }
        // åˆ›å»ºå…¥èŒæ•°æ®
@@ -88,23 +89,23 @@
        staffOnJobMapper.insert(staffOnJobPrams);
        // æŸ¥è¯¢ç”¨æˆ·æ˜¯å¦å·²ç»æ–°å¢ž
        SysUser sysUser = sysUserService.selectUserById(staffOnJobPrams.getId());
        if(sysUser == null){
        if (sysUser == null) {
            SysUser sysUser1 = new SysUser();
            sysUser1.setUserName(staffOnJobPrams.getStaffNo());
            sysUser1.setNickName(staffOnJobPrams.getStaffName());
            String s = SecurityUtils.encryptPassword("123456");
            sysUser1.setPassword(s);
            if(staffOnJobPrams.getSysPostId() != null){
                Long[] posts = new Long[]{staffOnJobPrams.getSysPostId().longValue()};
            if (staffOnJobPrams.getSysPostId() != null) {
                Long[] posts = new Long[] { staffOnJobPrams.getSysPostId().longValue() };
                sysUser1.setPostIds(posts);
            }
            sysUser1.setRoleIds(new Long[]{staffOnJobPrams.getRoleId()});
            sysUser1.setDeptIds(new  Long[]{staffOnJobPrams.getSysDeptId()});
            sysUser1.setRoleIds(new Long[] { staffOnJobPrams.getRoleId() });
            sysUser1.setDeptIds(new Long[] { staffOnJobPrams.getSysDeptId() });
            sysUser1.setStatus("0");
            sysUserService.insertUser(sysUser1);
        }
        // ç»‘定子表数据
        bingingStaffOnJobExtra(staffOnJobPrams.getId(),staffOnJobPrams);
        bingingStaffOnJobExtra(staffOnJobPrams.getId(), staffOnJobPrams);
        // åˆ›å»ºåˆåŒè®°å½•
        StaffContract staffContract = new StaffContract();
        staffContract.setStaffOnJobId(staffOnJobPrams.getId());
@@ -114,32 +115,32 @@
        return staffContractMapper.insert(staffContract);
    }
    //更新入职信息
    // æ›´æ–°å…¥èŒä¿¡æ¯
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int update(Long id, StaffOnJobDto staffOnJobParams) {
        // åˆ¤æ–­å¯¹è±¡æ˜¯å¦å­˜åœ¨
        StaffOnJob job = staffOnJobMapper.selectById(id);
        if (job == null){
            throw new BaseException("编号为"+staffOnJobParams.getStaffNo()+"的员工不存在,无法更新!!!");
        if (job == null) {
            throw new BaseException("编号为" + staffOnJobParams.getStaffNo() + "的员工不存在,无法更新!!!");
        }
        String[] ignoreProperties = {"id"};//排除更新属性
        String[] ignoreProperties = { "id" };// æŽ’除更新属性
        // èŽ·å–æœ€æ–°åˆåŒæ•°æ®ï¼Œå¹¶ä¸”æ›´æ–°
        StaffContract contract = staffContractMapper.selectOne(Wrappers.<StaffContract>lambdaQuery()
                .eq(StaffContract::getStaffOnJobId, id)
                .last("limit 1")
                .orderByDesc(StaffContract::getId));
        if (contract != null){
            BeanUtils.copyProperties(staffOnJobParams,contract,ignoreProperties);
        if (contract != null) {
            BeanUtils.copyProperties(staffOnJobParams, contract, ignoreProperties);
            staffContractMapper.updateById(contract);
        }
        // åˆ é™¤æ‰€æœ‰å­è¡¨æ•°æ®
        delStaffOnJobExtra(Arrays.asList(id));
        // ç»‘定子表数据
        bingingStaffOnJobExtra(id,staffOnJobParams);
        bingingStaffOnJobExtra(id, staffOnJobParams);
        // æ›´æ–°å‘˜å·¥æ•°æ®
        staffOnJobParams.setContractExpireTime(staffOnJobParams.getContractEndTime());
        return staffOnJobMapper.updateById(staffOnJobParams);
@@ -147,26 +148,27 @@
    /**
     * ç»‘定员工子表数据
     *
     * @param staffOnJobPrams
     * @param id
     */
    public void bingingStaffOnJobExtra(Long id,StaffOnJob staffOnJobPrams) {
    public void bingingStaffOnJobExtra(Long id, StaffOnJob staffOnJobPrams) {
        // æ–°å¢žæ•™è‚²ç»åކ
        if(CollectionUtils.isNotEmpty(staffOnJobPrams.getStaffEducationList())){
        if (CollectionUtils.isNotEmpty(staffOnJobPrams.getStaffEducationList())) {
            staffOnJobPrams.getStaffEducationList().stream()
                    .filter(Objects::nonNull) // è¿‡æ»¤null对象,避免空指针
                    .forEach(staff -> staff.setStaffOnJobId(id)); // èµ‹å€¼
            staffEducationService.saveBatch(staffOnJobPrams.getStaffEducationList());
        }
        // æ–°å¢žå·¥ä½œç»åކ
        if(CollectionUtils.isNotEmpty(staffOnJobPrams.getStaffWorkExperienceList())){
        if (CollectionUtils.isNotEmpty(staffOnJobPrams.getStaffWorkExperienceList())) {
            staffOnJobPrams.getStaffWorkExperienceList().stream()
                    .filter(Objects::nonNull) // è¿‡æ»¤null对象,避免空指针
                    .forEach(staff -> staff.setStaffOnJobId(id)); // èµ‹å€¼
            staffWorkExperienceServiceImpl.saveBatch(staffOnJobPrams.getStaffWorkExperienceList());
        }
        // æ–°å¢žç´§æ€¥è”系人
        if(CollectionUtils.isNotEmpty(staffOnJobPrams.getStaffEmergencyContactList())){
        if (CollectionUtils.isNotEmpty(staffOnJobPrams.getStaffEmergencyContactList())) {
            staffOnJobPrams.getStaffEmergencyContactList().stream()
                    .filter(Objects::nonNull) // è¿‡æ»¤null对象,避免空指针
                    .forEach(staff -> staff.setStaffOnJobId(id)); // èµ‹å€¼
@@ -174,27 +176,30 @@
        }
    }
    /**
     * é€šè¿‡å‘˜å·¥id删除教育经历,工作经历,紧急联系人
     *
     * @param ids
     * @return
     */
    public void delStaffOnJobExtra(List<Long> ids) {
        // åˆ é™¤æ•™è‚²ç»åކ
        staffEducationService.remove(Wrappers.<StaffEducation>lambdaQuery().in(StaffEducation::getStaffOnJobId,ids));
        staffEducationService.remove(Wrappers.<StaffEducation>lambdaQuery().in(StaffEducation::getStaffOnJobId, ids));
        // åˆ é™¤å·¥ä½œç»åކ
        staffWorkExperienceServiceImpl.remove(Wrappers.<StaffWorkExperience>lambdaQuery().in(StaffWorkExperience::getStaffOnJobId,ids));
        staffWorkExperienceServiceImpl
                .remove(Wrappers.<StaffWorkExperience>lambdaQuery().in(StaffWorkExperience::getStaffOnJobId, ids));
        // åˆ é™¤ç´§æ€¥è”系人
        staffEmergencyContactServiceImpl.remove(Wrappers.<StaffEmergencyContact>lambdaQuery().in(StaffEmergencyContact::getStaffOnJobId,ids));
        staffEmergencyContactServiceImpl
                .remove(Wrappers.<StaffEmergencyContact>lambdaQuery().in(StaffEmergencyContact::getStaffOnJobId, ids));
    }
    //删除入职
    // åˆ é™¤å…¥èŒ
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int delStaffOnJobs(List<Integer> ids) {
        List<StaffOnJob> staffOnJobs = staffOnJobMapper.selectList(Wrappers.<StaffOnJob>lambdaQuery().in(StaffOnJob::getId, ids));
        if(CollectionUtils.isEmpty(staffOnJobs)){
        List<StaffOnJob> staffOnJobs = staffOnJobMapper
                .selectList(Wrappers.<StaffOnJob>lambdaQuery().in(StaffOnJob::getId, ids));
        if (CollectionUtils.isEmpty(staffOnJobs)) {
            throw new BaseException("该员工不存在,无法删除!!!");
        }
        // åˆ é™¤å…¥èŒæ•°æ®
@@ -202,11 +207,13 @@
        // åˆ é™¤ç¦»èŒæ•°æ®
        staffLeaveMapper.delete(Wrappers.<StaffLeave>lambdaQuery().in(StaffLeave::getStaffOnJobId, ids));
        // åˆ é™¤æ‰“卡记录
        personalAttendanceRecordsMapper.delete(Wrappers.<PersonalAttendanceRecords>lambdaQuery().in(PersonalAttendanceRecords::getStaffOnJobId, ids));
        personalAttendanceRecordsMapper.delete(
                Wrappers.<PersonalAttendanceRecords>lambdaQuery().in(PersonalAttendanceRecords::getStaffOnJobId, ids));
        // åˆ é™¤ç”¨æˆ·æ•°æ®
        List<SysUser> sysUsers = sysUserMapper.selectList(Wrappers.<SysUser>lambdaQuery()
                .in(SysUser::getUserName, staffOnJobs.stream().map(StaffOnJob::getStaffNo).collect(Collectors.toList())));
        if(CollectionUtils.isNotEmpty(sysUsers)){
                .in(SysUser::getUserName,
                        staffOnJobs.stream().map(StaffOnJob::getStaffNo).collect(Collectors.toList())));
        if (CollectionUtils.isNotEmpty(sysUsers)) {
            Long[] longs = sysUsers.stream().map(SysUser::getUserId).toArray(Long[]::new);
            sysUserService.deleteUserByIds(longs);
        }
@@ -214,7 +221,8 @@
        delStaffOnJobExtra(ids.stream().map(Integer::longValue).collect(Collectors.toList()));
        // åˆ é™¤åˆåŒæ•°æ®
        return staffContractMapper.delete(Wrappers.<StaffContract>lambdaQuery().in(StaffContract::getStaffOnJobId, ids));
        return staffContractMapper
                .delete(Wrappers.<StaffContract>lambdaQuery().in(StaffContract::getStaffOnJobId, ids));
    }
    // ç»­ç­¾åˆåŒ
@@ -223,7 +231,7 @@
    public int renewContract(Long id, StaffContract staffContract) {
        // åˆ¤æ–­å¯¹è±¡æ˜¯å¦å­˜åœ¨
        StaffOnJob job = staffOnJobMapper.selectById(id);
        if (job == null){
        if (job == null) {
            throw new BaseException("该员工不存在,无法更新!!!");
        }
@@ -241,10 +249,10 @@
        return 0;
    }
    //在职员工详情
    // åœ¨èŒå‘˜å·¥è¯¦æƒ…
    @Override
    public StaffOnJobDto staffOnJobDetail(Long id) {
        StaffOnJob staffOnJob  = staffOnJobMapper.selectById(id);
        StaffOnJob staffOnJob = staffOnJobMapper.selectById(id);
        if (staffOnJob == null) {
            throw new IllegalArgumentException("该员工不存在");
        }
@@ -264,7 +272,7 @@
                .eq(StaffContract::getStaffOnJobId, staffOnJob.getId())
                .last("limit 1")
                .orderByDesc(StaffContract::getId));
        if (contract != null){
        if (contract != null) {
            staffOnJobDto.setContractTerm(contract.getContractTerm());
            staffOnJobDto.setContractStartTime(contract.getContractStartTime());
            staffOnJobDto.setContractEndTime(contract.getContractEndTime());
@@ -272,14 +280,16 @@
        // èŽ·å–å­è¡¨æ•°æ®
        staffOnJobDto.setStaffEducationList(staffEducationMapper.selectList(Wrappers.<StaffEducation>lambdaQuery()
                .eq(StaffEducation::getStaffOnJobId, staffOnJob.getId())));
        staffOnJobDto.setStaffWorkExperienceList(staffWorkExperienceMapper.selectList(Wrappers.<StaffWorkExperience>lambdaQuery()
                .eq(StaffWorkExperience::getStaffOnJobId, staffOnJob.getId())));
        staffOnJobDto.setStaffEmergencyContactList(staffEmergencyContactMapper.selectList(Wrappers.<StaffEmergencyContact>lambdaQuery()
                .eq(StaffEmergencyContact::getStaffOnJobId, staffOnJob.getId())));
        staffOnJobDto.setStaffWorkExperienceList(
                staffWorkExperienceMapper.selectList(Wrappers.<StaffWorkExperience>lambdaQuery()
                        .eq(StaffWorkExperience::getStaffOnJobId, staffOnJob.getId())));
        staffOnJobDto.setStaffEmergencyContactList(
                staffEmergencyContactMapper.selectList(Wrappers.<StaffEmergencyContact>lambdaQuery()
                        .eq(StaffEmergencyContact::getStaffOnJobId, staffOnJob.getId())));
        return staffOnJobDto;
    }
    //在职员工导出
    // åœ¨èŒå‘˜å·¥å¯¼å‡º
    @Override
    public void staffOnJobExport(HttpServletResponse response, StaffOnJob staffOnJob) {
        List<StaffOnJobDto> staffOnJobs = staffOnJobMapper.staffOnJobList(staffOnJob);
@@ -298,39 +308,62 @@
        try {
            ExcelUtil<StaffOnJobExcelDto> util = new ExcelUtil<>(StaffOnJobExcelDto.class);
            List<StaffOnJobExcelDto> staffOnJobs = util.importExcel(file.getInputStream());
            if (CollectionUtils.isEmpty(staffOnJobs)){
            if (CollectionUtils.isEmpty(staffOnJobs)) {
                return false;
            }
            // èŽ·å–æ‰€æœ‰éƒ¨é—¨æ•°æ®
            List<SysDept> sysDepts = sysDeptMapper.selectList(Wrappers.<SysDept>lambdaQuery().eq(SysDept::getDelFlag, 0));
            List<SysDept> sysDepts = sysDeptMapper
                    .selectList(Wrappers.<SysDept>lambdaQuery().eq(SysDept::getDelFlag, 0));
            // èŽ·å–æ‰€æœ‰è§’è‰²æ•°æ®
            List<SysRole> sysRoles = sysRoleMapper.selectRoleAll();
            staffOnJobs.forEach(staffOnJob -> {
                // å¤„理合同期限数据格式
                if (staffOnJob.getContractTerm() != null && !staffOnJob.getContractTerm().trim().isEmpty()) {
                    String term = staffOnJob.getContractTerm().trim();
                    try {
                        Integer.parseInt(term);
                    } catch (NumberFormatException e) {
                        throw new ServiceException("员工[" + staffOnJob.getStaffName() + "]的合同期限["
                                + staffOnJob.getContractTerm() + "]格式不正确,必须为纯数字(如: 1, 2, 3)");
                    }
                }
                StaffOnJobDto staffOnJobDto = new StaffOnJobDto();
                BeanUtils.copyProperties(staffOnJob, staffOnJobDto);
                // é€šè¿‡åç§°èŽ·å–éƒ¨é—¨id
                staffOnJobDto.setSysDeptId(// ... existing code ...
                        sysDepts.stream()
                            .filter(dept -> dept.getDeptName() != null && dept.getDeptName().equals(staffOnJob.getSysDeptName()))
                            .findFirst()
                            .map(SysDept::getDeptId)
                            .orElse(null)
                        );
                Long deptId = sysDepts.stream()
                        .filter(dept -> dept.getDeptName() != null
                                && dept.getDeptName().equals(staffOnJob.getSysDeptName()))
                        .findFirst()
                        .map(SysDept::getDeptId)
                        .orElse(null);
                if (deptId == null) {
                    throw new ServiceException(
                            "员工[" + staffOnJob.getStaffName() + "]的部门[" + staffOnJob.getSysDeptName() + "]不存在,请检查数据");
                }
                staffOnJobDto.setSysDeptId(deptId);
                // é€šè¿‡åç§°èŽ·å–è§’è‰²id
                staffOnJobDto.setRoleId(sysRoles.stream()
                        .filter(role -> role.getRoleName() != null && role.getRoleName().equals(staffOnJob.getRoleName()))
                Long roleId = sysRoles.stream()
                        .filter(role -> role.getRoleName() != null
                                && role.getRoleName().equals(staffOnJob.getRoleName()))
                        .findFirst()
                        .map(SysRole::getRoleId)
                        .orElse( null));
                add(staffOnJobDto);
                        .orElse(null);
                if (roleId == null) {
                    throw new ServiceException(
                            "员工[" + staffOnJob.getStaffName() + "]的角色[" + staffOnJob.getRoleName() + "]不存在,请检查数据");
                }
                staffOnJobDto.setRoleId(roleId);
                SpringUtils.getAopProxy(this).add(staffOnJobDto);
            });
            return true;
        } catch (ServiceException | BaseException e) {
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
            log.error("员工台账导入失败 : " + e.getMessage());
            throw new ServiceException("导入失败: " + e.getMessage());
        }
    }
    @Override
    public String exportCopy(HttpServletResponse response, StaffOnJob staffOnJob) throws Exception {
@@ -339,7 +372,7 @@
        // è®¾ç½®æ¨¡æ¿æ–‡ä»¶æ‰€åœ¨ç›®å½•(绝对路径,例如:/templates/)
        cfg.setClassForTemplateLoading(StaffOnJobServiceImpl.class, "/static");
        cfg.setDefaultEncoding("UTF-8");
        //2.定义需要填充的变里
        // 2.定义需要填充的变里
        // â‘  æž„造员工信息(实际项目中可从数据库/Excel读取)
        WordDateDto staff = new WordDateDto();
        BeanUtils.copyProperties(staffOnJob, staff);
@@ -349,7 +382,7 @@
        Instant instant = staff.getContractExpireTime().toInstant();
        // ä¹Ÿå¯ä»¥æŒ‡å®šå…·ä½“时区,例如Asia/Shanghai:
        LocalDate localDate = instant.atZone(ZoneId.of("Asia/Shanghai")).toLocalDate();  // åˆåŒç»“束时间
        LocalDate localDate = instant.atZone(ZoneId.of("Asia/Shanghai")).toLocalDate(); // åˆåŒç»“束时间
        LocalDate localDate1 = localDate.minusYears(Integer.parseInt(staff.getContractTerm()));// åˆåŒå¼€å§‹æ—¶é—´
        // ç­¾è®¢æ—¥æœŸè½¬æ¢lcoaldate
@@ -362,7 +395,7 @@
        staff.setQyear(localDate2.getYear() + "");
        staff.setQmoth(localDate2.getMonthValue() + "");
        staff.setQday(localDate2.getDayOfMonth() + "");
        if(staff.getDateSelect().equals("A")){
        if (staff.getDateSelect().equals("A")) {
            staff.setSyear(localDate1.getYear() + "");
            staff.setSmoth(localDate1.getMonthValue() + "");
            staff.setSday(localDate1.getDayOfMonth() + "");
@@ -376,7 +409,7 @@
            staff.setSeyear(localDate4.getYear() + "");
            staff.setSemoth(localDate4.getMonthValue() + "");
            staff.setSeday(localDate4.getDayOfMonth() + "");
        }else if (staff.getDateSelect().equals("B")){
        } else if (staff.getDateSelect().equals("B")) {
            staff.setBsyear(localDate1.getYear() + "");
            staff.setBsmoth(localDate1.getMonthValue() + "");
@@ -388,29 +421,27 @@
            staff.setBseyear(localDate4.getYear() + "");
            staff.setBsemoth(localDate4.getMonthValue() + "");
            staff.setBseday(localDate4.getDayOfMonth() + "");
        }else if (staff.getDateSelect().equals("C")){
        } else if (staff.getDateSelect().equals("C")) {
            staff.setCsyear(localDate1.getYear() + "");
            staff.setCsmoth(localDate1.getMonthValue() + "");
            staff.setCsday(localDate1.getDayOfMonth() + "");
        }
        Map<String,Object> data = new HashMap<>();
        data.put("item",staff);
        //3.加载XML æ¨¡æ¿
        Map<String, Object> data = new HashMap<>();
        data.put("item", staff);
        // 3.加载XML æ¨¡æ¿
        Template template = cfg.getTemplate("劳动合同书.xml");
        //4.生成填充后的 XML å†…容
        // 4.生成填充后的 XML å†…容
        StringWriter out = new StringWriter();
        template.process(data, out);
        String filledXml = out.toString();
        //5.将XML内容写入交件并改为.docx æ ¼å¼
        // 5.将XML内容写入交件并改为.docx æ ¼å¼
        File outputFile = new File(url);
        try(FileOutputStream fos = new FileOutputStream(outputFile);
            OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8)) {
        try (FileOutputStream fos = new FileOutputStream(outputFile);
                OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8)) {
            osw.write(filledXml);
        }
        return url;
    }
}
src/main/java/com/ruoyi/stock/dto/StockInRecordDto.java
@@ -18,6 +18,11 @@
     */
    private String model;
    /**
     * æ‰¹æ¬¡å·
     */
    private String batchNo;
    /**
     * äº§å“å•位
     */
    private String unit;
src/main/java/com/ruoyi/stock/dto/StockInventoryDto.java
@@ -79,4 +79,7 @@
    @Schema(description = "产品id")
    private Long productId;
    @Schema(description = "批次号")
    private String batchNo;
}
src/main/java/com/ruoyi/stock/dto/StockOutRecordDto.java
@@ -21,6 +21,10 @@
     */
    private String model;
    /**
     * æ‰¹æ¬¡å·
     */
    private String batchNo;
    /**
     * äº§å“å•位
     */
    private String unit;
src/main/resources/mapper/stock/StockInRecordMapper.xml
@@ -31,6 +31,12 @@
            <if test="params.productName != null and params.productName != ''">
                and p.product_name like concat('%',#{params.productName},'%')
            </if>
            <if test="params.model != null and params.model != ''">
                and pm.model like concat('%',#{params.model},'%')
            </if>
            <if test="params.batchNo != null and params.batchNo != ''">
                and sir.batch_no like concat('%',#{params.batchNo},'%')
            </if>
            <if test="params.type != null and params.type != ''">
                and sir.type = #{params.type}
            </if>
src/main/resources/mapper/stock/StockInventoryMapper.xml
@@ -209,6 +209,12 @@
            <if test="ew.topParentProductId != null and ew.topParentProductId > 0">
                and combined.product_id in (select id from product_tree)
            </if>
            <if test="ew.model != null and ew.model !=''">
                and combined.model like concat('%',#{ew.model},'%')
            </if>
            <if test="ew.batchNo != null and ew.batchNo !=''">
                and combined.batch_no like concat('%',#{ew.batchNo},'%')
            </if>
        </where>
        group by
        product_model_id,
src/main/resources/mapper/stock/StockOutRecordMapper.xml
@@ -46,6 +46,12 @@
            <if test="params.productName != null and params.productName != ''">
                and p.product_name like concat('%',#{params.productName},'%')
            </if>
            <if test="params.model != null and params.model != ''">
                and pm.model like concat('%',#{params.model},'%')
            </if>
            <if test="params.batchNo != null and params.batchNo != ''">
                and sor.batch_no like concat('%',#{params.batchNo},'%')
            </if>
            <if test="params.type != null and params.type != ''">
                and sor.type = #{params.type}
            </if>
src/main/resources/static/ÏúÊŲ̂Õ˵¼ÈëÄ£°å.xlsx
Binary files differ