Commit 30de2176a4d547bc754943e40efaa27609146188
1 parent
94247add
✨ ERP:增加 ERP 销售订单的实现 50%
Showing
14 changed files
with
522 additions
and
264 deletions
yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/sale/ErpSaleOrderStatusEnum.java deleted
| 1 | -package cn.iocoder.yudao.module.erp.enums.sale; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.framework.common.core.IntArrayValuable; | ||
| 4 | -import lombok.AllArgsConstructor; | ||
| 5 | -import lombok.Getter; | ||
| 6 | - | ||
| 7 | -import java.util.Arrays; | ||
| 8 | - | ||
| 9 | -/** | ||
| 10 | - * ERP 销售订单的状态枚举 | ||
| 11 | - * | ||
| 12 | - * @author 芋道源码 | ||
| 13 | - */ | ||
| 14 | -@AllArgsConstructor | ||
| 15 | -@Getter | ||
| 16 | -public enum ErpSaleOrderStatusEnum implements IntArrayValuable { | ||
| 17 | - | ||
| 18 | - AUDIT_NONE(0, "未审核"), | ||
| 19 | - AUDIT_PASS(10, "已审核"), | ||
| 20 | - SALE_PART(20, "部分销售"), | ||
| 21 | - SALE_ALL(21, "完成销售"), | ||
| 22 | - ; | ||
| 23 | - | ||
| 24 | - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ErpSaleOrderStatusEnum::getStatus).toArray(); | ||
| 25 | - | ||
| 26 | - /** | ||
| 27 | - * 状态 | ||
| 28 | - */ | ||
| 29 | - private final Integer status; | ||
| 30 | - /** | ||
| 31 | - * 状态名 | ||
| 32 | - */ | ||
| 33 | - private final String name; | ||
| 34 | - | ||
| 35 | - @Override | ||
| 36 | - public int[] array() { | ||
| 37 | - return ARRAYS; | ||
| 38 | - } | ||
| 39 | - | ||
| 40 | -} |
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java
| 1 | package cn.iocoder.yudao.module.erp.controller.admin.sale; | 1 | package cn.iocoder.yudao.module.erp.controller.admin.sale; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | import cn.iocoder.yudao.framework.common.pojo.PageParam; | 5 | import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 7 | +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; | ||
| 6 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 8 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 7 | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; | 9 | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; |
| 8 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; | 10 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; |
| 11 | +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; | ||
| 9 | import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderPageReqVO; | 12 | import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderPageReqVO; |
| 10 | import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderRespVO; | 13 | import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderRespVO; |
| 11 | import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderSaveReqVO; | 14 | import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderSaveReqVO; |
| 15 | +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpCustomerDO; | ||
| 12 | import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderDO; | 16 | import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderDO; |
| 17 | +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderItemDO; | ||
| 18 | +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; | ||
| 19 | +import cn.iocoder.yudao.module.erp.service.sale.ErpCustomerService; | ||
| 13 | import cn.iocoder.yudao.module.erp.service.sale.ErpSaleOrderService; | 20 | import cn.iocoder.yudao.module.erp.service.sale.ErpSaleOrderService; |
| 21 | +import cn.iocoder.yudao.module.erp.service.stock.ErpStockService; | ||
| 22 | +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; | ||
| 23 | +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; | ||
| 14 | import io.swagger.v3.oas.annotations.Operation; | 24 | import io.swagger.v3.oas.annotations.Operation; |
| 15 | import io.swagger.v3.oas.annotations.Parameter; | 25 | import io.swagger.v3.oas.annotations.Parameter; |
| 16 | import io.swagger.v3.oas.annotations.tags.Tag; | 26 | import io.swagger.v3.oas.annotations.tags.Tag; |
| @@ -22,9 +32,13 @@ import org.springframework.validation.annotation.Validated; | @@ -22,9 +32,13 @@ import org.springframework.validation.annotation.Validated; | ||
| 22 | import org.springframework.web.bind.annotation.*; | 32 | import org.springframework.web.bind.annotation.*; |
| 23 | 33 | ||
| 24 | import java.io.IOException; | 34 | import java.io.IOException; |
| 35 | +import java.math.BigDecimal; | ||
| 25 | import java.util.List; | 36 | import java.util.List; |
| 37 | +import java.util.Map; | ||
| 26 | 38 | ||
| 27 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 39 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 40 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; | ||
| 41 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | ||
| 28 | import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; | 42 | import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; |
| 29 | 43 | ||
| 30 | 44 | ||
| @@ -36,65 +50,116 @@ public class ErpSaleOrderController { | @@ -36,65 +50,116 @@ public class ErpSaleOrderController { | ||
| 36 | 50 | ||
| 37 | @Resource | 51 | @Resource |
| 38 | private ErpSaleOrderService saleOrderService; | 52 | private ErpSaleOrderService saleOrderService; |
| 53 | + @Resource | ||
| 54 | + private ErpStockService stockService; | ||
| 55 | + @Resource | ||
| 56 | + private ErpProductService productService; | ||
| 57 | + @Resource | ||
| 58 | + private ErpCustomerService customerService; | ||
| 59 | + | ||
| 60 | + @Resource | ||
| 61 | + private AdminUserApi adminUserApi; | ||
| 39 | 62 | ||
| 40 | - // TODO 芋艿:待 review | ||
| 41 | @PostMapping("/create") | 63 | @PostMapping("/create") |
| 42 | - @Operation(summary = "创建ERP 销售订单") | ||
| 43 | - @PreAuthorize("@ss.hasPermission('erp:sale-order:create')") | 64 | + @Operation(summary = "创建销售订单") |
| 65 | + @PreAuthorize("@ss.hasPermission('erp:stock-out:create')") | ||
| 44 | public CommonResult<Long> createSaleOrder(@Valid @RequestBody ErpSaleOrderSaveReqVO createReqVO) { | 66 | public CommonResult<Long> createSaleOrder(@Valid @RequestBody ErpSaleOrderSaveReqVO createReqVO) { |
| 45 | return success(saleOrderService.createSaleOrder(createReqVO)); | 67 | return success(saleOrderService.createSaleOrder(createReqVO)); |
| 46 | } | 68 | } |
| 47 | 69 | ||
| 48 | - // TODO 芋艿:待 review | ||
| 49 | @PutMapping("/update") | 70 | @PutMapping("/update") |
| 50 | - @Operation(summary = "更新ERP 销售订单") | ||
| 51 | - @PreAuthorize("@ss.hasPermission('erp:sale-order:update')") | 71 | + @Operation(summary = "更新销售订单") |
| 72 | + @PreAuthorize("@ss.hasPermission('erp:stock-out:update')") | ||
| 52 | public CommonResult<Boolean> updateSaleOrder(@Valid @RequestBody ErpSaleOrderSaveReqVO updateReqVO) { | 73 | public CommonResult<Boolean> updateSaleOrder(@Valid @RequestBody ErpSaleOrderSaveReqVO updateReqVO) { |
| 53 | saleOrderService.updateSaleOrder(updateReqVO); | 74 | saleOrderService.updateSaleOrder(updateReqVO); |
| 54 | return success(true); | 75 | return success(true); |
| 55 | } | 76 | } |
| 56 | 77 | ||
| 57 | - // TODO 芋艿:待 review | 78 | + @PutMapping("/update-status") |
| 79 | + @Operation(summary = "更新销售订单的状态") | ||
| 80 | + @PreAuthorize("@ss.hasPermission('erp:stock-out:update-status')") | ||
| 81 | + public CommonResult<Boolean> updateSaleOrderStatus(@RequestParam("id") Long id, | ||
| 82 | + @RequestParam("status") Integer status) { | ||
| 83 | + saleOrderService.updateSaleOrderStatus(id, status); | ||
| 84 | + return success(true); | ||
| 85 | + } | ||
| 86 | + | ||
| 58 | @DeleteMapping("/delete") | 87 | @DeleteMapping("/delete") |
| 59 | - @Operation(summary = "删除ERP 销售订单") | ||
| 60 | - @Parameter(name = "id", description = "编号", required = true) | ||
| 61 | - @PreAuthorize("@ss.hasPermission('erp:sale-order:delete')") | ||
| 62 | - public CommonResult<Boolean> deleteSaleOrder(@RequestParam("id") Long id) { | ||
| 63 | - saleOrderService.deleteSaleOrder(id); | 88 | + @Operation(summary = "删除销售订单") |
| 89 | + @Parameter(name = "ids", description = "编号数组", required = true) | ||
| 90 | + @PreAuthorize("@ss.hasPermission('erp:stock-out:delete')") | ||
| 91 | + public CommonResult<Boolean> deleteSaleOrder(@RequestParam("ids") List<Long> ids) { | ||
| 92 | + saleOrderService.deleteSaleOrder(ids); | ||
| 64 | return success(true); | 93 | return success(true); |
| 65 | } | 94 | } |
| 66 | 95 | ||
| 67 | - // TODO 芋艿:待 review | ||
| 68 | @GetMapping("/get") | 96 | @GetMapping("/get") |
| 69 | - @Operation(summary = "获得ERP 销售订单") | 97 | + @Operation(summary = "获得销售订单") |
| 70 | @Parameter(name = "id", description = "编号", required = true, example = "1024") | 98 | @Parameter(name = "id", description = "编号", required = true, example = "1024") |
| 71 | - @PreAuthorize("@ss.hasPermission('erp:sale-order:query')") | 99 | + @PreAuthorize("@ss.hasPermission('erp:stock-out:query')") |
| 72 | public CommonResult<ErpSaleOrderRespVO> getSaleOrder(@RequestParam("id") Long id) { | 100 | public CommonResult<ErpSaleOrderRespVO> getSaleOrder(@RequestParam("id") Long id) { |
| 73 | ErpSaleOrderDO saleOrder = saleOrderService.getSaleOrder(id); | 101 | ErpSaleOrderDO saleOrder = saleOrderService.getSaleOrder(id); |
| 74 | - return success(BeanUtils.toBean(saleOrder, ErpSaleOrderRespVO.class)); | 102 | + if (saleOrder == null) { |
| 103 | + return success(null); | ||
| 104 | + } | ||
| 105 | + List<ErpSaleOrderItemDO> saleOrderItemList = saleOrderService.getSaleOrderItemListByOrderId(id); | ||
| 106 | + Map<Long, ErpProductRespVO> productMap = productService.getProductVOMap( | ||
| 107 | + convertSet(saleOrderItemList, ErpSaleOrderItemDO::getProductId)); | ||
| 108 | + return success(BeanUtils.toBean(saleOrder, ErpSaleOrderRespVO.class, saleOrderVO -> | ||
| 109 | + saleOrderVO.setItems(BeanUtils.toBean(saleOrderItemList, ErpSaleOrderRespVO.Item.class, item -> { | ||
| 110 | + BigDecimal stockCount = stockService.getStockCount(item.getProductId()); | ||
| 111 | + item.setStockCount(stockCount != null ? stockCount : BigDecimal.ZERO); | ||
| 112 | + MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) | ||
| 113 | + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())); | ||
| 114 | + })))); | ||
| 75 | } | 115 | } |
| 76 | 116 | ||
| 77 | - // TODO 芋艿:待 review | ||
| 78 | @GetMapping("/page") | 117 | @GetMapping("/page") |
| 79 | - @Operation(summary = "获得ERP 销售订单分页") | ||
| 80 | - @PreAuthorize("@ss.hasPermission('erp:sale-order:query')") | 118 | + @Operation(summary = "获得销售订单分页") |
| 119 | + @PreAuthorize("@ss.hasPermission('erp:stock-out:query')") | ||
| 81 | public CommonResult<PageResult<ErpSaleOrderRespVO>> getSaleOrderPage(@Valid ErpSaleOrderPageReqVO pageReqVO) { | 120 | public CommonResult<PageResult<ErpSaleOrderRespVO>> getSaleOrderPage(@Valid ErpSaleOrderPageReqVO pageReqVO) { |
| 82 | PageResult<ErpSaleOrderDO> pageResult = saleOrderService.getSaleOrderPage(pageReqVO); | 121 | PageResult<ErpSaleOrderDO> pageResult = saleOrderService.getSaleOrderPage(pageReqVO); |
| 83 | - return success(BeanUtils.toBean(pageResult, ErpSaleOrderRespVO.class)); | 122 | + return success(buildSaleOrderVOPageResult(pageResult)); |
| 84 | } | 123 | } |
| 85 | 124 | ||
| 86 | - // TODO 芋艿:待 review | ||
| 87 | @GetMapping("/export-excel") | 125 | @GetMapping("/export-excel") |
| 88 | - @Operation(summary = "导出ERP 销售订单 Excel") | ||
| 89 | - @PreAuthorize("@ss.hasPermission('erp:sale-order:export')") | 126 | + @Operation(summary = "导出销售订单 Excel") |
| 127 | + @PreAuthorize("@ss.hasPermission('erp:stock-out:export')") | ||
| 90 | @OperateLog(type = EXPORT) | 128 | @OperateLog(type = EXPORT) |
| 91 | public void exportSaleOrderExcel(@Valid ErpSaleOrderPageReqVO pageReqVO, | 129 | public void exportSaleOrderExcel(@Valid ErpSaleOrderPageReqVO pageReqVO, |
| 92 | - HttpServletResponse response) throws IOException { | 130 | + HttpServletResponse response) throws IOException { |
| 93 | pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); | 131 | pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); |
| 94 | - List<ErpSaleOrderDO> list = saleOrderService.getSaleOrderPage(pageReqVO).getList(); | 132 | + List<ErpSaleOrderRespVO> list = buildSaleOrderVOPageResult(saleOrderService.getSaleOrderPage(pageReqVO)).getList(); |
| 95 | // 导出 Excel | 133 | // 导出 Excel |
| 96 | - ExcelUtils.write(response, "ERP 销售订单.xls", "数据", ErpSaleOrderRespVO.class, | ||
| 97 | - BeanUtils.toBean(list, ErpSaleOrderRespVO.class)); | 134 | + ExcelUtils.write(response, "销售订单.xls", "数据", ErpSaleOrderRespVO.class, list); |
| 135 | + } | ||
| 136 | + | ||
| 137 | + private PageResult<ErpSaleOrderRespVO> buildSaleOrderVOPageResult(PageResult<ErpSaleOrderDO> pageResult) { | ||
| 138 | + if (CollUtil.isEmpty(pageResult.getList())) { | ||
| 139 | + return PageResult.empty(pageResult.getTotal()); | ||
| 140 | + } | ||
| 141 | + // 1.1 出库项 | ||
| 142 | + List<ErpSaleOrderItemDO> saleOrderItemList = saleOrderService.getSaleOrderItemListByOrderIds( | ||
| 143 | + convertSet(pageResult.getList(), ErpSaleOrderDO::getId)); | ||
| 144 | + Map<Long, List<ErpSaleOrderItemDO>> saleOrderItemMap = convertMultiMap(saleOrderItemList, ErpSaleOrderItemDO::getOrderId); | ||
| 145 | + // 1.2 商品信息 | ||
| 146 | + Map<Long, ErpProductRespVO> productMap = productService.getProductVOMap( | ||
| 147 | + convertSet(saleOrderItemList, ErpSaleOrderItemDO::getProductId)); | ||
| 148 | + // 1.3 客户信息 | ||
| 149 | + Map<Long, ErpCustomerDO> customerMap = customerService.getCustomerMap( | ||
| 150 | + convertSet(pageResult.getList(), ErpSaleOrderDO::getCustomerId)); | ||
| 151 | + // 1.4 管理员信息 | ||
| 152 | + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap( | ||
| 153 | + convertSet(pageResult.getList(), erpStockRecordDO -> Long.parseLong(erpStockRecordDO.getCreator()))); | ||
| 154 | + // 2. 开始拼接 | ||
| 155 | + return BeanUtils.toBean(pageResult, ErpSaleOrderRespVO.class, saleOrder -> { | ||
| 156 | + saleOrder.setItems(BeanUtils.toBean(saleOrderItemMap.get(saleOrder.getId()), ErpSaleOrderRespVO.Item.class, | ||
| 157 | + item -> MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) | ||
| 158 | + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())))); | ||
| 159 | + saleOrder.setProductNames(CollUtil.join(saleOrder.getItems(), ",", ErpSaleOrderRespVO.Item::getProductName)); | ||
| 160 | + MapUtils.findAndThen(customerMap, saleOrder.getCustomerId(), supplier -> saleOrder.setCustomerName(supplier.getName())); | ||
| 161 | + MapUtils.findAndThen(userMap, Long.parseLong(saleOrder.getCreator()), user -> saleOrder.setCreatorName(user.getNickname())); | ||
| 162 | + }); | ||
| 98 | } | 163 | } |
| 99 | 164 | ||
| 100 | } | 165 | } |
| 101 | \ No newline at end of file | 166 | \ No newline at end of file |
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_ | @@ -17,6 +17,19 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ | ||
| 17 | @ToString(callSuper = true) | 17 | @ToString(callSuper = true) |
| 18 | public class ErpSaleOrderPageReqVO extends PageParam { | 18 | public class ErpSaleOrderPageReqVO extends PageParam { |
| 19 | 19 | ||
| 20 | + /** | ||
| 21 | + * 入库状态 - 无 | ||
| 22 | + */ | ||
| 23 | + public static final Integer IN_STATUS_NONE = 0; | ||
| 24 | + /** | ||
| 25 | + * 入库状态 - 部分 | ||
| 26 | + */ | ||
| 27 | + public static final Integer IN_STATUS_PART = 1; | ||
| 28 | + /** | ||
| 29 | + * 入库状态 - 全部 | ||
| 30 | + */ | ||
| 31 | + public static final Integer IN_STATUS_ALL = 2; | ||
| 32 | + | ||
| 20 | @Schema(description = "销售单编号", example = "XS001") | 33 | @Schema(description = "销售单编号", example = "XS001") |
| 21 | private String no; | 34 | private String no; |
| 22 | 35 | ||
| @@ -28,7 +41,7 @@ public class ErpSaleOrderPageReqVO extends PageParam { | @@ -28,7 +41,7 @@ public class ErpSaleOrderPageReqVO extends PageParam { | ||
| 28 | private LocalDateTime[] orderTime; | 41 | private LocalDateTime[] orderTime; |
| 29 | 42 | ||
| 30 | @Schema(description = "备注", example = "你猜") | 43 | @Schema(description = "备注", example = "你猜") |
| 31 | - private String description; | 44 | + private String remark; |
| 32 | 45 | ||
| 33 | @Schema(description = "销售状态", example = "2") | 46 | @Schema(description = "销售状态", example = "2") |
| 34 | private Integer status; | 47 | private Integer status; |
| @@ -36,4 +49,10 @@ public class ErpSaleOrderPageReqVO extends PageParam { | @@ -36,4 +49,10 @@ public class ErpSaleOrderPageReqVO extends PageParam { | ||
| 36 | @Schema(description = "创建者") | 49 | @Schema(description = "创建者") |
| 37 | private String creator; | 50 | private String creator; |
| 38 | 51 | ||
| 52 | + @Schema(description = "产品编号", example = "1") | ||
| 53 | + private Long productId; | ||
| 54 | + | ||
| 55 | + @Schema(description = "入库状态", example = "2") | ||
| 56 | + private Integer inStatus; | ||
| 57 | + | ||
| 39 | } | 58 | } |
| 40 | \ No newline at end of file | 59 | \ No newline at end of file |
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; | @@ -3,12 +3,13 @@ package cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order; | ||
| 3 | import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; | 3 | import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; |
| 4 | import com.alibaba.excel.annotation.ExcelProperty; | 4 | import com.alibaba.excel.annotation.ExcelProperty; |
| 5 | import io.swagger.v3.oas.annotations.media.Schema; | 5 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | +import jakarta.validation.constraints.NotNull; | ||
| 6 | import lombok.Data; | 7 | import lombok.Data; |
| 7 | 8 | ||
| 8 | import java.math.BigDecimal; | 9 | import java.math.BigDecimal; |
| 9 | import java.time.LocalDateTime; | 10 | import java.time.LocalDateTime; |
| 11 | +import java.util.List; | ||
| 10 | 12 | ||
| 11 | -// TODO 芋艿:导出最后搞 | ||
| 12 | @Schema(description = "管理后台 - ERP 销售订单 Response VO") | 13 | @Schema(description = "管理后台 - ERP 销售订单 Response VO") |
| 13 | @Data | 14 | @Data |
| 14 | @ExcelIgnoreUnannotated | 15 | @ExcelIgnoreUnannotated |
| @@ -23,56 +24,103 @@ public class ErpSaleOrderRespVO { | @@ -23,56 +24,103 @@ public class ErpSaleOrderRespVO { | ||
| 23 | private String no; | 24 | private String no; |
| 24 | 25 | ||
| 25 | @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1724") | 26 | @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1724") |
| 26 | - @ExcelProperty("客户编号") | ||
| 27 | private Long customerId; | 27 | private Long customerId; |
| 28 | + @Schema(description = "客户名称", example = "芋道") | ||
| 29 | + @ExcelProperty("客户名称") | ||
| 30 | + private String customerName; | ||
| 28 | 31 | ||
| 29 | @Schema(description = "下单时间", requiredMode = Schema.RequiredMode.REQUIRED) | 32 | @Schema(description = "下单时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| 30 | @ExcelProperty("下单时间") | 33 | @ExcelProperty("下单时间") |
| 31 | private LocalDateTime orderTime; | 34 | private LocalDateTime orderTime; |
| 32 | 35 | ||
| 33 | - // TODO 芋艿:example 后面 | ||
| 34 | - @Schema(description = "销售员编号数组") | ||
| 35 | - @ExcelProperty("销售员编号数组") | ||
| 36 | - private String salePersonIds; | 36 | + @Schema(description = "销售员编号", example = "1888") |
| 37 | + private Long saleUserId; | ||
| 37 | 38 | ||
| 38 | - @Schema(description = "合计价格,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "26094") | ||
| 39 | - @ExcelProperty("合计价格,单位:元") | ||
| 40 | - private BigDecimal totalPrice; | 39 | + @Schema(description = "结算账户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "311.89") |
| 40 | + @ExcelProperty("结算账户编号") | ||
| 41 | + private Long accountId; | ||
| 42 | + | ||
| 43 | + @Schema(description = "合计产品价格,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") | ||
| 44 | + private BigDecimal totalProductPrice; | ||
| 45 | + | ||
| 46 | + @Schema(description = "合计税额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") | ||
| 47 | + private BigDecimal totalTaxPrice; | ||
| 41 | 48 | ||
| 42 | @Schema(description = "优惠率,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "99.88") | 49 | @Schema(description = "优惠率,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "99.88") |
| 43 | - @ExcelProperty("优惠率,百分比") | ||
| 44 | private BigDecimal discountPercent; | 50 | private BigDecimal discountPercent; |
| 45 | 51 | ||
| 46 | - @Schema(description = "优惠金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "44.52") | ||
| 47 | - @ExcelProperty("优惠金额,单位:元") | 52 | + @Schema(description = "优惠金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") |
| 48 | private BigDecimal discountPrice; | 53 | private BigDecimal discountPrice; |
| 49 | 54 | ||
| 50 | - @Schema(description = "支付金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "322.40") | ||
| 51 | - @ExcelProperty("支付金额,单位:元") | ||
| 52 | - private BigDecimal payPrice; | ||
| 53 | - | ||
| 54 | - @Schema(description = "定金金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "71.27") | ||
| 55 | - @ExcelProperty("定金金额,单位:元") | 55 | + @Schema(description = "定金金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") |
| 56 | + @NotNull(message = "定金金额,单位:元不能为空") | ||
| 56 | private BigDecimal depositPrice; | 57 | private BigDecimal depositPrice; |
| 57 | 58 | ||
| 59 | + @Schema(description = "销售状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||
| 60 | + @ExcelProperty("销售状态") | ||
| 61 | + private Integer status; | ||
| 62 | + | ||
| 58 | @Schema(description = "附件地址", example = "https://www.iocoder.cn") | 63 | @Schema(description = "附件地址", example = "https://www.iocoder.cn") |
| 59 | @ExcelProperty("附件地址") | 64 | @ExcelProperty("附件地址") |
| 60 | private String fileUrl; | 65 | private String fileUrl; |
| 61 | 66 | ||
| 62 | - @Schema(description = "结算账户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "311.89") | ||
| 63 | - @ExcelProperty("结算账户编号") | ||
| 64 | - private Long accountId; | ||
| 65 | - | ||
| 66 | @Schema(description = "备注", example = "你猜") | 67 | @Schema(description = "备注", example = "你猜") |
| 67 | @ExcelProperty("备注") | 68 | @ExcelProperty("备注") |
| 68 | - private String description; | 69 | + private String remark; |
| 69 | 70 | ||
| 70 | - @Schema(description = "销售状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||
| 71 | - @ExcelProperty("销售状态") | ||
| 72 | - private Integer status; | 71 | + @Schema(description = "审核人", example = "芋道") |
| 72 | + private String creator; | ||
| 73 | + @Schema(description = "审核人名称", example = "芋道") | ||
| 74 | + private String creatorName; | ||
| 73 | 75 | ||
| 74 | @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | 76 | @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| 75 | @ExcelProperty("创建时间") | 77 | @ExcelProperty("创建时间") |
| 76 | private LocalDateTime createTime; | 78 | private LocalDateTime createTime; |
| 77 | 79 | ||
| 80 | + @Schema(description = "订单项列表", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 81 | + private List<Item> items; | ||
| 82 | + | ||
| 83 | + @Schema(description = "产品信息", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 84 | + @ExcelProperty("产品信息") | ||
| 85 | + private String productNames; | ||
| 86 | + | ||
| 87 | + @Data | ||
| 88 | + public static class Item { | ||
| 89 | + | ||
| 90 | + @Schema(description = "订单项编号", example = "11756") | ||
| 91 | + private Long id; | ||
| 92 | + | ||
| 93 | + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") | ||
| 94 | + private Long productId; | ||
| 95 | + | ||
| 96 | + @Schema(description = "产品单位单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") | ||
| 97 | + private Long productUnitId; | ||
| 98 | + | ||
| 99 | + @Schema(description = "产品单价", example = "100.00") | ||
| 100 | + private BigDecimal productPrice; | ||
| 101 | + | ||
| 102 | + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") | ||
| 103 | + @NotNull(message = "产品数量不能为空") | ||
| 104 | + private BigDecimal count; | ||
| 105 | + | ||
| 106 | + @Schema(description = "税率,百分比", example = "99.88") | ||
| 107 | + private BigDecimal taxPercent; | ||
| 108 | + | ||
| 109 | + @Schema(description = "备注", example = "随便") | ||
| 110 | + private String remark; | ||
| 111 | + | ||
| 112 | + // ========== 关联字段 ========== | ||
| 113 | + | ||
| 114 | + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "巧克力") | ||
| 115 | + private String productName; | ||
| 116 | + @Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "A9985") | ||
| 117 | + private String productBarCode; | ||
| 118 | + @Schema(description = "产品单位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "盒") | ||
| 119 | + private String productUnitName; | ||
| 120 | + | ||
| 121 | + @Schema(description = "库存数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") | ||
| 122 | + private BigDecimal stockCount; // 该字段仅仅在“详情”和“编辑”时使用 | ||
| 123 | + | ||
| 124 | + } | ||
| 125 | + | ||
| 78 | } | 126 | } |
| 79 | \ No newline at end of file | 127 | \ No newline at end of file |
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 { | @@ -28,26 +28,16 @@ public class ErpSaleOrderSaveReqVO { | ||
| 28 | @NotNull(message = "下单时间不能为空") | 28 | @NotNull(message = "下单时间不能为空") |
| 29 | private LocalDateTime orderTime; | 29 | private LocalDateTime orderTime; |
| 30 | 30 | ||
| 31 | - @Schema(description = "销售员编号数组") | ||
| 32 | - private List<Long> salePersonIds; | 31 | + @Schema(description = "销售员编号", example = "1888") |
| 32 | + private Long saleUserId; | ||
| 33 | 33 | ||
| 34 | - @Schema(description = "合计价格,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "26094") | ||
| 35 | - @NotNull(message = "合计价格,单位:元不能为空") | ||
| 36 | - private BigDecimal totalPrice; | 34 | + @Schema(description = "结算账户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31189") |
| 35 | + @NotNull(message = "结算账户编号不能为空") | ||
| 36 | + private Long accountId; | ||
| 37 | 37 | ||
| 38 | @Schema(description = "优惠率,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "99.88") | 38 | @Schema(description = "优惠率,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "99.88") |
| 39 | - @NotNull(message = "优惠率,百分比不能为空") | ||
| 40 | private BigDecimal discountPercent; | 39 | private BigDecimal discountPercent; |
| 41 | 40 | ||
| 42 | - @Schema(description = "优惠金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "4452") | ||
| 43 | - @NotNull(message = "优惠金额,单位:元不能为空") | ||
| 44 | - private BigDecimal discountPrice; | ||
| 45 | - | ||
| 46 | - // TODO 芋艿:后面删除 | ||
| 47 | -// @Schema(description = "支付金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "32240") | ||
| 48 | -// @NotNull(message = "支付金额,单位:元不能为空") | ||
| 49 | -// private BigDecimal payPrice; | ||
| 50 | - | ||
| 51 | @Schema(description = "定金金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") | 41 | @Schema(description = "定金金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") |
| 52 | @NotNull(message = "定金金额,单位:元不能为空") | 42 | @NotNull(message = "定金金额,单位:元不能为空") |
| 53 | private BigDecimal depositPrice; | 43 | private BigDecimal depositPrice; |
| @@ -55,73 +45,38 @@ public class ErpSaleOrderSaveReqVO { | @@ -55,73 +45,38 @@ public class ErpSaleOrderSaveReqVO { | ||
| 55 | @Schema(description = "附件地址", example = "https://www.iocoder.cn") | 45 | @Schema(description = "附件地址", example = "https://www.iocoder.cn") |
| 56 | private String fileUrl; | 46 | private String fileUrl; |
| 57 | 47 | ||
| 58 | - @Schema(description = "结算账户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31189") | ||
| 59 | - @NotNull(message = "结算账户编号不能为空") | ||
| 60 | - private Long accountId; | ||
| 61 | - | ||
| 62 | @Schema(description = "备注", example = "你猜") | 48 | @Schema(description = "备注", example = "你猜") |
| 63 | - private String description; | ||
| 64 | - | ||
| 65 | - // TODO 芋艿:后面删除 | ||
| 66 | -// @Schema(description = "销售状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||
| 67 | -// @NotNull(message = "销售状态不能为空") | ||
| 68 | -// private Integer status; | 49 | + private String remark; |
| 69 | 50 | ||
| 70 | - @Schema(description = "ERP 销售订单明细列表") | ||
| 71 | - private List<Item> salesOrderItems; | 51 | + @Schema(description = "订单清单列表") |
| 52 | + private List<Item> items; | ||
| 72 | 53 | ||
| 73 | - @Schema(description = "管理后台 - ERP 销售订单明细新增/修改 Request VO") | ||
| 74 | @Data | 54 | @Data |
| 75 | - public class Item { | 55 | + public static class Item { |
| 76 | 56 | ||
| 77 | - @Schema(description = "编号", example = "20704") | 57 | + @Schema(description = "订单项编号", example = "11756") |
| 78 | private Long id; | 58 | private Long id; |
| 79 | 59 | ||
| 80 | - // TODO 芋艿:后面删除 | ||
| 81 | -// @Schema(description = "销售订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "30765") | ||
| 82 | -// @NotNull(message = "销售订单编号不能为空") | ||
| 83 | -// private Long orderId; | ||
| 84 | - | ||
| 85 | -// @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "5574") | ||
| 86 | -// @NotNull(message = "商品 SPU 编号不能为空") | ||
| 87 | -// private Long productSpuId; | ||
| 88 | - | ||
| 89 | - @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "21273") | ||
| 90 | - @NotNull(message = "商品 SKU 编号不能为空") | ||
| 91 | - private Long productSkuId; | 60 | + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") |
| 61 | + @NotNull(message = "产品编号不能为空") | ||
| 62 | + private Long productId; | ||
| 92 | 63 | ||
| 93 | - @Schema(description = "商品单位", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 94 | - @NotEmpty(message = "商品单位不能为空") | ||
| 95 | - private String productUnit; | 64 | + @Schema(description = "产品单位单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") |
| 65 | + @NotNull(message = "产品单位单位不能为空") | ||
| 66 | + private Long productUnitId; | ||
| 96 | 67 | ||
| 97 | - @Schema(description = "商品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "6897") | ||
| 98 | - @NotNull(message = "商品单价不能为空") | 68 | + @Schema(description = "产品单价", example = "100.00") |
| 99 | private BigDecimal productPrice; | 69 | private BigDecimal productPrice; |
| 100 | 70 | ||
| 101 | - @Schema(description = "数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "22100") | ||
| 102 | - @NotNull(message = "数量不能为空") | ||
| 103 | - private Integer count; | 71 | + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") |
| 72 | + @NotNull(message = "产品数量不能为空") | ||
| 73 | + private BigDecimal count; | ||
| 104 | 74 | ||
| 105 | - // TODO 芋艿:后面删除 | ||
| 106 | -// @Schema(description = "总价", requiredMode = Schema.RequiredMode.REQUIRED, example = "26868") | ||
| 107 | -// @NotNull(message = "总价不能为空") | ||
| 108 | -// private BigDecimal totalPrice; | ||
| 109 | - | ||
| 110 | - @Schema(description = "备注", example = "你说的对") | ||
| 111 | - private String description; | ||
| 112 | - | ||
| 113 | - @Schema(description = "税率,百分比", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 114 | - @NotNull(message = "税率,百分比不能为空") | 75 | + @Schema(description = "税率,百分比", example = "99.88") |
| 115 | private BigDecimal taxPercent; | 76 | private BigDecimal taxPercent; |
| 116 | 77 | ||
| 117 | - @Schema(description = "税额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "15791") | ||
| 118 | - @NotNull(message = "税额,单位:元不能为空") | ||
| 119 | - private BigDecimal taxPrice; | ||
| 120 | - | ||
| 121 | - // TODO 芋艿:后面删除 | ||
| 122 | -// @Schema(description = "支付金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "21930") | ||
| 123 | -// @NotNull(message = "支付金额,单位:元不能为空") | ||
| 124 | -// private BigDecimal payPrice; | 78 | + @Schema(description = "备注", example = "随便") |
| 79 | + private String remark; | ||
| 125 | 80 | ||
| 126 | } | 81 | } |
| 127 | 82 |
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOrderDO.java
| 1 | package cn.iocoder.yudao.module.erp.dal.dataobject.sale; | 1 | package cn.iocoder.yudao.module.erp.dal.dataobject.sale; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| 4 | -import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; | ||
| 5 | -import cn.iocoder.yudao.module.erp.enums.sale.ErpSaleOrderStatusEnum; | ||
| 6 | import com.baomidou.mybatisplus.annotation.KeySequence; | 4 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| 7 | -import com.baomidou.mybatisplus.annotation.TableField; | ||
| 8 | import com.baomidou.mybatisplus.annotation.TableId; | 5 | import com.baomidou.mybatisplus.annotation.TableId; |
| 9 | import com.baomidou.mybatisplus.annotation.TableName; | 6 | import com.baomidou.mybatisplus.annotation.TableName; |
| 10 | import lombok.*; | 7 | import lombok.*; |
| 11 | 8 | ||
| 12 | import java.math.BigDecimal; | 9 | import java.math.BigDecimal; |
| 13 | import java.time.LocalDateTime; | 10 | import java.time.LocalDateTime; |
| 14 | -import java.util.List; | ||
| 15 | 11 | ||
| 16 | /** | 12 | /** |
| 17 | * ERP 销售订单 DO | 13 | * ERP 销售订单 DO |
| 18 | * | 14 | * |
| 19 | * @author 芋道源码 | 15 | * @author 芋道源码 |
| 20 | */ | 16 | */ |
| 21 | -@TableName(value = "erp_sale_order", autoResultMap = true) | 17 | +@TableName(value = "erp_sale_order") |
| 22 | @KeySequence("erp_sale_order_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 | 18 | @KeySequence("erp_sale_order_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 |
| 23 | @Data | 19 | @Data |
| 24 | @EqualsAndHashCode(callSuper = true) | 20 | @EqualsAndHashCode(callSuper = true) |
| @@ -40,13 +36,13 @@ public class ErpSaleOrderDO extends BaseDO { | @@ -40,13 +36,13 @@ public class ErpSaleOrderDO extends BaseDO { | ||
| 40 | /** | 36 | /** |
| 41 | * 销售状态 | 37 | * 销售状态 |
| 42 | * | 38 | * |
| 43 | - * 枚举 {@link ErpSaleOrderStatusEnum} | 39 | + * 枚举 {@link cn.iocoder.yudao.module.erp.enums.ErpAuditStatus} |
| 44 | */ | 40 | */ |
| 45 | private Integer status; | 41 | private Integer status; |
| 46 | /** | 42 | /** |
| 47 | * 客户编号 | 43 | * 客户编号 |
| 48 | * | 44 | * |
| 49 | - * TODO 芋艿:关联 | 45 | + * 关联 {@link ErpCustomerDO#getId()} |
| 50 | */ | 46 | */ |
| 51 | private Long customerId; | 47 | private Long customerId; |
| 52 | /** | 48 | /** |
| @@ -56,34 +52,46 @@ public class ErpSaleOrderDO extends BaseDO { | @@ -56,34 +52,46 @@ public class ErpSaleOrderDO extends BaseDO { | ||
| 56 | */ | 52 | */ |
| 57 | private Long accountId; | 53 | private Long accountId; |
| 58 | /** | 54 | /** |
| 59 | - * 销售员编号数组 | 55 | + * 销售员编号 |
| 60 | * | 56 | * |
| 61 | - * TODO 芋艿:关联 | 57 | + * 关联 AdminUserDO 的 id 字段 |
| 62 | */ | 58 | */ |
| 63 | - @TableField(typeHandler = LongListTypeHandler.class) | ||
| 64 | - private List<Long> salePersonIds; | 59 | + private Long saleUserId; |
| 65 | /** | 60 | /** |
| 66 | * 下单时间 | 61 | * 下单时间 |
| 67 | */ | 62 | */ |
| 68 | private LocalDateTime orderTime; | 63 | private LocalDateTime orderTime; |
| 69 | 64 | ||
| 70 | /** | 65 | /** |
| 71 | - * 合计价格,单位:元 | 66 | + * 合计数量 |
| 67 | + */ | ||
| 68 | + private BigDecimal totalCount; | ||
| 69 | + /** | ||
| 70 | + * 最终合计价格,单位:元 | ||
| 71 | + * | ||
| 72 | + * totalPrice = totalProductPrice + totalTaxPrice - discountPrice | ||
| 72 | */ | 73 | */ |
| 73 | private BigDecimal totalPrice; | 74 | private BigDecimal totalPrice; |
| 75 | + | ||
| 76 | + /** | ||
| 77 | + * 合计产品价格,单位:元 | ||
| 78 | + */ | ||
| 79 | + private BigDecimal totalProductPrice; | ||
| 80 | + /** | ||
| 81 | + * 合计税额,单位:元 | ||
| 82 | + */ | ||
| 83 | + private BigDecimal totalTaxPrice; | ||
| 74 | /** | 84 | /** |
| 75 | * 优惠率,百分比 | 85 | * 优惠率,百分比 |
| 76 | */ | 86 | */ |
| 77 | private BigDecimal discountPercent; | 87 | private BigDecimal discountPercent; |
| 78 | /** | 88 | /** |
| 79 | * 优惠金额,单位:元 | 89 | * 优惠金额,单位:元 |
| 90 | + * | ||
| 91 | + * discountPrice = (totalProductPrice + totalTaxPrice) * discountPercent | ||
| 80 | */ | 92 | */ |
| 81 | private BigDecimal discountPrice; | 93 | private BigDecimal discountPrice; |
| 82 | /** | 94 | /** |
| 83 | - * 支付金额,单位:元 | ||
| 84 | - */ | ||
| 85 | - private BigDecimal payPrice; | ||
| 86 | - /** | ||
| 87 | * 定金金额,单位:元 | 95 | * 定金金额,单位:元 |
| 88 | */ | 96 | */ |
| 89 | private BigDecimal depositPrice; | 97 | private BigDecimal depositPrice; |
| @@ -95,6 +103,18 @@ public class ErpSaleOrderDO extends BaseDO { | @@ -95,6 +103,18 @@ public class ErpSaleOrderDO extends BaseDO { | ||
| 95 | /** | 103 | /** |
| 96 | * 备注 | 104 | * 备注 |
| 97 | */ | 105 | */ |
| 98 | - private String description; | 106 | + private String remark; |
| 107 | + | ||
| 108 | + // ========== 销售入库 ========== | ||
| 109 | + /** | ||
| 110 | + * 销售入库数量 | ||
| 111 | + */ | ||
| 112 | + private BigDecimal inCount; | ||
| 113 | + | ||
| 114 | + // ========== 销售退货(出库)) ========== | ||
| 115 | + /** | ||
| 116 | + * 销售退货数量 | ||
| 117 | + */ | ||
| 118 | + private BigDecimal returnCount; | ||
| 99 | 119 | ||
| 100 | } | 120 | } |
| 101 | \ No newline at end of file | 121 | \ No newline at end of file |
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSalesOrderItemDO.java renamed to yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOrderItemDO.java
| 1 | package cn.iocoder.yudao.module.erp.dal.dataobject.sale; | 1 | package cn.iocoder.yudao.module.erp.dal.dataobject.sale; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| 4 | +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; | ||
| 4 | import com.baomidou.mybatisplus.annotation.KeySequence; | 5 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| 5 | import com.baomidou.mybatisplus.annotation.TableId; | 6 | import com.baomidou.mybatisplus.annotation.TableId; |
| 6 | import com.baomidou.mybatisplus.annotation.TableName; | 7 | import com.baomidou.mybatisplus.annotation.TableName; |
| @@ -13,15 +14,15 @@ import java.math.BigDecimal; | @@ -13,15 +14,15 @@ import java.math.BigDecimal; | ||
| 13 | * | 14 | * |
| 14 | * @author 芋道源码 | 15 | * @author 芋道源码 |
| 15 | */ | 16 | */ |
| 16 | -@TableName("erp_sales_order_items") | ||
| 17 | -@KeySequence("erp_sales_order_items_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 | 17 | +@TableName("erp_sale_order_items") |
| 18 | +@KeySequence("erp_sale_order_items_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 | ||
| 18 | @Data | 19 | @Data |
| 19 | @EqualsAndHashCode(callSuper = true) | 20 | @EqualsAndHashCode(callSuper = true) |
| 20 | @ToString(callSuper = true) | 21 | @ToString(callSuper = true) |
| 21 | @Builder | 22 | @Builder |
| 22 | @NoArgsConstructor | 23 | @NoArgsConstructor |
| 23 | @AllArgsConstructor | 24 | @AllArgsConstructor |
| 24 | -public class ErpSalesOrderItemDO extends BaseDO { | 25 | +public class ErpSaleOrderItemDO extends BaseDO { |
| 25 | 26 | ||
| 26 | /** | 27 | /** |
| 27 | * 编号 | 28 | * 编号 |
| @@ -36,53 +37,58 @@ public class ErpSalesOrderItemDO extends BaseDO { | @@ -36,53 +37,58 @@ public class ErpSalesOrderItemDO extends BaseDO { | ||
| 36 | private Long orderId; | 37 | private Long orderId; |
| 37 | 38 | ||
| 38 | /** | 39 | /** |
| 39 | - * 商品 SPU 编号 | 40 | + * 产品编号 |
| 40 | * | 41 | * |
| 41 | - * TODO 芋艿 关联 | 42 | + * 关联 {@link ErpProductDO#getId()} |
| 42 | */ | 43 | */ |
| 43 | - private Long productSpuId; | 44 | + private Long productId; |
| 44 | /** | 45 | /** |
| 45 | - * 商品 SKU 编号 | 46 | + * 产品单位单位 |
| 46 | * | 47 | * |
| 47 | - * TODO 芋艿 关联 | 48 | + * 冗余 {@link ErpProductDO#getUnitId()} |
| 48 | */ | 49 | */ |
| 49 | - private Long productSkuId; | ||
| 50 | - /** | ||
| 51 | - * 商品单位 | ||
| 52 | - * | ||
| 53 | - * TODO 芋艿 冗余 | ||
| 54 | - */ | ||
| 55 | - private String productUnit; | 50 | + private Long productUnitId; |
| 51 | + | ||
| 56 | /** | 52 | /** |
| 57 | - * 商品单价 | ||
| 58 | - * | ||
| 59 | - * TODO 芋艿 冗余 | 53 | + * 产品单位单价,单位:元 |
| 60 | */ | 54 | */ |
| 61 | private BigDecimal productPrice; | 55 | private BigDecimal productPrice; |
| 62 | - | ||
| 63 | /** | 56 | /** |
| 64 | * 数量 | 57 | * 数量 |
| 65 | */ | 58 | */ |
| 66 | - private Integer count; | 59 | + private BigDecimal count; |
| 67 | /** | 60 | /** |
| 68 | - * 总价 | 61 | + * 总价,单位:元 |
| 62 | + * | ||
| 63 | + * totalPrice = productPrice * count | ||
| 69 | */ | 64 | */ |
| 70 | private BigDecimal totalPrice; | 65 | private BigDecimal totalPrice; |
| 71 | /** | 66 | /** |
| 72 | - * 备注 | ||
| 73 | - */ | ||
| 74 | - private String description; | ||
| 75 | - /** | ||
| 76 | * 税率,百分比 | 67 | * 税率,百分比 |
| 77 | */ | 68 | */ |
| 78 | private BigDecimal taxPercent; | 69 | private BigDecimal taxPercent; |
| 79 | /** | 70 | /** |
| 80 | * 税额,单位:元 | 71 | * 税额,单位:元 |
| 72 | + * | ||
| 73 | + * taxPrice = totalPrice * taxPercent | ||
| 81 | */ | 74 | */ |
| 82 | private BigDecimal taxPrice; | 75 | private BigDecimal taxPrice; |
| 76 | + | ||
| 77 | + /** | ||
| 78 | + * 备注 | ||
| 79 | + */ | ||
| 80 | + private String remark; | ||
| 81 | + | ||
| 82 | + // ========== 销售入库 ========== | ||
| 83 | + /** | ||
| 84 | + * 销售入库数量 | ||
| 85 | + */ | ||
| 86 | + private BigDecimal inCount; | ||
| 87 | + | ||
| 88 | + // ========== 销售退货(出库)) ========== | ||
| 83 | /** | 89 | /** |
| 84 | - * 支付金额,单位:元 | 90 | + * 销售退货数量 |
| 85 | */ | 91 | */ |
| 86 | - private BigDecimal payPrice; | 92 | + private BigDecimal returnCount; |
| 87 | 93 | ||
| 88 | } | 94 | } |
| 89 | \ No newline at end of file | 95 | \ No newline at end of file |
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSalesOrderItemMapper.java renamed to yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleOrderItemMapper.java
| 1 | package cn.iocoder.yudao.module.erp.dal.mysql.sale; | 1 | package cn.iocoder.yudao.module.erp.dal.mysql.sale; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | 3 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 4 | -import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSalesOrderItemDO; | 4 | +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderItemDO; |
| 5 | import org.apache.ibatis.annotations.Mapper; | 5 | import org.apache.ibatis.annotations.Mapper; |
| 6 | 6 | ||
| 7 | +import java.util.Collection; | ||
| 7 | import java.util.List; | 8 | import java.util.List; |
| 8 | 9 | ||
| 9 | /** | 10 | /** |
| @@ -12,14 +13,18 @@ import java.util.List; | @@ -12,14 +13,18 @@ import java.util.List; | ||
| 12 | * @author 芋道源码 | 13 | * @author 芋道源码 |
| 13 | */ | 14 | */ |
| 14 | @Mapper | 15 | @Mapper |
| 15 | -public interface ErpSalesOrderItemMapper extends BaseMapperX<ErpSalesOrderItemDO> { | 16 | +public interface ErpSaleOrderItemMapper extends BaseMapperX<ErpSaleOrderItemDO> { |
| 16 | 17 | ||
| 17 | - default List<ErpSalesOrderItemDO> selectListById(Long id) { | ||
| 18 | - return selectList(ErpSalesOrderItemDO::getId, id); | 18 | + default List<ErpSaleOrderItemDO> selectListByOrderId(Long orderId) { |
| 19 | + return selectList(ErpSaleOrderItemDO::getOrderId, orderId); | ||
| 19 | } | 20 | } |
| 20 | 21 | ||
| 21 | - default int deleteById(Long id) { | ||
| 22 | - return delete(ErpSalesOrderItemDO::getId, id); | 22 | + default List<ErpSaleOrderItemDO> selectListByOrderIds(Collection<Long> orderIds) { |
| 23 | + return selectList(ErpSaleOrderItemDO::getOrderId, orderIds); | ||
| 24 | + } | ||
| 25 | + | ||
| 26 | + default int deleteByOrderId(Long orderId) { | ||
| 27 | + return delete(ErpSaleOrderItemDO::getOrderId, orderId); | ||
| 23 | } | 28 | } |
| 24 | 29 | ||
| 25 | } | 30 | } |
| 26 | \ No newline at end of file | 31 | \ No newline at end of file |
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; | @@ -3,9 +3,11 @@ package cn.iocoder.yudao.module.erp.dal.mysql.sale; | ||
| 3 | 3 | ||
| 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | 5 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 6 | -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | 6 | +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; |
| 7 | import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderPageReqVO; | 7 | import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderPageReqVO; |
| 8 | import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderDO; | 8 | import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderDO; |
| 9 | +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutItemDO; | ||
| 10 | +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | ||
| 9 | import org.apache.ibatis.annotations.Mapper; | 11 | import org.apache.ibatis.annotations.Mapper; |
| 10 | 12 | ||
| 11 | /** | 13 | /** |
| @@ -17,14 +19,29 @@ import org.apache.ibatis.annotations.Mapper; | @@ -17,14 +19,29 @@ import org.apache.ibatis.annotations.Mapper; | ||
| 17 | public interface ErpSaleOrderMapper extends BaseMapperX<ErpSaleOrderDO> { | 19 | public interface ErpSaleOrderMapper extends BaseMapperX<ErpSaleOrderDO> { |
| 18 | 20 | ||
| 19 | default PageResult<ErpSaleOrderDO> selectPage(ErpSaleOrderPageReqVO reqVO) { | 21 | default PageResult<ErpSaleOrderDO> selectPage(ErpSaleOrderPageReqVO reqVO) { |
| 20 | - return selectPage(reqVO, new LambdaQueryWrapperX<ErpSaleOrderDO>() | ||
| 21 | - .likeIfPresent(ErpSaleOrderDO::getNo, reqVO.getNo()) | 22 | + MPJLambdaWrapperX<ErpSaleOrderDO> query = new MPJLambdaWrapperX<ErpSaleOrderDO>() |
| 23 | + .eqIfPresent(ErpSaleOrderDO::getNo, reqVO.getNo()) | ||
| 22 | .eqIfPresent(ErpSaleOrderDO::getCustomerId, reqVO.getCustomerId()) | 24 | .eqIfPresent(ErpSaleOrderDO::getCustomerId, reqVO.getCustomerId()) |
| 23 | .betweenIfPresent(ErpSaleOrderDO::getOrderTime, reqVO.getOrderTime()) | 25 | .betweenIfPresent(ErpSaleOrderDO::getOrderTime, reqVO.getOrderTime()) |
| 24 | - .eqIfPresent(ErpSaleOrderDO::getDescription, reqVO.getDescription()) | ||
| 25 | .eqIfPresent(ErpSaleOrderDO::getStatus, reqVO.getStatus()) | 26 | .eqIfPresent(ErpSaleOrderDO::getStatus, reqVO.getStatus()) |
| 27 | + .likeIfPresent(ErpSaleOrderDO::getRemark, reqVO.getRemark()) | ||
| 26 | .eqIfPresent(ErpSaleOrderDO::getCreator, reqVO.getCreator()) | 28 | .eqIfPresent(ErpSaleOrderDO::getCreator, reqVO.getCreator()) |
| 27 | - .orderByDesc(ErpSaleOrderDO::getId)); | 29 | + .orderByDesc(ErpSaleOrderDO::getId); |
| 30 | + if (reqVO.getProductId() != null) { | ||
| 31 | + query.leftJoin(ErpStockOutItemDO.class, ErpStockOutItemDO::getOutId, ErpSaleOrderDO::getId) | ||
| 32 | + .eq(reqVO.getProductId() != null, ErpStockOutItemDO::getProductId, reqVO.getProductId()) | ||
| 33 | + .groupBy(ErpSaleOrderDO::getId); // 避免 1 对多查询,产生相同的 1 | ||
| 34 | + } | ||
| 35 | + return selectJoinPage(reqVO, ErpSaleOrderDO.class, query); | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + default int updateByIdAndStatus(Long id, Integer status, ErpSaleOrderDO updateObj) { | ||
| 39 | + return update(updateObj, new LambdaUpdateWrapper<ErpSaleOrderDO>() | ||
| 40 | + .eq(ErpSaleOrderDO::getId, id).eq(ErpSaleOrderDO::getStatus, status)); | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + default ErpSaleOrderDO selectByNo(String no) { | ||
| 44 | + return selectOne(ErpSaleOrderDO::getNo, no); | ||
| 28 | } | 45 | } |
| 29 | 46 | ||
| 30 | } | 47 | } |
| 31 | \ No newline at end of file | 48 | \ No newline at end of file |
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java
| 1 | package cn.iocoder.yudao.module.erp.dal.mysql.stock; | 1 | package cn.iocoder.yudao.module.erp.dal.mysql.stock; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 4 | +import cn.hutool.core.map.MapUtil; | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | 6 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 5 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | 7 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| 6 | import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stock.ErpStockPageReqVO; | 8 | import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stock.ErpStockPageReqVO; |
| 7 | import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; | 9 | import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; |
| 10 | +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | ||
| 8 | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | 11 | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| 9 | import org.apache.ibatis.annotations.Mapper; | 12 | import org.apache.ibatis.annotations.Mapper; |
| 10 | 13 | ||
| 11 | import java.math.BigDecimal; | 14 | import java.math.BigDecimal; |
| 15 | +import java.util.List; | ||
| 16 | +import java.util.Map; | ||
| 12 | 17 | ||
| 13 | /** | 18 | /** |
| 14 | * ERP 产品库存 Mapper | 19 | * ERP 产品库存 Mapper |
| @@ -37,11 +42,23 @@ public interface ErpStockMapper extends BaseMapperX<ErpStockDO> { | @@ -37,11 +42,23 @@ public interface ErpStockMapper extends BaseMapperX<ErpStockDO> { | ||
| 37 | updateWrapper.setSql("count = count + " + count); | 42 | updateWrapper.setSql("count = count + " + count); |
| 38 | } else if (count.compareTo(BigDecimal.ZERO) < 0) { | 43 | } else if (count.compareTo(BigDecimal.ZERO) < 0) { |
| 39 | if (!negativeEnable) { | 44 | if (!negativeEnable) { |
| 40 | - updateWrapper.gt(ErpStockDO::getCount, count.abs()); | 45 | + updateWrapper.ge(ErpStockDO::getCount, count.abs()); |
| 41 | } | 46 | } |
| 42 | updateWrapper.setSql("count = count - " + count.abs()); | 47 | updateWrapper.setSql("count = count - " + count.abs()); |
| 43 | } | 48 | } |
| 44 | return update(null, updateWrapper); | 49 | return update(null, updateWrapper); |
| 45 | } | 50 | } |
| 46 | 51 | ||
| 52 | + default BigDecimal selectSumByProductId(Long productId) { | ||
| 53 | + // SQL sum 查询 | ||
| 54 | + List<Map<String, Object>> result = selectMaps(new QueryWrapper<ErpStockDO>() | ||
| 55 | + .select("SUM(count) AS sumCount") | ||
| 56 | + .eq("product_id", productId)); | ||
| 57 | + // 获得数量 | ||
| 58 | + if (CollUtil.isEmpty(result)) { | ||
| 59 | + return BigDecimal.ZERO; | ||
| 60 | + } | ||
| 61 | + return BigDecimal.valueOf(MapUtil.getDouble(result.get(0), "sumCount", 0D)); | ||
| 62 | + } | ||
| 63 | + | ||
| 47 | } | 64 | } |
| 48 | \ No newline at end of file | 65 | \ No newline at end of file |
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; | @@ -4,8 +4,12 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 4 | import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderPageReqVO; | 4 | import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderPageReqVO; |
| 5 | import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderSaveReqVO; | 5 | import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderSaveReqVO; |
| 6 | import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderDO; | 6 | import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderDO; |
| 7 | +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderItemDO; | ||
| 7 | import jakarta.validation.Valid; | 8 | import jakarta.validation.Valid; |
| 8 | 9 | ||
| 10 | +import java.util.Collection; | ||
| 11 | +import java.util.List; | ||
| 12 | + | ||
| 9 | /** | 13 | /** |
| 10 | * ERP 销售订单 Service 接口 | 14 | * ERP 销售订单 Service 接口 |
| 11 | * | 15 | * |
| @@ -14,7 +18,7 @@ import jakarta.validation.Valid; | @@ -14,7 +18,7 @@ import jakarta.validation.Valid; | ||
| 14 | public interface ErpSaleOrderService { | 18 | public interface ErpSaleOrderService { |
| 15 | 19 | ||
| 16 | /** | 20 | /** |
| 17 | - * 创建ERP 销售订单 | 21 | + * 创建销售订单 |
| 18 | * | 22 | * |
| 19 | * @param createReqVO 创建信息 | 23 | * @param createReqVO 创建信息 |
| 20 | * @return 编号 | 24 | * @return 编号 |
| @@ -22,33 +26,59 @@ public interface ErpSaleOrderService { | @@ -22,33 +26,59 @@ public interface ErpSaleOrderService { | ||
| 22 | Long createSaleOrder(@Valid ErpSaleOrderSaveReqVO createReqVO); | 26 | Long createSaleOrder(@Valid ErpSaleOrderSaveReqVO createReqVO); |
| 23 | 27 | ||
| 24 | /** | 28 | /** |
| 25 | - * 更新ERP 销售订单 | 29 | + * 更新销售订单 |
| 26 | * | 30 | * |
| 27 | * @param updateReqVO 更新信息 | 31 | * @param updateReqVO 更新信息 |
| 28 | */ | 32 | */ |
| 29 | void updateSaleOrder(@Valid ErpSaleOrderSaveReqVO updateReqVO); | 33 | void updateSaleOrder(@Valid ErpSaleOrderSaveReqVO updateReqVO); |
| 30 | 34 | ||
| 31 | /** | 35 | /** |
| 32 | - * 删除ERP 销售订单 | 36 | + * 更新销售订单的状态 |
| 33 | * | 37 | * |
| 34 | * @param id 编号 | 38 | * @param id 编号 |
| 39 | + * @param status 状态 | ||
| 35 | */ | 40 | */ |
| 36 | - void deleteSaleOrder(Long id); | 41 | + void updateSaleOrderStatus(Long id, Integer status); |
| 37 | 42 | ||
| 38 | /** | 43 | /** |
| 39 | - * 获得ERP 销售订单 | 44 | + * 删除销售订单 |
| 45 | + * | ||
| 46 | + * @param ids 编号数组 | ||
| 47 | + */ | ||
| 48 | + void deleteSaleOrder(List<Long> ids); | ||
| 49 | + | ||
| 50 | + /** | ||
| 51 | + * 获得销售订单 | ||
| 40 | * | 52 | * |
| 41 | * @param id 编号 | 53 | * @param id 编号 |
| 42 | - * @return ERP 销售订单 | 54 | + * @return 销售订单 |
| 43 | */ | 55 | */ |
| 44 | ErpSaleOrderDO getSaleOrder(Long id); | 56 | ErpSaleOrderDO getSaleOrder(Long id); |
| 45 | 57 | ||
| 46 | /** | 58 | /** |
| 47 | - * 获得ERP 销售订单分页 | 59 | + * 获得销售订单分页 |
| 48 | * | 60 | * |
| 49 | * @param pageReqVO 分页查询 | 61 | * @param pageReqVO 分页查询 |
| 50 | - * @return ERP 销售订单分页 | 62 | + * @return 销售订单分页 |
| 51 | */ | 63 | */ |
| 52 | PageResult<ErpSaleOrderDO> getSaleOrderPage(ErpSaleOrderPageReqVO pageReqVO); | 64 | PageResult<ErpSaleOrderDO> getSaleOrderPage(ErpSaleOrderPageReqVO pageReqVO); |
| 53 | 65 | ||
| 66 | + // ==================== 销售订单项 ==================== | ||
| 67 | + | ||
| 68 | + /** | ||
| 69 | + * 获得销售订单项列表 | ||
| 70 | + * | ||
| 71 | + * @param orderId 销售订单编号 | ||
| 72 | + * @return 销售订单项列表 | ||
| 73 | + */ | ||
| 74 | + List<ErpSaleOrderItemDO> getSaleOrderItemListByOrderId(Long orderId); | ||
| 75 | + | ||
| 76 | + /** | ||
| 77 | + * 获得销售订单项 List | ||
| 78 | + * | ||
| 79 | + * @param orderIds 销售订单编号数组 | ||
| 80 | + * @return 销售订单项 List | ||
| 81 | + */ | ||
| 82 | + List<ErpSaleOrderItemDO> getSaleOrderItemListByOrderIds(Collection<Long> orderIds); | ||
| 83 | + | ||
| 54 | } | 84 | } |
| 55 | \ No newline at end of file | 85 | \ No newline at end of file |
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderServiceImpl.java
| 1 | package cn.iocoder.yudao.module.erp.service.sale; | 1 | package cn.iocoder.yudao.module.erp.service.sale; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | +import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; | ||
| 4 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 6 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 5 | import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderPageReqVO; | 7 | import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderPageReqVO; |
| 6 | import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderSaveReqVO; | 8 | import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderSaveReqVO; |
| 9 | +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; | ||
| 7 | import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderDO; | 10 | import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderDO; |
| 8 | -import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSalesOrderItemDO; | 11 | +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderItemDO; |
| 12 | +import cn.iocoder.yudao.module.erp.dal.mysql.sale.ErpSaleOrderItemMapper; | ||
| 9 | import cn.iocoder.yudao.module.erp.dal.mysql.sale.ErpSaleOrderMapper; | 13 | import cn.iocoder.yudao.module.erp.dal.mysql.sale.ErpSaleOrderMapper; |
| 10 | -import cn.iocoder.yudao.module.erp.dal.mysql.sale.ErpSalesOrderItemMapper; | 14 | +import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO; |
| 15 | +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; | ||
| 16 | +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; | ||
| 11 | import jakarta.annotation.Resource; | 17 | import jakarta.annotation.Resource; |
| 12 | import org.springframework.stereotype.Service; | 18 | import org.springframework.stereotype.Service; |
| 13 | import org.springframework.transaction.annotation.Transactional; | 19 | import org.springframework.transaction.annotation.Transactional; |
| 14 | import org.springframework.validation.annotation.Validated; | 20 | import org.springframework.validation.annotation.Validated; |
| 15 | 21 | ||
| 22 | +import java.math.BigDecimal; | ||
| 23 | +import java.util.Collection; | ||
| 24 | +import java.util.Collections; | ||
| 16 | import java.util.List; | 25 | import java.util.List; |
| 26 | +import java.util.Map; | ||
| 17 | 27 | ||
| 18 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 28 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 29 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; | ||
| 19 | import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; | 30 | import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; |
| 20 | 31 | ||
| 32 | +// TODO 芋艿:记录操作日志 | ||
| 33 | + | ||
| 21 | /** | 34 | /** |
| 22 | * ERP 销售订单 Service 实现类 | 35 | * ERP 销售订单 Service 实现类 |
| 23 | * | 36 | * |
| @@ -30,61 +43,142 @@ public class ErpSaleOrderServiceImpl implements ErpSaleOrderService { | @@ -30,61 +43,142 @@ public class ErpSaleOrderServiceImpl implements ErpSaleOrderService { | ||
| 30 | @Resource | 43 | @Resource |
| 31 | private ErpSaleOrderMapper saleOrderMapper; | 44 | private ErpSaleOrderMapper saleOrderMapper; |
| 32 | @Resource | 45 | @Resource |
| 33 | - private ErpSalesOrderItemMapper salesOrderItemMapper; | 46 | + private ErpSaleOrderItemMapper saleOrderItemMapper; |
| 47 | + | ||
| 48 | + @Resource | ||
| 49 | + private ErpNoRedisDAO noRedisDAO; | ||
| 50 | + | ||
| 51 | + @Resource | ||
| 52 | + private ErpProductService productService; | ||
| 53 | + @Resource | ||
| 54 | + private ErpCustomerService customerService; | ||
| 34 | 55 | ||
| 35 | @Override | 56 | @Override |
| 36 | @Transactional(rollbackFor = Exception.class) | 57 | @Transactional(rollbackFor = Exception.class) |
| 37 | public Long createSaleOrder(ErpSaleOrderSaveReqVO createReqVO) { | 58 | public Long createSaleOrder(ErpSaleOrderSaveReqVO createReqVO) { |
| 38 | - // 插入 | ||
| 39 | - ErpSaleOrderDO saleOrder = BeanUtils.toBean(createReqVO, ErpSaleOrderDO.class); | ||
| 40 | - saleOrderMapper.insert(saleOrder); | 59 | + // 1.1 校验订单项的有效性 |
| 60 | + List<ErpSaleOrderItemDO> saleOrderItems = validateSaleOrderItems(createReqVO.getItems()); | ||
| 61 | + // 1.2 校验客户 | ||
| 62 | + customerService.validateCustomer(createReqVO.getCustomerId()); | ||
| 63 | + // 1.3 生成调拨单号,并校验唯一性 | ||
| 64 | + String no = noRedisDAO.generate(ErpNoRedisDAO.STOCK_MOVE_NO_PREFIX); | ||
| 65 | + if (saleOrderMapper.selectByNo(no) != null) { | ||
| 66 | + throw exception(STOCK_MOVE_NO_EXISTS); | ||
| 67 | + } | ||
| 41 | 68 | ||
| 42 | - // 插入子表 | ||
| 43 | -// createSalesOrderItemsList(saleOrder.getId(), createReqVO.getSalesOrderItems()); | ||
| 44 | - // 返回 | 69 | + // 2.1 插入订单 |
| 70 | + ErpSaleOrderDO saleOrder = BeanUtils.toBean(createReqVO, ErpSaleOrderDO.class, in -> in | ||
| 71 | + .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus()) | ||
| 72 | + .setTotalCount(getSumValue(saleOrderItems, ErpSaleOrderItemDO::getCount, BigDecimal::add)) | ||
| 73 | + .setTotalPrice(getSumValue(saleOrderItems, ErpSaleOrderItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO))); | ||
| 74 | + saleOrderMapper.insert(saleOrder); | ||
| 75 | + // 2.2 插入订单项 | ||
| 76 | + saleOrderItems.forEach(o -> o.setOrderId(saleOrder.getId())); | ||
| 77 | + saleOrderItemMapper.insertBatch(saleOrderItems); | ||
| 45 | return saleOrder.getId(); | 78 | return saleOrder.getId(); |
| 46 | } | 79 | } |
| 47 | 80 | ||
| 48 | - private void createSalesOrderItemsList(Long id, List<ErpSalesOrderItemDO> list) { | ||
| 49 | - list.forEach(o -> o.setId(id)); | ||
| 50 | - salesOrderItemMapper.insertBatch(list); | ||
| 51 | - } | ||
| 52 | - | ||
| 53 | @Override | 81 | @Override |
| 54 | @Transactional(rollbackFor = Exception.class) | 82 | @Transactional(rollbackFor = Exception.class) |
| 55 | public void updateSaleOrder(ErpSaleOrderSaveReqVO updateReqVO) { | 83 | public void updateSaleOrder(ErpSaleOrderSaveReqVO updateReqVO) { |
| 56 | - // 校验存在 | ||
| 57 | - validateSaleOrderExists(updateReqVO.getId()); | ||
| 58 | - // 更新 | ||
| 59 | - ErpSaleOrderDO updateObj = BeanUtils.toBean(updateReqVO, ErpSaleOrderDO.class); | 84 | + // 1.1 校验存在 |
| 85 | + ErpSaleOrderDO saleOrder = validateSaleOrderExists(updateReqVO.getId()); | ||
| 86 | + if (ErpAuditStatus.APPROVE.getStatus().equals(saleOrder.getStatus())) { | ||
| 87 | + throw exception(STOCK_MOVE_UPDATE_FAIL_APPROVE, saleOrder.getNo()); | ||
| 88 | + } | ||
| 89 | + // 1.2 校验客户 | ||
| 90 | + customerService.validateCustomer(updateReqVO.getCustomerId()); | ||
| 91 | + // 1.3 校验订单项的有效性 | ||
| 92 | + List<ErpSaleOrderItemDO> saleOrderItems = validateSaleOrderItems(updateReqVO.getItems()); | ||
| 93 | + | ||
| 94 | + // 2.1 更新订单 | ||
| 95 | + ErpSaleOrderDO updateObj = BeanUtils.toBean(updateReqVO, ErpSaleOrderDO.class, in -> in | ||
| 96 | + .setTotalCount(getSumValue(saleOrderItems, ErpSaleOrderItemDO::getCount, BigDecimal::add)) | ||
| 97 | + .setTotalPrice(getSumValue(saleOrderItems, ErpSaleOrderItemDO::getTotalPrice, BigDecimal::add))); | ||
| 60 | saleOrderMapper.updateById(updateObj); | 98 | saleOrderMapper.updateById(updateObj); |
| 99 | + // 2.2 更新订单项 | ||
| 100 | + updateSaleOrderItemList(updateReqVO.getId(), saleOrderItems); | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + @Override | ||
| 104 | + @Transactional(rollbackFor = Exception.class) | ||
| 105 | + public void updateSaleOrderStatus(Long id, Integer status) { | ||
| 106 | + boolean approve = ErpAuditStatus.APPROVE.getStatus().equals(status); | ||
| 107 | + // 1.1 校验存在 | ||
| 108 | + ErpSaleOrderDO saleOrder = validateSaleOrderExists(id); | ||
| 109 | + // 1.2 校验状态 | ||
| 110 | + if (saleOrder.getStatus().equals(status)) { | ||
| 111 | + throw exception(approve ? STOCK_MOVE_APPROVE_FAIL : STOCK_MOVE_PROCESS_FAIL); | ||
| 112 | + } | ||
| 113 | + // TODO @芋艿:需要校验是不是有入库、有退货 | ||
| 61 | 114 | ||
| 62 | - // 更新子表 | ||
| 63 | -// updateSalesOrderItemsList(updateReqVO.getId(), updateReqVO.getSalesOrderItems()); | 115 | + // 2. 更新状态 |
| 116 | + int updateCount = saleOrderMapper.updateByIdAndStatus(id, saleOrder.getStatus(), | ||
| 117 | + new ErpSaleOrderDO().setStatus(status)); | ||
| 118 | + if (updateCount == 0) { | ||
| 119 | + throw exception(approve ? STOCK_MOVE_APPROVE_FAIL : STOCK_MOVE_PROCESS_FAIL); | ||
| 120 | + } | ||
| 64 | } | 121 | } |
| 65 | 122 | ||
| 66 | - private void updateSalesOrderItemsList(Long id, List<ErpSalesOrderItemDO> list) { | ||
| 67 | - deleteSalesOrderItemsById(id); | ||
| 68 | - list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下:1)id 冲突;2)updateTime 不更新 | ||
| 69 | - createSalesOrderItemsList(id, list); | 123 | + private List<ErpSaleOrderItemDO> validateSaleOrderItems(List<ErpSaleOrderSaveReqVO.Item> list) { |
| 124 | + // 1. 校验产品存在 | ||
| 125 | + List<ErpProductDO> productList = productService.validProductList( | ||
| 126 | + convertSet(list, ErpSaleOrderSaveReqVO.Item::getProductId)); | ||
| 127 | + Map<Long, ErpProductDO> productMap = convertMap(productList, ErpProductDO::getId); | ||
| 128 | + // 2. 转化为 ErpSaleOrderItemDO 列表 | ||
| 129 | + return convertList(list, o -> BeanUtils.toBean(o, ErpSaleOrderItemDO.class, item -> item | ||
| 130 | + .setProductUnitId(productMap.get(item.getProductId()).getUnitId()) | ||
| 131 | + .setTotalPrice(MoneyUtils.priceMultiply(item.getProductPrice(), item.getCount())))); | ||
| 132 | + } | ||
| 133 | + | ||
| 134 | + private void updateSaleOrderItemList(Long id, List<ErpSaleOrderItemDO> newList) { | ||
| 135 | + // 第一步,对比新老数据,获得添加、修改、删除的列表 | ||
| 136 | + List<ErpSaleOrderItemDO> oldList = saleOrderItemMapper.selectListByOrderId(id); | ||
| 137 | + List<List<ErpSaleOrderItemDO>> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录 | ||
| 138 | + (oldVal, newVal) -> oldVal.getId().equals(newVal.getId())); | ||
| 139 | + | ||
| 140 | + // 第二步,批量添加、修改、删除 | ||
| 141 | + if (CollUtil.isNotEmpty(diffList.get(0))) { | ||
| 142 | + diffList.get(0).forEach(o -> o.setOrderId(id)); | ||
| 143 | + saleOrderItemMapper.insertBatch(diffList.get(0)); | ||
| 144 | + } | ||
| 145 | + if (CollUtil.isNotEmpty(diffList.get(1))) { | ||
| 146 | + saleOrderItemMapper.updateBatch(diffList.get(1)); | ||
| 147 | + } | ||
| 148 | + if (CollUtil.isNotEmpty(diffList.get(2))) { | ||
| 149 | + saleOrderItemMapper.deleteBatchIds(convertList(diffList.get(2), ErpSaleOrderItemDO::getId)); | ||
| 150 | + } | ||
| 70 | } | 151 | } |
| 71 | 152 | ||
| 72 | @Override | 153 | @Override |
| 73 | @Transactional(rollbackFor = Exception.class) | 154 | @Transactional(rollbackFor = Exception.class) |
| 74 | - public void deleteSaleOrder(Long id) { | ||
| 75 | - // 校验存在 | ||
| 76 | - validateSaleOrderExists(id); | ||
| 77 | - // 删除 | ||
| 78 | - saleOrderMapper.deleteById(id); | ||
| 79 | - | ||
| 80 | - // 删除子表 | ||
| 81 | - deleteSalesOrderItemsById(id); | 155 | + public void deleteSaleOrder(List<Long> ids) { |
| 156 | + // 1. 校验不处于已审批 | ||
| 157 | + List<ErpSaleOrderDO> saleOrders = saleOrderMapper.selectBatchIds(ids); | ||
| 158 | + if (CollUtil.isEmpty(saleOrders)) { | ||
| 159 | + return; | ||
| 160 | + } | ||
| 161 | + saleOrders.forEach(saleOrder -> { | ||
| 162 | + if (ErpAuditStatus.APPROVE.getStatus().equals(saleOrder.getStatus())) { | ||
| 163 | + throw exception(STOCK_MOVE_DELETE_FAIL_APPROVE, saleOrder.getNo()); | ||
| 164 | + } | ||
| 165 | + }); | ||
| 166 | + | ||
| 167 | + // 2. 遍历删除,并记录操作日志 | ||
| 168 | + saleOrders.forEach(saleOrder -> { | ||
| 169 | + // 2.1 删除订单 | ||
| 170 | + saleOrderMapper.deleteById(saleOrder.getId()); | ||
| 171 | + // 2.2 删除订单项 | ||
| 172 | + saleOrderItemMapper.deleteByOrderId(saleOrder.getId()); | ||
| 173 | + }); | ||
| 82 | } | 174 | } |
| 83 | 175 | ||
| 84 | - private void validateSaleOrderExists(Long id) { | ||
| 85 | - if (saleOrderMapper.selectById(id) == null) { | ||
| 86 | - throw exception(SALE_ORDER_NOT_EXISTS); | 176 | + private ErpSaleOrderDO validateSaleOrderExists(Long id) { |
| 177 | + ErpSaleOrderDO saleOrder = saleOrderMapper.selectById(id); | ||
| 178 | + if (saleOrder == null) { | ||
| 179 | + throw exception(STOCK_MOVE_NOT_EXISTS); | ||
| 87 | } | 180 | } |
| 181 | + return saleOrder; | ||
| 88 | } | 182 | } |
| 89 | 183 | ||
| 90 | @Override | 184 | @Override |
| @@ -97,10 +191,19 @@ public class ErpSaleOrderServiceImpl implements ErpSaleOrderService { | @@ -97,10 +191,19 @@ public class ErpSaleOrderServiceImpl implements ErpSaleOrderService { | ||
| 97 | return saleOrderMapper.selectPage(pageReqVO); | 191 | return saleOrderMapper.selectPage(pageReqVO); |
| 98 | } | 192 | } |
| 99 | 193 | ||
| 100 | - // ==================== 子表(ERP 销售订单明细) ==================== | 194 | + // ==================== 订单项 ==================== |
| 101 | 195 | ||
| 102 | - private void deleteSalesOrderItemsById(Long id) { | ||
| 103 | - salesOrderItemMapper.deleteById(id); | 196 | + @Override |
| 197 | + public List<ErpSaleOrderItemDO> getSaleOrderItemListByOrderId(Long moveId) { | ||
| 198 | + return saleOrderItemMapper.selectListByOrderId(moveId); | ||
| 199 | + } | ||
| 200 | + | ||
| 201 | + @Override | ||
| 202 | + public List<ErpSaleOrderItemDO> getSaleOrderItemListByOrderIds(Collection<Long> moveIds) { | ||
| 203 | + if (CollUtil.isEmpty(moveIds)) { | ||
| 204 | + return Collections.emptyList(); | ||
| 205 | + } | ||
| 206 | + return saleOrderItemMapper.selectListByOrderIds(moveIds); | ||
| 104 | } | 207 | } |
| 105 | 208 | ||
| 106 | } | 209 | } |
| 107 | \ No newline at end of file | 210 | \ No newline at end of file |
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockService.java
| @@ -31,6 +31,14 @@ public interface ErpStockService { | @@ -31,6 +31,14 @@ public interface ErpStockService { | ||
| 31 | ErpStockDO getStock(Long productId, Long warehouseId); | 31 | ErpStockDO getStock(Long productId, Long warehouseId); |
| 32 | 32 | ||
| 33 | /** | 33 | /** |
| 34 | + * 获得产品库存数量 | ||
| 35 | + * | ||
| 36 | + * @param productId 产品编号 | ||
| 37 | + * @return 产品库存数量 | ||
| 38 | + */ | ||
| 39 | + BigDecimal getStockCount(Long productId); | ||
| 40 | + | ||
| 41 | + /** | ||
| 34 | * 获得产品库存分页 | 42 | * 获得产品库存分页 |
| 35 | * | 43 | * |
| 36 | * @param pageReqVO 分页查询 | 44 | * @param pageReqVO 分页查询 |
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockServiceImpl.java
| @@ -50,6 +50,11 @@ public class ErpStockServiceImpl implements ErpStockService { | @@ -50,6 +50,11 @@ public class ErpStockServiceImpl implements ErpStockService { | ||
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | @Override | 52 | @Override |
| 53 | + public BigDecimal getStockCount(Long productId) { | ||
| 54 | + return stockMapper.selectSumByProductId(productId); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + @Override | ||
| 53 | public PageResult<ErpStockDO> getStockPage(ErpStockPageReqVO pageReqVO) { | 58 | public PageResult<ErpStockDO> getStockPage(ErpStockPageReqVO pageReqVO) { |
| 54 | return stockMapper.selectPage(pageReqVO); | 59 | return stockMapper.selectPage(pageReqVO); |
| 55 | } | 60 | } |