src/main/java/com/ruoyi/ai/config/XiaozhiAgentConfig.java
@@ -1,24 +1,15 @@ package com.ruoyi.ai.config; import com.ruoyi.ai.store.MongoChatMemoryStore; import dev.langchain4j.data.document.Document; import dev.langchain4j.data.document.loader.FileSystemDocumentLoader; import dev.langchain4j.data.segment.TextSegment; import dev.langchain4j.memory.chat.ChatMemoryProvider; import dev.langchain4j.memory.chat.MessageWindowChatMemory; import dev.langchain4j.model.embedding.EmbeddingModel; import dev.langchain4j.rag.content.retriever.ContentRetriever; import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever; import dev.langchain4j.store.embedding.EmbeddingStore; import dev.langchain4j.store.embedding.EmbeddingStoreIngestor; import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.Collections; import java.util.List; /** * @author :yys @@ -35,8 +26,8 @@ @Autowired private EmbeddingModel embeddingModel; @Value("${knowledge.one}") private String one; // @Value("${knowledge.one}") // private String one; // // @Value("${knowledge.two}") // private String two; @@ -53,33 +44,33 @@ .build(); } @Bean ContentRetriever contentRetrieverXiaozhi() { //使ç¨FileSystemDocumentLoader读åæå®ç®å½ä¸çç¥è¯åºææ¡£ //并使ç¨é»è®¤çææ¡£è§£æå¨å¯¹ææ¡£è¿è¡è§£æ Document document1 = FileSystemDocumentLoader.loadDocument(one); // Document document2 = FileSystemDocumentLoader.loadDocument(two); // Document document3 = FileSystemDocumentLoader.loadDocument(three); // List<Document> documents = Arrays.asList(document1, document2, document3); List<Document> documents = Collections.singletonList(document1); // 2. å°æ°æ®åºæ°æ®è½¬ä¸ºLangChain4jçDocument对象 // List<Document> documents = new ArrayList<>(); //使ç¨å ååéåå¨ InMemoryEmbeddingStore<TextSegment> inMemoryEmbeddingStore = new InMemoryEmbeddingStore<>(); //使ç¨é»è®¤çææ¡£åå²å¨ EmbeddingStoreIngestor.builder() .embeddingModel(embeddingModel) .embeddingStore(inMemoryEmbeddingStore) .build() .ingest(documents); //ä»åµå ¥åå¨ï¼EmbeddingStoreï¼éæ£ç´¢åæ¥è¯¢å 容ç¸å ³çä¿¡æ¯ return EmbeddingStoreContentRetriever.builder() .embeddingModel(embeddingModel) .embeddingStore(inMemoryEmbeddingStore) .build(); } // @Bean // ContentRetriever contentRetrieverXiaozhi() { // //使ç¨FileSystemDocumentLoader读åæå®ç®å½ä¸çç¥è¯åºææ¡£ // //并使ç¨é»è®¤çææ¡£è§£æå¨å¯¹ææ¡£è¿è¡è§£æ //// Document document1 = FileSystemDocumentLoader.loadDocument(one); //// Document document2 = FileSystemDocumentLoader.loadDocument(two); //// Document document3 = FileSystemDocumentLoader.loadDocument(three); //// List<Document> documents = Arrays.asList(document1, document2, document3); // //// List<Document> documents = Collections.singletonList(document1); //// 2. å°æ°æ®åºæ°æ®è½¬ä¸ºLangChain4jçDocument对象 //// List<Document> documents = new ArrayList<>(); // // //使ç¨å ååéåå¨ // InMemoryEmbeddingStore<TextSegment> inMemoryEmbeddingStore = new InMemoryEmbeddingStore<>(); // //使ç¨é»è®¤çææ¡£åå²å¨ // EmbeddingStoreIngestor.builder() // .embeddingModel(embeddingModel) // .embeddingStore(inMemoryEmbeddingStore) // .build() // .ingest(documents); // //ä»åµå ¥åå¨ï¼EmbeddingStoreï¼éæ£ç´¢åæ¥è¯¢å 容ç¸å ³çä¿¡æ¯ // return EmbeddingStoreContentRetriever.builder() // .embeddingModel(embeddingModel) // .embeddingStore(inMemoryEmbeddingStore) // .build(); // } @Bean ContentRetriever contentRetrieverXiaozhiPincone() { src/main/java/com/ruoyi/basic/controller/ProductController.java
@@ -10,6 +10,7 @@ import com.ruoyi.basic.pojo.ProductModel; import com.ruoyi.basic.service.IProductModelService; import com.ruoyi.basic.service.IProductService; import com.ruoyi.basic.vo.ProductModelVo; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.framework.aspectj.lang.annotation.Log; import com.ruoyi.framework.aspectj.lang.enums.BusinessType; @@ -17,11 +18,8 @@ import com.ruoyi.framework.web.domain.AjaxResult; import com.ruoyi.sales.pojo.SalesLedgerProduct; import com.ruoyi.sales.service.ISalesLedgerProductService; import com.ruoyi.sales.service.ISalesLedgerService; import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.Operation; import lombok.AllArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; @@ -118,7 +116,7 @@ @Operation(summary = "å页æ¥è¯¢ææäº§ååå·") @GetMapping("/pageModel") public IPage<ProductModel> listPageProductModel(Page<ProductModel> page, ProductModel productModel) { public IPage<ProductModelVo> listPageProductModel(Page<ProductModelVo> page, ProductModel productModel) { return productService.listPageProductModel(page, productModel); } src/main/java/com/ruoyi/basic/mapper/ProductModelMapper.java
@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.basic.pojo.ProductModel; import com.ruoyi.basic.vo.ProductModelVo; import com.ruoyi.procurementrecord.dto.ProcurementPageDto; import org.apache.ibatis.annotations.Param; @@ -19,7 +20,7 @@ */ public interface ProductModelMapper extends BaseMapper<ProductModel> { IPage<ProductModel> listPageProductModel(Page<ProductModel> page, @Param("c") ProductModel productModel); IPage<ProductModelVo> listPageProductModel(Page<ProductModelVo> page, @Param("c") ProductModel productModel); IPage<ProductModel> listPageProductionStock(Page<ProductModel> page, @Param("req") ProcurementPageDto req); src/main/java/com/ruoyi/basic/pojo/ProductModel.java
@@ -5,12 +5,13 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.io.Serializable; import java.math.BigDecimal; import java.time.LocalDateTime; @Data @TableName("product_model") public class ProductModel { public class ProductModel implements Serializable { private static final long serialVersionUID = 1L; src/main/java/com/ruoyi/basic/service/IProductService.java
@@ -7,6 +7,7 @@ import com.ruoyi.basic.dto.ProductTreeDto; import com.ruoyi.basic.pojo.Product; import com.ruoyi.basic.pojo.ProductModel; import com.ruoyi.basic.vo.ProductModelVo; import java.util.List; @@ -18,5 +19,5 @@ List<ProductTreeDto> selectProductList(ProductDto productDto); IPage<ProductModel> listPageProductModel(Page<ProductModel> page, ProductModel productModel); IPage<ProductModelVo> listPageProductModel(Page<ProductModelVo> page, ProductModel productModel); } src/main/java/com/ruoyi/basic/service/impl/ProductServiceImpl.java
@@ -12,6 +12,7 @@ import com.ruoyi.basic.pojo.Product; import com.ruoyi.basic.pojo.ProductModel; import com.ruoyi.basic.service.IProductService; import com.ruoyi.basic.vo.ProductModelVo; import com.ruoyi.common.utils.bean.BeanUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.framework.web.domain.AjaxResult; @@ -56,7 +57,7 @@ } @Override public IPage<ProductModel> listPageProductModel(Page<ProductModel> page, ProductModel productModel) { public IPage<ProductModelVo> listPageProductModel(Page<ProductModelVo> page, ProductModel productModel) { return productModelMapper.listPageProductModel(page, productModel); } src/main/java/com/ruoyi/basic/vo/ProductModelVo.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,14 @@ package com.ruoyi.basic.vo; import com.ruoyi.basic.pojo.ProductModel; import lombok.Data; import lombok.EqualsAndHashCode; import java.util.List; @EqualsAndHashCode(callSuper = true) @Data public class ProductModelVo extends ProductModel { private List<String> batchNoList; } src/main/java/com/ruoyi/production/bean/dto/ProductionOrderPickDto.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,42 @@ package com.ruoyi.production.bean.dto; import com.fasterxml.jackson.annotation.JsonAlias; import com.ruoyi.production.pojo.ProductionOrderPick; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.math.BigDecimal; import java.util.List; @Data @Schema(name = "ProductionOrderPickDto", description = "ç产订å颿ä¿ååæ°") public class ProductionOrderPickDto extends ProductionOrderPick { @Schema(description = "ç产订åID") private Long productionOrderId; @Schema(description = "ç产工åID") private Long productionOperationTaskId; @Schema(description = "æ¹å·") private String batchNo; @Schema(description = "æ¹å·å表") private List<String> batchNoList; @Schema(description = "颿æ°é") private BigDecimal pickQuantity; @Schema(description = "é¢æç±»åï¼1æ£å¸¸é¢æï¼2è¡¥æ") private Byte pickType; @Schema(description = "夿³¨") private String remark; @Schema(description = "颿æç»å表") @JsonAlias({"dto", "productionOrderPickDto"}) private List<ProductionOrderPickDto> pickList; @Schema(description = "éè¦å é¤ç颿IDå表") private List<Long> deletePickIds; } src/main/java/com/ruoyi/production/bean/vo/ProductionOrderPickRecordVo.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,25 @@ package com.ruoyi.production.bean.vo; import com.ruoyi.production.pojo.ProductionOrderPickRecord; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; @Data @EqualsAndHashCode(callSuper = true) @Schema(name = "ProductionOrderPickRecordVo", description = "å·²é¢æè¯¦æ ") public class ProductionOrderPickRecordVo extends ProductionOrderPickRecord { @Schema(description = "å·¥åºåç§°") private String operationName; @Schema(description = "产ååç§°") private String productName; @Schema(description = "åå·") private String model; @Schema(description = "åä½") private String unit; } src/main/java/com/ruoyi/production/bean/vo/ProductionOrderPickVo.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,32 @@ package com.ruoyi.production.bean.vo; import com.ruoyi.production.pojo.ProductionOrderPick; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; import java.math.BigDecimal; import java.util.List; @EqualsAndHashCode(callSuper = true) @Data public class ProductionOrderPickVo extends ProductionOrderPick { @Schema(description = "åä½") private String unit; @Schema(description = "åºåæ°é") private BigDecimal stockQuantity; @Schema(description = "é¢ç¨æ°é") private BigDecimal pickQuantity; @Schema(description = "产ååç§°") private String productName; @Schema(description = "è§æ ¼åå·") private String model; @Schema(description = "æ¹å·") private List<String> batchNoList; } src/main/java/com/ruoyi/production/controller/ProductionOrderController.java
@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.framework.web.domain.R; import com.ruoyi.production.bean.dto.ProductionOrderDto; import com.ruoyi.production.bean.vo.ProductionOrderPickVo; import com.ruoyi.production.bean.vo.ProductionOrderVo; import com.ruoyi.production.bean.vo.ProductionPlanVo; import com.ruoyi.production.pojo.ProductionOrder; @@ -75,4 +76,10 @@ public R<List<ProductionPlanVo>> getSource(@PathVariable Long id) { return R.ok(productionOrderService.getSource(id)); } @GetMapping("/pick/{productionOrderId}") @Operation(summary = "æ ¹æ®è®¢åidæ¥è¯¢bom颿å") public R<List<ProductionOrderPickVo>> pick(@PathVariable Long productionOrderId) { return R.ok(productionOrderService.pick(productionOrderId)); } } src/main/java/com/ruoyi/production/controller/ProductionOrderPickController.java
@@ -1,7 +1,15 @@ package com.ruoyi.production.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.ruoyi.framework.web.domain.R; import com.ruoyi.production.bean.dto.ProductionOrderPickDto; import com.ruoyi.production.bean.vo.ProductionOrderPickVo; import com.ruoyi.production.service.ProductionOrderPickService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; import java.util.List; /** * <p> @@ -13,6 +21,28 @@ */ @RestController @RequestMapping("/productionOrderPick") @Tag(name = "ç产订å颿") @RequiredArgsConstructor public class ProductionOrderPickController { private final ProductionOrderPickService productionOrderPickService; @PostMapping("/savePick") @Operation(summary = "颿ä¿åå°çº¿è¾¹ä»") public R<Boolean> savePick(@RequestBody ProductionOrderPickDto dto) { return R.ok(productionOrderPickService.savePick(dto)); } @PostMapping("/updatePick") @Operation(summary = "忴颿") public R<Boolean> updatePick(@RequestBody ProductionOrderPickDto dto) { return R.ok(productionOrderPickService.updatePick(dto)); } @GetMapping("/detail/{productionOrderId}") @Operation(summary = "æ¥è¯¢å·²é¢æè¯¦æ ") public R<List<ProductionOrderPickVo>> listPickedDetail(@PathVariable Long productionOrderId) { return R.ok(productionOrderPickService.listPickedDetail(productionOrderId)); } } src/main/java/com/ruoyi/production/mapper/ProductionBomStructureMapper.java
@@ -21,4 +21,10 @@ List<ProductionBomStructureVo> listByBomId(@Param("bomId") Long bomId); /** * 颿bom * @param bomId * @return */ List<ProductionBomStructureVo> pickByBomId(@Param("bomId") Long bomId); } src/main/java/com/ruoyi/production/mapper/ProductionOrderPickMapper.java
@@ -1,8 +1,12 @@ package com.ruoyi.production.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruoyi.production.bean.vo.ProductionOrderPickVo; import com.ruoyi.production.pojo.ProductionOrderPick; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import java.util.List; /** * <p> @@ -15,4 +19,5 @@ @Mapper public interface ProductionOrderPickMapper extends BaseMapper<ProductionOrderPick> { List<ProductionOrderPickVo> listPickedDetailByOrderId(@Param("productionOrderId") Long productionOrderId); } src/main/java/com/ruoyi/production/mapper/ProductionOrderPickRecordMapper.java
@@ -1,8 +1,12 @@ package com.ruoyi.production.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruoyi.production.bean.vo.ProductionOrderPickVo; import com.ruoyi.production.pojo.ProductionOrderPickRecord; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import java.util.List; /** * <p> @@ -15,4 +19,6 @@ @Mapper public interface ProductionOrderPickRecordMapper extends BaseMapper<ProductionOrderPickRecord> { List<ProductionOrderPickVo> listPickedDetailByOrderId(@Param("productionOrderId") Long productionOrderId); } src/main/java/com/ruoyi/production/pojo/ProductionOrderPick.java
@@ -28,7 +28,7 @@ private Long id; @Schema(description = "产åè§æ ¼id") private Integer productModelId; private Long productModelId; @Schema(description = "æ°é") private BigDecimal quantity; @@ -56,4 +56,17 @@ @Schema(description = "é¨é¨ID") @TableField(fill = FieldFill.INSERT) private Long deptId; @Schema(description = "å·¥åºåç§°") private String operationName; @Schema(description = "å·¥åºid") private Long technologyOperationId; @Schema(description = "éæ±æ°é") private BigDecimal demandedQuantity; @Schema(description = "æ¯å¦bom颿") @TableField("is_bom") private Boolean bom; } src/main/java/com/ruoyi/production/pojo/ProductionOrderPickRecord.java
@@ -3,8 +3,6 @@ import com.baomidou.mybatisplus.annotation.*; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.Getter; import lombok.Setter; import java.io.Serializable; import java.math.BigDecimal; @@ -39,7 +37,7 @@ private Long productionOperationTaskId; @Schema(description = "产åè§æ ¼id") private Integer productModelId; private Long productModelId; @Schema(description = "æ¹å·") private String batchNo; src/main/java/com/ruoyi/production/service/ProductionOrderPickService.java
@@ -1,7 +1,11 @@ package com.ruoyi.production.service; import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.production.bean.dto.ProductionOrderPickDto; import com.ruoyi.production.bean.vo.ProductionOrderPickVo; import com.ruoyi.production.pojo.ProductionOrderPick; import java.util.List; /** * <p> @@ -13,4 +17,9 @@ */ public interface ProductionOrderPickService extends IService<ProductionOrderPick> { Boolean savePick(ProductionOrderPickDto dto); Boolean updatePick(ProductionOrderPickDto dto); List<ProductionOrderPickVo> listPickedDetail(Long productionOrderId); } src/main/java/com/ruoyi/production/service/ProductionOrderService.java
@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.production.bean.dto.ProductionOrderDto; import com.ruoyi.production.bean.vo.ProductionOrderPickVo; import com.ruoyi.production.bean.vo.ProductionOrderVo; import com.ruoyi.production.bean.vo.ProductionPlanVo; import com.ruoyi.production.pojo.ProductionOrder; @@ -27,4 +28,6 @@ Object bindingRoute(ProductionOrderDto productionOrderDto); List<ProductionPlanVo> getSource(Long id); List<ProductionOrderPickVo> pick(Long productionOrderId); } src/main/java/com/ruoyi/production/service/impl/ProductionOrderPickServiceImpl.java
@@ -1,20 +1,657 @@ package com.ruoyi.production.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.production.bean.dto.ProductionOrderPickDto; import com.ruoyi.production.bean.vo.ProductionOrderPickVo; import com.ruoyi.production.mapper.ProductionOperationTaskMapper; import com.ruoyi.production.mapper.ProductionOrderMapper; import com.ruoyi.production.mapper.ProductionOrderPickMapper; import com.ruoyi.production.mapper.ProductionOrderPickRecordMapper; import com.ruoyi.production.pojo.ProductionOrder; import com.ruoyi.production.pojo.ProductionOrderPick; import com.ruoyi.production.pojo.ProductionOrderPickRecord; import com.ruoyi.production.service.ProductionOrderPickService; import com.ruoyi.stock.dto.StockInventoryDto; import com.ruoyi.stock.mapper.StockInventoryMapper; import com.ruoyi.stock.pojo.StockInventory; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; /** * <p> * 订åé¢æçº¿è¾¹ä» æå¡å®ç°ç±» * çã å´æ£°åæ¡ç»¾è¯ç«æµ ?éå¶ å§ç¹çµå¹ç»«? * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @author éºîî±æîæ¬¢éå çé»å¿¥ç´é夿ªºéîå¾ * @since 2026-04-21 03:55:52 */ @Service @RequiredArgsConstructor public class ProductionOrderPickServiceImpl extends ServiceImpl<ProductionOrderPickMapper, ProductionOrderPick> implements ProductionOrderPickService { private final ProductionOrderMapper productionOrderMapper; private final ProductionOperationTaskMapper productionOperationTaskMapper; private final ProductionOrderPickRecordMapper productionOrderPickRecordMapper; private final StockInventoryMapper stockInventoryMapper; @Override @Transactional(rollbackFor = Exception.class) public Boolean savePick(ProductionOrderPickDto dto) { List<ProductionOrderPickDto> pickItems = resolvePickItems(dto); for (int i = 0; i < pickItems.size(); i++) { int rowNo = i + 1; ProductionOrderPickDto resolvedDto = mergeDto(dto, pickItems.get(i)); validatePickParam(resolvedDto, rowNo); List<String> batchNoList = resolveBatchNoList(resolvedDto); String inventoryBatchNo = pickInventoryBatchNo(batchNoList); String storedBatchNo = formatBatchNoStorage(batchNoList); subtractInventory(resolvedDto.getProductModelId(), inventoryBatchNo, resolvedDto.getPickQuantity(), rowNo); ProductionOrderPick orderPick = new ProductionOrderPick(); orderPick.setProductionOrderId(resolvedDto.getProductionOrderId()); orderPick.setProductModelId(resolvedDto.getProductModelId()); orderPick.setBatchNo(storedBatchNo); orderPick.setQuantity(resolvedDto.getPickQuantity()); orderPick.setRemark(resolvedDto.getRemark()); orderPick.setOperationName(resolvedDto.getOperationName()); orderPick.setTechnologyOperationId(resolvedDto.getTechnologyOperationId()); orderPick.setDemandedQuantity(resolvedDto.getDemandedQuantity()); orderPick.setBom(resolvedDto.getBom()); baseMapper.insert(orderPick); insertPickRecord(orderPick.getId(), resolvedDto.getProductionOrderId(), resolvedDto.getProductionOperationTaskId(), resolvedDto.getProductModelId(), inventoryBatchNo, resolvedDto.getPickQuantity(), BigDecimal.ZERO, resolvedDto.getPickQuantity(), resolvedDto.getPickType(), resolvedDto.getRemark()); } return true; } @Override @Transactional(rollbackFor = Exception.class) public Boolean updatePick(ProductionOrderPickDto dto) { if (dto == null) { throw new ServiceException("åæ´åæ°ä¸è½ä¸ºç©º"); } Long productionOrderId = resolveProductionOrderId(dto); if (productionOrderId == null) { throw new ServiceException("ç产订åIDä¸è½ä¸ºç©º"); } ProductionOrder productionOrder = productionOrderMapper.selectById(productionOrderId); if (productionOrder == null) { throw new ServiceException("ç产订åä¸åå¨"); } List<ProductionOrderPick> existingPickList = baseMapper.selectList( Wrappers.<ProductionOrderPick>lambdaQuery() .eq(ProductionOrderPick::getProductionOrderId, productionOrderId)); Map<Long, ProductionOrderPick> existingPickMap = existingPickList.stream() .filter(item -> item.getId() != null) .collect(Collectors.toMap(ProductionOrderPick::getId, Function.identity(), (a, b) -> a)); processDeletePickIds(dto, existingPickMap, productionOrderId); List<ProductionOrderPickDto> pickItems = resolveUpdateItems(dto); Set<Long> keepPickIdSet = new HashSet<>(); for (int i = 0; i < pickItems.size(); i++) { int rowNo = i + 1; ProductionOrderPickDto resolvedDto = mergeDto(dto, pickItems.get(i)); if (isEmptyUpdateItem(resolvedDto)) { continue; } if (resolvedDto.getProductionOrderId() == null) { resolvedDto.setProductionOrderId(productionOrderId); } validatePickParam(resolvedDto, rowNo); if (resolvedDto.getId() == null) { addNewPickInUpdate(resolvedDto, rowNo); continue; } keepPickIdSet.add(resolvedDto.getId()); updateExistingPick(resolvedDto, rowNo, existingPickMap); } processMissingPickItems(dto, existingPickMap, productionOrderId, keepPickIdSet); return true; } @Override public List<ProductionOrderPickVo> listPickedDetail(Long productionOrderId) { if (productionOrderId == null) { return Collections.emptyList(); } List<ProductionOrderPickVo> detailList = baseMapper.listPickedDetailByOrderId(productionOrderId); fillBatchNoList(detailList); fillSelectableBatchNoList(detailList); return detailList; } private void processDeletePickIds(ProductionOrderPickDto rootDto, Map<Long, ProductionOrderPick> existingPickMap, Long productionOrderId) { if (rootDto.getDeletePickIds() == null || rootDto.getDeletePickIds().isEmpty()) { return; } Set<Long> deleteIdSet = new LinkedHashSet<>(rootDto.getDeletePickIds()); for (Long deleteId : deleteIdSet) { if (deleteId == null) { continue; } ProductionOrderPick existingPick = existingPickMap.get(deleteId); if (existingPick == null || !Objects.equals(existingPick.getProductionOrderId(), productionOrderId)) { throw new ServiceException("è¦å é¤çé¢æè®°å½ä¸å卿ä¸å±äºå½å订åï¼ID=" + deleteId); } String oldBatchNo = resolveInventoryBatchNoFromStored(existingPick.getBatchNo()); BigDecimal oldQuantity = defaultDecimal(existingPick.getQuantity()); addInventory(existingPick.getProductModelId(), oldBatchNo, oldQuantity); int affected = baseMapper.deleteById(deleteId); if (affected <= 0) { throw new ServiceException("å é¤é¢æå¤±è´¥ï¼ID=" + deleteId); } insertPickRecord(existingPick.getId(), existingPick.getProductionOrderId(), rootDto.getProductionOperationTaskId(), existingPick.getProductModelId(), oldBatchNo, oldQuantity, oldQuantity, BigDecimal.ZERO, rootDto.getPickType(), rootDto.getRemark()); existingPickMap.remove(deleteId); } } private void processMissingPickItems(ProductionOrderPickDto rootDto, Map<Long, ProductionOrderPick> existingPickMap, Long productionOrderId, Set<Long> keepPickIdSet) { if (rootDto.getPickList() == null) { return; } List<ProductionOrderPick> missingPickList = existingPickMap.values().stream() .filter(Objects::nonNull) .filter(item -> item.getId() != null) .filter(item -> Objects.equals(item.getProductionOrderId(), productionOrderId)) .filter(item -> !keepPickIdSet.contains(item.getId())) .collect(Collectors.toList()); for (ProductionOrderPick missingPick : missingPickList) { String oldBatchNo = resolveInventoryBatchNoFromStored(missingPick.getBatchNo()); BigDecimal oldQuantity = defaultDecimal(missingPick.getQuantity()); addInventory(missingPick.getProductModelId(), oldBatchNo, oldQuantity); int affected = baseMapper.deleteById(missingPick.getId()); if (affected <= 0) { throw new ServiceException("å é¤é¢æå¤±è´¥ï¼ID=" + missingPick.getId()); } insertPickRecord(missingPick.getId(), missingPick.getProductionOrderId(), rootDto.getProductionOperationTaskId(), missingPick.getProductModelId(), oldBatchNo, oldQuantity, oldQuantity, BigDecimal.ZERO, rootDto.getPickType(), rootDto.getRemark()); existingPickMap.remove(missingPick.getId()); } } private void addNewPickInUpdate(ProductionOrderPickDto dto, int rowNo) { List<String> batchNoList = resolveBatchNoList(dto); String inventoryBatchNo = pickInventoryBatchNo(batchNoList); String storedBatchNo = formatBatchNoStorage(batchNoList); subtractInventory(dto.getProductModelId(), inventoryBatchNo, dto.getPickQuantity(), rowNo); ProductionOrderPick orderPick = new ProductionOrderPick(); orderPick.setProductionOrderId(dto.getProductionOrderId()); orderPick.setProductModelId(dto.getProductModelId()); orderPick.setBatchNo(storedBatchNo); orderPick.setQuantity(dto.getPickQuantity()); orderPick.setRemark(dto.getRemark()); orderPick.setOperationName(dto.getOperationName()); orderPick.setTechnologyOperationId(dto.getTechnologyOperationId()); orderPick.setDemandedQuantity(dto.getDemandedQuantity()); orderPick.setBom(dto.getBom()); baseMapper.insert(orderPick); insertPickRecord(orderPick.getId(), dto.getProductionOrderId(), dto.getProductionOperationTaskId(), dto.getProductModelId(), inventoryBatchNo, dto.getPickQuantity(), BigDecimal.ZERO, dto.getPickQuantity(), dto.getPickType(), dto.getRemark()); } private void updateExistingPick(ProductionOrderPickDto dto, int rowNo, Map<Long, ProductionOrderPick> existingPickMap) { ProductionOrderPick oldPick = existingPickMap.get(dto.getId()); if (oldPick == null || !Objects.equals(oldPick.getProductionOrderId(), dto.getProductionOrderId())) { throw new ServiceException("第" + rowNo + "æ¡é¢æè®°å½ä¸å卿ä¸å±äºå½å订å"); } Long oldProductModelId = oldPick.getProductModelId(); String oldBatchNo = resolveInventoryBatchNoFromStored(oldPick.getBatchNo()); BigDecimal oldQuantity = defaultDecimal(oldPick.getQuantity()); Long newProductModelId = dto.getProductModelId(); List<String> newBatchNoList = resolveBatchNoList(dto); String newBatchNo = pickInventoryBatchNo(newBatchNoList); String newStoredBatchNo = formatBatchNoStorage(newBatchNoList); BigDecimal newQuantity = dto.getPickQuantity(); boolean sameStockKey = Objects.equals(oldProductModelId, newProductModelId) && Objects.equals(oldBatchNo, newBatchNo); if (sameStockKey) { BigDecimal delta = newQuantity.subtract(oldQuantity); if (delta.compareTo(BigDecimal.ZERO) > 0) { subtractInventory(newProductModelId, newBatchNo, delta, rowNo); } else if (delta.compareTo(BigDecimal.ZERO) < 0) { addInventory(oldProductModelId, oldBatchNo, delta.abs()); } } else { addInventory(oldProductModelId, oldBatchNo, oldQuantity); subtractInventory(newProductModelId, newBatchNo, newQuantity, rowNo); } oldPick.setProductModelId(newProductModelId); oldPick.setBatchNo(newStoredBatchNo); oldPick.setQuantity(newQuantity); oldPick.setRemark(dto.getRemark()); oldPick.setOperationName(dto.getOperationName()); oldPick.setTechnologyOperationId(dto.getTechnologyOperationId()); if (dto.getDemandedQuantity() != null) { oldPick.setDemandedQuantity(dto.getDemandedQuantity()); } if (dto.getBom() != null) { oldPick.setBom(dto.getBom()); } int affected = baseMapper.updateById(oldPick); if (affected <= 0) { throw new ServiceException("第" + rowNo + "æ¡é¢ææ´æ°å¤±è´¥"); } BigDecimal recordQuantity = sameStockKey ? oldQuantity.subtract(newQuantity).abs() : newQuantity; if (recordQuantity.compareTo(BigDecimal.ZERO) > 0 || oldQuantity.compareTo(newQuantity) != 0 || !sameStockKey) { insertPickRecord(oldPick.getId(), dto.getProductionOrderId(), dto.getProductionOperationTaskId(), newProductModelId, newBatchNo, recordQuantity, oldQuantity, newQuantity, dto.getPickType(), dto.getRemark()); } } private void insertPickRecord(Long pickId, Long productionOrderId, Long productionOperationTaskId, Long productModelId, String batchNo, BigDecimal pickQuantity, BigDecimal beforeQuantity, BigDecimal afterQuantity, Byte pickType, String remark) { ProductionOrderPickRecord pickRecord = new ProductionOrderPickRecord(); pickRecord.setPickId(pickId); pickRecord.setProductionOrderId(productionOrderId); pickRecord.setProductionOperationTaskId(productionOperationTaskId); pickRecord.setProductModelId(productModelId); pickRecord.setBatchNo(batchNo); pickRecord.setPickQuantity(defaultDecimal(pickQuantity)); pickRecord.setBeforeQuantity(defaultDecimal(beforeQuantity)); pickRecord.setAfterQuantity(defaultDecimal(afterQuantity)); pickRecord.setPickType(pickType == null ? (byte) 1 : pickType); pickRecord.setRemark(remark); productionOrderPickRecordMapper.insert(pickRecord); } private void subtractInventory(Long productModelId, String batchNo, BigDecimal quantity, int rowNo) { StockInventory stockInventory = stockInventoryMapper.selectOne(buildStockWrapper(productModelId, batchNo)); if (stockInventory == null) { throw new ServiceException("第" + rowNo + "æ¡é¢æå¯¹åºåºåä¸åå¨"); } BigDecimal availableQuantity = defaultDecimal(stockInventory.getQualitity()) .subtract(defaultDecimal(stockInventory.getLockedQuantity())); if (quantity.compareTo(availableQuantity) > 0) { throw new ServiceException("第" + rowNo + "æ¡é¢æå¯ç¨åºåä¸è¶³"); } StockInventoryDto stockInventoryDto = new StockInventoryDto(); stockInventoryDto.setProductModelId(productModelId); stockInventoryDto.setBatchNo(batchNo); stockInventoryDto.setQualitity(quantity); int affected = stockInventoryMapper.updateSubtractStockInventory(stockInventoryDto); if (affected <= 0) { throw new ServiceException("第" + rowNo + "æ¡é¢ææ£ååºå失败"); } } private void addInventory(Long productModelId, String batchNo, BigDecimal quantity) { BigDecimal addQuantity = defaultDecimal(quantity); if (addQuantity.compareTo(BigDecimal.ZERO) <= 0) { return; } StockInventory stockInventory = stockInventoryMapper.selectOne(buildStockWrapper(productModelId, batchNo)); if (stockInventory == null) { StockInventory newStockInventory = new StockInventory(); newStockInventory.setProductModelId(productModelId); newStockInventory.setBatchNo(batchNo); newStockInventory.setQualitity(addQuantity); newStockInventory.setLockedQuantity(BigDecimal.ZERO); newStockInventory.setVersion(1); stockInventoryMapper.insert(newStockInventory); return; } StockInventoryDto stockInventoryDto = new StockInventoryDto(); stockInventoryDto.setProductModelId(productModelId); stockInventoryDto.setBatchNo(batchNo); stockInventoryDto.setQualitity(addQuantity); int affected = stockInventoryMapper.updateAddStockInventory(stockInventoryDto); if (affected <= 0) { throw new ServiceException("åºååé失败ï¼äº§åè§æ ¼ID=" + productModelId); } } private List<ProductionOrderPickDto> resolvePickItems(ProductionOrderPickDto dto) { if (dto == null) { throw new ServiceException("颿忰ä¸è½ä¸ºç©º"); } if (dto.getPickList() != null && !dto.getPickList().isEmpty()) { return dto.getPickList(); } return Collections.singletonList(dto); } private List<ProductionOrderPickDto> resolveUpdateItems(ProductionOrderPickDto dto) { if (dto.getPickList() != null) { return dto.getPickList(); } if (isEmptyUpdateItem(dto)) { return Collections.emptyList(); } return Collections.singletonList(dto); } private boolean isEmptyUpdateItem(ProductionOrderPickDto dto) { return dto.getId() == null && dto.getProductModelId() == null && dto.getPickQuantity() == null && StringUtils.isEmpty(dto.getBatchNo()) && (dto.getBatchNoList() == null || dto.getBatchNoList().isEmpty()) && dto.getPickType() == null && dto.getProductionOperationTaskId() == null && dto.getTechnologyOperationId() == null && StringUtils.isEmpty(dto.getOperationName()) && dto.getDemandedQuantity() == null && dto.getBom() == null && StringUtils.isEmpty(dto.getRemark()); } private Long resolveProductionOrderId(ProductionOrderPickDto dto) { if (dto.getProductionOrderId() != null) { return dto.getProductionOrderId(); } if (dto.getPickList() == null || dto.getPickList().isEmpty()) { return null; } return dto.getPickList().stream() .filter(Objects::nonNull) .map(ProductionOrderPickDto::getProductionOrderId) .filter(Objects::nonNull) .findFirst() .orElse(null); } private ProductionOrderPickDto mergeDto(ProductionOrderPickDto rootDto, ProductionOrderPickDto itemDto) { ProductionOrderPickDto merged = new ProductionOrderPickDto(); if (itemDto != null) { merged.setId(itemDto.getId()); merged.setProductionOrderId(itemDto.getProductionOrderId()); merged.setProductionOperationTaskId(itemDto.getProductionOperationTaskId()); merged.setProductModelId(itemDto.getProductModelId()); merged.setBatchNo(itemDto.getBatchNo()); merged.setBatchNoList(itemDto.getBatchNoList()); merged.setPickQuantity(itemDto.getPickQuantity()); merged.setPickType(itemDto.getPickType()); merged.setRemark(itemDto.getRemark()); merged.setTechnologyOperationId(itemDto.getTechnologyOperationId()); merged.setOperationName(itemDto.getOperationName()); merged.setDemandedQuantity(itemDto.getDemandedQuantity()); merged.setBom(itemDto.getBom()); } if (merged.getId() == null) { merged.setId(rootDto.getId()); } if (merged.getProductionOrderId() == null) { merged.setProductionOrderId(rootDto.getProductionOrderId()); } if (merged.getProductionOperationTaskId() == null) { merged.setProductionOperationTaskId(rootDto.getProductionOperationTaskId()); } if (merged.getProductModelId() == null) { merged.setProductModelId(rootDto.getProductModelId()); } if (merged.getBatchNo() == null) { merged.setBatchNo(rootDto.getBatchNo()); } if (merged.getBatchNoList() == null || merged.getBatchNoList().isEmpty()) { merged.setBatchNoList(rootDto.getBatchNoList()); } if (merged.getPickQuantity() == null) { merged.setPickQuantity(rootDto.getPickQuantity()); } if (merged.getPickType() == null) { merged.setPickType(rootDto.getPickType()); } if (merged.getRemark() == null) { merged.setRemark(rootDto.getRemark()); } if (merged.getTechnologyOperationId() == null) { merged.setTechnologyOperationId(rootDto.getTechnologyOperationId()); } if (merged.getOperationName() == null) { merged.setOperationName(rootDto.getOperationName()); } if (merged.getDemandedQuantity() == null) { merged.setDemandedQuantity(rootDto.getDemandedQuantity()); } if (merged.getBom() == null) { merged.setBom(rootDto.getBom()); } return merged; } private void validatePickParam(ProductionOrderPickDto dto, int rowNo) { if (dto.getProductionOrderId() == null) { throw new ServiceException("第" + rowNo + "æ¡ç产订åIDä¸è½ä¸ºç©º"); } if (dto.getProductModelId() == null) { throw new ServiceException("第" + rowNo + "æ¡äº§åè§æ ¼IDä¸è½ä¸ºç©º"); } if (dto.getPickQuantity() == null || dto.getPickQuantity().compareTo(BigDecimal.ZERO) <= 0) { throw new ServiceException("第" + rowNo + "æ¡é¢ææ°éå¿ é¡»å¤§äº0"); } if (dto.getPickType() != null && dto.getPickType() != 1 && dto.getPickType() != 2) { throw new ServiceException("第" + rowNo + "æ¡é¢æç±»ååªè½æ¯1æ2"); } } private String normalizeBatchNo(String batchNo) { if (StringUtils.isEmpty(batchNo)) { return null; } String trimBatchNo = batchNo.trim(); return trimBatchNo.isEmpty() ? null : trimBatchNo; } private List<String> resolveBatchNoList(ProductionOrderPickDto dto) { List<String> normalizedBatchNoList = normalizeBatchNoList(dto.getBatchNoList()); if (!normalizedBatchNoList.isEmpty()) { return normalizedBatchNoList; } return parseBatchNoValue(dto.getBatchNo()); } private String pickInventoryBatchNo(List<String> batchNoList) { if (batchNoList == null || batchNoList.isEmpty()) { return null; } return batchNoList.get(0); } private String resolveInventoryBatchNoFromStored(String storedBatchNo) { return pickInventoryBatchNo(parseBatchNoValue(storedBatchNo)); } private String formatBatchNoStorage(List<String> batchNoList) { if (batchNoList == null || batchNoList.isEmpty()) { return null; } if (batchNoList.size() == 1) { return batchNoList.get(0); } return String.join(",", batchNoList); } private List<String> normalizeBatchNoList(List<String> batchNoList) { if (batchNoList == null || batchNoList.isEmpty()) { return Collections.emptyList(); } LinkedHashSet<String> normalizedSet = new LinkedHashSet<>(); for (String batchNo : batchNoList) { String normalizedBatchNo = normalizeBatchNo(batchNo); if (!StringUtils.isEmpty(normalizedBatchNo)) { normalizedSet.add(normalizedBatchNo); } } return new ArrayList<>(normalizedSet); } private void fillBatchNoList(List<ProductionOrderPickVo> detailList) { if (detailList == null || detailList.isEmpty()) { return; } Map<String, LinkedHashSet<String>> batchNoGroupMap = new HashMap<>(); for (ProductionOrderPickVo detail : detailList) { String key = buildBatchNoGroupKey(detail); LinkedHashSet<String> batchSet = batchNoGroupMap.computeIfAbsent(key, k -> new LinkedHashSet<>()); batchSet.addAll(parseBatchNoValue(detail.getBatchNo())); if (detail.getBatchNoList() != null && !detail.getBatchNoList().isEmpty()) { batchSet.addAll(normalizeBatchNoList(detail.getBatchNoList())); } } for (ProductionOrderPickVo detail : detailList) { String key = buildBatchNoGroupKey(detail); LinkedHashSet<String> batchSet = batchNoGroupMap.get(key); detail.setBatchNoList(batchSet == null ? Collections.emptyList() : new ArrayList<>(batchSet)); } } private void fillSelectableBatchNoList(List<ProductionOrderPickVo> detailList) { if (detailList == null || detailList.isEmpty()) { return; } Set<Long> productModelIdSet = detailList.stream() .map(ProductionOrderPickVo::getProductModelId) .filter(Objects::nonNull) .collect(Collectors.toSet()); if (productModelIdSet.isEmpty()) { return; } List<StockInventory> stockBatchList = stockInventoryMapper.listSelectableBatchNoByProductModelIds( new ArrayList<>(productModelIdSet)); Map<Long, LinkedHashSet<String>> stockBatchMap = new HashMap<>(); for (StockInventory stockInventory : stockBatchList) { if (stockInventory == null || stockInventory.getProductModelId() == null) { continue; } String normalizedBatchNo = normalizeBatchNo(stockInventory.getBatchNo()); if (StringUtils.isEmpty(normalizedBatchNo)) { continue; } stockBatchMap.computeIfAbsent(stockInventory.getProductModelId(), k -> new LinkedHashSet<>()) .add(normalizedBatchNo); } for (ProductionOrderPickVo detail : detailList) { LinkedHashSet<String> mergedBatchSet = new LinkedHashSet<>(); mergedBatchSet.addAll(normalizeBatchNoList(detail.getBatchNoList())); LinkedHashSet<String> selectableBatchSet = stockBatchMap.get(detail.getProductModelId()); if (selectableBatchSet != null) { mergedBatchSet.addAll(selectableBatchSet); } detail.setBatchNoList(new ArrayList<>(mergedBatchSet)); } } private String buildBatchNoGroupKey(ProductionOrderPickVo detail) { return String.valueOf(detail.getProductionOrderId()) + "|" + String.valueOf(detail.getProductModelId()) + "|" + String.valueOf(detail.getTechnologyOperationId()) + "|" + String.valueOf(detail.getOperationName()); } private List<String> parseBatchNoValue(String rawBatchNoValue) { String normalizedValue = normalizeBatchNo(rawBatchNoValue); if (StringUtils.isEmpty(normalizedValue)) { return Collections.emptyList(); } if (normalizedValue.startsWith("[") && normalizedValue.endsWith("]")) { String value = normalizedValue.substring(1, normalizedValue.length() - 1); if (StringUtils.isEmpty(value)) { return Collections.emptyList(); } List<String> parsed = Arrays.stream(value.split(",")) .map(item -> item == null ? null : item.trim().replace("\"", "").replace("'", "")) .collect(Collectors.toList()); return normalizeBatchNoList(parsed); } if (normalizedValue.contains(",")) { List<String> parsed = Arrays.stream(normalizedValue.split(",")) .map(item -> item == null ? null : item.trim()) .collect(Collectors.toList()); return normalizeBatchNoList(parsed); } return Collections.singletonList(normalizedValue); } private LambdaQueryWrapper<StockInventory> buildStockWrapper(Long productModelId, String batchNo) { LambdaQueryWrapper<StockInventory> wrapper = Wrappers.<StockInventory>lambdaQuery() .eq(StockInventory::getProductModelId, productModelId); if (StringUtils.isEmpty(batchNo)) { wrapper.isNull(StockInventory::getBatchNo); } else { wrapper.eq(StockInventory::getBatchNo, batchNo); } return wrapper; } private BigDecimal defaultDecimal(BigDecimal value) { return value == null ? BigDecimal.ZERO : value; } } src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java
@@ -15,6 +15,8 @@ import com.ruoyi.common.constant.StorageAttachmentConstants; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.production.bean.dto.ProductionOrderDto; import com.ruoyi.production.bean.vo.ProductionBomStructureVo; import com.ruoyi.production.bean.vo.ProductionOrderPickVo; import com.ruoyi.production.bean.vo.ProductionOrderVo; import com.ruoyi.production.bean.vo.ProductionPlanVo; import com.ruoyi.production.enums.ProductOrderStatusEnum; @@ -23,6 +25,8 @@ import com.ruoyi.production.service.ProductionOrderService; import com.ruoyi.sales.mapper.SalesLedgerMapper; import com.ruoyi.sales.mapper.SalesLedgerProductMapper; import com.ruoyi.stock.mapper.StockInventoryMapper; import com.ruoyi.stock.pojo.StockInventory; import com.ruoyi.technology.mapper.*; import com.ruoyi.technology.pojo.*; import lombok.RequiredArgsConstructor; @@ -50,6 +54,7 @@ private final ProductionOrderPickMapper productionOrderPickMapper; private final ProductionOrderPickRecordMapper productionOrderPickRecordMapper; private final ProductionPlanMapper productionPlanMapper; private final StockInventoryMapper stockInventoryMapper; private final StorageAttachmentMapper storageAttachmentMapper; private final StorageBlobMapper storageBlobMapper; private final SalesLedgerMapper salesLedgerMapper; @@ -112,11 +117,7 @@ || productionOrderRoutingMapper.selectCount(Wrappers.<ProductionOrderRouting>lambdaQuery() .eq(ProductionOrderRouting::getProductionOrderId, productionOrder.getId())) == 0); if (needSync) { // å·¥èºãäº§åææ°éåååï¼è®¢åå¿«ç §å¿ é¡»åå½åä¸åæ°æ®éæ°å¯¹é½ã syncProductionOrderSnapshot(productionOrder.getId()); } else { // æªéå»ºå¿«ç §æ¶ï¼ä¹è¦ç¡®ä¿å¤æä¸»ååè®¢åæ°éä¿æåæ¥ã upsertOrderPick(productionOrder); } return true; } @@ -274,8 +275,6 @@ syncedParamCount++; } } upsertOrderPick(productionOrder); return syncedParamCount; } @@ -551,29 +550,6 @@ return issuedQuantity.compareTo(requiredQuantity) < 0 ? 1 : 2; } private void upsertOrderPick(ProductionOrder productionOrder) { if (productionOrder == null || productionOrder.getId() == null) { return; } // 订åä¸è¾¾åèªå¨çæä¸å¼ 夿䏻åï¼åç»é¢æè®°å½é½æå¨è¿å¼ åä¸ã ProductionOrderPick orderPick = productionOrderPickMapper.selectOne( Wrappers.<ProductionOrderPick>lambdaQuery() .eq(ProductionOrderPick::getProductionOrderId, productionOrder.getId()) .last("limit 1")); if (orderPick == null) { orderPick = new ProductionOrderPick(); orderPick.setProductionOrderId(productionOrder.getId()); } orderPick.setProductModelId(productionOrder.getProductModelId() == null ? null : Math.toIntExact(productionOrder.getProductModelId())); orderPick.setQuantity(defaultDecimal(productionOrder.getQuantity())); orderPick.setRemark("ä¸åèªå¨çæ"); if (orderPick.getId() == null) { productionOrderPickMapper.insert(orderPick); } else { productionOrderPickMapper.updateById(orderPick); } } private List<Long> parsePlanIds(String productionPlanIds) { if (productionPlanIds == null || productionPlanIds.trim().isEmpty()) { return new ArrayList<>(); @@ -677,4 +653,73 @@ vo.setDownloadURL(fileUtil.buildSignedDownloadUrl(vo)); return vo; } @Override public List<ProductionOrderPickVo> pick(Long productionOrderId) { if (productionOrderId == null) { return Collections.emptyList(); } ProductionOrderBom orderBom = productionOrderBomMapper.selectOne( Wrappers.<ProductionOrderBom>lambdaQuery() .eq(ProductionOrderBom::getProductionOrderId, productionOrderId) .orderByDesc(ProductionOrderBom::getId) .last("limit 1")); if (orderBom == null || orderBom.getId() == null) { return Collections.emptyList(); } List<ProductionBomStructureVo> bomStructureList = productionBomStructureMapper.pickByBomId(orderBom.getId()); if (bomStructureList == null || bomStructureList.isEmpty()) { return Collections.emptyList(); } List<Long> productModelIds = bomStructureList.stream() .map(ProductionBomStructureVo::getProductModelId) .filter(Objects::nonNull) .distinct() .collect(Collectors.toList()); Map<Long, BigDecimal> stockQuantityMap = new HashMap<>(); Map<Long, LinkedHashSet<String>> stockBatchNoMap = new HashMap<>(); if (!productModelIds.isEmpty()) { List<StockInventory> stockList = stockInventoryMapper.selectList( Wrappers.<StockInventory>lambdaQuery() .in(StockInventory::getProductModelId, productModelIds)); for (StockInventory stockItem : stockList) { if (stockItem == null || stockItem.getProductModelId() == null) { continue; } Long productModelId = stockItem.getProductModelId(); stockQuantityMap.merge(productModelId, defaultDecimal(stockItem.getQualitity()), BigDecimal::add); String batchNo = stockItem.getBatchNo(); if (batchNo != null && !batchNo.trim().isEmpty()) { stockBatchNoMap.computeIfAbsent(productModelId, key -> new LinkedHashSet<>()).add(batchNo); } } } List<ProductionOrderPickVo> result = new ArrayList<>(bomStructureList.size()); for (ProductionBomStructureVo structure : bomStructureList) { if (structure == null || structure.getProductModelId() == null) { continue; } Long productModelId = structure.getProductModelId(); ProductionOrderPickVo vo = new ProductionOrderPickVo(); vo.setProductModelId(productModelId); vo.setOperationName(structure.getOperationName()); vo.setTechnologyOperationId(structure.getTechnologyOperationId()); vo.setProductName(structure.getProductName()); vo.setModel(structure.getModel()); vo.setDemandedQuantity(defaultDecimal(structure.getDemandedQuantity())); vo.setUnit(structure.getUnit()); List<String> batchNoList = stockBatchNoMap.get(productModelId) == null ? Collections.emptyList() : new ArrayList<>(stockBatchNoMap.get(productModelId)); vo.setBatchNoList(batchNoList); vo.setStockQuantity(stockQuantityMap.getOrDefault(productModelId, BigDecimal.ZERO)); vo.setBom(true); result.add(vo); } return result; } } src/main/java/com/ruoyi/stock/mapper/StockInventoryMapper.java
@@ -52,4 +52,6 @@ BigDecimal selectTotalByDate(@Param("now") LocalDate now); BigDecimal selectPendingOutQuantity(@Param("productModelId") Long productModelId, @Param("batchNo") String batchNo, @Param("type") String type); List<StockInventory> listSelectableBatchNoByProductModelIds(@Param("productModelIds") List<Long> productModelIds); } src/main/resources/mapper/basic/ProductModelMapper.xml
@@ -14,7 +14,16 @@ <result column="product_name" property="productName" /> <result column="product_id" property="productId" /> </resultMap> <select id="listPageProductModel" resultType="com.ruoyi.basic.pojo.ProductModel"> <resultMap id="ProductModelVoResultMap" type="com.ruoyi.basic.vo.ProductModelVo" extends="BaseResultMap"> <result column="create_time" property="createTime" /> <collection property="batchNoList" ofType="java.lang.String" column="{productModelId=id}" select="selectBatchNoListByProductModelId"/> </resultMap> <select id="listPageProductModel" resultMap="ProductModelVoResultMap"> select pm.*,p.product_name from product_model pm left join product p on pm.product_id = p.id @@ -44,6 +53,15 @@ </where> order by pm.id </select> <select id="selectBatchNoListByProductModelId" resultType="java.lang.String"> select distinct si.batch_no from stock_inventory si where si.product_model_id = #{productModelId} and si.batch_no is not null and si.batch_no != '' order by si.batch_no </select> <select id="selectLatestRecord" resultType="com.ruoyi.basic.pojo.ProductModel"> SELECT * FROM product_model ORDER BY create_time DESC, id DESC src/main/resources/mapper/production/ProductionBomStructureMapper.xml
@@ -31,4 +31,23 @@ order by pbs.id </select> <select id="pickByBomId" resultType="com.ruoyi.production.bean.vo.ProductionBomStructureVo"> SELECT pbs.*, p.product_name AS productName, pm.product_id AS productId, pm.model, top1.NAME AS operationName FROM production_bom_structure pbs LEFT JOIN product_model pm ON pbs.product_model_id = pm.id LEFT JOIN product p ON pm.product_id = p.id LEFT JOIN technology_operation top1 ON pbs.technology_operation_id = top1.id WHERE pbs.parent_id IS NOT NULL AND pbs.production_order_bom_id = #{bomId} ORDER BY pbs.id </select> </mapper> src/main/resources/mapper/production/ProductionOrderPickMapper.xml
@@ -14,6 +14,24 @@ <result column="remark" property="remark" /> <result column="create_user" property="createUser" /> <result column="dept_id" property="deptId" /> <result column="operation_name" property="operationName" /> <result column="technology_operation_id" property="technologyOperationId" /> <result column="demanded_quantity" property="demandedQuantity" /> <result column="is_bom" property="bom" /> </resultMap> <select id="listPickedDetailByOrderId" resultType="com.ruoyi.production.bean.vo.ProductionOrderPickVo"> select pop.*, pop.is_bom as bom, pop.quantity as pickQuantity, p.product_name as productName, pm.model as model, pm.unit as unit from production_order_pick pop left join product_model pm on pop.product_model_id = pm.id left join product p on pm.product_id = p.id where pop.production_order_id = #{productionOrderId} order by pop.create_time desc, pop.id desc </select> </mapper> src/main/resources/mapper/production/ProductionOrderPickRecordMapper.xml
@@ -21,4 +21,19 @@ <result column="dept_id" property="deptId" /> </resultMap> <select id="listPickedDetailByOrderId" resultType="com.ruoyi.production.bean.vo.ProductionOrderPickVo"> select popr.*, poro.operation_name as operationName, p.product_name as productName, pm.model as model, pm.unit as unit from production_order_pick_record popr left join production_operation_task pot on popr.production_operation_task_id = pot.id left join production_order_routing_operation poro on pot.technology_routing_operation_id = poro.id left join product_model pm on popr.product_model_id = pm.id left join product p on pm.product_id = p.id where popr.production_order_id = #{productionOrderId} order by popr.create_time desc, popr.id desc </select> </mapper> src/main/resources/mapper/stock/StockInventoryMapper.xml
@@ -439,4 +439,18 @@ AND sor.approval_status = 0 </select> <select id="listSelectableBatchNoByProductModelIds" resultType="com.ruoyi.stock.pojo.StockInventory"> select distinct si.product_model_id, si.batch_no from stock_inventory si where si.product_model_id in <foreach collection="productModelIds" item="productModelId" open="(" separator="," close=")"> #{productModelId} </foreach> and si.batch_no is not null and si.batch_no != '' and (si.qualitity - ifnull(si.locked_quantity, 0)) > 0 order by si.product_model_id, si.batch_no </select> </mapper>