| | |
| | | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; |
| | | import cn.iocoder.yudao.module.crm.api.customer.CrmCustomerApi; |
| | | import cn.iocoder.yudao.module.crm.api.customer.dto.CrmCustomerRespDTO; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderItemRespVO; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderPageReqVO; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderRespVO; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderSaveReqVO; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderImportExcelVO; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderImportRespVO; |
| | | 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.sale.ErpSaleOrderService; |
| | | import cn.iocoder.yudao.module.mdm.api.item.MdmItemApi; |
| | | import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO; |
| | | import cn.iocoder.yudao.module.mdm.api.unit.MdmUnitMeasureApi; |
| | | import cn.iocoder.yudao.module.mdm.api.unit.dto.MdmUnitMeasureRespDTO; |
| | | import cn.iocoder.yudao.module.mes.api.mps.MesProMpsApi; |
| | | import cn.iocoder.yudao.module.mes.api.productsales.MesWmProductSalesLineApi; |
| | | import cn.iocoder.yudao.module.mes.api.salesnotice.MesWmSalesNoticeApi; |
| | | import cn.iocoder.yudao.module.mes.api.wms.MesWmStockApi; |
| | | import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi; |
| | | 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 org.springframework.security.access.prepost.PreAuthorize; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.*; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | |
| | | import java.io.IOException; |
| | | import java.math.BigDecimal; |
| | | import java.util.List; |
| | | import java.util.Arrays; |
| | | import java.util.Map; |
| | | |
| | | import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; |
| | | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| | | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| | | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; |
| | | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| | | |
| | |
| | | @Resource |
| | | private MesWmSalesNoticeApi salesNoticeApi; |
| | | @Resource |
| | | private MesWmProductSalesLineApi productSalesLineApi; |
| | | @Resource |
| | | private MesProMpsApi mpsApi; |
| | | @Resource |
| | | private StorageAttachmentApi storageAttachmentApi; |
| | | @Resource |
| | | private MdmUnitMeasureApi mdmUnitMeasureApi; |
| | | @Resource |
| | | private MesWmStockApi mesWmStockApi; |
| | | |
| | | @PostMapping("/create") |
| | | @Operation(summary = "创建销售订单") |
| | |
| | | return success(true); |
| | | } |
| | | |
| | | @PutMapping("/update-status") |
| | | @Operation(summary = "更新销售订单的状态") |
| | | @PostMapping("/submit") |
| | | @Operation(summary = "提交销售订单审批(协同办公)") |
| | | @PreAuthorize("@ss.hasPermission('erp:sale-order:update-status')") |
| | | public CommonResult<Boolean> updateSaleOrderStatus(@RequestParam("id") Long id, |
| | | @RequestParam("status") Integer status) { |
| | | saleOrderService.updateSaleOrderStatus(id, status); |
| | | public CommonResult<Boolean> submitSaleOrder(@RequestParam("id") Long id, |
| | | @RequestParam("processDefinitionKey") String processDefinitionKey) { |
| | | Long userId = getLoginUserId(); |
| | | saleOrderService.submitSaleOrder(id, processDefinitionKey, userId); |
| | | return success(true); |
| | | } |
| | | |
| | | @GetMapping("/approve-process-list") |
| | | @Operation(summary = "获取销售订单审批流程列表") |
| | | @PreAuthorize("@ss.hasPermission('erp:sale-order:query')") |
| | | public CommonResult<List<Map<String, Object>>> getApproveProcessList() { |
| | | return success(saleOrderService.getSaleOrderApproveProcessDefinitionList()); |
| | | } |
| | | |
| | | @PutMapping("/cancel") |
| | |
| | | return success(true); |
| | | } |
| | | |
| | | @GetMapping("/item/list-by-order-id") |
| | | @Operation(summary = "查询销售订单的物料明细列表(用于发货通知单创建)") |
| | | @Parameter(name = "orderId", description = "销售订单编号", required = true, example = "1") |
| | | @PreAuthorize("@ss.hasPermission('erp:sale-order:query')") |
| | | public CommonResult<List<ErpSaleOrderItemRespVO>> getSaleOrderItemListByOrderId(@RequestParam("orderId") Long orderId) { |
| | | List<ErpSaleOrderItemDO> itemList = saleOrderService.getSaleOrderItemListByOrderId(orderId); |
| | | Map<Long, MdmItemRespDTO> itemMap = mdmItemApi.getItemMap( |
| | | convertSet(itemList, ErpSaleOrderItemDO::getProductId)); |
| | | return success(BeanUtils.toBean(itemList, ErpSaleOrderItemRespVO.class, vo -> { |
| | | MapUtils.findAndThen(itemMap, vo.getProductId(), item -> |
| | | vo.setProductName(item.getName()).setProductBarCode(item.getBarCode())); |
| | | })); |
| | | } |
| | | |
| | | @GetMapping("/get") |
| | | @Operation(summary = "获得销售订单") |
| | | @Parameter(name = "id", description = "编号", required = true, example = "1024") |
| | |
| | | if (saleOrder == null) { |
| | | return success(null); |
| | | } |
| | | // 1. 查询订单项 |
| | | List<ErpSaleOrderItemDO> saleOrderItemList = saleOrderService.getSaleOrderItemListByOrderId(id); |
| | | // 2. 批量查询关联数据 |
| | | Map<Long, MdmItemRespDTO> itemMap = mdmItemApi.getItemMap( |
| | | convertSet(saleOrderItemList, ErpSaleOrderItemDO::getProductId)); |
| | | return success(BeanUtils.toBean(saleOrder, ErpSaleOrderRespVO.class, saleOrderVO -> |
| | | saleOrderVO.setItems(BeanUtils.toBean(saleOrderItemList, ErpSaleOrderRespVO.Item.class, item -> { |
| | | // 库存信息暂不查询(仓储物流模块) |
| | | item.setStockCount(BigDecimal.ZERO); |
| | | MapUtils.findAndThen(itemMap, item.getProductId(), mdmItem -> item.setProductName(mdmItem.getName()) |
| | | .setProductBarCode(mdmItem.getBarCode())); |
| | | })))); |
| | | Map<Long, String> batchCodeMap = productSalesLineApi.getBatchCodesBySaleOrderItemIds( |
| | | convertSet(saleOrderItemList, ErpSaleOrderItemDO::getId)); |
| | | Map<Long, MdmUnitMeasureRespDTO> unitMeasureMap = mdmUnitMeasureApi.getUnitMeasureMap( |
| | | convertSet(saleOrderItemList, ErpSaleOrderItemDO::getProductUnitId)); |
| | | // 3. 转换订单项 |
| | | List<ErpSaleOrderRespVO.Item> itemVOList = BeanUtils.toBean(saleOrderItemList, ErpSaleOrderRespVO.Item.class, item -> { |
| | | fillItemPrice(item); |
| | | item.setStockCount(mesWmStockApi.getStockQuantity(item.getProductId())); |
| | | item.setBatchCode(batchCodeMap.get(item.getId())); |
| | | MapUtils.findAndThen(itemMap, item.getProductId(), mdmItem -> |
| | | item.setProductName(mdmItem.getName()).setProductBarCode(mdmItem.getBarCode()) |
| | | .setProductSpecification(mdmItem.getSpecification())); |
| | | MapUtils.findAndThen(unitMeasureMap, item.getProductUnitId(), unit -> |
| | | item.setProductUnitName(unit.getName())); |
| | | }); |
| | | // 4. 组装响应 |
| | | ErpSaleOrderRespVO saleOrderVO = BeanUtils.toBean(saleOrder, ErpSaleOrderRespVO.class); |
| | | saleOrderVO.setItems(itemVOList); |
| | | saleOrderVO.setAttachmentList(storageAttachmentApi.listAttachments("erp_sale_order", id)); |
| | | return success(saleOrderVO); |
| | | } |
| | | |
| | | @GetMapping("/page") |
| | |
| | | ExcelUtils.write(response, "销售订单.xls", "数据", ErpSaleOrderRespVO.class, list); |
| | | } |
| | | |
| | | @GetMapping("/get-import-template") |
| | | @Operation(summary = "获得导入销售订单模板") |
| | | @PreAuthorize("@ss.hasPermission('erp:sale-order:import')") |
| | | public void importTemplate(HttpServletResponse response) throws IOException { |
| | | List<ErpSaleOrderImportExcelVO> list = Arrays.asList( |
| | | ErpSaleOrderImportExcelVO.builder() |
| | | .no("XSDD20260101000001").customerName("示例客户").contractNo("HT20260101") |
| | | .orderTime("2026-01-01 10:00:00").productCode("ITEM001").productName("示例产品A") |
| | | .count(new BigDecimal("100")).productPrice(new BigDecimal("20.00")) |
| | | .taxPercent(new BigDecimal("13")).needProduction("是").remark("示例").build()); |
| | | ExcelUtils.write(response, "销售订单导入模板.xls", "销售订单", ErpSaleOrderImportExcelVO.class, list); |
| | | } |
| | | |
| | | @PostMapping("/import") |
| | | @Operation(summary = "导入销售订单") |
| | | @PreAuthorize("@ss.hasPermission('erp:sale-order:import')") |
| | | public CommonResult<ErpSaleOrderImportRespVO> importSaleOrderExcel( |
| | | @RequestParam("file") MultipartFile file) throws Exception { |
| | | List<ErpSaleOrderImportExcelVO> list = ExcelUtils.read(file, ErpSaleOrderImportExcelVO.class); |
| | | return success(saleOrderService.importSaleOrderList(list)); |
| | | } |
| | | |
| | | private PageResult<ErpSaleOrderRespVO> buildSaleOrderVOPageResult(PageResult<ErpSaleOrderDO> pageResult) { |
| | | if (CollUtil.isEmpty(pageResult.getList())) { |
| | | return PageResult.empty(pageResult.getTotal()); |
| | |
| | | // 1.5 发货通知单信息 |
| | | Map<Long, Boolean> salesNoticeMap = salesNoticeApi.checkSalesNoticeBySaleOrderIds( |
| | | convertSet(pageResult.getList(), ErpSaleOrderDO::getId)); |
| | | // 1.6 检查是否可以生成发货通知单(需要生产的明细对应的 MPS 是否已完成) |
| | | // 1.6 出库批号 |
| | | Map<Long, String> batchCodeMap = productSalesLineApi.getBatchCodesBySaleOrderItemIds( |
| | | convertSet(saleOrderItemList, ErpSaleOrderItemDO::getId)); |
| | | // 1.7 计量单位 |
| | | Map<Long, MdmUnitMeasureRespDTO> unitMeasureMap = mdmUnitMeasureApi.getUnitMeasureMap( |
| | | convertSet(saleOrderItemList, ErpSaleOrderItemDO::getProductUnitId)); |
| | | // 1.8 检查是否可以生成发货通知单(需要生产的明细对应的 MPS 是否已完成) |
| | | // 筛选出需要生产的明细ID |
| | | List<Long> needProductionItemIds = saleOrderItemList.stream() |
| | | .filter(item -> item.getNeedProduction() != null && item.getNeedProduction() == 1) |
| | |
| | | } |
| | | // 2. 开始拼接 |
| | | return BeanUtils.toBean(pageResult, ErpSaleOrderRespVO.class, saleOrder -> { |
| | | saleOrder.setItems(BeanUtils.toBean(saleOrderItemMap.get(saleOrder.getId()), ErpSaleOrderRespVO.Item.class, |
| | | item -> MapUtils.findAndThen(itemMap, item.getProductId(), mdmItem -> item.setProductName(mdmItem.getName()) |
| | | .setProductBarCode(mdmItem.getBarCode())))); |
| | | saleOrder.setItems(BeanUtils.toBean( |
| | | saleOrderItemMap.getOrDefault(saleOrder.getId(), java.util.Collections.<ErpSaleOrderItemDO>emptyList()), |
| | | ErpSaleOrderRespVO.Item.class, |
| | | item -> { |
| | | fillItemPrice(item); |
| | | item.setBatchCode(batchCodeMap.get(item.getId())); |
| | | MapUtils.findAndThen(itemMap, item.getProductId(), mdmItem -> |
| | | item.setProductName(mdmItem.getName()).setProductBarCode(mdmItem.getBarCode()) |
| | | .setProductSpecification(mdmItem.getSpecification())); |
| | | MapUtils.findAndThen(unitMeasureMap, item.getProductUnitId(), unit -> |
| | | item.setProductUnitName(unit.getName())); |
| | | })); |
| | | 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())); |
| | |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * 填充订单项的金额字段 |
| | | * |
| | | * DO 中 totalPrice 为产品金额(不含税),RespVO 需要补全: |
| | | * - totalProductPrice:产品金额 |
| | | * - totalPrice:含税金额(产品金额 + 税额) |
| | | */ |
| | | private void fillItemPrice(ErpSaleOrderRespVO.Item item) { |
| | | BigDecimal productAmount = item.getTotalPrice() != null ? item.getTotalPrice() : BigDecimal.ZERO; |
| | | BigDecimal tax = item.getTaxPrice() != null ? item.getTaxPrice() : BigDecimal.ZERO; |
| | | item.setTotalProductPrice(productAmount); |
| | | item.setTotalPrice(productAmount.add(tax)); |
| | | } |
| | | |
| | | } |