From a36ae0c469f9ab634c7fcc80e370fd3194d1a98c Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 5 Feb 2024 00:15:51 +0800 Subject: [PATCH 01/15] =?UTF-8?q?=E2=9C=A8=20ERP=EF=BC=9A=E5=AE=8C?= =?UTF-8?q?=E6=88=90=20product=20=E4=BF=A1=E6=81=AF=E3=80=81=E5=88=86?= =?UTF-8?q?=E7=B1=BB=E3=80=81=E5=8D=95=E4=BD=8D=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/erp/ErrorCodeConstants.java | 3 + .../product/ErpProductCategoryController.java | 29 +++++--- .../admin/product/ErpProductController.java | 35 ++++++++-- .../product/ErpProductUnitController.java | 9 +++ .../product/vo/product/ProductRespVO.java | 10 ++- .../product/vo/product/ProductSaveReqVO.java | 9 +-- .../vo/unit/ErpProductUnitPageReqVO.java | 9 --- .../product/vo/unit/ErpProductUnitRespVO.java | 5 +- .../vo/unit/ErpProductUnitSaveReqVO.java | 3 + .../dal/dataobject/product/ErpProductDO.java | 4 +- .../dal/mysql/product/ErpProductMapper.java | 8 +++ .../mysql/product/ErpProductUnitMapper.java | 11 ++- .../product/ErpProductCategoryService.java | 26 ++++++- .../ErpProductCategoryServiceImpl.java | 21 +++++- .../service/product/ErpProductService.java | 16 +++++ .../product/ErpProductServiceImpl.java | 10 +++ .../product/ErpProductUnitService.java | 36 +++++++++- .../product/ErpProductUnitServiceImpl.java | 69 +++++++++++++++---- 18 files changed, 257 insertions(+), 56 deletions(-) diff --git a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/ErrorCodeConstants.java b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/ErrorCodeConstants.java index 9363bab11..db3a3a37d 100644 --- a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/ErrorCodeConstants.java +++ b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/ErrorCodeConstants.java @@ -19,8 +19,11 @@ public interface ErrorCodeConstants { ErrorCode PRODUCT_CATEGORY_PARENT_ERROR = new ErrorCode(1_030_501_003, "不能设置自己为父产品分类"); ErrorCode PRODUCT_CATEGORY_NAME_DUPLICATE = new ErrorCode(1_030_501_004, "已经存在该分类名称的产品分类"); ErrorCode PRODUCT_CATEGORY_PARENT_IS_CHILD = new ErrorCode(1_030_501_005, "不能设置自己的子分类为父分类"); + ErrorCode PRODUCT_CATEGORY_EXITS_PRODUCT = new ErrorCode(1_030_502_002, "存在产品使用该分类,无法删除"); // ========== ERP 产品单位 1-030-502-000 ========== ErrorCode PRODUCT_UNIT_NOT_EXISTS = new ErrorCode(1_030_502_000, "产品单位不存在"); + ErrorCode PRODUCT_UNIT_NAME_DUPLICATE = new ErrorCode(1_030_502_001, "已存在该名字的产品单位"); + ErrorCode PRODUCT_UNIT_EXITS_PRODUCT = new ErrorCode(1_030_502_002, "存在产品使用该单位,无法删除"); } diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductCategoryController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductCategoryController.java index f542d6983..85f51c1c6 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductCategoryController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductCategoryController.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.erp.controller.admin.product; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; @@ -23,6 +24,7 @@ import java.io.IOException; import java.util.List; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; @Tag(name = "管理后台 - ERP 产品分类") @@ -35,14 +37,14 @@ public class ErpProductCategoryController { private ErpProductCategoryService productCategoryService; @PostMapping("/create") - @Operation(summary = "创建ERP 产品分类") + @Operation(summary = "创建产品分类") @PreAuthorize("@ss.hasPermission('erp:product-category:create')") public CommonResult createProductCategory(@Valid @RequestBody ErpProductCategorySaveReqVO createReqVO) { return success(productCategoryService.createProductCategory(createReqVO)); } @PutMapping("/update") - @Operation(summary = "更新ERP 产品分类") + @Operation(summary = "更新产品分类") @PreAuthorize("@ss.hasPermission('erp:product-category:update')") public CommonResult updateProductCategory(@Valid @RequestBody ErpProductCategorySaveReqVO updateReqVO) { productCategoryService.updateProductCategory(updateReqVO); @@ -50,7 +52,7 @@ public class ErpProductCategoryController { } @DeleteMapping("/delete") - @Operation(summary = "删除ERP 产品分类") + @Operation(summary = "删除产品分类") @Parameter(name = "id", description = "编号", required = true) @PreAuthorize("@ss.hasPermission('erp:product-category:delete')") public CommonResult deleteProductCategory(@RequestParam("id") Long id) { @@ -59,31 +61,40 @@ public class ErpProductCategoryController { } @GetMapping("/get") - @Operation(summary = "获得ERP 产品分类") + @Operation(summary = "获得产品分类") @Parameter(name = "id", description = "编号", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('erp:product-category:query')") public CommonResult getProductCategory(@RequestParam("id") Long id) { - ErpProductCategoryDO productCategory = productCategoryService.getProductCategory(id); - return success(BeanUtils.toBean(productCategory, ErpProductCategoryRespVO.class)); + ErpProductCategoryDO category = productCategoryService.getProductCategory(id); + return success(BeanUtils.toBean(category, ErpProductCategoryRespVO.class)); } @GetMapping("/list") - @Operation(summary = "获得ERP 产品分类列表") + @Operation(summary = "获得产品分类列表") @PreAuthorize("@ss.hasPermission('erp:product-category:query')") public CommonResult> getProductCategoryList(@Valid ErpProductCategoryListReqVO listReqVO) { List list = productCategoryService.getProductCategoryList(listReqVO); return success(BeanUtils.toBean(list, ErpProductCategoryRespVO.class)); } + @GetMapping("/simple-list") + @Operation(summary = "获得产品分类精简列表", description = "只包含被开启的分类,主要用于前端的下拉选项") + public CommonResult> getProductCategorySimpleList() { + List list = productCategoryService.getProductCategoryList( + new ErpProductCategoryListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus())); + return success(convertList(list, category -> new ErpProductCategoryRespVO() + .setId(category.getId()).setName(category.getName()).setParentId(category.getParentId()))); + } + @GetMapping("/export-excel") - @Operation(summary = "导出ERP 产品分类 Excel") + @Operation(summary = "导出产品分类 Excel") @PreAuthorize("@ss.hasPermission('erp:product-category:export')") @OperateLog(type = EXPORT) public void exportProductCategoryExcel(@Valid ErpProductCategoryListReqVO listReqVO, HttpServletResponse response) throws IOException { List list = productCategoryService.getProductCategoryList(listReqVO); // 导出 Excel - ExcelUtils.write(response, "ERP 产品分类.xls", "数据", ErpProductCategoryRespVO.class, + ExcelUtils.write(response, "产品分类.xls", "数据", ErpProductCategoryRespVO.class, BeanUtils.toBean(list, ErpProductCategoryRespVO.class)); } diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductController.java index 098eb8679..30135a6fe 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductController.java @@ -1,16 +1,22 @@ package cn.iocoder.yudao.module.erp.controller.admin.product; +import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductPageReqVO; import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductRespVO; import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductCategoryDO; import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO; +import cn.iocoder.yudao.module.erp.service.product.ErpProductCategoryService; import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.product.ErpProductUnitService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -22,9 +28,10 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import java.io.IOException; -import java.util.List; +import java.util.Map; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; @Tag(name = "管理后台 - ERP 产品") @@ -35,6 +42,10 @@ public class ErpProductController { @Resource private ErpProductService productService; + @Resource + private ErpProductCategoryService productCategoryService; + @Resource + private ErpProductUnitService productUnitService; @PostMapping("/create") @Operation(summary = "创建产品") @@ -74,7 +85,7 @@ public class ErpProductController { @PreAuthorize("@ss.hasPermission('erp:product:query')") public CommonResult> getProductPage(@Valid ProductPageReqVO pageReqVO) { PageResult pageResult = productService.getProductPage(pageReqVO); - return success(BeanUtils.toBean(pageResult, ProductRespVO.class)); + return success(buildProductDetailPage(pageResult)); } @GetMapping("/export-excel") @@ -84,10 +95,26 @@ public class ErpProductController { public void exportProductExcel(@Valid ProductPageReqVO pageReqVO, HttpServletResponse response) throws IOException { pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); - List list = productService.getProductPage(pageReqVO).getList(); + PageResult pageResult = productService.getProductPage(pageReqVO); // 导出 Excel ExcelUtils.write(response, "产品.xls", "数据", ProductRespVO.class, - BeanUtils.toBean(list, ProductRespVO.class)); + buildProductDetailPage(pageResult).getList()); + } + + private PageResult buildProductDetailPage(PageResult pageResult) { + if (CollUtil.isEmpty(pageResult.getList())) { + return PageResult.empty(pageResult.getTotal()); + } + Map categoryMap = productCategoryService.getProductCategoryMap( + convertSet(pageResult.getList(), ErpProductDO::getCategoryId)); + Map unitMap = productUnitService.getProductUnitMap( + convertSet(pageResult.getList(), ErpProductDO::getUnitId)); + return BeanUtils.toBean(pageResult, ProductRespVO.class, product -> { + MapUtils.findAndThen(categoryMap, product.getCategoryId(), + category -> product.setCategoryName(category.getName())); + MapUtils.findAndThen(unitMap, product.getUnitId(), + unit -> product.setUnitName(unit.getName())); + }); } } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductUnitController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductUnitController.java index 34d97ff2e..0be3db01c 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductUnitController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductUnitController.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.erp.controller.admin.product; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; @@ -25,6 +26,7 @@ import java.io.IOException; import java.util.List; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; @Tag(name = "管理后台 - ERP 产品单位") @@ -77,6 +79,13 @@ public class ErpProductUnitController { return success(BeanUtils.toBean(pageResult, ErpProductUnitRespVO.class)); } + @GetMapping("/simple-list") + @Operation(summary = "获得产品单位精简列表", description = "只包含被开启的单位,主要用于前端的下拉选项") + public CommonResult> getProductUnitSimpleList() { + List list = productUnitService.getProductUnitListByStatus(CommonStatusEnum.ENABLE.getStatus()); + return success(convertList(list, unit -> new ErpProductUnitRespVO().setId(unit.getId()).setName(unit.getName()))); + } + @GetMapping("/export-excel") @Operation(summary = "导出产品单位 Excel") @PreAuthorize("@ss.hasPermission('erp:product-unit:export')") diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ProductRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ProductRespVO.java index d96cbad98..f6f255c09 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ProductRespVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ProductRespVO.java @@ -26,12 +26,16 @@ public class ProductRespVO { private String barCode; @Schema(description = "产品分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11161") - @ExcelProperty("产品分类编号") private Long categoryId; + @Schema(description = "产品分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "水果") + @ExcelProperty("产品分类") + private String categoryName; @Schema(description = "单位编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8869") - @ExcelProperty("单位编号") - private Integer unitId; + private Long unitId; + @Schema(description = "单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "个") + @ExcelProperty("单位") + private String unitName; @Schema(description = "产品状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") @ExcelProperty("产品状态") diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ProductSaveReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ProductSaveReqVO.java index e881bf46b..6cf806e3e 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ProductSaveReqVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ProductSaveReqVO.java @@ -1,9 +1,10 @@ package cn.iocoder.yudao.module.erp.controller.admin.product.vo.product; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; -import java.util.*; -import jakarta.validation.constraints.*; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + import java.math.BigDecimal; @Schema(description = "管理后台 - ERP 产品新增/修改 Request VO") @@ -27,7 +28,7 @@ public class ProductSaveReqVO { @Schema(description = "单位编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8869") @NotNull(message = "单位编号不能为空") - private Integer unitId; + private Long unitId; @Schema(description = "产品状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") @NotNull(message = "产品状态不能为空") diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitPageReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitPageReqVO.java index cef41c7ec..87119c126 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitPageReqVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitPageReqVO.java @@ -5,11 +5,6 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; -import org.springframework.format.annotation.DateTimeFormat; - -import java.time.LocalDateTime; - -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; @Schema(description = "管理后台 - ERP 产品单位分页 Request VO") @Data @@ -23,8 +18,4 @@ public class ErpProductUnitPageReqVO extends PageParam { @Schema(description = "单位状态", example = "1") private Integer status; - @Schema(description = "创建时间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime[] createTime; - } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitRespVO.java index e1287b0f5..06f604920 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitRespVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitRespVO.java @@ -1,9 +1,10 @@ package cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit; +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.module.system.enums.DictTypeConstants; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotNull; import lombok.Data; import java.time.LocalDateTime; @@ -23,7 +24,7 @@ public class ErpProductUnitRespVO { @Schema(description = "单位状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @ExcelProperty("单位状态") - @NotNull(message = "分类排序不能为空") + @DictFormat(DictTypeConstants.COMMON_STATUS) private Integer status; @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitSaveReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitSaveReqVO.java index eccf291b0..e413ec1bf 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitSaveReqVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitSaveReqVO.java @@ -1,5 +1,7 @@ package cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; @@ -18,6 +20,7 @@ public class ErpProductUnitSaveReqVO { @Schema(description = "单位状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @NotNull(message = "单位状态不能为空") + @InEnum(CommonStatusEnum.class) private Integer status; } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/product/ErpProductDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/product/ErpProductDO.java index c6d947956..31e4aa2d9 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/product/ErpProductDO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/product/ErpProductDO.java @@ -45,9 +45,9 @@ public class ErpProductDO extends BaseDO { /** * 单位编号 * - * TODO 芋艿,关联 + * 关联 {@link ErpProductUnitDO#getId()} */ - private Integer unitId; + private Long unitId; /** * 产品状态 * diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductMapper.java index 8ecad6c54..81bca5cf9 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductMapper.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductMapper.java @@ -23,4 +23,12 @@ public interface ErpProductMapper extends BaseMapperX { .orderByDesc(ErpProductDO::getId)); } + default Long selectCountByCategoryId(Long categoryId) { + return selectCount(ErpProductDO::getCategoryId, categoryId); + } + + default Long selectCountByUnitId(Long unitId) { + return selectCount(ErpProductDO::getUnitId, unitId); + } + } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductUnitMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductUnitMapper.java index b24af15d3..45db6a829 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductUnitMapper.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductUnitMapper.java @@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUn import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO; import org.apache.ibatis.annotations.Mapper; +import java.util.List; + /** * ERP 产品单位 Mapper * @@ -19,8 +21,15 @@ public interface ErpProductUnitMapper extends BaseMapperX { return selectPage(reqVO, new LambdaQueryWrapperX() .likeIfPresent(ErpProductUnitDO::getName, reqVO.getName()) .eqIfPresent(ErpProductUnitDO::getStatus, reqVO.getStatus()) - .betweenIfPresent(ErpProductUnitDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(ErpProductUnitDO::getId)); } + default ErpProductUnitDO selectByName(String name) { + return selectOne(ErpProductUnitDO::getName, name); + } + + default List selectListByStatus(Integer status) { + return selectList(ErpProductUnitDO::getStatus, status); + } + } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductCategoryService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductCategoryService.java index c5b1e9d21..2b11faf61 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductCategoryService.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductCategoryService.java @@ -5,7 +5,11 @@ import cn.iocoder.yudao.module.erp.controller.admin.product.vo.category.ErpProdu import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductCategoryDO; import jakarta.validation.Valid; +import java.util.Collection; import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; /** * ERP 产品分类 Service 接口 @@ -40,7 +44,7 @@ public interface ErpProductCategoryService { * 获得产品分类 * * @param id 编号 - * @return ERP 产品分类 + * @return 产品分类 */ ErpProductCategoryDO getProductCategory(Long id); @@ -48,8 +52,26 @@ public interface ErpProductCategoryService { * 获得产品分类列表 * * @param listReqVO 查询条件 - * @return ERP 产品分类列表 + * @return 产品分类列表 */ List getProductCategoryList(ErpProductCategoryListReqVO listReqVO); + /** + * 获得产品分类列表 + * + * @param ids 编号数组 + * @return 产品分类列表 + */ + List getProductCategoryList(Collection ids); + + /** + * 获得产品分类 Map + * + * @param ids 编号数组 + * @return 产品分类 Map + */ + default Map getProductCategoryMap(Collection ids) { + return convertMap(getProductCategoryList(ids), ErpProductCategoryDO::getId); + } + } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductCategoryServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductCategoryServiceImpl.java index 6253914be..28d8b3172 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductCategoryServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductCategoryServiceImpl.java @@ -6,9 +6,11 @@ import cn.iocoder.yudao.module.erp.controller.admin.product.vo.category.ErpProdu import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductCategoryDO; import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductCategoryMapper; import jakarta.annotation.Resource; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.util.Collection; import java.util.List; import java.util.Objects; @@ -27,6 +29,10 @@ public class ErpProductCategoryServiceImpl implements ErpProductCategoryService @Resource private ErpProductCategoryMapper productCategoryMapper; + @Resource + @Lazy // 延迟加载,避免循环依赖 + private ErpProductService productService; + @Override public Long createProductCategory(ErpProductCategorySaveReqVO createReqVO) { // 校验父分类编号的有效性 @@ -57,13 +63,17 @@ public class ErpProductCategoryServiceImpl implements ErpProductCategoryService @Override public void deleteProductCategory(Long id) { - // 校验存在 + // 1.1 校验存在 validateProductCategoryExists(id); - // 校验是否有子产品分类 + // 1.2 校验是否有子产品分类 if (productCategoryMapper.selectCountByParentId(id) > 0) { throw exception(PRODUCT_CATEGORY_EXITS_CHILDREN); } - // 删除 + // 1.3 校验是否有产品 + if (productService.getProductCountByCategoryId(id) > 0) { + throw exception(PRODUCT_CATEGORY_EXITS_PRODUCT); + } + // 2. 删除 productCategoryMapper.deleteById(id); } @@ -131,4 +141,9 @@ public class ErpProductCategoryServiceImpl implements ErpProductCategoryService return productCategoryMapper.selectList(listReqVO); } + @Override + public List getProductCategoryList(Collection ids) { + return productCategoryMapper.selectBatchIds(ids); + } + } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductService.java index 1087ab70d..3a2e08ce6 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductService.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductService.java @@ -51,4 +51,20 @@ public interface ErpProductService { */ PageResult getProductPage(ProductPageReqVO pageReqVO); + /** + * 基于产品分类编号,获得产品数量 + * + * @param categoryId 产品分类编号 + * @return 产品数量 + */ + Long getProductCountByCategoryId(Long categoryId); + + /** + * 基于产品单位编号,获得产品数量 + * + * @param unitId 产品单位编号 + * @return 产品数量 + */ + Long getProductCountByUnitId(Long unitId); + } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java index 9fbe1f6e4..3efb981e3 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java @@ -69,4 +69,14 @@ public class ErpProductServiceImpl implements ErpProductService { return productMapper.selectPage(pageReqVO); } + @Override + public Long getProductCountByCategoryId(Long categoryId) { + return productMapper.selectCountByCategoryId(categoryId); + } + + @Override + public Long getProductCountByUnitId(Long unitId) { + return productMapper.selectCountByUnitId(unitId); + } + } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitService.java index 68599baf1..340278ab9 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitService.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitService.java @@ -1,10 +1,16 @@ package cn.iocoder.yudao.module.erp.service.product; +import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitPageReqVO; import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitSaveReqVO; -import jakarta.validation.*; import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO; -import cn.iocoder.yudao.framework.common.pojo.PageResult; +import jakarta.validation.Valid; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; /** * ERP 产品单位 Service 接口 @@ -51,4 +57,30 @@ public interface ErpProductUnitService { */ PageResult getProductUnitPage(ErpProductUnitPageReqVO pageReqVO); + /** + * 获得指定状态的产品单位列表 + * + * @param status 状态 + * @return 产品单位列表 + */ + List getProductUnitListByStatus(Integer status); + + /** + * 获得产品单位列表 + * + * @param ids 编号数组 + * @return 产品单位列表 + */ + List getProductUnitList(Collection ids); + + /** + * 获得产品单位 Map + * + * @param ids 编号数组 + * @return 产品单位 Map + */ + default Map getProductUnitMap(Collection ids) { + return convertMap(getProductUnitList(ids), ErpProductUnitDO::getId); + } + } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitServiceImpl.java index 6800bda31..1ab412b11 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitServiceImpl.java @@ -1,19 +1,22 @@ package cn.iocoder.yudao.module.erp.service.product; -import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitPageReqVO; -import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitSaveReqVO; -import org.springframework.stereotype.Service; -import jakarta.annotation.Resource; -import org.springframework.validation.annotation.Validated; - -import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; - +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO; import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductUnitMapper; +import com.google.common.annotations.VisibleForTesting; +import jakarta.annotation.Resource; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.Collection; +import java.util.List; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.erp.ErrorCodeConstants.PRODUCT_UNIT_NOT_EXISTS; +import static cn.iocoder.yudao.module.erp.ErrorCodeConstants.*; /** * ERP 产品单位 Service 实现类 @@ -27,29 +30,55 @@ public class ErpProductUnitServiceImpl implements ErpProductUnitService { @Resource private ErpProductUnitMapper productUnitMapper; + @Resource + @Lazy // 延迟加载,避免循环依赖 + private ErpProductService productService; + @Override public Long createProductUnit(ErpProductUnitSaveReqVO createReqVO) { - // 插入 + // 1. 校验名字唯一 + validateProductUnitNameUnique(null, createReqVO.getName()); + // 2. 插入 ErpProductUnitDO unit = BeanUtils.toBean(createReqVO, ErpProductUnitDO.class); productUnitMapper.insert(unit); - // 返回 return unit.getId(); } @Override public void updateProductUnit(ErpProductUnitSaveReqVO updateReqVO) { - // 校验存在 + // 1.1 校验存在 validateProductUnitExists(updateReqVO.getId()); - // 更新 + // 1.2 校验名字唯一 + validateProductUnitNameUnique(updateReqVO.getId(), updateReqVO.getName()); + // 2. 更新 ErpProductUnitDO updateObj = BeanUtils.toBean(updateReqVO, ErpProductUnitDO.class); productUnitMapper.updateById(updateObj); } + @VisibleForTesting + void validateProductUnitNameUnique(Long id, String name) { + ErpProductUnitDO unit = productUnitMapper.selectByName(name); + if (unit == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的字典类型 + if (id == null) { + throw exception(PRODUCT_UNIT_NAME_DUPLICATE); + } + if (!unit.getId().equals(id)) { + throw exception(PRODUCT_UNIT_NAME_DUPLICATE); + } + } + @Override public void deleteProductUnit(Long id) { - // 校验存在 + // 1.1 校验存在 validateProductUnitExists(id); - // 删除 + // 1.2 校验商品是否使用 + if (productService.getProductCountByUnitId(id) > 0) { + throw exception(PRODUCT_UNIT_EXITS_PRODUCT); + } + // 2. 删除 productUnitMapper.deleteById(id); } @@ -69,4 +98,14 @@ public class ErpProductUnitServiceImpl implements ErpProductUnitService { return productUnitMapper.selectPage(pageReqVO); } + @Override + public List getProductUnitListByStatus(Integer status) { + return productUnitMapper.selectListByStatus(status); + } + + @Override + public List getProductUnitList(Collection ids) { + return productUnitMapper.selectBatchIds(ids); + } + } \ No newline at end of file From b7654eafeafd5100b6ee3543b07bd3a7ddb23e69 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 5 Feb 2024 01:36:34 +0800 Subject: [PATCH 02/15] =?UTF-8?q?=E2=9C=A8=20ERP=EF=BC=9A=E5=AE=8C?= =?UTF-8?q?=E6=88=90=20stock=20=E4=BB=93=E5=BA=93=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/erp/ErrorCodeConstants.java | 3 + .../admin/stock/ErpWarehouseController.java | 106 +++++++++++++++ .../vo/warehouse/ErpWarehousePageReqVO.java | 24 ++++ .../vo/warehouse/ErpWarehouseRespVO.java | 64 +++++++++ .../vo/warehouse/ErpWarehouseSaveReqVO.java | 47 +++++++ .../dal/dataobject/stock/ErpWarehouseDO.java | 70 ++++++++++ .../dal/mysql/stock/ErpWarehouseMapper.java | 29 ++++ .../service/stock/ErpWarehouseService.java | 62 +++++++++ .../stock/ErpWarehouseServiceImpl.java | 88 ++++++++++++ .../mapper/stock/ErpWarehouseMapper.xml | 12 ++ .../stock/ErpWarehouseServiceImplTest.java | 126 ++++++++++++++++++ 11 files changed, 631 insertions(+) create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpWarehouseController.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehousePageReqVO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehouseRespVO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehouseSaveReqVO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpWarehouseDO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpWarehouseMapper.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseService.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseServiceImpl.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/resources/mapper/stock/ErpWarehouseMapper.xml create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/test/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseServiceImplTest.java diff --git a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/ErrorCodeConstants.java b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/ErrorCodeConstants.java index db3a3a37d..f174ed854 100644 --- a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/ErrorCodeConstants.java +++ b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/ErrorCodeConstants.java @@ -9,6 +9,9 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode; */ public interface ErrorCodeConstants { + // ========== ERP 仓库 1-030-400-000 ========== + ErrorCode WAREHOUSE_NOT_EXISTS = new ErrorCode(1_030_400_000, "仓库不存在"); + // ========== ERP 产品 1-030-500-000 ========== ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_030_500_000, "产品不存在"); diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpWarehouseController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpWarehouseController.java new file mode 100644 index 000000000..8877780d8 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpWarehouseController.java @@ -0,0 +1,106 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.ErpWarehouseSaveReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehousePageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehouseRespVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO; +import cn.iocoder.yudao.module.erp.service.stock.ErpWarehouseService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; + +@Tag(name = "管理后台 - ERP 仓库") +@RestController +@RequestMapping("/erp/warehouse") +@Validated +public class ErpWarehouseController { + + @Resource + private ErpWarehouseService warehouseService; + + @PostMapping("/create") + @Operation(summary = "创建仓库") + @PreAuthorize("@ss.hasPermission('erp:warehouse:create')") + public CommonResult createWarehouse(@Valid @RequestBody ErpWarehouseSaveReqVO createReqVO) { + return success(warehouseService.createWarehouse(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新仓库") + @PreAuthorize("@ss.hasPermission('erp:warehouse:update')") + public CommonResult updateWarehouse(@Valid @RequestBody ErpWarehouseSaveReqVO updateReqVO) { + warehouseService.updateWarehouse(updateReqVO); + return success(true); + } + + @PutMapping("/update-default-status") + @Operation(summary = "更新仓库默认状态") + @Parameters({ + @Parameter(name = "id", description = "编号", required = true), + @Parameter(name = "status", description = "状态", required = true) + }) + public CommonResult updateWarehouseDefaultStatus(@RequestParam("id") Long id, + @RequestParam("defaultStatus") Boolean defaultStatus) { + warehouseService.updateWarehouseDefaultStatus(id, defaultStatus); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除仓库") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('erp:warehouse:delete')") + public CommonResult deleteWarehouse(@RequestParam("id") Long id) { + warehouseService.deleteWarehouse(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得仓库") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('erp:warehouse:query')") + public CommonResult getWarehouse(@RequestParam("id") Long id) { + ErpWarehouseDO warehouse = warehouseService.getWarehouse(id); + return success(BeanUtils.toBean(warehouse, ErpWarehouseRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得仓库分页") + @PreAuthorize("@ss.hasPermission('erp:warehouse:query')") + public CommonResult> getWarehousePage(@Valid ErpWarehousePageReqVO pageReqVO) { + PageResult pageResult = warehouseService.getWarehousePage(pageReqVO); + return success(BeanUtils.toBean(pageResult, ErpWarehouseRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出仓库 Excel") + @PreAuthorize("@ss.hasPermission('erp:warehouse:export')") + @OperateLog(type = EXPORT) + public void exportWarehouseExcel(@Valid ErpWarehousePageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = warehouseService.getWarehousePage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "仓库.xls", "数据", ErpWarehouseRespVO.class, + BeanUtils.toBean(list, ErpWarehouseRespVO.class)); + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehousePageReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehousePageReqVO.java new file mode 100644 index 000000000..2accf9a0f --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehousePageReqVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - ERP 仓库分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ErpWarehousePageReqVO extends PageParam { + + @Schema(description = "仓库名称", example = "李四") + private String name; + + @Schema(description = "开启状态", example = "1") + @InEnum(CommonStatusEnum.class) + private Integer status; + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehouseRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehouseRespVO.java new file mode 100644 index 000000000..188d42699 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehouseRespVO.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.system.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - ERP 仓库 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ErpWarehouseRespVO { + + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11614") + @ExcelProperty("仓库编号") + private Long id; + + @Schema(description = "仓库名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @ExcelProperty("仓库名称") + private String name; + + @Schema(description = "仓库地址", example = "上海陆家嘴") + @ExcelProperty("仓库地址") + private String address; + + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @ExcelProperty("排序") + private Long sort; + + @Schema(description = "备注", example = "随便") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "负责人", example = "芋头") + @ExcelProperty("负责人") + private String principal; + + @Schema(description = "仓储费,单位:元", example = "13973") + @ExcelProperty("仓储费,单位:元") + private BigDecimal warehousePrice; + + @Schema(description = "搬运费,单位:元", example = "9903") + @ExcelProperty("搬运费,单位:元") + private BigDecimal truckagePrice; + + @Schema(description = "开启状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "开启状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.COMMON_STATUS) + private Integer status; + + @Schema(description = "是否默认", example = "1") + @ExcelProperty("是否默认") + private Boolean defaultStatus; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehouseSaveReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehouseSaveReqVO.java new file mode 100644 index 000000000..8a6f1ce78 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehouseSaveReqVO.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.math.BigDecimal; + +@Schema(description = "管理后台 - ERP 仓库新增/修改 Request VO") +@Data +public class ErpWarehouseSaveReqVO { + + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11614") + private Long id; + + @Schema(description = "仓库名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @NotEmpty(message = "仓库名称不能为空") + private String name; + + @Schema(description = "仓库地址", example = "上海陆家嘴") + private String address; + + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @NotNull(message = "排序不能为空") + private Long sort; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "负责人", example = "芋头") + private String principal; + + @Schema(description = "仓储费,单位:元", example = "13973") + private BigDecimal warehousePrice; + + @Schema(description = "搬运费,单位:元", example = "9903") + private BigDecimal truckagePrice; + + @Schema(description = "开启状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotNull(message = "开启状态不能为空") + @InEnum(CommonStatusEnum.class) + private Integer status; + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpWarehouseDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpWarehouseDO.java new file mode 100644 index 000000000..4f206173f --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpWarehouseDO.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.stock; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * ERP 仓库 DO + * + * @author 芋道源码 + */ +@TableName("erp_warehouse") +@KeySequence("erp_warehouse_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpWarehouseDO extends BaseDO { + + /** + * 仓库编号 + */ + @TableId + private Long id; + /** + * 仓库名称 + */ + private String name; + /** + * 仓库地址 + */ + private String address; + /** + * 排序 + */ + private Long sort; + /** + * 备注 + */ + private String remark; + /** + * 负责人 + */ + private String principal; + /** + * 仓储费,单位:元 + */ + private BigDecimal warehousePrice; + /** + * 搬运费,单位:元 + */ + private BigDecimal truckagePrice; + /** + * 开启状态 + * + * 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum} + */ + private Integer status; + /** + * 是否默认 + */ + private Boolean defaultStatus; + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpWarehouseMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpWarehouseMapper.java new file mode 100644 index 000000000..7d3bf0d3e --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpWarehouseMapper.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehousePageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * ERP 仓库 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpWarehouseMapper extends BaseMapperX { + + default PageResult selectPage(ErpWarehousePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(ErpWarehouseDO::getName, reqVO.getName()) + .eqIfPresent(ErpWarehouseDO::getStatus, reqVO.getStatus()) + .orderByDesc(ErpWarehouseDO::getId)); + } + + default ErpWarehouseDO selectByDefaultStatus() { + return selectOne(ErpWarehouseDO::getDefaultStatus, true); + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseService.java new file mode 100644 index 000000000..47e4dbed2 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseService.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.ErpWarehouseSaveReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehousePageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO; +import jakarta.validation.Valid; + +/** + * ERP 仓库 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpWarehouseService { + + /** + * 创建仓库 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createWarehouse(@Valid ErpWarehouseSaveReqVO createReqVO); + + /** + * 更新ERP 仓库 + * + * @param updateReqVO 更新信息 + */ + void updateWarehouse(@Valid ErpWarehouseSaveReqVO updateReqVO); + + /** + * 更新仓库默认状态 + * + * @param id 编号 + * @param defaultStatus 默认状态 + */ + void updateWarehouseDefaultStatus(Long id, Boolean defaultStatus); + + /** + * 删除仓库 + * + * @param id 编号 + */ + void deleteWarehouse(Long id); + + /** + * 获得仓库 + * + * @param id 编号 + * @return 仓库 + */ + ErpWarehouseDO getWarehouse(Long id); + + /** + * 获得仓库分页 + * + * @param pageReqVO 分页查询 + * @return 仓库分页 + */ + PageResult getWarehousePage(ErpWarehousePageReqVO pageReqVO); + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseServiceImpl.java new file mode 100644 index 000000000..e4c34ade4 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseServiceImpl.java @@ -0,0 +1,88 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.ErpWarehouseSaveReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehousePageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO; +import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpWarehouseMapper; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.erp.ErrorCodeConstants.WAREHOUSE_NOT_EXISTS; + +/** + * ERP 仓库 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ErpWarehouseServiceImpl implements ErpWarehouseService { + + @Resource + private ErpWarehouseMapper warehouseMapper; + + @Override + public Long createWarehouse(ErpWarehouseSaveReqVO createReqVO) { + // 插入 + ErpWarehouseDO warehouse = BeanUtils.toBean(createReqVO, ErpWarehouseDO.class); + warehouseMapper.insert(warehouse); + // 返回 + return warehouse.getId(); + } + + @Override + public void updateWarehouse(ErpWarehouseSaveReqVO updateReqVO) { + // 校验存在 + validateWarehouseExists(updateReqVO.getId()); + // 更新 + ErpWarehouseDO updateObj = BeanUtils.toBean(updateReqVO, ErpWarehouseDO.class); + warehouseMapper.updateById(updateObj); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateWarehouseDefaultStatus(Long id, Boolean defaultStatus) { + // 1. 校验存在 + validateWarehouseExists(id); + + // 2.1 如果开启,则需要关闭所有其它的默认 + if (defaultStatus) { + ErpWarehouseDO warehouse = warehouseMapper.selectByDefaultStatus(); + if (warehouse != null) { + warehouseMapper.updateById(new ErpWarehouseDO().setId(warehouse.getId()).setDefaultStatus(false)); + } + } + // 2.2 更新对应的默认状态 + warehouseMapper.updateById(new ErpWarehouseDO().setId(id).setDefaultStatus(defaultStatus)); + } + + @Override + public void deleteWarehouse(Long id) { + // 校验存在 + validateWarehouseExists(id); + // 删除 + warehouseMapper.deleteById(id); + } + + private void validateWarehouseExists(Long id) { + if (warehouseMapper.selectById(id) == null) { + throw exception(WAREHOUSE_NOT_EXISTS); + } + } + + @Override + public ErpWarehouseDO getWarehouse(Long id) { + return warehouseMapper.selectById(id); + } + + @Override + public PageResult getWarehousePage(ErpWarehousePageReqVO pageReqVO) { + return warehouseMapper.selectPage(pageReqVO); + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/resources/mapper/stock/ErpWarehouseMapper.xml b/yudao-module-erp/yudao-module-erp-biz/src/main/resources/mapper/stock/ErpWarehouseMapper.xml new file mode 100644 index 000000000..be2bc61cb --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/resources/mapper/stock/ErpWarehouseMapper.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/test/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseServiceImplTest.java b/yudao-module-erp/yudao-module-erp-biz/src/test/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseServiceImplTest.java new file mode 100644 index 000000000..fa74620e2 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/test/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseServiceImplTest.java @@ -0,0 +1,126 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehousePageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehouseSaveReqVO; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import jakarta.annotation.Resource; + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; + +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO; +import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpWarehouseMapper; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import org.springframework.context.annotation.Import; + +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; +import static org.junit.jupiter.api.Assertions.*; + +/** + * {@link ErpWarehouseServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(ErpWarehouseServiceImpl.class) +public class ErpWarehouseServiceImplTest extends BaseDbUnitTest { + + @Resource + private ErpWarehouseServiceImpl warehouseService; + + @Resource + private ErpWarehouseMapper warehouseMapper; + + @Test + public void testCreateWarehouse_success() { + // 准备参数 + ErpWarehouseSaveReqVO createReqVO = randomPojo(ErpWarehouseSaveReqVO.class).setId(null); + + // 调用 + Long warehouseId = warehouseService.createWarehouse(createReqVO); + // 断言 + assertNotNull(warehouseId); + // 校验记录的属性是否正确 + ErpWarehouseDO warehouse = warehouseMapper.selectById(warehouseId); + assertPojoEquals(createReqVO, warehouse, "id"); + } + + @Test + public void testUpdateWarehouse_success() { + // mock 数据 + ErpWarehouseDO dbWarehouse = randomPojo(ErpWarehouseDO.class); + warehouseMapper.insert(dbWarehouse);// @Sql: 先插入出一条存在的数据 + // 准备参数 + ErpWarehouseSaveReqVO updateReqVO = randomPojo(ErpWarehouseSaveReqVO.class, o -> { + o.setId(dbWarehouse.getId()); // 设置更新的 ID + }); + + // 调用 + warehouseService.updateWarehouse(updateReqVO); + // 校验是否更新正确 + ErpWarehouseDO warehouse = warehouseMapper.selectById(updateReqVO.getId()); // 获取最新的 + assertPojoEquals(updateReqVO, warehouse); + } + + @Test + public void testUpdateWarehouse_notExists() { + // 准备参数 + ErpWarehouseSaveReqVO updateReqVO = randomPojo(ErpWarehouseSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> warehouseService.updateWarehouse(updateReqVO), WAREHOUSE_NOT_EXISTS); + } + + @Test + public void testDeleteWarehouse_success() { + // mock 数据 + ErpWarehouseDO dbWarehouse = randomPojo(ErpWarehouseDO.class); + warehouseMapper.insert(dbWarehouse);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbWarehouse.getId(); + + // 调用 + warehouseService.deleteWarehouse(id); + // 校验数据不存在了 + assertNull(warehouseMapper.selectById(id)); + } + + @Test + public void testDeleteWarehouse_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> warehouseService.deleteWarehouse(id), WAREHOUSE_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetWarehousePage() { + // mock 数据 + ErpWarehouseDO dbWarehouse = randomPojo(ErpWarehouseDO.class, o -> { // 等会查询到 + o.setName(null); + o.setStatus(null); + }); + warehouseMapper.insert(dbWarehouse); + // 测试 name 不匹配 + warehouseMapper.insert(cloneIgnoreId(dbWarehouse, o -> o.setName(null))); + // 测试 status 不匹配 + warehouseMapper.insert(cloneIgnoreId(dbWarehouse, o -> o.setStatus(null))); + // 准备参数 + ErpWarehousePageReqVO reqVO = new ErpWarehousePageReqVO(); + reqVO.setName(null); + reqVO.setStatus(null); + + // 调用 + PageResult pageResult = warehouseService.getWarehousePage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbWarehouse, pageResult.getList().get(0)); + } + +} \ No newline at end of file From 4f236c62eed1b62e1cdedd1c051e71ec8b3fb3cf Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 5 Feb 2024 19:04:44 +0800 Subject: [PATCH 03/15] =?UTF-8?q?=E2=9C=A8=20=E5=85=A8=E5=B1=80=EF=BC=9A?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=20Vue3=20+=20EP=20=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E7=9A=84=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90=E7=9A=84=E6=B3=A8?= =?UTF-8?q?=E9=87=8A=E7=9B=B8=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/codegen/vue3/api/api.ts.vm | 7 +++---- .../src/main/resources/codegen/vue3/views/form.vue.vm | 2 +- .../src/main/resources/codegen/vue3/views/index.vue.vm | 3 +-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/api/api.ts.vm b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/api/api.ts.vm index 7c2ab277b..c3044fb87 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/api/api.ts.vm +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/api/api.ts.vm @@ -5,13 +5,12 @@ import request from '@/config/axios' export interface ${simpleClassName}VO { #foreach ($column in $columns) #if ($column.createOperation || $column.updateOperation) - // ${column.columnComment} #if(${column.javaType.toLowerCase()} == "long" || ${column.javaType.toLowerCase()} == "integer" || ${column.javaType.toLowerCase()} == "short" || ${column.javaType.toLowerCase()} == "double" || ${column.javaType.toLowerCase()} == "bigdecimal") - ${column.javaField}: number + ${column.javaField}: number // ${column.columnComment} #elseif(${column.javaType.toLowerCase()} == "date" || ${column.javaType.toLowerCase()} == "localdate" || ${column.javaType.toLowerCase()} == "localdatetime") - ${column.javaField}: Date + ${column.javaField}: Date // ${column.columnComment} #else - ${column.javaField}: ${column.javaType.toLowerCase()} + ${column.javaField}: ${column.javaType.toLowerCase()} // ${column.columnComment} #end #end #end diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/form.vue.vm b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/form.vue.vm index 14a72d264..8e3596b4f 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/form.vue.vm +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/form.vue.vm @@ -244,7 +244,7 @@ const submitForm = async () => { // 提交请求 formLoading.value = true try { - const data = formData.value as unknown as ${simpleClassName}Api.${simpleClassName}VO + const data = formData.value as unknown as ${simpleClassName}VO ## 特殊:主子表专属逻辑 #if ( $table.templateType == 10 || $table.templateType == 12 ) #if ( $subTables && $subTables.size() > 0 ) diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/index.vue.vm b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/index.vue.vm index a76dbaa82..361d379fa 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/index.vue.vm +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/index.vue.vm @@ -259,8 +259,7 @@ const loading = ref(true) // 列表的加载中 const list = ref<${simpleClassName}VO[]>([]) // 列表的数据 ## 特殊:树表专属逻辑(树不需要分页接口) #if ( $table.templateType != 2 ) -// 列表的总页数 -const total = ref(0) +const total = ref(0) // 列表的总页数 #end const queryParams = reactive({ ## 特殊:树表专属逻辑(树不需要分页接口) From db79926c31b9756dc40dc754a1ab62fdc764b3c7 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 5 Feb 2024 19:24:33 +0800 Subject: [PATCH 04/15] =?UTF-8?q?=E2=9C=A8=20ERP=EF=BC=9A=E5=AE=8C?= =?UTF-8?q?=E6=88=90=20stock=20=E4=BA=A7=E5=93=81=E5=BA=93=E5=AD=98?= =?UTF-8?q?=E3=80=81=E5=BA=93=E5=AD=98=E6=98=8E=E7=BB=86=E7=9A=84=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/erp/ErrorCodeConstants.java | 32 ------ .../module/erp/enums/DictTypeConstants.java | 2 + .../module/erp/enums/ErrorCodeConstants.java | 24 +++- .../stock/ErpStockRecordBizTypeEnum.java | 41 +++++++ .../admin/product/ErpProductController.java | 58 ++++------ ...ageReqVO.java => ErpProductPageReqVO.java} | 4 +- ...oductRespVO.java => ErpProductRespVO.java} | 2 +- .../admin/stock/ErpStockController.java | 97 ++++++++++++++++ .../admin/stock/ErpStockRecordController.java | 105 ++++++++++++++++++ .../admin/stock/ErpWarehouseController.java | 8 ++ .../stock/vo/stock/ErpStockPageReqVO.java | 21 ++++ .../admin/stock/vo/stock/ErpStockRespVO.java | 49 ++++++++ .../stockrecord/ErpStockRecordPageReqVO.java | 36 ++++++ .../vo/stockrecord/ErpStockRecordRespVO.java | 87 +++++++++++++++ .../erp/dal/dataobject/stock/ErpStockDO.java | 49 ++++++++ .../dataobject/stock/ErpStockRecordDO.java | 81 ++++++++++++++ .../dal/mysql/product/ErpProductMapper.java | 10 +- .../erp/dal/mysql/stock/ErpStockMapper.java | 25 +++++ .../dal/mysql/stock/ErpStockRecordMapper.java | 28 +++++ .../dal/mysql/stock/ErpWarehouseMapper.java | 6 + .../ErpProductCategoryServiceImpl.java | 2 +- .../service/product/ErpProductService.java | 45 +++++++- .../product/ErpProductServiceImpl.java | 62 +++++++++-- .../product/ErpProductUnitServiceImpl.java | 2 +- .../service/stock/ErpStockRecordService.java | 30 +++++ .../stock/ErpStockRecordServiceImpl.java | 33 ++++++ .../erp/service/stock/ErpStockService.java | 30 +++++ .../service/stock/ErpStockServiceImpl.java | 33 ++++++ .../service/stock/ErpWarehouseService.java | 32 ++++++ .../stock/ErpWarehouseServiceImpl.java | 15 ++- .../product/ProductServiceImplTest.java | 6 +- 31 files changed, 954 insertions(+), 101 deletions(-) delete mode 100644 yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/ErrorCodeConstants.java create mode 100644 yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/stock/ErpStockRecordBizTypeEnum.java rename yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/{ProductPageReqVO.java => ErpProductPageReqVO.java} (89%) rename yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/{ProductRespVO.java => ErpProductRespVO.java} (98%) create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockController.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockRecordController.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stock/ErpStockPageReqVO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stock/ErpStockRespVO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stockrecord/ErpStockRecordPageReqVO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stockrecord/ErpStockRecordRespVO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockDO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockRecordDO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockRecordMapper.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordService.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordServiceImpl.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockService.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockServiceImpl.java diff --git a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/ErrorCodeConstants.java b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/ErrorCodeConstants.java deleted file mode 100644 index f174ed854..000000000 --- a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/ErrorCodeConstants.java +++ /dev/null @@ -1,32 +0,0 @@ -package cn.iocoder.yudao.module.erp; - -import cn.iocoder.yudao.framework.common.exception.ErrorCode; - -/** - * ERP 错误码枚举类 - *

- * erp 系统,使用 1-030-000-000 段 - */ -public interface ErrorCodeConstants { - - // ========== ERP 仓库 1-030-400-000 ========== - ErrorCode WAREHOUSE_NOT_EXISTS = new ErrorCode(1_030_400_000, "仓库不存在"); - - // ========== ERP 产品 1-030-500-000 ========== - ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_030_500_000, "产品不存在"); - - // ========== ERP 产品分类 1-030-501-000 ========== - ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_030_501_000, "产品分类不存在"); - ErrorCode PRODUCT_CATEGORY_EXITS_CHILDREN = new ErrorCode(1_030_501_001, "存在存在子产品分类,无法删除"); - ErrorCode PRODUCT_CATEGORY_PARENT_NOT_EXITS = new ErrorCode(1_030_501_002,"父级产品分类不存在"); - ErrorCode PRODUCT_CATEGORY_PARENT_ERROR = new ErrorCode(1_030_501_003, "不能设置自己为父产品分类"); - ErrorCode PRODUCT_CATEGORY_NAME_DUPLICATE = new ErrorCode(1_030_501_004, "已经存在该分类名称的产品分类"); - ErrorCode PRODUCT_CATEGORY_PARENT_IS_CHILD = new ErrorCode(1_030_501_005, "不能设置自己的子分类为父分类"); - ErrorCode PRODUCT_CATEGORY_EXITS_PRODUCT = new ErrorCode(1_030_502_002, "存在产品使用该分类,无法删除"); - - // ========== ERP 产品单位 1-030-502-000 ========== - ErrorCode PRODUCT_UNIT_NOT_EXISTS = new ErrorCode(1_030_502_000, "产品单位不存在"); - ErrorCode PRODUCT_UNIT_NAME_DUPLICATE = new ErrorCode(1_030_502_001, "已存在该名字的产品单位"); - ErrorCode PRODUCT_UNIT_EXITS_PRODUCT = new ErrorCode(1_030_502_002, "存在产品使用该单位,无法删除"); - -} diff --git a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/DictTypeConstants.java b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/DictTypeConstants.java index 87b498543..af7033895 100644 --- a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/DictTypeConstants.java +++ b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/DictTypeConstants.java @@ -7,4 +7,6 @@ package cn.iocoder.yudao.module.erp.enums; */ public interface DictTypeConstants { + String STOCK_RECORD_BIZ_TYPE = "erp_stock_record_biz_type"; // 库存明细的业务类型 + } diff --git a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java index 7b11fa0a5..51cae4ad9 100644 --- a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java +++ b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java @@ -9,7 +9,27 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode; */ public interface ErrorCodeConstants { - // ========== 销售订单(1-030-000-000) ========== - ErrorCode SALE_ORDER_NOT_EXISTS = new ErrorCode(1_030_000_000, "销售订单不存在"); + // ========== 销售订单(1-020-000-000) ========== + ErrorCode SALE_ORDER_NOT_EXISTS = new ErrorCode(1_020_000_000, "销售订单不存在"); + + // ========== ERP 仓库 1-030-400-000 ========== + ErrorCode WAREHOUSE_NOT_EXISTS = new ErrorCode(1_030_400_000, "仓库不存在"); + + // ========== ERP 产品 1-030-500-000 ========== + ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_030_500_000, "产品不存在"); + + // ========== ERP 产品分类 1-030-501-000 ========== + ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_030_501_000, "产品分类不存在"); + ErrorCode PRODUCT_CATEGORY_EXITS_CHILDREN = new ErrorCode(1_030_501_001, "存在存在子产品分类,无法删除"); + ErrorCode PRODUCT_CATEGORY_PARENT_NOT_EXITS = new ErrorCode(1_030_501_002,"父级产品分类不存在"); + ErrorCode PRODUCT_CATEGORY_PARENT_ERROR = new ErrorCode(1_030_501_003, "不能设置自己为父产品分类"); + ErrorCode PRODUCT_CATEGORY_NAME_DUPLICATE = new ErrorCode(1_030_501_004, "已经存在该分类名称的产品分类"); + ErrorCode PRODUCT_CATEGORY_PARENT_IS_CHILD = new ErrorCode(1_030_501_005, "不能设置自己的子分类为父分类"); + ErrorCode PRODUCT_CATEGORY_EXITS_PRODUCT = new ErrorCode(1_030_502_002, "存在产品使用该分类,无法删除"); + + // ========== ERP 产品单位 1-030-502-000 ========== + ErrorCode PRODUCT_UNIT_NOT_EXISTS = new ErrorCode(1_030_502_000, "产品单位不存在"); + ErrorCode PRODUCT_UNIT_NAME_DUPLICATE = new ErrorCode(1_030_502_001, "已存在该名字的产品单位"); + ErrorCode PRODUCT_UNIT_EXITS_PRODUCT = new ErrorCode(1_030_502_002, "存在产品使用该单位,无法删除"); } diff --git a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/stock/ErpStockRecordBizTypeEnum.java b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/stock/ErpStockRecordBizTypeEnum.java new file mode 100644 index 000000000..fb16934d9 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/stock/ErpStockRecordBizTypeEnum.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.erp.enums.stock; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * ERP 库存明细 - 业务类型枚举 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +@Getter +public enum ErpStockRecordBizTypeEnum implements IntArrayValuable { + + OTHER_IN(10, "其它入库"), + OTHER_IN_CANCEL(11, "其它入库(作废)"), + + OTHER_OUT(20, "其它出库"), + OTHER_OUT_CANCEL(21, "其它出库(作废)"), + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ErpStockRecordBizTypeEnum::getType).toArray(); + + /** + * 类型 + */ + private final Integer type; + /** + * 名字 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductController.java index 30135a6fe..63977890c 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductController.java @@ -1,22 +1,17 @@ package cn.iocoder.yudao.module.erp.controller.admin.product; -import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.MapUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; -import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductPageReqVO; -import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductSaveReqVO; -import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductCategoryDO; import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; -import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO; -import cn.iocoder.yudao.module.erp.service.product.ErpProductCategoryService; import cn.iocoder.yudao.module.erp.service.product.ErpProductService; -import cn.iocoder.yudao.module.erp.service.product.ErpProductUnitService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -28,10 +23,9 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import java.io.IOException; -import java.util.Map; +import java.util.List; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; @Tag(name = "管理后台 - ERP 产品") @@ -42,10 +36,6 @@ public class ErpProductController { @Resource private ErpProductService productService; - @Resource - private ErpProductCategoryService productCategoryService; - @Resource - private ErpProductUnitService productUnitService; @PostMapping("/create") @Operation(summary = "创建产品") @@ -75,46 +65,36 @@ public class ErpProductController { @Operation(summary = "获得产品") @Parameter(name = "id", description = "编号", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('erp:product:query')") - public CommonResult getProduct(@RequestParam("id") Long id) { + public CommonResult getProduct(@RequestParam("id") Long id) { ErpProductDO product = productService.getProduct(id); - return success(BeanUtils.toBean(product, ProductRespVO.class)); + return success(BeanUtils.toBean(product, ErpProductRespVO.class)); } @GetMapping("/page") @Operation(summary = "获得产品分页") @PreAuthorize("@ss.hasPermission('erp:product:query')") - public CommonResult> getProductPage(@Valid ProductPageReqVO pageReqVO) { - PageResult pageResult = productService.getProductPage(pageReqVO); - return success(buildProductDetailPage(pageResult)); + public CommonResult> getProductPage(@Valid ErpProductPageReqVO pageReqVO) { + return success(productService.getProductVOPage(pageReqVO)); + } + + @GetMapping("/simple-list") + @Operation(summary = "获得产品精简列表", description = "只包含被开启的产品,主要用于前端的下拉选项") + public CommonResult> getProductSimpleList() { + List list = productService.getProductListByStatus(CommonStatusEnum.ENABLE.getStatus()); + return success(BeanUtils.toBean(list, ErpProductRespVO.class)); } @GetMapping("/export-excel") @Operation(summary = "导出产品 Excel") @PreAuthorize("@ss.hasPermission('erp:product:export')") @OperateLog(type = EXPORT) - public void exportProductExcel(@Valid ProductPageReqVO pageReqVO, + public void exportProductExcel(@Valid ErpProductPageReqVO pageReqVO, HttpServletResponse response) throws IOException { pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); - PageResult pageResult = productService.getProductPage(pageReqVO); + PageResult pageResult = productService.getProductVOPage(pageReqVO); // 导出 Excel - ExcelUtils.write(response, "产品.xls", "数据", ProductRespVO.class, - buildProductDetailPage(pageResult).getList()); - } - - private PageResult buildProductDetailPage(PageResult pageResult) { - if (CollUtil.isEmpty(pageResult.getList())) { - return PageResult.empty(pageResult.getTotal()); - } - Map categoryMap = productCategoryService.getProductCategoryMap( - convertSet(pageResult.getList(), ErpProductDO::getCategoryId)); - Map unitMap = productUnitService.getProductUnitMap( - convertSet(pageResult.getList(), ErpProductDO::getUnitId)); - return BeanUtils.toBean(pageResult, ProductRespVO.class, product -> { - MapUtils.findAndThen(categoryMap, product.getCategoryId(), - category -> product.setCategoryName(category.getName())); - MapUtils.findAndThen(unitMap, product.getUnitId(), - unit -> product.setUnitName(unit.getName())); - }); + ExcelUtils.write(response, "产品.xls", "数据", ErpProductRespVO.class, + pageResult.getList()); } } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ProductPageReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductPageReqVO.java similarity index 89% rename from yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ProductPageReqVO.java rename to yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductPageReqVO.java index eb560603b..de4f8142a 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ProductPageReqVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductPageReqVO.java @@ -1,10 +1,8 @@ package cn.iocoder.yudao.module.erp.controller.admin.product.vo.product; import lombok.*; -import java.util.*; import io.swagger.v3.oas.annotations.media.Schema; import cn.iocoder.yudao.framework.common.pojo.PageParam; -import java.math.BigDecimal; import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDateTime; @@ -14,7 +12,7 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) -public class ProductPageReqVO extends PageParam { +public class ErpProductPageReqVO extends PageParam { @Schema(description = "产品名称", example = "李四") private String name; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ProductRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductRespVO.java similarity index 98% rename from yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ProductRespVO.java rename to yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductRespVO.java index f6f255c09..9be9bc255 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ProductRespVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductRespVO.java @@ -11,7 +11,7 @@ import java.time.LocalDateTime; @Schema(description = "管理后台 - ERP 产品 Response VO") @Data @ExcelIgnoreUnannotated -public class ProductRespVO { +public class ErpProductRespVO { @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15672") @ExcelProperty("产品编号") diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockController.java new file mode 100644 index 000000000..18bf063d3 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockController.java @@ -0,0 +1,97 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stock.ErpStockPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stock.ErpStockRespVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.stock.ErpStockService; +import cn.iocoder.yudao.module.erp.service.stock.ErpWarehouseService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +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.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; + +@Tag(name = "管理后台 - ERP 产品库存") +@RestController +@RequestMapping("/erp/stock") +@Validated +public class ErpStockController { + + @Resource + private ErpStockService stockService; + @Resource + private ErpProductService productService; + @Resource + private ErpWarehouseService warehouseService; + + @GetMapping("/get") + @Operation(summary = "获得产品库存") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('erp:stock:query')") + public CommonResult getStock(@RequestParam("id") Long id) { + ErpStockDO stock = stockService.getStock(id); + return success(BeanUtils.toBean(stock, ErpStockRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得产品库存分页") + @PreAuthorize("@ss.hasPermission('erp:stock:query')") + public CommonResult> getStockPage(@Valid ErpStockPageReqVO pageReqVO) { + PageResult pageResult = stockService.getStockPage(pageReqVO); + return success(buildStockVOPageResult(pageResult)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出产品库存 Excel") + @PreAuthorize("@ss.hasPermission('erp:stock:export')") + @OperateLog(type = EXPORT) + public void exportStockExcel(@Valid ErpStockPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = buildStockVOPageResult(stockService.getStockPage(pageReqVO)).getList(); + // 导出 Excel + ExcelUtils.write(response, "产品库存.xls", "数据", ErpStockRespVO.class, list); + } + + private PageResult buildStockVOPageResult(PageResult pageResult) { + if (CollUtil.isEmpty(pageResult.getList())) { + return PageResult.empty(pageResult.getTotal()); + } + Map productMap = productService.getProductVOMap( + convertSet(pageResult.getList(), ErpStockDO::getProductId)); + Map warehouseMap = warehouseService.getWarehouseMap( + convertSet(pageResult.getList(), ErpStockDO::getWarehouseId)); + return BeanUtils.toBean(pageResult, ErpStockRespVO.class, stock -> { + MapUtils.findAndThen(productMap, stock.getProductId(), product -> stock.setProductName(product.getName()) + .setCategoryName(product.getCategoryName()).setUnitName(product.getUnitName())); + MapUtils.findAndThen(warehouseMap, stock.getWarehouseId(), warehouse -> stock.setWarehouseName(warehouse.getName())); + }); + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockRecordController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockRecordController.java new file mode 100644 index 000000000..e92856378 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockRecordController.java @@ -0,0 +1,105 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stockrecord.ErpStockRecordPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stockrecord.ErpStockRecordRespVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockRecordDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.stock.ErpStockRecordService; +import cn.iocoder.yudao.module.erp.service.stock.ErpWarehouseService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +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.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; + +@Tag(name = "管理后台 - ERP 产品库存明细") +@RestController +@RequestMapping("/erp/stock-record") +@Validated +public class ErpStockRecordController { + + @Resource + private ErpStockRecordService stockRecordService; + @Resource + private ErpProductService productService; + @Resource + private ErpWarehouseService warehouseService; + + @Resource + private AdminUserApi adminUserApi; + + @GetMapping("/get") + @Operation(summary = "获得产品库存明细") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('erp:stock-record:query')") + public CommonResult getStockRecord(@RequestParam("id") Long id) { + ErpStockRecordDO stockRecord = stockRecordService.getStockRecord(id); + return success(BeanUtils.toBean(stockRecord, ErpStockRecordRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得产品库存明细分页") + @PreAuthorize("@ss.hasPermission('erp:stock-record:query')") + public CommonResult> getStockRecordPage(@Valid ErpStockRecordPageReqVO pageReqVO) { + PageResult pageResult = stockRecordService.getStockRecordPage(pageReqVO); + return success(buildStockRecrodVOPageResult(pageResult)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出产品库存明细 Excel") + @PreAuthorize("@ss.hasPermission('erp:stock-record:export')") + @OperateLog(type = EXPORT) + public void exportStockRecordExcel(@Valid ErpStockRecordPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = buildStockRecrodVOPageResult(stockRecordService.getStockRecordPage(pageReqVO)).getList(); + // 导出 Excel + ExcelUtils.write(response, "产品库存明细.xls", "数据", ErpStockRecordRespVO.class, list); + } + + private PageResult buildStockRecrodVOPageResult(PageResult pageResult) { + if (CollUtil.isEmpty(pageResult.getList())) { + return PageResult.empty(pageResult.getTotal()); + } + Map productMap = productService.getProductVOMap( + convertSet(pageResult.getList(), ErpStockRecordDO::getProductId)); + Map warehouseMap = warehouseService.getWarehouseMap( + convertSet(pageResult.getList(), ErpStockRecordDO::getWarehouseId)); + Map userMap = adminUserApi.getUserMap( + convertSet(pageResult.getList(), erpStockRecordDO -> Long.parseLong(erpStockRecordDO.getCreator()))); + return BeanUtils.toBean(pageResult, ErpStockRecordRespVO.class, stock -> { + MapUtils.findAndThen(productMap, stock.getProductId(), product -> stock.setProductName(product.getName()) + .setCategoryName(product.getCategoryName()).setUnitName(product.getUnitName())); + MapUtils.findAndThen(warehouseMap, stock.getWarehouseId(), warehouse -> stock.setWarehouseName(warehouse.getName())); + MapUtils.findAndThen(userMap, Long.parseLong(stock.getCreator()), user -> stock.setCreatorName(user.getNickname())); + }); + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpWarehouseController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpWarehouseController.java index 8877780d8..32c33075d 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpWarehouseController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpWarehouseController.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.erp.controller.admin.stock; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; @@ -90,6 +91,13 @@ public class ErpWarehouseController { return success(BeanUtils.toBean(pageResult, ErpWarehouseRespVO.class)); } + @GetMapping("/simple-list") + @Operation(summary = "获得仓库精简列表", description = "只包含被开启的仓库,主要用于前端的下拉选项") + public CommonResult> getWarehouseSimpleList() { + List list = warehouseService.getWarehouseListByStatus(CommonStatusEnum.ENABLE.getStatus()); + return success(BeanUtils.toBean(list, ErpWarehouseRespVO.class)); + } + @GetMapping("/export-excel") @Operation(summary = "导出仓库 Excel") @PreAuthorize("@ss.hasPermission('erp:warehouse:export')") diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stock/ErpStockPageReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stock/ErpStockPageReqVO.java new file mode 100644 index 000000000..f7f3fa343 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stock/ErpStockPageReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - ERP 库存分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ErpStockPageReqVO extends PageParam { + + @Schema(description = "产品编号", example = "19614") + private Long productId; + + @Schema(description = "仓库编号", example = "2802") + private Long warehouseId; + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stock/ErpStockRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stock/ErpStockRespVO.java new file mode 100644 index 000000000..06366a0dd --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stock/ErpStockRespVO.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stock; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; + +@Schema(description = "管理后台 - ERP 库存 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ErpStockRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17086") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "19614") + private Long productId; + + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2802") + private Long warehouseId; + + @Schema(description = "库存数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "21935") + @ExcelProperty("库存数量") + private BigDecimal count; + + // ========== 产品信息 ========== + + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "苹果") + @ExcelProperty("产品名称") + private String productName; + + @Schema(description = "产品分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "水果") + @ExcelProperty("产品分类") + private String categoryName; + + @Schema(description = "单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "个") + @ExcelProperty("单位") + private String unitName; + + // ========== 仓库信息 ========== + + @Schema(description = "仓库名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @ExcelProperty("仓库名称") + private String warehouseName; + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stockrecord/ErpStockRecordPageReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stockrecord/ErpStockRecordPageReqVO.java new file mode 100644 index 000000000..b9030f821 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stockrecord/ErpStockRecordPageReqVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stockrecord; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - ERP 产品库存明细分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ErpStockRecordPageReqVO extends PageParam { + + @Schema(description = "产品编号", example = "10625") + private Long productId; + + @Schema(description = "仓库编号", example = "32407") + private Long warehouseId; + + @Schema(description = "业务类型", example = "10") + private Integer bizType; + + @Schema(description = "业务单号", example = "Z110") + private String bizNo; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stockrecord/ErpStockRecordRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stockrecord/ErpStockRecordRespVO.java new file mode 100644 index 000000000..0073fafba --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stockrecord/ErpStockRecordRespVO.java @@ -0,0 +1,87 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stockrecord; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.erp.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - ERP 产品库存明细 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ErpStockRecordRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18909") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10625") + private Long productId; + + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "32407") + private Long warehouseId; + + @Schema(description = "出入库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "11084") + @ExcelProperty("出入库数量") + private BigDecimal count; + + @Schema(description = "总库存量", requiredMode = Schema.RequiredMode.REQUIRED, example = "4307") + @ExcelProperty("总库存量") + private BigDecimal totalCount; + + @Schema(description = "业务类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @ExcelProperty(value = "业务类型", converter = DictConvert.class) + @DictFormat(DictTypeConstants.STOCK_RECORD_BIZ_TYPE) + private Integer bizType; + + @Schema(description = "业务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "27093") + @ExcelProperty("业务编号") + private Long bizId; + + @Schema(description = "业务项编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23516") + @ExcelProperty("业务项编号") + private Long bizItemId; + + @Schema(description = "业务单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "Z110") + @ExcelProperty("业务单号") + private String bizNo; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "创建人", requiredMode = Schema.RequiredMode.REQUIRED, example = "25682") + private String creator; + + // ========== 产品信息 ========== + + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "苹果") + @ExcelProperty("产品名称") + private String productName; + + @Schema(description = "产品分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "水果") + @ExcelProperty("产品分类") + private String categoryName; + + @Schema(description = "单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "个") + @ExcelProperty("单位") + private String unitName; + + // ========== 仓库信息 ========== + + @Schema(description = "仓库名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @ExcelProperty("仓库名称") + private String warehouseName; + + // ========== 用户信息 ========== + + @Schema(description = "创建人", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三") + @ExcelProperty("创建人") + private String creatorName; + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockDO.java new file mode 100644 index 000000000..558c6c6e5 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockDO.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.stock; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * ERP 产品库存 DO + * + * @author 芋道源码 + */ +@TableName("erp_stock") +@KeySequence("erp_stock_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpStockDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 产品编号 + * + * 关联 {@link ErpProductDO#getId()} + */ + private Long productId; + /** + * 仓库编号 + * + * 关联 {@link ErpWarehouseDO#getId()} + */ + private Long warehouseId; + /** + * 库存数量 + */ + private BigDecimal count; + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockRecordDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockRecordDO.java new file mode 100644 index 000000000..be010eb04 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockRecordDO.java @@ -0,0 +1,81 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.stock; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * ERP 产品库存明细 DO + * + * @author 芋道源码 + */ +@TableName("erp_stock_record") +@KeySequence("erp_stock_record_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpStockRecordDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 产品编号 + * + * 关联 {@link ErpProductDO#getId()} + */ + private Long productId; + /** + * 仓库编号 + * + * 关联 {@link ErpWarehouseDO#getId()} + */ + private Long warehouseId; + /** + * 出入库数量 + * + * 正数,表示入库;负数,表示出库 + */ + private BigDecimal count; + /** + * 总库存量 + * + * 出入库之后,目前的库存量 + */ + private BigDecimal totalCount; + /** + * 业务类型 + * + * 枚举 {@link cn.iocoder.yudao.module.erp.enums.stock.ErpStockRecordBizTypeEnum} + */ + private Integer bizType; + /** + * 业务编号 + * + * 例如说:TODO + */ + private Long bizId; + /** + * 业务项编号 + * + * 例如说:TODO + */ + private Long bizItemId; + /** + * 业务单号 + * + * 例如说:TODO + */ + private String bizNo; + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductMapper.java index 81bca5cf9..ff491fe22 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductMapper.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductMapper.java @@ -3,10 +3,12 @@ package cn.iocoder.yudao.module.erp.dal.mysql.product; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductPageReqVO; import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; import org.apache.ibatis.annotations.Mapper; +import java.util.List; + /** * ERP 产品 Mapper * @@ -15,7 +17,7 @@ import org.apache.ibatis.annotations.Mapper; @Mapper public interface ErpProductMapper extends BaseMapperX { - default PageResult selectPage(ProductPageReqVO reqVO) { + default PageResult selectPage(ErpProductPageReqVO reqVO) { return selectPage(reqVO, new LambdaQueryWrapperX() .likeIfPresent(ErpProductDO::getName, reqVO.getName()) .eqIfPresent(ErpProductDO::getCategoryId, reqVO.getCategoryId()) @@ -31,4 +33,8 @@ public interface ErpProductMapper extends BaseMapperX { return selectCount(ErpProductDO::getUnitId, unitId); } + default List selectListByStatus(Integer status) { + return selectList(ErpProductDO::getStatus, status); + } + } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java new file mode 100644 index 000000000..c634f9780 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stock.ErpStockPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * ERP 产品库存 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpStockMapper extends BaseMapperX { + + default PageResult selectPage(ErpStockPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(ErpStockDO::getProductId, reqVO.getProductId()) + .eqIfPresent(ErpStockDO::getWarehouseId, reqVO.getWarehouseId()) + .orderByDesc(ErpStockDO::getId)); + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockRecordMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockRecordMapper.java new file mode 100644 index 000000000..6c5c48fd0 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockRecordMapper.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stockrecord.ErpStockRecordPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockRecordDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * ERP 产品库存明细 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpStockRecordMapper extends BaseMapperX { + + default PageResult selectPage(ErpStockRecordPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(ErpStockRecordDO::getProductId, reqVO.getProductId()) + .eqIfPresent(ErpStockRecordDO::getWarehouseId, reqVO.getWarehouseId()) + .eqIfPresent(ErpStockRecordDO::getBizType, reqVO.getBizType()) + .likeIfPresent(ErpStockRecordDO::getBizNo, reqVO.getBizNo()) + .betweenIfPresent(ErpStockRecordDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(ErpStockRecordDO::getId)); + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpWarehouseMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpWarehouseMapper.java index 7d3bf0d3e..0442011f2 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpWarehouseMapper.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpWarehouseMapper.java @@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWareho import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO; import org.apache.ibatis.annotations.Mapper; +import java.util.List; + /** * ERP 仓库 Mapper * @@ -26,4 +28,8 @@ public interface ErpWarehouseMapper extends BaseMapperX { return selectOne(ErpWarehouseDO::getDefaultStatus, true); } + default List selectListByStatus(Integer status) { + return selectList(ErpWarehouseDO::getStatus, status); + } + } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductCategoryServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductCategoryServiceImpl.java index 28d8b3172..bad19a0ee 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductCategoryServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductCategoryServiceImpl.java @@ -15,7 +15,7 @@ import java.util.List; import java.util.Objects; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.erp.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; /** * ERP 产品分类 Service 实现类 diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductService.java index 3a2e08ce6..9fa18a073 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductService.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductService.java @@ -1,10 +1,17 @@ package cn.iocoder.yudao.module.erp.service.product; -import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductPageReqVO; -import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductSaveReqVO; -import jakarta.validation.*; -import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import jakarta.validation.Valid; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; /** * ERP 产品 Service 接口 @@ -44,12 +51,38 @@ public interface ErpProductService { ErpProductDO getProduct(Long id); /** - * 获得产品分页 + * 获得指定状态的产品列表 + * + * @param status 状态 + * @return 产品列表 + */ + List getProductListByStatus(Integer status); + + /** + * 获得产品 VO 列表 + * + * @param ids 编号数组 + * @return 产品 VO 列表 + */ + List getProductVOList(Collection ids); + + /** + * 获得产品 VO Map + * + * @param ids 编号数组 + * @return 产品 VO Map + */ + default Map getProductVOMap(Collection ids) { + return convertMap(getProductVOList(ids), ErpProductRespVO::getId); + } + + /** + * 获得产品 VO 分页 * * @param pageReqVO 分页查询 * @return 产品分页 */ - PageResult getProductPage(ProductPageReqVO pageReqVO); + PageResult getProductVOPage(ErpProductPageReqVO pageReqVO); /** * 基于产品分类编号,获得产品数量 diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java index 3efb981e3..58c7b7c3b 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java @@ -1,19 +1,28 @@ package cn.iocoder.yudao.module.erp.service.product; -import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductPageReqVO; +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductSaveReqVO; -import org.springframework.stereotype.Service; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductCategoryDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO; +import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductMapper; import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; -import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; - -import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductMapper; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.erp.ErrorCodeConstants.PRODUCT_NOT_EXISTS; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.PRODUCT_NOT_EXISTS; /** * ERP 产品 Service 实现类 @@ -27,6 +36,11 @@ public class ErpProductServiceImpl implements ErpProductService { @Resource private ErpProductMapper productMapper; + @Resource + private ErpProductCategoryService productCategoryService; + @Resource + private ErpProductUnitService productUnitService; + @Override public Long createProduct(ProductSaveReqVO createReqVO) { // 插入 @@ -65,8 +79,36 @@ public class ErpProductServiceImpl implements ErpProductService { } @Override - public PageResult getProductPage(ProductPageReqVO pageReqVO) { - return productMapper.selectPage(pageReqVO); + public List getProductListByStatus(Integer status) { + return productMapper.selectListByStatus(status); + } + + @Override + public List getProductVOList(Collection ids) { + List list = productMapper.selectBatchIds(ids); + return buildProductVOList(list); + } + + @Override + public PageResult getProductVOPage(ErpProductPageReqVO pageReqVO) { + PageResult pageResult = productMapper.selectPage(pageReqVO); + return new PageResult<>(buildProductVOList(pageResult.getList()), pageResult.getTotal()); + } + + private List buildProductVOList(List list) { + if (CollUtil.isEmpty(list)) { + return Collections.emptyList(); + } + Map categoryMap = productCategoryService.getProductCategoryMap( + convertSet(list, ErpProductDO::getCategoryId)); + Map unitMap = productUnitService.getProductUnitMap( + convertSet(list, ErpProductDO::getUnitId)); + return BeanUtils.toBean(list, ErpProductRespVO.class, product -> { + MapUtils.findAndThen(categoryMap, product.getCategoryId(), + category -> product.setCategoryName(category.getName())); + MapUtils.findAndThen(unitMap, product.getUnitId(), + unit -> product.setUnitName(unit.getName())); + }); } @Override diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitServiceImpl.java index 1ab412b11..87d78a54f 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitServiceImpl.java @@ -16,7 +16,7 @@ import java.util.Collection; import java.util.List; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.erp.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; /** * ERP 产品单位 Service 实现类 diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordService.java new file mode 100644 index 000000000..8b90a0e4c --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordService.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stockrecord.ErpStockRecordPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockRecordDO; + +/** + * ERP 产品库存明细 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpStockRecordService { + + /** + * 获得产品库存明细 + * + * @param id 编号 + * @return 产品库存明细 + */ + ErpStockRecordDO getStockRecord(Long id); + + /** + * 获得产品库存明细分页 + * + * @param pageReqVO 分页查询 + * @return 产品库存明细分页 + */ + PageResult getStockRecordPage(ErpStockRecordPageReqVO pageReqVO); + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordServiceImpl.java new file mode 100644 index 000000000..0adc7c864 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordServiceImpl.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stockrecord.ErpStockRecordPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockRecordDO; +import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockRecordMapper; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +/** + * ERP 产品库存明细 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ErpStockRecordServiceImpl implements ErpStockRecordService { + + @Resource + private ErpStockRecordMapper stockRecordMapper; + + @Override + public ErpStockRecordDO getStockRecord(Long id) { + return stockRecordMapper.selectById(id); + } + + @Override + public PageResult getStockRecordPage(ErpStockRecordPageReqVO pageReqVO) { + return stockRecordMapper.selectPage(pageReqVO); + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockService.java new file mode 100644 index 000000000..041aca6d5 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockService.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stock.ErpStockPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; + +/** + * ERP 产品库存 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpStockService { + + /** + * 获得产品库存 + * + * @param id 编号 + * @return 库存 + */ + ErpStockDO getStock(Long id); + + /** + * 获得产品库存分页 + * + * @param pageReqVO 分页查询 + * @return 库存分页 + */ + PageResult getStockPage(ErpStockPageReqVO pageReqVO); + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockServiceImpl.java new file mode 100644 index 000000000..7ee4a3fc0 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockServiceImpl.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stock.ErpStockPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; +import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockMapper; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +/** + * ERP 产品库存 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ErpStockServiceImpl implements ErpStockService { + + @Resource + private ErpStockMapper stockMapper; + + @Override + public ErpStockDO getStock(Long id) { + return stockMapper.selectById(id); + } + + @Override + public PageResult getStockPage(ErpStockPageReqVO pageReqVO) { + return stockMapper.selectPage(pageReqVO); + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseService.java index 47e4dbed2..6f9d3c8fa 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseService.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseService.java @@ -6,6 +6,12 @@ import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWareho import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO; import jakarta.validation.Valid; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + /** * ERP 仓库 Service 接口 * @@ -51,6 +57,32 @@ public interface ErpWarehouseService { */ ErpWarehouseDO getWarehouse(Long id); + /** + * 获得指定状态的仓库列表 + * + * @param status 状态 + * @return 仓库列表 + */ + List getWarehouseListByStatus(Integer status); + + /** + * 获得仓库列表 + * + * @param ids 编号数组 + * @return 仓库列表 + */ + List getWarehouseList(Collection ids); + + /** + * 获得仓库 Map + * + * @param ids 编号数组 + * @return 仓库 Map + */ + default Map getWarehouseMap(Collection ids) { + return convertMap(getWarehouseList(ids), ErpWarehouseDO::getId); + } + /** * 获得仓库分页 * diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseServiceImpl.java index e4c34ade4..e2f6d7667 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseServiceImpl.java @@ -11,8 +11,11 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; +import java.util.Collection; +import java.util.List; + import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.erp.ErrorCodeConstants.WAREHOUSE_NOT_EXISTS; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.WAREHOUSE_NOT_EXISTS; /** * ERP 仓库 Service 实现类 @@ -80,6 +83,16 @@ public class ErpWarehouseServiceImpl implements ErpWarehouseService { return warehouseMapper.selectById(id); } + @Override + public List getWarehouseListByStatus(Integer status) { + return warehouseMapper.selectListByStatus(status); + } + + @Override + public List getWarehouseList(Collection ids) { + return warehouseMapper.selectBatchIds(ids); + } + @Override public PageResult getWarehousePage(ErpWarehousePageReqVO pageReqVO) { return warehouseMapper.selectPage(pageReqVO); diff --git a/yudao-module-erp/yudao-module-erp-biz/src/test/java/cn/iocoder/yudao/module/erp/service/product/ProductServiceImplTest.java b/yudao-module-erp/yudao-module-erp-biz/src/test/java/cn/iocoder/yudao/module/erp/service/product/ProductServiceImplTest.java index 03298bcc3..5045dbfb0 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/test/java/cn/iocoder/yudao/module/erp/service/product/ProductServiceImplTest.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/test/java/cn/iocoder/yudao/module/erp/service/product/ProductServiceImplTest.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.erp.service.product; -import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductPageReqVO; import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductSaveReqVO; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -115,13 +115,13 @@ public class ProductServiceImplTest extends BaseDbUnitTest { // 测试 createTime 不匹配 productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setCreateTime(null))); // 准备参数 - ProductPageReqVO reqVO = new ProductPageReqVO(); + ErpProductPageReqVO reqVO = new ErpProductPageReqVO(); reqVO.setName(null); reqVO.setCategoryId(null); reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); // 调用 - PageResult pageResult = productService.getProductPage(reqVO); + PageResult pageResult = productService.getProductVOPage(reqVO); // 断言 assertEquals(1, pageResult.getTotal()); assertEquals(1, pageResult.getList().size()); From 46d26659bf49b6457be3cad084979e90c43d2d54 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 6 Feb 2024 15:58:29 +0800 Subject: [PATCH 05/15] =?UTF-8?q?=E2=9C=A8=20ERP=EF=BC=9A=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E5=8C=96=E5=85=B6=E5=AE=83=E5=85=A5=E5=BA=93=E7=9A=84?= =?UTF-8?q?=E8=A1=A8=E5=8D=95=2050%?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/erp/enums/DictTypeConstants.java | 1 + .../module/erp/enums/ErpAuditStatus.java | 39 +++++ .../module/erp/enums/ErrorCodeConstants.java | 5 + .../admin/product/ErpProductController.java | 9 +- .../admin/stock/ErpStockController.java | 13 +- .../admin/stock/ErpStockInController.java | 145 ++++++++++++++++ .../admin/stock/ErpStockRecordController.java | 4 +- .../stock/vo/in/ErpStockInPageReqVO.java | 42 +++++ .../admin/stock/vo/in/ErpStockInRespVO.java | 106 ++++++++++++ .../stock/vo/in/ErpStockInSaveReqVO.java | 69 ++++++++ .../ErpStockRecordPageReqVO.java | 2 +- .../ErpStockRecordRespVO.java | 2 +- .../dal/dataobject/stock/ErpStockInDO.java | 69 ++++++++ .../dataobject/stock/ErpStockInItemDO.java | 73 ++++++++ .../dal/mysql/stock/ErpStockInItemMapper.java | 30 ++++ .../erp/dal/mysql/stock/ErpStockInMapper.java | 29 ++++ .../erp/dal/mysql/stock/ErpStockMapper.java | 5 + .../dal/mysql/stock/ErpStockRecordMapper.java | 2 +- .../service/product/ErpProductService.java | 14 +- .../product/ErpProductServiceImpl.java | 34 +++- .../erp/service/stock/ErpStockInService.java | 76 ++++++++ .../service/stock/ErpStockInServiceImpl.java | 162 ++++++++++++++++++ .../service/stock/ErpStockRecordService.java | 2 +- .../stock/ErpStockRecordServiceImpl.java | 2 +- .../erp/service/stock/ErpStockService.java | 9 + .../service/stock/ErpStockServiceImpl.java | 5 + .../service/stock/ErpWarehouseService.java | 8 + .../stock/ErpWarehouseServiceImpl.java | 27 ++- 28 files changed, 960 insertions(+), 24 deletions(-) create mode 100644 yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErpAuditStatus.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockInController.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInPageReqVO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInRespVO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInSaveReqVO.java rename yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/{stockrecord => record}/ErpStockRecordPageReqVO.java (93%) rename yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/{stockrecord => record}/ErpStockRecordRespVO.java (97%) create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockInDO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockInItemDO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockInItemMapper.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockInMapper.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInService.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java diff --git a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/DictTypeConstants.java b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/DictTypeConstants.java index af7033895..36d4df852 100644 --- a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/DictTypeConstants.java +++ b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/DictTypeConstants.java @@ -7,6 +7,7 @@ package cn.iocoder.yudao.module.erp.enums; */ public interface DictTypeConstants { + String AUDIT_STATUS = "erp_audit_status"; // 审核状态 String STOCK_RECORD_BIZ_TYPE = "erp_stock_record_biz_type"; // 库存明细的业务类型 } diff --git a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErpAuditStatus.java b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErpAuditStatus.java new file mode 100644 index 000000000..a10147a70 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErpAuditStatus.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.erp.enums; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * ERP 审核状态枚举 + * + * TODO 芋艿:目前只有待审批、已审批两个状态,未来接入工作流后,会丰富下:待提交(草稿)=》已提交(待审核)=》审核通过、审核不通过;另外,工作流需要支持“反审核”,把工作流退回到原点; + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +@Getter +public enum ErpAuditStatus implements IntArrayValuable { + + PROCESS(10, "未审核"), // 审核中 + APPROVE(20, "已审核"); // 审核通过 + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ErpAuditStatus::getStatus).toArray(); + + /** + * 状态 + */ + private final Integer status; + /** + * 状态名 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java index 51cae4ad9..e4db13763 100644 --- a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java +++ b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java @@ -14,9 +14,14 @@ public interface ErrorCodeConstants { // ========== ERP 仓库 1-030-400-000 ========== ErrorCode WAREHOUSE_NOT_EXISTS = new ErrorCode(1_030_400_000, "仓库不存在"); + ErrorCode WAREHOUSE_NOT_ENABLE = new ErrorCode(1_030_500_001, "仓库({})未启用"); + + // ========== ERP 其它入库单 1-030-401-000 ========== + ErrorCode STOCK_IN_NOT_EXISTS = new ErrorCode(1_030_401_000, "其它入库单不存在"); // ========== ERP 产品 1-030-500-000 ========== ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_030_500_000, "产品不存在"); + ErrorCode PRODUCT_NOT_ENABLE = new ErrorCode(1_030_500_001, "产品({})未启用"); // ========== ERP 产品分类 1-030-501-000 ========== ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_030_501_000, "产品分类不存在"); diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductController.java index 63977890c..cde7bd704 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductController.java @@ -26,6 +26,7 @@ import java.io.IOException; import java.util.List; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; @Tag(name = "管理后台 - ERP 产品") @@ -80,8 +81,12 @@ public class ErpProductController { @GetMapping("/simple-list") @Operation(summary = "获得产品精简列表", description = "只包含被开启的产品,主要用于前端的下拉选项") public CommonResult> getProductSimpleList() { - List list = productService.getProductListByStatus(CommonStatusEnum.ENABLE.getStatus()); - return success(BeanUtils.toBean(list, ErpProductRespVO.class)); + List list = productService.getProductVOListByStatus(CommonStatusEnum.ENABLE.getStatus()); + return success(convertList(list, product -> new ErpProductRespVO().setId(product.getId()) + .setName(product.getName()).setBarCode(product.getBarCode()) + .setCategoryId(product.getCategoryId()).setCategoryName(product.getCategoryName()) + .setUnitId(product.getUnitId()).setUnitName(product.getUnitName()) + .setPurchasePrice(product.getPurchasePrice()).setSalePrice(product.getSalePrice()).setMinPrice(product.getMinPrice()))); } @GetMapping("/export-excel") diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockController.java index 18bf063d3..224468657 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockController.java @@ -18,6 +18,7 @@ import cn.iocoder.yudao.module.erp.service.stock.ErpStockService; import cn.iocoder.yudao.module.erp.service.stock.ErpWarehouseService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletResponse; @@ -52,10 +53,16 @@ public class ErpStockController { @GetMapping("/get") @Operation(summary = "获得产品库存") - @Parameter(name = "id", description = "编号", required = true, example = "1024") + @Parameters({ + @Parameter(name = "id", description = "编号", example = "1"), // 方案一:传递 id + @Parameter(name = "productId", description = "产品编号", example = "10"), // 方案二:传递 productId + warehouseId + @Parameter(name = "warehouseId", description = "仓库编号", example = "2") + }) @PreAuthorize("@ss.hasPermission('erp:stock:query')") - public CommonResult getStock(@RequestParam("id") Long id) { - ErpStockDO stock = stockService.getStock(id); + public CommonResult getStock(@RequestParam(value = "id", required = false) Long id, + @RequestParam(value = "productId", required = false) Long productId, + @RequestParam(value = "warehouseId", required = false) Long warehouseId) { + ErpStockDO stock = id != null ? stockService.getStock(id) : stockService.getStock(productId, warehouseId); return success(BeanUtils.toBean(stock, ErpStockRespVO.class)); } diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockInController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockInController.java new file mode 100644 index 000000000..192fbf50a --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockInController.java @@ -0,0 +1,145 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInItemDO; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.stock.ErpStockInService; +import cn.iocoder.yudao.module.erp.service.stock.ErpStockService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; + +@Tag(name = "管理后台 - ERP 其它入库单") +@RestController +@RequestMapping("/erp/stock-in") +@Validated +public class ErpStockInController { + + @Resource + private ErpStockInService stockInService; + @Resource + private ErpStockService stockService; + @Resource + private ErpProductService productService; + + @Resource + private AdminUserApi adminUserApi; + + @PostMapping("/create") + @Operation(summary = "创建其它入库单") + @PreAuthorize("@ss.hasPermission('erp:stock-in:create')") + public CommonResult createStockIn(@Valid @RequestBody ErpStockInSaveReqVO createReqVO) { + return success(stockInService.createStockIn(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新其它入库单") + @PreAuthorize("@ss.hasPermission('erp:stock-in:update')") + public CommonResult updateStockIn(@Valid @RequestBody ErpStockInSaveReqVO updateReqVO) { + stockInService.updateStockIn(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除其它入库单") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('erp:stock-in:delete')") + public CommonResult deleteStockIn(@RequestParam("id") Long id) { + stockInService.deleteStockIn(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得其它入库单") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('erp:stock-in:query')") + public CommonResult getStockIn(@RequestParam("id") Long id) { + ErpStockInDO stockIn = stockInService.getStockIn(id); + if (stockIn == null) { + return success(null); + } + List stockInItems = stockInService.getStockInItemListByInId(id); + + return success(BeanUtils.toBean(stockIn, ErpStockInRespVO.class, stockInVO -> + stockInVO.setItems(BeanUtils.toBean(stockInItems, ErpStockInRespVO.Item.class, item -> { + ErpStockDO stock = stockService.getStock(item.getProductId(), item.getWarehouseId()); + item.setStockCount(stock != null ? stock.getCount() : BigDecimal.ZERO); + })))); + } + + @GetMapping("/page") + @Operation(summary = "获得其它入库单分页") + @PreAuthorize("@ss.hasPermission('erp:stock-in:query')") + public CommonResult> getStockInPage(@Valid ErpStockInPageReqVO pageReqVO) { + PageResult pageResult = stockInService.getStockInPage(pageReqVO); + return success(buildStockInVOPageResult(pageResult)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出其它入库单 Excel") + @PreAuthorize("@ss.hasPermission('erp:stock-in:export')") + @OperateLog(type = EXPORT) + public void exportStockInExcel(@Valid ErpStockInPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = buildStockInVOPageResult(stockInService.getStockInPage(pageReqVO)).getList(); + // 导出 Excel + ExcelUtils.write(response, "其它入库单.xls", "数据", ErpStockInRespVO.class, list); + } + + private PageResult buildStockInVOPageResult(PageResult pageResult) { + if (CollUtil.isEmpty(pageResult.getList())) { + return PageResult.empty(pageResult.getTotal()); + } + // 1.1 入库项 + List stockInItemList = stockInService.getStockInItemListByInIds( + convertSet(pageResult.getList(), ErpStockInDO::getId)); + Map> stockInItemMap = convertMultiMap(stockInItemList, ErpStockInItemDO::getInId); + // 1.2 商品信息 + Map productMap = productService.getProductVOMap( + convertSet(stockInItemList, ErpStockInItemDO::getProductId)); + // 1.3 管理员信息 + Map userMap = adminUserApi.getUserMap( + convertSet(pageResult.getList(), erpStockRecordDO -> Long.parseLong(erpStockRecordDO.getCreator()))); + // 2. 开始拼接 + return BeanUtils.toBean(pageResult, ErpStockInRespVO.class, stockIn -> { + stockIn.setItems(BeanUtils.toBean(stockInItemMap.get(stockIn.getId()), ErpStockInRespVO.Item.class, + item -> MapUtils.findAndThen(productMap, item.getProductId(), + product -> item.setProductName(product.getName()).setProductUnitName(product.getUnitName())))); + stockIn.setProductNames(CollUtil.join(stockIn.getItems(), ",", ErpStockInRespVO.Item::getProductName)); + MapUtils.findAndThen(userMap, Long.parseLong(stockIn.getCreator()), user -> stockIn.setCreatorName(user.getNickname())); + }); + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockRecordController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockRecordController.java index e92856378..09f9feaf9 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockRecordController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockRecordController.java @@ -9,8 +9,8 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; -import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stockrecord.ErpStockRecordPageReqVO; -import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stockrecord.ErpStockRecordRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.record.ErpStockRecordPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.record.ErpStockRecordRespVO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockRecordDO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO; import cn.iocoder.yudao.module.erp.service.product.ErpProductService; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInPageReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInPageReqVO.java new file mode 100644 index 000000000..05f1915ce --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInPageReqVO.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - ERP 其它入库单分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ErpStockInPageReqVO extends PageParam { + + @Schema(description = "入库单号", example = "S123") + private String no; + + @Schema(description = "供应商编号", example = "3113") + private Long supplierId; + + @Schema(description = "入库时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] inTime; + + @Schema(description = "状态", example = "10") + @InEnum(ErpAuditStatus.class) + private Integer status; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "创建者") + private String creator; + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInRespVO.java new file mode 100644 index 000000000..429ec77a4 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInRespVO.java @@ -0,0 +1,106 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.module.erp.enums.DictTypeConstants.AUDIT_STATUS; + +@Schema(description = "管理后台 - ERP 其它入库单 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ErpStockInRespVO { + + @Schema(description = "入库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + @ExcelProperty("入库编号") + private Long id; + + @Schema(description = "入库单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "S123") + @ExcelProperty("入库单号") + private String no; + + @Schema(description = "供应商编号", example = "3113") + @ExcelProperty("供应商编号") + private Long supplierId; + + @Schema(description = "入库时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("入库时间") + private LocalDateTime inTime; + + @Schema(description = "合计数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "15663") + @ExcelProperty("合计数量") + private BigDecimal totalCount; + + @Schema(description = "合计金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "24906") + @ExcelProperty("合计金额") + private BigDecimal totalPrice; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @ExcelProperty(value = "状态", converter = DictConvert.class) + @DictFormat(AUDIT_STATUS) + private Integer status; + + @Schema(description = "备注", example = "随便") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "附件 URL", example = "https://www.iocoder.cn/1.doc") + private String fileUrl; + + @Schema(description = "审核人", example = "芋道") + private String creator; + @Schema(description = "审核人名称", example = "芋道") + private String creatorName; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "入库项列表", requiredMode = Schema.RequiredMode.REQUIRED) + private List items; + + @Schema(description = "产品信息", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("产品信息") + private String productNames; + + @Data + public static class Item { + + @Schema(description = "入库项编号", example = "11756") + private Long id; + + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long warehouseId; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long productId; + + @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal productPrice; + + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal count; + + @Schema(description = "备注", example = "随便") + private String remark; + + // ========== 关联字段 ========== + + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "巧克力") + private String productName; + @Schema(description = "产品单位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "盒") + private String productUnitName; + + @Schema(description = "库存数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal stockCount; // 该字段仅仅在“详情”和“编辑”时使用 + + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInSaveReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInSaveReqVO.java new file mode 100644 index 000000000..c3cc6be95 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInSaveReqVO.java @@ -0,0 +1,69 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - ERP 其它入库单新增/修改 Request VO") +@Data +public class ErpStockInSaveReqVO { + + @Schema(description = "入库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + private Long id; + + @Schema(description = "入库单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "S123") + @NotEmpty(message = "入库单号不能为空") + private String no; + + @Schema(description = "供应商编号", example = "3113") + private Long supplierId; + + @Schema(description = "入库时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "入库时间不能为空") + private LocalDateTime inTime; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "附件 URL", example = "https://www.iocoder.cn/1.doc") + private String fileUrl; + + @Schema(description = "入库项列表", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "入库项列表不能为空") + @Valid + private List items; + + @Data + public static class Item { + + @Schema(description = "入库项编号", example = "11756") + private Long id; + + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "仓库编号不能为空") + private Long warehouseId; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "产品编号不能为空") + private Long productId; + + @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "产品单价不能为空") + private BigDecimal productPrice; + + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "产品数量不能为空") + private BigDecimal count; + + @Schema(description = "备注", example = "随便") + private String remark; + + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stockrecord/ErpStockRecordPageReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/record/ErpStockRecordPageReqVO.java similarity index 93% rename from yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stockrecord/ErpStockRecordPageReqVO.java rename to yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/record/ErpStockRecordPageReqVO.java index b9030f821..c478e4fef 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stockrecord/ErpStockRecordPageReqVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/record/ErpStockRecordPageReqVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stockrecord; +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.record; import cn.iocoder.yudao.framework.common.pojo.PageParam; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stockrecord/ErpStockRecordRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/record/ErpStockRecordRespVO.java similarity index 97% rename from yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stockrecord/ErpStockRecordRespVO.java rename to yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/record/ErpStockRecordRespVO.java index 0073fafba..ff4b3e12a 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stockrecord/ErpStockRecordRespVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/record/ErpStockRecordRespVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stockrecord; +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.record; import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockInDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockInDO.java new file mode 100644 index 000000000..4eaa316e9 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockInDO.java @@ -0,0 +1,69 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.stock; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * ERP 其它入库单 DO + * + * @author 芋道源码 + */ +@TableName("erp_stock_in") +@KeySequence("erp_stock_in_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpStockInDO extends BaseDO { + + /** + * 入库编号 + */ + @TableId + private Long id; + /** + * 入库单号 + */ + private String no; + /** + * 供应商编号 + * + * TODO 芋艿:待关联 + */ + private Long supplierId; + /** + * 入库时间 + */ + private LocalDateTime inTime; + /** + * 合计数量 + */ + private BigDecimal totalCount; + /** + * 合计金额,单位:元 + */ + private BigDecimal totalPrice; + /** + * 状态 + * + * 枚举 {@link cn.iocoder.yudao.module.erp.enums.ErpAuditStatus} + */ + private Integer status; + /** + * 备注 + */ + private String remark; + /** + * 附件 URL + */ + private String fileUrl; + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockInItemDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockInItemDO.java new file mode 100644 index 000000000..3e3ca9c5c --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockInItemDO.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.stock; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * ERP 其它入库单项 DO + * + * @author 芋道源码 + */ +@TableName("erp_stock_in_item") +@KeySequence("erp_stock_in_item_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpStockInItemDO extends BaseDO { + + /** + * 入库项编号 + */ + @TableId + private Long id; + /** + * 入库编号 + * + * 关联 {@link ErpStockInDO#getId()} + */ + private Long inId; + /** + * 仓库编号 + * + * 关联 {@link ErpWarehouseDO#getId()} + */ + private Long warehouseId; + /** + * 产品编号 + * + * 关联 {@link ErpProductDO#getId()} + */ + private Long productId; + /** + * 产品单位编号 + * + * 冗余 {@link ErpProductDO#getUnitId()} + */ + private Long productUnitId; + /** + * 产品单价 + */ + private BigDecimal productPrice; + /** + * 产品数量 + */ + private BigDecimal count; + /** + * 合计金额,单位:元 + */ + private BigDecimal totalPrice; + /** + * 备注 + */ + private String remark; + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockInItemMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockInItemMapper.java new file mode 100644 index 000000000..2731aa7bb --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockInItemMapper.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.stock; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInItemDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +/** + * ERP 其它入库单项 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpStockInItemMapper extends BaseMapperX { + + default List selectListByInId(Long inId) { + return selectList(ErpStockInItemDO::getInId, inId); + } + + default List selectListByInIds(Collection inIds) { + return selectList(ErpStockInItemDO::getInId, inIds); + } + + default int deleteByInId(Long inId) { + return delete(ErpStockInItemDO::getInId, inId); + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockInMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockInMapper.java new file mode 100644 index 000000000..782112129 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockInMapper.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * ERP 其它入库单 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpStockInMapper extends BaseMapperX { + + default PageResult selectPage(ErpStockInPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(ErpStockInDO::getNo, reqVO.getNo()) + .eqIfPresent(ErpStockInDO::getSupplierId, reqVO.getSupplierId()) + .betweenIfPresent(ErpStockInDO::getInTime, reqVO.getInTime()) + .eqIfPresent(ErpStockInDO::getStatus, reqVO.getStatus()) + .likeIfPresent(ErpStockInDO::getRemark, reqVO.getRemark()) + .eqIfPresent(ErpStockInDO::getCreator, reqVO.getCreator()) + .orderByDesc(ErpStockInDO::getId)); + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java index c634f9780..5afe42da0 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java @@ -22,4 +22,9 @@ public interface ErpStockMapper extends BaseMapperX { .orderByDesc(ErpStockDO::getId)); } + default ErpStockDO selectByProductIdAndWarehouseId(Long productId, Long warehouseId) { + return selectOne(ErpStockDO::getProductId, productId, + ErpStockDO::getWarehouseId, warehouseId); + } + } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockRecordMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockRecordMapper.java index 6c5c48fd0..bfd8b6751 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockRecordMapper.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockRecordMapper.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.erp.dal.mysql.stock; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stockrecord.ErpStockRecordPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.record.ErpStockRecordPageReqVO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockRecordDO; import org.apache.ibatis.annotations.Mapper; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductService.java index 9fa18a073..778c7f29a 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductService.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductService.java @@ -42,6 +42,14 @@ public interface ErpProductService { */ void deleteProduct(Long id); + /** + * 校验产品们的有效性 + * + * @param ids 编号数组 + * @return 产品列表 + */ + List validProductList(Collection ids); + /** * 获得产品 * @@ -51,12 +59,12 @@ public interface ErpProductService { ErpProductDO getProduct(Long id); /** - * 获得指定状态的产品列表 + * 获得指定状态的产品 VO 列表 * * @param status 状态 - * @return 产品列表 + * @return 产品 VO 列表 */ - List getProductListByStatus(Integer status); + List getProductVOListByStatus(Integer status); /** * 获得产品 VO 列表 diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java index 58c7b7c3b..074fd3c29 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.erp.service.product; import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.MapUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; @@ -15,14 +16,11 @@ import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; +import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; -import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.PRODUCT_NOT_EXISTS; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; /** * ERP 产品 Service 实现类 @@ -67,6 +65,25 @@ public class ErpProductServiceImpl implements ErpProductService { productMapper.deleteById(id); } + @Override + public List validProductList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + List list = productMapper.selectBatchIds(ids); + Map productMap = convertMap(list, ErpProductDO::getId); + for (Long id : ids) { + ErpProductDO product = productMap.get(id); + if (productMap.get(id) == null) { + throw exception(PRODUCT_NOT_EXISTS); + } + if (CommonStatusEnum.isDisable(product.getStatus())) { + throw exception(PRODUCT_NOT_ENABLE, product.getName()); + } + } + return list; + } + private void validateProductExists(Long id) { if (productMapper.selectById(id) == null) { throw exception(PRODUCT_NOT_EXISTS); @@ -79,8 +96,9 @@ public class ErpProductServiceImpl implements ErpProductService { } @Override - public List getProductListByStatus(Integer status) { - return productMapper.selectListByStatus(status); + public List getProductVOListByStatus(Integer status) { + List list = productMapper.selectListByStatus(status); + return buildProductVOList(list); } @Override diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInService.java new file mode 100644 index 000000000..92555135f --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInService.java @@ -0,0 +1,76 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInItemDO; +import jakarta.validation.Valid; + +import java.util.Collection; +import java.util.List; + +/** + * ERP 其它入库单 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpStockInService { + + /** + * 创建其它入库单 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createStockIn(@Valid ErpStockInSaveReqVO createReqVO); + + /** + * 更新其它入库单 + * + * @param updateReqVO 更新信息 + */ + void updateStockIn(@Valid ErpStockInSaveReqVO updateReqVO); + + /** + * 删除其它入库单 + * + * @param id 编号 + */ + void deleteStockIn(Long id); + + /** + * 获得其它入库单 + * + * @param id 编号 + * @return 其它入库单 + */ + ErpStockInDO getStockIn(Long id); + + /** + * 获得其它入库单分页 + * + * @param pageReqVO 分页查询 + * @return 其它入库单分页 + */ + PageResult getStockInPage(ErpStockInPageReqVO pageReqVO); + + // ==================== 入库项 ==================== + + /** + * 获得其它入库单项列表 + * + * @param inId 入库编号 + * @return 其它入库单项列表 + */ + List getStockInItemListByInId(Long inId); + + /** + * 获得其它入库单项 List + * + * @param inIds 入库编号数组 + * @return 其它入库单项 List + */ + List getStockInItemListByInIds(Collection inIds); + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java new file mode 100644 index 000000000..4945d8111 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java @@ -0,0 +1,162 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInItemDO; +import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockInItemMapper; +import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockInMapper; +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_IN_NOT_EXISTS; + + +/** + * ERP 其它入库单 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ErpStockInServiceImpl implements ErpStockInService { + + @Resource + private ErpStockInMapper stockInMapper; + @Resource + private ErpStockInItemMapper stockInItemMapper; + + @Resource + private ErpProductService productService; + @Resource + private ErpWarehouseService warehouseService; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createStockIn(ErpStockInSaveReqVO createReqVO) { + // 1.1 校验入库项的有效性 + List stockInItems = validateStockInItems(createReqVO.getItems()); + // 1.2 TODO 芋艿:校验供应商 + + // 2.1 插入入库单 + ErpStockInDO stockIn = BeanUtils.toBean(createReqVO, ErpStockInDO.class, in -> in + .setStatus(ErpAuditStatus.PROCESS.getStatus()) + .setTotalCount(getSumValue(stockInItems, ErpStockInItemDO::getCount, BigDecimal::add)) + .setTotalPrice(getSumValue(stockInItems, ErpStockInItemDO::getTotalPrice, BigDecimal::add))); + stockInMapper.insert(stockIn); + // 2. 插入子表 + stockInItems.forEach(o -> o.setInId(stockIn.getId())); + stockInItemMapper.insertBatch(stockInItems); + return stockIn.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateStockIn(ErpStockInSaveReqVO updateReqVO) { + // 1.1 校验存在 + validateStockInExists(updateReqVO.getId()); + // 1.2 TODO 芋艿:校验供应商 + // 1.3 校验入库项的有效性 + List stockInItems = validateStockInItems(updateReqVO.getItems()); + + // 2.1 更新入库单 + ErpStockInDO updateObj = BeanUtils.toBean(updateReqVO, ErpStockInDO.class, in -> in + .setTotalCount(getSumValue(stockInItems, ErpStockInItemDO::getCount, BigDecimal::add)) + .setTotalPrice(getSumValue(stockInItems, ErpStockInItemDO::getTotalPrice, BigDecimal::add))); + stockInMapper.updateById(updateObj); + // 2.2 更新入库单项 + updateStockInItemList(updateReqVO.getId(), stockInItems); + } + + private List validateStockInItems(List list) { + // 1.1 校验产品存在 + List productList = productService.validProductList(convertSet(list, ErpStockInSaveReqVO.Item::getProductId)); + Map productMap = convertMap(productList, ErpProductDO::getId); + // 1.2 校验仓库存在 + warehouseService.validWarehouseList(convertSet(list, ErpStockInSaveReqVO.Item::getWarehouseId)); + // 2. 转化为 ErpStockInItemDO 列表 + return convertList(list, o -> BeanUtils.toBean(o, ErpStockInItemDO.class, item -> item + .setProductUnitId(productMap.get(item.getProductId()).getUnitId()) + .setTotalPrice(item.getProductPrice().multiply(item.getCount())))); + } + + private void updateStockInItemList(Long id, List newList) { + // 第一步,对比新老数据,获得添加、修改、删除的列表 + List oldList = stockInItemMapper.selectListByInId(id); + List> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录 + (oldVal, newVal) -> oldVal.getId().equals(newVal.getId())); + + // 第二步,批量添加、修改、删除 + if (CollUtil.isNotEmpty(diffList.get(0))) { + diffList.get(0).forEach(o -> o.setInId(id)); + stockInItemMapper.insertBatch(diffList.get(0)); + } + if (CollUtil.isNotEmpty(diffList.get(1))) { + stockInItemMapper.updateBatch(diffList.get(1)); + } + if (CollUtil.isNotEmpty(diffList.get(2))) { + stockInItemMapper.deleteBatchIds(convertList(diffList.get(2), ErpStockInItemDO::getId)); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteStockIn(Long id) { + // 1. 校验存在 + validateStockInExists(id); + // TODO 芋艿:校验一下; + + // 2.1 删除 + stockInMapper.deleteById(id); + // 2.2 删除子表 + stockInItemMapper.deleteByInId(id); + } + + private void validateStockInExists(Long id) { + if (stockInMapper.selectById(id) == null) { + throw exception(STOCK_IN_NOT_EXISTS); + } + } + + @Override + public ErpStockInDO getStockIn(Long id) { + return stockInMapper.selectById(id); + } + + @Override + public PageResult getStockInPage(ErpStockInPageReqVO pageReqVO) { + return stockInMapper.selectPage(pageReqVO); + } + + // ==================== 子表(ERP 其它入库单项) ==================== + + @Override + public List getStockInItemListByInId(Long inId) { + return stockInItemMapper.selectListByInId(inId); + } + + @Override + public List getStockInItemListByInIds(Collection inIds) { + if (CollUtil.isEmpty(inIds)) { + return Collections.emptyList(); + } + return stockInItemMapper.selectListByInIds(inIds); + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordService.java index 8b90a0e4c..08acb89b5 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordService.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordService.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.erp.service.stock; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stockrecord.ErpStockRecordPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.record.ErpStockRecordPageReqVO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockRecordDO; /** diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordServiceImpl.java index 0adc7c864..6f50b91cc 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordServiceImpl.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.erp.service.stock; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stockrecord.ErpStockRecordPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.record.ErpStockRecordPageReqVO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockRecordDO; import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockRecordMapper; import jakarta.annotation.Resource; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockService.java index 041aca6d5..f9cd26158 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockService.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockService.java @@ -19,6 +19,15 @@ public interface ErpStockService { */ ErpStockDO getStock(Long id); + /** + * 基于产品 + 仓库,获得产品库存 + * + * @param productId 产品编号 + * @param warehouseId 仓库编号 + * @return 产品库存 + */ + ErpStockDO getStock(Long productId, Long warehouseId); + /** * 获得产品库存分页 * diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockServiceImpl.java index 7ee4a3fc0..423774265 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockServiceImpl.java @@ -25,6 +25,11 @@ public class ErpStockServiceImpl implements ErpStockService { return stockMapper.selectById(id); } + @Override + public ErpStockDO getStock(Long productId, Long warehouseId) { + return stockMapper.selectByProductIdAndWarehouseId(productId, warehouseId); + } + @Override public PageResult getStockPage(ErpStockPageReqVO pageReqVO) { return stockMapper.selectPage(pageReqVO); diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseService.java index 6f9d3c8fa..872a698de 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseService.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseService.java @@ -57,6 +57,14 @@ public interface ErpWarehouseService { */ ErpWarehouseDO getWarehouse(Long id); + /** + * 校验仓库列表的有效性 + * + * @param ids 编号数组 + * @return 仓库列表 + */ + List validWarehouseList(Collection ids); + /** * 获得指定状态的仓库列表 * diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseServiceImpl.java index e2f6d7667..fb4829146 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseServiceImpl.java @@ -1,9 +1,12 @@ package cn.iocoder.yudao.module.erp.service.stock; +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.ErpWarehouseSaveReqVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehousePageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO; import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpWarehouseMapper; import jakarta.annotation.Resource; @@ -12,10 +15,13 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.Collection; +import java.util.Collections; import java.util.List; +import java.util.Map; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.WAREHOUSE_NOT_EXISTS; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; /** * ERP 仓库 Service 实现类 @@ -83,6 +89,25 @@ public class ErpWarehouseServiceImpl implements ErpWarehouseService { return warehouseMapper.selectById(id); } + @Override + public List validWarehouseList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + List list = warehouseMapper.selectBatchIds(ids); + Map warehouseMap = convertMap(list, ErpWarehouseDO::getId); + for (Long id : ids) { + ErpWarehouseDO warehouse = warehouseMap.get(id); + if (warehouseMap.get(id) == null) { + throw exception(WAREHOUSE_NOT_EXISTS); + } + if (CommonStatusEnum.isDisable(warehouse.getStatus())) { + throw exception(WAREHOUSE_NOT_ENABLE, warehouse.getName()); + } + } + return list; + } + @Override public List getWarehouseListByStatus(Integer status) { return warehouseMapper.selectListByStatus(status); From bfe3dc95fe7c6b428c91012782adff5ae43a38c4 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 6 Feb 2024 17:59:44 +0800 Subject: [PATCH 06/15] =?UTF-8?q?=E2=9C=A8=20ERP=EF=BC=9A=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E4=BE=9B=E5=BA=94=E5=95=86=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/erp/enums/ErrorCodeConstants.java | 10 +- .../admin/purchase/ErpSupplierController.java | 102 ++++++++++++++++++ .../vo/supplier/ErpSupplierPageReqVO.java | 24 +++++ .../vo/supplier/ErpSupplierRespVO.java | 84 +++++++++++++++ .../vo/supplier/ErpSupplierSaveReqVO.java | 71 ++++++++++++ .../admin/stock/ErpStockInController.java | 12 ++- .../stock/vo/in/ErpStockInPageReqVO.java | 6 ++ .../admin/stock/vo/in/ErpStockInRespVO.java | 4 +- .../dataobject/supplier/ErpSupplierDO.java | 90 ++++++++++++++++ .../dal/mysql/purchase/ErpSupplierMapper.java | 32 ++++++ .../erp/dal/mysql/stock/ErpStockInMapper.java | 14 ++- .../product/ErpProductServiceImpl.java | 2 + .../service/purchase/ErpSupplierService.java | 94 ++++++++++++++++ .../purchase/ErpSupplierServiceImpl.java | 94 ++++++++++++++++ .../service/stock/ErpStockInServiceImpl.java | 9 +- .../mapper/supplier/ErpSupplierMapper.xml | 12 +++ .../src/main/resources/application-local.yaml | 1 + 17 files changed, 650 insertions(+), 11 deletions(-) create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpSupplierController.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/supplier/ErpSupplierPageReqVO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/supplier/ErpSupplierRespVO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/supplier/ErpSupplierSaveReqVO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/supplier/ErpSupplierDO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpSupplierMapper.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpSupplierService.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpSupplierServiceImpl.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/resources/mapper/supplier/ErpSupplierMapper.xml diff --git a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java index e4db13763..1cc2807ad 100644 --- a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java +++ b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java @@ -9,12 +9,16 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode; */ public interface ErrorCodeConstants { - // ========== 销售订单(1-020-000-000) ========== - ErrorCode SALE_ORDER_NOT_EXISTS = new ErrorCode(1_020_000_000, "销售订单不存在"); + // ========== ERP 供应商(1-030-100-000) ========== + ErrorCode SUPPLIER_NOT_EXISTS = new ErrorCode(1_030_100_000, "供应商不存在"); + ErrorCode SUPPLIER_NOT_ENABLE = new ErrorCode(1_030_100_000, "供应商({})未启用"); + + // ========== 销售订单(1-030-200-000) ========== + ErrorCode SALE_ORDER_NOT_EXISTS = new ErrorCode(1_020_200_000, "销售订单不存在"); // ========== ERP 仓库 1-030-400-000 ========== ErrorCode WAREHOUSE_NOT_EXISTS = new ErrorCode(1_030_400_000, "仓库不存在"); - ErrorCode WAREHOUSE_NOT_ENABLE = new ErrorCode(1_030_500_001, "仓库({})未启用"); + ErrorCode WAREHOUSE_NOT_ENABLE = new ErrorCode(1_030_400_001, "仓库({})未启用"); // ========== ERP 其它入库单 1-030-401-000 ========== ErrorCode STOCK_IN_NOT_EXISTS = new ErrorCode(1_030_401_000, "其它入库单不存在"); diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpSupplierController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpSupplierController.java new file mode 100644 index 000000000..60893ea57 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpSupplierController.java @@ -0,0 +1,102 @@ +package cn.iocoder.yudao.module.erp.controller.admin.purchase; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier.ErpSupplierPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier.ErpSupplierRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier.ErpSupplierSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.supplier.ErpSupplierDO; +import cn.iocoder.yudao.module.erp.service.purchase.ErpSupplierService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; + +@Tag(name = "管理后台 - ERP 供应商") +@RestController +@RequestMapping("/erp/supplier") +@Validated +public class ErpSupplierController { + + @Resource + private ErpSupplierService supplierService; + + @PostMapping("/create") + @Operation(summary = "创建供应商") + @PreAuthorize("@ss.hasPermission('erp:supplier:create')") + public CommonResult createSupplier(@Valid @RequestBody ErpSupplierSaveReqVO createReqVO) { + return success(supplierService.createSupplier(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新供应商") + @PreAuthorize("@ss.hasPermission('erp:supplier:update')") + public CommonResult updateSupplier(@Valid @RequestBody ErpSupplierSaveReqVO updateReqVO) { + supplierService.updateSupplier(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除供应商") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('erp:supplier:delete')") + public CommonResult deleteSupplier(@RequestParam("id") Long id) { + supplierService.deleteSupplier(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得供应商") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('erp:supplier:query')") + public CommonResult getSupplier(@RequestParam("id") Long id) { + ErpSupplierDO supplier = supplierService.getSupplier(id); + return success(BeanUtils.toBean(supplier, ErpSupplierRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得供应商分页") + @PreAuthorize("@ss.hasPermission('erp:supplier:query')") + public CommonResult> getSupplierPage(@Valid ErpSupplierPageReqVO pageReqVO) { + PageResult pageResult = supplierService.getSupplierPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, ErpSupplierRespVO.class)); + } + + @GetMapping("/simple-list") + @Operation(summary = "获得供应商精简列表", description = "只包含被开启的供应商,主要用于前端的下拉选项") + public CommonResult> getSupplierSimpleList() { + List list = supplierService.getSupplierListByStatus(CommonStatusEnum.ENABLE.getStatus()); + return success(convertList(list, supplier -> new ErpSupplierRespVO().setId(supplier.getId()).setName(supplier.getName()))); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出供应商 Excel") + @PreAuthorize("@ss.hasPermission('erp:supplier:export')") + @OperateLog(type = EXPORT) + public void exportSupplierExcel(@Valid ErpSupplierPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = supplierService.getSupplierPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "供应商.xls", "数据", ErpSupplierRespVO.class, + BeanUtils.toBean(list, ErpSupplierRespVO.class)); + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/supplier/ErpSupplierPageReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/supplier/ErpSupplierPageReqVO.java new file mode 100644 index 000000000..229ab63d9 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/supplier/ErpSupplierPageReqVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - ERP 供应商分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ErpSupplierPageReqVO extends PageParam { + + @Schema(description = "供应商名称", example = "芋道源码") + private String name; + + @Schema(description = "手机号码", example = "15601691300") + private String mobile; + + @Schema(description = "联系电话", example = "18818288888") + private String telephone; + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/supplier/ErpSupplierRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/supplier/ErpSupplierRespVO.java new file mode 100644 index 000000000..5ba5892c1 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/supplier/ErpSupplierRespVO.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.system.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - ERP 供应商 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ErpSupplierRespVO { + + @Schema(description = "供应商编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17791") + @ExcelProperty("供应商编号") + private Long id; + + @Schema(description = "供应商名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + @ExcelProperty("供应商名称") + private String name; + + @Schema(description = "联系人", example = "芋艿") + @ExcelProperty("联系人") + private String contact; + + @Schema(description = "手机号码", example = "15601691300") + @ExcelProperty("手机号码") + private String mobile; + + @Schema(description = "联系电话", example = "18818288888") + @ExcelProperty("联系电话") + private String telephone; + + @Schema(description = "电子邮箱", example = "76853@qq.com") + @ExcelProperty("电子邮箱") + private String email; + + @Schema(description = "传真", example = "20 7123 4567") + @ExcelProperty("传真") + private String fax; + + @Schema(description = "备注", example = "你猜") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "开启状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "开启状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.COMMON_STATUS) + private Integer status; + + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @ExcelProperty("排序") + private Integer sort; + + @Schema(description = "纳税人识别号", example = "91130803MA098BY05W") + @ExcelProperty("纳税人识别号") + private String taxNo; + + @Schema(description = "税率", example = "10") + @ExcelProperty("税率") + private BigDecimal taxPercent; + + @Schema(description = "开户行", example = "张三") + @ExcelProperty("开户行") + private String bankName; + + @Schema(description = "开户账号", example = "622908212277228617") + @ExcelProperty("开户账号") + private String bankAccount; + + @Schema(description = "开户地址", example = "兴业银行浦东支行") + @ExcelProperty("开户地址") + private String bankAddress; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/supplier/ErpSupplierSaveReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/supplier/ErpSupplierSaveReqVO.java new file mode 100644 index 000000000..2291de050 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/supplier/ErpSupplierSaveReqVO.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.framework.common.validation.Mobile; +import cn.iocoder.yudao.framework.common.validation.Telephone; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.math.BigDecimal; + +@Schema(description = "管理后台 - ERP 供应商新增/修改 Request VO") +@Data +public class ErpSupplierSaveReqVO { + + @Schema(description = "供应商编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17791") + private Long id; + + @Schema(description = "供应商名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + @NotEmpty(message = "供应商名称不能为空") + private String name; + + @Schema(description = "联系人", example = "芋艿") + private String contact; + + @Schema(description = "手机号码", example = "15601691300") + @Mobile + private String mobile; + + @Schema(description = "联系电话", example = "18818288888") + @Telephone + private String telephone; + + @Schema(description = "电子邮箱", example = "76853@qq.com") + @Email + private String email; + + @Schema(description = "传真", example = "20 7123 4567") + private String fax; + + @Schema(description = "备注", example = "你猜") + private String remark; + + @Schema(description = "开启状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "开启状态不能为空") + @InEnum(value = CommonStatusEnum.class) + private Integer status; + + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @NotNull(message = "排序不能为空") + private Integer sort; + + @Schema(description = "纳税人识别号", example = "91130803MA098BY05W") + private String taxNo; + + @Schema(description = "税率", example = "10") + private BigDecimal taxPercent; + + @Schema(description = "开户行", example = "张三") + private String bankName; + + @Schema(description = "开户账号", example = "622908212277228617") + private String bankAccount; + + @Schema(description = "开户地址", example = "兴业银行浦东支行") + private String bankAddress; + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockInController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockInController.java index 192fbf50a..1351516ed 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockInController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockInController.java @@ -15,7 +15,9 @@ import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInSaveRe import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInDO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInItemDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.supplier.ErpSupplierDO; import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.purchase.ErpSupplierService; import cn.iocoder.yudao.module.erp.service.stock.ErpStockInService; import cn.iocoder.yudao.module.erp.service.stock.ErpStockService; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; @@ -52,6 +54,8 @@ public class ErpStockInController { private ErpStockService stockService; @Resource private ErpProductService productService; + @Resource + private ErpSupplierService supplierService; @Resource private AdminUserApi adminUserApi; @@ -90,7 +94,7 @@ public class ErpStockInController { return success(null); } List stockInItems = stockInService.getStockInItemListByInId(id); - + // TODO 芋艿:有个锤子; return success(BeanUtils.toBean(stockIn, ErpStockInRespVO.class, stockInVO -> stockInVO.setItems(BeanUtils.toBean(stockInItems, ErpStockInRespVO.Item.class, item -> { ErpStockDO stock = stockService.getStock(item.getProductId(), item.getWarehouseId()); @@ -129,7 +133,10 @@ public class ErpStockInController { // 1.2 商品信息 Map productMap = productService.getProductVOMap( convertSet(stockInItemList, ErpStockInItemDO::getProductId)); - // 1.3 管理员信息 + // 1.3 供应商信息 + Map supplierMap = supplierService.getSupplierMap( + convertSet(pageResult.getList(), ErpStockInDO::getSupplierId)); + // 1.4 管理员信息 Map userMap = adminUserApi.getUserMap( convertSet(pageResult.getList(), erpStockRecordDO -> Long.parseLong(erpStockRecordDO.getCreator()))); // 2. 开始拼接 @@ -138,6 +145,7 @@ public class ErpStockInController { item -> MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()).setProductUnitName(product.getUnitName())))); stockIn.setProductNames(CollUtil.join(stockIn.getItems(), ",", ErpStockInRespVO.Item::getProductName)); + MapUtils.findAndThen(supplierMap, stockIn.getSupplierId(), supplier -> stockIn.setSupplierName(supplier.getName())); MapUtils.findAndThen(userMap, Long.parseLong(stockIn.getCreator()), user -> stockIn.setCreatorName(user.getNickname())); }); } diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInPageReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInPageReqVO.java index 05f1915ce..02e3db37a 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInPageReqVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInPageReqVO.java @@ -39,4 +39,10 @@ public class ErpStockInPageReqVO extends PageParam { @Schema(description = "创建者") private String creator; + @Schema(description = "产品编号", example = "1") + private Long productId; + + @Schema(description = "仓库编号", example = "1") + private Long warehouseId; + } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInRespVO.java index 429ec77a4..07897ad30 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInRespVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInRespVO.java @@ -27,8 +27,10 @@ public class ErpStockInRespVO { private String no; @Schema(description = "供应商编号", example = "3113") - @ExcelProperty("供应商编号") private Long supplierId; + @Schema(description = "供应商名称", example = "芋道") + @ExcelProperty("供应商名称") + private String supplierName; @Schema(description = "入库时间", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("入库时间") diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/supplier/ErpSupplierDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/supplier/ErpSupplierDO.java new file mode 100644 index 000000000..108922a22 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/supplier/ErpSupplierDO.java @@ -0,0 +1,90 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.supplier; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * ERP 供应商 DO + * + * @author 芋道源码 + */ +@TableName("erp_supplier") +@KeySequence("erp_supplier_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpSupplierDO extends BaseDO { + + /** + * 供应商编号 + */ + @TableId + private Long id; + /** + * 供应商名称 + */ + private String name; + /** + * 联系人 + */ + private String contact; + /** + * 手机号码 + */ + private String mobile; + /** + * 联系电话 + */ + private String telephone; + /** + * 电子邮箱 + */ + private String email; + /** + * 传真 + */ + private String fax; + /** + * 备注 + */ + private String remark; + /** + * 开启状态 + * + * 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum} + */ + private Integer status; + /** + * 排序 + */ + private Integer sort; + /** + * 纳税人识别号 + */ + private String taxNo; + /** + * 税率 + */ + private BigDecimal taxPercent; + /** + * 开户行 + */ + private String bankName; + /** + * 开户账号 + */ + private String bankAccount; + /** + * 开户地址 + */ + private String bankAddress; + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpSupplierMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpSupplierMapper.java new file mode 100644 index 000000000..93f3d6994 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpSupplierMapper.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.purchase; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier.ErpSupplierPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.supplier.ErpSupplierDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * ERP 供应商 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpSupplierMapper extends BaseMapperX { + + default PageResult selectPage(ErpSupplierPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(ErpSupplierDO::getName, reqVO.getName()) + .likeIfPresent(ErpSupplierDO::getMobile, reqVO.getMobile()) + .likeIfPresent(ErpSupplierDO::getTelephone, reqVO.getTelephone()) + .orderByDesc(ErpSupplierDO::getId)); + } + + default List selectListByStatus(Integer status) { + return selectList(ErpSupplierDO::getStatus, status); + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockInMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockInMapper.java index 782112129..0b3e71a5f 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockInMapper.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockInMapper.java @@ -2,9 +2,10 @@ package cn.iocoder.yudao.module.erp.dal.mysql.stock; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInPageReqVO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInItemDO; import org.apache.ibatis.annotations.Mapper; /** @@ -16,14 +17,21 @@ import org.apache.ibatis.annotations.Mapper; public interface ErpStockInMapper extends BaseMapperX { default PageResult selectPage(ErpStockInPageReqVO reqVO) { - return selectPage(reqVO, new LambdaQueryWrapperX() + MPJLambdaWrapperX query = new MPJLambdaWrapperX() .eqIfPresent(ErpStockInDO::getNo, reqVO.getNo()) .eqIfPresent(ErpStockInDO::getSupplierId, reqVO.getSupplierId()) .betweenIfPresent(ErpStockInDO::getInTime, reqVO.getInTime()) .eqIfPresent(ErpStockInDO::getStatus, reqVO.getStatus()) .likeIfPresent(ErpStockInDO::getRemark, reqVO.getRemark()) .eqIfPresent(ErpStockInDO::getCreator, reqVO.getCreator()) - .orderByDesc(ErpStockInDO::getId)); + .orderByDesc(ErpStockInDO::getId); + if (reqVO.getWarehouseId() != null || reqVO.getProductId() != null) { + query.leftJoin(ErpStockInItemDO.class, ErpStockInItemDO::getInId, ErpStockInDO::getId) + .eq(reqVO.getWarehouseId() != null, ErpStockInItemDO::getWarehouseId, reqVO.getWarehouseId()) + .eq(reqVO.getProductId() != null, ErpStockInItemDO::getProductId, reqVO.getProductId()) + .groupBy(ErpStockInDO::getId); // 避免 1 对多查询,产生相同的 1 + } + return selectJoinPage(reqVO, ErpStockInDO.class, query); } } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java index 074fd3c29..53794043f 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java @@ -41,6 +41,7 @@ public class ErpProductServiceImpl implements ErpProductService { @Override public Long createProduct(ProductSaveReqVO createReqVO) { + // TODO 芋艿:校验分类 // 插入 ErpProductDO product = BeanUtils.toBean(createReqVO, ErpProductDO.class); productMapper.insert(product); @@ -50,6 +51,7 @@ public class ErpProductServiceImpl implements ErpProductService { @Override public void updateProduct(ProductSaveReqVO updateReqVO) { + // TODO 芋艿:校验分类 // 校验存在 validateProductExists(updateReqVO.getId()); // 更新 diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpSupplierService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpSupplierService.java new file mode 100644 index 000000000..a2f6547c2 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpSupplierService.java @@ -0,0 +1,94 @@ +package cn.iocoder.yudao.module.erp.service.purchase; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier.ErpSupplierPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier.ErpSupplierSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.supplier.ErpSupplierDO; +import jakarta.validation.Valid; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * ERP 供应商 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpSupplierService { + + /** + * 创建供应商 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createSupplier(@Valid ErpSupplierSaveReqVO createReqVO); + + /** + * 更新供应商 + * + * @param updateReqVO 更新信息 + */ + void updateSupplier(@Valid ErpSupplierSaveReqVO updateReqVO); + + /** + * 删除供应商 + * + * @param id 编号 + */ + void deleteSupplier(Long id); + + /** + * 获得供应商 + * + * @param id 编号 + * @return 供应商 + */ + ErpSupplierDO getSupplier(Long id); + + /** + * 校验供应商 + * + * @param id 编号 + * @return 供应商 + */ + ErpSupplierDO validateSupplier(Long id); + + /** + * 获得供应商列表 + * + * @param ids 编号列表 + * @return 供应商列表 + */ + List getSupplierList(Collection ids); + + /** + * 获得供应商 Map + * + * @param ids 编号列表 + * @return 供应商 Map + */ + default Map getSupplierMap(Collection ids) { + return convertMap(getSupplierList(ids), ErpSupplierDO::getId); + } + + /** + * 获得供应商分页 + * + * @param pageReqVO 分页查询 + * @return 供应商分页 + */ + PageResult getSupplierPage(ErpSupplierPageReqVO pageReqVO); + + /** + * 获得指定状态的供应商列表 + * + * @param status 状态 + * @return 供应商列表 + */ + List getSupplierListByStatus(Integer status); + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpSupplierServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpSupplierServiceImpl.java new file mode 100644 index 000000000..09c789c57 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpSupplierServiceImpl.java @@ -0,0 +1,94 @@ +package cn.iocoder.yudao.module.erp.service.purchase; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier.ErpSupplierPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier.ErpSupplierSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.supplier.ErpSupplierDO; +import cn.iocoder.yudao.module.erp.dal.mysql.purchase.ErpSupplierMapper; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; + +/** + * ERP 供应商 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ErpSupplierServiceImpl implements ErpSupplierService { + + @Resource + private ErpSupplierMapper supplierMapper; + + @Override + public Long createSupplier(ErpSupplierSaveReqVO createReqVO) { + ErpSupplierDO supplier = BeanUtils.toBean(createReqVO, ErpSupplierDO.class); + supplierMapper.insert(supplier); + return supplier.getId(); + } + + @Override + public void updateSupplier(ErpSupplierSaveReqVO updateReqVO) { + // 校验存在 + validateSupplierExists(updateReqVO.getId()); + // 更新 + ErpSupplierDO updateObj = BeanUtils.toBean(updateReqVO, ErpSupplierDO.class); + supplierMapper.updateById(updateObj); + } + + @Override + public void deleteSupplier(Long id) { + // 校验存在 + validateSupplierExists(id); + // 删除 + supplierMapper.deleteById(id); + } + + private void validateSupplierExists(Long id) { + if (supplierMapper.selectById(id) == null) { + throw exception(SUPPLIER_NOT_EXISTS); + } + } + + @Override + public ErpSupplierDO getSupplier(Long id) { + return supplierMapper.selectById(id); + } + + @Override + public ErpSupplierDO validateSupplier(Long id) { + ErpSupplierDO supplier = supplierMapper.selectById(id); + if (supplier == null) { + throw exception(WAREHOUSE_NOT_EXISTS); + } + if (CommonStatusEnum.isDisable(supplier.getStatus())) { + throw exception(WAREHOUSE_NOT_ENABLE, supplier.getName()); + } + return supplier; + } + + @Override + public List getSupplierList(Collection ids) { + return supplierMapper.selectBatchIds(ids); + } + + @Override + public PageResult getSupplierPage(ErpSupplierPageReqVO pageReqVO) { + return supplierMapper.selectPage(pageReqVO); + } + + @Override + public List getSupplierListByStatus(Integer status) { + return supplierMapper.selectListByStatus(status); + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java index 4945d8111..0cf716018 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java @@ -12,6 +12,7 @@ import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockInItemMapper; import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockInMapper; import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.purchase.ErpSupplierService; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -46,13 +47,16 @@ public class ErpStockInServiceImpl implements ErpStockInService { private ErpProductService productService; @Resource private ErpWarehouseService warehouseService; + @Resource + private ErpSupplierService supplierService; @Override @Transactional(rollbackFor = Exception.class) public Long createStockIn(ErpStockInSaveReqVO createReqVO) { // 1.1 校验入库项的有效性 List stockInItems = validateStockInItems(createReqVO.getItems()); - // 1.2 TODO 芋艿:校验供应商 + // 1.2 校验供应商 + supplierService.validateSupplier(createReqVO.getSupplierId()); // 2.1 插入入库单 ErpStockInDO stockIn = BeanUtils.toBean(createReqVO, ErpStockInDO.class, in -> in @@ -71,7 +75,8 @@ public class ErpStockInServiceImpl implements ErpStockInService { public void updateStockIn(ErpStockInSaveReqVO updateReqVO) { // 1.1 校验存在 validateStockInExists(updateReqVO.getId()); - // 1.2 TODO 芋艿:校验供应商 + // 1.2 校验供应商 + supplierService.validateSupplier(updateReqVO.getSupplierId()); // 1.3 校验入库项的有效性 List stockInItems = validateStockInItems(updateReqVO.getItems()); diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/resources/mapper/supplier/ErpSupplierMapper.xml b/yudao-module-erp/yudao-module-erp-biz/src/main/resources/mapper/supplier/ErpSupplierMapper.xml new file mode 100644 index 000000000..54849af3f --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/resources/mapper/supplier/ErpSupplierMapper.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index f5e300c51..cddf42014 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -188,6 +188,7 @@ logging: cn.iocoder.yudao.module.promotion.dal.mysql: debug cn.iocoder.yudao.module.statistics.dal.mysql: debug cn.iocoder.yudao.module.crm.dal.mysql: debug + cn.iocoder.yudao.module.erp.dal.mysql: debug org.springframework.context.support.PostProcessorRegistrationDelegate: ERROR # TODO 芋艿:先禁用,Spring Boot 3.X 存在部分错误的 WARN 提示 debug: false From 593e1fd59c68422b582c21a27ab8b9e43fcb2bc6 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 6 Feb 2024 23:28:57 +0800 Subject: [PATCH 07/15] =?UTF-8?q?=E2=9C=A8=20ERP=EF=BC=9A=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=85=A5=E5=BA=93=E5=8D=95=E7=9A=84=E5=AE=A1=E6=89=B9?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../util/collection/CollectionUtils.java | 15 +++-- .../common/util/number/NumberUtils.java | 20 ++++++ .../module/erp/enums/ErrorCodeConstants.java | 6 +- .../admin/stock/ErpStockInController.java | 28 +++++--- .../admin/stock/vo/in/ErpStockInRespVO.java | 2 + .../stock/vo/in/ErpStockInSaveReqVO.java | 3 +- .../erp/dal/mysql/stock/ErpStockInMapper.java | 6 ++ .../erp/service/stock/ErpStockInService.java | 12 +++- .../service/stock/ErpStockInServiceImpl.java | 67 ++++++++++++++----- 9 files changed, 125 insertions(+), 34 deletions(-) diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java index 35ebc8ff3..2d9e4dd63 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java @@ -288,11 +288,16 @@ public class CollectionUtils { public static > V getSumValue(List from, Function valueFunc, BinaryOperator accumulator) { + return getSumValue(from, valueFunc, accumulator, null); + } + + public static > V getSumValue(List from, Function valueFunc, + BinaryOperator accumulator, V defaultValue) { if (CollUtil.isEmpty(from)) { - return null; + return defaultValue; } - assert from.size() > 0; // 断言,避免告警 - return from.stream().map(valueFunc).reduce(accumulator).get(); + assert !from.isEmpty(); // 断言,避免告警 + return from.stream().map(valueFunc).filter(Objects::nonNull).reduce(accumulator).orElse(defaultValue); } public static void addIfNotNull(Collection coll, T item) { @@ -302,8 +307,8 @@ public class CollectionUtils { coll.add(item); } - public static Collection singleton(T deptId) { - return deptId == null ? Collections.emptyList() : Collections.singleton(deptId); + public static Collection singleton(T obj) { + return obj == null ? Collections.emptyList() : Collections.singleton(obj); } } diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/NumberUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/NumberUtils.java index 55ab367a3..ea131e86e 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/NumberUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/NumberUtils.java @@ -1,7 +1,10 @@ package cn.iocoder.yudao.framework.common.util.number; +import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.StrUtil; +import java.math.BigDecimal; + /** * 数字的工具类,补全 {@link cn.hutool.core.util.NumberUtil} 的功能 * @@ -37,4 +40,21 @@ public class NumberUtils { return distance; } + /** + * 提供精确的乘法运算 + * + * 和 hutool {@link NumberUtil#mul(BigDecimal...)} 的差别是,如果存在 null,则返回 null + * + * @param values 多个被乘值 + * @return 积 + */ + public static BigDecimal mul(BigDecimal... values) { + for (BigDecimal value : values) { + if (value == null) { + return null; + } + } + return NumberUtil.mul(values); + } + } diff --git a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java index 1cc2807ad..5cfec682c 100644 --- a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java +++ b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java @@ -13,7 +13,7 @@ public interface ErrorCodeConstants { ErrorCode SUPPLIER_NOT_EXISTS = new ErrorCode(1_030_100_000, "供应商不存在"); ErrorCode SUPPLIER_NOT_ENABLE = new ErrorCode(1_030_100_000, "供应商({})未启用"); - // ========== 销售订单(1-030-200-000) ========== + // ========== ERP 销售订单(1-030-200-000) ========== ErrorCode SALE_ORDER_NOT_EXISTS = new ErrorCode(1_020_200_000, "销售订单不存在"); // ========== ERP 仓库 1-030-400-000 ========== @@ -22,6 +22,10 @@ public interface ErrorCodeConstants { // ========== ERP 其它入库单 1-030-401-000 ========== ErrorCode STOCK_IN_NOT_EXISTS = new ErrorCode(1_030_401_000, "其它入库单不存在"); + ErrorCode STOCK_IN_DELETE_FAIL_APPROVE = new ErrorCode(1_030_401_001, "其它入库单({})已审核,无法删除"); + ErrorCode STOCK_IN_PROCESS_FAIL = new ErrorCode(1_030_401_002, "反审核失败,只有已审核的入库单才能反审核"); + ErrorCode STOCK_IN_APPROVE_FAIL = new ErrorCode(1_030_401_003, "审核失败,只有未审核的入库单才能审核"); + // ========== ERP 产品 1-030-500-000 ========== ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_030_500_000, "产品不存在"); diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockInController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockInController.java index 1351516ed..530d04350 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockInController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockInController.java @@ -75,12 +75,21 @@ public class ErpStockInController { return success(true); } + @PutMapping("/update-status") + @Operation(summary = "更新其它入库单的状态") + @PreAuthorize("@ss.hasPermission('erp:stock-in:update')") + public CommonResult updateStockInStatus(@RequestParam("id") Long id, + @RequestParam("status") Integer status) { + stockInService.updateStockInStatus(id, status); + return success(true); + } + @DeleteMapping("/delete") @Operation(summary = "删除其它入库单") - @Parameter(name = "id", description = "编号", required = true) + @Parameter(name = "ids", description = "编号数组", required = true) @PreAuthorize("@ss.hasPermission('erp:stock-in:delete')") - public CommonResult deleteStockIn(@RequestParam("id") Long id) { - stockInService.deleteStockIn(id); + public CommonResult deleteStockIn(@RequestParam("ids") List ids) { + stockInService.deleteStockIn(ids); return success(true); } @@ -93,12 +102,15 @@ public class ErpStockInController { if (stockIn == null) { return success(null); } - List stockInItems = stockInService.getStockInItemListByInId(id); - // TODO 芋艿:有个锤子; + List stockInItemList = stockInService.getStockInItemListByInId(id); + Map productMap = productService.getProductVOMap( + convertSet(stockInItemList, ErpStockInItemDO::getProductId)); return success(BeanUtils.toBean(stockIn, ErpStockInRespVO.class, stockInVO -> - stockInVO.setItems(BeanUtils.toBean(stockInItems, ErpStockInRespVO.Item.class, item -> { + stockInVO.setItems(BeanUtils.toBean(stockInItemList, ErpStockInRespVO.Item.class, item -> { ErpStockDO stock = stockService.getStock(item.getProductId(), item.getWarehouseId()); item.setStockCount(stock != null ? stock.getCount() : BigDecimal.ZERO); + MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())); })))); } @@ -142,8 +154,8 @@ public class ErpStockInController { // 2. 开始拼接 return BeanUtils.toBean(pageResult, ErpStockInRespVO.class, stockIn -> { stockIn.setItems(BeanUtils.toBean(stockInItemMap.get(stockIn.getId()), ErpStockInRespVO.Item.class, - item -> MapUtils.findAndThen(productMap, item.getProductId(), - product -> item.setProductName(product.getName()).setProductUnitName(product.getUnitName())))); + item -> MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())))); stockIn.setProductNames(CollUtil.join(stockIn.getItems(), ",", ErpStockInRespVO.Item::getProductName)); MapUtils.findAndThen(supplierMap, stockIn.getSupplierId(), supplier -> stockIn.setSupplierName(supplier.getName())); MapUtils.findAndThen(userMap, Long.parseLong(stockIn.getCreator()), user -> stockIn.setCreatorName(user.getNickname())); diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInRespVO.java index 07897ad30..e6263db61 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInRespVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInRespVO.java @@ -97,6 +97,8 @@ public class ErpStockInRespVO { @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "巧克力") private String productName; + @Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "A9985") + private String productBarCode; @Schema(description = "产品单位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "盒") private String productUnitName; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInSaveReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInSaveReqVO.java index c3cc6be95..e3a87da8a 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInSaveReqVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInSaveReqVO.java @@ -53,8 +53,7 @@ public class ErpStockInSaveReqVO { @NotNull(message = "产品编号不能为空") private Long productId; - @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") - @NotNull(message = "产品单价不能为空") + @Schema(description = "产品单价", example = "100.00") private BigDecimal productPrice; @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockInMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockInMapper.java index 0b3e71a5f..eadf02c75 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockInMapper.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockInMapper.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInPageReqVO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInDO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInItemDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; /** @@ -34,4 +35,9 @@ public interface ErpStockInMapper extends BaseMapperX { return selectJoinPage(reqVO, ErpStockInDO.class, query); } + default int updateByIdAndStatus(Long id, Integer status, ErpStockInDO updateObj) { + return update(updateObj, new LambdaUpdateWrapper() + .eq(ErpStockInDO::getId, id).eq(ErpStockInDO::getStatus, status)); + } + } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInService.java index 92555135f..4e51545e4 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInService.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInService.java @@ -33,11 +33,19 @@ public interface ErpStockInService { void updateStockIn(@Valid ErpStockInSaveReqVO updateReqVO); /** - * 删除其它入库单 + * 更新其它入库单的状态 * * @param id 编号 + * @param status 状态 */ - void deleteStockIn(Long id); + void updateStockInStatus(Long id, Integer status); + + /** + * 删除其它入库单 + * + * @param ids 编号数组 + */ + void deleteStockIn(List ids); /** * 获得其它入库单 diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java index 0cf716018..305676445 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.erp.service.stock; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInPageReqVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInSaveReqVO; @@ -26,9 +27,9 @@ import java.util.Map; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; -import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_IN_NOT_EXISTS; - +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; +// TODO 芋艿:记录操作日志 /** * ERP 其它入库单 Service 实现类 * @@ -62,9 +63,9 @@ public class ErpStockInServiceImpl implements ErpStockInService { ErpStockInDO stockIn = BeanUtils.toBean(createReqVO, ErpStockInDO.class, in -> in .setStatus(ErpAuditStatus.PROCESS.getStatus()) .setTotalCount(getSumValue(stockInItems, ErpStockInItemDO::getCount, BigDecimal::add)) - .setTotalPrice(getSumValue(stockInItems, ErpStockInItemDO::getTotalPrice, BigDecimal::add))); + .setTotalPrice(getSumValue(stockInItems, ErpStockInItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO))); stockInMapper.insert(stockIn); - // 2. 插入子表 + // 2.2 插入入库单项 stockInItems.forEach(o -> o.setInId(stockIn.getId())); stockInItemMapper.insertBatch(stockInItems); return stockIn.getId(); @@ -89,6 +90,28 @@ public class ErpStockInServiceImpl implements ErpStockInService { updateStockInItemList(updateReqVO.getId(), stockInItems); } + @Override + @Transactional(rollbackFor = Exception.class) + public void updateStockInStatus(Long id, Integer status) { + // 1.1 校验存在 + ErpStockInDO stockIn = validateStockInExists(id); + // 1.2 校验状态 + if (stockIn.getStatus().equals(status)) { + throw exception(ErpAuditStatus.PROCESS.getStatus().equals(status) ? + STOCK_IN_PROCESS_FAIL : STOCK_IN_APPROVE_FAIL); + } + + // 2. 更新状态 + int updateCount = stockInMapper.updateByIdAndStatus(id, stockIn.getStatus(), + new ErpStockInDO().setStatus(status)); + if (updateCount == 0) { + throw exception(ErpAuditStatus.PROCESS.getStatus().equals(status) ? + STOCK_IN_PROCESS_FAIL : STOCK_IN_APPROVE_FAIL); + } + + // 3. TODO 芋艿:调整库存记录 + } + private List validateStockInItems(List list) { // 1.1 校验产品存在 List productList = productService.validProductList(convertSet(list, ErpStockInSaveReqVO.Item::getProductId)); @@ -98,7 +121,7 @@ public class ErpStockInServiceImpl implements ErpStockInService { // 2. 转化为 ErpStockInItemDO 列表 return convertList(list, o -> BeanUtils.toBean(o, ErpStockInItemDO.class, item -> item .setProductUnitId(productMap.get(item.getProductId()).getUnitId()) - .setTotalPrice(item.getProductPrice().multiply(item.getCount())))); + .setTotalPrice(NumberUtils.mul(item.getProductPrice(), item.getCount())))); } private void updateStockInItemList(Long id, List newList) { @@ -122,21 +145,33 @@ public class ErpStockInServiceImpl implements ErpStockInService { @Override @Transactional(rollbackFor = Exception.class) - public void deleteStockIn(Long id) { - // 1. 校验存在 - validateStockInExists(id); - // TODO 芋艿:校验一下; + public void deleteStockIn(List ids) { + // 1. 校验不处于已审批 + List stockIns = stockInMapper.selectBatchIds(ids); + if (CollUtil.isEmpty(stockIns)) { + return; + } + stockIns.forEach(stockIn -> { + if (ErpAuditStatus.APPROVE.getStatus().equals(stockIn.getStatus())) { + throw exception(STOCK_IN_DELETE_FAIL_APPROVE, stockIn.getNo()); + } + }); - // 2.1 删除 - stockInMapper.deleteById(id); - // 2.2 删除子表 - stockInItemMapper.deleteByInId(id); + // 2. 遍历删除,并记录操作日志 + stockIns.forEach(stockIn -> { + // 2.1 删除入库单 + stockInMapper.deleteById(stockIn.getId()); + // 2.2 删除入库单项 + stockInItemMapper.deleteByInId(stockIn.getId()); + }); } - private void validateStockInExists(Long id) { - if (stockInMapper.selectById(id) == null) { + private ErpStockInDO validateStockInExists(Long id) { + ErpStockInDO stockIn = stockInMapper.selectById(id); + if (stockIn == null) { throw exception(STOCK_IN_NOT_EXISTS); } + return stockIn; } @Override @@ -149,7 +184,7 @@ public class ErpStockInServiceImpl implements ErpStockInService { return stockInMapper.selectPage(pageReqVO); } - // ==================== 子表(ERP 其它入库单项) ==================== + // ==================== 入库项 ==================== @Override public List getStockInItemListByInId(Long inId) { From f6d3290426fce784dded91579775a5af244208e0 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 7 Feb 2024 00:37:42 +0800 Subject: [PATCH 08/15] =?UTF-8?q?=E2=9C=A8=20ERP=EF=BC=9A=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=85=A5=E5=BA=93=E5=8D=95=E5=8F=B7=E7=9A=84=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E7=94=9F=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/erp/enums/ErrorCodeConstants.java | 2 +- yudao-module-erp/yudao-module-erp-biz/pom.xml | 5 ++ .../stock/vo/in/ErpStockInSaveReqVO.java | 4 -- .../erp/dal/mysql/stock/ErpStockInMapper.java | 4 ++ .../erp/dal/redis/RedisKeyConstants.java | 18 +++++++ .../erp/dal/redis/no/ErpNoRedisDAO.java | 47 +++++++++++++++++++ .../service/stock/ErpStockInServiceImpl.java | 11 ++++- 7 files changed, 85 insertions(+), 6 deletions(-) create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/RedisKeyConstants.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java diff --git a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java index 5cfec682c..3f98d4314 100644 --- a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java +++ b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java @@ -25,7 +25,7 @@ public interface ErrorCodeConstants { ErrorCode STOCK_IN_DELETE_FAIL_APPROVE = new ErrorCode(1_030_401_001, "其它入库单({})已审核,无法删除"); ErrorCode STOCK_IN_PROCESS_FAIL = new ErrorCode(1_030_401_002, "反审核失败,只有已审核的入库单才能反审核"); ErrorCode STOCK_IN_APPROVE_FAIL = new ErrorCode(1_030_401_003, "审核失败,只有未审核的入库单才能审核"); - + ErrorCode STOCK_IN_NO_EXISTS = new ErrorCode(1_030_401_004, "生成入库单失败,请重新提交"); // ========== ERP 产品 1-030-500-000 ========== ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_030_500_000, "产品不存在"); diff --git a/yudao-module-erp/yudao-module-erp-biz/pom.xml b/yudao-module-erp/yudao-module-erp-biz/pom.xml index 83b3900cf..1d0b44162 100644 --- a/yudao-module-erp/yudao-module-erp-biz/pom.xml +++ b/yudao-module-erp/yudao-module-erp-biz/pom.xml @@ -51,6 +51,11 @@ yudao-spring-boot-starter-mybatis + + cn.iocoder.boot + yudao-spring-boot-starter-redis + + cn.iocoder.boot diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInSaveReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInSaveReqVO.java index e3a87da8a..0187872c8 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInSaveReqVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInSaveReqVO.java @@ -17,10 +17,6 @@ public class ErpStockInSaveReqVO { @Schema(description = "入库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") private Long id; - @Schema(description = "入库单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "S123") - @NotEmpty(message = "入库单号不能为空") - private String no; - @Schema(description = "供应商编号", example = "3113") private Long supplierId; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockInMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockInMapper.java index eadf02c75..9e7ea9bca 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockInMapper.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockInMapper.java @@ -40,4 +40,8 @@ public interface ErpStockInMapper extends BaseMapperX { .eq(ErpStockInDO::getId, id).eq(ErpStockInDO::getStatus, status)); } + default ErpStockInDO selectByNo(String no) { + return selectOne(ErpStockInDO::getNo, no); + } + } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/RedisKeyConstants.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/RedisKeyConstants.java new file mode 100644 index 000000000..f0ba46807 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/RedisKeyConstants.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.erp.dal.redis; + +/** + * ERP Redis Key 枚举类 + * + * @author 芋道源码 + */ +public interface RedisKeyConstants { + + /** + * 序号的缓存 + * + * KEY 格式:trade_no:{prefix} + * VALUE 数据格式:编号自增 + */ + String NO = "seq_no:"; + +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java new file mode 100644 index 000000000..e211864cc --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.erp.dal.redis.no; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import cn.iocoder.yudao.module.erp.dal.redis.RedisKeyConstants; +import jakarta.annotation.Resource; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Repository; + +import java.time.Duration; +import java.time.LocalDateTime; + + +/** + * 订单序号的 Redis DAO + * + * @author HUIHUI + */ +@Repository +public class ErpNoRedisDAO { + + /** + * 其它入库 STOCK_IN + */ + public static final String STOCK_IN_NO_PREFIX = "QTRK"; + + @Resource + private StringRedisTemplate stringRedisTemplate; + + /** + * 生成序号,使用当前日期,格式为 {PREFIX} + yyyyMMdd + 6 位自增 + * 例如说:QTRK 202109 000001 (没有中间空格) + * + * @param prefix 前缀 + * @return 序号 + */ + public String generate(String prefix) { + // 递增序号 + String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATE_PATTERN); + String key = RedisKeyConstants.NO + noPrefix; + Long no = stringRedisTemplate.opsForValue().increment(key); + // 设置过期时间 + stringRedisTemplate.expire(key, Duration.ofMinutes(1L)); + return noPrefix + String.format("%06d", no); + } + +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java index 305676445..8f4835013 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java @@ -11,6 +11,7 @@ import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInDO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInItemDO; import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockInItemMapper; import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockInMapper; +import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO; import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; import cn.iocoder.yudao.module.erp.service.product.ErpProductService; import cn.iocoder.yudao.module.erp.service.purchase.ErpSupplierService; @@ -44,6 +45,9 @@ public class ErpStockInServiceImpl implements ErpStockInService { @Resource private ErpStockInItemMapper stockInItemMapper; + @Resource + private ErpNoRedisDAO noRedisDAO; + @Resource private ErpProductService productService; @Resource @@ -58,10 +62,15 @@ public class ErpStockInServiceImpl implements ErpStockInService { List stockInItems = validateStockInItems(createReqVO.getItems()); // 1.2 校验供应商 supplierService.validateSupplier(createReqVO.getSupplierId()); + // 1.3 + String no = noRedisDAO.generate(ErpNoRedisDAO.STOCK_IN_NO_PREFIX); + if (stockInMapper.selectByNo(no) != null) { + throw exception(STOCK_IN_NO_EXISTS); + } // 2.1 插入入库单 ErpStockInDO stockIn = BeanUtils.toBean(createReqVO, ErpStockInDO.class, in -> in - .setStatus(ErpAuditStatus.PROCESS.getStatus()) + .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus()) .setTotalCount(getSumValue(stockInItems, ErpStockInItemDO::getCount, BigDecimal::add)) .setTotalPrice(getSumValue(stockInItems, ErpStockInItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO))); stockInMapper.insert(stockIn); From 3479ef81234da086d606989ddcdec1e796a65ca2 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 7 Feb 2024 10:34:23 +0800 Subject: [PATCH 09/15] =?UTF-8?q?=E2=9C=A8=20ERP=EF=BC=9A=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E9=87=91=E9=A2=9D=E8=AE=A1=E7=AE=97=E7=9A=84=E5=9B=9B?= =?UTF-8?q?=E8=88=8D=E4=BA=94=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/util/number/MoneyUtils.java | 21 +++++++++++++++++++ .../service/stock/ErpStockInServiceImpl.java | 4 ++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/MoneyUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/MoneyUtils.java index ccfeb3917..dbc16dc86 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/MoneyUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/MoneyUtils.java @@ -13,6 +13,11 @@ import java.math.RoundingMode; */ public class MoneyUtils { + /** + * 金额的小数位数 + */ + private static final int PRICE_SCALE = 2; + /** * 计算百分比金额,四舍五入 * @@ -86,4 +91,20 @@ public class MoneyUtils { return new Money(0, fen).toString(); } + /** + * 金额相乘,默认进行四舍五入 + * + * 位数:{@link #PRICE_SCALE} + * + * @param price 金额 + * @param count 数量 + * @return 金额相乘结果 + */ + public static BigDecimal priceMultiply(BigDecimal price, BigDecimal count) { + if (price == null || count == null) { + return null; + } + return price.multiply(count).setScale(PRICE_SCALE, RoundingMode.HALF_UP); + } + } diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java index 8f4835013..55dbf8def 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.erp.service.stock; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInPageReqVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInSaveReqVO; @@ -130,7 +130,7 @@ public class ErpStockInServiceImpl implements ErpStockInService { // 2. 转化为 ErpStockInItemDO 列表 return convertList(list, o -> BeanUtils.toBean(o, ErpStockInItemDO.class, item -> item .setProductUnitId(productMap.get(item.getProductId()).getUnitId()) - .setTotalPrice(NumberUtils.mul(item.getProductPrice(), item.getCount())))); + .setTotalPrice(MoneyUtils.priceMultiply(item.getProductPrice(), item.getCount())))); } private void updateStockInItemList(Long id, List newList) { From dbc6134f805d82d4a3d6d214d71e8eda4064df7f Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 7 Feb 2024 12:24:56 +0800 Subject: [PATCH 10/15] =?UTF-8?q?=E2=9C=A8=20ERP=EF=BC=9A=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=BA=93=E5=AD=98=E5=8F=98=E6=9B=B4=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/erp/enums/ErrorCodeConstants.java | 6 ++ .../dataobject/stock/ErpStockRecordDO.java | 9 +-- .../erp/dal/mysql/stock/ErpStockMapper.java | 17 ++++++ .../service/stock/ErpStockInServiceImpl.java | 22 +++++-- .../service/stock/ErpStockRecordService.java | 9 +++ .../stock/ErpStockRecordServiceImpl.java | 20 +++++++ .../erp/service/stock/ErpStockService.java | 12 ++++ .../service/stock/ErpStockServiceImpl.java | 36 +++++++++++ .../stock/bo/ErpStockInCreateReqBO.java | 59 +++++++++++++++++++ 9 files changed, 181 insertions(+), 9 deletions(-) create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/bo/ErpStockInCreateReqBO.java diff --git a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java index 3f98d4314..ba7d7685c 100644 --- a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java +++ b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java @@ -27,6 +27,12 @@ public interface ErrorCodeConstants { ErrorCode STOCK_IN_APPROVE_FAIL = new ErrorCode(1_030_401_003, "审核失败,只有未审核的入库单才能审核"); ErrorCode STOCK_IN_NO_EXISTS = new ErrorCode(1_030_401_004, "生成入库单失败,请重新提交"); + // ========== ERP 其它出库单 1-030-402-000 ========== + + // ========== ERP 产品库存 1-030-403-000 ========== + ErrorCode STOCK_COUNT_NEGATIVE = new ErrorCode(1_030_403_000, "操作失败,产品当前库存:{},小于变更数量:{}"); + ErrorCode STOCK_COUNT_NEGATIVE2 = new ErrorCode(1_030_403_000, "操作失败,库存不足"); + // ========== ERP 产品 1-030-500-000 ========== ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_030_500_000, "产品不存在"); ErrorCode PRODUCT_NOT_ENABLE = new ErrorCode(1_030_500_001, "产品({})未启用"); diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockRecordDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockRecordDO.java index be010eb04..7bc5e5a01 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockRecordDO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockRecordDO.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.erp.dal.dataobject.stock; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import cn.iocoder.yudao.module.erp.enums.stock.ErpStockRecordBizTypeEnum; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; @@ -56,25 +57,25 @@ public class ErpStockRecordDO extends BaseDO { /** * 业务类型 * - * 枚举 {@link cn.iocoder.yudao.module.erp.enums.stock.ErpStockRecordBizTypeEnum} + * 枚举 {@link ErpStockRecordBizTypeEnum} */ private Integer bizType; /** * 业务编号 * - * 例如说:TODO + * 例如说:{@link ErpStockInDO#getId()} */ private Long bizId; /** * 业务项编号 * - * 例如说:TODO + * 例如说:{@link ErpStockInItemDO#getId()} */ private Long bizItemId; /** * 业务单号 * - * 例如说:TODO + * 例如说:{@link ErpStockInDO#getNo()} */ private String bizNo; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java index 5afe42da0..35fd85248 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java @@ -5,8 +5,11 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stock.ErpStockPageReqVO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; +import java.math.BigDecimal; + /** * ERP 产品库存 Mapper * @@ -27,4 +30,18 @@ public interface ErpStockMapper extends BaseMapperX { ErpStockDO::getWarehouseId, warehouseId); } + default int updateCountIncrement(Long id, BigDecimal count, boolean negativeEnable) { + LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper() + .eq(ErpStockDO::getId, id); + if (count.compareTo(BigDecimal.ZERO) > 0) { + updateWrapper.setSql("count = count + " + count); + } else if (count.compareTo(BigDecimal.ZERO) < 0) { + if (!negativeEnable) { + updateWrapper.gt(ErpStockDO::getCount, count.abs()); + } + updateWrapper.setSql("count = count - " + count.abs()); + } + return update(null, updateWrapper); + } + } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java index 55dbf8def..85aa6ff53 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java @@ -13,8 +13,10 @@ import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockInItemMapper; import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockInMapper; import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO; import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import cn.iocoder.yudao.module.erp.enums.stock.ErpStockRecordBizTypeEnum; import cn.iocoder.yudao.module.erp.service.product.ErpProductService; import cn.iocoder.yudao.module.erp.service.purchase.ErpSupplierService; +import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockInCreateReqBO; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -54,6 +56,8 @@ public class ErpStockInServiceImpl implements ErpStockInService { private ErpWarehouseService warehouseService; @Resource private ErpSupplierService supplierService; + @Resource + private ErpStockRecordService stockRecordService; @Override @Transactional(rollbackFor = Exception.class) @@ -102,23 +106,31 @@ public class ErpStockInServiceImpl implements ErpStockInService { @Override @Transactional(rollbackFor = Exception.class) public void updateStockInStatus(Long id, Integer status) { + boolean approve = ErpAuditStatus.APPROVE.getStatus().equals(status); // 1.1 校验存在 ErpStockInDO stockIn = validateStockInExists(id); // 1.2 校验状态 if (stockIn.getStatus().equals(status)) { - throw exception(ErpAuditStatus.PROCESS.getStatus().equals(status) ? - STOCK_IN_PROCESS_FAIL : STOCK_IN_APPROVE_FAIL); + throw exception(approve ? STOCK_IN_APPROVE_FAIL : STOCK_IN_PROCESS_FAIL); } // 2. 更新状态 int updateCount = stockInMapper.updateByIdAndStatus(id, stockIn.getStatus(), new ErpStockInDO().setStatus(status)); if (updateCount == 0) { - throw exception(ErpAuditStatus.PROCESS.getStatus().equals(status) ? - STOCK_IN_PROCESS_FAIL : STOCK_IN_APPROVE_FAIL); + throw exception(approve ? STOCK_IN_APPROVE_FAIL : STOCK_IN_PROCESS_FAIL); } - // 3. TODO 芋艿:调整库存记录 + // 3. 变更库存 + List stockInItems = stockInItemMapper.selectListByInId(id); + Integer bizType = approve ? ErpStockRecordBizTypeEnum.OTHER_IN.getType() + : ErpStockRecordBizTypeEnum.OTHER_IN_CANCEL.getType(); + stockInItems.forEach(stockInItem -> { + BigDecimal count = approve ? stockInItem.getCount() : stockInItem.getCount().negate(); + stockRecordService.createStockRecord(new ErpStockInCreateReqBO( + stockInItem.getProductId(), stockInItem.getWarehouseId(), count, + bizType, stockInItem.getInId(), stockInItem.getId(), stockIn.getNo())); + }); } private List validateStockInItems(List list) { diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordService.java index 08acb89b5..0e20a55f2 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordService.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordService.java @@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.erp.service.stock; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.record.ErpStockRecordPageReqVO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockRecordDO; +import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockInCreateReqBO; +import jakarta.validation.Valid; /** * ERP 产品库存明细 Service 接口 @@ -27,4 +29,11 @@ public interface ErpStockRecordService { */ PageResult getStockRecordPage(ErpStockRecordPageReqVO pageReqVO); + /** + * 创建库存明细 + * + * @param createReqBO 创建库存明细 BO + */ + void createStockRecord(@Valid ErpStockInCreateReqBO createReqBO); + } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordServiceImpl.java index 6f50b91cc..708a39f18 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordServiceImpl.java @@ -1,13 +1,18 @@ package cn.iocoder.yudao.module.erp.service.stock; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.record.ErpStockRecordPageReqVO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockRecordDO; import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockRecordMapper; +import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockInCreateReqBO; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; +import java.math.BigDecimal; + /** * ERP 产品库存明细 Service 实现类 * @@ -20,6 +25,9 @@ public class ErpStockRecordServiceImpl implements ErpStockRecordService { @Resource private ErpStockRecordMapper stockRecordMapper; + @Resource + private ErpStockService stockService; + @Override public ErpStockRecordDO getStockRecord(Long id) { return stockRecordMapper.selectById(id); @@ -30,4 +38,16 @@ public class ErpStockRecordServiceImpl implements ErpStockRecordService { return stockRecordMapper.selectPage(pageReqVO); } + @Override + @Transactional(rollbackFor = Exception.class) + public void createStockRecord(ErpStockInCreateReqBO createReqBO) { + // 1. 更新库存 + BigDecimal totalCount = stockService.updateStockCountIncrement( + createReqBO.getProductId(), createReqBO.getWarehouseId(), createReqBO.getCount()); + // 2. 创建库存明细 + ErpStockRecordDO stockRecord = BeanUtils.toBean(createReqBO, ErpStockRecordDO.class) + .setTotalCount(totalCount); + stockRecordMapper.insert(stockRecord); + } + } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockService.java index f9cd26158..91224c7fa 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockService.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockService.java @@ -4,6 +4,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stock.ErpStockPageReqVO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; +import java.math.BigDecimal; + /** * ERP 产品库存 Service 接口 * @@ -36,4 +38,14 @@ public interface ErpStockService { */ PageResult getStockPage(ErpStockPageReqVO pageReqVO); + /** + * 增量更新产品库存数量 + * + * @param productId 产品编号 + * @param warehouseId 仓库编号 + * @param count 增量数量:正数,表示增加;负数,表示减少 + * @return 更新后的库存 + */ + BigDecimal updateStockCountIncrement(Long productId, Long warehouseId, BigDecimal count); + } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockServiceImpl.java index 423774265..c930cff36 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockServiceImpl.java @@ -8,6 +8,12 @@ import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.math.BigDecimal; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_COUNT_NEGATIVE; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_COUNT_NEGATIVE2; + /** * ERP 产品库存 Service 实现类 * @@ -17,6 +23,13 @@ import org.springframework.validation.annotation.Validated; @Validated public class ErpStockServiceImpl implements ErpStockService { + /** + * 允许库存为负数 + * + * TODO 芋艿:后续做成 db 配置 + */ + private static final Boolean NEGATIVE_STOCK_COUNT_ENABLE = false; + @Resource private ErpStockMapper stockMapper; @@ -35,4 +48,27 @@ public class ErpStockServiceImpl implements ErpStockService { return stockMapper.selectPage(pageReqVO); } + @Override + public BigDecimal updateStockCountIncrement(Long productId, Long warehouseId, BigDecimal count) { + // 1.1 查询当前库存 + ErpStockDO stock = stockMapper.selectByProductIdAndWarehouseId(productId, warehouseId); + if (stock == null) { + stock = new ErpStockDO().setProductId(productId).setWarehouseId(warehouseId).setCount(BigDecimal.ZERO); + stockMapper.insert(stock); + } + // 1.2 校验库存是否充足 + if (!NEGATIVE_STOCK_COUNT_ENABLE && stock.getCount().add(count).compareTo(BigDecimal.ZERO) < 0) { + throw exception(STOCK_COUNT_NEGATIVE, stock.getCount(), count); + } + + // 2. 库存变更 + int updateCount = stockMapper.updateCountIncrement(stock.getId(), count, NEGATIVE_STOCK_COUNT_ENABLE); + if (updateCount == 0) { + throw exception(STOCK_COUNT_NEGATIVE2); // 此时不好去查询最新库存,所以直接抛出该提示,不提供具体库存数字 + } + + // 3. 返回最新库存 + return stock.getCount().add(count); + } + } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/bo/ErpStockInCreateReqBO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/bo/ErpStockInCreateReqBO.java new file mode 100644 index 000000000..3211a2e76 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/bo/ErpStockInCreateReqBO.java @@ -0,0 +1,59 @@ +package cn.iocoder.yudao.module.erp.service.stock.bo; + +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +/** + * 库存明细的创建 Request BO + * + * @author 芋道源码 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ErpStockInCreateReqBO { + + /** + * 产品编号 + */ + @NotNull(message = "产品编号不能为空") + private Long productId; + /** + * 仓库编号 + */ + @NotNull(message = "仓库编号不能为空") + private Long warehouseId; + /** + * 出入库数量 + * + * 正数,表示入库;负数,表示出库 + */ + @NotNull(message = "出入库数量不能为空") + private BigDecimal count; + + /** + * 业务类型 + */ + @NotNull(message = "业务类型不能为空") + private Integer bizType; + /** + * 业务编号 + */ + @NotNull(message = "业务编号不能为空") + private Long bizId; + /** + * 业务项编号 + */ + @NotNull(message = "业务项编号不能为空") + private Long bizItemId; + /** + * 业务单号 + */ + @NotNull(message = "业务单号不能为空") + private String bizNo; + +} From 256d2435079c64b807fa3383d4a85167229c4992 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 7 Feb 2024 15:00:40 +0800 Subject: [PATCH 11/15] =?UTF-8?q?=E2=9C=A8=20ERP=EF=BC=9A=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E5=8C=96=E5=85=B6=E5=AE=83=E5=87=BA=E5=BA=93=E7=9A=84?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/erp/enums/ErrorCodeConstants.java | 7 + .../admin/stock/ErpStockOutController.java | 163 +++++++++++++ .../stock/vo/out/ErpStockOutPageReqVO.java | 48 ++++ .../admin/stock/vo/out/ErpStockOutRespVO.java | 110 +++++++++ .../stock/vo/out/ErpStockOutSaveReqVO.java | 64 +++++ .../dal/dataobject/stock/ErpStockInDO.java | 3 +- .../dal/dataobject/stock/ErpStockOutDO.java | 69 ++++++ .../dataobject/stock/ErpStockOutItemDO.java | 73 ++++++ .../mysql/stock/ErpStockOutItemMapper.java | 30 +++ .../dal/mysql/stock/ErpStockOutMapper.java | 47 ++++ .../erp/dal/redis/no/ErpNoRedisDAO.java | 6 +- .../service/stock/ErpStockInServiceImpl.java | 9 +- .../erp/service/stock/ErpStockOutService.java | 84 +++++++ .../service/stock/ErpStockOutServiceImpl.java | 227 ++++++++++++++++++ .../service/stock/ErpStockRecordService.java | 4 +- .../stock/ErpStockRecordServiceImpl.java | 4 +- ...BO.java => ErpStockRecordCreateReqBO.java} | 2 +- 17 files changed, 940 insertions(+), 10 deletions(-) create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockOutController.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/out/ErpStockOutPageReqVO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/out/ErpStockOutRespVO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/out/ErpStockOutSaveReqVO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockOutDO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockOutItemDO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockOutItemMapper.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockOutMapper.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutService.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java rename yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/bo/{ErpStockInCreateReqBO.java => ErpStockRecordCreateReqBO.java} (96%) diff --git a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java index ba7d7685c..7bd87bdb9 100644 --- a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java +++ b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java @@ -26,8 +26,15 @@ public interface ErrorCodeConstants { ErrorCode STOCK_IN_PROCESS_FAIL = new ErrorCode(1_030_401_002, "反审核失败,只有已审核的入库单才能反审核"); ErrorCode STOCK_IN_APPROVE_FAIL = new ErrorCode(1_030_401_003, "审核失败,只有未审核的入库单才能审核"); ErrorCode STOCK_IN_NO_EXISTS = new ErrorCode(1_030_401_004, "生成入库单失败,请重新提交"); + ErrorCode STOCK_IN_UPDATE_FAIL_APPROVE = new ErrorCode(1_030_401_005, "其它入库单({})已审核,无法修改"); // ========== ERP 其它出库单 1-030-402-000 ========== + ErrorCode STOCK_OUT_NOT_EXISTS = new ErrorCode(1_030_402_000, "其它出库单不存在"); + ErrorCode STOCK_OUT_DELETE_FAIL_APPROVE = new ErrorCode(1_030_402_001, "其它出库单({})已审核,无法删除"); + ErrorCode STOCK_OUT_PROCESS_FAIL = new ErrorCode(1_030_402_002, "反审核失败,只有已审核的出库单才能反审核"); + ErrorCode STOCK_OUT_APPROVE_FAIL = new ErrorCode(1_030_402_003, "审核失败,只有未审核的出库单才能审核"); + ErrorCode STOCK_OUT_NO_EXISTS = new ErrorCode(1_030_402_004, "生成出库单失败,请重新提交"); + ErrorCode STOCK_OUT_UPDATE_FAIL_APPROVE = new ErrorCode(1_030_402_005, "其它出库单({})已审核,无法修改"); // ========== ERP 产品库存 1-030-403-000 ========== ErrorCode STOCK_COUNT_NEGATIVE = new ErrorCode(1_030_403_000, "操作失败,产品当前库存:{},小于变更数量:{}"); diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockOutController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockOutController.java new file mode 100644 index 000000000..306d51277 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockOutController.java @@ -0,0 +1,163 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutItemDO; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.stock.ErpStockOutService; +import cn.iocoder.yudao.module.erp.service.stock.ErpStockService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; + +@Tag(name = "管理后台 - ERP 其它出库单") +@RestController +@RequestMapping("/erp/stock-out") +@Validated +public class ErpStockOutController { + + @Resource + private ErpStockOutService stockOutService; + @Resource + private ErpStockService stockService; + @Resource + private ErpProductService productService; +// @Resource +// private ErpSupplierService supplierService; + + @Resource + private AdminUserApi adminUserApi; + + @PostMapping("/create") + @Operation(summary = "创建其它出库单") + @PreAuthorize("@ss.hasPermission('erp:stock-out:create')") + public CommonResult createStockOut(@Valid @RequestBody ErpStockOutSaveReqVO createReqVO) { + return success(stockOutService.createStockOut(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新其它出库单") + @PreAuthorize("@ss.hasPermission('erp:stock-out:update')") + public CommonResult updateStockOut(@Valid @RequestBody ErpStockOutSaveReqVO updateReqVO) { + stockOutService.updateStockOut(updateReqVO); + return success(true); + } + + @PutMapping("/update-status") + @Operation(summary = "更新其它出库单的状态") + @PreAuthorize("@ss.hasPermission('erp:stock-out:update')") + public CommonResult updateStockOutStatus(@RequestParam("id") Long id, + @RequestParam("status") Integer status) { + stockOutService.updateStockOutStatus(id, status); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除其它出库单") + @Parameter(name = "ids", description = "编号数组", required = true) + @PreAuthorize("@ss.hasPermission('erp:stock-out:delete')") + public CommonResult deleteStockOut(@RequestParam("ids") List ids) { + stockOutService.deleteStockOut(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得其它出库单") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('erp:stock-out:query')") + public CommonResult getStockOut(@RequestParam("id") Long id) { + ErpStockOutDO stockOut = stockOutService.getStockOut(id); + if (stockOut == null) { + return success(null); + } + List stockOutItemList = stockOutService.getStockOutItemListByOutId(id); + Map productMap = productService.getProductVOMap( + convertSet(stockOutItemList, ErpStockOutItemDO::getProductId)); + return success(BeanUtils.toBean(stockOut, ErpStockOutRespVO.class, stockOutVO -> + stockOutVO.setItems(BeanUtils.toBean(stockOutItemList, ErpStockOutRespVO.Item.class, item -> { + ErpStockDO stock = stockService.getStock(item.getProductId(), item.getWarehouseId()); + item.setStockCount(stock != null ? stock.getCount() : BigDecimal.ZERO); + MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())); + })))); + } + + @GetMapping("/page") + @Operation(summary = "获得其它出库单分页") + @PreAuthorize("@ss.hasPermission('erp:stock-out:query')") + public CommonResult> getStockOutPage(@Valid ErpStockOutPageReqVO pageReqVO) { + PageResult pageResult = stockOutService.getStockOutPage(pageReqVO); + return success(buildStockOutVOPageResult(pageResult)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出其它出库单 Excel") + @PreAuthorize("@ss.hasPermission('erp:stock-out:export')") + @OperateLog(type = EXPORT) + public void exportStockOutExcel(@Valid ErpStockOutPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = buildStockOutVOPageResult(stockOutService.getStockOutPage(pageReqVO)).getList(); + // 导出 Excel + ExcelUtils.write(response, "其它出库单.xls", "数据", ErpStockOutRespVO.class, list); + } + + private PageResult buildStockOutVOPageResult(PageResult pageResult) { + if (CollUtil.isEmpty(pageResult.getList())) { + return PageResult.empty(pageResult.getTotal()); + } + // 1.1 出库项 + List stockOutItemList = stockOutService.getStockOutItemListByOutIds( + convertSet(pageResult.getList(), ErpStockOutDO::getId)); + Map> stockOutItemMap = convertMultiMap(stockOutItemList, ErpStockOutItemDO::getOutId); + // 1.2 商品信息 + Map productMap = productService.getProductVOMap( + convertSet(stockOutItemList, ErpStockOutItemDO::getProductId)); + // 1.3 客户信息 TODO +// Map supplierMap = supplierService.getSupplierMap( +// convertSet(pageResult.getList(), ErpStockOutDO::getSupplierId)); + // 1.4 管理员信息 + Map userMap = adminUserApi.getUserMap( + convertSet(pageResult.getList(), erpStockRecordDO -> Long.parseLong(erpStockRecordDO.getCreator()))); + // 2. 开始拼接 + return BeanUtils.toBean(pageResult, ErpStockOutRespVO.class, stockOut -> { + stockOut.setItems(BeanUtils.toBean(stockOutItemMap.get(stockOut.getId()), ErpStockOutRespVO.Item.class, + item -> MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())))); + stockOut.setProductNames(CollUtil.join(stockOut.getItems(), ",", ErpStockOutRespVO.Item::getProductName)); +// MapUtils.findAndThen(supplierMap, stockOut.getSupplierId(), supplier -> stockOut.setSupplierName(supplier.getName())); + MapUtils.findAndThen(userMap, Long.parseLong(stockOut.getCreator()), user -> stockOut.setCreatorName(user.getNickname())); + }); + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/out/ErpStockOutPageReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/out/ErpStockOutPageReqVO.java new file mode 100644 index 000000000..5f6558b19 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/out/ErpStockOutPageReqVO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - ERP 其它出库单分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ErpStockOutPageReqVO extends PageParam { + + @Schema(description = "出库单号", example = "S123") + private String no; + + @Schema(description = "客户编号", example = "3113") + private Long customerId; + + @Schema(description = "出库时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] outTime; + + @Schema(description = "状态", example = "10") + @InEnum(ErpAuditStatus.class) + private Integer status; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "创建者") + private String creator; + + @Schema(description = "产品编号", example = "1") + private Long productId; + + @Schema(description = "仓库编号", example = "1") + private Long warehouseId; + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/out/ErpStockOutRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/out/ErpStockOutRespVO.java new file mode 100644 index 000000000..e0128730e --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/out/ErpStockOutRespVO.java @@ -0,0 +1,110 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.module.erp.enums.DictTypeConstants.AUDIT_STATUS; + +@Schema(description = "管理后台 - ERP 其它出库单 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ErpStockOutRespVO { + + @Schema(description = "出库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + @ExcelProperty("出库编号") + private Long id; + + @Schema(description = "出库单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "S123") + @ExcelProperty("出库单号") + private String no; + + @Schema(description = "客户编号", example = "3113") + private Long customerId; + @Schema(description = "客户名称", example = "芋道") + @ExcelProperty("客户名称") + private String customerName; + + @Schema(description = "出库时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("出库时间") + private LocalDateTime outTime; + + @Schema(description = "合计数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "15663") + @ExcelProperty("合计数量") + private BigDecimal totalCount; + + @Schema(description = "合计金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "24906") + @ExcelProperty("合计金额") + private BigDecimal totalPrice; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @ExcelProperty(value = "状态", converter = DictConvert.class) + @DictFormat(AUDIT_STATUS) + private Integer status; + + @Schema(description = "备注", example = "随便") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "附件 URL", example = "https://www.iocoder.cn/1.doc") + private String fileUrl; + + @Schema(description = "审核人", example = "芋道") + private String creator; + @Schema(description = "审核人名称", example = "芋道") + private String creatorName; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "出库项列表", requiredMode = Schema.RequiredMode.REQUIRED) + private List items; + + @Schema(description = "产品信息", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("产品信息") + private String productNames; + + @Data + public static class Item { + + @Schema(description = "出库项编号", example = "11756") + private Long id; + + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long warehouseId; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long productId; + + @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal productPrice; + + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal count; + + @Schema(description = "备注", example = "随便") + private String remark; + + // ========== 关联字段 ========== + + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "巧克力") + private String productName; + @Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "A9985") + private String productBarCode; + @Schema(description = "产品单位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "盒") + private String productUnitName; + + @Schema(description = "库存数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal stockCount; // 该字段仅仅在“详情”和“编辑”时使用 + + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/out/ErpStockOutSaveReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/out/ErpStockOutSaveReqVO.java new file mode 100644 index 000000000..5a903798e --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/out/ErpStockOutSaveReqVO.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - ERP 其它出库单新增/修改 Request VO") +@Data +public class ErpStockOutSaveReqVO { + + @Schema(description = "出库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + private Long id; + + @Schema(description = "客户编号", example = "3113") + private Long customerId; + + @Schema(description = "出库时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "出库时间不能为空") + private LocalDateTime outTime; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "附件 URL", example = "https://www.iocoder.cn/1.doc") + private String fileUrl; + + @Schema(description = "出库项列表", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "出库项列表不能为空") + @Valid + private List items; + + @Data + public static class Item { + + @Schema(description = "出库项编号", example = "11756") + private Long id; + + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "仓库编号不能为空") + private Long warehouseId; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "产品编号不能为空") + private Long productId; + + @Schema(description = "产品单价", example = "100.00") + private BigDecimal productPrice; + + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "产品数量不能为空") + private BigDecimal count; + + @Schema(description = "备注", example = "随便") + private String remark; + + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockInDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockInDO.java index 4eaa316e9..5115b9daf 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockInDO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockInDO.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.erp.dal.dataobject.stock; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.supplier.ErpSupplierDO; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; @@ -36,7 +37,7 @@ public class ErpStockInDO extends BaseDO { /** * 供应商编号 * - * TODO 芋艿:待关联 + * 关联 {@link ErpSupplierDO#getId()} */ private Long supplierId; /** diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockOutDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockOutDO.java new file mode 100644 index 000000000..e0b337adb --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockOutDO.java @@ -0,0 +1,69 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.stock; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * ERP 其它出库单 DO + * + * @author 芋道源码 + */ +@TableName("erp_stock_out") +@KeySequence("erp_stock_out_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpStockOutDO extends BaseDO { + + /** + * 出库编号 + */ + @TableId + private Long id; + /** + * 出库单号 + */ + private String no; + /** + * 客户编号 + * + * TODO 芋艿:待关联 + */ + private Long customerId; + /** + * 出库时间 + */ + private LocalDateTime outTime; + /** + * 合计数量 + */ + private BigDecimal totalCount; + /** + * 合计金额,单位:元 + */ + private BigDecimal totalPrice; + /** + * 状态 + * + * 枚举 {@link cn.iocoder.yudao.module.erp.enums.ErpAuditStatus} + */ + private Integer status; + /** + * 备注 + */ + private String remark; + /** + * 附件 URL + */ + private String fileUrl; + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockOutItemDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockOutItemDO.java new file mode 100644 index 000000000..065c5255a --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockOutItemDO.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.stock; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * ERP 其它出库单项 DO + * + * @author 芋道源码 + */ +@TableName("erp_stock_out_item") +@KeySequence("erp_stock_out_item_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpStockOutItemDO extends BaseDO { + + /** + * 出库项编号 + */ + @TableId + private Long id; + /** + * 出库编号 + * + * 关联 {@link ErpStockOutDO#getId()} + */ + private Long outId; + /** + * 仓库编号 + * + * 关联 {@link ErpWarehouseDO#getId()} + */ + private Long warehouseId; + /** + * 产品编号 + * + * 关联 {@link ErpProductDO#getId()} + */ + private Long productId; + /** + * 产品单位编号 + * + * 冗余 {@link ErpProductDO#getUnitId()} + */ + private Long productUnitId; + /** + * 产品单价 + */ + private BigDecimal productPrice; + /** + * 产品数量 + */ + private BigDecimal count; + /** + * 合计金额,单位:元 + */ + private BigDecimal totalPrice; + /** + * 备注 + */ + private String remark; + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockOutItemMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockOutItemMapper.java new file mode 100644 index 000000000..3b27cd3dc --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockOutItemMapper.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.stock; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutItemDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +/** + * ERP 其它出库单项 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpStockOutItemMapper extends BaseMapperX { + + default List selectListByOutId(Long outId) { + return selectList(ErpStockOutItemDO::getOutId, outId); + } + + default List selectListByOutIds(Collection outIds) { + return selectList(ErpStockOutItemDO::getOutId, outIds); + } + + default int deleteByOutId(Long outId) { + return delete(ErpStockOutItemDO::getOutId, outId); + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockOutMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockOutMapper.java new file mode 100644 index 000000000..f27e01310 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockOutMapper.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutItemDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +/** + * ERP 其它出库单 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpStockOutMapper extends BaseMapperX { + + default PageResult selectPage(ErpStockOutPageReqVO reqVO) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX() + .eqIfPresent(ErpStockOutDO::getNo, reqVO.getNo()) + .eqIfPresent(ErpStockOutDO::getCustomerId, reqVO.getCustomerId()) + .betweenIfPresent(ErpStockOutDO::getOutTime, reqVO.getOutTime()) + .eqIfPresent(ErpStockOutDO::getStatus, reqVO.getStatus()) + .likeIfPresent(ErpStockOutDO::getRemark, reqVO.getRemark()) + .eqIfPresent(ErpStockOutDO::getCreator, reqVO.getCreator()) + .orderByDesc(ErpStockOutDO::getId); + if (reqVO.getWarehouseId() != null || reqVO.getProductId() != null) { + query.leftJoin(ErpStockOutItemDO.class, ErpStockOutItemDO::getOutId, ErpStockOutDO::getId) + .eq(reqVO.getWarehouseId() != null, ErpStockOutItemDO::getWarehouseId, reqVO.getWarehouseId()) + .eq(reqVO.getProductId() != null, ErpStockOutItemDO::getProductId, reqVO.getProductId()) + .groupBy(ErpStockOutDO::getId); // 避免 1 对多查询,产生相同的 1 + } + return selectJoinPage(reqVO, ErpStockOutDO.class, query); + } + + default int updateByIdAndStatus(Long id, Integer status, ErpStockOutDO updateObj) { + return update(updateObj, new LambdaUpdateWrapper() + .eq(ErpStockOutDO::getId, id).eq(ErpStockOutDO::getStatus, status)); + } + + default ErpStockOutDO selectByNo(String no) { + return selectOne(ErpStockOutDO::getNo, no); + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java index e211864cc..04d2c25ca 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java @@ -20,9 +20,13 @@ import java.time.LocalDateTime; public class ErpNoRedisDAO { /** - * 其它入库 STOCK_IN + * 其它入库 {@link cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInDO} */ public static final String STOCK_IN_NO_PREFIX = "QTRK"; + /** + * 其它出库 {@link cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutDO} + */ + public static final String STOCK_OUT_NO_PREFIX = "QCKD"; @Resource private StringRedisTemplate stringRedisTemplate; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java index 85aa6ff53..9e9280fcd 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java @@ -16,7 +16,7 @@ import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; import cn.iocoder.yudao.module.erp.enums.stock.ErpStockRecordBizTypeEnum; import cn.iocoder.yudao.module.erp.service.product.ErpProductService; import cn.iocoder.yudao.module.erp.service.purchase.ErpSupplierService; -import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockInCreateReqBO; +import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockRecordCreateReqBO; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -88,7 +88,10 @@ public class ErpStockInServiceImpl implements ErpStockInService { @Transactional(rollbackFor = Exception.class) public void updateStockIn(ErpStockInSaveReqVO updateReqVO) { // 1.1 校验存在 - validateStockInExists(updateReqVO.getId()); + ErpStockInDO stockIn = validateStockInExists(updateReqVO.getId()); + if (ErpAuditStatus.APPROVE.getStatus().equals(stockIn.getStatus())) { + throw exception(STOCK_IN_UPDATE_FAIL_APPROVE, stockIn.getNo()); + } // 1.2 校验供应商 supplierService.validateSupplier(updateReqVO.getSupplierId()); // 1.3 校验入库项的有效性 @@ -127,7 +130,7 @@ public class ErpStockInServiceImpl implements ErpStockInService { : ErpStockRecordBizTypeEnum.OTHER_IN_CANCEL.getType(); stockInItems.forEach(stockInItem -> { BigDecimal count = approve ? stockInItem.getCount() : stockInItem.getCount().negate(); - stockRecordService.createStockRecord(new ErpStockInCreateReqBO( + stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO( stockInItem.getProductId(), stockInItem.getWarehouseId(), count, bizType, stockInItem.getInId(), stockInItem.getId(), stockIn.getNo())); }); diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutService.java new file mode 100644 index 000000000..558fb6948 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutService.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutItemDO; +import jakarta.validation.Valid; + +import java.util.Collection; +import java.util.List; + +/** + * ERP 其它出库单 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpStockOutService { + + /** + * 创建其它出库单 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createStockOut(@Valid ErpStockOutSaveReqVO createReqVO); + + /** + * 更新其它出库单 + * + * @param updateReqVO 更新信息 + */ + void updateStockOut(@Valid ErpStockOutSaveReqVO updateReqVO); + + /** + * 更新其它出库单的状态 + * + * @param id 编号 + * @param status 状态 + */ + void updateStockOutStatus(Long id, Integer status); + + /** + * 删除其它出库单 + * + * @param ids 编号数组 + */ + void deleteStockOut(List ids); + + /** + * 获得其它出库单 + * + * @param id 编号 + * @return 其它出库单 + */ + ErpStockOutDO getStockOut(Long id); + + /** + * 获得其它出库单分页 + * + * @param pageReqVO 分页查询 + * @return 其它出库单分页 + */ + PageResult getStockOutPage(ErpStockOutPageReqVO pageReqVO); + + // ==================== 出库项 ==================== + + /** + * 获得其它出库单项列表 + * + * @param outId 出库编号 + * @return 其它出库单项列表 + */ + List getStockOutItemListByOutId(Long outId); + + /** + * 获得其它出库单项 List + * + * @param outIds 出库编号数组 + * @return 其它出库单项 List + */ + List getStockOutItemListByOutIds(Collection outIds); + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java new file mode 100644 index 000000000..67041209b --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java @@ -0,0 +1,227 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutItemDO; +import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockOutItemMapper; +import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockOutMapper; +import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO; +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import cn.iocoder.yudao.module.erp.enums.stock.ErpStockRecordBizTypeEnum; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.purchase.ErpSupplierService; +import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockRecordCreateReqBO; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; + +// TODO 芋艿:记录操作日志 + +/** + * ERP 其它出库单 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ErpStockOutServiceImpl implements ErpStockOutService { + + @Resource + private ErpStockOutMapper stockOutMapper; + @Resource + private ErpStockOutItemMapper stockOutItemMapper; + + @Resource + private ErpNoRedisDAO noRedisDAO; + + @Resource + private ErpProductService productService; + @Resource + private ErpWarehouseService warehouseService; + @Resource + private ErpSupplierService supplierService; + @Resource + private ErpStockRecordService stockRecordService; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createStockOut(ErpStockOutSaveReqVO createReqVO) { + // 1.1 校验出库项的有效性 + List stockOutItems = validateStockOutItems(createReqVO.getItems()); + // 1.2 校验客户 TODO +// supplierService.validateSupplier(createReqVO.getSupplierId()); + // 1.3 + String no = noRedisDAO.generate(ErpNoRedisDAO.STOCK_OUT_NO_PREFIX); + if (stockOutMapper.selectByNo(no) != null) { + throw exception(STOCK_OUT_NO_EXISTS); + } + + // 2.1 插入出库单 + ErpStockOutDO stockOut = BeanUtils.toBean(createReqVO, ErpStockOutDO.class, in -> in + .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus()) + .setTotalCount(getSumValue(stockOutItems, ErpStockOutItemDO::getCount, BigDecimal::add)) + .setTotalPrice(getSumValue(stockOutItems, ErpStockOutItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO))); + stockOutMapper.insert(stockOut); + // 2.2 插入出库单项 + stockOutItems.forEach(o -> o.setOutId(stockOut.getId())); + stockOutItemMapper.insertBatch(stockOutItems); + return stockOut.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateStockOut(ErpStockOutSaveReqVO updateReqVO) { + // 1.1 校验存在 + ErpStockOutDO stockOut = validateStockOutExists(updateReqVO.getId()); + if (ErpAuditStatus.APPROVE.getStatus().equals(stockOut.getStatus())) { + throw exception(STOCK_OUT_UPDATE_FAIL_APPROVE, stockOut.getNo()); + } + // 1.2 校验客户 TODO +// supplierService.validateSupplier(updateReqVO.getSupplierId()); + // 1.3 校验出库项的有效性 + List stockOutItems = validateStockOutItems(updateReqVO.getItems()); + + // 2.1 更新出库单 + ErpStockOutDO updateObj = BeanUtils.toBean(updateReqVO, ErpStockOutDO.class, in -> in + .setTotalCount(getSumValue(stockOutItems, ErpStockOutItemDO::getCount, BigDecimal::add)) + .setTotalPrice(getSumValue(stockOutItems, ErpStockOutItemDO::getTotalPrice, BigDecimal::add))); + stockOutMapper.updateById(updateObj); + // 2.2 更新出库单项 + updateStockOutItemList(updateReqVO.getId(), stockOutItems); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateStockOutStatus(Long id, Integer status) { + boolean approve = ErpAuditStatus.APPROVE.getStatus().equals(status); + // 1.1 校验存在 + ErpStockOutDO stockOut = validateStockOutExists(id); + // 1.2 校验状态 + if (stockOut.getStatus().equals(status)) { + throw exception(approve ? STOCK_OUT_APPROVE_FAIL : STOCK_OUT_PROCESS_FAIL); + } + + // 2. 更新状态 + int updateCount = stockOutMapper.updateByIdAndStatus(id, stockOut.getStatus(), + new ErpStockOutDO().setStatus(status)); + if (updateCount == 0) { + throw exception(approve ? STOCK_OUT_APPROVE_FAIL : STOCK_OUT_PROCESS_FAIL); + } + + // 3. 变更库存 + List stockOutItems = stockOutItemMapper.selectListByOutId(id); + Integer bizType = approve ? ErpStockRecordBizTypeEnum.OTHER_OUT.getType() + : ErpStockRecordBizTypeEnum.OTHER_OUT_CANCEL.getType(); + stockOutItems.forEach(stockOutItem -> { + BigDecimal count = approve ? stockOutItem.getCount() : stockOutItem.getCount().negate(); + stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO( + stockOutItem.getProductId(), stockOutItem.getWarehouseId(), count, + bizType, stockOutItem.getOutId(), stockOutItem.getId(), stockOut.getNo())); + }); + } + + private List validateStockOutItems(List list) { + // 1.1 校验产品存在 + List productList = productService.validProductList(convertSet(list, ErpStockOutSaveReqVO.Item::getProductId)); + Map productMap = convertMap(productList, ErpProductDO::getId); + // 1.2 校验仓库存在 + warehouseService.validWarehouseList(convertSet(list, ErpStockOutSaveReqVO.Item::getWarehouseId)); + // 2. 转化为 ErpStockOutItemDO 列表 + return convertList(list, o -> BeanUtils.toBean(o, ErpStockOutItemDO.class, item -> item + .setProductUnitId(productMap.get(item.getProductId()).getUnitId()) + .setTotalPrice(MoneyUtils.priceMultiply(item.getProductPrice(), item.getCount())))); + } + + private void updateStockOutItemList(Long id, List newList) { + // 第一步,对比新老数据,获得添加、修改、删除的列表 + List oldList = stockOutItemMapper.selectListByOutId(id); + List> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录 + (oldVal, newVal) -> oldVal.getId().equals(newVal.getId())); + + // 第二步,批量添加、修改、删除 + if (CollUtil.isNotEmpty(diffList.get(0))) { + diffList.get(0).forEach(o -> o.setOutId(id)); + stockOutItemMapper.insertBatch(diffList.get(0)); + } + if (CollUtil.isNotEmpty(diffList.get(1))) { + stockOutItemMapper.updateBatch(diffList.get(1)); + } + if (CollUtil.isNotEmpty(diffList.get(2))) { + stockOutItemMapper.deleteBatchIds(convertList(diffList.get(2), ErpStockOutItemDO::getId)); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteStockOut(List ids) { + // 1. 校验不处于已审批 + List stockOuts = stockOutMapper.selectBatchIds(ids); + if (CollUtil.isEmpty(stockOuts)) { + return; + } + stockOuts.forEach(stockOut -> { + if (ErpAuditStatus.APPROVE.getStatus().equals(stockOut.getStatus())) { + throw exception(STOCK_OUT_DELETE_FAIL_APPROVE, stockOut.getNo()); + } + }); + + // 2. 遍历删除,并记录操作日志 + stockOuts.forEach(stockOut -> { + // 2.1 删除出库单 + stockOutMapper.deleteById(stockOut.getId()); + // 2.2 删除出库单项 + stockOutItemMapper.deleteByOutId(stockOut.getId()); + }); + } + + private ErpStockOutDO validateStockOutExists(Long id) { + ErpStockOutDO stockOut = stockOutMapper.selectById(id); + if (stockOut == null) { + throw exception(STOCK_OUT_NOT_EXISTS); + } + return stockOut; + } + + @Override + public ErpStockOutDO getStockOut(Long id) { + return stockOutMapper.selectById(id); + } + + @Override + public PageResult getStockOutPage(ErpStockOutPageReqVO pageReqVO) { + return stockOutMapper.selectPage(pageReqVO); + } + + // ==================== 出库项 ==================== + + @Override + public List getStockOutItemListByOutId(Long inId) { + return stockOutItemMapper.selectListByOutId(inId); + } + + @Override + public List getStockOutItemListByOutIds(Collection inIds) { + if (CollUtil.isEmpty(inIds)) { + return Collections.emptyList(); + } + return stockOutItemMapper.selectListByOutIds(inIds); + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordService.java index 0e20a55f2..506b992a4 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordService.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordService.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.erp.service.stock; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.record.ErpStockRecordPageReqVO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockRecordDO; -import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockInCreateReqBO; +import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockRecordCreateReqBO; import jakarta.validation.Valid; /** @@ -34,6 +34,6 @@ public interface ErpStockRecordService { * * @param createReqBO 创建库存明细 BO */ - void createStockRecord(@Valid ErpStockInCreateReqBO createReqBO); + void createStockRecord(@Valid ErpStockRecordCreateReqBO createReqBO); } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordServiceImpl.java index 708a39f18..d84951c28 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordServiceImpl.java @@ -5,7 +5,7 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.record.ErpStockRecordPageReqVO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockRecordDO; import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockRecordMapper; -import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockInCreateReqBO; +import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockRecordCreateReqBO; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -40,7 +40,7 @@ public class ErpStockRecordServiceImpl implements ErpStockRecordService { @Override @Transactional(rollbackFor = Exception.class) - public void createStockRecord(ErpStockInCreateReqBO createReqBO) { + public void createStockRecord(ErpStockRecordCreateReqBO createReqBO) { // 1. 更新库存 BigDecimal totalCount = stockService.updateStockCountIncrement( createReqBO.getProductId(), createReqBO.getWarehouseId(), createReqBO.getCount()); diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/bo/ErpStockInCreateReqBO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/bo/ErpStockRecordCreateReqBO.java similarity index 96% rename from yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/bo/ErpStockInCreateReqBO.java rename to yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/bo/ErpStockRecordCreateReqBO.java index 3211a2e76..7006f10b5 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/bo/ErpStockInCreateReqBO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/bo/ErpStockRecordCreateReqBO.java @@ -15,7 +15,7 @@ import java.math.BigDecimal; @Data @NoArgsConstructor @AllArgsConstructor -public class ErpStockInCreateReqBO { +public class ErpStockRecordCreateReqBO { /** * 产品编号 From 7495bb05d19819c5e026750c118b65ee6d336021 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 7 Feb 2024 15:41:00 +0800 Subject: [PATCH 12/15] =?UTF-8?q?=E2=9C=A8=20ERP=EF=BC=9A=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=20ERP=20=E5=AE=A2=E6=88=B7=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/erp/enums/ErrorCodeConstants.java | 8 +- .../admin/purchase/ErpSupplierController.java | 2 +- .../admin/sale/ErpCustomerController.java | 102 ++++++++++++++ .../vo/customer/ErpCustomerPageReqVO.java | 28 ++++ .../sale/vo/customer/ErpCustomerRespVO.java | 84 +++++++++++ .../vo/customer/ErpCustomerSaveReqVO.java | 61 ++++++++ .../admin/stock/ErpStockInController.java | 4 +- .../admin/stock/ErpStockOutController.java | 16 ++- .../{supplier => purchase}/ErpSupplierDO.java | 2 +- .../dal/dataobject/sale/ErpCustomerDO.java | 90 ++++++++++++ .../dal/dataobject/stock/ErpStockInDO.java | 2 +- .../dal/mysql/purchase/ErpSupplierMapper.java | 2 +- .../erp/dal/mysql/sale/ErpCustomerMapper.java | 32 +++++ .../service/purchase/ErpSupplierService.java | 2 +- .../purchase/ErpSupplierServiceImpl.java | 2 +- .../erp/service/sale/ErpCustomerService.java | 94 +++++++++++++ .../service/sale/ErpCustomerServiceImpl.java | 97 +++++++++++++ .../service/stock/ErpStockOutServiceImpl.java | 12 +- .../mapper/sale/ErpCustomerMapper.xml | 12 ++ .../sale/ErpCustomerServiceImplTest.java | 131 ++++++++++++++++++ 20 files changed, 760 insertions(+), 23 deletions(-) create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpCustomerController.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/customer/ErpCustomerPageReqVO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/customer/ErpCustomerRespVO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/customer/ErpCustomerSaveReqVO.java rename yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/{supplier => purchase}/ErpSupplierDO.java (96%) create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpCustomerDO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpCustomerMapper.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpCustomerService.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpCustomerServiceImpl.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/resources/mapper/sale/ErpCustomerMapper.xml create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/test/java/cn/iocoder/yudao/module/erp/service/sale/ErpCustomerServiceImplTest.java diff --git a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java index 7bd87bdb9..1926b34ac 100644 --- a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java +++ b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java @@ -13,8 +13,12 @@ public interface ErrorCodeConstants { ErrorCode SUPPLIER_NOT_EXISTS = new ErrorCode(1_030_100_000, "供应商不存在"); ErrorCode SUPPLIER_NOT_ENABLE = new ErrorCode(1_030_100_000, "供应商({})未启用"); - // ========== ERP 销售订单(1-030-200-000) ========== - ErrorCode SALE_ORDER_NOT_EXISTS = new ErrorCode(1_020_200_000, "销售订单不存在"); + // ========== ERP 客户(1-030-200-000)========== + ErrorCode CUSTOMER_NOT_EXISTS = new ErrorCode(1_020_200_000, "客户不存在"); + ErrorCode CUSTOMER_NOT_ENABLE = new ErrorCode(1_020_200_001, "客户({})未启用"); + + // ========== ERP 销售订单(1-030-201-000) ========== + ErrorCode SALE_ORDER_NOT_EXISTS = new ErrorCode(1_020_201_000, "销售订单不存在"); // ========== ERP 仓库 1-030-400-000 ========== ErrorCode WAREHOUSE_NOT_EXISTS = new ErrorCode(1_030_400_000, "仓库不存在"); diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpSupplierController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpSupplierController.java index 60893ea57..88253286d 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpSupplierController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpSupplierController.java @@ -10,7 +10,7 @@ import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier.ErpSupplierPageReqVO; import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier.ErpSupplierRespVO; import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier.ErpSupplierSaveReqVO; -import cn.iocoder.yudao.module.erp.dal.dataobject.supplier.ErpSupplierDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpSupplierDO; import cn.iocoder.yudao.module.erp.service.purchase.ErpSupplierService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpCustomerController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpCustomerController.java new file mode 100644 index 000000000..2c2886460 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpCustomerController.java @@ -0,0 +1,102 @@ +package cn.iocoder.yudao.module.erp.controller.admin.sale; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.customer.ErpCustomerPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.customer.ErpCustomerRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.customer.ErpCustomerSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpCustomerDO; +import cn.iocoder.yudao.module.erp.service.sale.ErpCustomerService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; + +@Tag(name = "管理后台 - ERP 客户") +@RestController +@RequestMapping("/erp/customer") +@Validated +public class ErpCustomerController { + + @Resource + private ErpCustomerService customerService; + + @PostMapping("/create") + @Operation(summary = "创建客户") + @PreAuthorize("@ss.hasPermission('erp:customer:create')") + public CommonResult createCustomer(@Valid @RequestBody ErpCustomerSaveReqVO createReqVO) { + return success(customerService.createCustomer(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新客户") + @PreAuthorize("@ss.hasPermission('erp:customer:update')") + public CommonResult updateCustomer(@Valid @RequestBody ErpCustomerSaveReqVO updateReqVO) { + customerService.updateCustomer(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除客户") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('erp:customer:delete')") + public CommonResult deleteCustomer(@RequestParam("id") Long id) { + customerService.deleteCustomer(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得客户") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('erp:customer:query')") + public CommonResult getCustomer(@RequestParam("id") Long id) { + ErpCustomerDO customer = customerService.getCustomer(id); + return success(BeanUtils.toBean(customer, ErpCustomerRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得客户分页") + @PreAuthorize("@ss.hasPermission('erp:customer:query')") + public CommonResult> getCustomerPage(@Valid ErpCustomerPageReqVO pageReqVO) { + PageResult pageResult = customerService.getCustomerPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, ErpCustomerRespVO.class)); + } + + @GetMapping("/simple-list") + @Operation(summary = "获得客户精简列表", description = "只包含被开启的客户,主要用于前端的下拉选项") + public CommonResult> getCustomerSimpleList() { + List list = customerService.getCustomerListByStatus(CommonStatusEnum.ENABLE.getStatus()); + return success(convertList(list, customer -> new ErpCustomerRespVO().setId(customer.getId()).setName(customer.getName()))); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出客户 Excel") + @PreAuthorize("@ss.hasPermission('erp:customer:export')") + @OperateLog(type = EXPORT) + public void exportCustomerExcel(@Valid ErpCustomerPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = customerService.getCustomerPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "客户.xls", "数据", ErpCustomerRespVO.class, + BeanUtils.toBean(list, ErpCustomerRespVO.class)); + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/customer/ErpCustomerPageReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/customer/ErpCustomerPageReqVO.java new file mode 100644 index 000000000..e790cb958 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/customer/ErpCustomerPageReqVO.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.erp.controller.admin.sale.vo.customer; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import java.math.BigDecimal; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - ERP 客户分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ErpCustomerPageReqVO extends PageParam { + + @Schema(description = "客户名称", example = "张三") + private String name; + + @Schema(description = "手机号码", example = "15601691300") + private String mobile; + + @Schema(description = "联系电话", example = "15601691300") + private String telephone; + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/customer/ErpCustomerRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/customer/ErpCustomerRespVO.java new file mode 100644 index 000000000..f1a58a03d --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/customer/ErpCustomerRespVO.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.erp.controller.admin.sale.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import java.util.*; +import java.math.BigDecimal; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import com.alibaba.excel.annotation.*; +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; + +@Schema(description = "管理后台 - ERP 客户 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ErpCustomerRespVO { + + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "27520") + @ExcelProperty("客户编号") + private Long id; + + @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三") + @ExcelProperty("客户名称") + private String name; + + @Schema(description = "联系人", example = "老王") + @ExcelProperty("联系人") + private String contact; + + @Schema(description = "手机号码", example = "15601691300") + @ExcelProperty("手机号码") + private String mobile; + + @Schema(description = "联系电话", example = "15601691300") + @ExcelProperty("联系电话") + private String telephone; + + @Schema(description = "电子邮箱", example = "7685323@qq.com") + @ExcelProperty("电子邮箱") + private String email; + + @Schema(description = "传真", example = "20 7123 4567") + @ExcelProperty("传真") + private String fax; + + @Schema(description = "备注", example = "你猜") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "开启状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "开启状态", converter = DictConvert.class) + @DictFormat("common_status") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Integer status; + + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @ExcelProperty("排序") + private Integer sort; + + @Schema(description = "纳税人识别号", example = "91130803MA098BY05W") + @ExcelProperty("纳税人识别号") + private String taxNo; + + @Schema(description = "税率", example = "10") + @ExcelProperty("税率") + private BigDecimal taxPercent; + + @Schema(description = "开户行", example = "芋艿") + @ExcelProperty("开户行") + private String bankName; + + @Schema(description = "开户账号", example = "622908212277228617") + @ExcelProperty("开户账号") + private String bankAccount; + + @Schema(description = "开户地址", example = "兴业银行浦东支行") + @ExcelProperty("开户地址") + private String bankAddress; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/customer/ErpCustomerSaveReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/customer/ErpCustomerSaveReqVO.java new file mode 100644 index 000000000..aef0b2df1 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/customer/ErpCustomerSaveReqVO.java @@ -0,0 +1,61 @@ +package cn.iocoder.yudao.module.erp.controller.admin.sale.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import jakarta.validation.constraints.*; +import java.math.BigDecimal; + +@Schema(description = "管理后台 - ERP 客户新增/修改 Request VO") +@Data +public class ErpCustomerSaveReqVO { + + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "27520") + private Long id; + + @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三") + @NotEmpty(message = "客户名称不能为空") + private String name; + + @Schema(description = "联系人", example = "老王") + private String contact; + + @Schema(description = "手机号码", example = "15601691300") + private String mobile; + + @Schema(description = "联系电话", example = "15601691300") + private String telephone; + + @Schema(description = "电子邮箱", example = "7685323@qq.com") + private String email; + + @Schema(description = "传真", example = "20 7123 4567") + private String fax; + + @Schema(description = "备注", example = "你猜") + private String remark; + + @Schema(description = "开启状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "开启状态不能为空") + private Integer status; + + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @NotNull(message = "排序不能为空") + private Integer sort; + + @Schema(description = "纳税人识别号", example = "91130803MA098BY05W") + private String taxNo; + + @Schema(description = "税率", example = "10") + private BigDecimal taxPercent; + + @Schema(description = "开户行", example = "芋艿") + private String bankName; + + @Schema(description = "开户账号", example = "622908212277228617") + private String bankAccount; + + @Schema(description = "开户地址", example = "兴业银行浦东支行") + private String bankAddress; + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockInController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockInController.java index 530d04350..75120fce5 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockInController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockInController.java @@ -15,7 +15,7 @@ import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInSaveRe import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInDO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInItemDO; -import cn.iocoder.yudao.module.erp.dal.dataobject.supplier.ErpSupplierDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpSupplierDO; import cn.iocoder.yudao.module.erp.service.product.ErpProductService; import cn.iocoder.yudao.module.erp.service.purchase.ErpSupplierService; import cn.iocoder.yudao.module.erp.service.stock.ErpStockInService; @@ -77,7 +77,7 @@ public class ErpStockInController { @PutMapping("/update-status") @Operation(summary = "更新其它入库单的状态") - @PreAuthorize("@ss.hasPermission('erp:stock-in:update')") + @PreAuthorize("@ss.hasPermission('erp:stock-in:update-status')") public CommonResult updateStockInStatus(@RequestParam("id") Long id, @RequestParam("status") Integer status) { stockInService.updateStockInStatus(id, status); diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockOutController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockOutController.java index 306d51277..504a06e98 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockOutController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockOutController.java @@ -12,10 +12,12 @@ import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProduc import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutPageReqVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutRespVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpCustomerDO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutDO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutItemDO; import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.sale.ErpCustomerService; import cn.iocoder.yudao.module.erp.service.stock.ErpStockOutService; import cn.iocoder.yudao.module.erp.service.stock.ErpStockService; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; @@ -52,8 +54,8 @@ public class ErpStockOutController { private ErpStockService stockService; @Resource private ErpProductService productService; -// @Resource -// private ErpSupplierService supplierService; + @Resource + private ErpCustomerService customerService; @Resource private AdminUserApi adminUserApi; @@ -75,7 +77,7 @@ public class ErpStockOutController { @PutMapping("/update-status") @Operation(summary = "更新其它出库单的状态") - @PreAuthorize("@ss.hasPermission('erp:stock-out:update')") + @PreAuthorize("@ss.hasPermission('erp:stock-out:update-status')") public CommonResult updateStockOutStatus(@RequestParam("id") Long id, @RequestParam("status") Integer status) { stockOutService.updateStockOutStatus(id, status); @@ -143,9 +145,9 @@ public class ErpStockOutController { // 1.2 商品信息 Map productMap = productService.getProductVOMap( convertSet(stockOutItemList, ErpStockOutItemDO::getProductId)); - // 1.3 客户信息 TODO -// Map supplierMap = supplierService.getSupplierMap( -// convertSet(pageResult.getList(), ErpStockOutDO::getSupplierId)); + // 1.3 客户信息 + Map customerMap = customerService.getCustomerMap( + convertSet(pageResult.getList(), ErpStockOutDO::getCustomerId)); // 1.4 管理员信息 Map userMap = adminUserApi.getUserMap( convertSet(pageResult.getList(), erpStockRecordDO -> Long.parseLong(erpStockRecordDO.getCreator()))); @@ -155,7 +157,7 @@ public class ErpStockOutController { item -> MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())))); stockOut.setProductNames(CollUtil.join(stockOut.getItems(), ",", ErpStockOutRespVO.Item::getProductName)); -// MapUtils.findAndThen(supplierMap, stockOut.getSupplierId(), supplier -> stockOut.setSupplierName(supplier.getName())); + MapUtils.findAndThen(customerMap, stockOut.getCustomerId(), supplier -> stockOut.setCustomerName(supplier.getName())); MapUtils.findAndThen(userMap, Long.parseLong(stockOut.getCreator()), user -> stockOut.setCreatorName(user.getNickname())); }); } diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/supplier/ErpSupplierDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpSupplierDO.java similarity index 96% rename from yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/supplier/ErpSupplierDO.java rename to yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpSupplierDO.java index 108922a22..6e94c6669 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/supplier/ErpSupplierDO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpSupplierDO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.erp.dal.dataobject.supplier; +package cn.iocoder.yudao.module.erp.dal.dataobject.purchase; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import com.baomidou.mybatisplus.annotation.KeySequence; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpCustomerDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpCustomerDO.java new file mode 100644 index 000000000..7bffcc17c --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpCustomerDO.java @@ -0,0 +1,90 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.sale; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * ERP 客户 DO + * + * @author 芋道源码 + */ +@TableName("erp_customer") +@KeySequence("erp_customer_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpCustomerDO extends BaseDO { + + /** + * 客户编号 + */ + @TableId + private Long id; + /** + * 客户名称 + */ + private String name; + /** + * 联系人 + */ + private String contact; + /** + * 手机号码 + */ + private String mobile; + /** + * 联系电话 + */ + private String telephone; + /** + * 电子邮箱 + */ + private String email; + /** + * 传真 + */ + private String fax; + /** + * 备注 + */ + private String remark; + /** + * 开启状态 + * + * 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum} + */ + private Integer status; + /** + * 排序 + */ + private Integer sort; + /** + * 纳税人识别号 + */ + private String taxNo; + /** + * 税率 + */ + private BigDecimal taxPercent; + /** + * 开户行 + */ + private String bankName; + /** + * 开户账号 + */ + private String bankAccount; + /** + * 开户地址 + */ + private String bankAddress; + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockInDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockInDO.java index 5115b9daf..ee2512ab6 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockInDO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockInDO.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.erp.dal.dataobject.stock; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.module.erp.dal.dataobject.supplier.ErpSupplierDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpSupplierDO; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpSupplierMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpSupplierMapper.java index 93f3d6994..c74f1e6f8 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpSupplierMapper.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpSupplierMapper.java @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier.ErpSupplierPageReqVO; -import cn.iocoder.yudao.module.erp.dal.dataobject.supplier.ErpSupplierDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpSupplierDO; import org.apache.ibatis.annotations.Mapper; import java.util.List; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpCustomerMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpCustomerMapper.java new file mode 100644 index 000000000..4970f9ad5 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpCustomerMapper.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.sale; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.customer.ErpCustomerPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpCustomerDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * ERP 客户 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpCustomerMapper extends BaseMapperX { + + default PageResult selectPage(ErpCustomerPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(ErpCustomerDO::getName, reqVO.getName()) + .eqIfPresent(ErpCustomerDO::getMobile, reqVO.getMobile()) + .eqIfPresent(ErpCustomerDO::getTelephone, reqVO.getTelephone()) + .orderByDesc(ErpCustomerDO::getId)); + } + + default List selectListByStatus(Integer status) { + return selectList(ErpCustomerDO::getStatus, status); + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpSupplierService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpSupplierService.java index a2f6547c2..495474d13 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpSupplierService.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpSupplierService.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.erp.service.purchase; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier.ErpSupplierPageReqVO; import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier.ErpSupplierSaveReqVO; -import cn.iocoder.yudao.module.erp.dal.dataobject.supplier.ErpSupplierDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpSupplierDO; import jakarta.validation.Valid; import java.util.Collection; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpSupplierServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpSupplierServiceImpl.java index 09c789c57..c862a84da 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpSupplierServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpSupplierServiceImpl.java @@ -5,7 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier.ErpSupplierPageReqVO; import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier.ErpSupplierSaveReqVO; -import cn.iocoder.yudao.module.erp.dal.dataobject.supplier.ErpSupplierDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpSupplierDO; import cn.iocoder.yudao.module.erp.dal.mysql.purchase.ErpSupplierMapper; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpCustomerService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpCustomerService.java new file mode 100644 index 000000000..d047300e8 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpCustomerService.java @@ -0,0 +1,94 @@ +package cn.iocoder.yudao.module.erp.service.sale; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.customer.ErpCustomerPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.customer.ErpCustomerSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpCustomerDO; +import jakarta.validation.Valid; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * ERP 客户 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpCustomerService { + + /** + * 创建客户 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createCustomer(@Valid ErpCustomerSaveReqVO createReqVO); + + /** + * 更新客户 + * + * @param updateReqVO 更新信息 + */ + void updateCustomer(@Valid ErpCustomerSaveReqVO updateReqVO); + + /** + * 删除客户 + * + * @param id 编号 + */ + void deleteCustomer(Long id); + + /** + * 获得客户 + * + * @param id 编号 + * @return 客户 + */ + ErpCustomerDO getCustomer(Long id); + + /** + * 校验客户 + * + * @param id 编号 + * @return 客户 + */ + ErpCustomerDO validateCustomer(Long id); + + /** + * 获得客户列表 + * + * @param ids 编号列表 + * @return 客户列表 + */ + List getCustomerList(Collection ids); + + /** + * 获得客户 Map + * + * @param ids 编号列表 + * @return 客户 Map + */ + default Map getCustomerMap(Collection ids) { + return convertMap(getCustomerList(ids), ErpCustomerDO::getId); + } + + /** + * 获得客户分页 + * + * @param pageReqVO 分页查询 + * @return 客户分页 + */ + PageResult getCustomerPage(ErpCustomerPageReqVO pageReqVO); + + /** + * 获得指定状态的客户列表 + * + * @param status 状态 + * @return 客户列表 + */ + List getCustomerListByStatus(Integer status); + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpCustomerServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpCustomerServiceImpl.java new file mode 100644 index 000000000..73d2aa9d5 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpCustomerServiceImpl.java @@ -0,0 +1,97 @@ +package cn.iocoder.yudao.module.erp.service.sale; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.customer.ErpCustomerPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.customer.ErpCustomerSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpCustomerDO; +import cn.iocoder.yudao.module.erp.dal.mysql.sale.ErpCustomerMapper; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.CUSTOMER_NOT_ENABLE; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.CUSTOMER_NOT_EXISTS; + +/** + * ERP 客户 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ErpCustomerServiceImpl implements ErpCustomerService { + + @Resource + private ErpCustomerMapper customerMapper; + + @Override + public Long createCustomer(ErpCustomerSaveReqVO createReqVO) { + // 插入 + ErpCustomerDO customer = BeanUtils.toBean(createReqVO, ErpCustomerDO.class); + customerMapper.insert(customer); + // 返回 + return customer.getId(); + } + + @Override + public void updateCustomer(ErpCustomerSaveReqVO updateReqVO) { + // 校验存在 + validateCustomerExists(updateReqVO.getId()); + // 更新 + ErpCustomerDO updateObj = BeanUtils.toBean(updateReqVO, ErpCustomerDO.class); + customerMapper.updateById(updateObj); + } + + @Override + public void deleteCustomer(Long id) { + // 校验存在 + validateCustomerExists(id); + // 删除 + customerMapper.deleteById(id); + } + + private void validateCustomerExists(Long id) { + if (customerMapper.selectById(id) == null) { + throw exception(CUSTOMER_NOT_EXISTS); + } + } + + @Override + public ErpCustomerDO getCustomer(Long id) { + return customerMapper.selectById(id); + } + + @Override + public ErpCustomerDO validateCustomer(Long id) { + ErpCustomerDO customer = customerMapper.selectById(id); + if (customer == null) { + throw exception(CUSTOMER_NOT_EXISTS); + } + if (CommonStatusEnum.isDisable(customer.getStatus())) { + throw exception(CUSTOMER_NOT_ENABLE, customer.getName()); + } + return customer; + } + + @Override + public List getCustomerList(Collection ids) { + return customerMapper.selectBatchIds(ids); + } + + @Override + public PageResult getCustomerPage(ErpCustomerPageReqVO pageReqVO) { + return customerMapper.selectPage(pageReqVO); + } + + @Override + public List getCustomerListByStatus(Integer status) { + return customerMapper.selectListByStatus(status); + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java index 67041209b..36b5a30d8 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java @@ -15,7 +15,7 @@ import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO; import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; import cn.iocoder.yudao.module.erp.enums.stock.ErpStockRecordBizTypeEnum; import cn.iocoder.yudao.module.erp.service.product.ErpProductService; -import cn.iocoder.yudao.module.erp.service.purchase.ErpSupplierService; +import cn.iocoder.yudao.module.erp.service.sale.ErpCustomerService; import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockRecordCreateReqBO; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; @@ -56,7 +56,7 @@ public class ErpStockOutServiceImpl implements ErpStockOutService { @Resource private ErpWarehouseService warehouseService; @Resource - private ErpSupplierService supplierService; + private ErpCustomerService customerService; @Resource private ErpStockRecordService stockRecordService; @@ -65,8 +65,8 @@ public class ErpStockOutServiceImpl implements ErpStockOutService { public Long createStockOut(ErpStockOutSaveReqVO createReqVO) { // 1.1 校验出库项的有效性 List stockOutItems = validateStockOutItems(createReqVO.getItems()); - // 1.2 校验客户 TODO -// supplierService.validateSupplier(createReqVO.getSupplierId()); + // 1.2 校验客户 + customerService.validateCustomer(createReqVO.getCustomerId()); // 1.3 String no = noRedisDAO.generate(ErpNoRedisDAO.STOCK_OUT_NO_PREFIX); if (stockOutMapper.selectByNo(no) != null) { @@ -93,8 +93,8 @@ public class ErpStockOutServiceImpl implements ErpStockOutService { if (ErpAuditStatus.APPROVE.getStatus().equals(stockOut.getStatus())) { throw exception(STOCK_OUT_UPDATE_FAIL_APPROVE, stockOut.getNo()); } - // 1.2 校验客户 TODO -// supplierService.validateSupplier(updateReqVO.getSupplierId()); + // 1.2 校验客户 + customerService.validateCustomer(updateReqVO.getCustomerId()); // 1.3 校验出库项的有效性 List stockOutItems = validateStockOutItems(updateReqVO.getItems()); diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/resources/mapper/sale/ErpCustomerMapper.xml b/yudao-module-erp/yudao-module-erp-biz/src/main/resources/mapper/sale/ErpCustomerMapper.xml new file mode 100644 index 000000000..c012f4467 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/resources/mapper/sale/ErpCustomerMapper.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/test/java/cn/iocoder/yudao/module/erp/service/sale/ErpCustomerServiceImplTest.java b/yudao-module-erp/yudao-module-erp-biz/src/test/java/cn/iocoder/yudao/module/erp/service/sale/ErpCustomerServiceImplTest.java new file mode 100644 index 000000000..caee693cc --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/test/java/cn/iocoder/yudao/module/erp/service/sale/ErpCustomerServiceImplTest.java @@ -0,0 +1,131 @@ +package cn.iocoder.yudao.module.erp.service.sale; + +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.customer.ErpCustomerPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.customer.ErpCustomerSaveReqVO; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import jakarta.annotation.Resource; + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; + +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpCustomerDO; +import cn.iocoder.yudao.module.erp.dal.mysql.sale.ErpCustomerMapper; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import org.springframework.context.annotation.Import; + +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; +import static org.junit.jupiter.api.Assertions.*; + +/** + * {@link ErpCustomerServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(ErpCustomerServiceImpl.class) +public class ErpCustomerServiceImplTest extends BaseDbUnitTest { + + @Resource + private ErpCustomerServiceImpl customerService; + + @Resource + private ErpCustomerMapper customerMapper; + + @Test + public void testCreateCustomer_success() { + // 准备参数 + ErpCustomerSaveReqVO createReqVO = randomPojo(ErpCustomerSaveReqVO.class).setId(null); + + // 调用 + Long customerId = customerService.createCustomer(createReqVO); + // 断言 + assertNotNull(customerId); + // 校验记录的属性是否正确 + ErpCustomerDO customer = customerMapper.selectById(customerId); + assertPojoEquals(createReqVO, customer, "id"); + } + + @Test + public void testUpdateCustomer_success() { + // mock 数据 + ErpCustomerDO dbCustomer = randomPojo(ErpCustomerDO.class); + customerMapper.insert(dbCustomer);// @Sql: 先插入出一条存在的数据 + // 准备参数 + ErpCustomerSaveReqVO updateReqVO = randomPojo(ErpCustomerSaveReqVO.class, o -> { + o.setId(dbCustomer.getId()); // 设置更新的 ID + }); + + // 调用 + customerService.updateCustomer(updateReqVO); + // 校验是否更新正确 + ErpCustomerDO customer = customerMapper.selectById(updateReqVO.getId()); // 获取最新的 + assertPojoEquals(updateReqVO, customer); + } + + @Test + public void testUpdateCustomer_notExists() { + // 准备参数 + ErpCustomerSaveReqVO updateReqVO = randomPojo(ErpCustomerSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> customerService.updateCustomer(updateReqVO), CUSTOMER_NOT_EXISTS); + } + + @Test + public void testDeleteCustomer_success() { + // mock 数据 + ErpCustomerDO dbCustomer = randomPojo(ErpCustomerDO.class); + customerMapper.insert(dbCustomer);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbCustomer.getId(); + + // 调用 + customerService.deleteCustomer(id); + // 校验数据不存在了 + assertNull(customerMapper.selectById(id)); + } + + @Test + public void testDeleteCustomer_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> customerService.deleteCustomer(id), CUSTOMER_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetCustomerPage() { + // mock 数据 + ErpCustomerDO dbCustomer = randomPojo(ErpCustomerDO.class, o -> { // 等会查询到 + o.setName(null); + o.setMobile(null); + o.setTelephone(null); + }); + customerMapper.insert(dbCustomer); + // 测试 name 不匹配 + customerMapper.insert(cloneIgnoreId(dbCustomer, o -> o.setName(null))); + // 测试 mobile 不匹配 + customerMapper.insert(cloneIgnoreId(dbCustomer, o -> o.setMobile(null))); + // 测试 telephone 不匹配 + customerMapper.insert(cloneIgnoreId(dbCustomer, o -> o.setTelephone(null))); + // 准备参数 + ErpCustomerPageReqVO reqVO = new ErpCustomerPageReqVO(); + reqVO.setName(null); + reqVO.setMobile(null); + reqVO.setTelephone(null); + + // 调用 + PageResult pageResult = customerService.getCustomerPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbCustomer, pageResult.getList().get(0)); + } + +} \ No newline at end of file From f93963028fea115b34feb4b182fedffaa3d70cb4 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 7 Feb 2024 17:01:33 +0800 Subject: [PATCH 13/15] =?UTF-8?q?=E2=9C=A8=20ERP=EF=BC=9A=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=20ERP=20=E8=B0=83=E6=8B=A8=E5=8D=95=E7=9A=84=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=2050%?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/stock/ErpStockMoveController.java | 163 +++++++++++++ .../stock/vo/move/ErpStockMovePageReqVO.java | 45 ++++ .../stock/vo/move/ErpStockMoveRespVO.java | 107 ++++++++ .../stock/vo/move/ErpStockMoveSaveReqVO.java | 68 ++++++ .../dal/dataobject/stock/ErpStockMoveDO.java | 63 +++++ .../dataobject/stock/ErpStockMoveItemDO.java | 79 ++++++ .../mysql/stock/ErpStockMoveItemMapper.java | 30 +++ .../dal/mysql/stock/ErpStockMoveMapper.java | 46 ++++ .../service/stock/ErpStockMoveService.java | 84 +++++++ .../stock/ErpStockMoveServiceImpl.java | 229 ++++++++++++++++++ 10 files changed, 914 insertions(+) create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockMoveController.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMovePageReqVO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveRespVO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveSaveReqVO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveDO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveItemDO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMoveItemMapper.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMoveMapper.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveService.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveServiceImpl.java diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockMoveController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockMoveController.java new file mode 100644 index 000000000..e39b7bba7 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockMoveController.java @@ -0,0 +1,163 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMovePageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMoveRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMoveSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveItemDO; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.sale.ErpCustomerService; +import cn.iocoder.yudao.module.erp.service.stock.ErpStockMoveService; +import cn.iocoder.yudao.module.erp.service.stock.ErpStockService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; + +@Tag(name = "管理后台 - ERP 库存调拨单") +@RestController +@RequestMapping("/erp/stock-move") +@Validated +public class ErpStockMoveController { + + @Resource + private ErpStockMoveService stockMoveService; + @Resource + private ErpStockService stockService; + @Resource + private ErpProductService productService; + @Resource + private ErpCustomerService customerService; + + @Resource + private AdminUserApi adminUserApi; + + @PostMapping("/create") + @Operation(summary = "创建库存调拨单") + @PreAuthorize("@ss.hasPermission('erp:stock-move:create')") + public CommonResult createStockMove(@Valid @RequestBody ErpStockMoveSaveReqVO createReqVO) { + return success(stockMoveService.createStockMove(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新库存调拨单") + @PreAuthorize("@ss.hasPermission('erp:stock-move:update')") + public CommonResult updateStockMove(@Valid @RequestBody ErpStockMoveSaveReqVO updateReqVO) { + stockMoveService.updateStockMove(updateReqVO); + return success(true); + } + + @PutMapping("/update-status") + @Operation(summary = "更新库存调拨单的状态") + @PreAuthorize("@ss.hasPermission('erp:stock-move:update-status')") + public CommonResult updateStockMoveStatus(@RequestParam("id") Long id, + @RequestParam("status") Integer status) { + stockMoveService.updateStockMoveStatus(id, status); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除库存调拨单") + @Parameter(name = "ids", description = "编号数组", required = true) + @PreAuthorize("@ss.hasPermission('erp:stock-move:delete')") + public CommonResult deleteStockMove(@RequestParam("ids") List ids) { + stockMoveService.deleteStockMove(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得库存调拨单") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('erp:stock-move:query')") + public CommonResult getStockMove(@RequestParam("id") Long id) { + ErpStockMoveDO stockMove = stockMoveService.getStockMove(id); + if (stockMove == null) { + return success(null); + } + List stockMoveItemList = stockMoveService.getStockMoveItemListByMoveId(id); + Map productMap = productService.getProductVOMap( + convertSet(stockMoveItemList, ErpStockMoveItemDO::getProductId)); + return success(BeanUtils.toBean(stockMove, ErpStockMoveRespVO.class, stockMoveVO -> + stockMoveVO.setItems(BeanUtils.toBean(stockMoveItemList, ErpStockMoveRespVO.Item.class, item -> { + ErpStockDO stock = stockService.getStock(item.getProductId(), item.getFromWarehouseId()); + item.setStockCount(stock != null ? stock.getCount() : BigDecimal.ZERO); + MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())); + })))); + } + + @GetMapping("/page") + @Operation(summary = "获得库存调拨单分页") + @PreAuthorize("@ss.hasPermission('erp:stock-move:query')") + public CommonResult> getStockMovePage(@Valid ErpStockMovePageReqVO pageReqVO) { + PageResult pageResult = stockMoveService.getStockMovePage(pageReqVO); + return success(buildStockMoveVOPageResult(pageResult)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出库存调拨单 Excel") + @PreAuthorize("@ss.hasPermission('erp:stock-move:export')") + @OperateLog(type = EXPORT) + public void exportStockMoveExcel(@Valid ErpStockMovePageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = buildStockMoveVOPageResult(stockMoveService.getStockMovePage(pageReqVO)).getList(); + // 导出 Excel + ExcelUtils.write(response, "库存调拨单.xls", "数据", ErpStockMoveRespVO.class, list); + } + + private PageResult buildStockMoveVOPageResult(PageResult pageResult) { + if (CollUtil.isEmpty(pageResult.getList())) { + return PageResult.empty(pageResult.getTotal()); + } + // 1.1 出库项 + List stockMoveItemList = stockMoveService.getStockMoveItemListByMoveIds( + convertSet(pageResult.getList(), ErpStockMoveDO::getId)); + Map> stockMoveItemMap = convertMultiMap(stockMoveItemList, ErpStockMoveItemDO::getMoveId); + // 1.2 商品信息 + Map productMap = productService.getProductVOMap( + convertSet(stockMoveItemList, ErpStockMoveItemDO::getProductId)); + // 1.3 TODO 芋艿:搞仓库信息 + // 1.4 管理员信息 + Map userMap = adminUserApi.getUserMap( + convertSet(pageResult.getList(), erpStockRecordDO -> Long.parseLong(erpStockRecordDO.getCreator()))); + // 2. 开始拼接 + return BeanUtils.toBean(pageResult, ErpStockMoveRespVO.class, stockMove -> { + stockMove.setItems(BeanUtils.toBean(stockMoveItemMap.get(stockMove.getId()), ErpStockMoveRespVO.Item.class, + item -> MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())))); + stockMove.setProductNames(CollUtil.join(stockMove.getItems(), ",", ErpStockMoveRespVO.Item::getProductName)); + // TODO 芋艿: +// MapUtils.findAndThen(customerMap, stockMove.getCustomerId(), supplier -> stockMove.setCustomerName(supplier.getName())); + MapUtils.findAndThen(userMap, Long.parseLong(stockMove.getCreator()), user -> stockMove.setCreatorName(user.getNickname())); + }); + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMovePageReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMovePageReqVO.java new file mode 100644 index 000000000..98a1fe95e --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMovePageReqVO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - ERP 库存调拨单分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ErpStockMovePageReqVO extends PageParam { + + @Schema(description = "调拨单号", example = "S123") + private String no; + + @Schema(description = "调拨时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] moveTime; + + @Schema(description = "状态", example = "10") + @InEnum(ErpAuditStatus.class) + private Integer status; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "创建者") + private String creator; + + @Schema(description = "产品编号", example = "1") + private Long productId; + + @Schema(description = "调出仓库编号", example = "1") + private Long fromWarehouseId; + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveRespVO.java new file mode 100644 index 000000000..b09fb15a1 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveRespVO.java @@ -0,0 +1,107 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.module.erp.enums.DictTypeConstants.AUDIT_STATUS; + +@Schema(description = "管理后台 - ERP 库存调拨单 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ErpStockMoveRespVO { + + @Schema(description = "调拨编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + @ExcelProperty("调拨编号") + private Long id; + + @Schema(description = "调拨单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "S123") + @ExcelProperty("调拨单号") + private String no; + + @Schema(description = "调拨时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("调拨时间") + private LocalDateTime moveTime; + + @Schema(description = "合计数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "15663") + @ExcelProperty("合计数量") + private BigDecimal totalCount; + + @Schema(description = "合计金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "24906") + @ExcelProperty("合计金额") + private BigDecimal totalPrice; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @ExcelProperty(value = "状态", converter = DictConvert.class) + @DictFormat(AUDIT_STATUS) + private Integer status; + + @Schema(description = "备注", example = "随便") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "附件 URL", example = "https://www.iocoder.cn/1.doc") + private String fileUrl; + + @Schema(description = "审核人", example = "芋道") + private String creator; + @Schema(description = "审核人名称", example = "芋道") + private String creatorName; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "调拨项列表", requiredMode = Schema.RequiredMode.REQUIRED) + private List items; + + @Schema(description = "产品信息", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("产品信息") + private String productNames; + + @Data + public static class Item { + + @Schema(description = "调拨项编号", example = "11756") + private Long id; + + @Schema(description = "调出仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long fromWarehouseId; + + @Schema(description = "调入仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "888") + private Long toWarehouseId; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long productId; + + @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal productPrice; + + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal count; + + @Schema(description = "备注", example = "随便") + private String remark; + + // ========== 关联字段 ========== + + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "巧克力") + private String productName; + @Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "A9985") + private String productBarCode; + @Schema(description = "产品单位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "盒") + private String productUnitName; + + @Schema(description = "库存数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal stockCount; // 该字段仅仅在“详情”和“编辑”时使用 + + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveSaveReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveSaveReqVO.java new file mode 100644 index 000000000..699d0d2a5 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveSaveReqVO.java @@ -0,0 +1,68 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - ERP 库存调拨单新增/修改 Request VO") +@Data +public class ErpStockMoveSaveReqVO { + + @Schema(description = "调拨编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + private Long id; + + @Schema(description = "客户编号", example = "3113") + private Long customerId; + + @Schema(description = "调拨时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "调拨时间不能为空") + private LocalDateTime moveTime; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "附件 URL", example = "https://www.iocoder.cn/1.doc") + private String fileUrl; + + @Schema(description = "调拨项列表", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "调拨项列表不能为空") + @Valid + private List items; + + @Data + public static class Item { + + @Schema(description = "调拨项编号", example = "11756") + private Long id; + + @Schema(description = "调出仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "调出仓库编号不能为空") + private Long fromWarehouseId; + + @Schema(description = "调入仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "888") + @NotNull(message = "调入仓库编号不能为空") + private Long toWarehouseId; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "产品编号不能为空") + private Long productId; + + @Schema(description = "产品单价", example = "100.00") + private BigDecimal productPrice; + + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "产品数量不能为空") + private BigDecimal count; + + @Schema(description = "备注", example = "随便") + private String remark; + + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveDO.java new file mode 100644 index 000000000..a07c9549d --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveDO.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.stock; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * ERP 库存调拨单 DO + * + * @author 芋道源码 + */ +@TableName("erp_stock_in") +@KeySequence("erp_stock_in_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpStockMoveDO extends BaseDO { + + /** + * 调拨编号 + */ + @TableId + private Long id; + /** + * 调拨单号 + */ + private String no; + /** + * 调拨时间 + */ + private LocalDateTime moveTime; + /** + * 合计数量 + */ + private BigDecimal totalCount; + /** + * 合计金额,单位:元 + */ + private BigDecimal totalPrice; + /** + * 状态 + * + * 枚举 {@link cn.iocoder.yudao.module.erp.enums.ErpAuditStatus} + */ + private Integer status; + /** + * 备注 + */ + private String remark; + /** + * 附件 URL + */ + private String fileUrl; + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveItemDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveItemDO.java new file mode 100644 index 000000000..2e34df0dc --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveItemDO.java @@ -0,0 +1,79 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.stock; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * ERP 库存调拨单项 DO + * + * @author 芋道源码 + */ +@TableName("erp_stock_in_item") +@KeySequence("erp_stock_in_item_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpStockMoveItemDO extends BaseDO { + + /** + * 调拨项编号 + */ + @TableId + private Long id; + /** + * 调拨编号 + * + * 关联 {@link ErpStockMoveDO#getId()} + */ + private Long moveId; + /** + * 调出仓库编号 + * + * 关联 {@link ErpWarehouseDO#getId()} + */ + private Long fromWarehouseId; + /** + * 调入仓库编号 + * + * 关联 {@link ErpWarehouseDO#getId()} + */ + private Long toWarehouseId; + /** + * 产品编号 + * + * 关联 {@link ErpProductDO#getId()} + */ + private Long productId; + /** + * 产品单位编号 + * + * 冗余 {@link ErpProductDO#getUnitId()} + */ + private Long productUnitId; + /** + * 产品单价 + */ + private BigDecimal productPrice; + /** + * 产品数量 + */ + private BigDecimal count; + /** + * 合计金额,单位:元 + */ + private BigDecimal totalPrice; + /** + * 备注 + */ + private String remark; + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMoveItemMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMoveItemMapper.java new file mode 100644 index 000000000..21a267029 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMoveItemMapper.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.stock; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveItemDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +/** + * ERP 库存调拨单项 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpStockMoveItemMapper extends BaseMapperX { + + default List selectListByMoveId(Long moveId) { + return selectList(ErpStockMoveItemDO::getMoveId, moveId); + } + + default List selectListByMoveIds(Collection moveIds) { + return selectList(ErpStockMoveItemDO::getMoveId, moveIds); + } + + default int deleteByMoveId(Long moveId) { + return delete(ErpStockMoveItemDO::getMoveId, moveId); + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMoveMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMoveMapper.java new file mode 100644 index 000000000..2b45f6c7e --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMoveMapper.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMovePageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveItemDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +/** + * ERP 库存调拨单 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpStockMoveMapper extends BaseMapperX { + + default PageResult selectPage(ErpStockMovePageReqVO reqVO) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX() + .eqIfPresent(ErpStockMoveDO::getNo, reqVO.getNo()) + .betweenIfPresent(ErpStockMoveDO::getMoveTime, reqVO.getMoveTime()) + .eqIfPresent(ErpStockMoveDO::getStatus, reqVO.getStatus()) + .likeIfPresent(ErpStockMoveDO::getRemark, reqVO.getRemark()) + .eqIfPresent(ErpStockMoveDO::getCreator, reqVO.getCreator()) + .orderByDesc(ErpStockMoveDO::getId); + if (reqVO.getFromWarehouseId() != null || reqVO.getProductId() != null) { + query.leftJoin(ErpStockMoveItemDO.class, ErpStockMoveItemDO::getMoveId, ErpStockMoveDO::getId) + .eq(reqVO.getFromWarehouseId() != null, ErpStockMoveItemDO::getFromWarehouseId, reqVO.getFromWarehouseId()) + .eq(reqVO.getProductId() != null, ErpStockMoveItemDO::getProductId, reqVO.getProductId()) + .groupBy(ErpStockMoveDO::getId); // 避免 1 对多查询,产生相同的 1 + } + return selectJoinPage(reqVO, ErpStockMoveDO.class, query); + } + + default int updateByIdAndStatus(Long id, Integer status, ErpStockMoveDO updateObj) { + return update(updateObj, new LambdaUpdateWrapper() + .eq(ErpStockMoveDO::getId, id).eq(ErpStockMoveDO::getStatus, status)); + } + + default ErpStockMoveDO selectByNo(String no) { + return selectOne(ErpStockMoveDO::getNo, no); + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveService.java new file mode 100644 index 000000000..8af13a639 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveService.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMovePageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMoveSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveItemDO; +import jakarta.validation.Valid; + +import java.util.Collection; +import java.util.List; + +/** + * ERP 库存调拨单 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpStockMoveService { + + /** + * 创建库存调拨单 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createStockMove(@Valid ErpStockMoveSaveReqVO createReqVO); + + /** + * 更新库存调拨单 + * + * @param updateReqVO 更新信息 + */ + void updateStockMove(@Valid ErpStockMoveSaveReqVO updateReqVO); + + /** + * 更新库存调拨单的状态 + * + * @param id 编号 + * @param status 状态 + */ + void updateStockMoveStatus(Long id, Integer status); + + /** + * 删除库存调拨单 + * + * @param ids 编号数组 + */ + void deleteStockMove(List ids); + + /** + * 获得库存调拨单 + * + * @param id 编号 + * @return 库存调拨单 + */ + ErpStockMoveDO getStockMove(Long id); + + /** + * 获得库存调拨单分页 + * + * @param pageReqVO 分页查询 + * @return 库存调拨单分页 + */ + PageResult getStockMovePage(ErpStockMovePageReqVO pageReqVO); + + // ==================== 调拨项 ==================== + + /** + * 获得库存调拨单项列表 + * + * @param moveId 调拨编号 + * @return 库存调拨单项列表 + */ + List getStockMoveItemListByMoveId(Long moveId); + + /** + * 获得库存调拨单项 List + * + * @param moveIds 调拨编号数组 + * @return 库存调拨单项 List + */ + List getStockMoveItemListByMoveIds(Collection moveIds); + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveServiceImpl.java new file mode 100644 index 000000000..603ddfcaa --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveServiceImpl.java @@ -0,0 +1,229 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMovePageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMoveSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveItemDO; +import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockMoveItemMapper; +import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockMoveMapper; +import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO; +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import cn.iocoder.yudao.module.erp.enums.stock.ErpStockRecordBizTypeEnum; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.sale.ErpCustomerService; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; + +// TODO 芋艿:记录操作日志 + +/** + * ERP 库存调拨单 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ErpStockMoveServiceImpl implements ErpStockMoveService { + + @Resource + private ErpStockMoveMapper stockMoveMapper; + @Resource + private ErpStockMoveItemMapper stockMoveItemMapper; + + @Resource + private ErpNoRedisDAO noRedisDAO; + + @Resource + private ErpProductService productService; + @Resource + private ErpWarehouseService warehouseService; + @Resource + private ErpCustomerService customerService; + @Resource + private ErpStockRecordService stockRecordService; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createStockMove(ErpStockMoveSaveReqVO createReqVO) { + // 1.1 校验出库项的有效性 + List stockMoveItems = validateStockMoveItems(createReqVO.getItems()); + // 1.2 校验客户 + customerService.validateCustomer(createReqVO.getCustomerId()); + // 1.3 + String no = noRedisDAO.generate(ErpNoRedisDAO.STOCK_OUT_NO_PREFIX); + if (stockMoveMapper.selectByNo(no) != null) { + throw exception(STOCK_OUT_NO_EXISTS); + } + + // 2.1 插入出库单 + ErpStockMoveDO stockMove = BeanUtils.toBean(createReqVO, ErpStockMoveDO.class, in -> in + .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus()) + .setTotalCount(getSumValue(stockMoveItems, ErpStockMoveItemDO::getCount, BigDecimal::add)) + .setTotalPrice(getSumValue(stockMoveItems, ErpStockMoveItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO))); + stockMoveMapper.insert(stockMove); + // 2.2 插入出库单项 + stockMoveItems.forEach(o -> o.setMoveId(stockMove.getId())); + stockMoveItemMapper.insertBatch(stockMoveItems); + return stockMove.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateStockMove(ErpStockMoveSaveReqVO updateReqVO) { + // 1.1 校验存在 + ErpStockMoveDO stockMove = validateStockMoveExists(updateReqVO.getId()); + if (ErpAuditStatus.APPROVE.getStatus().equals(stockMove.getStatus())) { + throw exception(STOCK_OUT_UPDATE_FAIL_APPROVE, stockMove.getNo()); + } + // 1.2 校验客户 + customerService.validateCustomer(updateReqVO.getCustomerId()); + // 1.3 校验出库项的有效性 + List stockMoveItems = validateStockMoveItems(updateReqVO.getItems()); + + // 2.1 更新出库单 + ErpStockMoveDO updateObj = BeanUtils.toBean(updateReqVO, ErpStockMoveDO.class, in -> in + .setTotalCount(getSumValue(stockMoveItems, ErpStockMoveItemDO::getCount, BigDecimal::add)) + .setTotalPrice(getSumValue(stockMoveItems, ErpStockMoveItemDO::getTotalPrice, BigDecimal::add))); + stockMoveMapper.updateById(updateObj); + // 2.2 更新出库单项 + updateStockMoveItemList(updateReqVO.getId(), stockMoveItems); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateStockMoveStatus(Long id, Integer status) { + boolean approve = ErpAuditStatus.APPROVE.getStatus().equals(status); + // 1.1 校验存在 + ErpStockMoveDO stockMove = validateStockMoveExists(id); + // 1.2 校验状态 + if (stockMove.getStatus().equals(status)) { + throw exception(approve ? STOCK_OUT_APPROVE_FAIL : STOCK_OUT_PROCESS_FAIL); + } + + // 2. 更新状态 + int updateCount = stockMoveMapper.updateByIdAndStatus(id, stockMove.getStatus(), + new ErpStockMoveDO().setStatus(status)); + if (updateCount == 0) { + throw exception(approve ? STOCK_OUT_APPROVE_FAIL : STOCK_OUT_PROCESS_FAIL); + } + + // 3. 变更库存 + List stockMoveItems = stockMoveItemMapper.selectListByMoveId(id); + Integer bizType = approve ? ErpStockRecordBizTypeEnum.OTHER_OUT.getType() + : ErpStockRecordBizTypeEnum.OTHER_OUT_CANCEL.getType(); + stockMoveItems.forEach(stockMoveItem -> { + BigDecimal count = approve ? stockMoveItem.getCount() : stockMoveItem.getCount().negate(); + // TODO 芋艿:稍后搞 +// stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO( +// stockMoveItem.getProductId(), stockMoveItem.getWarehouseId(), count, +// bizType, stockMoveItem.getMoveId(), stockMoveItem.getId(), stockMove.getNo())); + }); + } + + private List validateStockMoveItems(List list) { + // 1.1 校验产品存在 + List productList = productService.validProductList( + convertSet(list, ErpStockMoveSaveReqVO.Item::getProductId)); + Map productMap = convertMap(productList, ErpProductDO::getId); + // 1.2 校验仓库存在 + // TODO 芋艿:稍后搞 +// warehouseService.validWarehouseList(convertSet(list, ErpStockMoveSaveReqVO.Item::getWarehouseId)); + // 2. 转化为 ErpStockMoveItemDO 列表 + return convertList(list, o -> BeanUtils.toBean(o, ErpStockMoveItemDO.class, item -> item + .setProductUnitId(productMap.get(item.getProductId()).getUnitId()) + .setTotalPrice(MoneyUtils.priceMultiply(item.getProductPrice(), item.getCount())))); + } + + private void updateStockMoveItemList(Long id, List newList) { + // 第一步,对比新老数据,获得添加、修改、删除的列表 + List oldList = stockMoveItemMapper.selectListByMoveId(id); + List> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录 + (oldVal, newVal) -> oldVal.getId().equals(newVal.getId())); + + // 第二步,批量添加、修改、删除 + if (CollUtil.isNotEmpty(diffList.get(0))) { + diffList.get(0).forEach(o -> o.setMoveId(id)); + stockMoveItemMapper.insertBatch(diffList.get(0)); + } + if (CollUtil.isNotEmpty(diffList.get(1))) { + stockMoveItemMapper.updateBatch(diffList.get(1)); + } + if (CollUtil.isNotEmpty(diffList.get(2))) { + stockMoveItemMapper.deleteBatchIds(convertList(diffList.get(2), ErpStockMoveItemDO::getId)); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteStockMove(List ids) { + // 1. 校验不处于已审批 + List stockMoves = stockMoveMapper.selectBatchIds(ids); + if (CollUtil.isEmpty(stockMoves)) { + return; + } + stockMoves.forEach(stockMove -> { + if (ErpAuditStatus.APPROVE.getStatus().equals(stockMove.getStatus())) { + throw exception(STOCK_OUT_DELETE_FAIL_APPROVE, stockMove.getNo()); + } + }); + + // 2. 遍历删除,并记录操作日志 + stockMoves.forEach(stockMove -> { + // 2.1 删除出库单 + stockMoveMapper.deleteById(stockMove.getId()); + // 2.2 删除出库单项 + stockMoveItemMapper.deleteByMoveId(stockMove.getId()); + }); + } + + private ErpStockMoveDO validateStockMoveExists(Long id) { + ErpStockMoveDO stockMove = stockMoveMapper.selectById(id); + if (stockMove == null) { + throw exception(STOCK_OUT_NOT_EXISTS); + } + return stockMove; + } + + @Override + public ErpStockMoveDO getStockMove(Long id) { + return stockMoveMapper.selectById(id); + } + + @Override + public PageResult getStockMovePage(ErpStockMovePageReqVO pageReqVO) { + return stockMoveMapper.selectPage(pageReqVO); + } + + // ==================== 出库项 ==================== + + @Override + public List getStockMoveItemListByMoveId(Long inId) { + return stockMoveItemMapper.selectListByMoveId(inId); + } + + @Override + public List getStockMoveItemListByMoveIds(Collection inIds) { + if (CollUtil.isEmpty(inIds)) { + return Collections.emptyList(); + } + return stockMoveItemMapper.selectListByMoveIds(inIds); + } + +} \ No newline at end of file From 573a79cad6851cc7b8a36bad99824d3242339238 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 7 Feb 2024 20:47:26 +0800 Subject: [PATCH 14/15] =?UTF-8?q?=E2=9C=A8=20ERP=EF=BC=9A=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=20ERP=20=E8=B0=83=E6=8B=A8=E5=8D=95=E7=9A=84=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=20100%?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/erp/enums/ErrorCodeConstants.java | 12 ++++- .../stock/ErpStockRecordBizTypeEnum.java | 5 ++ .../stock/vo/move/ErpStockMoveSaveReqVO.java | 9 ++++ .../dal/dataobject/stock/ErpStockMoveDO.java | 4 +- .../dataobject/stock/ErpStockMoveItemDO.java | 4 +- .../erp/dal/redis/no/ErpNoRedisDAO.java | 5 ++ .../service/stock/ErpStockInServiceImpl.java | 2 +- .../stock/ErpStockMoveServiceImpl.java | 50 +++++++++---------- .../service/stock/ErpStockOutServiceImpl.java | 4 +- .../service/stock/ErpStockServiceImpl.java | 13 ++++- 10 files changed, 72 insertions(+), 36 deletions(-) diff --git a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java index 1926b34ac..ace58df2a 100644 --- a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java +++ b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java @@ -40,9 +40,17 @@ public interface ErrorCodeConstants { ErrorCode STOCK_OUT_NO_EXISTS = new ErrorCode(1_030_402_004, "生成出库单失败,请重新提交"); ErrorCode STOCK_OUT_UPDATE_FAIL_APPROVE = new ErrorCode(1_030_402_005, "其它出库单({})已审核,无法修改"); + // ========== ERP 其它出库单 1-030-403-000 ========== + ErrorCode STOCK_MOVE_NOT_EXISTS = new ErrorCode(1_030_402_000, "库存调拨单不存在"); + ErrorCode STOCK_MOVE_DELETE_FAIL_APPROVE = new ErrorCode(1_030_402_001, "库存调拨单({})已审核,无法删除"); + ErrorCode STOCK_MOVE_PROCESS_FAIL = new ErrorCode(1_030_402_002, "反审核失败,只有已审核的出库单才能反审核"); + ErrorCode STOCK_MOVE_APPROVE_FAIL = new ErrorCode(1_030_402_003, "审核失败,只有未审核的出库单才能审核"); + ErrorCode STOCK_MOVE_NO_EXISTS = new ErrorCode(1_030_402_004, "生成调拨号失败,请重新提交"); + ErrorCode STOCK_MOVE_UPDATE_FAIL_APPROVE = new ErrorCode(1_030_402_005, "库存调拨单({})已审核,无法修改"); + // ========== ERP 产品库存 1-030-403-000 ========== - ErrorCode STOCK_COUNT_NEGATIVE = new ErrorCode(1_030_403_000, "操作失败,产品当前库存:{},小于变更数量:{}"); - ErrorCode STOCK_COUNT_NEGATIVE2 = new ErrorCode(1_030_403_000, "操作失败,库存不足"); + ErrorCode STOCK_COUNT_NEGATIVE = new ErrorCode(1_030_403_000, "操作失败,产品({})所在仓库({})的库存:{},小于变更数量:{}"); + ErrorCode STOCK_COUNT_NEGATIVE2 = new ErrorCode(1_030_403_000, "操作失败,产品({})所在仓库({})的库存不足"); // ========== ERP 产品 1-030-500-000 ========== ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_030_500_000, "产品不存在"); diff --git a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/stock/ErpStockRecordBizTypeEnum.java b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/stock/ErpStockRecordBizTypeEnum.java index fb16934d9..d56bfa928 100644 --- a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/stock/ErpStockRecordBizTypeEnum.java +++ b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/stock/ErpStockRecordBizTypeEnum.java @@ -20,6 +20,11 @@ public enum ErpStockRecordBizTypeEnum implements IntArrayValuable { OTHER_OUT(20, "其它出库"), OTHER_OUT_CANCEL(21, "其它出库(作废)"), + + MOVE_IN(30, "调拨入库"), + MOVE_IN_CANCEL(31, "调拨入库(作废)"), + MOVE_OUT(32, "调拨出库"), + MOVE_OUT_CANCEL(33, "调拨出库(作废)"), ; public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ErpStockRecordBizTypeEnum::getType).toArray(); diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveSaveReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveSaveReqVO.java index 699d0d2a5..17a431561 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveSaveReqVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveSaveReqVO.java @@ -1,7 +1,10 @@ package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move; +import cn.hutool.core.util.ObjectUtil; +import com.fasterxml.jackson.annotation.JsonIgnore; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.Valid; +import jakarta.validation.constraints.AssertTrue; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.Data; @@ -63,6 +66,12 @@ public class ErpStockMoveSaveReqVO { @Schema(description = "备注", example = "随便") private String remark; + @AssertTrue(message = "调出、调仓仓库不能相同") + @JsonIgnore + public boolean isWarehouseValid() { + return ObjectUtil.notEqual(fromWarehouseId, toWarehouseId); + } + } } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveDO.java index a07c9549d..682b33104 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveDO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveDO.java @@ -14,8 +14,8 @@ import java.time.LocalDateTime; * * @author 芋道源码 */ -@TableName("erp_stock_in") -@KeySequence("erp_stock_in_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@TableName("erp_stock_move") +@KeySequence("erp_stock_move_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveItemDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveItemDO.java index 2e34df0dc..aee203670 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveItemDO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveItemDO.java @@ -14,8 +14,8 @@ import java.math.BigDecimal; * * @author 芋道源码 */ -@TableName("erp_stock_in_item") -@KeySequence("erp_stock_in_item_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@TableName("erp_stock_move_item") +@KeySequence("erp_stock_move_item_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java index 04d2c25ca..4be18012b 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java @@ -28,6 +28,11 @@ public class ErpNoRedisDAO { */ public static final String STOCK_OUT_NO_PREFIX = "QCKD"; + /** + * 库存调拨 {@link cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveDO} + */ + public static final String STOCK_MOVE_NO_PREFIX = "QCDB"; + @Resource private StringRedisTemplate stringRedisTemplate; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java index 9e9280fcd..22b08b266 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java @@ -66,7 +66,7 @@ public class ErpStockInServiceImpl implements ErpStockInService { List stockInItems = validateStockInItems(createReqVO.getItems()); // 1.2 校验供应商 supplierService.validateSupplier(createReqVO.getSupplierId()); - // 1.3 + // 1.3 生成入库单号,并校验唯一性 String no = noRedisDAO.generate(ErpNoRedisDAO.STOCK_IN_NO_PREFIX); if (stockInMapper.selectByNo(no) != null) { throw exception(STOCK_IN_NO_EXISTS); diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveServiceImpl.java index 603ddfcaa..089c98e72 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveServiceImpl.java @@ -15,7 +15,7 @@ import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO; import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; import cn.iocoder.yudao.module.erp.enums.stock.ErpStockRecordBizTypeEnum; import cn.iocoder.yudao.module.erp.service.product.ErpProductService; -import cn.iocoder.yudao.module.erp.service.sale.ErpCustomerService; +import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockRecordCreateReqBO; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -26,6 +26,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.stream.Stream; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; @@ -55,8 +56,6 @@ public class ErpStockMoveServiceImpl implements ErpStockMoveService { @Resource private ErpWarehouseService warehouseService; @Resource - private ErpCustomerService customerService; - @Resource private ErpStockRecordService stockRecordService; @Override @@ -64,12 +63,10 @@ public class ErpStockMoveServiceImpl implements ErpStockMoveService { public Long createStockMove(ErpStockMoveSaveReqVO createReqVO) { // 1.1 校验出库项的有效性 List stockMoveItems = validateStockMoveItems(createReqVO.getItems()); - // 1.2 校验客户 - customerService.validateCustomer(createReqVO.getCustomerId()); - // 1.3 - String no = noRedisDAO.generate(ErpNoRedisDAO.STOCK_OUT_NO_PREFIX); + // 1.2 生成调拨单号,并校验唯一性 + String no = noRedisDAO.generate(ErpNoRedisDAO.STOCK_MOVE_NO_PREFIX); if (stockMoveMapper.selectByNo(no) != null) { - throw exception(STOCK_OUT_NO_EXISTS); + throw exception(STOCK_MOVE_NO_EXISTS); } // 2.1 插入出库单 @@ -90,11 +87,9 @@ public class ErpStockMoveServiceImpl implements ErpStockMoveService { // 1.1 校验存在 ErpStockMoveDO stockMove = validateStockMoveExists(updateReqVO.getId()); if (ErpAuditStatus.APPROVE.getStatus().equals(stockMove.getStatus())) { - throw exception(STOCK_OUT_UPDATE_FAIL_APPROVE, stockMove.getNo()); + throw exception(STOCK_MOVE_UPDATE_FAIL_APPROVE, stockMove.getNo()); } - // 1.2 校验客户 - customerService.validateCustomer(updateReqVO.getCustomerId()); - // 1.3 校验出库项的有效性 + // 1.2 校验出库项的有效性 List stockMoveItems = validateStockMoveItems(updateReqVO.getItems()); // 2.1 更新出库单 @@ -114,26 +109,31 @@ public class ErpStockMoveServiceImpl implements ErpStockMoveService { ErpStockMoveDO stockMove = validateStockMoveExists(id); // 1.2 校验状态 if (stockMove.getStatus().equals(status)) { - throw exception(approve ? STOCK_OUT_APPROVE_FAIL : STOCK_OUT_PROCESS_FAIL); + throw exception(approve ? STOCK_MOVE_APPROVE_FAIL : STOCK_MOVE_PROCESS_FAIL); } // 2. 更新状态 int updateCount = stockMoveMapper.updateByIdAndStatus(id, stockMove.getStatus(), new ErpStockMoveDO().setStatus(status)); if (updateCount == 0) { - throw exception(approve ? STOCK_OUT_APPROVE_FAIL : STOCK_OUT_PROCESS_FAIL); + throw exception(approve ? STOCK_MOVE_APPROVE_FAIL : STOCK_MOVE_PROCESS_FAIL); } // 3. 变更库存 List stockMoveItems = stockMoveItemMapper.selectListByMoveId(id); - Integer bizType = approve ? ErpStockRecordBizTypeEnum.OTHER_OUT.getType() - : ErpStockRecordBizTypeEnum.OTHER_OUT_CANCEL.getType(); + Integer fromBizType = approve ? ErpStockRecordBizTypeEnum.MOVE_OUT.getType() + : ErpStockRecordBizTypeEnum.MOVE_OUT_CANCEL.getType(); + Integer toBizType = approve ? ErpStockRecordBizTypeEnum.MOVE_IN.getType() + : ErpStockRecordBizTypeEnum.MOVE_IN_CANCEL.getType(); stockMoveItems.forEach(stockMoveItem -> { - BigDecimal count = approve ? stockMoveItem.getCount() : stockMoveItem.getCount().negate(); - // TODO 芋艿:稍后搞 -// stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO( -// stockMoveItem.getProductId(), stockMoveItem.getWarehouseId(), count, -// bizType, stockMoveItem.getMoveId(), stockMoveItem.getId(), stockMove.getNo())); + BigDecimal fromCount = approve ? stockMoveItem.getCount().negate() : stockMoveItem.getCount(); + BigDecimal toCount = approve ? stockMoveItem.getCount() : stockMoveItem.getCount().negate(); + stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO( + stockMoveItem.getProductId(), stockMoveItem.getFromWarehouseId(), fromCount, + fromBizType, stockMoveItem.getMoveId(), stockMoveItem.getId(), stockMove.getNo())); + stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO( + stockMoveItem.getProductId(), stockMoveItem.getToWarehouseId(), toCount, + toBizType, stockMoveItem.getMoveId(), stockMoveItem.getId(), stockMove.getNo())); }); } @@ -143,8 +143,8 @@ public class ErpStockMoveServiceImpl implements ErpStockMoveService { convertSet(list, ErpStockMoveSaveReqVO.Item::getProductId)); Map productMap = convertMap(productList, ErpProductDO::getId); // 1.2 校验仓库存在 - // TODO 芋艿:稍后搞 -// warehouseService.validWarehouseList(convertSet(list, ErpStockMoveSaveReqVO.Item::getWarehouseId)); + warehouseService.validWarehouseList(convertSetByFlatMap(list, + item -> Stream.of(item.getFromWarehouseId(), item.getToWarehouseId()))); // 2. 转化为 ErpStockMoveItemDO 列表 return convertList(list, o -> BeanUtils.toBean(o, ErpStockMoveItemDO.class, item -> item .setProductUnitId(productMap.get(item.getProductId()).getUnitId()) @@ -180,7 +180,7 @@ public class ErpStockMoveServiceImpl implements ErpStockMoveService { } stockMoves.forEach(stockMove -> { if (ErpAuditStatus.APPROVE.getStatus().equals(stockMove.getStatus())) { - throw exception(STOCK_OUT_DELETE_FAIL_APPROVE, stockMove.getNo()); + throw exception(STOCK_MOVE_DELETE_FAIL_APPROVE, stockMove.getNo()); } }); @@ -196,7 +196,7 @@ public class ErpStockMoveServiceImpl implements ErpStockMoveService { private ErpStockMoveDO validateStockMoveExists(Long id) { ErpStockMoveDO stockMove = stockMoveMapper.selectById(id); if (stockMove == null) { - throw exception(STOCK_OUT_NOT_EXISTS); + throw exception(STOCK_MOVE_NOT_EXISTS); } return stockMove; } diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java index 36b5a30d8..8117ef36a 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java @@ -67,7 +67,7 @@ public class ErpStockOutServiceImpl implements ErpStockOutService { List stockOutItems = validateStockOutItems(createReqVO.getItems()); // 1.2 校验客户 customerService.validateCustomer(createReqVO.getCustomerId()); - // 1.3 + // 1.3 生成出库单号,并校验唯一性 String no = noRedisDAO.generate(ErpNoRedisDAO.STOCK_OUT_NO_PREFIX); if (stockOutMapper.selectByNo(no) != null) { throw exception(STOCK_OUT_NO_EXISTS); @@ -130,7 +130,7 @@ public class ErpStockOutServiceImpl implements ErpStockOutService { Integer bizType = approve ? ErpStockRecordBizTypeEnum.OTHER_OUT.getType() : ErpStockRecordBizTypeEnum.OTHER_OUT_CANCEL.getType(); stockOutItems.forEach(stockOutItem -> { - BigDecimal count = approve ? stockOutItem.getCount() : stockOutItem.getCount().negate(); + BigDecimal count = approve ? stockOutItem.getCount().negate() : stockOutItem.getCount(); stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO( stockOutItem.getProductId(), stockOutItem.getWarehouseId(), count, bizType, stockOutItem.getOutId(), stockOutItem.getId(), stockOut.getNo())); diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockServiceImpl.java index c930cff36..91495acda 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockServiceImpl.java @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stock.ErpStockPageReqVO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockMapper; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -30,6 +31,11 @@ public class ErpStockServiceImpl implements ErpStockService { */ private static final Boolean NEGATIVE_STOCK_COUNT_ENABLE = false; + @Resource + private ErpProductService productService; + @Resource + private ErpWarehouseService warehouseService; + @Resource private ErpStockMapper stockMapper; @@ -58,13 +64,16 @@ public class ErpStockServiceImpl implements ErpStockService { } // 1.2 校验库存是否充足 if (!NEGATIVE_STOCK_COUNT_ENABLE && stock.getCount().add(count).compareTo(BigDecimal.ZERO) < 0) { - throw exception(STOCK_COUNT_NEGATIVE, stock.getCount(), count); + throw exception(STOCK_COUNT_NEGATIVE, productService.getProduct(productId).getName(), + warehouseService.getWarehouse(warehouseId).getName(), stock.getCount(), count); } // 2. 库存变更 int updateCount = stockMapper.updateCountIncrement(stock.getId(), count, NEGATIVE_STOCK_COUNT_ENABLE); if (updateCount == 0) { - throw exception(STOCK_COUNT_NEGATIVE2); // 此时不好去查询最新库存,所以直接抛出该提示,不提供具体库存数字 + // 此时不好去查询最新库存,所以直接抛出该提示,不提供具体库存数字 + throw exception(STOCK_COUNT_NEGATIVE2, productService.getProduct(productId).getName(), + warehouseService.getWarehouse(warehouseId).getName()); } // 3. 返回最新库存 From 94247addc6a572698ab5e448086143a327dd5a4d Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 8 Feb 2024 06:59:19 +0800 Subject: [PATCH 15/15] =?UTF-8?q?=E2=9C=A8=20ERP=EF=BC=9A=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=20ERP=20=E7=9B=98=E7=82=B9=E5=8D=95=E7=9A=84=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=20100%?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/erp/enums/ErrorCodeConstants.java | 20 +- .../stock/ErpStockRecordBizTypeEnum.java | 5 + .../admin/stock/ErpStockCheckController.java | 149 +++++++++++ .../admin/stock/ErpStockMoveController.java | 3 - .../vo/check/ErpStockCheckPageReqVO.java | 45 ++++ .../stock/vo/check/ErpStockCheckRespVO.java | 111 +++++++++ .../vo/check/ErpStockCheckSaveReqVO.java | 69 ++++++ .../dal/dataobject/stock/ErpStockCheckDO.java | 63 +++++ .../dataobject/stock/ErpStockCheckItemDO.java | 83 +++++++ .../mysql/stock/ErpStockCheckItemMapper.java | 30 +++ .../dal/mysql/stock/ErpStockCheckMapper.java | 46 ++++ .../erp/dal/redis/no/ErpNoRedisDAO.java | 5 + .../service/stock/ErpStockCheckService.java | 84 +++++++ .../stock/ErpStockCheckServiceImpl.java | 232 ++++++++++++++++++ .../service/stock/ErpStockInServiceImpl.java | 6 +- .../stock/ErpStockMoveServiceImpl.java | 10 +- .../service/stock/ErpStockOutServiceImpl.java | 13 +- 17 files changed, 952 insertions(+), 22 deletions(-) create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockCheckController.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckPageReqVO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckRespVO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckSaveReqVO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockCheckDO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockCheckItemDO.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockCheckItemMapper.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockCheckMapper.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockCheckService.java create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockCheckServiceImpl.java diff --git a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java index ace58df2a..7c04c19f1 100644 --- a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java +++ b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java @@ -40,17 +40,25 @@ public interface ErrorCodeConstants { ErrorCode STOCK_OUT_NO_EXISTS = new ErrorCode(1_030_402_004, "生成出库单失败,请重新提交"); ErrorCode STOCK_OUT_UPDATE_FAIL_APPROVE = new ErrorCode(1_030_402_005, "其它出库单({})已审核,无法修改"); - // ========== ERP 其它出库单 1-030-403-000 ========== + // ========== ERP 库存调拨单 1-030-403-000 ========== ErrorCode STOCK_MOVE_NOT_EXISTS = new ErrorCode(1_030_402_000, "库存调拨单不存在"); ErrorCode STOCK_MOVE_DELETE_FAIL_APPROVE = new ErrorCode(1_030_402_001, "库存调拨单({})已审核,无法删除"); - ErrorCode STOCK_MOVE_PROCESS_FAIL = new ErrorCode(1_030_402_002, "反审核失败,只有已审核的出库单才能反审核"); - ErrorCode STOCK_MOVE_APPROVE_FAIL = new ErrorCode(1_030_402_003, "审核失败,只有未审核的出库单才能审核"); + ErrorCode STOCK_MOVE_PROCESS_FAIL = new ErrorCode(1_030_402_002, "反审核失败,只有已审核的调拨单才能反审核"); + ErrorCode STOCK_MOVE_APPROVE_FAIL = new ErrorCode(1_030_402_003, "审核失败,只有未审核的调拨单才能审核"); ErrorCode STOCK_MOVE_NO_EXISTS = new ErrorCode(1_030_402_004, "生成调拨号失败,请重新提交"); ErrorCode STOCK_MOVE_UPDATE_FAIL_APPROVE = new ErrorCode(1_030_402_005, "库存调拨单({})已审核,无法修改"); - // ========== ERP 产品库存 1-030-403-000 ========== - ErrorCode STOCK_COUNT_NEGATIVE = new ErrorCode(1_030_403_000, "操作失败,产品({})所在仓库({})的库存:{},小于变更数量:{}"); - ErrorCode STOCK_COUNT_NEGATIVE2 = new ErrorCode(1_030_403_000, "操作失败,产品({})所在仓库({})的库存不足"); + // ========== ERP 库存盘点单 1-030-403-000 ========== + ErrorCode STOCK_CHECK_NOT_EXISTS = new ErrorCode(1_030_403_000, "库存盘点单不存在"); + ErrorCode STOCK_CHECK_DELETE_FAIL_APPROVE = new ErrorCode(1_030_403_001, "库存盘点单({})已审核,无法删除"); + ErrorCode STOCK_CHECK_PROCESS_FAIL = new ErrorCode(1_030_403_002, "反审核失败,只有已审核的盘点单才能反审核"); + ErrorCode STOCK_CHECK_APPROVE_FAIL = new ErrorCode(1_030_403_003, "审核失败,只有未审核的盘点单才能审核"); + ErrorCode STOCK_CHECK_NO_EXISTS = new ErrorCode(1_030_403_004, "生成盘点号失败,请重新提交"); + ErrorCode STOCK_CHECK_UPDATE_FAIL_APPROVE = new ErrorCode(1_030_403_005, "库存盘点单({})已审核,无法修改"); + + // ========== ERP 产品库存 1-030-404-000 ========== + ErrorCode STOCK_COUNT_NEGATIVE = new ErrorCode(1_030_404_000, "操作失败,产品({})所在仓库({})的库存:{},小于变更数量:{}"); + ErrorCode STOCK_COUNT_NEGATIVE2 = new ErrorCode(1_030_404_001, "操作失败,产品({})所在仓库({})的库存不足"); // ========== ERP 产品 1-030-500-000 ========== ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_030_500_000, "产品不存在"); diff --git a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/stock/ErpStockRecordBizTypeEnum.java b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/stock/ErpStockRecordBizTypeEnum.java index d56bfa928..31129a2e4 100644 --- a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/stock/ErpStockRecordBizTypeEnum.java +++ b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/stock/ErpStockRecordBizTypeEnum.java @@ -25,6 +25,11 @@ public enum ErpStockRecordBizTypeEnum implements IntArrayValuable { MOVE_IN_CANCEL(31, "调拨入库(作废)"), MOVE_OUT(32, "调拨出库"), MOVE_OUT_CANCEL(33, "调拨出库(作废)"), + + CHECK_MORE_IN(40, "盘盈入库"), + CHECK_MORE_IN_CANCEL(41, "盘盈入库(作废)"), + CHECK_LESS_OUT(42, "盘亏出库"), + CHECK_LESS_OUT_CANCEL(43, "盘亏出库(作废)"), ; public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ErpStockRecordBizTypeEnum::getType).toArray(); diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockCheckController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockCheckController.java new file mode 100644 index 000000000..c2abc6ec9 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockCheckController.java @@ -0,0 +1,149 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckItemDO; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.stock.ErpStockCheckService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; + +@Tag(name = "管理后台 - ERP 库存调拨单") +@RestController +@RequestMapping("/erp/stock-check") +@Validated +public class ErpStockCheckController { + + @Resource + private ErpStockCheckService stockCheckService; + @Resource + private ErpProductService productService; + + @Resource + private AdminUserApi adminUserApi; + + @PostMapping("/create") + @Operation(summary = "创建库存调拨单") + @PreAuthorize("@ss.hasPermission('erp:stock-check:create')") + public CommonResult createStockCheck(@Valid @RequestBody ErpStockCheckSaveReqVO createReqVO) { + return success(stockCheckService.createStockCheck(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新库存调拨单") + @PreAuthorize("@ss.hasPermission('erp:stock-check:update')") + public CommonResult updateStockCheck(@Valid @RequestBody ErpStockCheckSaveReqVO updateReqVO) { + stockCheckService.updateStockCheck(updateReqVO); + return success(true); + } + + @PutMapping("/update-status") + @Operation(summary = "更新库存调拨单的状态") + @PreAuthorize("@ss.hasPermission('erp:stock-check:update-status')") + public CommonResult updateStockCheckStatus(@RequestParam("id") Long id, + @RequestParam("status") Integer status) { + stockCheckService.updateStockCheckStatus(id, status); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除库存调拨单") + @Parameter(name = "ids", description = "编号数组", required = true) + @PreAuthorize("@ss.hasPermission('erp:stock-check:delete')") + public CommonResult deleteStockCheck(@RequestParam("ids") List ids) { + stockCheckService.deleteStockCheck(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得库存调拨单") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('erp:stock-check:query')") + public CommonResult getStockCheck(@RequestParam("id") Long id) { + ErpStockCheckDO stockCheck = stockCheckService.getStockCheck(id); + if (stockCheck == null) { + return success(null); + } + List stockCheckItemList = stockCheckService.getStockCheckItemListByCheckId(id); + Map productMap = productService.getProductVOMap( + convertSet(stockCheckItemList, ErpStockCheckItemDO::getProductId)); + return success(BeanUtils.toBean(stockCheck, ErpStockCheckRespVO.class, stockCheckVO -> + stockCheckVO.setItems(BeanUtils.toBean(stockCheckItemList, ErpStockCheckRespVO.Item.class, item -> + MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())))))); + } + + @GetMapping("/page") + @Operation(summary = "获得库存调拨单分页") + @PreAuthorize("@ss.hasPermission('erp:stock-check:query')") + public CommonResult> getStockCheckPage(@Valid ErpStockCheckPageReqVO pageReqVO) { + PageResult pageResult = stockCheckService.getStockCheckPage(pageReqVO); + return success(buildStockCheckVOPageResult(pageResult)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出库存调拨单 Excel") + @PreAuthorize("@ss.hasPermission('erp:stock-check:export')") + @OperateLog(type = EXPORT) + public void exportStockCheckExcel(@Valid ErpStockCheckPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = buildStockCheckVOPageResult(stockCheckService.getStockCheckPage(pageReqVO)).getList(); + // 导出 Excel + ExcelUtils.write(response, "库存调拨单.xls", "数据", ErpStockCheckRespVO.class, list); + } + + private PageResult buildStockCheckVOPageResult(PageResult pageResult) { + if (CollUtil.isEmpty(pageResult.getList())) { + return PageResult.empty(pageResult.getTotal()); + } + // 1.1 出库项 + List stockCheckItemList = stockCheckService.getStockCheckItemListByCheckIds( + convertSet(pageResult.getList(), ErpStockCheckDO::getId)); + Map> stockCheckItemMap = convertMultiMap(stockCheckItemList, ErpStockCheckItemDO::getCheckId); + // 1.2 商品信息 + Map productMap = productService.getProductVOMap( + convertSet(stockCheckItemList, ErpStockCheckItemDO::getProductId)); + // 1.3 管理员信息 + Map userMap = adminUserApi.getUserMap( + convertSet(pageResult.getList(), erpStockRecordDO -> Long.parseLong(erpStockRecordDO.getCreator()))); + // 2. 开始拼接 + return BeanUtils.toBean(pageResult, ErpStockCheckRespVO.class, stockCheck -> { + stockCheck.setItems(BeanUtils.toBean(stockCheckItemMap.get(stockCheck.getId()), ErpStockCheckRespVO.Item.class, + item -> MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())))); + stockCheck.setProductNames(CollUtil.join(stockCheck.getItems(), ",", ErpStockCheckRespVO.Item::getProductName)); + MapUtils.findAndThen(userMap, Long.parseLong(stockCheck.getCreator()), user -> stockCheck.setCreatorName(user.getNickname())); + }); + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockMoveController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockMoveController.java index e39b7bba7..d8c838b61 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockMoveController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockMoveController.java @@ -16,7 +16,6 @@ import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveDO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveItemDO; import cn.iocoder.yudao.module.erp.service.product.ErpProductService; -import cn.iocoder.yudao.module.erp.service.sale.ErpCustomerService; import cn.iocoder.yudao.module.erp.service.stock.ErpStockMoveService; import cn.iocoder.yudao.module.erp.service.stock.ErpStockService; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; @@ -53,8 +52,6 @@ public class ErpStockMoveController { private ErpStockService stockService; @Resource private ErpProductService productService; - @Resource - private ErpCustomerService customerService; @Resource private AdminUserApi adminUserApi; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckPageReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckPageReqVO.java new file mode 100644 index 000000000..2bae14c1e --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckPageReqVO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - ERP 库存盘点单分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ErpStockCheckPageReqVO extends PageParam { + + @Schema(description = "盘点单号", example = "S123") + private String no; + + @Schema(description = "仓库编号", example = "3113") + private Long warehouseId; + + @Schema(description = "盘点时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] checkTime; + + @Schema(description = "状态", example = "10") + @InEnum(ErpAuditStatus.class) + private Integer status; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "创建者") + private String creator; + + @Schema(description = "产品编号", example = "1") + private Long productId; + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckRespVO.java new file mode 100644 index 000000000..d761516d9 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckRespVO.java @@ -0,0 +1,111 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.module.erp.enums.DictTypeConstants.AUDIT_STATUS; + +@Schema(description = "管理后台 - ERP 库存盘点单 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ErpStockCheckRespVO { + + @Schema(description = "盘点编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + @ExcelProperty("盘点编号") + private Long id; + + @Schema(description = "盘点单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "S123") + @ExcelProperty("盘点单号") + private String no; + + @Schema(description = "盘点时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("盘点时间") + private LocalDateTime checkTime; + + @Schema(description = "合计数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "15663") + @ExcelProperty("合计数量") + private BigDecimal totalCount; + + @Schema(description = "合计金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "24906") + @ExcelProperty("合计金额") + private BigDecimal totalPrice; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @ExcelProperty(value = "状态", converter = DictConvert.class) + @DictFormat(AUDIT_STATUS) + private Integer status; + + @Schema(description = "备注", example = "随便") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "附件 URL", example = "https://www.iocoder.cn/1.doc") + private String fileUrl; + + @Schema(description = "审核人", example = "芋道") + private String creator; + @Schema(description = "审核人名称", example = "芋道") + private String creatorName; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "盘点项列表", requiredMode = Schema.RequiredMode.REQUIRED) + private List items; + + @Schema(description = "产品信息", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("产品信息") + private String productNames; + + @Data + public static class Item { + + @Schema(description = "盘点项编号", example = "11756") + private Long id; + + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long warehouseId; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long productId; + + @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal productPrice; + + @Schema(description = "账面数量(当前库存)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "账面数量不能为空") + private BigDecimal stockCount; + + @Schema(description = "实际数量(实际库存)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "实际数量不能为空") + private BigDecimal actualCount; + + @Schema(description = "盈亏数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "盈亏数量不能为空") + private BigDecimal count; + + @Schema(description = "备注", example = "随便") + private String remark; + + // ========== 关联字段 ========== + + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "巧克力") + private String productName; + @Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "A9985") + private String productBarCode; + @Schema(description = "产品单位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "盒") + private String productUnitName; + + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckSaveReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckSaveReqVO.java new file mode 100644 index 000000000..0af223fb5 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckSaveReqVO.java @@ -0,0 +1,69 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - ERP 其它出库单新增/修改 Request VO") +@Data +public class ErpStockCheckSaveReqVO { + + @Schema(description = "出库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + private Long id; + + @Schema(description = "出库时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "出库时间不能为空") + private LocalDateTime checkTime; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "附件 URL", example = "https://www.iocoder.cn/1.doc") + private String fileUrl; + + @Schema(description = "出库项列表", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "出库项列表不能为空") + @Valid + private List items; + + @Data + public static class Item { + + @Schema(description = "出库项编号", example = "11756") + private Long id; + + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "仓库编号不能为空") + private Long warehouseId; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "产品编号不能为空") + private Long productId; + + @Schema(description = "产品单价", example = "100.00") + private BigDecimal productPrice; + + @Schema(description = "账面数量(当前库存)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "账面数量不能为空") + private BigDecimal stockCount; + + @Schema(description = "实际数量(实际库存)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "实际数量不能为空") + private BigDecimal actualCount; + + @Schema(description = "盈亏数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "盈亏数量不能为空") + private BigDecimal count; + + @Schema(description = "备注", example = "随便") + private String remark; + + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockCheckDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockCheckDO.java new file mode 100644 index 000000000..e9168275f --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockCheckDO.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.stock; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * ERP 库存盘点单 DO + * + * @author 芋道源码 + */ +@TableName("erp_stock_check") +@KeySequence("erp_stock_check_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpStockCheckDO extends BaseDO { + + /** + * 盘点编号 + */ + @TableId + private Long id; + /** + * 盘点单号 + */ + private String no; + /** + * 盘点时间 + */ + private LocalDateTime checkTime; + /** + * 合计数量 + */ + private BigDecimal totalCount; + /** + * 合计金额,单位:元 + */ + private BigDecimal totalPrice; + /** + * 状态 + * + * 枚举 {@link cn.iocoder.yudao.module.erp.enums.ErpAuditStatus} + */ + private Integer status; + /** + * 备注 + */ + private String remark; + /** + * 附件 URL + */ + private String fileUrl; + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockCheckItemDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockCheckItemDO.java new file mode 100644 index 000000000..c3c4dbf99 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockCheckItemDO.java @@ -0,0 +1,83 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.stock; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * ERP 库存盘点单项 DO + * + * @author 芋道源码 + */ +@TableName("erp_stock_check_item") +@KeySequence("erp_stock_check_item_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpStockCheckItemDO extends BaseDO { + + /** + * 盘点项编号 + */ + @TableId + private Long id; + /** + * 盘点编号 + * + * 关联 {@link ErpStockCheckDO#getId()} + */ + private Long checkId; + /** + * 仓库编号 + * + * 关联 {@link ErpWarehouseDO#getId()} + */ + private Long warehouseId; + /** + * 产品编号 + * + * 关联 {@link ErpProductDO#getId()} + */ + private Long productId; + /** + * 产品单位编号 + * + * 冗余 {@link ErpProductDO#getUnitId()} + */ + private Long productUnitId; + /** + * 产品单价 + */ + private BigDecimal productPrice; + /** + * 账面数量(当前库存) + */ + private BigDecimal stockCount; + /** + * 实际数量(实际库存) + */ + private BigDecimal actualCount; + /** + * 盈亏数量 + * + * count = stockCount - actualCount + */ + private BigDecimal count; + /** + * 合计金额,单位:元 + */ + private BigDecimal totalPrice; + /** + * 备注 + */ + private String remark; + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockCheckItemMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockCheckItemMapper.java new file mode 100644 index 000000000..ae13f9f96 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockCheckItemMapper.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.stock; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckItemDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +/** + * ERP 库存盘点单项 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpStockCheckItemMapper extends BaseMapperX { + + default List selectListByCheckId(Long checkId) { + return selectList(ErpStockCheckItemDO::getCheckId, checkId); + } + + default List selectListByCheckIds(Collection checkIds) { + return selectList(ErpStockCheckItemDO::getCheckId, checkIds); + } + + default int deleteByCheckId(Long checkId) { + return delete(ErpStockCheckItemDO::getCheckId, checkId); + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockCheckMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockCheckMapper.java new file mode 100644 index 000000000..3328f39b2 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockCheckMapper.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckItemDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +/** + * ERP 库存调拨单 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpStockCheckMapper extends BaseMapperX { + + default PageResult selectPage(ErpStockCheckPageReqVO reqVO) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX() + .eqIfPresent(ErpStockCheckDO::getNo, reqVO.getNo()) + .betweenIfPresent(ErpStockCheckDO::getCheckTime, reqVO.getCheckTime()) + .eqIfPresent(ErpStockCheckDO::getStatus, reqVO.getStatus()) + .likeIfPresent(ErpStockCheckDO::getRemark, reqVO.getRemark()) + .eqIfPresent(ErpStockCheckDO::getCreator, reqVO.getCreator()) + .orderByDesc(ErpStockCheckDO::getId); + if (reqVO.getWarehouseId() != null || reqVO.getProductId() != null) { + query.leftJoin(ErpStockCheckItemDO.class, ErpStockCheckItemDO::getCheckId, ErpStockCheckDO::getId) + .eq(reqVO.getWarehouseId() != null, ErpStockCheckItemDO::getWarehouseId, reqVO.getWarehouseId()) + .eq(reqVO.getProductId() != null, ErpStockCheckItemDO::getProductId, reqVO.getProductId()) + .groupBy(ErpStockCheckDO::getId); // 避免 1 对多查询,产生相同的 1 + } + return selectJoinPage(reqVO, ErpStockCheckDO.class, query); + } + + default int updateByIdAndStatus(Long id, Integer status, ErpStockCheckDO updateObj) { + return update(updateObj, new LambdaUpdateWrapper() + .eq(ErpStockCheckDO::getId, id).eq(ErpStockCheckDO::getStatus, status)); + } + + default ErpStockCheckDO selectByNo(String no) { + return selectOne(ErpStockCheckDO::getNo, no); + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java index 4be18012b..bd2612db1 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java @@ -33,6 +33,11 @@ public class ErpNoRedisDAO { */ public static final String STOCK_MOVE_NO_PREFIX = "QCDB"; + /** + * 库存盘点 {@link cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckDO} + */ + public static final String STOCK_CHECK_NO_PREFIX = "QCPD"; + @Resource private StringRedisTemplate stringRedisTemplate; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockCheckService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockCheckService.java new file mode 100644 index 000000000..2f8a0f9ee --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockCheckService.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckItemDO; +import jakarta.validation.Valid; + +import java.util.Collection; +import java.util.List; + +/** + * ERP 库存盘点单 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpStockCheckService { + + /** + * 创建库存盘点单 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createStockCheck(@Valid ErpStockCheckSaveReqVO createReqVO); + + /** + * 更新库存盘点单 + * + * @param updateReqVO 更新信息 + */ + void updateStockCheck(@Valid ErpStockCheckSaveReqVO updateReqVO); + + /** + * 更新库存盘点单的状态 + * + * @param id 编号 + * @param status 状态 + */ + void updateStockCheckStatus(Long id, Integer status); + + /** + * 删除库存盘点单 + * + * @param ids 编号数组 + */ + void deleteStockCheck(List ids); + + /** + * 获得库存盘点单 + * + * @param id 编号 + * @return 库存盘点单 + */ + ErpStockCheckDO getStockCheck(Long id); + + /** + * 获得库存盘点单分页 + * + * @param pageReqVO 分页查询 + * @return 库存盘点单分页 + */ + PageResult getStockCheckPage(ErpStockCheckPageReqVO pageReqVO); + + // ==================== 盘点项 ==================== + + /** + * 获得库存盘点单项列表 + * + * @param checkId 盘点编号 + * @return 库存盘点单项列表 + */ + List getStockCheckItemListByCheckId(Long checkId); + + /** + * 获得库存盘点单项 List + * + * @param checkIds 盘点编号数组 + * @return 库存盘点单项 List + */ + List getStockCheckItemListByCheckIds(Collection checkIds); + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockCheckServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockCheckServiceImpl.java new file mode 100644 index 000000000..49aca94d3 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockCheckServiceImpl.java @@ -0,0 +1,232 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckItemDO; +import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockCheckItemMapper; +import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockCheckMapper; +import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO; +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import cn.iocoder.yudao.module.erp.enums.stock.ErpStockRecordBizTypeEnum; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockRecordCreateReqBO; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; + +// TODO 芋艿:记录操作日志 + +/** + * ERP 库存盘点单 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ErpStockCheckServiceImpl implements ErpStockCheckService { + + @Resource + private ErpStockCheckMapper stockCheckMapper; + @Resource + private ErpStockCheckItemMapper stockCheckItemMapper; + + @Resource + private ErpNoRedisDAO noRedisDAO; + + @Resource + private ErpProductService productService; + @Resource + private ErpWarehouseService warehouseService; + @Resource + private ErpStockRecordService stockRecordService; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createStockCheck(ErpStockCheckSaveReqVO createReqVO) { + // 1.1 校验盘点项的有效性 + List stockCheckItems = validateStockCheckItems(createReqVO.getItems()); + // 1.2 生成盘点单号,并校验唯一性 + String no = noRedisDAO.generate(ErpNoRedisDAO.STOCK_CHECK_NO_PREFIX); + if (stockCheckMapper.selectByNo(no) != null) { + throw exception(STOCK_CHECK_NO_EXISTS); + } + + // 2.1 插入盘点单 + ErpStockCheckDO stockCheck = BeanUtils.toBean(createReqVO, ErpStockCheckDO.class, in -> in + .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus()) + .setTotalCount(getSumValue(stockCheckItems, ErpStockCheckItemDO::getCount, BigDecimal::add)) + .setTotalPrice(getSumValue(stockCheckItems, ErpStockCheckItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO))); + stockCheckMapper.insert(stockCheck); + // 2.2 插入盘点单项 + stockCheckItems.forEach(o -> o.setCheckId(stockCheck.getId())); + stockCheckItemMapper.insertBatch(stockCheckItems); + return stockCheck.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateStockCheck(ErpStockCheckSaveReqVO updateReqVO) { + // 1.1 校验存在 + ErpStockCheckDO stockCheck = validateStockCheckExists(updateReqVO.getId()); + if (ErpAuditStatus.APPROVE.getStatus().equals(stockCheck.getStatus())) { + throw exception(STOCK_CHECK_UPDATE_FAIL_APPROVE, stockCheck.getNo()); + } + // 1.2 校验盘点项的有效性 + List stockCheckItems = validateStockCheckItems(updateReqVO.getItems()); + + // 2.1 更新盘点单 + ErpStockCheckDO updateObj = BeanUtils.toBean(updateReqVO, ErpStockCheckDO.class, in -> in + .setTotalCount(getSumValue(stockCheckItems, ErpStockCheckItemDO::getCount, BigDecimal::add)) + .setTotalPrice(getSumValue(stockCheckItems, ErpStockCheckItemDO::getTotalPrice, BigDecimal::add))); + stockCheckMapper.updateById(updateObj); + // 2.2 更新盘点单项 + updateStockCheckItemList(updateReqVO.getId(), stockCheckItems); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateStockCheckStatus(Long id, Integer status) { + boolean approve = ErpAuditStatus.APPROVE.getStatus().equals(status); + // 1.1 校验存在 + ErpStockCheckDO stockCheck = validateStockCheckExists(id); + // 1.2 校验状态 + if (stockCheck.getStatus().equals(status)) { + throw exception(approve ? STOCK_CHECK_APPROVE_FAIL : STOCK_CHECK_PROCESS_FAIL); + } + + // 2. 更新状态 + int updateCount = stockCheckMapper.updateByIdAndStatus(id, stockCheck.getStatus(), + new ErpStockCheckDO().setStatus(status)); + if (updateCount == 0) { + throw exception(approve ? STOCK_CHECK_APPROVE_FAIL : STOCK_CHECK_PROCESS_FAIL); + } + + // 3. 变更库存 + List stockCheckItems = stockCheckItemMapper.selectListByCheckId(id); + stockCheckItems.forEach(stockCheckItem -> { + // 没有盈亏,不用出入库 + if (stockCheckItem.getCount().compareTo(BigDecimal.ZERO) == 0) { + return; + } + // 10;12;-2() + BigDecimal count = approve ? stockCheckItem.getCount(): stockCheckItem.getCount().negate(); + Integer bizType; + if (approve) { + bizType = count.compareTo(BigDecimal.ZERO) > 0 ? ErpStockRecordBizTypeEnum.CHECK_MORE_IN.getType() + : ErpStockRecordBizTypeEnum.CHECK_LESS_OUT.getType(); + } else { + bizType = count.compareTo(BigDecimal.ZERO) > 0 ? ErpStockRecordBizTypeEnum.CHECK_MORE_IN_CANCEL.getType() + : ErpStockRecordBizTypeEnum.CHECK_LESS_OUT_CANCEL.getType(); + } + stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO( + stockCheckItem.getProductId(), stockCheckItem.getWarehouseId(), count, + bizType, stockCheckItem.getCheckId(), stockCheckItem.getId(), stockCheck.getNo())); + }); + } + + private List validateStockCheckItems(List list) { + // 1.1 校验产品存在 + List productList = productService.validProductList( + convertSet(list, ErpStockCheckSaveReqVO.Item::getProductId)); + Map productMap = convertMap(productList, ErpProductDO::getId); + // 1.2 校验仓库存在 + warehouseService.validWarehouseList(convertSet(list, ErpStockCheckSaveReqVO.Item::getWarehouseId)); + // 2. 转化为 ErpStockCheckItemDO 列表 + return convertList(list, o -> BeanUtils.toBean(o, ErpStockCheckItemDO.class, item -> item + .setProductUnitId(productMap.get(item.getProductId()).getUnitId()) + .setTotalPrice(MoneyUtils.priceMultiply(item.getProductPrice(), item.getCount())))); + } + + private void updateStockCheckItemList(Long id, List newList) { + // 第一步,对比新老数据,获得添加、修改、删除的列表 + List oldList = stockCheckItemMapper.selectListByCheckId(id); + List> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录 + (oldVal, newVal) -> oldVal.getId().equals(newVal.getId())); + + // 第二步,批量添加、修改、删除 + if (CollUtil.isNotEmpty(diffList.get(0))) { + diffList.get(0).forEach(o -> o.setCheckId(id)); + stockCheckItemMapper.insertBatch(diffList.get(0)); + } + if (CollUtil.isNotEmpty(diffList.get(1))) { + stockCheckItemMapper.updateBatch(diffList.get(1)); + } + if (CollUtil.isNotEmpty(diffList.get(2))) { + stockCheckItemMapper.deleteBatchIds(convertList(diffList.get(2), ErpStockCheckItemDO::getId)); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteStockCheck(List ids) { + // 1. 校验不处于已审批 + List stockChecks = stockCheckMapper.selectBatchIds(ids); + if (CollUtil.isEmpty(stockChecks)) { + return; + } + stockChecks.forEach(stockCheck -> { + if (ErpAuditStatus.APPROVE.getStatus().equals(stockCheck.getStatus())) { + throw exception(STOCK_CHECK_DELETE_FAIL_APPROVE, stockCheck.getNo()); + } + }); + + // 2. 遍历删除,并记录操作日志 + stockChecks.forEach(stockCheck -> { + // 2.1 删除盘点单 + stockCheckMapper.deleteById(stockCheck.getId()); + // 2.2 删除盘点单项 + stockCheckItemMapper.deleteByCheckId(stockCheck.getId()); + }); + } + + private ErpStockCheckDO validateStockCheckExists(Long id) { + ErpStockCheckDO stockCheck = stockCheckMapper.selectById(id); + if (stockCheck == null) { + throw exception(STOCK_CHECK_NOT_EXISTS); + } + return stockCheck; + } + + @Override + public ErpStockCheckDO getStockCheck(Long id) { + return stockCheckMapper.selectById(id); + } + + @Override + public PageResult getStockCheckPage(ErpStockCheckPageReqVO pageReqVO) { + return stockCheckMapper.selectPage(pageReqVO); + } + + // ==================== 盘点项 ==================== + + @Override + public List getStockCheckItemListByCheckId(Long checkId) { + return stockCheckItemMapper.selectListByCheckId(checkId); + } + + @Override + public List getStockCheckItemListByCheckIds(Collection checkIds) { + if (CollUtil.isEmpty(checkIds)) { + return Collections.emptyList(); + } + return stockCheckItemMapper.selectListByCheckIds(checkIds); + } + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java index 22b08b266..213fca8b8 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java @@ -138,10 +138,12 @@ public class ErpStockInServiceImpl implements ErpStockInService { private List validateStockInItems(List list) { // 1.1 校验产品存在 - List productList = productService.validProductList(convertSet(list, ErpStockInSaveReqVO.Item::getProductId)); + List productList = productService.validProductList( + convertSet(list, ErpStockInSaveReqVO.Item::getProductId)); Map productMap = convertMap(productList, ErpProductDO::getId); // 1.2 校验仓库存在 - warehouseService.validWarehouseList(convertSet(list, ErpStockInSaveReqVO.Item::getWarehouseId)); + warehouseService.validWarehouseList(convertSet( + list, ErpStockInSaveReqVO.Item::getWarehouseId)); // 2. 转化为 ErpStockInItemDO 列表 return convertList(list, o -> BeanUtils.toBean(o, ErpStockInItemDO.class, item -> item .setProductUnitId(productMap.get(item.getProductId()).getUnitId()) diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveServiceImpl.java index 089c98e72..a0d8f79d4 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveServiceImpl.java @@ -214,16 +214,16 @@ public class ErpStockMoveServiceImpl implements ErpStockMoveService { // ==================== 出库项 ==================== @Override - public List getStockMoveItemListByMoveId(Long inId) { - return stockMoveItemMapper.selectListByMoveId(inId); + public List getStockMoveItemListByMoveId(Long moveId) { + return stockMoveItemMapper.selectListByMoveId(moveId); } @Override - public List getStockMoveItemListByMoveIds(Collection inIds) { - if (CollUtil.isEmpty(inIds)) { + public List getStockMoveItemListByMoveIds(Collection moveIds) { + if (CollUtil.isEmpty(moveIds)) { return Collections.emptyList(); } - return stockMoveItemMapper.selectListByMoveIds(inIds); + return stockMoveItemMapper.selectListByMoveIds(moveIds); } } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java index 8117ef36a..9fa192465 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java @@ -139,7 +139,8 @@ public class ErpStockOutServiceImpl implements ErpStockOutService { private List validateStockOutItems(List list) { // 1.1 校验产品存在 - List productList = productService.validProductList(convertSet(list, ErpStockOutSaveReqVO.Item::getProductId)); + List productList = productService.validProductList( + convertSet(list, ErpStockOutSaveReqVO.Item::getProductId)); Map productMap = convertMap(productList, ErpProductDO::getId); // 1.2 校验仓库存在 warehouseService.validWarehouseList(convertSet(list, ErpStockOutSaveReqVO.Item::getWarehouseId)); @@ -212,16 +213,16 @@ public class ErpStockOutServiceImpl implements ErpStockOutService { // ==================== 出库项 ==================== @Override - public List getStockOutItemListByOutId(Long inId) { - return stockOutItemMapper.selectListByOutId(inId); + public List getStockOutItemListByOutId(Long outId) { + return stockOutItemMapper.selectListByOutId(outId); } @Override - public List getStockOutItemListByOutIds(Collection inIds) { - if (CollUtil.isEmpty(inIds)) { + public List getStockOutItemListByOutIds(Collection outIds) { + if (CollUtil.isEmpty(outIds)) { return Collections.emptyList(); } - return stockOutItemMapper.selectListByOutIds(inIds); + return stockOutItemMapper.selectListByOutIds(outIds); } } \ No newline at end of file