From 392e74134ab72fbadb4ff62f97e74620805a8398 Mon Sep 17 00:00:00 2001 From: c Date: Tue, 17 Mar 2026 15:15:06 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AC=AC=E4=B8=80=E7=89=88=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=90=8E=E7=9A=84=E5=AD=98=E6=A1=A3=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/exception/BusinessException.java | 12 +++ .../handler/GlobalExceptionHandler.java | 3 +- .../FinishedProductReceiptController.java | 8 ++ .../FinishedProductShipmentController.java | 8 ++ .../controller/ProductionIssueController.java | 6 ++ .../ProductionReturnController.java | 6 ++ .../dto/FinishedProductReceiptDto.java | 3 +- .../dto/FinishedProductShipmentDto.java | 4 +- .../controller/dto/ProductionIssueDto.java | 3 +- .../controller/dto/ProductionReturnDto.java | 3 +- .../FinishedProductShipmentServiceImpl.java | 6 +- .../impl/ProductionIssueServiceImpl.java | 1 + .../impl/ProductionPlanServiceImpl.java | 1 + .../controller/PurchasePlanController.java | 20 +++-- .../controller/dto/PurchasePlanDto.java | 3 +- .../sale/controller/DeviceController.java | 90 +++++++++++++++++++ .../sale/controller/SaleOrderController.java | 8 +- .../sale/controller/dto/SaleOrderDto.java | 3 +- .../module/sale/service/DeviceService.java | 3 + .../sale/service/impl/DeviceServiceImpl.java | 5 ++ .../warehouse/controller/StockController.java | 12 +++ .../StockTransferOrderController.java | 2 +- .../controller/dto/StockTransferOrderDto.java | 4 +- .../StockTransferOrderConverter.java | 3 + .../warehouse/mapper/WarehouseItemMapper.java | 3 + .../warehouse/service/StockService.java | 3 + .../impl/InventoryCountServiceImpl.java | 1 + .../service/impl/StockServiceImpl.java | 35 ++++++++ .../impl/StockTransferOrderServiceImpl.java | 26 +++--- .../impl/WarehouseReceiptServiceImpl.java | 3 + src/main/resources/i18n/messages.properties | 3 + .../resources/i18n/messages_zh_CN.properties | 3 + .../mapper/warehouse/WarehouseItemMapper.xml | 15 ++++ 33 files changed, 278 insertions(+), 31 deletions(-) diff --git a/src/main/java/com/niuan/erp/common/exception/BusinessException.java b/src/main/java/com/niuan/erp/common/exception/BusinessException.java index 0343c34..470c5a0 100644 --- a/src/main/java/com/niuan/erp/common/exception/BusinessException.java +++ b/src/main/java/com/niuan/erp/common/exception/BusinessException.java @@ -1,7 +1,19 @@ package com.niuan.erp.common.exception; public class BusinessException extends RuntimeException { + private final String[] args; + public BusinessException(String message) { super(message); + this.args = null; + } + + public BusinessException(String message, String... args) { + super(message); + this.args = args; + } + + public String[] getArgs() { + return args; } } diff --git a/src/main/java/com/niuan/erp/common/handler/GlobalExceptionHandler.java b/src/main/java/com/niuan/erp/common/handler/GlobalExceptionHandler.java index 61eb37c..4dda8f8 100644 --- a/src/main/java/com/niuan/erp/common/handler/GlobalExceptionHandler.java +++ b/src/main/java/com/niuan/erp/common/handler/GlobalExceptionHandler.java @@ -67,8 +67,9 @@ public class GlobalExceptionHandler { */ @ExceptionHandler(BusinessException.class) public ResponseEntity handleBusinessException(BusinessException e, Locale locale) { + String message = messageSource.getMessage(e.getMessage(), e.getArgs(), locale); return ResponseEntity.ok().body( - BaseResult.error(3, messageSource.getMessage(e.getMessage(), null, locale))); + BaseResult.error(3, message)); } /** diff --git a/src/main/java/com/niuan/erp/module/production/controller/FinishedProductReceiptController.java b/src/main/java/com/niuan/erp/module/production/controller/FinishedProductReceiptController.java index 370ae59..fb58b72 100644 --- a/src/main/java/com/niuan/erp/module/production/controller/FinishedProductReceiptController.java +++ b/src/main/java/com/niuan/erp/module/production/controller/FinishedProductReceiptController.java @@ -43,6 +43,14 @@ public class FinishedProductReceiptController { public BaseResult> getFinishedProductReceiptPage(@Validated BasePageReqParams pageParams, @Validated(Get.class) FinishedProductReceiptDto searchParams) { var wrapper = new LambdaQueryWrapper(); + if (searchParams != null && searchParams.searchCode() != null) { + String searchCode = searchParams.searchCode(); + wrapper.and(w -> w.like(Document::getFormCode, searchCode) + .or() + .like(Document::getFormName, searchCode) + .or() + .like(Document::getFormMark, searchCode)); + } return BaseResult.successWithData(finishedProductReceiptService.getFinishedProductReceiptPage(pageParams, wrapper)); } diff --git a/src/main/java/com/niuan/erp/module/production/controller/FinishedProductShipmentController.java b/src/main/java/com/niuan/erp/module/production/controller/FinishedProductShipmentController.java index 35913f6..cbf4934 100644 --- a/src/main/java/com/niuan/erp/module/production/controller/FinishedProductShipmentController.java +++ b/src/main/java/com/niuan/erp/module/production/controller/FinishedProductShipmentController.java @@ -38,6 +38,14 @@ public class FinishedProductShipmentController { public BaseResult> getFinishedProductShipmentPage(@Validated BasePageReqParams pageParams, @Validated(Get.class) FinishedProductShipmentDto searchParams) { var wrapper = new LambdaQueryWrapper(); + if (searchParams != null && searchParams.searchCode() != null) { + String searchCode = searchParams.searchCode(); + wrapper.and(w -> w.like(Document::getFormCode, searchCode) + .or() + .like(Document::getFormName, searchCode) + .or() + .like(Document::getFormMark, searchCode)); + } return BaseResult.successWithData(finishedProductShipmentService.getFinishedProductShipmentPage(pageParams, wrapper)); } diff --git a/src/main/java/com/niuan/erp/module/production/controller/ProductionIssueController.java b/src/main/java/com/niuan/erp/module/production/controller/ProductionIssueController.java index 2524a9e..c291438 100644 --- a/src/main/java/com/niuan/erp/module/production/controller/ProductionIssueController.java +++ b/src/main/java/com/niuan/erp/module/production/controller/ProductionIssueController.java @@ -43,6 +43,12 @@ public class ProductionIssueController { public BaseResult> getProductionIssuePage(@Validated BasePageReqParams pageParams, @Validated(Get.class) ProductionIssueDto searchParams) { var wrapper = new LambdaQueryWrapper(); + if (searchParams != null && searchParams.searchCode() != null) { + String searchCode = searchParams.searchCode(); + wrapper.and(w -> w.like(Document::getFormCode, searchCode) + .or() + .like(Document::getFormMark, searchCode)); + } return BaseResult.successWithData(productionIssueService.getProductionIssuePage(pageParams, wrapper)); } diff --git a/src/main/java/com/niuan/erp/module/production/controller/ProductionReturnController.java b/src/main/java/com/niuan/erp/module/production/controller/ProductionReturnController.java index 9dbd579..f8f7e89 100644 --- a/src/main/java/com/niuan/erp/module/production/controller/ProductionReturnController.java +++ b/src/main/java/com/niuan/erp/module/production/controller/ProductionReturnController.java @@ -39,6 +39,12 @@ public class ProductionReturnController { @Validated(Get.class) ProductionReturnDto searchParams) { var wrapper = new LambdaQueryWrapper(); wrapper.eq(Document::getFormType, DocumentType.PRODUCTION_RETURN.getCode()); + if (searchParams != null && searchParams.searchCode() != null) { + String searchCode = searchParams.searchCode(); + wrapper.and(w -> w.like(Document::getFormCode, searchCode) + .or() + .like(Document::getFormMark, searchCode)); + } return BaseResult.successWithData(productionReturnService.getProductionReturnPage(pageParams, wrapper)); } diff --git a/src/main/java/com/niuan/erp/module/production/controller/dto/FinishedProductReceiptDto.java b/src/main/java/com/niuan/erp/module/production/controller/dto/FinishedProductReceiptDto.java index 677d693..75592ae 100644 --- a/src/main/java/com/niuan/erp/module/production/controller/dto/FinishedProductReceiptDto.java +++ b/src/main/java/com/niuan/erp/module/production/controller/dto/FinishedProductReceiptDto.java @@ -26,4 +26,5 @@ public record FinishedProductReceiptDto( Integer outStoreNo, String outStoreName, Integer groupId, - Integer customerId) {} \ No newline at end of file + Integer customerId, + String searchCode) {} \ No newline at end of file diff --git a/src/main/java/com/niuan/erp/module/production/controller/dto/FinishedProductShipmentDto.java b/src/main/java/com/niuan/erp/module/production/controller/dto/FinishedProductShipmentDto.java index 0f09428..cfc7148 100644 --- a/src/main/java/com/niuan/erp/module/production/controller/dto/FinishedProductShipmentDto.java +++ b/src/main/java/com/niuan/erp/module/production/controller/dto/FinishedProductShipmentDto.java @@ -50,4 +50,6 @@ public record FinishedProductShipmentDto( @Schema(description = "客户ID") Integer customerId, @Schema(description = "出库明细列表") - java.util.List shipmentItems) {} + java.util.List shipmentItems, + @Schema(description = "搜索关键词") + String searchCode) {} diff --git a/src/main/java/com/niuan/erp/module/production/controller/dto/ProductionIssueDto.java b/src/main/java/com/niuan/erp/module/production/controller/dto/ProductionIssueDto.java index 1ca6d47..6b13346 100644 --- a/src/main/java/com/niuan/erp/module/production/controller/dto/ProductionIssueDto.java +++ b/src/main/java/com/niuan/erp/module/production/controller/dto/ProductionIssueDto.java @@ -26,4 +26,5 @@ public record ProductionIssueDto( Integer outStoreNo, String outStoreName, Integer groupId, - Integer customerId) {} \ No newline at end of file + Integer customerId, + String searchCode) {} \ No newline at end of file diff --git a/src/main/java/com/niuan/erp/module/production/controller/dto/ProductionReturnDto.java b/src/main/java/com/niuan/erp/module/production/controller/dto/ProductionReturnDto.java index f9dea55..eebc9be 100644 --- a/src/main/java/com/niuan/erp/module/production/controller/dto/ProductionReturnDto.java +++ b/src/main/java/com/niuan/erp/module/production/controller/dto/ProductionReturnDto.java @@ -11,4 +11,5 @@ public record ProductionReturnDto( String formMark, String partNumber, String productSpecs, - Integer returnQty) {} \ No newline at end of file + Integer returnQty, + String searchCode) {} \ No newline at end of file diff --git a/src/main/java/com/niuan/erp/module/production/service/impl/FinishedProductShipmentServiceImpl.java b/src/main/java/com/niuan/erp/module/production/service/impl/FinishedProductShipmentServiceImpl.java index 3846f76..6f58145 100644 --- a/src/main/java/com/niuan/erp/module/production/service/impl/FinishedProductShipmentServiceImpl.java +++ b/src/main/java/com/niuan/erp/module/production/service/impl/FinishedProductShipmentServiceImpl.java @@ -51,9 +51,9 @@ public class FinishedProductShipmentServiceImpl extends ServiceImpl getFinishedProductShipmentPage(BasePageReqParams pageParams, LambdaQueryWrapper wrapper) { - wrapper.eq(Document::getFormType, DocumentType.FINISHED_PRODUCT_SHIPMENT) + wrapper.and(w -> w.eq(Document::getFormType, DocumentType.FINISHED_PRODUCT_SHIPMENT) .or() - .eq(Document::getFormType, DocumentType.WAREHOUSE_ISSUE); + .eq(Document::getFormType, DocumentType.WAREHOUSE_ISSUE)); // 按创建时间倒序排列 wrapper.orderByDesc(Document::getCreateDate); IPage result = this.baseMapper.selectPage(new Page<>(pageParams.page(), pageParams.pageSize()), wrapper); @@ -238,6 +238,7 @@ public class FinishedProductShipmentServiceImpl extends ServiceImpl getProductionIssuePage(BasePageReqParams pageParams, LambdaQueryWrapper wrapper) { wrapper.eq(Document::getFormType, DocumentType.PRODUCTION_ISSUE) + .eq(Document::getCustomerId, SecurityUtils.getCustomerId()) .eq(Document::getGroupId, SecurityUtils.getLoginUser().getUser().getProjectId()) .orderByDesc(Document::getCreateDate); IPage result = this.baseMapper.selectPage(new Page<>(pageParams.page(), pageParams.pageSize()), wrapper); diff --git a/src/main/java/com/niuan/erp/module/production/service/impl/ProductionPlanServiceImpl.java b/src/main/java/com/niuan/erp/module/production/service/impl/ProductionPlanServiceImpl.java index 2b663e4..00d8649 100644 --- a/src/main/java/com/niuan/erp/module/production/service/impl/ProductionPlanServiceImpl.java +++ b/src/main/java/com/niuan/erp/module/production/service/impl/ProductionPlanServiceImpl.java @@ -44,6 +44,7 @@ public class ProductionPlanServiceImpl extends ServiceImpl getProductionPlanPage(BasePageReqParams pageParams, LambdaQueryWrapper wrapper) { + wrapper.eq(ProductionPlan::getCustomerId, SecurityUtils.getCustomerId()); IPage result = this.baseMapper.selectPage(new Page<>(pageParams.page(), pageParams.pageSize()), wrapper); return result.convert(productionPlanConverter::toDto); } diff --git a/src/main/java/com/niuan/erp/module/purchase/controller/PurchasePlanController.java b/src/main/java/com/niuan/erp/module/purchase/controller/PurchasePlanController.java index ac0af84..78fa100 100644 --- a/src/main/java/com/niuan/erp/module/purchase/controller/PurchasePlanController.java +++ b/src/main/java/com/niuan/erp/module/purchase/controller/PurchasePlanController.java @@ -40,12 +40,15 @@ public class PurchasePlanController { public BaseResult> getPurchasePlanPage(@Validated BasePageReqParams pageParams, @Validated(Get.class) PurchasePlanDto searchParams) { var wrapper = new LambdaQueryWrapper(); - if (searchParams != null) { - if (StringUtils.hasText(searchParams.vendorName())) { - wrapper.like(PurchasePlan::getVendorName, searchParams.vendorName()); - } + if (searchParams != null) { + if (StringUtils.hasText(searchParams.searchCode())) { + wrapper.and(w -> w.like(PurchasePlan::getPlanNo, searchParams.searchCode()) + .or() + .like(PurchasePlan::getPlanName, searchParams.searchCode()) + .or() + .like(PurchasePlan::getRemask, searchParams.searchCode())); } - // 按创建时间倒序排序 + } wrapper.orderByDesc(PurchasePlan::getCreateDate); return BaseResult.successWithData(purchasePlanService.getPurchasePlanPage(pageParams, wrapper)); } @@ -85,6 +88,13 @@ public class PurchasePlanController { return BaseResult.successWithData(purchasePlanService.getPurchasePlanItemsWithVendorSuggestions(planId)); } + @Operation(summary = "获取采购计划明细", operationId = "getPurchasePlanItems") + @GetMapping("/getPurchasePlanItems") + @PreAuthorize("hasAuthority('purchase_plan:index')") + public BaseResult> getPurchasePlanItems(@RequestParam Long planId) { + return BaseResult.successWithData(purchasePlanService.getPurchasePlanItems(planId)); + } + @ApiLog(type = OperationType.UPDATE, remark = "生成采购订单") @Operation(summary = "生成采购订单", operationId = "generatePurchaseOrder") @PostMapping("/generatePurchaseOrder") diff --git a/src/main/java/com/niuan/erp/module/purchase/controller/dto/PurchasePlanDto.java b/src/main/java/com/niuan/erp/module/purchase/controller/dto/PurchasePlanDto.java index 6f38df4..fa443cd 100644 --- a/src/main/java/com/niuan/erp/module/purchase/controller/dto/PurchasePlanDto.java +++ b/src/main/java/com/niuan/erp/module/purchase/controller/dto/PurchasePlanDto.java @@ -18,4 +18,5 @@ public record PurchasePlanDto( Integer planStatus, String storeName, String remask, - String planName) {} \ No newline at end of file + String planName, + String searchCode) {} \ No newline at end of file diff --git a/src/main/java/com/niuan/erp/module/sale/controller/DeviceController.java b/src/main/java/com/niuan/erp/module/sale/controller/DeviceController.java index dda4b1c..9b43a18 100644 --- a/src/main/java/com/niuan/erp/module/sale/controller/DeviceController.java +++ b/src/main/java/com/niuan/erp/module/sale/controller/DeviceController.java @@ -1,5 +1,6 @@ package com.niuan.erp.module.sale.controller; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.niuan.erp.common.annotation.ModuleLog; import com.niuan.erp.common.base.BasePageReqParams; @@ -7,16 +8,28 @@ import com.niuan.erp.common.base.BaseResult; import com.niuan.erp.common.base.CommonValidateGroup.Get; import com.niuan.erp.module.sale.controller.dto.DeviceQueryDto; import com.niuan.erp.module.sale.controller.dto.DeviceResultDto; +import com.niuan.erp.module.sale.controller.dto.DeviceValidateRequest; +import com.niuan.erp.module.sale.controller.dto.DeviceValidateResponse; +import com.niuan.erp.module.sale.entity.Device; import com.niuan.erp.module.sale.service.DeviceService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.util.StringUtils; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + @Tag(name = "SN溯源") @ModuleLog("SN溯源管理") @RestController @@ -33,4 +46,81 @@ public class DeviceController { @Validated(Get.class) DeviceQueryDto searchParams) { return BaseResult.successWithData(deviceService.getDeviceSnPage(pageParams, searchParams)); } + + @Operation(summary = "验证设备SN码、MAC地址、序列号是否重复", operationId = "validateDevices") + @PostMapping("/validateDevices") + @PreAuthorize("hasAnyAuthority('finished_product_receipt:add', 'finished_product_receipt:update')") + public BaseResult validateDevices(@Validated @RequestBody DeviceValidateRequest request) { + if (request.devices() == null || request.devices().isEmpty()) { + return BaseResult.successWithData(new DeviceValidateResponse(true, List.of(), List.of(), List.of(), null)); + } + + List productSns = request.devices().stream() + .map(item -> item.productSn()) + .filter(StringUtils::hasText) + .toList(); + List macs = request.devices().stream() + .map(item -> item.mac()) + .filter(StringUtils::hasText) + .toList(); + List serialNums = request.devices().stream() + .map(item -> item.serialNum()) + .filter(StringUtils::hasText) + .toList(); + + Set duplicateProductSns = new HashSet<>(); + Set duplicateMacs = new HashSet<>(); + Set duplicateSerialNums = new HashSet<>(); + + if (!productSns.isEmpty()) { + Set existingProductSns = deviceService.getDeviceMapper().selectList( + new LambdaQueryWrapper().in(Device::getProductSn, productSns)) + .stream() + .map(Device::getProductSn) + .collect(Collectors.toSet()); + duplicateProductSns.addAll(existingProductSns); + } + + if (!macs.isEmpty()) { + Set existingMacs = deviceService.getDeviceMapper().selectList( + new LambdaQueryWrapper().in(Device::getMac, macs)) + .stream() + .map(Device::getMac) + .collect(Collectors.toSet()); + duplicateMacs.addAll(existingMacs); + } + + if (!serialNums.isEmpty()) { + Set existingSerialNums = deviceService.getDeviceMapper().selectList( + new LambdaQueryWrapper().in(Device::getSerialNum, serialNums)) + .stream() + .map(Device::getSerialNum) + .collect(Collectors.toSet()); + duplicateSerialNums.addAll(existingSerialNums); + } + + boolean valid = duplicateProductSns.isEmpty() && duplicateMacs.isEmpty() && duplicateSerialNums.isEmpty(); + String message = null; + if (!valid) { + StringBuilder sb = new StringBuilder(); + if (!duplicateProductSns.isEmpty()) { + sb.append("重复的SN码:").append(String.join(", ", duplicateProductSns)).append(";"); + } + if (!duplicateMacs.isEmpty()) { + sb.append("重复的MAC地址:").append(String.join(", ", duplicateMacs)).append(";"); + } + if (!duplicateSerialNums.isEmpty()) { + sb.append("重复的序列号:").append(String.join(", ", duplicateSerialNums)).append(";"); + } + message = sb.toString(); + } + + return BaseResult.successWithData(new DeviceValidateResponse( + valid, + new ArrayList<>(duplicateProductSns), + new ArrayList<>(duplicateMacs), + new ArrayList<>(duplicateSerialNums), + message + )); + } } diff --git a/src/main/java/com/niuan/erp/module/sale/controller/SaleOrderController.java b/src/main/java/com/niuan/erp/module/sale/controller/SaleOrderController.java index 34f34c2..8b10a6c 100644 --- a/src/main/java/com/niuan/erp/module/sale/controller/SaleOrderController.java +++ b/src/main/java/com/niuan/erp/module/sale/controller/SaleOrderController.java @@ -43,8 +43,12 @@ public class SaleOrderController { @Validated(Get.class) SaleOrderDto searchParams) { var wrapper = new LambdaQueryWrapper(); if (searchParams != null) { - if (StringUtils.hasText(searchParams.customerName())) { - wrapper.like(Document::getStoreName, searchParams.customerName()); + if (StringUtils.hasText(searchParams.searchCode())) { + wrapper.and(w -> w.like(Document::getFormCode, searchParams.searchCode()) + .or() + .like(Document::getFormName, searchParams.searchCode()) + .or() + .like(Document::getFormMark, searchParams.searchCode())); } } return BaseResult.successWithData(saleOrderService.getSaleOrderPage(pageParams, wrapper)); diff --git a/src/main/java/com/niuan/erp/module/sale/controller/dto/SaleOrderDto.java b/src/main/java/com/niuan/erp/module/sale/controller/dto/SaleOrderDto.java index 2598769..37003e9 100644 --- a/src/main/java/com/niuan/erp/module/sale/controller/dto/SaleOrderDto.java +++ b/src/main/java/com/niuan/erp/module/sale/controller/dto/SaleOrderDto.java @@ -17,5 +17,6 @@ public record SaleOrderDto( Integer formStatus, Integer customerId, String customerName, - Double totalValue + Double totalValue, + String searchCode ) {} diff --git a/src/main/java/com/niuan/erp/module/sale/service/DeviceService.java b/src/main/java/com/niuan/erp/module/sale/service/DeviceService.java index 9b599c9..25c8259 100644 --- a/src/main/java/com/niuan/erp/module/sale/service/DeviceService.java +++ b/src/main/java/com/niuan/erp/module/sale/service/DeviceService.java @@ -4,8 +4,11 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.niuan.erp.common.base.BasePageReqParams; import com.niuan.erp.module.sale.controller.dto.DeviceQueryDto; import com.niuan.erp.module.sale.controller.dto.DeviceResultDto; +import com.niuan.erp.module.sale.mapper.DeviceMapper; public interface DeviceService { IPage getDeviceSnPage(BasePageReqParams pageParams, DeviceQueryDto searchParams); + + DeviceMapper getDeviceMapper(); } diff --git a/src/main/java/com/niuan/erp/module/sale/service/impl/DeviceServiceImpl.java b/src/main/java/com/niuan/erp/module/sale/service/impl/DeviceServiceImpl.java index 0ba58e3..55628d0 100644 --- a/src/main/java/com/niuan/erp/module/sale/service/impl/DeviceServiceImpl.java +++ b/src/main/java/com/niuan/erp/module/sale/service/impl/DeviceServiceImpl.java @@ -32,4 +32,9 @@ public class DeviceServiceImpl extends ServiceImpl impleme searchCode, keyAccountId); } + + @Override + public DeviceMapper getDeviceMapper() { + return this.baseMapper; + } } diff --git a/src/main/java/com/niuan/erp/module/warehouse/controller/StockController.java b/src/main/java/com/niuan/erp/module/warehouse/controller/StockController.java index 9dd5f73..5801cf9 100644 --- a/src/main/java/com/niuan/erp/module/warehouse/controller/StockController.java +++ b/src/main/java/com/niuan/erp/module/warehouse/controller/StockController.java @@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.niuan.erp.common.base.BasePageReqParams; import com.niuan.erp.common.base.BaseResult; import com.niuan.erp.common.base.CommonValidateGroup.Get; +import com.niuan.erp.common.base.CommonValidateGroup.Add; +import com.niuan.erp.module.warehouse.controller.dto.StockCheckDto; import com.niuan.erp.module.warehouse.controller.dto.StockDto; import com.niuan.erp.module.warehouse.service.StockService; import io.swagger.v3.oas.annotations.Operation; @@ -12,6 +14,8 @@ import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -30,4 +34,12 @@ public class StockController { @Validated(Get.class) StockDto searchParams) { return BaseResult.successWithData(stockService.getStockPage(pageParams, searchParams)); } + + @Operation(summary = "库存检测", operationId = "checkStock") + @PostMapping("/checkStock") + @PreAuthorize("hasAnyAuthority('stock_transfer_order:add', 'stock_transfer_order:update')") + public BaseResult checkStock(@Validated(Add.class) @RequestBody StockCheckDto dto) { + stockService.checkStock(dto); + return BaseResult.success(); + } } diff --git a/src/main/java/com/niuan/erp/module/warehouse/controller/StockTransferOrderController.java b/src/main/java/com/niuan/erp/module/warehouse/controller/StockTransferOrderController.java index 63b1ad4..866ca0b 100644 --- a/src/main/java/com/niuan/erp/module/warehouse/controller/StockTransferOrderController.java +++ b/src/main/java/com/niuan/erp/module/warehouse/controller/StockTransferOrderController.java @@ -50,7 +50,7 @@ public class StockTransferOrderController { @ApiLog(type = OperationType.UPDATE, remark = "更新一条StockTransferOrder记录") @Operation(summary = "更新StockTransferOrder", operationId = "updateStockTransferOrder") @PostMapping("/updateStockTransferOrder") - @PreAuthorize("hasAuthority('stock_transfer_order:update')") + @PreAuthorize("hasAuthority('stock_transfer_order:edit')") public BaseResult updateStockTransferOrder(@Validated(Update.class) @RequestBody StockTransferOrderAddDto dto) { stockTransferOrderService.updateStockTransferOrder(dto); return BaseResult.success(); diff --git a/src/main/java/com/niuan/erp/module/warehouse/controller/dto/StockTransferOrderDto.java b/src/main/java/com/niuan/erp/module/warehouse/controller/dto/StockTransferOrderDto.java index 72aab1d..2b4989c 100644 --- a/src/main/java/com/niuan/erp/module/warehouse/controller/dto/StockTransferOrderDto.java +++ b/src/main/java/com/niuan/erp/module/warehouse/controller/dto/StockTransferOrderDto.java @@ -15,7 +15,7 @@ import java.util.List; * @param formCode * @param formName * @param formMark - * @param formStatus + * @param status * @param orderItems */ @JsonInclude(JsonInclude.Include.NON_NULL) @@ -29,5 +29,5 @@ public record StockTransferOrderDto( String formCode, String formName, String formMark, - Integer formStatus, + Integer status, List orderItems) {} \ No newline at end of file diff --git a/src/main/java/com/niuan/erp/module/warehouse/converter/StockTransferOrderConverter.java b/src/main/java/com/niuan/erp/module/warehouse/converter/StockTransferOrderConverter.java index 4963f1a..eed28b1 100644 --- a/src/main/java/com/niuan/erp/module/warehouse/converter/StockTransferOrderConverter.java +++ b/src/main/java/com/niuan/erp/module/warehouse/converter/StockTransferOrderConverter.java @@ -8,6 +8,7 @@ import com.niuan.erp.module.warehouse.controller.dto.StockTransferOrderDto; import com.niuan.erp.module.warehouse.controller.dto.StockTransferOrderItemAddDto; import com.niuan.erp.module.warehouse.controller.dto.StockTransferOrderItemDto; import org.mapstruct.Mapper; +import org.mapstruct.Mapping; import org.mapstruct.ReportingPolicy; import java.util.List; @@ -16,6 +17,8 @@ import java.util.List; public interface StockTransferOrderConverter { Document toEntity(StockTransferOrderDto dto); Document toEntity(StockTransferOrderAddDto dto); + + @Mapping(source = "formStatus.value", target = "status") StockTransferOrderDto toDto(Document entity); DocumentMaterial toEntity(StockTransferOrderItemAddDto dto); diff --git a/src/main/java/com/niuan/erp/module/warehouse/mapper/WarehouseItemMapper.java b/src/main/java/com/niuan/erp/module/warehouse/mapper/WarehouseItemMapper.java index 19cefa5..91b48af 100644 --- a/src/main/java/com/niuan/erp/module/warehouse/mapper/WarehouseItemMapper.java +++ b/src/main/java/com/niuan/erp/module/warehouse/mapper/WarehouseItemMapper.java @@ -24,4 +24,7 @@ public interface WarehouseItemMapper extends BaseMapper { @MapKey("partNumber") Map> getWarehouseItemStockListByPartNumbers(List partNumbers); + @MapKey("partNumber") + Map> getWarehouseItemStockListByPartNumbersWithStore(List partNumbers, Integer storeNo); + } diff --git a/src/main/java/com/niuan/erp/module/warehouse/service/StockService.java b/src/main/java/com/niuan/erp/module/warehouse/service/StockService.java index bf181d3..36eaf2e 100644 --- a/src/main/java/com/niuan/erp/module/warehouse/service/StockService.java +++ b/src/main/java/com/niuan/erp/module/warehouse/service/StockService.java @@ -2,10 +2,13 @@ package com.niuan.erp.module.warehouse.service; import com.baomidou.mybatisplus.core.metadata.IPage; import com.niuan.erp.common.base.BasePageReqParams; +import com.niuan.erp.module.warehouse.controller.dto.StockCheckDto; import com.niuan.erp.module.warehouse.controller.dto.StockDto; public interface StockService { IPage getStockPage(BasePageReqParams pageParams, StockDto searchParams); + void checkStock(StockCheckDto dto); + } diff --git a/src/main/java/com/niuan/erp/module/warehouse/service/impl/InventoryCountServiceImpl.java b/src/main/java/com/niuan/erp/module/warehouse/service/impl/InventoryCountServiceImpl.java index 4cca5e6..df2d0b9 100644 --- a/src/main/java/com/niuan/erp/module/warehouse/service/impl/InventoryCountServiceImpl.java +++ b/src/main/java/com/niuan/erp/module/warehouse/service/impl/InventoryCountServiceImpl.java @@ -49,6 +49,7 @@ public class InventoryCountServiceImpl extends ServiceImpl getInventoryCountPage(BasePageReqParams pageParams, LambdaQueryWrapper wrapper) { wrapper.eq(Document::getFormType, DocumentType.INVENTORY_COUNT); + wrapper.eq(Document::getCustomerId, SecurityUtils.getCustomerId()); IPage result = this.baseMapper.selectPage(new Page<>(pageParams.page(), pageParams.pageSize()), wrapper); return result.convert(inventoryCountConverter::toDto); } diff --git a/src/main/java/com/niuan/erp/module/warehouse/service/impl/StockServiceImpl.java b/src/main/java/com/niuan/erp/module/warehouse/service/impl/StockServiceImpl.java index 5aba5ea..87fea5b 100644 --- a/src/main/java/com/niuan/erp/module/warehouse/service/impl/StockServiceImpl.java +++ b/src/main/java/com/niuan/erp/module/warehouse/service/impl/StockServiceImpl.java @@ -1,10 +1,13 @@ package com.niuan.erp.module.warehouse.service.impl; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.niuan.erp.common.base.BasePageReqParams; +import com.niuan.erp.common.exception.BusinessException; import com.niuan.erp.common.utils.SecurityUtils; +import com.niuan.erp.module.warehouse.controller.dto.StockCheckDto; import com.niuan.erp.module.warehouse.controller.dto.StockDto; import com.niuan.erp.module.warehouse.converter.StockConverter; import com.niuan.erp.module.warehouse.entity.Stock; @@ -14,6 +17,9 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.Map; +import java.util.stream.Collectors; + @Service @Transactional @@ -29,4 +35,33 @@ public class StockServiceImpl extends ServiceImpl implements searchParams, SecurityUtils.getUserId()); } + @Override + public void checkStock(StockCheckDto dto) { + if (dto.storeNo() == null) { + throw new BusinessException("warehouse.stock_check.validate.store_no_not_null"); + } + if (dto.items() == null || dto.items().isEmpty()) { + throw new BusinessException("warehouse.stock_check.validate.items_not_empty"); + } + + var partNumbers = dto.items().stream() + .map(StockCheckDto.StockCheckItem::partNumber) + .collect(Collectors.toList()); + + var stockWrapper = new LambdaQueryWrapper() + .eq(Stock::getStoreNo, dto.storeNo()) + .in(Stock::getPartNumber, partNumbers); + var stockList = this.baseMapper.selectList(stockWrapper); + + var stockMap = stockList.stream() + .collect(Collectors.toMap(Stock::getPartNumber, s -> s)); + + for (var item : dto.items()) { + var stock = stockMap.get(item.partNumber()); + if (stock == null || stock.getProductCount() == null || stock.getProductCount() < item.requiredCount()) { + throw new BusinessException("warehouse.stock_check.exception.insufficient_stock", item.partNumber()); + } + } + } + } \ No newline at end of file diff --git a/src/main/java/com/niuan/erp/module/warehouse/service/impl/StockTransferOrderServiceImpl.java b/src/main/java/com/niuan/erp/module/warehouse/service/impl/StockTransferOrderServiceImpl.java index fcf3a8a..f52b377 100644 --- a/src/main/java/com/niuan/erp/module/warehouse/service/impl/StockTransferOrderServiceImpl.java +++ b/src/main/java/com/niuan/erp/module/warehouse/service/impl/StockTransferOrderServiceImpl.java @@ -80,7 +80,7 @@ public class StockTransferOrderServiceImpl extends ServiceImpl item.getDocumentNo().equals(order.getId().intValue())) .map(stockTransferOrderConverter::toItemDto).toList())); @@ -109,7 +109,7 @@ public class StockTransferOrderServiceImpl extends ServiceImpl materials = stockTransferOrderConverter.toEntityList(dto.transferOrderItems()); Map> warehouseItems = - warehouseItemMapper.getWarehouseItemStockListByPartNumbers(materials.stream() + warehouseItemMapper.getWarehouseItemStockListByPartNumbersWithStore(materials.stream() .map(DocumentMaterial::getPartNumber) - .toList()); + .toList(), dto.outStoreNo()); materials.forEach(m -> { m.setDocumentNo(entity.getId().intValue()); @@ -177,9 +177,9 @@ public class StockTransferOrderServiceImpl extends ServiceImpl materials = stockTransferOrderConverter.toEntityList(dto.transferOrderItems()); Map> warehouseItems = - warehouseItemMapper.getWarehouseItemStockListByPartNumbers(materials.stream() + warehouseItemMapper.getWarehouseItemStockListByPartNumbersWithStore(materials.stream() .map(DocumentMaterial::getPartNumber) - .toList()); + .toList(), dto.outStoreNo()); materials.forEach(m -> { m.setDocumentNo(entity.getId().intValue()); @@ -268,7 +268,7 @@ public class StockTransferOrderServiceImpl extends ServiceImpl partNumbers = new ArrayList<>(partCountMap.keySet()); Map> warehouseItems = - warehouseItemMapper.getWarehouseItemStockListByPartNumbers(partNumbers); + warehouseItemMapper.getWarehouseItemStockListByPartNumbersWithStore(partNumbers, dto.outStoreNo()); for (Map.Entry entry : partCountMap.entrySet()) { String partNumber = entry.getKey(); @@ -441,12 +443,12 @@ public class StockTransferOrderServiceImpl extends ServiceImpl stockInfo = warehouseItems.get(partNumber); if (stockInfo == null) { - throw new BusinessException("warehouse.stock_transfer_order.exception.part_not_found"); + throw new BusinessException("warehouse.stock_transfer_order.exception.part_not_found", partNumber); } Long stockCount = (Long) stockInfo.get("productCount"); if (stockCount == null || stockCount < totalTransfer) { - throw new BusinessException("warehouse.stock_transfer_order.exception.insufficient_stock"); + throw new BusinessException("warehouse.stock_transfer_order.exception.insufficient_stock", partNumber); } } } diff --git a/src/main/java/com/niuan/erp/module/warehouse/service/impl/WarehouseReceiptServiceImpl.java b/src/main/java/com/niuan/erp/module/warehouse/service/impl/WarehouseReceiptServiceImpl.java index 7243065..2e16eeb 100644 --- a/src/main/java/com/niuan/erp/module/warehouse/service/impl/WarehouseReceiptServiceImpl.java +++ b/src/main/java/com/niuan/erp/module/warehouse/service/impl/WarehouseReceiptServiceImpl.java @@ -49,6 +49,7 @@ public class WarehouseReceiptServiceImpl extends ServiceImpl getWarehouseReceiptPage(BasePageReqParams pageParams, LambdaQueryWrapper wrapper) { wrapper.eq(Document::getFormType, DocumentType.WAREHOUSE_RECEIPT) + .eq(Document::getCustomerId, SecurityUtils.getCustomerId()) .orderByDesc(Document::getCreateDate); IPage result = this.baseMapper.selectPage(new Page<>(pageParams.page(), pageParams.pageSize()), wrapper); return result.convert(warehouseReceiptConverter::toDto); @@ -211,6 +212,7 @@ public class WarehouseReceiptServiceImpl extends ServiceImpl> 生产管理 diff --git a/src/main/resources/i18n/messages_zh_CN.properties b/src/main/resources/i18n/messages_zh_CN.properties index c040865..5b0f257 100644 --- a/src/main/resources/i18n/messages_zh_CN.properties +++ b/src/main/resources/i18n/messages_zh_CN.properties @@ -98,6 +98,9 @@ warehouse.inventory_count.exception.stock_not_found_for_unapprove=物料 {0} 在 warehouse.inventory_count.exception.file_empty=请选择要上传的文件 warehouse.inventory_count.exception.import_failed=导入文件失败 warehouse.inventory_count.exception.init_already_exists=当前仓库已经有初始库存单 +warehouse.stock_check.validate.store_no_not_null=仓库不能为空 +warehouse.stock_check.validate.items_not_empty=物料明细不能为空 +warehouse.stock_check.exception.insufficient_stock=物料 {0} 库存不足 production.finished_product_receipt.validate.form_code.not_null=单据编号不能为空 production.finished_product_receipt.validate.form_name.not_null=单据名称不能为空 production.finished_product_receipt.validate.store_no.not_null=仓库不能为空 diff --git a/src/main/resources/mapper/warehouse/WarehouseItemMapper.xml b/src/main/resources/mapper/warehouse/WarehouseItemMapper.xml index 4b23b49..392d16e 100644 --- a/src/main/resources/mapper/warehouse/WarehouseItemMapper.xml +++ b/src/main/resources/mapper/warehouse/WarehouseItemMapper.xml @@ -53,4 +53,19 @@ + +