src/main/java/com/ruoyi/production/bean/dto/BomImportDto.java
@@ -1,30 +1,38 @@ package com.ruoyi.production.bean.dto; import com.ruoyi.framework.aspectj.lang.annotation.Excel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.math.BigDecimal; @Data public class BomImportDto { @ApiModelProperty("ç¶äº§ååç§°") @Excel(name = "ç¶äº§ååç§°") private String parentName; @ApiModelProperty("ç¶äº§åè§æ ¼") @Excel(name = "ç¶äº§åè§æ ¼") private String parentSpec; @ApiModelProperty("å产ååç§°") @Excel(name = "å产ååç§°") private String childName; @ApiModelProperty("å产åè§æ ¼") @Excel(name = "å产åè§æ ¼") private String childSpec; @ApiModelProperty("åä½ç¨é") @Excel(name = "åä½ç¨é") private BigDecimal unitQty; @ApiModelProperty("å·¥åº") @Excel(name = "å·¥åº") private String process; @ApiModelProperty("夿³¨") @Excel(name = "夿³¨") private String remark; } src/main/java/com/ruoyi/production/bean/dto/ProductStructureDto.java
@@ -1,5 +1,6 @@ package com.ruoyi.production.bean.dto; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.math.BigDecimal; @@ -7,15 +8,26 @@ @Data public class ProductStructureDto { @ApiModelProperty("主é®ID") private Long id; @ApiModelProperty("BOM主é®ID") private Long bomId; @ApiModelProperty("ç¶çº§ID") private Long parentId; @ApiModelProperty("产ååå·ID") private Long productModelId; @ApiModelProperty("åä½ç¨é") private BigDecimal unitQuantity; @ApiModelProperty("åä½") private String unit; @ApiModelProperty("å·¥åºID") private Long processId; @ApiModelProperty("å·¥åºåç§°") private String processName; @ApiModelProperty("产ååç§°") private String productName; @ApiModelProperty("è§æ ¼åå·") private String model; @ApiModelProperty("åèç¹") private List<ProductStructureDto> children; } src/main/java/com/ruoyi/production/bean/dto/ProductionOperationTaskDto.java
@@ -2,7 +2,9 @@ import com.ruoyi.production.pojo.ProductionOperationTask; import lombok.Data; import lombok.EqualsAndHashCode; @EqualsAndHashCode(callSuper = true) @Data public class ProductionOperationTaskDto extends ProductionOperationTask { } src/main/java/com/ruoyi/production/bean/dto/ProductionOrderDto.java
@@ -2,7 +2,9 @@ import com.ruoyi.production.pojo.ProductionOrder; import lombok.Data; import lombok.EqualsAndHashCode; @EqualsAndHashCode(callSuper = true) @Data public class ProductionOrderDto extends ProductionOrder { } src/main/java/com/ruoyi/production/bean/dto/ProductionOrderRoutingOperationParamDto.java
@@ -2,7 +2,9 @@ import com.ruoyi.production.pojo.ProductionOrderRoutingOperationParam; import lombok.Data; import lombok.EqualsAndHashCode; @EqualsAndHashCode(callSuper = true) @Data public class ProductionOrderRoutingOperationParamDto extends ProductionOrderRoutingOperationParam { } src/main/java/com/ruoyi/production/bean/dto/ProductionOrderRoutingOperationParamSyncDto.java
@@ -1,11 +1,14 @@ package com.ruoyi.production.bean.dto; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @Data public class ProductionOrderRoutingOperationParamSyncDto { @ApiModelProperty("ç产订åå·¥åºåæ°ID") private Long productionOrderRoutingOperationId; @ApiModelProperty("æ¯å¦æ¿æ¢å·²æåæ°") private Boolean replaceExisting; } src/main/java/com/ruoyi/production/bean/dto/ProductionPlanSummaryDto.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,72 @@ package com.ruoyi.production.bean.dto; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.math.BigDecimal; /** * <br> * éå®çäº§éæ± - 产åç±»åæ±æ»DTO * </br> */ @Data @ApiModel("çäº§éæ±äº§åæ±æ»") public class ProductionPlanSummaryDto { /** * ç©æç¼ç */ @ApiModelProperty("ç©æç¼ç ") private String materialCode; /** * 产ååç§° */ @ApiModelProperty("产ååç§°") private String productName; /** * 产åè§æ ¼ */ @ApiModelProperty("产åè§æ ¼") private String model; /** * 产åé¿åº¦ */ @ApiModelProperty("产åé¿åº¦") private Integer length; /** * 产å宽度 */ @ApiModelProperty("产å宽度") private Integer width; /** * 产åé«åº¦ */ @ApiModelProperty("产åé«åº¦") private Integer height; /** * æ±æ»åæ° */ @ApiModelProperty("æ±æ»åæ°") private Integer quantity; /** * æ±æ»æ¹æ° */ @ApiModelProperty("æ±æ»æ¹æ°") private BigDecimal volume; /** * åºæ¬åä½ */ @ApiModelProperty("åºæ¬åä½") private String unit; } src/main/java/com/ruoyi/production/bean/dto/ProductionProductInputDto.java
@@ -1,5 +1,6 @@ package com.ruoyi.production.bean.dto; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.math.BigDecimal; @@ -7,21 +8,37 @@ @Data public class ProductionProductInputDto { @ApiModelProperty("主é®ID") private Long id; @ApiModelProperty("产å主表ID") private Long productMainId; @ApiModelProperty("ç产产å主表ID") private Long productionProductMainId; @ApiModelProperty("产ååå·ID") private Long productModelId; @ApiModelProperty("æ°é") private BigDecimal quantity; @ApiModelProperty("æå ¥æ°é") private BigDecimal inputQuantity; @ApiModelProperty("å建æ¶é´") private LocalDateTime createTime; @ApiModelProperty("æ´æ°æ¶é´") private LocalDateTime updateTime; @ApiModelProperty("ç§æ·ID") private Long tenantId; @ApiModelProperty("å建人") private Integer createUser; @ApiModelProperty("æ´æ°äºº") private Integer updateUser; @ApiModelProperty("é¨é¨ID") private Long deptId; @ApiModelProperty("产åç¼å·") private String productNo; @ApiModelProperty("è§æ ¼åå·") private String model; @ApiModelProperty("产ååç§°") private String productName; @ApiModelProperty("åä½") private String unit; } src/main/java/com/ruoyi/production/bean/dto/ProductionProductMainDto.java
@@ -1,5 +1,6 @@ package com.ruoyi.production.bean.dto; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.math.BigDecimal; @@ -8,32 +9,59 @@ @Data public class ProductionProductMainDto { @ApiModelProperty("主é®ID") private Long id; @ApiModelProperty("产åç¼å·") private String productNo; @ApiModelProperty("ç¨æ·ID") private Long userId; @ApiModelProperty("ç¨æ·åç§°") private String userName; @ApiModelProperty("产åå·¥èºè·¯çº¿æç»ID") private Long productProcessRouteItemId; @ApiModelProperty("å·¥åID") private Long workOrderId; @ApiModelProperty("ç产工åºä»»å¡ID") private Long productionOperationTaskId; @ApiModelProperty("ç¶æ") private Integer status; @ApiModelProperty("å建æ¶é´") private LocalDateTime createTime; @ApiModelProperty("æ´æ°æ¶é´") private LocalDateTime updateTime; @ApiModelProperty("ç§æ·ID") private Long tenantId; @ApiModelProperty("å建人") private Integer createUser; @ApiModelProperty("æ´æ°äºº") private Integer updateUser; @ApiModelProperty("é¨é¨ID") private Long deptId; @ApiModelProperty("å·¥åç¼å·") private String workOrderNo; @ApiModelProperty("å·¥åç¶æ") private String workOrderStatus; @ApiModelProperty("æµç§°") private String nickName; @ApiModelProperty("æ°é") private BigDecimal quantity; @ApiModelProperty("æ¥åºæ°é") private BigDecimal scrapQty; @ApiModelProperty("产ååç§°") private String productName; @ApiModelProperty("产ååå·åç§°") private String productModelName; @ApiModelProperty("åä½") private String unit; @ApiModelProperty("éå®ååç¼å·") private String salesContractNo; @ApiModelProperty("æäº§æ¥æ") private LocalDate schedulingDate; @ApiModelProperty("æäº§äººååç§°") private String schedulingUserName; @ApiModelProperty("客æ·åç§°") private String customerName; @ApiModelProperty("å·¥åº") private String process; } src/main/java/com/ruoyi/production/bean/dto/ProductionProductOutputDto.java
@@ -1,5 +1,6 @@ package com.ruoyi.production.bean.dto; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.math.BigDecimal; @@ -7,19 +8,33 @@ @Data public class ProductionProductOutputDto { @ApiModelProperty("主é®ID") private Long id; @ApiModelProperty("产å主表ID") private Long productMainId; @ApiModelProperty("ç产产å主表ID") private Long productionProductMainId; @ApiModelProperty("产ååå·ID") private Long productModelId; @ApiModelProperty("æ°é") private BigDecimal quantity; @ApiModelProperty("æ¥åºæ°é") private BigDecimal scrapQty; @ApiModelProperty("å建æ¶é´") private LocalDateTime createTime; @ApiModelProperty("æ´æ°æ¶é´") private LocalDateTime updateTime; @ApiModelProperty("ç§æ·ID") private Long tenantId; @ApiModelProperty("å建人") private Integer createUser; @ApiModelProperty("æ´æ°äºº") private Integer updateUser; @ApiModelProperty("é¨é¨ID") private Long deptId; @ApiModelProperty("产åç¼å·") private String productNo; @ApiModelProperty("è§æ ¼åå·") private String model; } src/main/java/com/ruoyi/production/bean/dto/SalesLedgerProductionAccountingDto.java
@@ -1,14 +1,20 @@ package com.ruoyi.production.bean.dto; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.time.LocalDate; @Data public class SalesLedgerProductionAccountingDto { @ApiModelProperty("ç¨æ·ID") private Long userId; @ApiModelProperty("ç¨æ·åç§°") private String userName; @ApiModelProperty("å·¥åº") private String process; @ApiModelProperty("å¼å§æ¥æ") private LocalDate startDate; @ApiModelProperty("ç»ææ¥æ") private LocalDate endDate; } src/main/java/com/ruoyi/production/bean/dto/UserAccountDto.java
@@ -1,11 +1,14 @@ package com.ruoyi.production.bean.dto; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.math.BigDecimal; @Data public class UserAccountDto { @ApiModelProperty("éé¢") private BigDecimal account = BigDecimal.ZERO; @ApiModelProperty("è´¦æ·ä½é¢") private BigDecimal accountBalance = BigDecimal.ZERO; } src/main/java/com/ruoyi/production/bean/dto/UserProductionAccountingDto.java
@@ -1,9 +1,12 @@ package com.ruoyi.production.bean.dto; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @Data public class UserProductionAccountingDto { @ApiModelProperty("ç¨æ·ID") private Long userId; @ApiModelProperty("æ¥æ") private String date; } src/main/java/com/ruoyi/production/controller/ProductionPlanController.java
@@ -42,14 +42,6 @@ return R.ok(productionPlanService.listPage(page, productionPlanDto)); } @GetMapping("/loadProdData") @ApiOperation("æåéå®ç产计å") @Log(title = "æåéå®ç产计å", businessType = BusinessType.INSERT) public R loadProdData() { productionPlanService.loadProdData(); return R.ok(); } @PostMapping("/combine") @Log(title = "åå¹¶ç产计å", businessType = BusinessType.INSERT) @ApiOperation("åå¹¶ç产计å") @@ -64,21 +56,21 @@ return R.ok(productionPlanService.combine(productionPlanDto)); } @PostMapping("") @PostMapping("addProductionPlan") @Log(title = "å建ç产计å", businessType = BusinessType.INSERT) @ApiOperation("å建ç产计å") public R add(@RequestBody ProductionPlanDto productionPlanDto) { return R.ok(productionPlanService.add(productionPlanDto)); } @PutMapping("") @PutMapping("updateProductionPlan") @Log(title = "æ´æ°ç产计å", businessType = BusinessType.UPDATE) @ApiOperation("æ´æ°ç产计å") public R update(@RequestBody ProductionPlanDto productionPlanDto) { return R.ok(productionPlanService.update(productionPlanDto)); } @DeleteMapping("") @DeleteMapping("deleteProductionPlan") @Log(title = "å é¤ç产计å", businessType = BusinessType.DELETE) @ApiOperation("å é¤ç产计å") public R delete(@RequestBody List<Long> ids) { src/main/java/com/ruoyi/production/pojo/ProductionAccount.java
@@ -3,8 +3,7 @@ import com.baomidou.mybatisplus.annotation.*; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Getter; import lombok.Setter; import lombok.Data; import java.io.Serializable; import java.math.BigDecimal; @@ -18,8 +17,7 @@ * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-04-21 03:55:52 */ @Getter @Setter @Data @TableName("production_account") @ApiModel(value = "ProductionAccount对象", description = "çäº§æ ¸ç®è¡¨") public class ProductionAccount implements Serializable { src/main/java/com/ruoyi/production/pojo/ProductionBomStructure.java
@@ -3,6 +3,7 @@ import com.baomidou.mybatisplus.annotation.*; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.Getter; import lombok.Setter; @@ -17,8 +18,7 @@ * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-04-21 03:55:52 */ @Getter @Setter @Data @TableName("production_bom_structure") @ApiModel(value = "ProductionBomStructure对象", description = "ç产订åBOM产åç»æ") public class ProductionBomStructure implements Serializable { src/main/java/com/ruoyi/production/pojo/ProductionOperationMainParam.java
@@ -3,6 +3,7 @@ import com.baomidou.mybatisplus.annotation.*; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.Getter; import lombok.Setter; @@ -17,8 +18,7 @@ * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-04-21 03:55:52 */ @Getter @Setter @Data @TableName("production_operation_main_param") @ApiModel(value = "ProductionOperationMainParam对象", description = "çäº§å·¥åæ¥å·¥åæ°è¡¨") public class ProductionOperationMainParam implements Serializable { src/main/java/com/ruoyi/production/pojo/ProductionOperationTask.java
@@ -3,8 +3,7 @@ import com.baomidou.mybatisplus.annotation.*; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Getter; import lombok.Setter; import lombok.Data; import java.io.Serializable; import java.math.BigDecimal; @@ -19,8 +18,7 @@ * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-04-21 03:55:52 */ @Getter @Setter @Data @TableName("production_operation_task") @ApiModel(value = "ProductionOperationTask对象", description = "ç产工å表") public class ProductionOperationTask implements Serializable { src/main/java/com/ruoyi/production/pojo/ProductionOrder.java
@@ -4,8 +4,7 @@ import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Getter; import lombok.Setter; import lombok.Data; import org.springframework.format.annotation.DateTimeFormat; import java.io.Serializable; @@ -21,8 +20,7 @@ * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-04-21 03:55:52 */ @Getter @Setter @Data @TableName("production_order") @ApiModel(value = "ProductionOrder对象", description = "ç产订å表") public class ProductionOrder implements Serializable { src/main/java/com/ruoyi/production/pojo/ProductionOrderBom.java
@@ -3,6 +3,7 @@ import com.baomidou.mybatisplus.annotation.*; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.Getter; import lombok.Setter; @@ -17,8 +18,7 @@ * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-04-21 03:55:52 */ @Getter @Setter @Data @TableName("production_order_bom") @ApiModel(value = "ProductionOrderBom对象", description = "ç产订åBOM") public class ProductionOrderBom implements Serializable { src/main/java/com/ruoyi/production/pojo/ProductionOrderPick.java
@@ -3,6 +3,7 @@ import com.baomidou.mybatisplus.annotation.*; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.Getter; import lombok.Setter; @@ -18,8 +19,7 @@ * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-04-21 03:55:52 */ @Getter @Setter @Data @TableName("production_order_pick") @ApiModel(value = "ProductionOrderPick对象", description = "订åé¢æçº¿è¾¹ä»") public class ProductionOrderPick implements Serializable { src/main/java/com/ruoyi/production/pojo/ProductionOrderPickRecord.java
@@ -3,6 +3,7 @@ import com.baomidou.mybatisplus.annotation.*; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.Getter; import lombok.Setter; @@ -18,8 +19,7 @@ * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-04-21 03:55:52 */ @Getter @Setter @Data @TableName("production_order_pick_record") @ApiModel(value = "ProductionOrderPickRecord对象", description = "线边ä»åºå ¥åºè®°å½") public class ProductionOrderPickRecord implements Serializable { src/main/java/com/ruoyi/production/pojo/ProductionOrderRouting.java
@@ -3,8 +3,7 @@ import com.baomidou.mybatisplus.annotation.*; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Getter; import lombok.Setter; import lombok.Data; import java.io.Serializable; import java.time.LocalDateTime; @@ -17,8 +16,7 @@ * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-04-21 03:55:52 */ @Getter @Setter @Data @TableName("production_order_routing") @ApiModel(value = "ProductionOrderRouting对象", description = "ç产订åå·¥èºè·¯çº¿è¡¨") public class ProductionOrderRouting implements Serializable { src/main/java/com/ruoyi/production/pojo/ProductionOrderRoutingOperation.java
@@ -3,6 +3,7 @@ import com.baomidou.mybatisplus.annotation.*; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.Getter; import lombok.Setter; @@ -17,8 +18,7 @@ * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-04-21 03:55:52 */ @Getter @Setter @Data @TableName("production_order_routing_operation") @ApiModel(value = "ProductionOrderRoutingOperation对象", description = "ç产订åå·¥èºè·¯çº¿å·¥åºè¡¨") public class ProductionOrderRoutingOperation implements Serializable { src/main/java/com/ruoyi/production/pojo/ProductionOrderRoutingOperationParam.java
@@ -3,6 +3,7 @@ import com.baomidou.mybatisplus.annotation.*; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.Getter; import lombok.Setter; @@ -17,8 +18,7 @@ * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-04-21 03:55:52 */ @Getter @Setter @Data @TableName("production_order_routing_operation_param") @ApiModel(value = "ProductionOrderRoutingOperationParam对象", description = "ç产订åå·¥èºè·¯çº¿å·¥åºåæ°è¡¨") public class ProductionOrderRoutingOperationParam implements Serializable { src/main/java/com/ruoyi/production/pojo/ProductionPlan.java
@@ -1,12 +1,12 @@ package com.ruoyi.production.pojo; import com.baomidou.mybatisplus.annotation.*; import com.ruoyi.framework.aspectj.lang.annotation.Excel; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Getter; import lombok.Setter; import java.io.Serial; import java.io.Serializable; import java.math.BigDecimal; import java.time.LocalDateTime; @@ -25,7 +25,6 @@ @ApiModel(value = "ProductionPlan对象", description = "ç产计å表") public class ProductionPlan implements Serializable { @Serial private static final long serialVersionUID = 1L; @ApiModelProperty("id") @@ -78,4 +77,10 @@ @ApiModelProperty("æ¿è¯ºæ¥æ") private LocalDateTime promisedDeliveryDate; @ApiModelProperty("ç³è¯·åç¼å·") private String applyNo; @ApiModelProperty("ç¶æ 0æªä¸å 1é¨åä¸å 2å·²ä¸å") private Integer status; } src/main/java/com/ruoyi/production/service/ProductionPlanService.java
@@ -24,16 +24,6 @@ IPage<ProductionPlanVo> listPage(Page<ProductionPlanDto> page, ProductionPlanDto productionPlanDto); /** * æå¨åæ¥ */ void loadProdData(); /** * 宿¶åæ¥ */ void syncProdDataJob(); /** * åå¹¶ç产计å */ boolean combine(ProductionPlanDto productionPlanDto); src/main/java/com/ruoyi/production/service/impl/ProductionPlanServiceImpl.java
@@ -1,285 +1,246 @@ package com.ruoyi.production.service.impl; import cn.hutool.core.bean.BeanUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; 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.ServiceException; import com.ruoyi.common.exception.base.BaseException; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.bean.BeanUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.production.bean.dto.ProductionPlanDto; import com.ruoyi.production.bean.dto.ProductionOrderDto; import com.ruoyi.production.bean.dto.ProductionPlanImportDto; import com.ruoyi.production.bean.vo.ProductionPlanVo; import com.ruoyi.production.enums.ProductOrderStatusEnum; import com.ruoyi.production.mapper.ProductionOrderMapper; import com.ruoyi.production.mapper.ProductionPlanMapper; import com.ruoyi.production.pojo.ProductionOrder; import com.ruoyi.production.pojo.ProductionPlan; import com.ruoyi.production.service.ProductionOrderService; import com.ruoyi.production.service.ProductionPlanService; import com.ruoyi.sales.mapper.SalesLedgerMapper; import com.ruoyi.sales.mapper.SalesLedgerProductMapper; import com.ruoyi.sales.pojo.SalesLedger; import com.ruoyi.sales.pojo.SalesLedgerProduct; import jakarta.servlet.http.HttpServletResponse; import lombok.AllArgsConstructor; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Comparator; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; @Service @RequiredArgsConstructor @Transactional(rollbackFor = Exception.class) public class ProductionPlanServiceImpl extends ServiceImpl<ProductionPlanMapper, ProductionPlan> implements ProductionPlanService { private final ProductionOrderService productionOrderService; private final SalesLedgerMapper salesLedgerMapper; private final SalesLedgerProductMapper salesLedgerProductMapper; private final ProductionPlanMapper productionPlanMapper; private final ProductionOrderMapper productionOrderMapper; @Override public IPage<ProductionPlanVo> listPage(Page<ProductionPlanDto> page, ProductionPlanDto productionPlanDto) { Page<ProductionPlan> entityPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal()); return this.page(entityPage, buildQueryWrapper(productionPlanDto)) .convert(item -> BeanUtil.copyProperties(item, ProductionPlanVo.class)); IPage<ProductionPlanVo> planVoIPage = productionPlanMapper.listPage(page, productionPlanDto) .convert(dto -> { ProductionPlanVo vo = new ProductionPlanVo(); BeanUtils.copyProperties(dto, vo); return vo; }); return planVoIPage; } /** * åå¹¶ç产计å */ @Override public void loadProdData() { // ç¨é宿ç»ä½ä¸ºæ¥æºåæ¥ç产计åï¼source åæ®µæ¿æ å¹çå»éä½ç¨ã List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList( Wrappers.<SalesLedgerProduct>lambdaQuery() .isNotNull(SalesLedgerProduct::getProductModelId) .gt(SalesLedgerProduct::getQuantity, BigDecimal.ZERO)); for (SalesLedgerProduct salesLedgerProduct : salesLedgerProducts) { String source = buildSalesSource(salesLedgerProduct.getId()); long exists = this.count(Wrappers.<ProductionPlan>lambdaQuery().eq(ProductionPlan::getSource, source)); if (exists > 0) { continue; } SalesLedger salesLedger = salesLedgerMapper.selectById(salesLedgerProduct.getSalesLedgerId()); ProductionPlan productionPlan = new ProductionPlan(); productionPlan.setMpsNo(generateNextPlanNo()); productionPlan.setProductModelId(salesLedgerProduct.getProductModelId()); productionPlan.setQtyRequired(defaultDecimal(salesLedgerProduct.getQuantity())); productionPlan.setRequiredDate(resolveDeliveryTime(salesLedger)); productionPlan.setPromisedDeliveryDate(resolveDeliveryTime(salesLedger)); productionPlan.setSource(source); productionPlan.setIssued(Boolean.FALSE); productionPlan.setState("1"); this.save(productionPlan); } } @Override public void syncProdDataJob() { loadProdData(); } @Override @Transactional(rollbackFor = Exception.class) public boolean combine(ProductionPlanDto productionPlanDto) { // å¤ä¸ªè®¡åå并转ååï¼ä»ç»ä¸èµ°ç产订åä¿åé»è¾ï¼é¿å 两å¥ä¸åæµç¨ä¸ä¸è´ã if (productionPlanDto == null || productionPlanDto.getIds() == null || productionPlanDto.getIds().isEmpty()) { throw new ServiceException("è¯·éæ©ç产计å"); } List<ProductionPlan> productionPlans = this.listByIds(productionPlanDto.getIds()); if (productionPlans.size() != productionPlanDto.getIds().size()) { throw new ServiceException("é¨åç产计åä¸åå¨"); } if (productionPlans.stream().anyMatch(item -> Boolean.TRUE.equals(item.getIssued()))) { throw new ServiceException("å·²ä¸åçç产计åä¸è½éå¤è½¬å"); } Long productModelId = productionPlans.stream() .map(ProductionPlan::getProductModelId) .distinct() .reduce((left, right) -> { throw new ServiceException("ä» æ¯æç¸å产åè§æ ¼çç产计åå并转å"); }) .orElseThrow(() -> new ServiceException("ç产计å缺å°äº§åè§æ ¼")); BigDecimal totalRequiredQuantity = productionPlans.stream() .map(ProductionPlan::getQtyRequired) .reduce(BigDecimal.ZERO, BigDecimal::add); BigDecimal assignedQuantity = defaultDecimal(productionPlanDto.getTotalAssignedQuantity()); if (assignedQuantity.compareTo(BigDecimal.ZERO) <= 0) { assignedQuantity = totalRequiredQuantity; } if (assignedQuantity.compareTo(totalRequiredQuantity) > 0) { throw new ServiceException("ä¸åæ°éä¸è½å¤§äºè®¡åæ»éæ±æ°é"); } ProductionOrder productionOrder = new ProductionOrder(); productionOrder.setProductModelId(productModelId); productionOrder.setQuantity(assignedQuantity); productionOrder.setProductionPlanIds(formatPlanIds(productionPlans)); productionOrder.setPlanCompleteTime(productionPlanDto.getPlanCompleteTime() != null ? productionPlanDto.getPlanCompleteTime() : resolveEarliestPlanDate(productionPlans)); productionOrder.setStrength(productionPlanDto.getStrength()); return productionOrderService.saveProductionOrder(productionOrder); } @Override public boolean add(ProductionPlanDto productionPlanDto) { // æå·¥å»ºè®¡åæ¶è¡¥é½é»è®¤ç¼å·åç¶æï¼ä¿è¯åç»å¯ä»¥ç´æ¥ä¸å转åã ProductionPlan productionPlan = BeanUtil.copyProperties(productionPlanDto, ProductionPlan.class); validateProductionPlan(productionPlan, false); if (productionPlan.getMpsNo() == null || productionPlan.getMpsNo().trim().isEmpty()) { productionPlan.setMpsNo(generateNextPlanNo()); } if (productionPlan.getIssued() == null) { productionPlan.setIssued(Boolean.FALSE); } if (productionPlan.getState() == null || productionPlan.getState().trim().isEmpty()) { productionPlan.setState("1"); } return this.save(productionPlan); } @Override public boolean update(ProductionPlanDto productionPlanDto) { // å·²ä¸å计åçæ ¸å¿å段ä¸è½ååæ´ï¼å¦åä¼åå·²çæè®¢åè±èã if (productionPlanDto == null || productionPlanDto.getId() == null) { throw new ServiceException("ç产计åIDä¸è½ä¸ºç©º"); } ProductionPlan current = this.getById(productionPlanDto.getId()); if (current == null) { throw new ServiceException("ç产计åä¸åå¨"); } if (Boolean.TRUE.equals(current.getIssued()) && hasPlanCoreChanges(current, productionPlanDto)) { throw new ServiceException("å·²ä¸åçç产计åä¸å 许修æ¹äº§åãæ°éå交æ"); } ProductionPlan update = BeanUtil.copyProperties(productionPlanDto, ProductionPlan.class); validateProductionPlan(update, true); return this.updateById(update); } @Override public boolean delete(List<Long> ids) { // å é¤åæ ¡éª issuedï¼é¿å æå·²è½¬å计åç´æ¥ä»æºå¤´å æã if (ids == null || ids.isEmpty()) { if (productionPlanDto.getIds() == null || productionPlanDto.getIds().isEmpty()) { return false; } List<ProductionPlan> productionPlans = this.listByIds(ids); if (productionPlans.stream().anyMatch(item -> Boolean.TRUE.equals(item.getIssued()))) { throw new ServiceException("å·²ä¸åçç产计åä¸å 许å é¤"); // æ¥è¯¢ä¸»ç产计å List<ProductionPlanDto> plans = productionPlanMapper.selectWithMaterialByIds(productionPlanDto.getIds()); if (plans == null || plans.isEmpty()) { throw new ServiceException("ä¸å失败,ç产计åä¸åå¨"); } return this.removeByIds(ids); // æ ¡éªæ¯å¦åå¨ä¸åç产ååç§° String firstProductName = plans.get(0).getProductName(); if (plans.stream().anyMatch(p -> p.getProductName() == null || !p.getProductName().equals(firstProductName))) { throw new BaseException("å并失败ï¼åå¨ä¸åç产ååç§°"); } // æ ¡éªæ¯å¦åå¨ä¸åç产åè§æ ¼ String firstProductSpec = plans.get(0).getModel(); if (plans.stream().anyMatch(p -> p.getModel() == null || !p.getModel().equals(firstProductSpec))) { throw new BaseException("å并失败ï¼åå¨ä¸åç产åè§æ ¼"); } // å建ç产订å ProductionOrder productionOrder = new ProductionOrder(); productionOrder.setQuantity(productionPlanDto.getTotalAssignedQuantity()); productionOrder.setPlanCompleteTime(productionPlanDto.getPlanCompleteTime()); productionOrder.setStatus(ProductOrderStatusEnum.WAIT.getCode()); productionOrder.setStrength(productionPlanDto.getStrength()); return true; } @Override public void importProdData(MultipartFile file) { @Transactional(rollbackFor = Exception.class) public boolean add(ProductionPlanDto dto) { if (StringUtils.isBlank(dto.getApplyNo())) { throw new ServiceException("æ°å¢å¤±è´¥ï¼ç³è¯·åç¼å·ä¸è½ä¸ºç©º"); } checkApplyNoUnique(dto.getApplyNo(), null); dto.setStatus(0); return productionPlanMapper.insert(dto) > 0; } @Override @Transactional(rollbackFor = Exception.class) public boolean update(ProductionPlanDto dto) { if (dto == null || dto.getId() == null) { throw new ServiceException("ç¼è¾å¤±è´¥,æ°æ®ä¸è½ä¸ºç©º"); } ProductionPlan old = getById(dto.getId()); if (old == null) { throw new ServiceException("ç¼è¾å¤±è´¥,主ç产计åä¸åå¨"); } // ç¶ææ ¡éª if (old.getStatus() != 0) { throw new BaseException("ç¼è¾å¤±è´¥,该ç产计åå·²ä¸åæé¨åä¸åç¶æ,ç¦æ¢ç¼è¾"); } // applyNoåæ´ææ ¡éª if (StringUtils.isNotBlank(dto.getApplyNo()) && !dto.getApplyNo().equals(old.getApplyNo())) { checkApplyNoUnique(dto.getApplyNo(), dto.getId()); } return productionPlanMapper.updateById(dto) > 0; } private void checkApplyNoUnique(String applyNo, Long excludeId) { LambdaQueryWrapper<ProductionPlan> wrapper = Wrappers.lambdaQuery(); wrapper.eq(ProductionPlan::getApplyNo, applyNo); if (excludeId != null) { wrapper.ne(ProductionPlan::getId, excludeId); } if (productionPlanMapper.selectCount(wrapper) > 0) { throw new ServiceException("ç³è¯·åç¼å· " + applyNo + " å·²åå¨"); } } @Override @Transactional(rollbackFor = Exception.class) public boolean delete(List<Long> ids) { // 妿åå¨å·²ä¸åç计åï¼åä¸è½å é¤ if (productionPlanMapper.selectList(Wrappers.<ProductionPlan>lambdaQuery().in(ProductionPlan::getId, ids)).stream().anyMatch(p -> p.getStatus() == 1 || p.getStatus() == 2)) { throw new BaseException("å é¤å¤±è´¥ï¼åå¨å·²ä¸åæé¨åä¸åç计å"); } // 妿æå ³è订åï¼åä¸è½å é¤ if (productionOrderMapper.selectList(Wrappers.<ProductionOrder>lambdaQuery().in(ProductionOrder::getProductionPlanIds, ids)).stream().anyMatch(p -> p.getId() != null)) { throw new BaseException("å é¤å¤±è´¥ï¼åå¨å ³è订å"); } return productionPlanMapper.deleteBatchIds(ids) > 0; } @Override @Transactional(rollbackFor = Exception.class) public void importProdData(MultipartFile file) { if (file == null || file.isEmpty()) { throw new ServiceException("å¯¼å ¥æ°æ®ä¸è½ä¸ºç©º"); } ExcelUtil<ProductionPlanImportDto> excelUtil = new ExcelUtil<>(ProductionPlanImportDto.class); List<ProductionPlanImportDto> list; try { list = excelUtil.importExcel(file.getInputStream()); } catch (Exception e) { log.error("çäº§éæ±Excelå¯¼å ¥å¤±è´¥", e); throw new ServiceException("Excelè§£æå¤±è´¥"); } if (list == null || list.isEmpty()) { throw new ServiceException("Excelæ²¡ææ°æ®"); } Set<String> applyNos = new HashSet<>(); Set<String> materialCodes = new HashSet<>(); for (int i = 0; i < list.size(); i++) { ProductionPlanImportDto dto = list.get(i); String applyNo = dto.getApplyNo(); String materialCode = dto.getMaterialCode(); if (StringUtils.isEmpty(applyNo)) { throw new ServiceException("å¯¼å ¥å¤±è´¥ï¼ç¬¬ " + (i + 2) + " è¡ç³è¯·åç¼å·ä¸è½ä¸ºç©º"); } if (!applyNos.add(applyNo)) { throw new ServiceException("å¯¼å ¥å¤±è´¥ï¼Excel ä¸åå¨éå¤çç³è¯·åç¼å·: " + applyNo); } if (StringUtils.isEmpty(materialCode)) { throw new ServiceException("å¯¼å ¥å¤±è´¥ï¼ç¬¬ " + (i + 2) + " è¡ç©æç¼ç ä¸è½ä¸ºç©º"); } String strength = dto.getStrength(); if (StringUtils.isNotEmpty(strength)) { if (!"A3.5".equals(strength) && !"A5.0".equals(strength)) { throw new ServiceException("å¯¼å ¥å¤±è´¥ï¼ç¬¬ " + (i + 2) + " è¡å¼ºåº¦åªè½æ¯ A3.5 æ A5.0"); } } materialCodes.add(materialCode); } // ç³è¯·åç¼å·æ¯å¦å·²åå¨ Long existApplyNoCount = baseMapper.selectCount(Wrappers.<ProductionPlan>lambdaQuery() .in(ProductionPlan::getApplyNo, applyNos)); if (existApplyNoCount > 0) { List<String> existApplyNos = baseMapper.selectList(Wrappers.<ProductionPlan>lambdaQuery() .in(ProductionPlan::getApplyNo, applyNos)) .stream().map(ProductionPlan::getApplyNo).collect(Collectors.toList()); throw new ServiceException("å¯¼å ¥å¤±è´¥ï¼ç³è¯·åç¼å·å·²åå¨: " + String.join(", ", existApplyNos)); } LocalDateTime now = LocalDateTime.now(); List<ProductionPlan> entityList = list.stream().map(dto -> { ProductionPlan entity = new ProductionPlan(); BeanUtils.copyProperties(dto, entity); entity.setStatus(0); entity.setCreateTime(now); entity.setUpdateTime(now); return entity; }).collect(Collectors.toList()); this.saveBatch(entityList); } @Override public void exportProdData(HttpServletResponse response, List<Long> ids) { } private LambdaQueryWrapper<ProductionPlan> buildQueryWrapper(ProductionPlanDto dto) { ProductionPlan query = dto == null ? new ProductionPlan() : dto; return Wrappers.<ProductionPlan>lambdaQuery() .eq(query.getId() != null, ProductionPlan::getId, query.getId()) .eq(query.getProductModelId() != null, ProductionPlan::getProductModelId, query.getProductModelId()) .eq(query.getIssued() != null, ProductionPlan::getIssued, query.getIssued()) .eq(query.getState() != null && !query.getState().trim().isEmpty(), ProductionPlan::getState, query.getState()) .eq(query.getIsAudit() != null && !query.getIsAudit().trim().isEmpty(), ProductionPlan::getIsAudit, query.getIsAudit()) .like(query.getMpsNo() != null && !query.getMpsNo().trim().isEmpty(), ProductionPlan::getMpsNo, query.getMpsNo()) .like(query.getSource() != null && !query.getSource().trim().isEmpty(), ProductionPlan::getSource, query.getSource()) .orderByDesc(ProductionPlan::getId); } private void validateProductionPlan(ProductionPlan productionPlan, boolean update) { if (productionPlan == null) { throw new ServiceException("ç产计åä¸è½ä¸ºç©º"); List<ProductionPlan> list; if (ids != null && !ids.isEmpty()) { list = baseMapper.selectBatchIds(ids); } else { list = baseMapper.selectList(null); } if (update && productionPlan.getId() == null) { throw new ServiceException("ç产计åIDä¸è½ä¸ºç©º"); List<ProductionPlanImportDto> exportList = new ArrayList<>(); for (ProductionPlan entity : list) { ProductionPlanImportDto dto = new ProductionPlanImportDto(); BeanUtils.copyProperties(entity, dto); exportList.add(dto); } if (productionPlan.getProductModelId() == null) { throw new ServiceException("productModelIdä¸è½ä¸ºç©º"); } if (defaultDecimal(productionPlan.getQtyRequired()).compareTo(BigDecimal.ZERO) <= 0) { throw new ServiceException("qtyRequiredå¿ é¡»å¤§äº0"); } } private boolean hasPlanCoreChanges(ProductionPlan current, ProductionPlanDto update) { // è¿äºå段ä¼ç´æ¥å½±å转åç»æï¼ç¨æ¥å¤ææ¯å¦å±äºæ ¸å¿åæ´ã return !Objects.equals(current.getProductModelId(), update.getProductModelId()) || defaultDecimal(current.getQtyRequired()).compareTo(defaultDecimal(update.getQtyRequired())) != 0 || !Objects.equals(toLocalDate(current.getPromisedDeliveryDate()), update.getPlanCompleteTime()) || !Objects.equals(toLocalDate(current.getRequiredDate()), toLocalDate(update.getRequiredDate())); } private String generateNextPlanNo() { // ç¼å·ææ¥æéå¢çæï¼æ¹ä¾¿å订åãå·¥åç»ä¸è¿½è¸ªã String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); String prefix = "MPS" + datePrefix; ProductionPlan latestPlan = this.getOne(Wrappers.<ProductionPlan>lambdaQuery() .likeRight(ProductionPlan::getMpsNo, prefix) .orderByDesc(ProductionPlan::getMpsNo) .last("limit 1")); int sequence = 1; if (latestPlan != null && latestPlan.getMpsNo() != null && latestPlan.getMpsNo().startsWith(prefix)) { try { sequence = Integer.parseInt(latestPlan.getMpsNo().substring(prefix.length())) + 1; } catch (NumberFormatException ignored) { sequence = 1; } } return prefix + String.format("%04d", sequence); } private String formatPlanIds(List<ProductionPlan> productionPlans) { return productionPlans.stream() .map(ProductionPlan::getId) .distinct() .map(String::valueOf) .collect(Collectors.joining(",", "[", "]")); } private LocalDate resolveEarliestPlanDate(List<ProductionPlan> productionPlans) { return productionPlans.stream() .map(this::resolvePlanDate) .filter(Objects::nonNull) .min(Comparator.naturalOrder()) .orElse(null); } private LocalDate resolvePlanDate(ProductionPlan productionPlan) { if (productionPlan.getPromisedDeliveryDate() != null) { return productionPlan.getPromisedDeliveryDate().toLocalDate(); } if (productionPlan.getRequiredDate() != null) { return productionPlan.getRequiredDate().toLocalDate(); } return null; } private LocalDateTime resolveDeliveryTime(SalesLedger salesLedger) { if (salesLedger == null || salesLedger.getDeliveryDate() == null) { return null; } return salesLedger.getDeliveryDate().atStartOfDay(); } private String buildSalesSource(Long salesLedgerProductId) { return "salesLedgerProduct:" + salesLedgerProductId; } private LocalDate toLocalDate(LocalDateTime value) { return value == null ? null : value.toLocalDate(); } private BigDecimal defaultDecimal(BigDecimal value) { return value == null ? BigDecimal.ZERO : value; ExcelUtil<ProductionPlanImportDto> util = new ExcelUtil<>(ProductionPlanImportDto.class); util.exportExcel(response, exportList, "éå®çäº§éæ±æ°æ®"); } } src/main/java/com/ruoyi/purchase/dto/PurchaseReturnOrderDto.java
@@ -1,11 +1,12 @@ package com.ruoyi.purchase.dto; import com.ruoyi.purchase.pojo.PurchaseReturnOrderProducts; import com.ruoyi.purchase.pojo.PurchaseReturnOrders; import lombok.Data; import lombok.EqualsAndHashCode; import java.util.List; @EqualsAndHashCode(callSuper = true) @Data public class PurchaseReturnOrderDto extends PurchaseReturnOrders { // æ¯å¦ä½¿ç¨ç³»ç»åå·