出入库
This commit is contained in:
@@ -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<GearStockIoOrderVo> list(GearStockIoOrderBo bo, PageQuery pageQuery) {
|
||||
return stockIoOrderService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
@GetMapping("/{orderId}")
|
||||
public R<GearStockIoOrderVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long orderId) {
|
||||
return R.ok(stockIoOrderService.queryById(orderId));
|
||||
}
|
||||
|
||||
@GetMapping("/withDetail/{orderId}")
|
||||
public R<GearStockIoOrderWithDetailVo> getWithDetail(@NotNull(message = "主键不能为空") @PathVariable Long orderId) {
|
||||
return R.ok(stockIoOrderService.queryWithDetail(orderId));
|
||||
}
|
||||
|
||||
@Log(title = "出入库单据", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit
|
||||
@PostMapping("/withDetail")
|
||||
public R<Long> addWithDetail(@Validated(AddGroup.class) @RequestBody GearStockIoOrderWithDetailBo bo) {
|
||||
return R.ok(stockIoOrderService.createWithDetail(bo));
|
||||
}
|
||||
|
||||
@Log(title = "出入库单据", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit
|
||||
@PutMapping("/withDetail")
|
||||
public R<Void> editWithDetail(@Validated(EditGroup.class) @RequestBody GearStockIoOrderWithDetailBo bo) {
|
||||
stockIoOrderService.updateWithDetail(bo);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@Log(title = "出入库单据", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{orderIds}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] orderIds) {
|
||||
return toAjax(stockIoOrderService.deleteWithValidByIds(Arrays.asList(orderIds), true));
|
||||
}
|
||||
|
||||
@Log(title = "出入库单据", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/submit/{orderId}")
|
||||
public R<Void> submit(@NotNull(message = "主键不能为空") @PathVariable Long orderId) {
|
||||
stockIoOrderService.submitOrder(orderId);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@Log(title = "出入库单据", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/audit/{orderId}")
|
||||
public R<Void> audit(@NotNull(message = "主键不能为空") @PathVariable Long orderId) {
|
||||
stockIoOrderService.auditOrder(orderId);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@Log(title = "出入库单据", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/execute/{orderId}")
|
||||
public R<Void> execute(@NotNull(message = "主键不能为空") @PathVariable Long orderId) {
|
||||
stockIoOrderService.executeOrder(orderId);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@Log(title = "出入库单据", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/arrival/{orderId}")
|
||||
public R<Void> arrival(@NotNull(message = "主键不能为空") @PathVariable Long orderId) {
|
||||
stockIoOrderService.confirmArrival(orderId);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@Log(title = "出入库单据", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/finish/{orderId}")
|
||||
public R<Void> finish(@NotNull(message = "主键不能为空") @PathVariable Long orderId) {
|
||||
stockIoOrderService.finishOrder(orderId);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@Log(title = "出入库单据", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit
|
||||
@PostMapping("/cancel/{orderId}")
|
||||
public R<Void> cancel(@NotNull(message = "主键不能为空") @PathVariable Long orderId,
|
||||
@RequestBody(required = false) Map<String, Object> 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<Long> reverse(@NotNull(message = "主键不能为空") @PathVariable Long orderId,
|
||||
@RequestBody(required = false) Map<String, Object> payload) {
|
||||
String reason = payload == null ? "" : String.valueOf(payload.getOrDefault("reason", ""));
|
||||
return R.ok(stockIoOrderService.reverseOrder(orderId, reason));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<GearStockIoOrderDetailBo> details;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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<GearStockIoOrderDetailVo> details;
|
||||
}
|
||||
|
||||
@@ -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<GearStockIoOrderDetailMapper, GearStockIoOrderDetail, GearStockIoOrderDetailVo> {
|
||||
}
|
||||
|
||||
@@ -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<GearStockIoOrderMapper, GearStockIoOrder, GearStockIoOrderVo> {
|
||||
}
|
||||
|
||||
@@ -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<String, Object> 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);
|
||||
}
|
||||
|
||||
@@ -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<GearStockIoOrderVo> queryPageList(GearStockIoOrderBo bo, PageQuery pageQuery);
|
||||
|
||||
List<GearStockIoOrderVo> queryList(GearStockIoOrderBo bo);
|
||||
|
||||
Long createWithDetail(GearStockIoOrderWithDetailBo bo);
|
||||
|
||||
void updateWithDetail(GearStockIoOrderWithDetailBo bo);
|
||||
|
||||
Boolean deleteWithValidByIds(Collection<Long> 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);
|
||||
}
|
||||
|
||||
@@ -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<GearStockIoOrderDetailVo> details = detailMapper.selectVoList(Wrappers.<GearStockIoOrderDetail>lambdaQuery()
|
||||
.eq(GearStockIoOrderDetail::getOrderId, orderId)
|
||||
.orderByAsc(GearStockIoOrderDetail::getLineNo));
|
||||
|
||||
GearStockIoOrderWithDetailVo vo = new GearStockIoOrderWithDetailVo();
|
||||
vo.setOrder(order);
|
||||
vo.setDetails(details);
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<GearStockIoOrderVo> queryPageList(GearStockIoOrderBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<GearStockIoOrder> lqw = buildQueryWrapper(bo);
|
||||
Page<GearStockIoOrderVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
fillMaterialNames(result.getRecords());
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GearStockIoOrderVo> queryList(GearStockIoOrderBo bo) {
|
||||
LambdaQueryWrapper<GearStockIoOrder> lqw = buildQueryWrapper(bo);
|
||||
List<GearStockIoOrderVo> list = baseMapper.selectVoList(lqw);
|
||||
fillMaterialNames(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
private void fillMaterialNames(List<GearStockIoOrderVo> orders) {
|
||||
if (orders == null || orders.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<Long> orderIds = new ArrayList<>();
|
||||
for (GearStockIoOrderVo o : orders) {
|
||||
if (o != null && o.getOrderId() != null) {
|
||||
orderIds.add(o.getOrderId());
|
||||
}
|
||||
}
|
||||
if (orderIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<GearStockIoOrderDetail> details = detailMapper.selectList(Wrappers.<GearStockIoOrderDetail>lambdaQuery()
|
||||
.in(GearStockIoOrderDetail::getOrderId, orderIds)
|
||||
.eq(GearStockIoOrderDetail::getDelFlag, "0")
|
||||
.orderByAsc(GearStockIoOrderDetail::getLineNo));
|
||||
if (details == null || details.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Map<Long, LinkedHashSet<String>> 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<String> set = namesMap.get(o.getOrderId());
|
||||
if (set == null || set.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
o.setMaterialNames(String.join("、", set));
|
||||
}
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<GearStockIoOrder> buildQueryWrapper(GearStockIoOrderBo bo) {
|
||||
LambdaQueryWrapper<GearStockIoOrder> 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<GearStockIoOrderDetail> details = detailMapper.selectList(Wrappers.<GearStockIoOrderDetail>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<GearStockIoOrderDetail> existing = detailMapper.selectList(Wrappers.<GearStockIoOrderDetail>lambdaQuery()
|
||||
.eq(GearStockIoOrderDetail::getOrderId, bo.getOrderId())
|
||||
.orderByAsc(GearStockIoOrderDetail::getLineNo));
|
||||
|
||||
Set<Long> 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<Long> 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<Long> 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.<GearStockIoOrderDetail>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.<GearStockIoOrderDetail>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<GearStockIoOrderDetail> details = detailMapper.selectList(Wrappers.<GearStockIoOrderDetail>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<GearStockIoOrderDetail> details = detailMapper.selectList(Wrappers.<GearStockIoOrderDetail>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.<GearStockIoOrderDetail>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.<GearStockIoOrder>lambdaQuery()
|
||||
.eq(GearStockIoOrder::getReversalFlag, "1")
|
||||
.eq(GearStockIoOrder::getReversalOrderId, orderId));
|
||||
if (exists != null && exists > 0) {
|
||||
throw new ServiceException("该单据已创建冲销单");
|
||||
}
|
||||
|
||||
List<GearStockIoOrderDetail> originalDetails = detailMapper.selectList(Wrappers.<GearStockIoOrderDetail>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<GearStockIoOrderDetail> reversalDetails = detailMapper.selectList(Wrappers.<GearStockIoOrderDetail>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<GearStockIoOrderDetailBo> 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<GearStockIoOrderDetailBo> 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<GearStockIoOrderDetail> 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<String, Object> 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<String, Object> 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<String, Object> 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> T firstNonNull(T... values) {
|
||||
if (values == null) {
|
||||
return null;
|
||||
}
|
||||
for (T v : values) {
|
||||
if (v != null) {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user