From ba540b3f4cbaeeee41b8f0ea3fa5287872021437 Mon Sep 17 00:00:00 2001 From: "HUOJIN\\92525" Date: Fri, 14 Nov 2025 22:55:32 +0800 Subject: [PATCH] no message --- .../cpte/modules/constant/CommonConstant.java | 17 +- .../constant/enums/PickStatusEnum.java | 47 ++ .../receive/controller/AsnController.java | 408 +++++++++--------- .../receive/mapper/AsnDetailMapper.java | 2 +- .../receive/mapper/xml/AsnDetailMapper.xml | 24 +- .../modules/receive/service/IAsnService.java | 2 +- .../receive/service/impl/AsnServiceImpl.java | 29 +- .../org/cpte/modules/receive/vo/AsnPage.java | 8 +- .../saiWms/controller/SaiWmsController.java | 25 +- .../saiWms/request/OutboundRequest.java | 91 ++++ .../saiWms/service/ISaiWmsService.java | 8 + .../service/impl/ISaiWmsServiceImpl.java | 107 ++++- .../serialNumber/AsnSerialNumberRule.java | 41 ++ .../serialNumber/PickSerialNumberRule.java | 41 ++ .../shipping/controller/PickController.java | 270 ++++++++++++ .../cpte/modules/shipping/entity/Pick.java | 153 +++++++ .../modules/shipping/entity/PickDetail.java | 197 +++++++++ .../shipping/mapper/PickDetailMapper.java | 31 ++ .../modules/shipping/mapper/PickMapper.java | 26 ++ .../shipping/mapper/xml/PickDetailMapper.xml | 18 + .../shipping/mapper/xml/PickMapper.xml | 5 + .../shipping/service/IPickDetailService.java | 22 + .../shipping/service/IPickService.java | 48 +++ .../service/impl/PickDetailServiceImpl.java | 27 ++ .../service/impl/PickServiceImpl.java | 153 +++++++ .../cpte/modules/shipping/vo/PickPage.java | 140 ++++++ .../cpte/modules/utils/CodeGeneratorUtil.java | 14 +- .../org/cpte/modules/utils/SmartEnumUtil.java | 163 ------- .../system/mapper/SysFillRuleMapper.java | 10 +- 29 files changed, 1697 insertions(+), 430 deletions(-) create mode 100644 cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/PickStatusEnum.java create mode 100644 cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/request/OutboundRequest.java create mode 100644 cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/serialNumber/AsnSerialNumberRule.java create mode 100644 cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/serialNumber/PickSerialNumberRule.java create mode 100644 cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/controller/PickController.java create mode 100644 cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/entity/Pick.java create mode 100644 cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/entity/PickDetail.java create mode 100644 cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/mapper/PickDetailMapper.java create mode 100644 cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/mapper/PickMapper.java create mode 100644 cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/mapper/xml/PickDetailMapper.xml create mode 100644 cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/mapper/xml/PickMapper.xml create mode 100644 cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/IPickDetailService.java create mode 100644 cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/IPickService.java create mode 100644 cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/impl/PickDetailServiceImpl.java create mode 100644 cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/impl/PickServiceImpl.java create mode 100644 cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/vo/PickPage.java delete mode 100644 cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/utils/SmartEnumUtil.java diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/CommonConstant.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/CommonConstant.java index d68ded8..8855b31 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/CommonConstant.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/CommonConstant.java @@ -1,6 +1,21 @@ package org.cpte.modules.constant; +/** + * 通用常量 + */ public interface CommonConstant { - //入库输送线任务均衡索引 + /** + * 入库输送线任务均衡索引 + */ String RK_DOCK_TASK_INDEX = "rk_dock_task_index"; + + /** + * 入库单规则编码 + */ + String ASN_ORDER_NO = "asn_order_no"; + + /** + * 出库单规则编码 + */ + String PICK_ORDER_NO = "pick_order_no"; } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/PickStatusEnum.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/PickStatusEnum.java new file mode 100644 index 0000000..ffef6de --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/PickStatusEnum.java @@ -0,0 +1,47 @@ +package org.cpte.modules.constant.enums; + +import lombok.Getter; + +/** + * 入库单状态 + * + * @author: cpte + */ +@Getter +public enum PickStatusEnum { + + CREATED(1, "已创建"), + + PARTIAL(2, "部分分配"), + + ASSIGNED(3, "已分配"), + + PICKING(4, "拣货中"), + + PICKED(5, "拣货完成"), + + CLOSED(6, "已关闭"), + + CANCELED(7, "已取消"), + + + ; + + PickStatusEnum(Integer value, String desc) { + this.value = value; + this.desc = desc; + } + + /** + * 值 + */ + final Integer value; + + /** + * 描述 + */ + final String desc; + + +} + diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/controller/AsnController.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/controller/AsnController.java index 89a10ab..da46220 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/controller/AsnController.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/controller/AsnController.java @@ -1,19 +1,15 @@ package org.cpte.modules.receive.controller; -import java.io.UnsupportedEncodingException; import java.io.IOException; -import java.net.URLDecoder; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; -import java.util.HashMap; - import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import org.cpte.modules.utils.CodeGeneratorUtil; +import org.cpte.modules.constant.CommonConstant; +import org.cpte.modules.serialNumber.AsnSerialNumberRule; import org.jeecgframework.poi.excel.ExcelImportUtil; import org.jeecgframework.poi.excel.def.NormalExcelConstants; import org.jeecgframework.poi.excel.entity.ExportParams; @@ -23,7 +19,6 @@ import org.jeecg.common.system.vo.LoginUser; import org.apache.shiro.SecurityUtils; import org.jeecg.common.api.vo.Result; import org.jeecg.common.system.query.QueryGenerator; -import org.jeecg.common.system.query.QueryRuleEnum; import org.jeecg.common.util.oConvertUtils; import org.cpte.modules.receive.entity.AsnDetail; import org.cpte.modules.receive.entity.Asn; @@ -40,235 +35,234 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import lombok.extern.slf4j.Slf4j; -import com.alibaba.fastjson.JSON; import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.Operation; import org.jeecg.common.aspect.annotation.AutoLog; import org.apache.shiro.authz.annotation.RequiresPermissions; - /** +/** * @Description: 入库单 * @author: cpte - * @Date: 2025-11-03 + * @Date: 2025-11-03 * @Version: V1.0 */ -@Tag(name="入库单") +@Tag(name = "入库单") @RestController @RequestMapping("/receive/asn") @Slf4j public class AsnController { - @Autowired - private IAsnService asnService; - @Autowired - private IAsnDetailService asnDetailService; - @Autowired - private CodeGeneratorUtil codeGeneratorUtil; - - /** - * 分页列表查询 - * - * @param asn - * @param pageNo - * @param pageSize - * @param req - * @return - */ - //@AutoLog(value = "入库单-分页列表查询") - @Operation(summary="入库单-分页列表查询") - @GetMapping(value = "/list") - public Result> queryPageList(Asn asn, - @RequestParam(name="pageNo", defaultValue="1") Integer pageNo, - @RequestParam(name="pageSize", defaultValue="10") Integer pageSize, - HttpServletRequest req) { - QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(asn, req.getParameterMap()); - Page page = new Page(pageNo, pageSize); - IPage pageList = asnService.page(page, queryWrapper); - return Result.OK(pageList); - } - - /** - * 添加 - * - * @param asnPage - * @return - */ - @AutoLog(value = "入库单-添加") - @Operation(summary="入库单-添加") - @RequiresPermissions("receive:data_asn:add") - @PostMapping(value = "/add") - public Result add(@RequestBody AsnPage asnPage) { - Asn asn = new Asn(); - asn.setOrderNo(codeGeneratorUtil.generateSerialNumber("RK")); - BeanUtils.copyProperties(asnPage, asn); - asnService.saveMain(asn, asnPage.getAsnDetailList()); - return Result.OK("添加成功!"); - } - - /** - * 编辑 - * - * @param asnPage - * @return - */ - @AutoLog(value = "入库单-编辑") - @Operation(summary="入库单-编辑") - @RequiresPermissions("receive:data_asn:edit") - @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) - public Result edit(@RequestBody AsnPage asnPage) { - Asn existingAsn = asnService.getById(asnPage.getId()); - if(existingAsn==null) { - return Result.error("未找到对应数据"); - } - // 将更新数据从 asnPage 复制到 existingAsn - BeanUtils.copyProperties(asnPage, existingAsn); - asnService.updateMain(existingAsn, asnPage.getAsnDetailList()); - return Result.OK("编辑成功!"); - } - - /** - * 通过id删除 - * - * @param id - * @return - */ - @AutoLog(value = "入库单-通过id删除") - @Operation(summary="入库单-通过id删除") - @RequiresPermissions("receive:data_asn:delete") - @DeleteMapping(value = "/delete") - public Result delete(@RequestParam(name="id",required=true) String id) { - asnService.delMain(id); - return Result.OK("删除成功!"); - } - - /** - * 批量删除 - * - * @param ids - * @return - */ - @AutoLog(value = "入库单-批量删除") - @Operation(summary="入库单-批量删除") - @RequiresPermissions("receive:data_asn:deleteBatch") - @DeleteMapping(value = "/deleteBatch") - public Result deleteBatch(@RequestParam(name="ids",required=true) String ids) { - this.asnService.delBatchMain(Arrays.asList(ids.split(","))); - return Result.OK("批量删除成功!"); - } - - /** - * 通过id查询 - * - * @param id - * @return - */ - //@AutoLog(value = "入库单-通过id查询") - @Operation(summary="入库单-通过id查询") - @GetMapping(value = "/queryById") - public Result queryById(@RequestParam(name="id",required=true) String id) { - Asn asn = asnService.getById(id); - if(asn==null) { - return Result.error("未找到对应数据"); - } - return Result.OK(asn); - - } - - /** - * 通过id查询 - * - * @param id - * @return - */ - //@AutoLog(value = "入库明细通过主表ID查询") - @Operation(summary="入库明细主表ID查询") - @GetMapping(value = "/queryAsnDetailByMainId") - public Result> queryAsnDetailListByMainId(@RequestParam(name="id",required=true) Long id) { - List asnDetailList = asnDetailService.selectByMainId(id); - return Result.OK(asnDetailList); - } + @Autowired + private IAsnService asnService; + @Autowired + private IAsnDetailService asnDetailService; + @Autowired + private AsnSerialNumberRule asnSerialNumberRule; /** - * 导出excel - * - * @param request - * @param asn - */ + * 分页列表查询 + * + * @param asn + * @param pageNo + * @param pageSize + * @param req + * @return + */ + @Operation(summary = "入库单-分页列表查询") + @GetMapping(value = "/list") + public Result> queryPageList(Asn asn, + @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, + HttpServletRequest req) { + QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(asn, req.getParameterMap()); + Page page = new Page(pageNo, pageSize); + IPage pageList = asnService.page(page, queryWrapper); + return Result.OK(pageList); + } + + /** + * 添加 + * + * @param asnPage + * @return + */ + @AutoLog(value = "入库单-添加") + @Operation(summary = "入库单-添加") + @RequiresPermissions("receive:data_asn:add") + @PostMapping(value = "/add") + public Result add(@RequestBody AsnPage asnPage) { + Asn asn = new Asn(); + String orderNo = asnSerialNumberRule.generateSerialNumber(CommonConstant.ASN_ORDER_NO); + asn.setOrderNo(orderNo); + BeanUtils.copyProperties(asnPage, asn); + asnService.saveMain(asn, asnPage.getAsnDetailList()); + return Result.OK("添加成功!"); + } + + /** + * 编辑 + * + * @param asnPage + * @return + */ + @AutoLog(value = "入库单-编辑") + @Operation(summary = "入库单-编辑") + @RequiresPermissions("receive:data_asn:edit") + @RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST}) + public Result edit(@RequestBody AsnPage asnPage) { + Asn existingAsn = asnService.getById(asnPage.getId()); + if (existingAsn == null) { + return Result.error("未找到对应数据"); + } + // 将更新数据从 asnPage 复制到 existingAsn + BeanUtils.copyProperties(asnPage, existingAsn); + asnService.updateMain(existingAsn, asnPage.getAsnDetailList()); + return Result.OK("编辑成功!"); + } + + /** + * 通过id删除 + * + * @param id + * @return + */ + @AutoLog(value = "入库单-通过id删除") + @Operation(summary = "入库单-通过id删除") + @RequiresPermissions("receive:data_asn:delete") + @DeleteMapping(value = "/delete") + public Result delete(@RequestParam(name = "id", required = true) Long id) { + asnService.delMain(id); + return Result.OK("删除成功!"); + } + + /** + * 批量删除 + * + * @param ids + * @return + */ + @AutoLog(value = "入库单-批量删除") + @Operation(summary = "入库单-批量删除") + @RequiresPermissions("receive:data_asn:deleteBatch") + @DeleteMapping(value = "/deleteBatch") + public Result deleteBatch(@RequestParam(name = "ids", required = true) String ids) { + this.asnService.delBatchMain(Arrays.asList(ids.split(","))); + return Result.OK("批量删除成功!"); + } + + /** + * 通过id查询 + * + * @param id + * @return + */ + //@AutoLog(value = "入库单-通过id查询") + @Operation(summary = "入库单-通过id查询") + @GetMapping(value = "/queryById") + public Result queryById(@RequestParam(name = "id", required = true) String id) { + Asn asn = asnService.getById(id); + if (asn == null) { + return Result.error("未找到对应数据"); + } + return Result.OK(asn); + + } + + /** + * 通过id查询 + * + * @param id + * @return + */ + //@AutoLog(value = "入库明细通过主表ID查询") + @Operation(summary = "入库明细主表ID查询") + @GetMapping(value = "/queryAsnDetailByMainId") + public Result> queryAsnDetailListByMainId(@RequestParam(name = "id", required = true) Long id) { + List asnDetailList = asnDetailService.selectByMainId(id); + return Result.OK(asnDetailList); + } + + /** + * 导出excel + * + * @param request + * @param asn + */ @RequiresPermissions("receive:data_asn:exportXls") @RequestMapping(value = "/exportXls") public ModelAndView exportXls(HttpServletRequest request, Asn asn) { - // Step.1 组装查询条件查询数据 - QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(asn, request.getParameterMap()); - LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal(); + // Step.1 组装查询条件查询数据 + QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(asn, request.getParameterMap()); + LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal(); - //配置选中数据查询条件 - String selections = request.getParameter("selections"); - if(oConvertUtils.isNotEmpty(selections)) { - List selectionList = Arrays.asList(selections.split(",")); - queryWrapper.in("id",selectionList); - } - //Step.2 获取导出数据 - List asnList = asnService.list(queryWrapper); + //配置选中数据查询条件 + String selections = request.getParameter("selections"); + if (oConvertUtils.isNotEmpty(selections)) { + List selectionList = Arrays.asList(selections.split(",")); + queryWrapper.in("id", selectionList); + } + //Step.2 获取导出数据 + List asnList = asnService.list(queryWrapper); - // Step.3 组装pageList - List pageList = new ArrayList(); - for (Asn main : asnList) { - AsnPage vo = new AsnPage(); - BeanUtils.copyProperties(main, vo); - List asnDetailList = asnDetailService.selectByMainId(main.getId()); - vo.setAsnDetailList(asnDetailList); - pageList.add(vo); - } + // Step.3 组装pageList + List pageList = new ArrayList(); + for (Asn main : asnList) { + AsnPage vo = new AsnPage(); + BeanUtils.copyProperties(main, vo); + List asnDetailList = asnDetailService.selectByMainId(main.getId()); + vo.setAsnDetailList(asnDetailList); + pageList.add(vo); + } - // Step.4 AutoPoi 导出Excel - ModelAndView mv = new ModelAndView(new JeecgEntityExcelView()); - mv.addObject(NormalExcelConstants.FILE_NAME, "入库单列表"); - mv.addObject(NormalExcelConstants.CLASS, AsnPage.class); - mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("入库单数据", "导出人:"+sysUser.getRealname(), "入库单")); - mv.addObject(NormalExcelConstants.DATA_LIST, pageList); - return mv; + // Step.4 AutoPoi 导出Excel + ModelAndView mv = new ModelAndView(new JeecgEntityExcelView()); + mv.addObject(NormalExcelConstants.FILE_NAME, "入库单列表"); + mv.addObject(NormalExcelConstants.CLASS, AsnPage.class); + mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("入库单数据", "导出人:" + sysUser.getRealname(), "入库单")); + mv.addObject(NormalExcelConstants.DATA_LIST, pageList); + return mv; } /** - * 通过excel导入数据 - * - * @param request - * @param response - * @return - */ + * 通过excel导入数据 + * + * @param request + * @param response + * @return + */ @RequiresPermissions("receive:data_asn:importExcel") @RequestMapping(value = "/importExcel", method = RequestMethod.POST) public Result importExcel(HttpServletRequest request, HttpServletResponse response) { - MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request; - Map fileMap = multipartRequest.getFileMap(); - for (Map.Entry entity : fileMap.entrySet()) { - // 获取上传文件对象 - MultipartFile file = entity.getValue(); - ImportParams params = new ImportParams(); - params.setTitleRows(2); - params.setHeadRows(1); - params.setNeedSave(true); - try { - List list = ExcelImportUtil.importExcel(file.getInputStream(), AsnPage.class, params); - for (AsnPage page : list) { - Asn po = new Asn(); - BeanUtils.copyProperties(page, po); - asnService.saveMain(po, page.getAsnDetailList()); - } - return Result.OK("文件导入成功!数据行数:" + list.size()); - } catch (Exception e) { - log.error(e.getMessage(),e); - return Result.error("文件导入失败:"+e.getMessage()); - } finally { - try { - file.getInputStream().close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - return Result.OK("文件导入失败!"); + MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request; + Map fileMap = multipartRequest.getFileMap(); + for (Map.Entry entity : fileMap.entrySet()) { + // 获取上传文件对象 + MultipartFile file = entity.getValue(); + ImportParams params = new ImportParams(); + params.setTitleRows(2); + params.setHeadRows(1); + params.setNeedSave(true); + try { + List list = ExcelImportUtil.importExcel(file.getInputStream(), AsnPage.class, params); + for (AsnPage page : list) { + Asn po = new Asn(); + BeanUtils.copyProperties(page, po); + asnService.saveMain(po, page.getAsnDetailList()); + } + return Result.OK("文件导入成功!数据行数:" + list.size()); + } catch (Exception e) { + log.error(e.getMessage(), e); + return Result.error("文件导入失败:" + e.getMessage()); + } finally { + try { + file.getInputStream().close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return Result.OK("文件导入失败!"); } } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/mapper/AsnDetailMapper.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/mapper/AsnDetailMapper.java index 47b0abf..64702ca 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/mapper/AsnDetailMapper.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/mapper/AsnDetailMapper.java @@ -22,7 +22,7 @@ public interface AsnDetailMapper extends BaseMapper { * @param mainId 主表id * @return boolean */ - public boolean deleteByMainId(@Param("mainId") String mainId); + public boolean deleteByMainId(@Param("mainId") Long mainId); /** * 通过主表id查询子表数据 diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/mapper/xml/AsnDetailMapper.xml b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/mapper/xml/AsnDetailMapper.xml index 54f4efc..1b1af92 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/mapper/xml/AsnDetailMapper.xml +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/mapper/xml/AsnDetailMapper.xml @@ -2,15 +2,17 @@ - - DELETE - FROM data_asn_detail - WHERE - asn_id = #{mainId} - - + + DELETE + FROM data_asn_detail + WHERE + asn_id = #{mainId} + + + diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/service/IAsnService.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/service/IAsnService.java index 5d29f0c..5c5a546 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/service/IAsnService.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/service/IAsnService.java @@ -37,7 +37,7 @@ public interface IAsnService extends IService { * * @param id */ - public void delMain(String id); + public void delMain(Long id); /** * 批量删除一对多 diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/service/impl/AsnServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/service/impl/AsnServiceImpl.java index 7bd4ebb..dbad152 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/service/impl/AsnServiceImpl.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/service/impl/AsnServiceImpl.java @@ -54,8 +54,6 @@ public class AsnServiceImpl extends ServiceImpl implements IAsnS @Autowired private ReceiveRecordMapper receiveRecordMapper; @Autowired - private InventoryMapper inventoryMapper; - @Autowired private IInventoryService iInventoryService; @Autowired private IInventoryLogService iInventoryLogService; @@ -78,7 +76,7 @@ public class AsnServiceImpl extends ServiceImpl implements IAsnS refreshAsn(asn, asnDetailList); } - public void refreshAsn(Asn asn, List asnDetails) { + public synchronized void refreshAsn(Asn asn, List asnDetails) { if (asnDetails == null) { asnDetails = new ArrayList<>(); @@ -93,12 +91,18 @@ public class AsnServiceImpl extends ServiceImpl implements IAsnS //当前状态 Integer status = asn.getStatus(); - if (orderQty.compareTo(BigDecimal.ZERO) >= 0 && receivedQty.compareTo(BigDecimal.ZERO) == 0) { + if (orderQty.compareTo(BigDecimal.ZERO) <= 0) { + // 无需求量时设为创建状态 status = AsnStatusEnum.CREATED.getValue(); - } else if (BigDecimalUtil.subtract(orderQty, receivedQty, 0).compareTo(BigDecimal.ZERO) > 0 && receivedQty.compareTo(BigDecimal.ZERO) > 0) { - status = AsnStatusEnum.RECEIVING.getValue(); - } else if (BigDecimalUtil.subtract(orderQty, receivedQty, 0).compareTo(BigDecimal.ZERO) == 0 && receivedQty.compareTo(BigDecimal.ZERO) > 0) { + } else if (receivedQty.compareTo(BigDecimal.ZERO) <= 0) { + // 未收货时为创建状态 + status = AsnStatusEnum.CREATED.getValue(); + } else if (receivedQty.compareTo(orderQty) >= 0) { + // 已完全收货 status = AsnStatusEnum.RECEIVED.getValue(); + } else { + // 部分收货 + status = AsnStatusEnum.RECEIVING.getValue(); } asn.setOrderQty(orderQty); @@ -131,7 +135,7 @@ public class AsnServiceImpl extends ServiceImpl implements IAsnS @Override @Transactional(rollbackFor = Exception.class) - public void delMain(String id) { + public void delMain(Long id) { Asn asn = this.getById(id); if (!AsnStatusEnum.CREATED.getValue().equals(asn.getStatus())) { throw new RuntimeException("操作失败:【" + asn.getOrderNo() + "】入库单,非创建状态不允许删除"); @@ -150,7 +154,7 @@ public class AsnServiceImpl extends ServiceImpl implements IAsnS orderNoList.add(asn.getOrderNo()); continue; } - asnDetailMapper.deleteByMainId(id.toString()); + asnDetailMapper.deleteByMainId(Long.parseLong(id.toString())); asnMapper.deleteById(id); } if (!orderNoList.isEmpty()) { @@ -176,13 +180,6 @@ public class AsnServiceImpl extends ServiceImpl implements IAsnS //容器 Stock stock = stockMapper.selectById(asnDetail.getStockId()); - //验证当前托盘是否有库存 -/* Stock stock = stockMapper.selectById(asnDetail.getStockId()); - Inventory existingInventory = inventoryMapper.selectByStockId(stock.getId()); - if (existingInventory != null) { - throw new RuntimeException("【" + stock.getStockCode() + "】托盘已入库"); - }*/ - //更新收货数量 BigDecimal receivedQty = BigDecimalUtil.add(asnDetail.getReceivedQty(), asnDetail.getOrderQty(), 0); asnDetail.setReceivedQty(receivedQty); diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/vo/AsnPage.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/vo/AsnPage.java index 002dc43..8d5a7b5 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/vo/AsnPage.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/vo/AsnPage.java @@ -33,11 +33,11 @@ public class AsnPage { * 主键 */ @Schema(description = "主键") - private java.lang.String id; + private java.lang.Long id; @Excel(name = "外部单号", width = 15) @Schema(description = "外部单号") - private java.lang.String thirdPartyOrderNo; + private java.lang.String thirdOrderNo; /** * 任务号 @@ -73,7 +73,7 @@ public class AsnPage { */ @Excel(name = "订单状态", width = 15) @Schema(description = "订单状态") - private java.lang.String status; + private java.lang.Integer status; /** * 需求数量 @@ -105,7 +105,7 @@ public class AsnPage { */ @Excel(name = "仓库ID", width = 15) @Schema(description = "仓库ID") - private java.lang.String tenantId; + private java.lang.Long tenantId; /** * 创建人 */ diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/controller/SaiWmsController.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/controller/SaiWmsController.java index 1b50f18..df1c27b 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/controller/SaiWmsController.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/controller/SaiWmsController.java @@ -5,6 +5,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.cpte.modules.saiWms.request.InboundRequest; +import org.cpte.modules.saiWms.request.OutboundRequest; import org.cpte.modules.saiWms.service.ISaiWmsService; import org.jeecg.common.api.vo.Result; import org.jeecg.common.aspect.annotation.AutoLog; @@ -17,12 +18,12 @@ import org.springframework.web.bind.annotation.RestController; @Tag(name = "赛意WMS") @RestController -@RequestMapping("/saiWms/inBound") +@RequestMapping("/saiWms") @Slf4j public class SaiWmsController { @Autowired - private ISaiWmsService iInBoundService; + private ISaiWmsService iSaiWmsService; /** * 入库任务下发 @@ -31,10 +32,24 @@ public class SaiWmsController { */ @AutoLog(value = "入库任务下发") @Operation(summary = "赛意WMS-入库任务下发") - @PostMapping(value = "/inBoundTask") + @PostMapping(value = "/inBound/inBoundTask") @IgnoreAuth - public Result inBoundTask(@RequestBody @Valid InboundRequest inboundRequest) { - iInBoundService.inBoundTask(inboundRequest); + public Result inBoundTask(@RequestBody @Valid InboundRequest inboundRequest) { + iSaiWmsService.inBoundTask(inboundRequest); + return Result.OK("下发成功!"); + } + + /** + * 出库任务下发 + * + * @param outboundRequest 请求参数 + */ + @AutoLog(value = "出库任务下发") + @Operation(summary = "赛意WMS-出库任务下发") + @PostMapping(value = "/outBound/outBoundTask") + @IgnoreAuth + public Result outBoundTask(@RequestBody @Valid OutboundRequest outboundRequest) { + iSaiWmsService.outBoundTask(outboundRequest); return Result.OK("下发成功!"); } } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/request/OutboundRequest.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/request/OutboundRequest.java new file mode 100644 index 0000000..62344d7 --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/request/OutboundRequest.java @@ -0,0 +1,91 @@ +package org.cpte.modules.saiWms.request; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +/** + * 赛意WMS-任务下发请求参数 + */ +@Data +public class OutboundRequest { + // 任务号 + @NotBlank(message = "任务号不能为空") + @JsonProperty("No") + private String no; + + // 单号 + @NotBlank(message = "单号不能为空") + @JsonProperty("OrderNo") + private String orderNo; + + // 仓库 + @NotBlank(message = "仓库不能为空") + @JsonProperty("WhCode") + private String whCode; + + // 供应商编码 + @JsonProperty("CustomerCode") + private String customerCode; + + // 单据类型:0.成品入库;1.配件入库;2.成品拆托入库;3.配件拆托入库;4.成品出库;5.配件出库;6.返工出库;7.检验出库;8.其他出库 + @NotNull(message = "单据类型不能为空") + @JsonProperty("Type") + private Integer type; + + // 生产车间 + @NotBlank(message = "生产车间") + @JsonProperty("Enterprise") + private String enterprise; + + // 出库明细列表 + @NotNull(message = "入库明细不能为空") + @JsonProperty("details") + @Valid + private List details; + + @Data + public static class OutboundDetail { + // 行号 + @NotBlank(message = "行号不能为空") + @JsonProperty("LineNo") + private String lineNo; + + // 物料 + @NotBlank(message = "物料不能为空") + @JsonProperty("Item") + private String item; + + // 单位 + @NotBlank(message = "单位不能为空") + @JsonProperty("Unit") + private String unit; + + // 数量 + @NotNull(message = "数量不能为空") + @JsonProperty("Qty") + private BigDecimal qty; + + // 项目号 + @JsonProperty("Project") + private String project; + + // 任务号 + @JsonProperty("TaskNo") + private String taskNo; + + // 批次号 + @JsonProperty("LotAtt04") + private String lotAtt04; + + // 库存状态 + @JsonProperty("LotAtt010") + private String lotAtt010; + } + +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/service/ISaiWmsService.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/service/ISaiWmsService.java index c9074f8..39307df 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/service/ISaiWmsService.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/service/ISaiWmsService.java @@ -1,6 +1,7 @@ package org.cpte.modules.saiWms.service; import org.cpte.modules.saiWms.request.InboundRequest; +import org.cpte.modules.saiWms.request.OutboundRequest; public interface ISaiWmsService { /** @@ -9,4 +10,11 @@ public interface ISaiWmsService { * @param inboundRequest 请求参数 */ void inBoundTask(InboundRequest inboundRequest); + + /** + * 出库任务下发 + * + * @param outboundRequest 请求参数 + */ + void outBoundTask(OutboundRequest outboundRequest); } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/service/impl/ISaiWmsServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/service/impl/ISaiWmsServiceImpl.java index 6c44a15..d8f9a43 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/service/impl/ISaiWmsServiceImpl.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/service/impl/ISaiWmsServiceImpl.java @@ -16,11 +16,15 @@ import org.cpte.modules.receive.entity.AsnDetail; import org.cpte.modules.receive.mapper.AsnMapper; import org.cpte.modules.receive.service.IAsnService; import org.cpte.modules.saiWms.request.InboundRequest; +import org.cpte.modules.saiWms.request.OutboundRequest; import org.cpte.modules.saiWms.service.ISaiWmsService; -import org.cpte.modules.utils.CodeGeneratorUtil; -import org.jeecg.common.config.TenantContext; +import org.cpte.modules.serialNumber.AsnSerialNumberRule; +import org.cpte.modules.serialNumber.PickSerialNumberRule; +import org.cpte.modules.shipping.entity.Pick; +import org.cpte.modules.shipping.entity.PickDetail; +import org.cpte.modules.shipping.mapper.PickMapper; +import org.cpte.modules.shipping.service.IPickService; import org.jeecg.common.util.RedisUtil; -import org.jeecg.common.util.oConvertUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -32,11 +36,15 @@ import java.util.*; @Slf4j public class ISaiWmsServiceImpl implements ISaiWmsService { + + @Autowired + private PointMapper pointMapper; + @Autowired private AsnMapper asnMapper; @Autowired - private PointMapper pointMapper; + private PickMapper pickMapper; @Autowired private IItemService itemService; @@ -50,11 +58,18 @@ public class ISaiWmsServiceImpl implements ISaiWmsService { @Autowired private IAsnService asnService; + @Autowired + private IPickService pickService; + + @Autowired private IAgvTaskService iAgvTaskService; @Autowired - private CodeGeneratorUtil codeGeneratorUtil; + private AsnSerialNumberRule asnSerialNumberRule; + + @Autowired + private PickSerialNumberRule pickSerialNumberRule; @Autowired private RedisUtil redisUtil; @@ -106,11 +121,42 @@ public class ISaiWmsServiceImpl implements ISaiWmsService { } } + @Override + @Transactional(rollbackFor = Exception.class) + public void outBoundTask(OutboundRequest outboundRequest) { + //验证任务号 + String no = outboundRequest.getNo(); + Pick pick = pickMapper.queryByNo(no); + if (pick != null) { + throw new RuntimeException("【" + no + "】任务号已接收,请勿重复下发"); + } + + // 获取集合中所有的物料 + List itemCodes = outboundRequest.getDetails().stream().map(OutboundRequest.OutboundDetail::getItem).distinct().toList(); + + //获取数据库已存在物料 + Map exitItemMap = itemService.queryByItemCodesToMap(itemCodes); + + //获取不存在的物料 + List notExitItemCodes = itemCodes.stream().filter(itemCode -> !exitItemMap.containsKey(itemCode)).toList(); + if (!notExitItemCodes.isEmpty()) { + throw new RuntimeException("系统无【" + notExitItemCodes + "】物料,请维护"); + } + + // 创建出库单和明细 + Pick createPick = buildPick(outboundRequest); + List pickDetails = buildPickDetail(outboundRequest.getDetails(), exitItemMap); + + // 保存出库单和出库明细 + pickService.saveMain(createPick, pickDetails); + + } + /** * 构建入库单 */ private Asn buildAsn(InboundRequest inboundRequest) { - String orderNo = (codeGeneratorUtil.generateSerialNumber("RK")); + String orderNo = asnSerialNumberRule.generateSerialNumber(CommonConstant.ASN_ORDER_NO); return Asn.builder() .orderNo(orderNo) .thirdOrderNo(inboundRequest.getOrderNo()) @@ -136,16 +182,61 @@ public class ISaiWmsServiceImpl implements ISaiWmsService { .itemId(item.getId()) .unit(detail.getUnit()) .orderQty(detail.getQty()) + .receivedQty(BigDecimal.ZERO) .stockId(stock.getId()) .pointId(srcPoint.getId()) .status(AsnStatusEnum.CREATED.getValue()) .project(detail.getProject()) .taskNo(detail.getTaskNo()) .propC1(detail.getLotAtt04()) - .propC2(detail.getLotAtt010()) - .receivedQty(BigDecimal.ZERO) + .propC3(detail.getLotAtt010()) .build(); } + + + /** + * 构建出库单 + */ + private Pick buildPick(OutboundRequest outboundRequest) { + String orderNo = pickSerialNumberRule.generateSerialNumber(CommonConstant.PICK_ORDER_NO); + return Pick.builder() + .orderNo(orderNo) + .thirdOrderNo(outboundRequest.getOrderNo()) + .no(outboundRequest.getNo()) + .whCode(outboundRequest.getWhCode()) + .customerCode(outboundRequest.getCustomerCode()) + .orderType(outboundRequest.getType()) + .status(PickStatusEnum.CREATED.getValue()) + .orderDate(new Date()) + .sysOrgCode("A05") + .tenantId(1000L) + .createBy("赛意") + .build(); + } + + /** + * 构建出库明细 + */ + private List buildPickDetail(List details, Map exitItemMap) { + List newDetailList = new ArrayList<>(); + for (OutboundRequest.OutboundDetail detail : details) { + PickDetail pickDetail = PickDetail.builder() + .lineNo(Integer.parseInt(detail.getLineNo())) + .itemId(exitItemMap.get(detail.getItem()).getId()) + .unit(detail.getUnit()) + .orderQty(detail.getQty()) + .allocatedQty(BigDecimal.ZERO) + .pickedQty(BigDecimal.ZERO) + .status(PickStatusEnum.CREATED.getValue()) + .project(detail.getProject()) + .taskNo(detail.getTaskNo()) + .propC1(detail.getLotAtt04()) + .propC3(detail.getLotAtt010()) + .build(); + newDetailList.add(pickDetail); + } + return newDetailList; + } } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/serialNumber/AsnSerialNumberRule.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/serialNumber/AsnSerialNumberRule.java new file mode 100644 index 0000000..d5cb32a --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/serialNumber/AsnSerialNumberRule.java @@ -0,0 +1,41 @@ +package org.cpte.modules.serialNumber; + +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.jeecg.common.handler.IFillRuleHandler; +import org.jeecg.modules.system.mapper.SysFillRuleMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.cpte.modules.utils.CodeGeneratorUtil; + +@Service +@Slf4j +public class AsnSerialNumberRule implements IFillRuleHandler { + + @Autowired + private CodeGeneratorUtil codeGeneratorUtil; + + @Autowired + private SysFillRuleMapper sysFillRuleMapper; + + + @Override + public Object execute(JSONObject params, JSONObject formData) { + String prefix = params.getString("code"); + String code = codeGeneratorUtil.generateSerialNumber(prefix); + log.info("生成业务编号:{}", code); + return code; + } + + public String generateSerialNumber(String ruleCode) { + String ruleParams = sysFillRuleMapper.queryByRuleCode(ruleCode); + JSONObject jsonObject = JSONObject.parseObject(ruleParams); + String prefix = null; + if (jsonObject != null) { + prefix = jsonObject.getString("code"); + } else { + prefix = "RK"; + } + return codeGeneratorUtil.generateSerialNumber(prefix); + } +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/serialNumber/PickSerialNumberRule.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/serialNumber/PickSerialNumberRule.java new file mode 100644 index 0000000..bed10d4 --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/serialNumber/PickSerialNumberRule.java @@ -0,0 +1,41 @@ +package org.cpte.modules.serialNumber; + +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.cpte.modules.utils.CodeGeneratorUtil; +import org.jeecg.common.handler.IFillRuleHandler; +import org.jeecg.modules.system.mapper.SysFillRuleMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +public class PickSerialNumberRule implements IFillRuleHandler { + + @Autowired + private CodeGeneratorUtil codeGeneratorUtil; + + @Autowired + private SysFillRuleMapper sysFillRuleMapper; + + + @Override + public Object execute(JSONObject params, JSONObject formData) { + String prefix = params.getString("code"); + String code = codeGeneratorUtil.generateSerialNumber(prefix); + log.info("生成业务编号:{}", code); + return code; + } + + public String generateSerialNumber(String ruleCode) { + String ruleParams = sysFillRuleMapper.queryByRuleCode(ruleCode); + JSONObject jsonObject = JSONObject.parseObject(ruleParams); + String prefix = null; + if (jsonObject != null) { + prefix = jsonObject.getString("code"); + } else { + prefix = "CK"; + } + return codeGeneratorUtil.generateSerialNumber(prefix); + } +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/controller/PickController.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/controller/PickController.java new file mode 100644 index 0000000..852d0c0 --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/controller/PickController.java @@ -0,0 +1,270 @@ +package org.cpte.modules.shipping.controller; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import org.cpte.modules.constant.CommonConstant; +import org.cpte.modules.serialNumber.PickSerialNumberRule; +import org.jeecgframework.poi.excel.ExcelImportUtil; +import org.jeecgframework.poi.excel.def.NormalExcelConstants; +import org.jeecgframework.poi.excel.entity.ExportParams; +import org.jeecgframework.poi.excel.entity.ImportParams; +import org.jeecgframework.poi.excel.view.JeecgEntityExcelView; +import org.jeecg.common.system.vo.LoginUser; +import org.apache.shiro.SecurityUtils; +import org.jeecg.common.api.vo.Result; +import org.jeecg.common.system.query.QueryGenerator; +import org.jeecg.common.util.oConvertUtils; +import org.cpte.modules.shipping.entity.PickDetail; +import org.cpte.modules.shipping.entity.Pick; +import org.cpte.modules.shipping.vo.PickPage; +import org.cpte.modules.shipping.service.IPickService; +import org.cpte.modules.shipping.service.IPickDetailService; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.MultipartHttpServletRequest; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.extern.slf4j.Slf4j; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.jeecg.common.aspect.annotation.AutoLog; +import org.apache.shiro.authz.annotation.RequiresPermissions; + + +/** + * @Description: 出库单 + * @author: cpte + * @Date: 2025-11-14 + * @Version: V1.0 + */ +@Tag(name = "出库单") +@RestController +@RequestMapping("/shipping/pick") +@Slf4j +public class PickController { + @Autowired + private IPickService pickService; + @Autowired + private IPickDetailService pickDetailService; + @Autowired + private PickSerialNumberRule pickSerialNumberRule; + + /** + * 分页列表查询 + * + * @param pick + * @param pageNo + * @param pageSize + * @param req + * @return + */ + //@AutoLog(value = "出库单-分页列表查询") + @Operation(summary = "出库单-分页列表查询") + @GetMapping(value = "/list") + public Result> queryPageList(Pick pick, + @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, + HttpServletRequest req) { + QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(pick, req.getParameterMap()); + Page page = new Page(pageNo, pageSize); + IPage pageList = pickService.page(page, queryWrapper); + return Result.OK(pageList); + } + + /** + * 添加 + * + * @param pickPage + * @return + */ + @AutoLog(value = "出库单-添加") + @Operation(summary = "出库单-添加") + @RequiresPermissions("shipping:data_pick:add") + @PostMapping(value = "/add") + public Result add(@RequestBody PickPage pickPage) { + Pick pick = new Pick(); + String orderNo = pickSerialNumberRule.generateSerialNumber(CommonConstant.PICK_ORDER_NO); + pick.setOrderNo(orderNo); + BeanUtils.copyProperties(pickPage, pick); + pickService.saveMain(pick, pickPage.getPickDetailList()); + return Result.OK("添加成功!"); + } + + /** + * 编辑 + * + * @param pickPage + * @return + */ + @AutoLog(value = "出库单-编辑") + @Operation(summary = "出库单-编辑") + @RequiresPermissions("shipping:data_pick:edit") + @RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST}) + public Result edit(@RequestBody PickPage pickPage) { + Pick existingPick = pickService.getById(pickPage.getId()); + if (existingPick == null) { + return Result.error("未找到对应数据"); + } + // 将更新数据从 pickPage 复制到 existingPick + BeanUtils.copyProperties(pickPage, existingPick); + pickService.updateMain(existingPick, pickPage.getPickDetailList()); + return Result.OK("编辑成功!"); + } + + /** + * 通过id删除 + * + * @param id + * @return + */ + @AutoLog(value = "出库单-通过id删除") + @Operation(summary = "出库单-通过id删除") + @RequiresPermissions("shipping:data_pick:delete") + @DeleteMapping(value = "/delete") + public Result delete(@RequestParam(name = "id", required = true) Long id) { + pickService.delMain(id); + return Result.OK("删除成功!"); + } + + /** + * 批量删除 + * + * @param ids + * @return + */ + @AutoLog(value = "出库单-批量删除") + @Operation(summary = "出库单-批量删除") + @RequiresPermissions("shipping:data_pick:deleteBatch") + @DeleteMapping(value = "/deleteBatch") + public Result deleteBatch(@RequestParam(name = "ids", required = true) String ids) { + this.pickService.delBatchMain(Arrays.asList(ids.split(","))); + return Result.OK("批量删除成功!"); + } + + /** + * 通过id查询 + * + * @param id + * @return + */ + //@AutoLog(value = "出库单-通过id查询") + @Operation(summary = "出库单-通过id查询") + @GetMapping(value = "/queryById") + public Result queryById(@RequestParam(name = "id", required = true) String id) { + Pick pick = pickService.getById(id); + if (pick == null) { + return Result.error("未找到对应数据"); + } + return Result.OK(pick); + + } + + /** + * 通过id查询 + * + * @param id + * @return + */ + //@AutoLog(value = "出库明细通过主表ID查询") + @Operation(summary = "出库明细主表ID查询") + @GetMapping(value = "/queryPickDetailByMainId") + public Result> queryPickDetailListByMainId(@RequestParam(name = "id", required = true) Long id) { + List pickDetailList = pickDetailService.selectByMainId(id); + return Result.OK(pickDetailList); + } + + /** + * 导出excel + * + * @param request + * @param pick + */ + @RequiresPermissions("shipping:data_pick:exportXls") + @RequestMapping(value = "/exportXls") + public ModelAndView exportXls(HttpServletRequest request, Pick pick) { + + // Step.1 组装查询条件查询数据 + QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(pick, request.getParameterMap()); + LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal(); + + //配置选中数据查询条件 + String selections = request.getParameter("selections"); + if (oConvertUtils.isNotEmpty(selections)) { + List selectionList = Arrays.asList(selections.split(",")); + queryWrapper.in("id", selectionList); + } + //Step.2 获取导出数据 + List pickList = pickService.list(queryWrapper); + + // Step.3 组装pageList + List pageList = new ArrayList(); + for (Pick main : pickList) { + PickPage vo = new PickPage(); + BeanUtils.copyProperties(main, vo); + List pickDetailList = pickDetailService.selectByMainId(main.getId()); + vo.setPickDetailList(pickDetailList); + pageList.add(vo); + } + + // Step.4 AutoPoi 导出Excel + ModelAndView mv = new ModelAndView(new JeecgEntityExcelView()); + mv.addObject(NormalExcelConstants.FILE_NAME, "出库单列表"); + mv.addObject(NormalExcelConstants.CLASS, PickPage.class); + mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("出库单数据", "导出人:" + sysUser.getRealname(), "出库单")); + mv.addObject(NormalExcelConstants.DATA_LIST, pageList); + return mv; + } + + /** + * 通过excel导入数据 + * + * @param request + * @param response + * @return + */ + @RequiresPermissions("shipping:data_pick:importExcel") + @RequestMapping(value = "/importExcel", method = RequestMethod.POST) + public Result importExcel(HttpServletRequest request, HttpServletResponse response) { + MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request; + Map fileMap = multipartRequest.getFileMap(); + for (Map.Entry entity : fileMap.entrySet()) { + // 获取上传文件对象 + MultipartFile file = entity.getValue(); + ImportParams params = new ImportParams(); + params.setTitleRows(2); + params.setHeadRows(1); + params.setNeedSave(true); + try { + List list = ExcelImportUtil.importExcel(file.getInputStream(), PickPage.class, params); + for (PickPage page : list) { + Pick po = new Pick(); + BeanUtils.copyProperties(page, po); + pickService.saveMain(po, page.getPickDetailList()); + } + return Result.OK("文件导入成功!数据行数:" + list.size()); + } catch (Exception e) { + log.error(e.getMessage(), e); + return Result.error("文件导入失败:" + e.getMessage()); + } finally { + try { + file.getInputStream().close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return Result.OK("文件导入失败!"); + } + +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/entity/Pick.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/entity/Pick.java new file mode 100644 index 0000000..cc3ebee --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/entity/Pick.java @@ -0,0 +1,153 @@ +package org.cpte.modules.shipping.entity; + +import java.io.Serializable; +import java.io.UnsupportedEncodingException; +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.NoArgsConstructor; +import org.jeecg.common.constant.ProvinceCityArea; +import org.jeecg.common.util.SpringContextUtils; +import lombok.Data; +import com.fasterxml.jackson.annotation.JsonFormat; +import org.springframework.format.annotation.DateTimeFormat; +import org.jeecgframework.poi.excel.annotation.Excel; +import org.jeecg.common.aspect.annotation.Dict; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * @Description: 出库单 + * @author: cpte + * @Date: 2025-11-14 + * @Version: V1.0 + */ +@Schema(description = "出库单") +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@TableName("data_pick") +public class Pick implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * id + */ + @TableId(type = IdType.ASSIGN_ID) + @Schema(description = "id") + @JsonSerialize(using = ToStringSerializer.class) + private java.lang.Long id; + /** + * 出库单号 + */ + @Excel(name = "出库单号", width = 15) + @Schema(description = "出库单号") + private java.lang.String orderNo; + /** + * 外部单号 + */ + @Excel(name = "外部单号", width = 15) + @Schema(description = "外部单号") + private java.lang.String thirdOrderNo; + /** + * 任务号 + */ + @Excel(name = "任务号", width = 15) + @Schema(description = "任务号") + private java.lang.String no; + /** + * 外部仓库 + */ + @Excel(name = "外部仓库", width = 15) + @Schema(description = "外部仓库") + private java.lang.String whCode; + /** + * 客户代码 + */ + @Excel(name = "客户代码", width = 15) + @Schema(description = "客户代码") + private java.lang.String customerCode; + /** + * 单据类型;0.成品入库;1.配件入库;2.成品拆托入库;3.配件拆托入库;4.成品出库;5.配件出库;6.返工出库;7.检验出库;8.其他出库 + */ + @Excel(name = "单据类型", width = 15) + @Schema(description = "单据类型") + @Dict(dicCode = "pick_order_type") + private java.lang.Integer orderType; + /** + * 订单状态:1.已创建;2.部分分配;3.已分配;4.拣货中;5.拣货完成;6.已关闭;7.已取消 + */ + @Excel(name = "订单状态", width = 15) + @Schema(description = "订单状态") + @Dict(dicCode = "pick_status") + private java.lang.Integer status; + /** + * 需求数量 + */ + @Excel(name = "需求数量", width = 15) + @Schema(description = "需求数量") + private java.math.BigDecimal orderQty; + /** + * 分配数量 + */ + @Excel(name = "分配数量", width = 15) + @Schema(description = "分配数量") + private java.math.BigDecimal allocatedQty; + /** + * 拣货数量 + */ + @Excel(name = "拣货数量", width = 15) + @Schema(description = "拣货数量") + private java.math.BigDecimal pickedQty; + /** + * 订单日期 + */ + @Excel(name = "订单日期", width = 20, format = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "订单日期") + private java.util.Date orderDate; + /** + * 所属部门 + */ + @Schema(description = "所属部门") + private java.lang.String sysOrgCode; + /** + * 仓库ID + */ + @Excel(name = "仓库ID", width = 15) + @Schema(description = "仓库ID") + private java.lang.Long tenantId; + /** + * 创建人 + */ + @Schema(description = "创建人") + private java.lang.String createBy; + /** + * 创建日期 + */ + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "创建日期") + private java.util.Date createTime; + /** + * 更新人 + */ + @Schema(description = "更新人") + private java.lang.String updateBy; + /** + * 更新日期 + */ + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "更新日期") + private java.util.Date updateTime; +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/entity/PickDetail.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/entity/PickDetail.java new file mode 100644 index 0000000..4afe5ef --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/entity/PickDetail.java @@ -0,0 +1,197 @@ +package org.cpte.modules.shipping.entity; + +import java.io.Serializable; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.NoArgsConstructor; +import org.jeecg.common.aspect.annotation.Dict; +import org.jeecg.common.constant.ProvinceCityArea; +import org.jeecg.common.util.SpringContextUtils; +import lombok.Data; +import com.fasterxml.jackson.annotation.JsonFormat; +import org.springframework.format.annotation.DateTimeFormat; +import org.jeecgframework.poi.excel.annotation.Excel; + +import java.util.Date; + +import io.swagger.v3.oas.annotations.media.Schema; + +import java.io.UnsupportedEncodingException; + +/** + * @Description: 出库明细 + * @author: cpte + * @Date: 2025-11-14 + * @Version: V1.0 + */ +@Schema(description = "出库明细") +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@TableName("data_pick_detail") +public class PickDetail implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * id + */ + @TableId(type = IdType.ASSIGN_ID) + @Schema(description = "id") + @JsonSerialize(using = ToStringSerializer.class) + private java.lang.Long id; + /** + * 出库单ID + */ + @Schema(description = "出库单ID") + @JsonSerialize(using = ToStringSerializer.class) + private java.lang.Long pickId; + /** + * 物料ID + */ + @Excel(name = "物料ID", width = 15) + @Schema(description = "物料ID") + @JsonSerialize(using = ToStringSerializer.class) + private java.lang.Long itemId; + /** + * 行号 + */ + @Excel(name = "行号", width = 15) + @Schema(description = "行号") + private java.lang.Integer lineNo; + /** + * 单位 + */ + @Excel(name = "单位", width = 15) + @Schema(description = "单位") + private java.lang.String unit; + /** + * 项目号 + */ + @Excel(name = "项目号", width = 15) + @Schema(description = "项目号") + private java.lang.String project; + /** + * 任务号 + */ + @Excel(name = "任务号", width = 15) + @Schema(description = "任务号") + private java.lang.String taskNo; + /** + * 需求数量 + */ + @Excel(name = "需求数量", width = 15) + @Schema(description = "需求数量") + private java.math.BigDecimal orderQty; + /** + * 分配数量 + */ + @Excel(name = "分配数量", width = 15) + @Schema(description = "分配数量") + private java.math.BigDecimal allocatedQty; + /** + * 拣货数量 + */ + @Excel(name = "拣货数量", width = 15) + @Schema(description = "拣货数量") + private java.math.BigDecimal pickedQty; + /** + * 订单状态:1.已创建;2.部分分配;3.已分配;4.拣货中;5.拣货完成;6.已关闭;7.已取消 + */ + @Excel(name = "订单状态", width = 15) + @Schema(description = "订单状态") + @Dict(dicCode = "pick_status") + private java.lang.Integer status; + /** + * 批次号 + */ + @Excel(name = "批次号", width = 15) + @Schema(description = "批次号") + private java.lang.String propC1; + /** + * 序列号 + */ + @Excel(name = "序列号", width = 15) + @Schema(description = "序列号") + private java.lang.String propC2; + /** + * 外部库存状态 + */ + @Excel(name = "外部库存状态", width = 15) + @Schema(description = "外部库存状态") + private java.lang.String propC3; + /** + * 扩展字段 + */ + @Excel(name = "扩展字段", width = 15) + @Schema(description = "扩展字段") + private java.lang.String propC4; + /** + * 生产日期 + */ + @Excel(name = "生产日期", width = 15, format = "yyyy-MM-dd") + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") + @DateTimeFormat(pattern = "yyyy-MM-dd") + @Schema(description = "生产日期") + private java.util.Date propD1; + /** + * 备注 + */ + @Excel(name = "备注", width = 15) + @Schema(description = "备注") + private java.lang.String description; + /** + * 来源ID + */ + @Excel(name = "来源ID", width = 15) + @Schema(description = "来源ID") + private java.lang.Long sourceId; + /** + * 来源 + */ + @Excel(name = "来源", width = 15) + @Schema(description = "来源") + private java.lang.String sourceName; + /** + * 仓库ID + */ + @Excel(name = "仓库ID", width = 15) + @Schema(description = "仓库ID") + private java.lang.Long tenantId; + /** + * 所属部门 + */ + @Schema(description = "所属部门") + private java.lang.String sysOrgCode; + /** + * 创建人 + */ + @Schema(description = "创建人") + private java.lang.String createBy; + /** + * 创建日期 + */ + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "创建日期") + private java.util.Date createTime; + /** + * 更新人 + */ + @Schema(description = "更新人") + private java.lang.String updateBy; + /** + * 更新日期 + */ + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "更新日期") + private java.util.Date updateTime; +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/mapper/PickDetailMapper.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/mapper/PickDetailMapper.java new file mode 100644 index 0000000..16a4618 --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/mapper/PickDetailMapper.java @@ -0,0 +1,31 @@ +package org.cpte.modules.shipping.mapper; + +import java.util.List; +import org.cpte.modules.shipping.entity.PickDetail; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Param; + +/** + * @Description: 出库明细 + * @author: cpte + * @Date: 2025-11-14 + * @Version: V1.0 + */ +public interface PickDetailMapper extends BaseMapper { + + /** + * 通过主表id删除子表数据 + * + * @param mainId 主表id + * @return boolean + */ + public boolean deleteByMainId(@Param("mainId") Long mainId); + + /** + * 通过主表id查询子表数据 + * + * @param mainId 主表id + * @return List + */ + public List selectByMainId(@Param("mainId") Long mainId); +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/mapper/PickMapper.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/mapper/PickMapper.java new file mode 100644 index 0000000..3c8b9a0 --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/mapper/PickMapper.java @@ -0,0 +1,26 @@ +package org.cpte.modules.shipping.mapper; + + +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import org.cpte.modules.shipping.entity.Pick; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * @Description: 出库单 + * @author: cpte + * @Date: 2025-11-14 + * @Version: V1.0 + */ +public interface PickMapper extends BaseMapper { + + /** + * 根据任务号查询出库单 + * + * @param no 任务号 + * @return Pick + */ + @Select("select * from data_pick where no = #{no} for update ") + Pick queryByNo(@Param("no") String no); + +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/mapper/xml/PickDetailMapper.xml b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/mapper/xml/PickDetailMapper.xml new file mode 100644 index 0000000..087918b --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/mapper/xml/PickDetailMapper.xml @@ -0,0 +1,18 @@ + + + + + + DELETE + FROM data_pick_detail + WHERE + pick_id = #{mainId} + + + + diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/mapper/xml/PickMapper.xml b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/mapper/xml/PickMapper.xml new file mode 100644 index 0000000..556325f --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/mapper/xml/PickMapper.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/IPickDetailService.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/IPickDetailService.java new file mode 100644 index 0000000..7ade81a --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/IPickDetailService.java @@ -0,0 +1,22 @@ +package org.cpte.modules.shipping.service; + +import org.cpte.modules.shipping.entity.PickDetail; +import com.baomidou.mybatisplus.extension.service.IService; +import java.util.List; + +/** + * @Description: 出库明细 + * @author: cpte + * @Date: 2025-11-14 + * @Version: V1.0 + */ +public interface IPickDetailService extends IService { + + /** + * 通过主表id查询子表数据 + * + * @param mainId 主表id + * @return List + */ + public List selectByMainId(Long mainId); +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/IPickService.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/IPickService.java new file mode 100644 index 0000000..70d0819 --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/IPickService.java @@ -0,0 +1,48 @@ +package org.cpte.modules.shipping.service; + +import org.cpte.modules.shipping.entity.PickDetail; +import org.cpte.modules.shipping.entity.Pick; +import com.baomidou.mybatisplus.extension.service.IService; +import java.io.Serializable; +import java.util.Collection; +import java.util.List; + +/** + * @Description: 出库单 + * @author: cpte + * @Date: 2025-11-14 + * @Version: V1.0 + */ +public interface IPickService extends IService { + + /** + * 添加一对多 + * + * @param pick + * @param pickDetailList + */ + public void saveMain(Pick pick,List pickDetailList) ; + + /** + * 修改一对多 + * + * @param pick + * @param pickDetailList + */ + public void updateMain(Pick pick,List pickDetailList); + + /** + * 删除一对多 + * + * @param id + */ + public void delMain (Long id); + + /** + * 批量删除一对多 + * + * @param idList + */ + public void delBatchMain (Collection idList); + +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/impl/PickDetailServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/impl/PickDetailServiceImpl.java new file mode 100644 index 0000000..7f9fb47 --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/impl/PickDetailServiceImpl.java @@ -0,0 +1,27 @@ +package org.cpte.modules.shipping.service.impl; + +import org.cpte.modules.shipping.entity.PickDetail; +import org.cpte.modules.shipping.mapper.PickDetailMapper; +import org.cpte.modules.shipping.service.IPickDetailService; +import org.springframework.stereotype.Service; +import java.util.List; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * @Description: 出库明细 + * @author: cpte + * @Date: 2025-11-14 + * @Version: V1.0 + */ +@Service +public class PickDetailServiceImpl extends ServiceImpl implements IPickDetailService { + + @Autowired + private PickDetailMapper pickDetailMapper; + + @Override + public List selectByMainId(Long mainId) { + return pickDetailMapper.selectByMainId(mainId); + } +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/impl/PickServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/impl/PickServiceImpl.java new file mode 100644 index 0000000..787efb8 --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/impl/PickServiceImpl.java @@ -0,0 +1,153 @@ +package org.cpte.modules.shipping.service.impl; + +import org.cpte.modules.constant.enums.AsnStatusEnum; +import org.cpte.modules.constant.enums.PickStatusEnum; +import org.cpte.modules.receive.entity.Asn; +import org.cpte.modules.receive.entity.AsnDetail; +import org.cpte.modules.shipping.entity.Pick; +import org.cpte.modules.shipping.entity.PickDetail; +import org.cpte.modules.shipping.mapper.PickDetailMapper; +import org.cpte.modules.shipping.mapper.PickMapper; +import org.cpte.modules.shipping.service.IPickService; +import org.cpte.modules.utils.BigDecimalUtil; +import org.springframework.stereotype.Service; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; +import java.util.Collection; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @Description: 出库单 + * @author: cpte + * @Date: 2025-11-14 + * @Version: V1.0 + */ +@Service +public class PickServiceImpl extends ServiceImpl implements IPickService { + + @Autowired + private PickMapper pickMapper; + @Autowired + private PickDetailMapper pickDetailMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public void saveMain(Pick pick, List pickDetailList) { + pickMapper.insert(pick); + if (pickDetailList != null && !pickDetailList.isEmpty()) { + AtomicInteger lineNoCounter = new AtomicInteger(1); + for (PickDetail entity : pickDetailList) { + if (entity.getLineNo() == null || entity.getLineNo() == 0) { + entity.setLineNo(lineNoCounter.getAndIncrement()); + } + entity.setPickId(pick.getId()); + pickDetailMapper.insert(entity); + } + } + //刷新出库单 + refreshPick(pick, pickDetailList); + } + + public synchronized void refreshPick(Pick pick, List pickDetails) { + if (pickDetails == null) { + pickDetails = new ArrayList<>(); + } + + // 计算各种数量 + BigDecimal orderQty = pickDetails.stream().map(PickDetail::getOrderQty).reduce(BigDecimal.ZERO, BigDecimal::add); + BigDecimal allocatedQty = pickDetails.stream().map(PickDetail::getAllocatedQty).reduce(BigDecimal.ZERO, BigDecimal::add); + BigDecimal pickedQty = pickDetails.stream().map(PickDetail::getPickedQty).reduce(BigDecimal.ZERO, BigDecimal::add); + + // 当前状态 + Integer status = pick.getStatus(); + + // 如果没有任何需求,则为创建状态 + if (orderQty.compareTo(BigDecimal.ZERO) <= 0) { + status = PickStatusEnum.CREATED.getValue(); + } + // 如果分配数量为0,但有需求数量,则为创建状态 + else if (allocatedQty.compareTo(BigDecimal.ZERO) == 0) { + status = PickStatusEnum.CREATED.getValue(); + } + // 如果已全部分配但未开始拣货 + else if (allocatedQty.compareTo(orderQty) >= 0 && pickedQty.compareTo(BigDecimal.ZERO) == 0) { + status = PickStatusEnum.ASSIGNED.getValue(); + } + // 如果部分分配且未开始拣货 + else if (allocatedQty.compareTo(orderQty) < 0 && pickedQty.compareTo(BigDecimal.ZERO) == 0) { + status = PickStatusEnum.PARTIAL.getValue(); + } + // 如果开始拣货但未完成 + else if (pickedQty.compareTo(BigDecimal.ZERO) > 0 && pickedQty.compareTo(allocatedQty) < 0) { + status = PickStatusEnum.PICKING.getValue(); + } + // 如果已完成拣货 + else if (pickedQty.compareTo(allocatedQty) >= 0 && allocatedQty.compareTo(BigDecimal.ZERO) > 0) { + status = PickStatusEnum.PICKED.getValue(); + } + + // 更新实体属性 + pick.setOrderQty(orderQty); + pick.setAllocatedQty(allocatedQty); + pick.setPickedQty(pickedQty); + pick.setStatus(status); + pickMapper.updateById(pick); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateMain(Pick pick, List pickDetailList) { + // 直接更新主表 + pickMapper.updateById(pick); + + // 更新明细表 - 只更新传入的明细数据 + if (pickDetailList != null && !pickDetailList.isEmpty()) { + for (PickDetail entity : pickDetailList) { + entity.setPickId(pick.getId()); + // 直接更新,而不是删除后重新插入 + if (entity.getId() != null) { + pickDetailMapper.updateById(entity); + } + } + } + + // 刷新出库单状态 + refreshPick(pick, pickDetailList); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delMain(Long id) { + Pick pick = this.getById(id); + if (!AsnStatusEnum.CREATED.getValue().equals(pick.getStatus())) { + throw new RuntimeException("操作失败:【" + pick.getOrderNo() + "】出库单,非创建状态不允许删除"); + } + pickDetailMapper.deleteByMainId(id); + pickMapper.deleteById(id); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delBatchMain(Collection idList) { + List orderNoList = new ArrayList<>(); + for (Serializable id : idList) { + Pick pick = this.getById(id); + if (!AsnStatusEnum.CREATED.getValue().equals(pick.getStatus())) { + orderNoList.add(pick.getOrderNo()); + continue; + } + pickDetailMapper.deleteByMainId(Long.parseLong(id.toString())); + pickMapper.deleteById(id); + } + if (!orderNoList.isEmpty()) { + throw new RuntimeException("操作失败:【" + orderNoList + "】出库单,非创建状态不允许删除"); + } + } + +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/vo/PickPage.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/vo/PickPage.java new file mode 100644 index 0000000..9b53f2b --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/vo/PickPage.java @@ -0,0 +1,140 @@ +package org.cpte.modules.shipping.vo; + +import java.util.List; + +import org.cpte.modules.shipping.entity.Pick; +import org.cpte.modules.shipping.entity.PickDetail; +import lombok.Data; +import org.jeecgframework.poi.excel.annotation.Excel; +import org.jeecgframework.poi.excel.annotation.ExcelEntity; +import org.jeecgframework.poi.excel.annotation.ExcelCollection; +import com.fasterxml.jackson.annotation.JsonFormat; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +import org.jeecg.common.aspect.annotation.Dict; +import org.jeecg.common.constant.ProvinceCityArea; +import org.jeecg.common.util.SpringContextUtils; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * @Description: 出库单 + * @author: cpte + * @Date: 2025-11-14 + * @Version: V1.0 + */ +@Data +@Schema(description = "出库单") +public class PickPage { + + /** + * id + */ + @Schema(description = "id") + private java.lang.Long id; + + /** + * 外部单号 + */ + @Excel(name = "外部单号", width = 15) + @Schema(description = "外部单号") + private java.lang.String thirdOrderNo; + /** + * 任务号 + */ + @Excel(name = "任务号", width = 15) + @Schema(description = "任务号") + private java.lang.String no; + /** + * 外部仓库 + */ + @Excel(name = "外部仓库", width = 15) + @Schema(description = "外部仓库") + private java.lang.String whCode; + /** + * 客户代码 + */ + @Excel(name = "客户代码", width = 15) + @Schema(description = "客户代码") + private java.lang.String customerCode; + /** + * 单据类型;0.成品入库;1.配件入库;2.成品拆托入库;3.配件拆托入库;4.成品出库;5.配件出库;6.返工出库;7.检验出库;8.其他出库 + */ + @Excel(name = "单据类型", width = 15) + @Schema(description = "单据类型") + private java.lang.Integer orderType; + /** + * 订单状态:1.已创建;2.部分分配;3.已分配;4.拣货中;5.拣货完成;6.已关闭;7.已取消 + */ + @Excel(name = "订单状态", width = 15) + @Schema(description = "订单状态") + private java.lang.Integer status; + /** + * 需求数量 + */ + @Excel(name = "需求数量", width = 15) + @Schema(description = "需求数量") + private java.math.BigDecimal orderQty; + /** + * 分配数量 + */ + @Excel(name = "分配数量", width = 15) + @Schema(description = "分配数量") + private java.math.BigDecimal allocatedQty; + /** + * 拣货数量 + */ + @Excel(name = "拣货数量", width = 15) + @Schema(description = "拣货数量") + private java.math.BigDecimal pickedQty; + /** + * 订单日期 + */ + @Excel(name = "订单日期", width = 20, format = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "订单日期") + private java.util.Date orderDate; + /** + * 所属部门 + */ + @Schema(description = "所属部门") + private java.lang.String sysOrgCode; + /** + * 仓库ID + */ + @Excel(name = "仓库ID", width = 15) + @Schema(description = "仓库ID") + private java.lang.Long tenantId; + /** + * 创建人 + */ + @Schema(description = "创建人") + private java.lang.String createBy; + /** + * 创建日期 + */ + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "创建日期") + private java.util.Date createTime; + /** + * 更新人 + */ + @Schema(description = "更新人") + private java.lang.String updateBy; + /** + * 更新日期 + */ + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "更新日期") + private java.util.Date updateTime; + + @ExcelCollection(name = "出库明细") + @Schema(description = "出库明细") + private List pickDetailList; + +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/utils/CodeGeneratorUtil.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/utils/CodeGeneratorUtil.java index 1923845..3a90fc5 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/utils/CodeGeneratorUtil.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/utils/CodeGeneratorUtil.java @@ -1,12 +1,8 @@ package org.cpte.modules.utils; -import com.alibaba.fastjson.JSONObject; -import com.jeecg.weibo.exception.BusinessException; import lombok.extern.slf4j.Slf4j; -import org.jeecg.common.handler.IFillRuleHandler; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.CannotAcquireLockException; -import org.springframework.dao.DeadlockLoserDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -18,7 +14,7 @@ import java.util.List; @Service @Slf4j -public class CodeGeneratorUtil implements IFillRuleHandler { +public class CodeGeneratorUtil { @Autowired public JdbcTemplate jdbcTemplate; @@ -61,13 +57,7 @@ public class CodeGeneratorUtil implements IFillRuleHandler { } } - @Override - public Object execute(JSONObject params, JSONObject formData) { - String prefix = params.getString("prefix"); - Object code = generateSerialNumber(prefix); - log.info("生成业务编号:{}", code); - return code; - } + } /* diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/utils/SmartEnumUtil.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/utils/SmartEnumUtil.java deleted file mode 100644 index a25a3a1..0000000 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/utils/SmartEnumUtil.java +++ /dev/null @@ -1,163 +0,0 @@ -package org.cpte.modules.utils; - -import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.StringUtils; -import org.cpte.modules.constant.enums.BaseEnum; - -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.function.BiConsumer; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - * 枚举工具类 - * - * @Author YouChain: 胡克 - * @Date 2017/10/10 18:17 - * @Email huoj@youchain56.com - */ -public class SmartEnumUtil { - - /** - * 校验参数与枚举类比较是否合法 - * - * @param value 参数 - * @param enumClass 枚举类必须实现BaseEnum接口 - * @return boolean - * @Author 胡克 - */ - public static boolean checkEnum(Object value, Class enumClass) { - if (null == value) { - return false; - } - return Stream.of(enumClass.getEnumConstants()).anyMatch(e -> e.equalsValue(value)); - } - - /** - * 创建一个具有唯一array值的数组,每个值不包含在其他给定的数组中。 - * - * @param enumClass - * @param exclude - * @param - * @return - */ - public static List differenceValueList(Class enumClass, T... exclude) { - HashSet valueSet = new HashSet<>(); - if (exclude != null) { - valueSet.addAll(Stream.of(exclude).map(BaseEnum::getValue).collect(Collectors.toSet())); - } - - return Stream.of(enumClass.getEnumConstants()) - .filter(e -> !valueSet.contains(e.getValue())) - .map(BaseEnum::getValue) - .collect(Collectors.toList()); - } - - /** - * 获取枚举类的说明 value : info 的形式 - * - * @param enumClass - * @return String - */ - public static String getEnumDesc(Class enumClass) { - BaseEnum[] enums = enumClass.getEnumConstants(); - // value : info 的形式 - StringBuilder sb = new StringBuilder(); - for (BaseEnum baseEnum : enums) { - sb.append(baseEnum.getValue()).append(":").append(baseEnum.getDesc()).append(","); - } - return sb.toString(); - } - - /** - * 获取与参数相匹配的枚举类实例的 说明 - * - * @param value 参数 - * @param enumClass 枚举类必须实现BaseEnum接口 - * @return String 如无匹配枚举则返回null - */ - public static String getEnumDescByValue(Object value, Class enumClass) { - if (null == value) { - return null; - } - return Stream.of(enumClass.getEnumConstants()) - .filter(e -> e.equalsValue(value)) - .findFirst() - .map(BaseEnum::getDesc) - .orElse(null); - } - - public static String getEnumDescByValueList(Collection values, Class enumClass) { - if (CollectionUtils.isEmpty(values)) { - return ""; - } - return Stream.of(enumClass.getEnumConstants()).filter(e -> values.contains(e.getValue())).map(BaseEnum::getDesc).collect(Collectors.joining(",")); - } - - /** - * 根据参数获取枚举类的实例 - * - * @param value 参数 - * @param enumClass 枚举类必须实现BaseEnum接口 - * @return BaseEnum 无匹配值返回null - * @Author 胡克 - */ - public static T getEnumByValue(Object value, Class enumClass) { - if (null == value) { - return null; - } - return Stream.of(enumClass.getEnumConstants()) - .filter(e -> e.equalsValue(value)) - .findFirst() - .orElse(null); - } - - /** - * 根据实例描述与获取枚举类的实例 - * - * @param desc 参数描述 - * @param enumClass 枚举类必须实现BaseEnum接口 - * @return BaseEnum 无匹配值返回null - * @Author 胡克 - */ - public static T getEnumByDesc(String desc, Class enumClass) { - return Stream.of(enumClass.getEnumConstants()) - .filter(e -> Objects.equals(e.getDesc(), desc)) - .findFirst() - .orElse(null); - } - - - public static T getEnumByName(String name, Class enumClass) { - return Stream.of(enumClass.getEnumConstants()) - .filter(e -> StringUtils.equalsIgnoreCase(e.toString(), name)) - .findFirst() - .orElse(null); - } - - - /** - * 根据lambda getter/setter 注入 - * - * @param list - * @param getter - * @param setter - * @param enumClass - * @param - */ - public static void inject(List list, Function getter, BiConsumer setter, Class enumClass) { - if (list == null || list.isEmpty()) { - return; - } - for (T t : list) { - Integer enumValue = getter.apply(t); - if (enumValue != null) { - setter.accept(t, getEnumDescByValue(enumValue, enumClass)); - } - } - } -} diff --git a/cpte-module-system/cpte-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysFillRuleMapper.java b/cpte-module-system/cpte-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysFillRuleMapper.java index 73c70ae..0ce0ab9 100644 --- a/cpte-module-system/cpte-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysFillRuleMapper.java +++ b/cpte-module-system/cpte-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysFillRuleMapper.java @@ -1,6 +1,7 @@ package org.jeecg.modules.system.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Select; import org.jeecg.modules.system.entity.SysFillRule; /** @@ -10,5 +11,12 @@ import org.jeecg.modules.system.entity.SysFillRule; * @Version: V1.0 */ public interface SysFillRuleMapper extends BaseMapper { - + /** + * 根据规则编码查询规则 + * + * @param ruleCode 编码规则 + * @return 返回规则 + */ + @Select("select rule_params from sys_fill_rule where rule_code = #{ruleCode}") + String queryByRuleCode(String ruleCode); }