mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-10-31 10:18:42 +08:00 
			
		
		
		
	✨ ERP:增加 ERP 销售订单的实现 50%
This commit is contained in:
		| @@ -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; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,16 +1,26 @@ | |||||||
| package cn.iocoder.yudao.module.erp.controller.admin.sale; | 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.CommonResult; | ||||||
| import cn.iocoder.yudao.framework.common.pojo.PageParam; | import cn.iocoder.yudao.framework.common.pojo.PageParam; | ||||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | 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.common.util.object.BeanUtils; | ||||||
| import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; | ||||||
| import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; | 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.ErpSaleOrderPageReqVO; | ||||||
| import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderRespVO; | 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.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.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.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.Operation; | ||||||
| import io.swagger.v3.oas.annotations.Parameter; | import io.swagger.v3.oas.annotations.Parameter; | ||||||
| import io.swagger.v3.oas.annotations.tags.Tag; | 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 org.springframework.web.bind.annotation.*; | ||||||
|  |  | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
|  | import java.math.BigDecimal; | ||||||
| import java.util.List; | 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.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; | import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -36,65 +50,116 @@ public class ErpSaleOrderController { | |||||||
|  |  | ||||||
|     @Resource |     @Resource | ||||||
|     private ErpSaleOrderService saleOrderService; |     private ErpSaleOrderService saleOrderService; | ||||||
|  |     @Resource | ||||||
|  |     private ErpStockService stockService; | ||||||
|  |     @Resource | ||||||
|  |     private ErpProductService productService; | ||||||
|  |     @Resource | ||||||
|  |     private ErpCustomerService customerService; | ||||||
|  |  | ||||||
|  |     @Resource | ||||||
|  |     private AdminUserApi adminUserApi; | ||||||
|  |  | ||||||
|     // TODO 芋艿:待 review |  | ||||||
|     @PostMapping("/create") |     @PostMapping("/create") | ||||||
|     @Operation(summary = "创建ERP 销售订单") |     @Operation(summary = "创建销售订单") | ||||||
|     @PreAuthorize("@ss.hasPermission('erp:sale-order:create')") |     @PreAuthorize("@ss.hasPermission('erp:stock-out:create')") | ||||||
|     public CommonResult<Long> createSaleOrder(@Valid @RequestBody ErpSaleOrderSaveReqVO createReqVO) { |     public CommonResult<Long> createSaleOrder(@Valid @RequestBody ErpSaleOrderSaveReqVO createReqVO) { | ||||||
|         return success(saleOrderService.createSaleOrder(createReqVO)); |         return success(saleOrderService.createSaleOrder(createReqVO)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // TODO 芋艿:待 review |  | ||||||
|     @PutMapping("/update") |     @PutMapping("/update") | ||||||
|     @Operation(summary = "更新ERP 销售订单") |     @Operation(summary = "更新销售订单") | ||||||
|     @PreAuthorize("@ss.hasPermission('erp:sale-order:update')") |     @PreAuthorize("@ss.hasPermission('erp:stock-out:update')") | ||||||
|     public CommonResult<Boolean> updateSaleOrder(@Valid @RequestBody ErpSaleOrderSaveReqVO updateReqVO) { |     public CommonResult<Boolean> updateSaleOrder(@Valid @RequestBody ErpSaleOrderSaveReqVO updateReqVO) { | ||||||
|         saleOrderService.updateSaleOrder(updateReqVO); |         saleOrderService.updateSaleOrder(updateReqVO); | ||||||
|         return success(true); |         return success(true); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // TODO 芋艿:待 review |     @PutMapping("/update-status") | ||||||
|     @DeleteMapping("/delete") |     @Operation(summary = "更新销售订单的状态") | ||||||
|     @Operation(summary = "删除ERP 销售订单") |     @PreAuthorize("@ss.hasPermission('erp:stock-out:update-status')") | ||||||
|     @Parameter(name = "id", description = "编号", required = true) |     public CommonResult<Boolean> updateSaleOrderStatus(@RequestParam("id") Long id, | ||||||
|     @PreAuthorize("@ss.hasPermission('erp:sale-order:delete')") |                                                       @RequestParam("status") Integer status) { | ||||||
|     public CommonResult<Boolean> deleteSaleOrder(@RequestParam("id") Long id) { |         saleOrderService.updateSaleOrderStatus(id, status); | ||||||
|         saleOrderService.deleteSaleOrder(id); |         return success(true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @DeleteMapping("/delete") | ||||||
|  |     @Operation(summary = "删除销售订单") | ||||||
|  |     @Parameter(name = "ids", description = "编号数组", required = true) | ||||||
|  |     @PreAuthorize("@ss.hasPermission('erp:stock-out:delete')") | ||||||
|  |     public CommonResult<Boolean> deleteSaleOrder(@RequestParam("ids") List<Long> ids) { | ||||||
|  |         saleOrderService.deleteSaleOrder(ids); | ||||||
|         return success(true); |         return success(true); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // TODO 芋艿:待 review |  | ||||||
|     @GetMapping("/get") |     @GetMapping("/get") | ||||||
|     @Operation(summary = "获得ERP 销售订单") |     @Operation(summary = "获得销售订单") | ||||||
|     @Parameter(name = "id", description = "编号", required = true, example = "1024") |     @Parameter(name = "id", description = "编号", required = true, example = "1024") | ||||||
|     @PreAuthorize("@ss.hasPermission('erp:sale-order:query')") |     @PreAuthorize("@ss.hasPermission('erp:stock-out:query')") | ||||||
|     public CommonResult<ErpSaleOrderRespVO> getSaleOrder(@RequestParam("id") Long id) { |     public CommonResult<ErpSaleOrderRespVO> getSaleOrder(@RequestParam("id") Long id) { | ||||||
|         ErpSaleOrderDO saleOrder = saleOrderService.getSaleOrder(id); |         ErpSaleOrderDO saleOrder = saleOrderService.getSaleOrder(id); | ||||||
|         return success(BeanUtils.toBean(saleOrder, ErpSaleOrderRespVO.class)); |         if (saleOrder == null) { | ||||||
|  |             return success(null); | ||||||
|  |         } | ||||||
|  |         List<ErpSaleOrderItemDO> saleOrderItemList = saleOrderService.getSaleOrderItemListByOrderId(id); | ||||||
|  |         Map<Long, ErpProductRespVO> 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") |     @GetMapping("/page") | ||||||
|     @Operation(summary = "获得ERP 销售订单分页") |     @Operation(summary = "获得销售订单分页") | ||||||
|     @PreAuthorize("@ss.hasPermission('erp:sale-order:query')") |     @PreAuthorize("@ss.hasPermission('erp:stock-out:query')") | ||||||
|     public CommonResult<PageResult<ErpSaleOrderRespVO>> getSaleOrderPage(@Valid ErpSaleOrderPageReqVO pageReqVO) { |     public CommonResult<PageResult<ErpSaleOrderRespVO>> getSaleOrderPage(@Valid ErpSaleOrderPageReqVO pageReqVO) { | ||||||
|         PageResult<ErpSaleOrderDO> pageResult = saleOrderService.getSaleOrderPage(pageReqVO); |         PageResult<ErpSaleOrderDO> pageResult = saleOrderService.getSaleOrderPage(pageReqVO); | ||||||
|         return success(BeanUtils.toBean(pageResult, ErpSaleOrderRespVO.class)); |         return success(buildSaleOrderVOPageResult(pageResult)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // TODO 芋艿:待 review |  | ||||||
|     @GetMapping("/export-excel") |     @GetMapping("/export-excel") | ||||||
|     @Operation(summary = "导出ERP 销售订单 Excel") |     @Operation(summary = "导出销售订单 Excel") | ||||||
|     @PreAuthorize("@ss.hasPermission('erp:sale-order:export')") |     @PreAuthorize("@ss.hasPermission('erp:stock-out:export')") | ||||||
|     @OperateLog(type = EXPORT) |     @OperateLog(type = EXPORT) | ||||||
|     public void exportSaleOrderExcel(@Valid ErpSaleOrderPageReqVO pageReqVO, |     public void exportSaleOrderExcel(@Valid ErpSaleOrderPageReqVO pageReqVO, | ||||||
|               HttpServletResponse response) throws IOException { |                                     HttpServletResponse response) throws IOException { | ||||||
|         pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); |         pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); | ||||||
|         List<ErpSaleOrderDO> list = saleOrderService.getSaleOrderPage(pageReqVO).getList(); |         List<ErpSaleOrderRespVO> list = buildSaleOrderVOPageResult(saleOrderService.getSaleOrderPage(pageReqVO)).getList(); | ||||||
|         // 导出 Excel |         // 导出 Excel | ||||||
|         ExcelUtils.write(response, "ERP 销售订单.xls", "数据", ErpSaleOrderRespVO.class, |         ExcelUtils.write(response, "销售订单.xls", "数据", ErpSaleOrderRespVO.class, list); | ||||||
|                         BeanUtils.toBean(list, ErpSaleOrderRespVO.class)); |     } | ||||||
|  |  | ||||||
|  |     private PageResult<ErpSaleOrderRespVO> buildSaleOrderVOPageResult(PageResult<ErpSaleOrderDO> pageResult) { | ||||||
|  |         if (CollUtil.isEmpty(pageResult.getList())) { | ||||||
|  |             return PageResult.empty(pageResult.getTotal()); | ||||||
|  |         } | ||||||
|  |         // 1.1 出库项 | ||||||
|  |         List<ErpSaleOrderItemDO> saleOrderItemList = saleOrderService.getSaleOrderItemListByOrderIds( | ||||||
|  |                 convertSet(pageResult.getList(), ErpSaleOrderDO::getId)); | ||||||
|  |         Map<Long, List<ErpSaleOrderItemDO>> saleOrderItemMap = convertMultiMap(saleOrderItemList, ErpSaleOrderItemDO::getOrderId); | ||||||
|  |         // 1.2 商品信息 | ||||||
|  |         Map<Long, ErpProductRespVO> productMap = productService.getProductVOMap( | ||||||
|  |                 convertSet(saleOrderItemList, ErpSaleOrderItemDO::getProductId)); | ||||||
|  |         // 1.3 客户信息 | ||||||
|  |         Map<Long, ErpCustomerDO> customerMap = customerService.getCustomerMap( | ||||||
|  |                 convertSet(pageResult.getList(), ErpSaleOrderDO::getCustomerId)); | ||||||
|  |         // 1.4 管理员信息 | ||||||
|  |         Map<Long, AdminUserRespDTO> 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())); | ||||||
|  |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -17,6 +17,19 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ | |||||||
| @ToString(callSuper = true) | @ToString(callSuper = true) | ||||||
| public class ErpSaleOrderPageReqVO extends PageParam { | 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") |     @Schema(description = "销售单编号", example = "XS001") | ||||||
|     private String no; |     private String no; | ||||||
|  |  | ||||||
| @@ -28,7 +41,7 @@ public class ErpSaleOrderPageReqVO extends PageParam { | |||||||
|     private LocalDateTime[] orderTime; |     private LocalDateTime[] orderTime; | ||||||
|  |  | ||||||
|     @Schema(description = "备注", example = "你猜") |     @Schema(description = "备注", example = "你猜") | ||||||
|     private String description; |     private String remark; | ||||||
|  |  | ||||||
|     @Schema(description = "销售状态", example = "2") |     @Schema(description = "销售状态", example = "2") | ||||||
|     private Integer status; |     private Integer status; | ||||||
| @@ -36,4 +49,10 @@ public class ErpSaleOrderPageReqVO extends PageParam { | |||||||
|     @Schema(description = "创建者") |     @Schema(description = "创建者") | ||||||
|     private String creator; |     private String creator; | ||||||
|  |  | ||||||
|  |     @Schema(description = "产品编号", example = "1") | ||||||
|  |     private Long productId; | ||||||
|  |  | ||||||
|  |     @Schema(description = "入库状态", example = "2") | ||||||
|  |     private Integer inStatus; | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -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.ExcelIgnoreUnannotated; | ||||||
| import com.alibaba.excel.annotation.ExcelProperty; | import com.alibaba.excel.annotation.ExcelProperty; | ||||||
| import io.swagger.v3.oas.annotations.media.Schema; | import io.swagger.v3.oas.annotations.media.Schema; | ||||||
|  | import jakarta.validation.constraints.NotNull; | ||||||
| import lombok.Data; | import lombok.Data; | ||||||
|  |  | ||||||
| import java.math.BigDecimal; | import java.math.BigDecimal; | ||||||
| import java.time.LocalDateTime; | import java.time.LocalDateTime; | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
| // TODO 芋艿:导出最后搞 |  | ||||||
| @Schema(description = "管理后台 - ERP 销售订单 Response VO") | @Schema(description = "管理后台 - ERP 销售订单 Response VO") | ||||||
| @Data | @Data | ||||||
| @ExcelIgnoreUnannotated | @ExcelIgnoreUnannotated | ||||||
| @@ -23,56 +24,103 @@ public class ErpSaleOrderRespVO { | |||||||
|     private String no; |     private String no; | ||||||
|  |  | ||||||
|     @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1724") |     @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1724") | ||||||
|     @ExcelProperty("客户编号") |  | ||||||
|     private Long customerId; |     private Long customerId; | ||||||
|  |     @Schema(description = "客户名称", example = "芋道") | ||||||
|  |     @ExcelProperty("客户名称") | ||||||
|  |     private String customerName; | ||||||
|  |  | ||||||
|     @Schema(description = "下单时间", requiredMode = Schema.RequiredMode.REQUIRED) |     @Schema(description = "下单时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||||||
|     @ExcelProperty("下单时间") |     @ExcelProperty("下单时间") | ||||||
|     private LocalDateTime orderTime; |     private LocalDateTime orderTime; | ||||||
|  |  | ||||||
|     // TODO 芋艿:example 后面 |     @Schema(description = "销售员编号", example = "1888") | ||||||
|     @Schema(description = "销售员编号数组") |     private Long saleUserId; | ||||||
|     @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 = "结算账户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "311.89") |     @Schema(description = "结算账户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "311.89") | ||||||
|     @ExcelProperty("结算账户编号") |     @ExcelProperty("结算账户编号") | ||||||
|     private Long accountId; |     private Long accountId; | ||||||
|  |  | ||||||
|     @Schema(description = "备注", example = "你猜") |     @Schema(description = "合计产品价格,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") | ||||||
|     @ExcelProperty("备注") |     private BigDecimal totalProductPrice; | ||||||
|     private String description; |  | ||||||
|  |     @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") |     @Schema(description = "销售状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||||||
|     @ExcelProperty("销售状态") |     @ExcelProperty("销售状态") | ||||||
|     private Integer status; |     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) |     @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||||||
|     @ExcelProperty("创建时间") |     @ExcelProperty("创建时间") | ||||||
|     private LocalDateTime createTime; |     private LocalDateTime createTime; | ||||||
|  |  | ||||||
|  |     @Schema(description = "订单项列表", requiredMode = Schema.RequiredMode.REQUIRED) | ||||||
|  |     private List<Item> 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; // 该字段仅仅在“详情”和“编辑”时使用 | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -28,26 +28,16 @@ public class ErpSaleOrderSaveReqVO { | |||||||
|     @NotNull(message = "下单时间不能为空") |     @NotNull(message = "下单时间不能为空") | ||||||
|     private LocalDateTime orderTime; |     private LocalDateTime orderTime; | ||||||
|  |  | ||||||
|     @Schema(description = "销售员编号数组") |     @Schema(description = "销售员编号", example = "1888") | ||||||
|     private List<Long> salePersonIds; |     private Long saleUserId; | ||||||
|  |  | ||||||
|     @Schema(description = "合计价格,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "26094") |     @Schema(description = "结算账户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31189") | ||||||
|     @NotNull(message = "合计价格,单位:元不能为空") |     @NotNull(message = "结算账户编号不能为空") | ||||||
|     private BigDecimal totalPrice; |     private Long accountId; | ||||||
|  |  | ||||||
|     @Schema(description = "优惠率,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "99.88") |     @Schema(description = "优惠率,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "99.88") | ||||||
|     @NotNull(message = "优惠率,百分比不能为空") |  | ||||||
|     private BigDecimal discountPercent; |     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") |     @Schema(description = "定金金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") | ||||||
|     @NotNull(message = "定金金额,单位:元不能为空") |     @NotNull(message = "定金金额,单位:元不能为空") | ||||||
|     private BigDecimal depositPrice; |     private BigDecimal depositPrice; | ||||||
| @@ -55,73 +45,38 @@ public class ErpSaleOrderSaveReqVO { | |||||||
|     @Schema(description = "附件地址", example = "https://www.iocoder.cn") |     @Schema(description = "附件地址", example = "https://www.iocoder.cn") | ||||||
|     private String fileUrl; |     private String fileUrl; | ||||||
|  |  | ||||||
|     @Schema(description = "结算账户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31189") |  | ||||||
|     @NotNull(message = "结算账户编号不能为空") |  | ||||||
|     private Long accountId; |  | ||||||
|  |  | ||||||
|     @Schema(description = "备注", example = "你猜") |     @Schema(description = "备注", example = "你猜") | ||||||
|     private String description; |     private String remark; | ||||||
|  |  | ||||||
|     // TODO 芋艿:后面删除 |     @Schema(description = "订单清单列表") | ||||||
| //    @Schema(description = "销售状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") |     private List<Item> items; | ||||||
| //    @NotNull(message = "销售状态不能为空") |  | ||||||
| //    private Integer status; |  | ||||||
|  |  | ||||||
|     @Schema(description = "ERP 销售订单明细列表") |  | ||||||
|     private List<Item> salesOrderItems; |  | ||||||
|  |  | ||||||
|     @Schema(description = "管理后台 - ERP 销售订单明细新增/修改 Request VO") |  | ||||||
|     @Data |     @Data | ||||||
|     public class Item { |     public static class Item { | ||||||
|  |  | ||||||
|         @Schema(description = "编号", example = "20704") |         @Schema(description = "订单项编号", example = "11756") | ||||||
|         private Long id; |         private Long id; | ||||||
|  |  | ||||||
|         // TODO 芋艿:后面删除 |         @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") | ||||||
| //        @Schema(description = "销售订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "30765") |         @NotNull(message = "产品编号不能为空") | ||||||
| //        @NotNull(message = "销售订单编号不能为空") |         private Long productId; | ||||||
| //        private Long orderId; |  | ||||||
|  |  | ||||||
| //        @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "5574") |         @Schema(description = "产品单位单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") | ||||||
| //        @NotNull(message = "商品 SPU 编号不能为空") |         @NotNull(message = "产品单位单位不能为空") | ||||||
| //        private Long productSpuId; |         private Long productUnitId; | ||||||
|  |  | ||||||
|         @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "21273") |         @Schema(description = "产品单价", example = "100.00") | ||||||
|         @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 = "商品单价不能为空") |  | ||||||
|         private BigDecimal productPrice; |         private BigDecimal productPrice; | ||||||
|  |  | ||||||
|         @Schema(description = "数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "22100") |         @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") | ||||||
|         @NotNull(message = "数量不能为空") |         @NotNull(message = "产品数量不能为空") | ||||||
|         private Integer count; |         private BigDecimal count; | ||||||
|  |  | ||||||
|         // TODO 芋艿:后面删除 |         @Schema(description = "税率,百分比", example = "99.88") | ||||||
| //        @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 = "税率,百分比不能为空") |  | ||||||
|         private BigDecimal taxPercent; |         private BigDecimal taxPercent; | ||||||
|  |  | ||||||
|         @Schema(description = "税额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "15791") |         @Schema(description = "备注", example = "随便") | ||||||
|         @NotNull(message = "税额,单位:元不能为空") |         private String remark; | ||||||
|         private BigDecimal taxPrice; |  | ||||||
|  |  | ||||||
|         // TODO 芋艿:后面删除 |  | ||||||
| //        @Schema(description = "支付金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "21930") |  | ||||||
| //        @NotNull(message = "支付金额,单位:元不能为空") |  | ||||||
| //        private BigDecimal payPrice; |  | ||||||
|  |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,24 +1,20 @@ | |||||||
| package cn.iocoder.yudao.module.erp.dal.dataobject.sale; | 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.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.KeySequence; | ||||||
| import com.baomidou.mybatisplus.annotation.TableField; |  | ||||||
| import com.baomidou.mybatisplus.annotation.TableId; | import com.baomidou.mybatisplus.annotation.TableId; | ||||||
| import com.baomidou.mybatisplus.annotation.TableName; | import com.baomidou.mybatisplus.annotation.TableName; | ||||||
| import lombok.*; | import lombok.*; | ||||||
|  |  | ||||||
| import java.math.BigDecimal; | import java.math.BigDecimal; | ||||||
| import java.time.LocalDateTime; | import java.time.LocalDateTime; | ||||||
| import java.util.List; |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * ERP 销售订单 DO |  * ERP 销售订单 DO | ||||||
|  * |  * | ||||||
|  * @author 芋道源码 |  * @author 芋道源码 | ||||||
|  */ |  */ | ||||||
| @TableName(value = "erp_sale_order", autoResultMap = true) | @TableName(value = "erp_sale_order") | ||||||
| @KeySequence("erp_sale_order_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 | @KeySequence("erp_sale_order_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 | ||||||
| @Data | @Data | ||||||
| @EqualsAndHashCode(callSuper = true) | @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; |     private Integer status; | ||||||
|     /** |     /** | ||||||
|      * 客户编号 |      * 客户编号 | ||||||
|      * |      * | ||||||
|      * TODO 芋艿:关联 |      * 关联 {@link ErpCustomerDO#getId()} | ||||||
|      */ |      */ | ||||||
|     private Long customerId; |     private Long customerId; | ||||||
|     /** |     /** | ||||||
| @@ -56,33 +52,45 @@ public class ErpSaleOrderDO extends BaseDO { | |||||||
|      */ |      */ | ||||||
|     private Long accountId; |     private Long accountId; | ||||||
|     /** |     /** | ||||||
|      * 销售员编号数组 |      * 销售员编号 | ||||||
|      * |      * | ||||||
|      * TODO 芋艿:关联 |      * 关联 AdminUserDO 的 id 字段 | ||||||
|      */ |      */ | ||||||
|     @TableField(typeHandler = LongListTypeHandler.class) |     private Long saleUserId; | ||||||
|     private List<Long> salePersonIds; |  | ||||||
|     /** |     /** | ||||||
|      * 下单时间 |      * 下单时间 | ||||||
|      */ |      */ | ||||||
|     private LocalDateTime orderTime; |     private LocalDateTime orderTime; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 合计价格,单位:元 |      * 合计数量 | ||||||
|  |      */ | ||||||
|  |     private BigDecimal totalCount; | ||||||
|  |     /** | ||||||
|  |      * 最终合计价格,单位:元 | ||||||
|  |      * | ||||||
|  |      * totalPrice = totalProductPrice + totalTaxPrice - discountPrice | ||||||
|      */ |      */ | ||||||
|     private BigDecimal totalPrice; |     private BigDecimal totalPrice; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 合计产品价格,单位:元 | ||||||
|  |      */ | ||||||
|  |     private BigDecimal totalProductPrice; | ||||||
|  |     /** | ||||||
|  |      * 合计税额,单位:元 | ||||||
|  |      */ | ||||||
|  |     private BigDecimal totalTaxPrice; | ||||||
|     /** |     /** | ||||||
|      * 优惠率,百分比 |      * 优惠率,百分比 | ||||||
|      */ |      */ | ||||||
|     private BigDecimal discountPercent; |     private BigDecimal discountPercent; | ||||||
|     /** |     /** | ||||||
|      * 优惠金额,单位:元 |      * 优惠金额,单位:元 | ||||||
|  |      * | ||||||
|  |      * discountPrice = (totalProductPrice + totalTaxPrice) * discountPercent | ||||||
|      */ |      */ | ||||||
|     private BigDecimal discountPrice; |     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; | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -1,6 +1,7 @@ | |||||||
| package cn.iocoder.yudao.module.erp.dal.dataobject.sale; | 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.dataobject.BaseDO; | ||||||
|  | import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; | ||||||
| import com.baomidou.mybatisplus.annotation.KeySequence; | import com.baomidou.mybatisplus.annotation.KeySequence; | ||||||
| import com.baomidou.mybatisplus.annotation.TableId; | import com.baomidou.mybatisplus.annotation.TableId; | ||||||
| import com.baomidou.mybatisplus.annotation.TableName; | import com.baomidou.mybatisplus.annotation.TableName; | ||||||
| @@ -13,15 +14,15 @@ import java.math.BigDecimal; | |||||||
|  * |  * | ||||||
|  * @author 芋道源码 |  * @author 芋道源码 | ||||||
|  */ |  */ | ||||||
| @TableName("erp_sales_order_items") | @TableName("erp_sale_order_items") | ||||||
| @KeySequence("erp_sales_order_items_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 | @KeySequence("erp_sale_order_items_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 | ||||||
| @Data | @Data | ||||||
| @EqualsAndHashCode(callSuper = true) | @EqualsAndHashCode(callSuper = true) | ||||||
| @ToString(callSuper = true) | @ToString(callSuper = true) | ||||||
| @Builder | @Builder | ||||||
| @NoArgsConstructor | @NoArgsConstructor | ||||||
| @AllArgsConstructor | @AllArgsConstructor | ||||||
| public class ErpSalesOrderItemDO extends BaseDO { | public class ErpSaleOrderItemDO extends BaseDO { | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * 编号 |      * 编号 | ||||||
| @@ -36,53 +37,58 @@ public class ErpSalesOrderItemDO extends BaseDO { | |||||||
|     private Long orderId; |     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 BigDecimal productPrice; | ||||||
| 
 |  | ||||||
|     /** |     /** | ||||||
|      * 数量 |      * 数量 | ||||||
|      */ |      */ | ||||||
|     private Integer count; |     private BigDecimal count; | ||||||
|     /** |     /** | ||||||
|      * 总价 |      * 总价,单位:元 | ||||||
|  |      * | ||||||
|  |      * totalPrice = productPrice * count | ||||||
|      */ |      */ | ||||||
|     private BigDecimal totalPrice; |     private BigDecimal totalPrice; | ||||||
|     /** |  | ||||||
|      * 备注 |  | ||||||
|      */ |  | ||||||
|     private String description; |  | ||||||
|     /** |     /** | ||||||
|      * 税率,百分比 |      * 税率,百分比 | ||||||
|      */ |      */ | ||||||
|     private BigDecimal taxPercent; |     private BigDecimal taxPercent; | ||||||
|     /** |     /** | ||||||
|      * 税额,单位:元 |      * 税额,单位:元 | ||||||
|  |      * | ||||||
|  |      * taxPrice = totalPrice * taxPercent | ||||||
|      */ |      */ | ||||||
|     private BigDecimal taxPrice; |     private BigDecimal taxPrice; | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * 支付金额,单位:元 |      * 备注 | ||||||
|      */ |      */ | ||||||
|     private BigDecimal payPrice; |     private String remark; | ||||||
|  | 
 | ||||||
|  |     // ========== 销售入库 ========== | ||||||
|  |     /** | ||||||
|  |      * 销售入库数量 | ||||||
|  |      */ | ||||||
|  |     private BigDecimal inCount; | ||||||
|  | 
 | ||||||
|  |     // ========== 销售退货(出库)) ========== | ||||||
|  |     /** | ||||||
|  |      * 销售退货数量 | ||||||
|  |      */ | ||||||
|  |     private BigDecimal returnCount; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| @@ -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<ErpSaleOrderItemDO> { | ||||||
|  |  | ||||||
|  |     default List<ErpSaleOrderItemDO> selectListByOrderId(Long orderId) { | ||||||
|  |         return selectList(ErpSaleOrderItemDO::getOrderId, orderId); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     default List<ErpSaleOrderItemDO> selectListByOrderIds(Collection<Long> orderIds) { | ||||||
|  |         return selectList(ErpSaleOrderItemDO::getOrderId, orderIds); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     default int deleteByOrderId(Long orderId) { | ||||||
|  |         return delete(ErpSaleOrderItemDO::getOrderId, orderId); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -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.common.pojo.PageResult; | ||||||
| import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | 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.controller.admin.sale.vo.order.ErpSaleOrderPageReqVO; | ||||||
| import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderDO; | 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; | import org.apache.ibatis.annotations.Mapper; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -17,14 +19,29 @@ import org.apache.ibatis.annotations.Mapper; | |||||||
| public interface ErpSaleOrderMapper extends BaseMapperX<ErpSaleOrderDO> { | public interface ErpSaleOrderMapper extends BaseMapperX<ErpSaleOrderDO> { | ||||||
|  |  | ||||||
|     default PageResult<ErpSaleOrderDO> selectPage(ErpSaleOrderPageReqVO reqVO) { |     default PageResult<ErpSaleOrderDO> selectPage(ErpSaleOrderPageReqVO reqVO) { | ||||||
|         return selectPage(reqVO, new LambdaQueryWrapperX<ErpSaleOrderDO>() |         MPJLambdaWrapperX<ErpSaleOrderDO> query = new MPJLambdaWrapperX<ErpSaleOrderDO>() | ||||||
|                 .likeIfPresent(ErpSaleOrderDO::getNo, reqVO.getNo()) |                 .eqIfPresent(ErpSaleOrderDO::getNo, reqVO.getNo()) | ||||||
|                 .eqIfPresent(ErpSaleOrderDO::getCustomerId, reqVO.getCustomerId()) |                 .eqIfPresent(ErpSaleOrderDO::getCustomerId, reqVO.getCustomerId()) | ||||||
|                 .betweenIfPresent(ErpSaleOrderDO::getOrderTime, reqVO.getOrderTime()) |                 .betweenIfPresent(ErpSaleOrderDO::getOrderTime, reqVO.getOrderTime()) | ||||||
|                 .eqIfPresent(ErpSaleOrderDO::getDescription, reqVO.getDescription()) |  | ||||||
|                 .eqIfPresent(ErpSaleOrderDO::getStatus, reqVO.getStatus()) |                 .eqIfPresent(ErpSaleOrderDO::getStatus, reqVO.getStatus()) | ||||||
|  |                 .likeIfPresent(ErpSaleOrderDO::getRemark, reqVO.getRemark()) | ||||||
|                 .eqIfPresent(ErpSaleOrderDO::getCreator, reqVO.getCreator()) |                 .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<ErpSaleOrderDO>() | ||||||
|  |                 .eq(ErpSaleOrderDO::getId, id).eq(ErpSaleOrderDO::getStatus, status)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     default ErpSaleOrderDO selectByNo(String no) { | ||||||
|  |         return selectOne(ErpSaleOrderDO::getNo, no); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -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<ErpSalesOrderItemDO> { |  | ||||||
|  |  | ||||||
|     default List<ErpSalesOrderItemDO> selectListById(Long id) { |  | ||||||
|         return selectList(ErpSalesOrderItemDO::getId, id); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     default int deleteById(Long id) { |  | ||||||
|         return delete(ErpSalesOrderItemDO::getId, id); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,14 +1,19 @@ | |||||||
| package cn.iocoder.yudao.module.erp.dal.mysql.stock; | 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.common.pojo.PageResult; | ||||||
| import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | 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.LambdaQueryWrapperX; | ||||||
| import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stock.ErpStockPageReqVO; | import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stock.ErpStockPageReqVO; | ||||||
| import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; | import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; | ||||||
|  | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | ||||||
| import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | ||||||
| import org.apache.ibatis.annotations.Mapper; | import org.apache.ibatis.annotations.Mapper; | ||||||
|  |  | ||||||
| import java.math.BigDecimal; | import java.math.BigDecimal; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * ERP 产品库存 Mapper |  * ERP 产品库存 Mapper | ||||||
| @@ -37,11 +42,23 @@ public interface ErpStockMapper extends BaseMapperX<ErpStockDO> { | |||||||
|             updateWrapper.setSql("count = count + " + count); |             updateWrapper.setSql("count = count + " + count); | ||||||
|         } else if (count.compareTo(BigDecimal.ZERO) < 0) { |         } else if (count.compareTo(BigDecimal.ZERO) < 0) { | ||||||
|             if (!negativeEnable) { |             if (!negativeEnable) { | ||||||
|                 updateWrapper.gt(ErpStockDO::getCount, count.abs()); |                 updateWrapper.ge(ErpStockDO::getCount, count.abs()); | ||||||
|             } |             } | ||||||
|             updateWrapper.setSql("count = count - " + count.abs()); |             updateWrapper.setSql("count = count - " + count.abs()); | ||||||
|         } |         } | ||||||
|         return update(null, updateWrapper); |         return update(null, updateWrapper); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     default BigDecimal selectSumByProductId(Long productId) { | ||||||
|  |         // SQL sum 查询 | ||||||
|  |         List<Map<String, Object>> result = selectMaps(new QueryWrapper<ErpStockDO>() | ||||||
|  |                 .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)); | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -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.ErpSaleOrderPageReqVO; | ||||||
| import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderSaveReqVO; | 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.ErpSaleOrderDO; | ||||||
|  | import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderItemDO; | ||||||
| import jakarta.validation.Valid; | import jakarta.validation.Valid; | ||||||
|  |  | ||||||
|  | import java.util.Collection; | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * ERP 销售订单 Service 接口 |  * ERP 销售订单 Service 接口 | ||||||
|  * |  * | ||||||
| @@ -14,7 +18,7 @@ import jakarta.validation.Valid; | |||||||
| public interface ErpSaleOrderService { | public interface ErpSaleOrderService { | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 创建ERP 销售订单 |      * 创建销售订单 | ||||||
|      * |      * | ||||||
|      * @param createReqVO 创建信息 |      * @param createReqVO 创建信息 | ||||||
|      * @return 编号 |      * @return 编号 | ||||||
| @@ -22,33 +26,59 @@ public interface ErpSaleOrderService { | |||||||
|     Long createSaleOrder(@Valid ErpSaleOrderSaveReqVO createReqVO); |     Long createSaleOrder(@Valid ErpSaleOrderSaveReqVO createReqVO); | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 更新ERP 销售订单 |      * 更新销售订单 | ||||||
|      * |      * | ||||||
|      * @param updateReqVO 更新信息 |      * @param updateReqVO 更新信息 | ||||||
|      */ |      */ | ||||||
|     void updateSaleOrder(@Valid ErpSaleOrderSaveReqVO updateReqVO); |     void updateSaleOrder(@Valid ErpSaleOrderSaveReqVO updateReqVO); | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 删除ERP 销售订单 |      * 更新销售订单的状态 | ||||||
|      * |      * | ||||||
|      * @param id 编号 |      * @param id 编号 | ||||||
|  |      * @param status 状态 | ||||||
|      */ |      */ | ||||||
|     void deleteSaleOrder(Long id); |     void updateSaleOrderStatus(Long id, Integer status); | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 获得ERP 销售订单 |      * 删除销售订单 | ||||||
|  |      * | ||||||
|  |      * @param ids 编号数组 | ||||||
|  |      */ | ||||||
|  |     void deleteSaleOrder(List<Long> ids); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获得销售订单 | ||||||
|      * |      * | ||||||
|      * @param id 编号 |      * @param id 编号 | ||||||
|      * @return ERP 销售订单 |      * @return 销售订单 | ||||||
|      */ |      */ | ||||||
|     ErpSaleOrderDO getSaleOrder(Long id); |     ErpSaleOrderDO getSaleOrder(Long id); | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 获得ERP 销售订单分页 |      * 获得销售订单分页 | ||||||
|      * |      * | ||||||
|      * @param pageReqVO 分页查询 |      * @param pageReqVO 分页查询 | ||||||
|      * @return ERP 销售订单分页 |      * @return 销售订单分页 | ||||||
|      */ |      */ | ||||||
|     PageResult<ErpSaleOrderDO> getSaleOrderPage(ErpSaleOrderPageReqVO pageReqVO); |     PageResult<ErpSaleOrderDO> getSaleOrderPage(ErpSaleOrderPageReqVO pageReqVO); | ||||||
|  |  | ||||||
|  |     // ==================== 销售订单项 ==================== | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获得销售订单项列表 | ||||||
|  |      * | ||||||
|  |      * @param orderId 销售订单编号 | ||||||
|  |      * @return 销售订单项列表 | ||||||
|  |      */ | ||||||
|  |     List<ErpSaleOrderItemDO> getSaleOrderItemListByOrderId(Long orderId); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获得销售订单项 List | ||||||
|  |      * | ||||||
|  |      * @param orderIds 销售订单编号数组 | ||||||
|  |      * @return 销售订单项 List | ||||||
|  |      */ | ||||||
|  |     List<ErpSaleOrderItemDO> getSaleOrderItemListByOrderIds(Collection<Long> orderIds); | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -1,23 +1,36 @@ | |||||||
| package cn.iocoder.yudao.module.erp.service.sale; | 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.pojo.PageResult; | ||||||
|  | import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; | ||||||
| import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 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.ErpSaleOrderPageReqVO; | ||||||
| import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderSaveReqVO; | 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.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.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 jakarta.annotation.Resource; | ||||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||||
| import org.springframework.transaction.annotation.Transactional; | import org.springframework.transaction.annotation.Transactional; | ||||||
| import org.springframework.validation.annotation.Validated; | 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.List; | ||||||
|  | import java.util.Map; | ||||||
|  |  | ||||||
| import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 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.*; | import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; | ||||||
|  |  | ||||||
|  | // TODO 芋艿:记录操作日志 | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * ERP 销售订单 Service 实现类 |  * ERP 销售订单 Service 实现类 | ||||||
|  * |  * | ||||||
| @@ -30,61 +43,142 @@ public class ErpSaleOrderServiceImpl implements ErpSaleOrderService { | |||||||
|     @Resource |     @Resource | ||||||
|     private ErpSaleOrderMapper saleOrderMapper; |     private ErpSaleOrderMapper saleOrderMapper; | ||||||
|     @Resource |     @Resource | ||||||
|     private ErpSalesOrderItemMapper salesOrderItemMapper; |     private ErpSaleOrderItemMapper saleOrderItemMapper; | ||||||
|  |  | ||||||
|  |     @Resource | ||||||
|  |     private ErpNoRedisDAO noRedisDAO; | ||||||
|  |  | ||||||
|  |     @Resource | ||||||
|  |     private ErpProductService productService; | ||||||
|  |     @Resource | ||||||
|  |     private ErpCustomerService customerService; | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     @Transactional(rollbackFor = Exception.class) |     @Transactional(rollbackFor = Exception.class) | ||||||
|     public Long createSaleOrder(ErpSaleOrderSaveReqVO createReqVO) { |     public Long createSaleOrder(ErpSaleOrderSaveReqVO createReqVO) { | ||||||
|         // 插入 |         // 1.1 校验订单项的有效性 | ||||||
|         ErpSaleOrderDO saleOrder = BeanUtils.toBean(createReqVO, ErpSaleOrderDO.class); |         List<ErpSaleOrderItemDO> 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); |         saleOrderMapper.insert(saleOrder); | ||||||
|  |         // 2.2 插入订单项 | ||||||
|         // 插入子表 |         saleOrderItems.forEach(o -> o.setOrderId(saleOrder.getId())); | ||||||
| //        createSalesOrderItemsList(saleOrder.getId(), createReqVO.getSalesOrderItems()); |         saleOrderItemMapper.insertBatch(saleOrderItems); | ||||||
|         // 返回 |  | ||||||
|         return saleOrder.getId(); |         return saleOrder.getId(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private void createSalesOrderItemsList(Long id, List<ErpSalesOrderItemDO> list) { |  | ||||||
|         list.forEach(o -> o.setId(id)); |  | ||||||
|         salesOrderItemMapper.insertBatch(list); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     @Transactional(rollbackFor = Exception.class) |     @Transactional(rollbackFor = Exception.class) | ||||||
|     public void updateSaleOrder(ErpSaleOrderSaveReqVO updateReqVO) { |     public void updateSaleOrder(ErpSaleOrderSaveReqVO updateReqVO) { | ||||||
|         // 校验存在 |         // 1.1 校验存在 | ||||||
|         validateSaleOrderExists(updateReqVO.getId()); |         ErpSaleOrderDO saleOrder = validateSaleOrderExists(updateReqVO.getId()); | ||||||
|         // 更新 |         if (ErpAuditStatus.APPROVE.getStatus().equals(saleOrder.getStatus())) { | ||||||
|         ErpSaleOrderDO updateObj = BeanUtils.toBean(updateReqVO, ErpSaleOrderDO.class); |             throw exception(STOCK_MOVE_UPDATE_FAIL_APPROVE, saleOrder.getNo()); | ||||||
|  |         } | ||||||
|  |         // 1.2 校验客户 | ||||||
|  |         customerService.validateCustomer(updateReqVO.getCustomerId()); | ||||||
|  |         // 1.3 校验订单项的有效性 | ||||||
|  |         List<ErpSaleOrderItemDO> 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); |         saleOrderMapper.updateById(updateObj); | ||||||
|  |         // 2.2 更新订单项 | ||||||
|         // 更新子表 |         updateSaleOrderItemList(updateReqVO.getId(), saleOrderItems); | ||||||
| //        updateSalesOrderItemsList(updateReqVO.getId(), updateReqVO.getSalesOrderItems()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void updateSalesOrderItemsList(Long id, List<ErpSalesOrderItemDO> list) { |  | ||||||
|         deleteSalesOrderItemsById(id); |  | ||||||
|         list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下:1)id 冲突;2)updateTime 不更新 |  | ||||||
|         createSalesOrderItemsList(id, list); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     @Transactional(rollbackFor = Exception.class) |     @Transactional(rollbackFor = Exception.class) | ||||||
|     public void deleteSaleOrder(Long id) { |     public void updateSaleOrderStatus(Long id, Integer status) { | ||||||
|         // 校验存在 |         boolean approve = ErpAuditStatus.APPROVE.getStatus().equals(status); | ||||||
|         validateSaleOrderExists(id); |         // 1.1 校验存在 | ||||||
|         // 删除 |         ErpSaleOrderDO saleOrder = validateSaleOrderExists(id); | ||||||
|         saleOrderMapper.deleteById(id); |         // 1.2 校验状态 | ||||||
|  |         if (saleOrder.getStatus().equals(status)) { | ||||||
|  |             throw exception(approve ? STOCK_MOVE_APPROVE_FAIL : STOCK_MOVE_PROCESS_FAIL); | ||||||
|  |         } | ||||||
|  |         // TODO @芋艿:需要校验是不是有入库、有退货 | ||||||
|  |  | ||||||
|         // 删除子表 |         // 2. 更新状态 | ||||||
|         deleteSalesOrderItemsById(id); |         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) { |     private List<ErpSaleOrderItemDO> validateSaleOrderItems(List<ErpSaleOrderSaveReqVO.Item> list) { | ||||||
|         if (saleOrderMapper.selectById(id) == null) { |         // 1. 校验产品存在 | ||||||
|             throw exception(SALE_ORDER_NOT_EXISTS); |         List<ErpProductDO> productList = productService.validProductList( | ||||||
|  |                 convertSet(list, ErpSaleOrderSaveReqVO.Item::getProductId)); | ||||||
|  |         Map<Long, ErpProductDO> 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<ErpSaleOrderItemDO> newList) { | ||||||
|  |         // 第一步,对比新老数据,获得添加、修改、删除的列表 | ||||||
|  |         List<ErpSaleOrderItemDO> oldList = saleOrderItemMapper.selectListByOrderId(id); | ||||||
|  |         List<List<ErpSaleOrderItemDO>> 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<Long> ids) { | ||||||
|  |         // 1. 校验不处于已审批 | ||||||
|  |         List<ErpSaleOrderDO> 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 |     @Override | ||||||
| @@ -97,10 +191,19 @@ public class ErpSaleOrderServiceImpl implements ErpSaleOrderService { | |||||||
|         return saleOrderMapper.selectPage(pageReqVO); |         return saleOrderMapper.selectPage(pageReqVO); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // ==================== 子表(ERP 销售订单明细) ==================== |     // ==================== 订单项 ==================== | ||||||
|  |  | ||||||
|     private void deleteSalesOrderItemsById(Long id) { |     @Override | ||||||
|         salesOrderItemMapper.deleteById(id); |     public List<ErpSaleOrderItemDO> getSaleOrderItemListByOrderId(Long moveId) { | ||||||
|  |         return saleOrderItemMapper.selectListByOrderId(moveId); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public List<ErpSaleOrderItemDO> getSaleOrderItemListByOrderIds(Collection<Long> moveIds) { | ||||||
|  |         if (CollUtil.isEmpty(moveIds)) { | ||||||
|  |             return Collections.emptyList(); | ||||||
|  |         } | ||||||
|  |         return saleOrderItemMapper.selectListByOrderIds(moveIds); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -30,6 +30,14 @@ public interface ErpStockService { | |||||||
|      */ |      */ | ||||||
|     ErpStockDO getStock(Long productId, Long warehouseId); |     ErpStockDO getStock(Long productId, Long warehouseId); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获得产品库存数量 | ||||||
|  |      * | ||||||
|  |      * @param productId 产品编号 | ||||||
|  |      * @return 产品库存数量 | ||||||
|  |      */ | ||||||
|  |     BigDecimal getStockCount(Long productId); | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 获得产品库存分页 |      * 获得产品库存分页 | ||||||
|      * |      * | ||||||
|   | |||||||
| @@ -49,6 +49,11 @@ public class ErpStockServiceImpl implements ErpStockService { | |||||||
|         return stockMapper.selectByProductIdAndWarehouseId(productId, warehouseId); |         return stockMapper.selectByProductIdAndWarehouseId(productId, warehouseId); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public BigDecimal getStockCount(Long productId) { | ||||||
|  |         return stockMapper.selectSumByProductId(productId); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public PageResult<ErpStockDO> getStockPage(ErpStockPageReqVO pageReqVO) { |     public PageResult<ErpStockDO> getStockPage(ErpStockPageReqVO pageReqVO) { | ||||||
|         return stockMapper.selectPage(pageReqVO); |         return stockMapper.selectPage(pageReqVO); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 YunaiV
					YunaiV