From 22ace156f909201c462fa452276b2dc0b894ed60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=B1=E6=98=8A=E5=A4=A9?= <15984976+n2319_0@user.noreply.gitee.com> Date: Thu, 7 May 2026 15:59:27 +0800 Subject: [PATCH] =?UTF-8?q?=E5=87=BA=E5=85=A5=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mat/controller/MatMaterialController.java | 8 +- .../GearStockIoOrderController.java | 124 +++ .../com/gear/oa/domain/GearStockIoOrder.java | 92 ++ .../oa/domain/GearStockIoOrderDetail.java | 57 ++ .../gear/oa/domain/bo/GearStockIoOrderBo.java | 90 ++ .../domain/bo/GearStockIoOrderDetailBo.java | 56 ++ .../bo/GearStockIoOrderWithDetailBo.java | 51 ++ .../domain/vo/GearStockIoOrderDetailVo.java | 52 ++ .../gear/oa/domain/vo/GearStockIoOrderVo.java | 91 ++ .../vo/GearStockIoOrderWithDetailVo.java | 14 + .../mapper/GearStockIoOrderDetailMapper.java | 9 + .../oa/mapper/GearStockIoOrderMapper.java | 9 + .../oa/mapper/MatMaterialSimpleMapper.java | 19 + .../oa/service/IGearStockIoOrderService.java | 43 + .../impl/GearStockIoOrderServiceImpl.java | 706 +++++++++++++++ gear-ui3/src/api/wms/stockIoOrder.js | 98 +++ gear-ui3/src/components/RawSelector/index.vue | 199 ++++- gear-ui3/src/views/mat/auxiliary/index.vue | 4 +- gear-ui3/src/views/mat/raw/index.vue | 2 - gear-ui3/src/views/wms/stockIoOrder/in.vue | 514 +++++++++++ gear-ui3/src/views/wms/stockIoOrder/index.vue | 12 + gear-ui3/src/views/wms/stockIoOrder/out.vue | 486 +++++++++++ .../stockIoOrder/panels/stockIoOrderPage.vue | 808 ++++++++++++++++++ 23 files changed, 3522 insertions(+), 22 deletions(-) create mode 100644 gear-oa/src/main/java/com/gear/oa/controller/GearStockIoOrderController.java create mode 100644 gear-oa/src/main/java/com/gear/oa/domain/GearStockIoOrder.java create mode 100644 gear-oa/src/main/java/com/gear/oa/domain/GearStockIoOrderDetail.java create mode 100644 gear-oa/src/main/java/com/gear/oa/domain/bo/GearStockIoOrderBo.java create mode 100644 gear-oa/src/main/java/com/gear/oa/domain/bo/GearStockIoOrderDetailBo.java create mode 100644 gear-oa/src/main/java/com/gear/oa/domain/bo/GearStockIoOrderWithDetailBo.java create mode 100644 gear-oa/src/main/java/com/gear/oa/domain/vo/GearStockIoOrderDetailVo.java create mode 100644 gear-oa/src/main/java/com/gear/oa/domain/vo/GearStockIoOrderVo.java create mode 100644 gear-oa/src/main/java/com/gear/oa/domain/vo/GearStockIoOrderWithDetailVo.java create mode 100644 gear-oa/src/main/java/com/gear/oa/mapper/GearStockIoOrderDetailMapper.java create mode 100644 gear-oa/src/main/java/com/gear/oa/mapper/GearStockIoOrderMapper.java create mode 100644 gear-oa/src/main/java/com/gear/oa/mapper/MatMaterialSimpleMapper.java create mode 100644 gear-oa/src/main/java/com/gear/oa/service/IGearStockIoOrderService.java create mode 100644 gear-oa/src/main/java/com/gear/oa/service/impl/GearStockIoOrderServiceImpl.java create mode 100644 gear-ui3/src/api/wms/stockIoOrder.js create mode 100644 gear-ui3/src/views/wms/stockIoOrder/in.vue create mode 100644 gear-ui3/src/views/wms/stockIoOrder/index.vue create mode 100644 gear-ui3/src/views/wms/stockIoOrder/out.vue create mode 100644 gear-ui3/src/views/wms/stockIoOrder/panels/stockIoOrderPage.vue diff --git a/gear-mat/src/main/java/com/gear/mat/controller/MatMaterialController.java b/gear-mat/src/main/java/com/gear/mat/controller/MatMaterialController.java index cf72e41..1d071e1 100644 --- a/gear-mat/src/main/java/com/gear/mat/controller/MatMaterialController.java +++ b/gear-mat/src/main/java/com/gear/mat/controller/MatMaterialController.java @@ -75,8 +75,12 @@ public class MatMaterialController extends BaseController { @Log(title = "配料配件基础信息", businessType = BusinessType.INSERT) @RepeatSubmit() @PostMapping() - public R add(@Validated(AddGroup.class) @RequestBody MatMaterialBo bo) { - return toAjax(iMatMaterialService.insertByBo(bo)); + public R add(@Validated(AddGroup.class) @RequestBody MatMaterialBo bo) { + boolean ok = iMatMaterialService.insertByBo(bo); + if (!ok) { + return R.fail(); + } + return R.ok(bo.getMaterialId()); } /** diff --git a/gear-oa/src/main/java/com/gear/oa/controller/GearStockIoOrderController.java b/gear-oa/src/main/java/com/gear/oa/controller/GearStockIoOrderController.java new file mode 100644 index 0000000..427cec5 --- /dev/null +++ b/gear-oa/src/main/java/com/gear/oa/controller/GearStockIoOrderController.java @@ -0,0 +1,124 @@ +package com.gear.oa.controller; + +import com.gear.common.annotation.Log; +import com.gear.common.annotation.RepeatSubmit; +import com.gear.common.core.controller.BaseController; +import com.gear.common.core.domain.PageQuery; +import com.gear.common.core.domain.R; +import com.gear.common.core.page.TableDataInfo; +import com.gear.common.core.validate.AddGroup; +import com.gear.common.core.validate.EditGroup; +import com.gear.common.enums.BusinessType; +import com.gear.oa.domain.bo.GearStockIoOrderBo; +import com.gear.oa.domain.bo.GearStockIoOrderWithDetailBo; +import com.gear.oa.domain.vo.GearStockIoOrderVo; +import com.gear.oa.domain.vo.GearStockIoOrderWithDetailVo; +import com.gear.oa.service.IGearStockIoOrderService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Arrays; +import java.util.Map; + +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/gear/stockIoOrder") +public class GearStockIoOrderController extends BaseController { + + private final IGearStockIoOrderService stockIoOrderService; + + @GetMapping("/list") + public TableDataInfo list(GearStockIoOrderBo bo, PageQuery pageQuery) { + return stockIoOrderService.queryPageList(bo, pageQuery); + } + + @GetMapping("/{orderId}") + public R getInfo(@NotNull(message = "主键不能为空") @PathVariable Long orderId) { + return R.ok(stockIoOrderService.queryById(orderId)); + } + + @GetMapping("/withDetail/{orderId}") + public R getWithDetail(@NotNull(message = "主键不能为空") @PathVariable Long orderId) { + return R.ok(stockIoOrderService.queryWithDetail(orderId)); + } + + @Log(title = "出入库单据", businessType = BusinessType.INSERT) + @RepeatSubmit + @PostMapping("/withDetail") + public R addWithDetail(@Validated(AddGroup.class) @RequestBody GearStockIoOrderWithDetailBo bo) { + return R.ok(stockIoOrderService.createWithDetail(bo)); + } + + @Log(title = "出入库单据", businessType = BusinessType.UPDATE) + @RepeatSubmit + @PutMapping("/withDetail") + public R editWithDetail(@Validated(EditGroup.class) @RequestBody GearStockIoOrderWithDetailBo bo) { + stockIoOrderService.updateWithDetail(bo); + return R.ok(); + } + + @Log(title = "出入库单据", businessType = BusinessType.DELETE) + @DeleteMapping("/{orderIds}") + public R remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] orderIds) { + return toAjax(stockIoOrderService.deleteWithValidByIds(Arrays.asList(orderIds), true)); + } + + @Log(title = "出入库单据", businessType = BusinessType.UPDATE) + @PostMapping("/submit/{orderId}") + public R submit(@NotNull(message = "主键不能为空") @PathVariable Long orderId) { + stockIoOrderService.submitOrder(orderId); + return R.ok(); + } + + @Log(title = "出入库单据", businessType = BusinessType.UPDATE) + @PostMapping("/audit/{orderId}") + public R audit(@NotNull(message = "主键不能为空") @PathVariable Long orderId) { + stockIoOrderService.auditOrder(orderId); + return R.ok(); + } + + @Log(title = "出入库单据", businessType = BusinessType.UPDATE) + @PostMapping("/execute/{orderId}") + public R execute(@NotNull(message = "主键不能为空") @PathVariable Long orderId) { + stockIoOrderService.executeOrder(orderId); + return R.ok(); + } + + @Log(title = "出入库单据", businessType = BusinessType.UPDATE) + @PostMapping("/arrival/{orderId}") + public R arrival(@NotNull(message = "主键不能为空") @PathVariable Long orderId) { + stockIoOrderService.confirmArrival(orderId); + return R.ok(); + } + + @Log(title = "出入库单据", businessType = BusinessType.UPDATE) + @PostMapping("/finish/{orderId}") + public R finish(@NotNull(message = "主键不能为空") @PathVariable Long orderId) { + stockIoOrderService.finishOrder(orderId); + return R.ok(); + } + + @Log(title = "出入库单据", businessType = BusinessType.UPDATE) + @RepeatSubmit + @PostMapping("/cancel/{orderId}") + public R cancel(@NotNull(message = "主键不能为空") @PathVariable Long orderId, + @RequestBody(required = false) Map payload) { + String reason = payload == null ? "" : String.valueOf(payload.getOrDefault("reason", "")); + stockIoOrderService.cancelOrder(orderId, reason); + return R.ok(); + } + + @Log(title = "出入库单据", businessType = BusinessType.UPDATE) + @RepeatSubmit + @PostMapping("/reverse/{orderId}") + public R reverse(@NotNull(message = "主键不能为空") @PathVariable Long orderId, + @RequestBody(required = false) Map payload) { + String reason = payload == null ? "" : String.valueOf(payload.getOrDefault("reason", "")); + return R.ok(stockIoOrderService.reverseOrder(orderId, reason)); + } +} + diff --git a/gear-oa/src/main/java/com/gear/oa/domain/GearStockIoOrder.java b/gear-oa/src/main/java/com/gear/oa/domain/GearStockIoOrder.java new file mode 100644 index 0000000..d517bfc --- /dev/null +++ b/gear-oa/src/main/java/com/gear/oa/domain/GearStockIoOrder.java @@ -0,0 +1,92 @@ +package com.gear.oa.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import com.gear.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; +import java.util.Date; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("gear_stock_io_order") +public class GearStockIoOrder extends BaseEntity { + + private static final long serialVersionUID = 1L; + + @TableId(value = "order_id") + private Long orderId; + + private String orderCode; + + private String ioType; + + private String bizType; + + private String sourceType; + + private String sourceNo; + + private Long sourceOrderId; + + private Long responsibleId; + + private String responsibleName; + + private Date planArrivalTime; + + private Date actualArrivalTime; + + private Date planFinishTime; + + private Date actualFinishTime; + + private Integer delayMinutes; + + private String delayReason; + + private String delayStatus; + + private Long warehouseId; + + private Long fromWarehouseId; + + private Long toWarehouseId; + + private String status; + + private String execFlag; + + private String reversalFlag; + + private Long reversalOrderId; + + private String reversalReason; + + private Date reversalTime; + + private String cancelReason; + + private Date cancelTime; + + private String auditBy; + + private Date auditTime; + + private String executeBy; + + private Date executeTime; + + private Long sourceIoId; + + private BigDecimal totalQty; + + private String remark; + + @TableLogic(value = "0", delval = "2") + private String delFlag; +} + diff --git a/gear-oa/src/main/java/com/gear/oa/domain/GearStockIoOrderDetail.java b/gear-oa/src/main/java/com/gear/oa/domain/GearStockIoOrderDetail.java new file mode 100644 index 0000000..a23bc2e --- /dev/null +++ b/gear-oa/src/main/java/com/gear/oa/domain/GearStockIoOrderDetail.java @@ -0,0 +1,57 @@ +package com.gear.oa.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import com.gear.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("gear_stock_io_order_detail") +public class GearStockIoOrderDetail extends BaseEntity { + + private static final long serialVersionUID = 1L; + + @TableId(value = "detail_id") + private Long detailId; + + private Long orderId; + + private Integer lineNo; + + private String itemType; + + private Long itemId; + + private String itemName; + + private String specName; + + private Long warehouseId; + + private Long fromWarehouseId; + + private BigDecimal quantity; + + private String unit; + + private String batchNo; + + private BigDecimal unitPrice; + + private BigDecimal amount; + + private String sourceDetailNo; + + private Long reversalDetailId; + + private String remark; + + @TableLogic(value = "0", delval = "2") + private String delFlag; +} + diff --git a/gear-oa/src/main/java/com/gear/oa/domain/bo/GearStockIoOrderBo.java b/gear-oa/src/main/java/com/gear/oa/domain/bo/GearStockIoOrderBo.java new file mode 100644 index 0000000..c94aaa1 --- /dev/null +++ b/gear-oa/src/main/java/com/gear/oa/domain/bo/GearStockIoOrderBo.java @@ -0,0 +1,90 @@ +package com.gear.oa.domain.bo; + +import com.gear.common.core.domain.BaseEntity; +import com.gear.common.core.validate.AddGroup; +import com.gear.common.core.validate.EditGroup; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.util.Date; + +@Data +@EqualsAndHashCode(callSuper = true) +public class GearStockIoOrderBo extends BaseEntity { + + private Long orderId; + + private String orderCode; + + @NotBlank(message = "出入库类型不能为空", groups = {AddGroup.class, EditGroup.class}) + private String ioType; + + @NotBlank(message = "业务类型不能为空", groups = {AddGroup.class, EditGroup.class}) + private String bizType; + + private String sourceType; + + private String sourceNo; + + private Long sourceOrderId; + + private Long responsibleId; + + private String responsibleName; + + private Date planArrivalTime; + + private Date actualArrivalTime; + + private Date planFinishTime; + + private Date actualFinishTime; + + private Integer delayMinutes; + + private String delayReason; + + private String delayStatus; + + private Long warehouseId; + + private Long fromWarehouseId; + + private Long toWarehouseId; + + private String status; + + private String execFlag; + + private String reversalFlag; + + private Long reversalOrderId; + + private String reversalReason; + + private Date reversalTime; + + private String cancelReason; + + private Date cancelTime; + + private String auditBy; + + private Date auditTime; + + private String executeBy; + + private Date executeTime; + + private Long sourceIoId; + + private BigDecimal totalQty; + + private String remark; + + private String delFlag; +} + diff --git a/gear-oa/src/main/java/com/gear/oa/domain/bo/GearStockIoOrderDetailBo.java b/gear-oa/src/main/java/com/gear/oa/domain/bo/GearStockIoOrderDetailBo.java new file mode 100644 index 0000000..9c4226b --- /dev/null +++ b/gear-oa/src/main/java/com/gear/oa/domain/bo/GearStockIoOrderDetailBo.java @@ -0,0 +1,56 @@ +package com.gear.oa.domain.bo; + +import com.gear.common.core.domain.BaseEntity; +import com.gear.common.core.validate.AddGroup; +import com.gear.common.core.validate.EditGroup; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; + +@Data +@EqualsAndHashCode(callSuper = true) +public class GearStockIoOrderDetailBo extends BaseEntity { + + private Long detailId; + + private Long orderId; + + private Integer lineNo; + + @NotBlank(message = "物料类型不能为空", groups = {AddGroup.class, EditGroup.class}) + private String itemType; + + @NotNull(message = "物料ID不能为空", groups = {AddGroup.class, EditGroup.class}) + private Long itemId; + + private String itemName; + + private String specName; + + private Long warehouseId; + + private Long fromWarehouseId; + + @NotNull(message = "数量不能为空", groups = {AddGroup.class, EditGroup.class}) + private BigDecimal quantity; + + private String unit; + + private String batchNo; + + private BigDecimal unitPrice; + + private BigDecimal amount; + + private String sourceDetailNo; + + private Long reversalDetailId; + + private String remark; + + private String delFlag; +} + diff --git a/gear-oa/src/main/java/com/gear/oa/domain/bo/GearStockIoOrderWithDetailBo.java b/gear-oa/src/main/java/com/gear/oa/domain/bo/GearStockIoOrderWithDetailBo.java new file mode 100644 index 0000000..254c725 --- /dev/null +++ b/gear-oa/src/main/java/com/gear/oa/domain/bo/GearStockIoOrderWithDetailBo.java @@ -0,0 +1,51 @@ +package com.gear.oa.domain.bo; + +import com.gear.common.core.validate.AddGroup; +import com.gear.common.core.validate.EditGroup; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; + +@Data +public class GearStockIoOrderWithDetailBo { + + private Long orderId; + + private String orderCode; + + @NotBlank(message = "出入库类型不能为空", groups = {AddGroup.class, EditGroup.class}) + private String ioType; + + @NotBlank(message = "业务类型不能为空", groups = {AddGroup.class, EditGroup.class}) + private String bizType; + + private String sourceType; + + private String sourceNo; + + private Long sourceOrderId; + + private Long responsibleId; + + private String responsibleName; + + private Date planArrivalTime; + + private Date planFinishTime; + + private Long warehouseId; + + private Long fromWarehouseId; + + private Long toWarehouseId; + + private String remark; + + private BigDecimal totalQty; + + private List details; +} + diff --git a/gear-oa/src/main/java/com/gear/oa/domain/vo/GearStockIoOrderDetailVo.java b/gear-oa/src/main/java/com/gear/oa/domain/vo/GearStockIoOrderDetailVo.java new file mode 100644 index 0000000..2545a8d --- /dev/null +++ b/gear-oa/src/main/java/com/gear/oa/domain/vo/GearStockIoOrderDetailVo.java @@ -0,0 +1,52 @@ +package com.gear.oa.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.gear.common.core.domain.BaseEntity; +import lombok.Data; + +import java.math.BigDecimal; + +@Data +@ExcelIgnoreUnannotated +public class GearStockIoOrderDetailVo extends BaseEntity { + + private static final long serialVersionUID = 1L; + + private Long detailId; + + private Long orderId; + + private Integer lineNo; + + private String itemType; + + private Long itemId; + + @ExcelProperty(value = "物料名称") + private String itemName; + + private String specName; + + private Long warehouseId; + + private Long fromWarehouseId; + + @ExcelProperty(value = "数量") + private BigDecimal quantity; + + private String unit; + + private String batchNo; + + private BigDecimal unitPrice; + + private BigDecimal amount; + + private String sourceDetailNo; + + private Long reversalDetailId; + + private String remark; +} + diff --git a/gear-oa/src/main/java/com/gear/oa/domain/vo/GearStockIoOrderVo.java b/gear-oa/src/main/java/com/gear/oa/domain/vo/GearStockIoOrderVo.java new file mode 100644 index 0000000..c40bd38 --- /dev/null +++ b/gear-oa/src/main/java/com/gear/oa/domain/vo/GearStockIoOrderVo.java @@ -0,0 +1,91 @@ +package com.gear.oa.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.gear.common.core.domain.BaseEntity; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; + +@Data +@ExcelIgnoreUnannotated +public class GearStockIoOrderVo extends BaseEntity { + + private static final long serialVersionUID = 1L; + + @ExcelProperty(value = "单据ID") + private Long orderId; + + @ExcelProperty(value = "单据编号") + private String orderCode; + + @ExcelProperty(value = "出入库类型") + private String ioType; + + @ExcelProperty(value = "业务类型") + private String bizType; + + private String sourceType; + + private String sourceNo; + + private Long sourceOrderId; + + private Long responsibleId; + + private String responsibleName; + + private Date planArrivalTime; + + private Date actualArrivalTime; + + private Date planFinishTime; + + private Date actualFinishTime; + + private Integer delayMinutes; + + private String delayReason; + + private String delayStatus; + + private Long warehouseId; + + private Long fromWarehouseId; + + private Long toWarehouseId; + + @ExcelProperty(value = "状态") + private String status; + + private String execFlag; + + private String reversalFlag; + + private Long reversalOrderId; + + private String reversalReason; + + private Date reversalTime; + + private String cancelReason; + + private Date cancelTime; + + private String auditBy; + + private Date auditTime; + + private String executeBy; + + private Date executeTime; + + private Long sourceIoId; + + private BigDecimal totalQty; + + private String remark; + + private String materialNames; +} diff --git a/gear-oa/src/main/java/com/gear/oa/domain/vo/GearStockIoOrderWithDetailVo.java b/gear-oa/src/main/java/com/gear/oa/domain/vo/GearStockIoOrderWithDetailVo.java new file mode 100644 index 0000000..edcd27c --- /dev/null +++ b/gear-oa/src/main/java/com/gear/oa/domain/vo/GearStockIoOrderWithDetailVo.java @@ -0,0 +1,14 @@ +package com.gear.oa.domain.vo; + +import lombok.Data; + +import java.util.List; + +@Data +public class GearStockIoOrderWithDetailVo { + + private GearStockIoOrderVo order; + + private List details; +} + diff --git a/gear-oa/src/main/java/com/gear/oa/mapper/GearStockIoOrderDetailMapper.java b/gear-oa/src/main/java/com/gear/oa/mapper/GearStockIoOrderDetailMapper.java new file mode 100644 index 0000000..92470bb --- /dev/null +++ b/gear-oa/src/main/java/com/gear/oa/mapper/GearStockIoOrderDetailMapper.java @@ -0,0 +1,9 @@ +package com.gear.oa.mapper; + +import com.gear.common.core.mapper.BaseMapperPlus; +import com.gear.oa.domain.GearStockIoOrderDetail; +import com.gear.oa.domain.vo.GearStockIoOrderDetailVo; + +public interface GearStockIoOrderDetailMapper extends BaseMapperPlus { +} + diff --git a/gear-oa/src/main/java/com/gear/oa/mapper/GearStockIoOrderMapper.java b/gear-oa/src/main/java/com/gear/oa/mapper/GearStockIoOrderMapper.java new file mode 100644 index 0000000..5c2abbc --- /dev/null +++ b/gear-oa/src/main/java/com/gear/oa/mapper/GearStockIoOrderMapper.java @@ -0,0 +1,9 @@ +package com.gear.oa.mapper; + +import com.gear.common.core.mapper.BaseMapperPlus; +import com.gear.oa.domain.GearStockIoOrder; +import com.gear.oa.domain.vo.GearStockIoOrderVo; + +public interface GearStockIoOrderMapper extends BaseMapperPlus { +} + diff --git a/gear-oa/src/main/java/com/gear/oa/mapper/MatMaterialSimpleMapper.java b/gear-oa/src/main/java/com/gear/oa/mapper/MatMaterialSimpleMapper.java new file mode 100644 index 0000000..89368b8 --- /dev/null +++ b/gear-oa/src/main/java/com/gear/oa/mapper/MatMaterialSimpleMapper.java @@ -0,0 +1,19 @@ +package com.gear.oa.mapper; + +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.annotations.Update; + +import java.math.BigDecimal; +import java.util.Map; + +public interface MatMaterialSimpleMapper { + + @Select("select material_id as materialId, material_name as materialName, material_type as materialType, unit as unit, current_stock as currentStock " + + "from mat_material where material_id = #{materialId} and del_flag = 0 limit 1") + Map selectSnapshot(@Param("materialId") Long materialId); + + @Update("update mat_material set current_stock = ifnull(current_stock, 0) + #{delta} where material_id = #{materialId} and del_flag = 0") + int updateStockDelta(@Param("materialId") Long materialId, @Param("delta") BigDecimal delta); +} + diff --git a/gear-oa/src/main/java/com/gear/oa/service/IGearStockIoOrderService.java b/gear-oa/src/main/java/com/gear/oa/service/IGearStockIoOrderService.java new file mode 100644 index 0000000..f5f2b0e --- /dev/null +++ b/gear-oa/src/main/java/com/gear/oa/service/IGearStockIoOrderService.java @@ -0,0 +1,43 @@ +package com.gear.oa.service; + +import com.gear.common.core.domain.PageQuery; +import com.gear.common.core.page.TableDataInfo; +import com.gear.oa.domain.bo.GearStockIoOrderBo; +import com.gear.oa.domain.bo.GearStockIoOrderWithDetailBo; +import com.gear.oa.domain.vo.GearStockIoOrderVo; +import com.gear.oa.domain.vo.GearStockIoOrderWithDetailVo; + +import java.util.Collection; +import java.util.List; + +public interface IGearStockIoOrderService { + + GearStockIoOrderVo queryById(Long orderId); + + GearStockIoOrderWithDetailVo queryWithDetail(Long orderId); + + TableDataInfo queryPageList(GearStockIoOrderBo bo, PageQuery pageQuery); + + List queryList(GearStockIoOrderBo bo); + + Long createWithDetail(GearStockIoOrderWithDetailBo bo); + + void updateWithDetail(GearStockIoOrderWithDetailBo bo); + + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + void submitOrder(Long orderId); + + void auditOrder(Long orderId); + + void executeOrder(Long orderId); + + void confirmArrival(Long orderId); + + void finishOrder(Long orderId); + + void cancelOrder(Long orderId, String reason); + + Long reverseOrder(Long orderId, String reason); +} + diff --git a/gear-oa/src/main/java/com/gear/oa/service/impl/GearStockIoOrderServiceImpl.java b/gear-oa/src/main/java/com/gear/oa/service/impl/GearStockIoOrderServiceImpl.java new file mode 100644 index 0000000..99197b3 --- /dev/null +++ b/gear-oa/src/main/java/com/gear/oa/service/impl/GearStockIoOrderServiceImpl.java @@ -0,0 +1,706 @@ +package com.gear.oa.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.IdUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.gear.common.core.domain.PageQuery; +import com.gear.common.core.page.TableDataInfo; +import com.gear.common.exception.ServiceException; +import com.gear.common.helper.LoginHelper; +import com.gear.common.utils.StringUtils; +import com.gear.oa.domain.GearStockIoOrder; +import com.gear.oa.domain.GearStockIoOrderDetail; +import com.gear.oa.domain.bo.GearStockIoOrderBo; +import com.gear.oa.domain.bo.GearStockIoOrderDetailBo; +import com.gear.oa.domain.bo.GearStockIoOrderWithDetailBo; +import com.gear.oa.domain.vo.GearStockIoOrderDetailVo; +import com.gear.oa.domain.vo.GearStockIoOrderVo; +import com.gear.oa.domain.vo.GearStockIoOrderWithDetailVo; +import com.gear.oa.mapper.*; +import com.gear.oa.service.IGearStockIoOrderService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.util.*; + +@RequiredArgsConstructor +@Service +public class GearStockIoOrderServiceImpl implements IGearStockIoOrderService { + + private final GearStockIoOrderMapper baseMapper; + private final GearStockIoOrderDetailMapper detailMapper; + private final MatMaterialSimpleMapper matMaterialMapper; + + @Override + public GearStockIoOrderVo queryById(Long orderId) { + return baseMapper.selectVoById(orderId); + } + + @Override + public GearStockIoOrderWithDetailVo queryWithDetail(Long orderId) { + GearStockIoOrderVo order = baseMapper.selectVoById(orderId); + if (order == null) { + return null; + } + List details = detailMapper.selectVoList(Wrappers.lambdaQuery() + .eq(GearStockIoOrderDetail::getOrderId, orderId) + .orderByAsc(GearStockIoOrderDetail::getLineNo)); + + GearStockIoOrderWithDetailVo vo = new GearStockIoOrderWithDetailVo(); + vo.setOrder(order); + vo.setDetails(details); + return vo; + } + + @Override + public TableDataInfo queryPageList(GearStockIoOrderBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + fillMaterialNames(result.getRecords()); + return TableDataInfo.build(result); + } + + @Override + public List queryList(GearStockIoOrderBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + List list = baseMapper.selectVoList(lqw); + fillMaterialNames(list); + return list; + } + + private void fillMaterialNames(List orders) { + if (orders == null || orders.isEmpty()) { + return; + } + List orderIds = new ArrayList<>(); + for (GearStockIoOrderVo o : orders) { + if (o != null && o.getOrderId() != null) { + orderIds.add(o.getOrderId()); + } + } + if (orderIds.isEmpty()) { + return; + } + List details = detailMapper.selectList(Wrappers.lambdaQuery() + .in(GearStockIoOrderDetail::getOrderId, orderIds) + .eq(GearStockIoOrderDetail::getDelFlag, "0") + .orderByAsc(GearStockIoOrderDetail::getLineNo)); + if (details == null || details.isEmpty()) { + return; + } + Map> namesMap = new HashMap<>(); + for (GearStockIoOrderDetail d : details) { + if (d == null || d.getOrderId() == null) { + continue; + } + String name = d.getItemName(); + if (StringUtils.isBlank(name)) { + continue; + } + namesMap.computeIfAbsent(d.getOrderId(), k -> new LinkedHashSet<>()).add(name); + } + for (GearStockIoOrderVo o : orders) { + if (o == null || o.getOrderId() == null) { + continue; + } + LinkedHashSet set = namesMap.get(o.getOrderId()); + if (set == null || set.isEmpty()) { + continue; + } + o.setMaterialNames(String.join("、", set)); + } + } + + private LambdaQueryWrapper buildQueryWrapper(GearStockIoOrderBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(bo.getOrderId() != null, GearStockIoOrder::getOrderId, bo.getOrderId()); + lqw.like(StringUtils.isNotBlank(bo.getOrderCode()), GearStockIoOrder::getOrderCode, bo.getOrderCode()); + lqw.eq(StringUtils.isNotBlank(bo.getIoType()), GearStockIoOrder::getIoType, bo.getIoType()); + lqw.eq(StringUtils.isNotBlank(bo.getBizType()), GearStockIoOrder::getBizType, bo.getBizType()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), GearStockIoOrder::getStatus, bo.getStatus()); + lqw.eq(StringUtils.isNotBlank(bo.getExecFlag()), GearStockIoOrder::getExecFlag, bo.getExecFlag()); + lqw.eq(StringUtils.isNotBlank(bo.getReversalFlag()), GearStockIoOrder::getReversalFlag, bo.getReversalFlag()); + lqw.like(StringUtils.isNotBlank(bo.getSourceNo()), GearStockIoOrder::getSourceNo, bo.getSourceNo()); + lqw.like(StringUtils.isNotBlank(bo.getResponsibleName()), GearStockIoOrder::getResponsibleName, bo.getResponsibleName()); + lqw.eq(StringUtils.isNotBlank(bo.getDelayStatus()), GearStockIoOrder::getDelayStatus, bo.getDelayStatus()); + lqw.orderByDesc(GearStockIoOrder::getCreateTime); + return lqw; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createWithDetail(GearStockIoOrderWithDetailBo bo) { + if (bo.getDetails() == null || bo.getDetails().isEmpty()) { + throw new ServiceException("单据明细不能为空"); + } + + GearStockIoOrder order = BeanUtil.toBean(bo, GearStockIoOrder.class); + if (StringUtils.isBlank(order.getOrderCode())) { + order.setOrderCode("SIOO_" + IdUtil.getSnowflakeNextIdStr()); + } + order.setStatus("0"); + order.setExecFlag("0"); + order.setReversalFlag("0"); + order.setDelayMinutes(0); + order.setDelayStatus("0"); + order.setDelFlag("0"); + + BigDecimal totalQty = sumQty(bo.getDetails()); + order.setTotalQty(totalQty); + + boolean ok = baseMapper.insert(order) > 0; + if (!ok) { + throw new ServiceException("创建单据失败"); + } + + insertDetails(order.getOrderId(), bo.getDetails()); + + if ("O".equalsIgnoreCase(order.getIoType())) { + List details = detailMapper.selectList(Wrappers.lambdaQuery() + .eq(GearStockIoOrderDetail::getOrderId, order.getOrderId()) + .orderByAsc(GearStockIoOrderDetail::getLineNo)); + applyMaterialStockChange(order.getIoType(), details); + GearStockIoOrder update = new GearStockIoOrder(); + update.setOrderId(order.getOrderId()); + update.setExecFlag("1"); + update.setExecuteBy(LoginHelper.getNickName()); + update.setExecuteTime(new Date()); + update.setStatus("1"); + update.setActualFinishTime(new Date()); + baseMapper.updateById(update); + } + return order.getOrderId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateWithDetail(GearStockIoOrderWithDetailBo bo) { + if (bo.getOrderId() == null) { + throw new ServiceException("单据ID不能为空"); + } + + GearStockIoOrder dbOrder = baseMapper.selectById(bo.getOrderId()); + if (dbOrder == null) { + throw new ServiceException("单据不存在"); + } + ensureEditable(dbOrder); + + if (bo.getDetails() == null || bo.getDetails().isEmpty()) { + throw new ServiceException("单据明细不能为空"); + } + + GearStockIoOrder update = BeanUtil.toBean(bo, GearStockIoOrder.class); + update.setStatus(null); + update.setExecFlag(null); + update.setReversalFlag(null); + update.setReversalOrderId(null); + update.setReversalReason(null); + update.setReversalTime(null); + update.setCancelReason(null); + update.setCancelTime(null); + update.setAuditBy(null); + update.setAuditTime(null); + update.setExecuteBy(null); + update.setExecuteTime(null); + update.setSourceIoId(null); + update.setDelayMinutes(null); + update.setDelayStatus(null); + update.setDelFlag(null); + + BigDecimal totalQty = sumQty(bo.getDetails()); + update.setTotalQty(totalQty); + + if (baseMapper.updateById(update) <= 0) { + throw new ServiceException("更新单据失败"); + } + + List existing = detailMapper.selectList(Wrappers.lambdaQuery() + .eq(GearStockIoOrderDetail::getOrderId, bo.getOrderId()) + .orderByAsc(GearStockIoOrderDetail::getLineNo)); + + Set incomingIds = new HashSet<>(); + int nextLineNo = 1; + for (GearStockIoOrderDetailBo d : bo.getDetails()) { + if (d == null) { + continue; + } + if (d.getLineNo() == null) { + d.setLineNo(nextLineNo++); + } else { + nextLineNo = Math.max(nextLineNo, d.getLineNo() + 1); + } + GearStockIoOrderDetail entity = BeanUtil.toBean(d, GearStockIoOrderDetail.class); + entity.setOrderId(bo.getOrderId()); + if (StringUtils.isBlank(entity.getItemType())) { + entity.setItemType("material"); + } + if (!"material".equals(entity.getItemType())) { + throw new ServiceException("仅支持原料(主材/辅材)出入库"); + } + fillMaterialSnapshotIfNeeded(entity); + entity.setUnit(resolveUnit(entity.getUnit(), entity.getItemType(), entity.getItemId())); + fillAmount(entity); + + if (entity.getDetailId() == null) { + detailMapper.insert(entity); + } else { + incomingIds.add(entity.getDetailId()); + detailMapper.updateById(entity); + } + } + + List toDelete = new ArrayList<>(); + for (GearStockIoOrderDetail e : existing) { + if (e.getDetailId() != null && !incomingIds.contains(e.getDetailId())) { + toDelete.add(e.getDetailId()); + } + } + if (!toDelete.isEmpty()) { + detailMapper.deleteBatchIds(toDelete); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (ids == null || ids.isEmpty()) { + return true; + } + for (Long id : ids) { + GearStockIoOrder order = baseMapper.selectById(id); + if (order == null) { + continue; + } + if ("1".equals(order.getStatus()) || "1".equals(order.getExecFlag())) { + throw new ServiceException("已执行/已完成单据不允许删除"); + } + } + for (Long orderId : ids) { + detailMapper.delete(Wrappers.lambdaQuery().eq(GearStockIoOrderDetail::getOrderId, orderId)); + } + return baseMapper.deleteBatchIds(ids) > 0; + } + + @Override + public void submitOrder(Long orderId) { + GearStockIoOrder order = requireOrder(orderId); + ensureNotCanceled(order); + Long cnt = detailMapper.selectCount(Wrappers.lambdaQuery().eq(GearStockIoOrderDetail::getOrderId, orderId)); + if (cnt == null || cnt <= 0) { + throw new ServiceException("单据明细不能为空"); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void auditOrder(Long orderId) { + GearStockIoOrder order = requireOrder(orderId); + ensureNotCanceled(order); + if (order.getAuditTime() != null) { + return; + } + GearStockIoOrder update = new GearStockIoOrder(); + update.setOrderId(orderId); + update.setAuditBy(LoginHelper.getNickName()); + update.setAuditTime(new Date()); + baseMapper.updateById(update); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void executeOrder(Long orderId) { + GearStockIoOrder order = requireOrder(orderId); + ensureNotCanceled(order); + if ("1".equals(order.getExecFlag())) { + return; + } + List details = detailMapper.selectList(Wrappers.lambdaQuery() + .eq(GearStockIoOrderDetail::getOrderId, orderId) + .orderByAsc(GearStockIoOrderDetail::getLineNo)); + if (details == null || details.isEmpty()) { + throw new ServiceException("单据明细不能为空"); + } + applyMaterialStockChange(order.getIoType(), details); + + GearStockIoOrder update = new GearStockIoOrder(); + update.setOrderId(orderId); + update.setExecFlag("1"); + update.setExecuteBy(LoginHelper.getNickName()); + update.setExecuteTime(new Date()); + update.setStatus("1"); + update.setActualFinishTime(new Date()); + baseMapper.updateById(update); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void confirmArrival(Long orderId) { + GearStockIoOrder order = requireOrder(orderId); + ensureNotCanceled(order); + if (!"I".equalsIgnoreCase(order.getIoType())) { + throw new ServiceException("仅入库单支持到货确认"); + } + if ("1".equals(order.getExecFlag())) { + return; + } + List details = detailMapper.selectList(Wrappers.lambdaQuery() + .eq(GearStockIoOrderDetail::getOrderId, orderId) + .orderByAsc(GearStockIoOrderDetail::getLineNo)); + if (details == null || details.isEmpty()) { + throw new ServiceException("单据明细不能为空"); + } + applyMaterialStockChange("I", details); + GearStockIoOrder update = new GearStockIoOrder(); + update.setOrderId(orderId); + update.setActualArrivalTime(new Date()); + update.setExecFlag("1"); + update.setExecuteBy(LoginHelper.getNickName()); + update.setExecuteTime(new Date()); + baseMapper.updateById(update); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void finishOrder(Long orderId) { + GearStockIoOrder order = requireOrder(orderId); + ensureNotCanceled(order); + if ("1".equals(order.getStatus())) { + return; + } + Date finishTime = order.getActualFinishTime() != null ? order.getActualFinishTime() : new Date(); + + GearStockIoOrder update = new GearStockIoOrder(); + update.setOrderId(orderId); + update.setStatus("1"); + update.setActualFinishTime(finishTime); + fillDelayOnFinish(order, update, finishTime); + baseMapper.updateById(update); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void cancelOrder(Long orderId, String reason) { + GearStockIoOrder order = requireOrder(orderId); + ensureNotCanceled(order); + if ("1".equals(order.getExecFlag())) { + throw new ServiceException("已执行单据不允许作废"); + } + if ("1".equals(order.getStatus())) { + throw new ServiceException("已完成单据不允许作废"); + } + + GearStockIoOrder update = new GearStockIoOrder(); + update.setOrderId(orderId); + update.setCancelReason(StringUtils.isBlank(reason) ? "" : reason); + update.setCancelTime(new Date()); + update.setDelFlag("2"); + baseMapper.updateById(update); + + detailMapper.delete(Wrappers.lambdaQuery().eq(GearStockIoOrderDetail::getOrderId, orderId)); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Long reverseOrder(Long orderId, String reason) { + GearStockIoOrder original = requireOrder(orderId); + ensureNotCanceled(original); + if ("1".equals(original.getReversalFlag())) { + throw new ServiceException("冲销单不允许再冲销"); + } + if (!"1".equals(original.getExecFlag())) { + throw new ServiceException("原单未执行,无法冲销"); + } + + Long exists = baseMapper.selectCount(Wrappers.lambdaQuery() + .eq(GearStockIoOrder::getReversalFlag, "1") + .eq(GearStockIoOrder::getReversalOrderId, orderId)); + if (exists != null && exists > 0) { + throw new ServiceException("该单据已创建冲销单"); + } + + List originalDetails = detailMapper.selectList(Wrappers.lambdaQuery() + .eq(GearStockIoOrderDetail::getOrderId, orderId) + .orderByAsc(GearStockIoOrderDetail::getLineNo)); + if (originalDetails == null || originalDetails.isEmpty()) { + throw new ServiceException("原单明细为空,无法冲销"); + } + + GearStockIoOrder reversal = new GearStockIoOrder(); + reversal.setOrderCode("SIOO_R_" + IdUtil.getSnowflakeNextIdStr()); + reversal.setIoType(reverseIoType(original.getIoType())); + reversal.setBizType(original.getBizType()); + reversal.setSourceType("reversal"); + reversal.setSourceNo(original.getOrderCode()); + reversal.setSourceOrderId(original.getOrderId()); + reversal.setResponsibleId(original.getResponsibleId()); + reversal.setResponsibleName(original.getResponsibleName()); + reversal.setWarehouseId(original.getWarehouseId()); + reversal.setFromWarehouseId(original.getFromWarehouseId()); + reversal.setToWarehouseId(original.getToWarehouseId()); + reversal.setStatus("0"); + reversal.setExecFlag("0"); + reversal.setReversalFlag("1"); + reversal.setReversalOrderId(original.getOrderId()); + reversal.setReversalReason(StringUtils.isBlank(reason) ? "" : reason); + reversal.setReversalTime(new Date()); + reversal.setDelayMinutes(0); + reversal.setDelayStatus("0"); + reversal.setDelFlag("0"); + reversal.setTotalQty(original.getTotalQty()); + reversal.setRemark(original.getRemark()); + baseMapper.insert(reversal); + + int lineNo = 1; + for (GearStockIoOrderDetail od : originalDetails) { + GearStockIoOrderDetail rd = new GearStockIoOrderDetail(); + rd.setOrderId(reversal.getOrderId()); + rd.setLineNo(od.getLineNo() == null ? lineNo++ : od.getLineNo()); + rd.setItemType(od.getItemType()); + rd.setItemId(od.getItemId()); + rd.setItemName(od.getItemName()); + rd.setSpecName(od.getSpecName()); + rd.setWarehouseId(od.getWarehouseId()); + rd.setFromWarehouseId(od.getFromWarehouseId()); + rd.setQuantity(od.getQuantity()); + rd.setUnit(od.getUnit()); + rd.setBatchNo(od.getBatchNo()); + rd.setUnitPrice(od.getUnitPrice()); + rd.setAmount(od.getAmount()); + rd.setSourceDetailNo(od.getSourceDetailNo()); + rd.setReversalDetailId(od.getDetailId()); + rd.setRemark(od.getRemark()); + rd.setDelFlag("0"); + detailMapper.insert(rd); + } + + List reversalDetails = detailMapper.selectList(Wrappers.lambdaQuery() + .eq(GearStockIoOrderDetail::getOrderId, reversal.getOrderId()) + .orderByAsc(GearStockIoOrderDetail::getLineNo)); + applyMaterialStockChange(reversal.getIoType(), reversalDetails); + + GearStockIoOrder update = new GearStockIoOrder(); + update.setOrderId(reversal.getOrderId()); + update.setAuditBy(LoginHelper.getNickName()); + update.setAuditTime(new Date()); + update.setExecFlag("1"); + update.setExecuteBy(LoginHelper.getNickName()); + update.setExecuteTime(new Date()); + update.setStatus("1"); + update.setActualFinishTime(new Date()); + baseMapper.updateById(update); + return reversal.getOrderId(); + } + + private GearStockIoOrder requireOrder(Long orderId) { + if (orderId == null) { + throw new ServiceException("单据ID不能为空"); + } + GearStockIoOrder order = baseMapper.selectById(orderId); + if (order == null) { + throw new ServiceException("单据不存在"); + } + return order; + } + + private void ensureNotCanceled(GearStockIoOrder order) { + if (order.getCancelTime() != null || "2".equals(order.getDelFlag())) { + throw new ServiceException("单据已作废"); + } + } + + private void ensureEditable(GearStockIoOrder order) { + ensureNotCanceled(order); + if ("1".equals(order.getStatus())) { + throw new ServiceException("已完成单据不允许修改"); + } + if ("1".equals(order.getExecFlag())) { + throw new ServiceException("已执行单据不允许修改"); + } + if (order.getAuditTime() != null) { + throw new ServiceException("已审核单据不允许修改"); + } + } + + private void insertDetails(Long orderId, List details) { + int lineNo = 1; + for (GearStockIoOrderDetailBo d : details) { + if (d == null) { + continue; + } + GearStockIoOrderDetail entity = BeanUtil.toBean(d, GearStockIoOrderDetail.class); + entity.setOrderId(orderId); + if (entity.getLineNo() == null) { + entity.setLineNo(lineNo++); + } else { + lineNo = Math.max(lineNo, entity.getLineNo() + 1); + } + if (StringUtils.isBlank(entity.getItemType())) { + entity.setItemType("material"); + } + if (!"material".equals(entity.getItemType())) { + throw new ServiceException("仅支持原料(主材/辅材)出入库"); + } + entity.setDelFlag("0"); + fillMaterialSnapshotIfNeeded(entity); + entity.setUnit(resolveUnit(entity.getUnit(), entity.getItemType(), entity.getItemId())); + fillAmount(entity); + detailMapper.insert(entity); + } + } + + private BigDecimal sumQty(List details) { + BigDecimal total = BigDecimal.ZERO; + if (details == null) { + return total; + } + for (GearStockIoOrderDetailBo d : details) { + if (d == null || d.getQuantity() == null) { + continue; + } + total = total.add(d.getQuantity()); + } + return total; + } + + private void fillAmount(GearStockIoOrderDetail detail) { + if (detail.getQuantity() == null) { + detail.setQuantity(BigDecimal.ZERO); + } + if (detail.getUnitPrice() == null) { + detail.setUnitPrice(BigDecimal.ZERO); + } + if (detail.getAmount() == null) { + detail.setAmount(detail.getUnitPrice().multiply(detail.getQuantity())); + } + } + + private void fillDelayOnFinish(GearStockIoOrder dbOrder, GearStockIoOrder update, Date finishTime) { + if ("2".equals(dbOrder.getDelayStatus())) { + return; + } + Date planFinish = dbOrder.getPlanFinishTime(); + if (planFinish == null || finishTime == null) { + update.setDelayMinutes(0); + update.setDelayStatus("0"); + return; + } + long diffMs = finishTime.getTime() - planFinish.getTime(); + int minutes = (int) Math.max(0, diffMs / (60_000L)); + update.setDelayMinutes(minutes); + update.setDelayStatus(minutes > 0 ? "1" : "0"); + } + + private void applyMaterialStockChange(String ioType, List details) { + if (!"I".equalsIgnoreCase(ioType) && !"O".equalsIgnoreCase(ioType)) { + throw new ServiceException("仅支持入库/出库类型"); + } + if (details == null || details.isEmpty()) { + throw new ServiceException("单据明细不能为空"); + } + for (GearStockIoOrderDetail d : details) { + if (d == null) { + continue; + } + if (!"material".equals(d.getItemType())) { + throw new ServiceException("仅支持原料(主材/辅材)出入库"); + } + fillMaterialSnapshotIfNeeded(d); + BigDecimal qty = d.getQuantity() == null ? BigDecimal.ZERO : d.getQuantity(); + if (qty.compareTo(BigDecimal.ZERO) <= 0) { + continue; + } + BigDecimal delta = "I".equalsIgnoreCase(ioType) ? qty : qty.negate(); + adjustMaterialStock(d.getItemId(), delta); + } + } + + private String resolveUnit(String preferred, String itemType, Long itemId) { + if (StringUtils.isNotBlank(preferred)) { + return preferred; + } + if ("material".equals(itemType)) { + Map snapshot = matMaterialMapper.selectSnapshot(itemId); + if (snapshot != null) { + Object unit = snapshot.get("unit"); + if (unit != null && StringUtils.isNotBlank(String.valueOf(unit))) { + return String.valueOf(unit); + } + } + } + return "个"; + } + + private void fillMaterialSnapshotIfNeeded(GearStockIoOrderDetail d) { + if (d.getItemId() == null) { + throw new ServiceException("原料ID不能为空"); + } + Map snapshot = matMaterialMapper.selectSnapshot(d.getItemId()); + if (snapshot == null) { + throw new ServiceException("原料不存在:" + d.getItemId()); + } + if (StringUtils.isBlank(d.getItemName())) { + Object name = snapshot.get("materialName"); + if (name != null) { + d.setItemName(String.valueOf(name)); + } + } + if (StringUtils.isBlank(d.getUnit())) { + Object unit = snapshot.get("unit"); + if (unit != null && StringUtils.isNotBlank(String.valueOf(unit))) { + d.setUnit(String.valueOf(unit)); + } + } + } + + private void adjustMaterialStock(Long materialId, BigDecimal delta) { + if (delta == null || delta.compareTo(BigDecimal.ZERO) == 0) { + return; + } + Map snapshot = matMaterialMapper.selectSnapshot(materialId); + if (snapshot == null) { + throw new ServiceException("原料不存在:" + materialId); + } + BigDecimal currentStock = BigDecimal.ZERO; + Object cur = snapshot.get("currentStock"); + if (cur instanceof BigDecimal) { + currentStock = (BigDecimal) cur; + } else if (cur != null) { + currentStock = new BigDecimal(String.valueOf(cur)); + } + BigDecimal after = currentStock.add(delta); + if (after.compareTo(BigDecimal.ZERO) < 0) { + throw new ServiceException("原料库存不足,无法出库"); + } + matMaterialMapper.updateStockDelta(materialId, delta); + } + + private String reverseIoType(String ioType) { + if ("I".equalsIgnoreCase(ioType)) { + return "O"; + } + if ("O".equalsIgnoreCase(ioType)) { + return "I"; + } + if ("T".equalsIgnoreCase(ioType)) { + return "T"; + } + return ioType; + } + + @SafeVarargs + private static T firstNonNull(T... values) { + if (values == null) { + return null; + } + for (T v : values) { + if (v != null) { + return v; + } + } + return null; + } +} diff --git a/gear-ui3/src/api/wms/stockIoOrder.js b/gear-ui3/src/api/wms/stockIoOrder.js new file mode 100644 index 0000000..d07c290 --- /dev/null +++ b/gear-ui3/src/api/wms/stockIoOrder.js @@ -0,0 +1,98 @@ +import request from '@/utils/request' + +export function listStockIoOrder(query) { + return request({ + url: '/gear/stockIoOrder/list', + method: 'get', + params: query + }) +} + +export function getStockIoOrder(orderId) { + return request({ + url: '/gear/stockIoOrder/' + orderId, + method: 'get' + }) +} + +export function getStockIoOrderWithDetail(orderId) { + return request({ + url: '/gear/stockIoOrder/withDetail/' + orderId, + method: 'get' + }) +} + +export function addStockIoOrderWithDetail(data) { + return request({ + url: '/gear/stockIoOrder/withDetail', + method: 'post', + data: data + }) +} + +export function updateStockIoOrderWithDetail(data) { + return request({ + url: '/gear/stockIoOrder/withDetail', + method: 'put', + data: data + }) +} + +export function delStockIoOrder(orderId) { + return request({ + url: '/gear/stockIoOrder/' + orderId, + method: 'delete' + }) +} + +export function submitStockIoOrder(orderId) { + return request({ + url: '/gear/stockIoOrder/submit/' + orderId, + method: 'post' + }) +} + +export function auditStockIoOrder(orderId) { + return request({ + url: '/gear/stockIoOrder/audit/' + orderId, + method: 'post' + }) +} + +export function executeStockIoOrder(orderId) { + return request({ + url: '/gear/stockIoOrder/execute/' + orderId, + method: 'post' + }) +} + +export function arrivalStockIoOrder(orderId) { + return request({ + url: '/gear/stockIoOrder/arrival/' + orderId, + method: 'post' + }) +} + +export function finishStockIoOrder(orderId) { + return request({ + url: '/gear/stockIoOrder/finish/' + orderId, + method: 'post' + }) +} + +export function cancelStockIoOrder(orderId, reason) { + return request({ + url: '/gear/stockIoOrder/cancel/' + orderId, + method: 'post', + data: { reason: reason || '' } + }) +} + +export function reverseStockIoOrder(orderId, reason) { + return request({ + url: '/gear/stockIoOrder/reverse/' + orderId, + method: 'post', + data: { reason: reason || '' } + }) +} + diff --git a/gear-ui3/src/components/RawSelector/index.vue b/gear-ui3/src/components/RawSelector/index.vue index b4a914e..c41c1f4 100644 --- a/gear-ui3/src/components/RawSelector/index.vue +++ b/gear-ui3/src/components/RawSelector/index.vue @@ -11,7 +11,7 @@ - + @@ -23,14 +23,34 @@ + + + + + + + + + 搜索 重置 + 新增原料 - + + \ No newline at end of file + +function openAdd() { + addForm.value = { + materialName: searchForm.value.materialName || '', + materialType: searchForm.value.materialType ? Number(searchForm.value.materialType) : undefined, + spec: '', + model: '', + factory: '', + unit: '', + remark: '' + } + addOpen.value = true +} + +function submitAdd() { + if (!addFormRef.value) { + return + } + addFormRef.value.validate(async (valid) => { + if (!valid) return + addLoading.value = true + try { + const payload = Object.assign({}, addForm.value) + const res = await addMaterial(payload) + const newId = res && res.data + if (!newId) { + ElMessage.success('新增成功') + addOpen.value = false + await fetchMaterialList() + return + } + materialId.value = newId + const detailRes = await getMaterial(newId) + const row = detailRes && detailRes.data ? detailRes.data : null + if (row) { + list.value = [row].concat(list.value.filter(i => String(i.materialId) !== String(newId))) + emit('change', row) + } + ElMessage.success('新增成功') + addOpen.value = false + open.value = false + } catch (e) { + ElMessage.error('新增失败,请重试') + } finally { + addLoading.value = false + } + }) +} + +function openDialog() { + open.value = true +} + +defineExpose({ openDialog }) + diff --git a/gear-ui3/src/views/mat/auxiliary/index.vue b/gear-ui3/src/views/mat/auxiliary/index.vue index e0e94cd..76b2d4d 100644 --- a/gear-ui3/src/views/mat/auxiliary/index.vue +++ b/gear-ui3/src/views/mat/auxiliary/index.vue @@ -68,8 +68,6 @@ @@ -461,4 +459,4 @@ function submitFormOut() { } getList(); - \ No newline at end of file + diff --git a/gear-ui3/src/views/mat/raw/index.vue b/gear-ui3/src/views/mat/raw/index.vue index 28dba70..a3ce4c2 100644 --- a/gear-ui3/src/views/mat/raw/index.vue +++ b/gear-ui3/src/views/mat/raw/index.vue @@ -72,8 +72,6 @@ diff --git a/gear-ui3/src/views/wms/stockIoOrder/in.vue b/gear-ui3/src/views/wms/stockIoOrder/in.vue new file mode 100644 index 0000000..7d6fb5d --- /dev/null +++ b/gear-ui3/src/views/wms/stockIoOrder/in.vue @@ -0,0 +1,514 @@ + + + diff --git a/gear-ui3/src/views/wms/stockIoOrder/index.vue b/gear-ui3/src/views/wms/stockIoOrder/index.vue new file mode 100644 index 0000000..75f7cab --- /dev/null +++ b/gear-ui3/src/views/wms/stockIoOrder/index.vue @@ -0,0 +1,12 @@ + + + diff --git a/gear-ui3/src/views/wms/stockIoOrder/out.vue b/gear-ui3/src/views/wms/stockIoOrder/out.vue new file mode 100644 index 0000000..b70f761 --- /dev/null +++ b/gear-ui3/src/views/wms/stockIoOrder/out.vue @@ -0,0 +1,486 @@ + + + diff --git a/gear-ui3/src/views/wms/stockIoOrder/panels/stockIoOrderPage.vue b/gear-ui3/src/views/wms/stockIoOrder/panels/stockIoOrderPage.vue new file mode 100644 index 0000000..031c458 --- /dev/null +++ b/gear-ui3/src/views/wms/stockIoOrder/panels/stockIoOrderPage.vue @@ -0,0 +1,808 @@ + + +