From 30de2176a4d547bc754943e40efaa27609146188 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 9 Feb 2024 20:03:02 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20ERP=EF=BC=9A=E5=A2=9E=E5=8A=A0=20ER?= =?UTF-8?q?P=20=E9=94=80=E5=94=AE=E8=AE=A2=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 --- .../enums/sale/ErpSaleOrderStatusEnum.java | 40 ---- .../admin/sale/ErpSaleOrderController.java | 121 +++++++++--- .../sale/vo/order/ErpSaleOrderPageReqVO.java | 21 +- .../sale/vo/order/ErpSaleOrderRespVO.java | 114 +++++++---- .../sale/vo/order/ErpSaleOrderSaveReqVO.java | 91 +++------ .../dal/dataobject/sale/ErpSaleOrderDO.java | 54 ++++-- ...derItemDO.java => ErpSaleOrderItemDO.java} | 60 +++--- .../mysql/sale/ErpSaleOrderItemMapper.java | 30 +++ .../dal/mysql/sale/ErpSaleOrderMapper.java | 27 ++- .../mysql/sale/ErpSalesOrderItemMapper.java | 25 --- .../erp/dal/mysql/stock/ErpStockMapper.java | 19 +- .../erp/service/sale/ErpSaleOrderService.java | 46 ++++- .../service/sale/ErpSaleOrderServiceImpl.java | 183 ++++++++++++++---- .../erp/service/stock/ErpStockService.java | 8 + .../service/stock/ErpStockServiceImpl.java | 5 + 15 files changed, 551 insertions(+), 293 deletions(-) delete mode 100644 yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/sale/ErpSaleOrderStatusEnum.java rename yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/{ErpSalesOrderItemDO.java => ErpSaleOrderItemDO.java} (54%) create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleOrderItemMapper.java delete mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSalesOrderItemMapper.java diff --git a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/sale/ErpSaleOrderStatusEnum.java b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/sale/ErpSaleOrderStatusEnum.java deleted file mode 100644 index 4caa7f515..000000000 --- a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/sale/ErpSaleOrderStatusEnum.java +++ /dev/null @@ -1,40 +0,0 @@ -package cn.iocoder.yudao.module.erp.enums.sale; - -import cn.iocoder.yudao.framework.common.core.IntArrayValuable; -import lombok.AllArgsConstructor; -import lombok.Getter; - -import java.util.Arrays; - -/** - * ERP 销售订单的状态枚举 - * - * @author 芋道源码 - */ -@AllArgsConstructor -@Getter -public enum ErpSaleOrderStatusEnum implements IntArrayValuable { - - AUDIT_NONE(0, "未审核"), - AUDIT_PASS(10, "已审核"), - SALE_PART(20, "部分销售"), - SALE_ALL(21, "完成销售"), - ; - - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ErpSaleOrderStatusEnum::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-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java index ba1345166..2971ff5fc 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java @@ -1,16 +1,26 @@ package cn.iocoder.yudao.module.erp.controller.admin.sale; +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.sale.vo.order.ErpSaleOrderPageReqVO; import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderRespVO; import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpCustomerDO; import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderItemDO; +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.sale.ErpSaleOrderService; +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; @@ -22,9 +32,13 @@ 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; @@ -36,65 +50,116 @@ public class ErpSaleOrderController { @Resource private ErpSaleOrderService saleOrderService; + @Resource + private ErpStockService stockService; + @Resource + private ErpProductService productService; + @Resource + private ErpCustomerService customerService; + + @Resource + private AdminUserApi adminUserApi; - // TODO 芋艿:待 review @PostMapping("/create") - @Operation(summary = "创建ERP 销售订单") - @PreAuthorize("@ss.hasPermission('erp:sale-order:create')") + @Operation(summary = "创建销售订单") + @PreAuthorize("@ss.hasPermission('erp:stock-out:create')") public CommonResult createSaleOrder(@Valid @RequestBody ErpSaleOrderSaveReqVO createReqVO) { return success(saleOrderService.createSaleOrder(createReqVO)); } - // TODO 芋艿:待 review @PutMapping("/update") - @Operation(summary = "更新ERP 销售订单") - @PreAuthorize("@ss.hasPermission('erp:sale-order:update')") + @Operation(summary = "更新销售订单") + @PreAuthorize("@ss.hasPermission('erp:stock-out:update')") public CommonResult updateSaleOrder(@Valid @RequestBody ErpSaleOrderSaveReqVO updateReqVO) { saleOrderService.updateSaleOrder(updateReqVO); return success(true); } - // TODO 芋艿:待 review - @DeleteMapping("/delete") - @Operation(summary = "删除ERP 销售订单") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('erp:sale-order:delete')") - public CommonResult deleteSaleOrder(@RequestParam("id") Long id) { - saleOrderService.deleteSaleOrder(id); + @PutMapping("/update-status") + @Operation(summary = "更新销售订单的状态") + @PreAuthorize("@ss.hasPermission('erp:stock-out:update-status')") + public CommonResult updateSaleOrderStatus(@RequestParam("id") Long id, + @RequestParam("status") Integer status) { + saleOrderService.updateSaleOrderStatus(id, status); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除销售订单") + @Parameter(name = "ids", description = "编号数组", required = true) + @PreAuthorize("@ss.hasPermission('erp:stock-out:delete')") + public CommonResult deleteSaleOrder(@RequestParam("ids") List ids) { + saleOrderService.deleteSaleOrder(ids); return success(true); } - // TODO 芋艿:待 review @GetMapping("/get") - @Operation(summary = "获得ERP 销售订单") + @Operation(summary = "获得销售订单") @Parameter(name = "id", description = "编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('erp:sale-order:query')") + @PreAuthorize("@ss.hasPermission('erp:stock-out:query')") public CommonResult getSaleOrder(@RequestParam("id") Long id) { ErpSaleOrderDO saleOrder = saleOrderService.getSaleOrder(id); - return success(BeanUtils.toBean(saleOrder, ErpSaleOrderRespVO.class)); + if (saleOrder == null) { + return success(null); + } + List saleOrderItemList = saleOrderService.getSaleOrderItemListByOrderId(id); + Map productMap = productService.getProductVOMap( + convertSet(saleOrderItemList, ErpSaleOrderItemDO::getProductId)); + return success(BeanUtils.toBean(saleOrder, ErpSaleOrderRespVO.class, saleOrderVO -> + saleOrderVO.setItems(BeanUtils.toBean(saleOrderItemList, ErpSaleOrderRespVO.Item.class, item -> { + BigDecimal stockCount = stockService.getStockCount(item.getProductId()); + item.setStockCount(stockCount != null ? stockCount : BigDecimal.ZERO); + MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())); + })))); } - // TODO 芋艿:待 review @GetMapping("/page") - @Operation(summary = "获得ERP 销售订单分页") - @PreAuthorize("@ss.hasPermission('erp:sale-order:query')") + @Operation(summary = "获得销售订单分页") + @PreAuthorize("@ss.hasPermission('erp:stock-out:query')") public CommonResult> getSaleOrderPage(@Valid ErpSaleOrderPageReqVO pageReqVO) { PageResult pageResult = saleOrderService.getSaleOrderPage(pageReqVO); - return success(BeanUtils.toBean(pageResult, ErpSaleOrderRespVO.class)); + return success(buildSaleOrderVOPageResult(pageResult)); } - // TODO 芋艿:待 review @GetMapping("/export-excel") - @Operation(summary = "导出ERP 销售订单 Excel") - @PreAuthorize("@ss.hasPermission('erp:sale-order:export')") + @Operation(summary = "导出销售订单 Excel") + @PreAuthorize("@ss.hasPermission('erp:stock-out:export')") @OperateLog(type = EXPORT) public void exportSaleOrderExcel(@Valid ErpSaleOrderPageReqVO pageReqVO, - HttpServletResponse response) throws IOException { + HttpServletResponse response) throws IOException { pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); - List list = saleOrderService.getSaleOrderPage(pageReqVO).getList(); + List list = buildSaleOrderVOPageResult(saleOrderService.getSaleOrderPage(pageReqVO)).getList(); // 导出 Excel - ExcelUtils.write(response, "ERP 销售订单.xls", "数据", ErpSaleOrderRespVO.class, - BeanUtils.toBean(list, ErpSaleOrderRespVO.class)); + ExcelUtils.write(response, "销售订单.xls", "数据", ErpSaleOrderRespVO.class, list); + } + + private PageResult buildSaleOrderVOPageResult(PageResult pageResult) { + if (CollUtil.isEmpty(pageResult.getList())) { + return PageResult.empty(pageResult.getTotal()); + } + // 1.1 出库项 + List saleOrderItemList = saleOrderService.getSaleOrderItemListByOrderIds( + convertSet(pageResult.getList(), ErpSaleOrderDO::getId)); + Map> saleOrderItemMap = convertMultiMap(saleOrderItemList, ErpSaleOrderItemDO::getOrderId); + // 1.2 商品信息 + Map productMap = productService.getProductVOMap( + convertSet(saleOrderItemList, ErpSaleOrderItemDO::getProductId)); + // 1.3 客户信息 + Map customerMap = customerService.getCustomerMap( + convertSet(pageResult.getList(), ErpSaleOrderDO::getCustomerId)); + // 1.4 管理员信息 + Map userMap = adminUserApi.getUserMap( + convertSet(pageResult.getList(), erpStockRecordDO -> Long.parseLong(erpStockRecordDO.getCreator()))); + // 2. 开始拼接 + return BeanUtils.toBean(pageResult, ErpSaleOrderRespVO.class, saleOrder -> { + saleOrder.setItems(BeanUtils.toBean(saleOrderItemMap.get(saleOrder.getId()), ErpSaleOrderRespVO.Item.class, + item -> MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())))); + saleOrder.setProductNames(CollUtil.join(saleOrder.getItems(), ",", ErpSaleOrderRespVO.Item::getProductName)); + MapUtils.findAndThen(customerMap, saleOrder.getCustomerId(), supplier -> saleOrder.setCustomerName(supplier.getName())); + MapUtils.findAndThen(userMap, Long.parseLong(saleOrder.getCreator()), user -> saleOrder.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/sale/vo/order/ErpSaleOrderPageReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderPageReqVO.java index 8e46a64b0..c5d748f22 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderPageReqVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderPageReqVO.java @@ -17,6 +17,19 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ @ToString(callSuper = true) public class ErpSaleOrderPageReqVO extends PageParam { + /** + * 入库状态 - 无 + */ + public static final Integer IN_STATUS_NONE = 0; + /** + * 入库状态 - 部分 + */ + public static final Integer IN_STATUS_PART = 1; + /** + * 入库状态 - 全部 + */ + public static final Integer IN_STATUS_ALL = 2; + @Schema(description = "销售单编号", example = "XS001") private String no; @@ -28,7 +41,7 @@ public class ErpSaleOrderPageReqVO extends PageParam { private LocalDateTime[] orderTime; @Schema(description = "备注", example = "你猜") - private String description; + private String remark; @Schema(description = "销售状态", example = "2") private Integer status; @@ -36,4 +49,10 @@ public class ErpSaleOrderPageReqVO extends PageParam { @Schema(description = "创建者") private String creator; + @Schema(description = "产品编号", example = "1") + private Long productId; + + @Schema(description = "入库状态", example = "2") + private Integer inStatus; + } \ 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/order/ErpSaleOrderRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderRespVO.java index ea24e08ca..8fd879621 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderRespVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderRespVO.java @@ -3,12 +3,13 @@ package cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order; 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; -// TODO 芋艿:导出最后搞 @Schema(description = "管理后台 - ERP 销售订单 Response VO") @Data @ExcelIgnoreUnannotated @@ -23,56 +24,103 @@ public class ErpSaleOrderRespVO { private String no; @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1724") - @ExcelProperty("客户编号") private Long customerId; + @Schema(description = "客户名称", example = "芋道") + @ExcelProperty("客户名称") + private String customerName; @Schema(description = "下单时间", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("下单时间") private LocalDateTime orderTime; - // TODO 芋艿:example 后面 - @Schema(description = "销售员编号数组") - @ExcelProperty("销售员编号数组") - private String salePersonIds; - - @Schema(description = "合计价格,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "26094") - @ExcelProperty("合计价格,单位:元") - private BigDecimal totalPrice; - - @Schema(description = "优惠率,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "99.88") - @ExcelProperty("优惠率,百分比") - private BigDecimal discountPercent; - - @Schema(description = "优惠金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "44.52") - @ExcelProperty("优惠金额,单位:元") - private BigDecimal discountPrice; - - @Schema(description = "支付金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "322.40") - @ExcelProperty("支付金额,单位:元") - private BigDecimal payPrice; - - @Schema(description = "定金金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "71.27") - @ExcelProperty("定金金额,单位:元") - private BigDecimal depositPrice; - - @Schema(description = "附件地址", example = "https://www.iocoder.cn") - @ExcelProperty("附件地址") - private String fileUrl; + @Schema(description = "销售员编号", example = "1888") + private Long saleUserId; @Schema(description = "结算账户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "311.89") @ExcelProperty("结算账户编号") private Long accountId; - @Schema(description = "备注", example = "你猜") - @ExcelProperty("备注") - private String description; + @Schema(description = "合计产品价格,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal totalProductPrice; + + @Schema(description = "合计税额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal totalTaxPrice; + + @Schema(description = "优惠率,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "99.88") + private BigDecimal discountPercent; + + @Schema(description = "优惠金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal discountPrice; + + @Schema(description = "定金金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + @NotNull(message = "定金金额,单位:元不能为空") + private BigDecimal depositPrice; @Schema(description = "销售状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") @ExcelProperty("销售状态") private Integer status; + @Schema(description = "附件地址", example = "https://www.iocoder.cn") + @ExcelProperty("附件地址") + private String fileUrl; + + @Schema(description = "备注", example = "你猜") + @ExcelProperty("备注") + private String remark; + + @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 productId; + + @Schema(description = "产品单位单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long productUnitId; + + @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 = "99.88") + private BigDecimal taxPercent; + + @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/sale/vo/order/ErpSaleOrderSaveReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderSaveReqVO.java index e40b38902..1706915aa 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderSaveReqVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderSaveReqVO.java @@ -28,26 +28,16 @@ public class ErpSaleOrderSaveReqVO { @NotNull(message = "下单时间不能为空") private LocalDateTime orderTime; - @Schema(description = "销售员编号数组") - private List salePersonIds; + @Schema(description = "销售员编号", example = "1888") + private Long saleUserId; - @Schema(description = "合计价格,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "26094") - @NotNull(message = "合计价格,单位:元不能为空") - private BigDecimal totalPrice; + @Schema(description = "结算账户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31189") + @NotNull(message = "结算账户编号不能为空") + private Long accountId; @Schema(description = "优惠率,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "99.88") - @NotNull(message = "优惠率,百分比不能为空") private BigDecimal discountPercent; - @Schema(description = "优惠金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "4452") - @NotNull(message = "优惠金额,单位:元不能为空") - private BigDecimal discountPrice; - - // TODO 芋艿:后面删除 -// @Schema(description = "支付金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "32240") -// @NotNull(message = "支付金额,单位:元不能为空") -// private BigDecimal payPrice; - @Schema(description = "定金金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") @NotNull(message = "定金金额,单位:元不能为空") private BigDecimal depositPrice; @@ -55,73 +45,38 @@ public class ErpSaleOrderSaveReqVO { @Schema(description = "附件地址", example = "https://www.iocoder.cn") private String fileUrl; - @Schema(description = "结算账户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31189") - @NotNull(message = "结算账户编号不能为空") - private Long accountId; - @Schema(description = "备注", example = "你猜") - private String description; + private String remark; - // TODO 芋艿:后面删除 -// @Schema(description = "销售状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") -// @NotNull(message = "销售状态不能为空") -// private Integer status; + @Schema(description = "订单清单列表") + private List items; - @Schema(description = "ERP 销售订单明细列表") - private List salesOrderItems; - - @Schema(description = "管理后台 - ERP 销售订单明细新增/修改 Request VO") @Data - public class Item { + public static class Item { - @Schema(description = "编号", example = "20704") + @Schema(description = "订单项编号", example = "11756") private Long id; - // TODO 芋艿:后面删除 -// @Schema(description = "销售订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "30765") -// @NotNull(message = "销售订单编号不能为空") -// private Long orderId; + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "产品编号不能为空") + private Long productId; -// @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "5574") -// @NotNull(message = "商品 SPU 编号不能为空") -// private Long productSpuId; + @Schema(description = "产品单位单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "产品单位单位不能为空") + private Long productUnitId; - @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "21273") - @NotNull(message = "商品 SKU 编号不能为空") - private Long productSkuId; - - @Schema(description = "商品单位", requiredMode = Schema.RequiredMode.REQUIRED) - @NotEmpty(message = "商品单位不能为空") - private String productUnit; - - @Schema(description = "商品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "6897") - @NotNull(message = "商品单价不能为空") + @Schema(description = "产品单价", example = "100.00") private BigDecimal productPrice; - @Schema(description = "数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "22100") - @NotNull(message = "数量不能为空") - private Integer count; + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "产品数量不能为空") + private BigDecimal count; - // TODO 芋艿:后面删除 -// @Schema(description = "总价", requiredMode = Schema.RequiredMode.REQUIRED, example = "26868") -// @NotNull(message = "总价不能为空") -// private BigDecimal totalPrice; - - @Schema(description = "备注", example = "你说的对") - private String description; - - @Schema(description = "税率,百分比", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "税率,百分比不能为空") + @Schema(description = "税率,百分比", example = "99.88") private BigDecimal taxPercent; - @Schema(description = "税额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "15791") - @NotNull(message = "税额,单位:元不能为空") - private BigDecimal taxPrice; - - // TODO 芋艿:后面删除 -// @Schema(description = "支付金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "21930") -// @NotNull(message = "支付金额,单位:元不能为空") -// private BigDecimal payPrice; + @Schema(description = "备注", example = "随便") + private String remark; } diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOrderDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOrderDO.java index 749eabd49..8bbbcdefb 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOrderDO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOrderDO.java @@ -1,24 +1,20 @@ package cn.iocoder.yudao.module.erp.dal.dataobject.sale; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; -import cn.iocoder.yudao.module.erp.enums.sale.ErpSaleOrderStatusEnum; import com.baomidou.mybatisplus.annotation.KeySequence; -import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; import java.math.BigDecimal; import java.time.LocalDateTime; -import java.util.List; /** * ERP 销售订单 DO * * @author 芋道源码 */ -@TableName(value = "erp_sale_order", autoResultMap = true) +@TableName(value = "erp_sale_order") @KeySequence("erp_sale_order_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @EqualsAndHashCode(callSuper = true) @@ -40,13 +36,13 @@ public class ErpSaleOrderDO extends BaseDO { /** * 销售状态 * - * 枚举 {@link ErpSaleOrderStatusEnum} + * 枚举 {@link cn.iocoder.yudao.module.erp.enums.ErpAuditStatus} */ private Integer status; /** * 客户编号 * - * TODO 芋艿:关联 + * 关联 {@link ErpCustomerDO#getId()} */ private Long customerId; /** @@ -56,33 +52,45 @@ public class ErpSaleOrderDO extends BaseDO { */ private Long accountId; /** - * 销售员编号数组 + * 销售员编号 * - * TODO 芋艿:关联 + * 关联 AdminUserDO 的 id 字段 */ - @TableField(typeHandler = LongListTypeHandler.class) - private List salePersonIds; + private Long saleUserId; /** * 下单时间 */ private LocalDateTime orderTime; /** - * 合计价格,单位:元 + * 合计数量 + */ + private BigDecimal totalCount; + /** + * 最终合计价格,单位:元 + * + * totalPrice = totalProductPrice + totalTaxPrice - discountPrice */ private BigDecimal totalPrice; + + /** + * 合计产品价格,单位:元 + */ + private BigDecimal totalProductPrice; + /** + * 合计税额,单位:元 + */ + private BigDecimal totalTaxPrice; /** * 优惠率,百分比 */ private BigDecimal discountPercent; /** * 优惠金额,单位:元 + * + * discountPrice = (totalProductPrice + totalTaxPrice) * discountPercent */ private BigDecimal discountPrice; - /** - * 支付金额,单位:元 - */ - private BigDecimal payPrice; /** * 定金金额,单位:元 */ @@ -95,6 +103,18 @@ public class ErpSaleOrderDO extends BaseDO { /** * 备注 */ - private String description; + private String remark; + + // ========== 销售入库 ========== + /** + * 销售入库数量 + */ + private BigDecimal inCount; + + // ========== 销售退货(出库)) ========== + /** + * 销售退货数量 + */ + private BigDecimal returnCount; } \ 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/sale/ErpSalesOrderItemDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOrderItemDO.java similarity index 54% rename from yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSalesOrderItemDO.java rename to yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOrderItemDO.java index 7e1b25f8d..d25a5471c 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSalesOrderItemDO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOrderItemDO.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.erp.dal.dataobject.sale; 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; @@ -13,15 +14,15 @@ import java.math.BigDecimal; * * @author 芋道源码 */ -@TableName("erp_sales_order_items") -@KeySequence("erp_sales_order_items_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@TableName("erp_sale_order_items") +@KeySequence("erp_sale_order_items_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor -public class ErpSalesOrderItemDO extends BaseDO { +public class ErpSaleOrderItemDO extends BaseDO { /** * 编号 @@ -36,53 +37,58 @@ public class ErpSalesOrderItemDO extends BaseDO { private Long orderId; /** - * 商品 SPU 编号 + * 产品编号 * - * TODO 芋艿 关联 + * 关联 {@link ErpProductDO#getId()} */ - private Long productSpuId; + private Long productId; /** - * 商品 SKU 编号 + * 产品单位单位 * - * TODO 芋艿 关联 + * 冗余 {@link ErpProductDO#getUnitId()} */ - private Long productSkuId; + private Long productUnitId; + /** - * 商品单位 - * - * TODO 芋艿 冗余 - */ - private String productUnit; - /** - * 商品单价 - * - * TODO 芋艿 冗余 + * 产品单位单价,单位:元 */ private BigDecimal productPrice; - /** * 数量 */ - private Integer count; + private BigDecimal count; /** - * 总价 + * 总价,单位:元 + * + * totalPrice = productPrice * count */ private BigDecimal totalPrice; - /** - * 备注 - */ - private String description; /** * 税率,百分比 */ private BigDecimal taxPercent; /** * 税额,单位:元 + * + * taxPrice = totalPrice * taxPercent */ private BigDecimal taxPrice; + /** - * 支付金额,单位:元 + * 备注 */ - private BigDecimal payPrice; + private String remark; + + // ========== 销售入库 ========== + /** + * 销售入库数量 + */ + private BigDecimal inCount; + + // ========== 销售退货(出库)) ========== + /** + * 销售退货数量 + */ + private BigDecimal returnCount; } \ 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/sale/ErpSaleOrderItemMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleOrderItemMapper.java new file mode 100644 index 000000000..fd3f82f0b --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleOrderItemMapper.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.sale; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderItemDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +/** + * ERP 销售订单明细 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpSaleOrderItemMapper extends BaseMapperX { + + default List selectListByOrderId(Long orderId) { + return selectList(ErpSaleOrderItemDO::getOrderId, orderId); + } + + default List selectListByOrderIds(Collection orderIds) { + return selectList(ErpSaleOrderItemDO::getOrderId, orderIds); + } + + default int deleteByOrderId(Long orderId) { + return delete(ErpSaleOrderItemDO::getOrderId, orderId); + } + +} \ 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/sale/ErpSaleOrderMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleOrderMapper.java index 07c80c480..d39c1ee4d 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleOrderMapper.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleOrderMapper.java @@ -3,9 +3,11 @@ 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.framework.mybatis.core.query.MPJLambdaWrapperX; import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderPageReqVO; import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutItemDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; /** @@ -17,14 +19,29 @@ import org.apache.ibatis.annotations.Mapper; public interface ErpSaleOrderMapper extends BaseMapperX { default PageResult selectPage(ErpSaleOrderPageReqVO reqVO) { - return selectPage(reqVO, new LambdaQueryWrapperX() - .likeIfPresent(ErpSaleOrderDO::getNo, reqVO.getNo()) + MPJLambdaWrapperX query = new MPJLambdaWrapperX() + .eqIfPresent(ErpSaleOrderDO::getNo, reqVO.getNo()) .eqIfPresent(ErpSaleOrderDO::getCustomerId, reqVO.getCustomerId()) .betweenIfPresent(ErpSaleOrderDO::getOrderTime, reqVO.getOrderTime()) - .eqIfPresent(ErpSaleOrderDO::getDescription, reqVO.getDescription()) .eqIfPresent(ErpSaleOrderDO::getStatus, reqVO.getStatus()) + .likeIfPresent(ErpSaleOrderDO::getRemark, reqVO.getRemark()) .eqIfPresent(ErpSaleOrderDO::getCreator, reqVO.getCreator()) - .orderByDesc(ErpSaleOrderDO::getId)); + .orderByDesc(ErpSaleOrderDO::getId); + if (reqVO.getProductId() != null) { + query.leftJoin(ErpStockOutItemDO.class, ErpStockOutItemDO::getOutId, ErpSaleOrderDO::getId) + .eq(reqVO.getProductId() != null, ErpStockOutItemDO::getProductId, reqVO.getProductId()) + .groupBy(ErpSaleOrderDO::getId); // 避免 1 对多查询,产生相同的 1 + } + return selectJoinPage(reqVO, ErpSaleOrderDO.class, query); + } + + default int updateByIdAndStatus(Long id, Integer status, ErpSaleOrderDO updateObj) { + return update(updateObj, new LambdaUpdateWrapper() + .eq(ErpSaleOrderDO::getId, id).eq(ErpSaleOrderDO::getStatus, status)); + } + + default ErpSaleOrderDO selectByNo(String no) { + return selectOne(ErpSaleOrderDO::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/mysql/sale/ErpSalesOrderItemMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSalesOrderItemMapper.java deleted file mode 100644 index eb8628291..000000000 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSalesOrderItemMapper.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.iocoder.yudao.module.erp.dal.mysql.sale; - -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSalesOrderItemDO; -import org.apache.ibatis.annotations.Mapper; - -import java.util.List; - -/** - * ERP 销售订单明细 Mapper - * - * @author 芋道源码 - */ -@Mapper -public interface ErpSalesOrderItemMapper extends BaseMapperX { - - default List selectListById(Long id) { - return selectList(ErpSalesOrderItemDO::getId, id); - } - - default int deleteById(Long id) { - return delete(ErpSalesOrderItemDO::getId, id); - } - -} \ 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 35fd85248..0ebc98597 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 @@ -1,14 +1,19 @@ package cn.iocoder.yudao.module.erp.dal.mysql.stock; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; 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 com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; import java.math.BigDecimal; +import java.util.List; +import java.util.Map; /** * ERP 产品库存 Mapper @@ -37,11 +42,23 @@ public interface ErpStockMapper extends BaseMapperX { updateWrapper.setSql("count = count + " + count); } else if (count.compareTo(BigDecimal.ZERO) < 0) { if (!negativeEnable) { - updateWrapper.gt(ErpStockDO::getCount, count.abs()); + updateWrapper.ge(ErpStockDO::getCount, count.abs()); } updateWrapper.setSql("count = count - " + count.abs()); } return update(null, updateWrapper); } + default BigDecimal selectSumByProductId(Long productId) { + // SQL sum 查询 + List> result = selectMaps(new QueryWrapper() + .select("SUM(count) AS sumCount") + .eq("product_id", productId)); + // 获得数量 + if (CollUtil.isEmpty(result)) { + return BigDecimal.ZERO; + } + return BigDecimal.valueOf(MapUtil.getDouble(result.get(0), "sumCount", 0D)); + } + } \ 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/ErpSaleOrderService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderService.java index 6554f2c18..cd32f62c4 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderService.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderService.java @@ -4,8 +4,12 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderPageReqVO; import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderSaveReqVO; import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderItemDO; import jakarta.validation.Valid; +import java.util.Collection; +import java.util.List; + /** * ERP 销售订单 Service 接口 * @@ -14,7 +18,7 @@ import jakarta.validation.Valid; public interface ErpSaleOrderService { /** - * 创建ERP 销售订单 + * 创建销售订单 * * @param createReqVO 创建信息 * @return 编号 @@ -22,33 +26,59 @@ public interface ErpSaleOrderService { Long createSaleOrder(@Valid ErpSaleOrderSaveReqVO createReqVO); /** - * 更新ERP 销售订单 + * 更新销售订单 * * @param updateReqVO 更新信息 */ void updateSaleOrder(@Valid ErpSaleOrderSaveReqVO updateReqVO); /** - * 删除ERP 销售订单 + * 更新销售订单的状态 * * @param id 编号 + * @param status 状态 */ - void deleteSaleOrder(Long id); + void updateSaleOrderStatus(Long id, Integer status); /** - * 获得ERP 销售订单 + * 删除销售订单 + * + * @param ids 编号数组 + */ + void deleteSaleOrder(List ids); + + /** + * 获得销售订单 * * @param id 编号 - * @return ERP 销售订单 + * @return 销售订单 */ ErpSaleOrderDO getSaleOrder(Long id); /** - * 获得ERP 销售订单分页 + * 获得销售订单分页 * * @param pageReqVO 分页查询 - * @return ERP 销售订单分页 + * @return 销售订单分页 */ PageResult getSaleOrderPage(ErpSaleOrderPageReqVO pageReqVO); + // ==================== 销售订单项 ==================== + + /** + * 获得销售订单项列表 + * + * @param orderId 销售订单编号 + * @return 销售订单项列表 + */ + List getSaleOrderItemListByOrderId(Long orderId); + + /** + * 获得销售订单项 List + * + * @param orderIds 销售订单编号数组 + * @return 销售订单项 List + */ + List getSaleOrderItemListByOrderIds(Collection orderIds); + } \ 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/ErpSaleOrderServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderServiceImpl.java index 429633f23..3e5d7d11b 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderServiceImpl.java @@ -1,23 +1,36 @@ package cn.iocoder.yudao.module.erp.service.sale; +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.sale.vo.order.ErpSaleOrderPageReqVO; import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderDO; -import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSalesOrderItemDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderItemDO; +import cn.iocoder.yudao.module.erp.dal.mysql.sale.ErpSaleOrderItemMapper; import cn.iocoder.yudao.module.erp.dal.mysql.sale.ErpSaleOrderMapper; -import cn.iocoder.yudao.module.erp.dal.mysql.sale.ErpSalesOrderItemMapper; +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 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 实现类 * @@ -30,61 +43,142 @@ public class ErpSaleOrderServiceImpl implements ErpSaleOrderService { @Resource private ErpSaleOrderMapper saleOrderMapper; @Resource - private ErpSalesOrderItemMapper salesOrderItemMapper; + private ErpSaleOrderItemMapper saleOrderItemMapper; + + @Resource + private ErpNoRedisDAO noRedisDAO; + + @Resource + private ErpProductService productService; + @Resource + private ErpCustomerService customerService; @Override @Transactional(rollbackFor = Exception.class) public Long createSaleOrder(ErpSaleOrderSaveReqVO createReqVO) { - // 插入 - ErpSaleOrderDO saleOrder = BeanUtils.toBean(createReqVO, ErpSaleOrderDO.class); + // 1.1 校验订单项的有效性 + List saleOrderItems = validateSaleOrderItems(createReqVO.getItems()); + // 1.2 校验客户 + customerService.validateCustomer(createReqVO.getCustomerId()); + // 1.3 生成调拨单号,并校验唯一性 + String no = noRedisDAO.generate(ErpNoRedisDAO.STOCK_MOVE_NO_PREFIX); + if (saleOrderMapper.selectByNo(no) != null) { + throw exception(STOCK_MOVE_NO_EXISTS); + } + + // 2.1 插入订单 + ErpSaleOrderDO saleOrder = BeanUtils.toBean(createReqVO, ErpSaleOrderDO.class, in -> in + .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus()) + .setTotalCount(getSumValue(saleOrderItems, ErpSaleOrderItemDO::getCount, BigDecimal::add)) + .setTotalPrice(getSumValue(saleOrderItems, ErpSaleOrderItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO))); saleOrderMapper.insert(saleOrder); - - // 插入子表 -// createSalesOrderItemsList(saleOrder.getId(), createReqVO.getSalesOrderItems()); - // 返回 + // 2.2 插入订单项 + saleOrderItems.forEach(o -> o.setOrderId(saleOrder.getId())); + saleOrderItemMapper.insertBatch(saleOrderItems); return saleOrder.getId(); } - private void createSalesOrderItemsList(Long id, List list) { - list.forEach(o -> o.setId(id)); - salesOrderItemMapper.insertBatch(list); - } - @Override @Transactional(rollbackFor = Exception.class) public void updateSaleOrder(ErpSaleOrderSaveReqVO updateReqVO) { - // 校验存在 - validateSaleOrderExists(updateReqVO.getId()); - // 更新 - ErpSaleOrderDO updateObj = BeanUtils.toBean(updateReqVO, ErpSaleOrderDO.class); + // 1.1 校验存在 + ErpSaleOrderDO saleOrder = validateSaleOrderExists(updateReqVO.getId()); + if (ErpAuditStatus.APPROVE.getStatus().equals(saleOrder.getStatus())) { + throw exception(STOCK_MOVE_UPDATE_FAIL_APPROVE, saleOrder.getNo()); + } + // 1.2 校验客户 + customerService.validateCustomer(updateReqVO.getCustomerId()); + // 1.3 校验订单项的有效性 + List saleOrderItems = validateSaleOrderItems(updateReqVO.getItems()); + + // 2.1 更新订单 + ErpSaleOrderDO updateObj = BeanUtils.toBean(updateReqVO, ErpSaleOrderDO.class, in -> in + .setTotalCount(getSumValue(saleOrderItems, ErpSaleOrderItemDO::getCount, BigDecimal::add)) + .setTotalPrice(getSumValue(saleOrderItems, ErpSaleOrderItemDO::getTotalPrice, BigDecimal::add))); saleOrderMapper.updateById(updateObj); - - // 更新子表 -// updateSalesOrderItemsList(updateReqVO.getId(), updateReqVO.getSalesOrderItems()); - } - - private void updateSalesOrderItemsList(Long id, List list) { - deleteSalesOrderItemsById(id); - list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下:1)id 冲突;2)updateTime 不更新 - createSalesOrderItemsList(id, list); + // 2.2 更新订单项 + updateSaleOrderItemList(updateReqVO.getId(), saleOrderItems); } @Override @Transactional(rollbackFor = Exception.class) - public void deleteSaleOrder(Long id) { - // 校验存在 - validateSaleOrderExists(id); - // 删除 - saleOrderMapper.deleteById(id); + public void updateSaleOrderStatus(Long id, Integer status) { + boolean approve = ErpAuditStatus.APPROVE.getStatus().equals(status); + // 1.1 校验存在 + ErpSaleOrderDO saleOrder = validateSaleOrderExists(id); + // 1.2 校验状态 + if (saleOrder.getStatus().equals(status)) { + throw exception(approve ? STOCK_MOVE_APPROVE_FAIL : STOCK_MOVE_PROCESS_FAIL); + } + // TODO @芋艿:需要校验是不是有入库、有退货 - // 删除子表 - deleteSalesOrderItemsById(id); + // 2. 更新状态 + int updateCount = saleOrderMapper.updateByIdAndStatus(id, saleOrder.getStatus(), + new ErpSaleOrderDO().setStatus(status)); + if (updateCount == 0) { + throw exception(approve ? STOCK_MOVE_APPROVE_FAIL : STOCK_MOVE_PROCESS_FAIL); + } } - private void validateSaleOrderExists(Long id) { - if (saleOrderMapper.selectById(id) == null) { - throw exception(SALE_ORDER_NOT_EXISTS); + private List validateSaleOrderItems(List list) { + // 1. 校验产品存在 + List productList = productService.validProductList( + convertSet(list, ErpSaleOrderSaveReqVO.Item::getProductId)); + Map productMap = convertMap(productList, ErpProductDO::getId); + // 2. 转化为 ErpSaleOrderItemDO 列表 + return convertList(list, o -> BeanUtils.toBean(o, ErpSaleOrderItemDO.class, item -> item + .setProductUnitId(productMap.get(item.getProductId()).getUnitId()) + .setTotalPrice(MoneyUtils.priceMultiply(item.getProductPrice(), item.getCount())))); + } + + private void updateSaleOrderItemList(Long id, List newList) { + // 第一步,对比新老数据,获得添加、修改、删除的列表 + List oldList = saleOrderItemMapper.selectListByOrderId(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.setOrderId(id)); + saleOrderItemMapper.insertBatch(diffList.get(0)); } + if (CollUtil.isNotEmpty(diffList.get(1))) { + saleOrderItemMapper.updateBatch(diffList.get(1)); + } + if (CollUtil.isNotEmpty(diffList.get(2))) { + saleOrderItemMapper.deleteBatchIds(convertList(diffList.get(2), ErpSaleOrderItemDO::getId)); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteSaleOrder(List ids) { + // 1. 校验不处于已审批 + List saleOrders = saleOrderMapper.selectBatchIds(ids); + if (CollUtil.isEmpty(saleOrders)) { + return; + } + saleOrders.forEach(saleOrder -> { + if (ErpAuditStatus.APPROVE.getStatus().equals(saleOrder.getStatus())) { + throw exception(STOCK_MOVE_DELETE_FAIL_APPROVE, saleOrder.getNo()); + } + }); + + // 2. 遍历删除,并记录操作日志 + saleOrders.forEach(saleOrder -> { + // 2.1 删除订单 + saleOrderMapper.deleteById(saleOrder.getId()); + // 2.2 删除订单项 + saleOrderItemMapper.deleteByOrderId(saleOrder.getId()); + }); + } + + private ErpSaleOrderDO validateSaleOrderExists(Long id) { + ErpSaleOrderDO saleOrder = saleOrderMapper.selectById(id); + if (saleOrder == null) { + throw exception(STOCK_MOVE_NOT_EXISTS); + } + return saleOrder; } @Override @@ -97,10 +191,19 @@ public class ErpSaleOrderServiceImpl implements ErpSaleOrderService { return saleOrderMapper.selectPage(pageReqVO); } - // ==================== 子表(ERP 销售订单明细) ==================== + // ==================== 订单项 ==================== - private void deleteSalesOrderItemsById(Long id) { - salesOrderItemMapper.deleteById(id); + @Override + public List getSaleOrderItemListByOrderId(Long moveId) { + return saleOrderItemMapper.selectListByOrderId(moveId); + } + + @Override + public List getSaleOrderItemListByOrderIds(Collection moveIds) { + if (CollUtil.isEmpty(moveIds)) { + return Collections.emptyList(); + } + return saleOrderItemMapper.selectListByOrderIds(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/ErpStockService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockService.java index 91224c7fa..7ca13548e 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 @@ -30,6 +30,14 @@ public interface ErpStockService { */ ErpStockDO getStock(Long productId, Long warehouseId); + /** + * 获得产品库存数量 + * + * @param productId 产品编号 + * @return 产品库存数量 + */ + BigDecimal getStockCount(Long productId); + /** * 获得产品库存分页 * 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 91495acda..432153759 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 @@ -49,6 +49,11 @@ public class ErpStockServiceImpl implements ErpStockService { return stockMapper.selectByProductIdAndWarehouseId(productId, warehouseId); } + @Override + public BigDecimal getStockCount(Long productId) { + return stockMapper.selectSumByProductId(productId); + } + @Override public PageResult getStockPage(ErpStockPageReqVO pageReqVO) { return stockMapper.selectPage(pageReqVO);