From f94ddb433dab29c90c61a6cfa0d8196388d98cae 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: Mon, 11 May 2026 17:59:12 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BA=A7=E5=93=81=E5=85=A5=E5=BA=93=EF=BC=8C?= =?UTF-8?q?=E5=8D=8A=E6=88=90=E5=93=81=E5=A7=94=E5=A4=96=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MatProductInDetailController.java | 71 ++++ .../MatProductOutsourceOrderController.java | 105 +++++ .../java/com/gear/mat/domain/MatProduct.java | 6 + .../gear/mat/domain/MatProductInDetail.java | 36 ++ .../mat/domain/MatProductOutsourceOrder.java | 51 +++ .../com/gear/mat/domain/bo/MatProductBo.java | 4 + .../mat/domain/bo/MatProductInDetailBo.java | 38 ++ .../domain/bo/MatProductOutsourceOrderBo.java | 45 +++ .../mat/domain/vo/MatProductInDetailVo.java | 52 +++ .../domain/vo/MatProductOutsourceOrderVo.java | 72 ++++ .../com/gear/mat/domain/vo/MatProductVo.java | 6 + .../domain/vo/MatProductWithMaterialsVo.java | 6 + .../mat/mapper/MatProductInDetailMapper.java | 14 + .../MatProductOutsourceOrderMapper.java | 14 + .../service/IMatProductInDetailService.java | 25 ++ .../IMatProductOutsourceOrderService.java | 24 ++ .../impl/MatProductInDetailServiceImpl.java | 163 ++++++++ .../MatProductOutsourceOrderServiceImpl.java | 215 ++++++++++ .../service/impl/MatProductServiceImpl.java | 32 +- .../mapper/MatProductInDetailMapper.xml | 42 ++ .../mapper/MatProductOutsourceOrderMapper.xml | 56 +++ .../GearStockIoOrderController.java | 188 ++++++++- gear-ui3/src/api/mat/productInDetail.js | 40 ++ gear-ui3/src/api/mat/productOutsourceOrder.js | 39 ++ gear-ui3/src/views/mat/product/detail.vue | 11 + gear-ui3/src/views/mat/product/index.vue | 42 ++ gear-ui3/src/views/mat/productIn/index.vue | 288 ++++++++++++++ .../src/views/mat/productOutsource/index.vue | 376 ++++++++++++++++++ gear-ui3/src/views/wms/stockIoOrder/in.vue | 45 +-- gear-ui3/src/views/wms/stockIoOrder/out.vue | 45 +-- .../stockIoOrder/panels/stockIoOrderPage.vue | 45 +-- 31 files changed, 2119 insertions(+), 77 deletions(-) create mode 100644 gear-mat/src/main/java/com/gear/mat/controller/MatProductInDetailController.java create mode 100644 gear-mat/src/main/java/com/gear/mat/controller/MatProductOutsourceOrderController.java create mode 100644 gear-mat/src/main/java/com/gear/mat/domain/MatProductInDetail.java create mode 100644 gear-mat/src/main/java/com/gear/mat/domain/MatProductOutsourceOrder.java create mode 100644 gear-mat/src/main/java/com/gear/mat/domain/bo/MatProductInDetailBo.java create mode 100644 gear-mat/src/main/java/com/gear/mat/domain/bo/MatProductOutsourceOrderBo.java create mode 100644 gear-mat/src/main/java/com/gear/mat/domain/vo/MatProductInDetailVo.java create mode 100644 gear-mat/src/main/java/com/gear/mat/domain/vo/MatProductOutsourceOrderVo.java create mode 100644 gear-mat/src/main/java/com/gear/mat/mapper/MatProductInDetailMapper.java create mode 100644 gear-mat/src/main/java/com/gear/mat/mapper/MatProductOutsourceOrderMapper.java create mode 100644 gear-mat/src/main/java/com/gear/mat/service/IMatProductInDetailService.java create mode 100644 gear-mat/src/main/java/com/gear/mat/service/IMatProductOutsourceOrderService.java create mode 100644 gear-mat/src/main/java/com/gear/mat/service/impl/MatProductInDetailServiceImpl.java create mode 100644 gear-mat/src/main/java/com/gear/mat/service/impl/MatProductOutsourceOrderServiceImpl.java create mode 100644 gear-mat/src/main/resources/mapper/MatProductInDetailMapper.xml create mode 100644 gear-mat/src/main/resources/mapper/MatProductOutsourceOrderMapper.xml create mode 100644 gear-ui3/src/api/mat/productInDetail.js create mode 100644 gear-ui3/src/api/mat/productOutsourceOrder.js create mode 100644 gear-ui3/src/views/mat/productIn/index.vue create mode 100644 gear-ui3/src/views/mat/productOutsource/index.vue diff --git a/gear-mat/src/main/java/com/gear/mat/controller/MatProductInDetailController.java b/gear-mat/src/main/java/com/gear/mat/controller/MatProductInDetailController.java new file mode 100644 index 0000000..9bf4b4f --- /dev/null +++ b/gear-mat/src/main/java/com/gear/mat/controller/MatProductInDetailController.java @@ -0,0 +1,71 @@ +package com.gear.mat.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.common.utils.poi.ExcelUtil; +import com.gear.mat.domain.bo.MatProductInDetailBo; +import com.gear.mat.domain.vo.MatProductInDetailVo; +import com.gear.mat.service.IMatProductInDetailService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Arrays; +import java.util.List; + +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/mat/productInDetail") +public class MatProductInDetailController extends BaseController { + + private final IMatProductInDetailService iMatProductInDetailService; + + @GetMapping("/list") + public TableDataInfo list(MatProductInDetailBo bo, PageQuery pageQuery) { + return iMatProductInDetailService.queryPageList(bo, pageQuery); + } + + @Log(title = "产品入库单", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(MatProductInDetailBo bo, HttpServletResponse response) { + List list = iMatProductInDetailService.queryList(bo); + ExcelUtil.exportExcel(list, "产品入库单", MatProductInDetailVo.class, response); + } + + @GetMapping("/{detailId}") + public R getInfo(@NotNull(message = "主键不能为空") @PathVariable Long detailId) { + return R.ok(iMatProductInDetailService.queryById(detailId)); + } + + @Log(title = "产品入库单", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody MatProductInDetailBo bo) { + return toAjax(iMatProductInDetailService.insertByBoWithInventory(bo)); + } + + @Log(title = "产品入库单", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody MatProductInDetailBo bo) { + return toAjax(iMatProductInDetailService.updateByBo(bo)); + } + + @Log(title = "产品入库单", businessType = BusinessType.DELETE) + @DeleteMapping("/{detailIds}") + public R remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] detailIds) { + return toAjax(iMatProductInDetailService.deleteWithValidByIdsWithInventory(Arrays.asList(detailIds), true)); + } +} + diff --git a/gear-mat/src/main/java/com/gear/mat/controller/MatProductOutsourceOrderController.java b/gear-mat/src/main/java/com/gear/mat/controller/MatProductOutsourceOrderController.java new file mode 100644 index 0000000..ed4d2a1 --- /dev/null +++ b/gear-mat/src/main/java/com/gear/mat/controller/MatProductOutsourceOrderController.java @@ -0,0 +1,105 @@ +package com.gear.mat.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.enums.BusinessType; +import com.gear.common.utils.poi.ExcelUtil; +import com.gear.mat.domain.bo.MatProductOutsourceOrderBo; +import com.gear.mat.domain.vo.MatProductOutsourceOrderVo; +import com.gear.mat.service.IMatProductOutsourceOrderService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.util.Date; +import java.util.Arrays; +import java.util.List; + +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/mat/productOutsourceOrder") +public class MatProductOutsourceOrderController extends BaseController { + + private final IMatProductOutsourceOrderService iMatProductOutsourceOrderService; + + @GetMapping("/list") + public TableDataInfo list(MatProductOutsourceOrderBo bo, PageQuery pageQuery) { + return iMatProductOutsourceOrderService.queryPageList(bo, pageQuery); + } + + @Log(title = "半成品委外单", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(MatProductOutsourceOrderBo bo, HttpServletResponse response) { + List list = iMatProductOutsourceOrderService.queryList(bo); + ExcelUtil.exportExcel(list, "半成品委外单", MatProductOutsourceOrderVo.class, response); + } + + @GetMapping("/{orderId}") + public R getInfo(@NotNull(message = "主键不能为空") @PathVariable Long orderId) { + return R.ok(iMatProductOutsourceOrderService.queryById(orderId)); + } + + @Log(title = "半成品委外单", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody MatProductOutsourceOrderBo bo) { + return toAjax(iMatProductOutsourceOrderService.insertByBoWithInventory(bo)); + } + + @Log(title = "半成品委外单", businessType = BusinessType.DELETE) + @DeleteMapping("/{orderIds}") + public R remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] orderIds) { + return toAjax(iMatProductOutsourceOrderService.deleteWithValidByIdsWithInventory(Arrays.asList(orderIds), true)); + } + + @Log(title = "半成品委外单", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PostMapping("/receive/{orderId}") + public R receive(@NotNull(message = "主键不能为空") @PathVariable Long orderId, + @RequestBody ReceiveReq req) { + BigDecimal qty = req == null ? null : req.getReceiveQty(); + Date time = req == null ? null : req.getReceiveTime(); + String by = req == null ? null : req.getReceiveBy(); + return toAjax(iMatProductOutsourceOrderService.receive(orderId, qty, time, by)); + } + + public static class ReceiveReq { + private BigDecimal receiveQty; + private Date receiveTime; + private String receiveBy; + + public BigDecimal getReceiveQty() { + return receiveQty; + } + + public void setReceiveQty(BigDecimal receiveQty) { + this.receiveQty = receiveQty; + } + + public Date getReceiveTime() { + return receiveTime; + } + + public void setReceiveTime(Date receiveTime) { + this.receiveTime = receiveTime; + } + + public String getReceiveBy() { + return receiveBy; + } + + public void setReceiveBy(String receiveBy) { + this.receiveBy = receiveBy; + } + } +} diff --git a/gear-mat/src/main/java/com/gear/mat/domain/MatProduct.java b/gear-mat/src/main/java/com/gear/mat/domain/MatProduct.java index e946972..bbf2495 100644 --- a/gear-mat/src/main/java/com/gear/mat/domain/MatProduct.java +++ b/gear-mat/src/main/java/com/gear/mat/domain/MatProduct.java @@ -44,6 +44,12 @@ public class MatProduct extends BaseEntity { * 产品单价 可手动维护 */ private BigDecimal unitPrice; + + @TableField("product_type") + private String productType; + + @TableField("current_stock") + private BigDecimal currentStock; /** * 删除标志(0=正常,1=已删除) */ diff --git a/gear-mat/src/main/java/com/gear/mat/domain/MatProductInDetail.java b/gear-mat/src/main/java/com/gear/mat/domain/MatProductInDetail.java new file mode 100644 index 0000000..1d68f26 --- /dev/null +++ b/gear-mat/src/main/java/com/gear/mat/domain/MatProductInDetail.java @@ -0,0 +1,36 @@ +package com.gear.mat.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("mat_product_in_detail") +public class MatProductInDetail extends BaseEntity { + + private static final long serialVersionUID = 1L; + + @TableId(value = "detail_id") + private Long detailId; + + private Long productId; + + private BigDecimal inNum; + + private Date inTime; + + private String operator; + + @TableLogic + private Integer delFlag; + + private String remark; +} + diff --git a/gear-mat/src/main/java/com/gear/mat/domain/MatProductOutsourceOrder.java b/gear-mat/src/main/java/com/gear/mat/domain/MatProductOutsourceOrder.java new file mode 100644 index 0000000..e457b5e --- /dev/null +++ b/gear-mat/src/main/java/com/gear/mat/domain/MatProductOutsourceOrder.java @@ -0,0 +1,51 @@ +package com.gear.mat.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("mat_product_outsource_order") +public class MatProductOutsourceOrder extends BaseEntity { + + private static final long serialVersionUID = 1L; + + @TableId(value = "order_id") + private Long orderId; + + private String orderNo; + + private Long productId; + + private String productTypeSnapshot; + + private Long customerId; + + private String customerName; + + private BigDecimal quantity; + + private Date outTime; + + private String operator; + + private BigDecimal receivedQty; + + private Integer receiveFlag; + + private Date receiveTime; + + private String receiveBy; + + @TableLogic + private Integer delFlag; + + private String remark; +} diff --git a/gear-mat/src/main/java/com/gear/mat/domain/bo/MatProductBo.java b/gear-mat/src/main/java/com/gear/mat/domain/bo/MatProductBo.java index 79befa3..132a444 100644 --- a/gear-mat/src/main/java/com/gear/mat/domain/bo/MatProductBo.java +++ b/gear-mat/src/main/java/com/gear/mat/domain/bo/MatProductBo.java @@ -47,6 +47,10 @@ public class MatProductBo extends BaseEntity { */ private BigDecimal unitPrice; + private String productType; + + private BigDecimal currentStock; + /** * 备注 */ diff --git a/gear-mat/src/main/java/com/gear/mat/domain/bo/MatProductInDetailBo.java b/gear-mat/src/main/java/com/gear/mat/domain/bo/MatProductInDetailBo.java new file mode 100644 index 0000000..d572c46 --- /dev/null +++ b/gear-mat/src/main/java/com/gear/mat/domain/bo/MatProductInDetailBo.java @@ -0,0 +1,38 @@ +package com.gear.mat.domain.bo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.gear.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springframework.format.annotation.DateTimeFormat; + +import java.math.BigDecimal; +import java.util.Date; + +@Data +@EqualsAndHashCode(callSuper = true) +public class MatProductInDetailBo extends BaseEntity { + + private Long detailId; + + private Long productId; + + private BigDecimal inNum; + + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date inTime; + + private String operator; + + private String remark; + + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date beginTime; + + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date endTime; +} + diff --git a/gear-mat/src/main/java/com/gear/mat/domain/bo/MatProductOutsourceOrderBo.java b/gear-mat/src/main/java/com/gear/mat/domain/bo/MatProductOutsourceOrderBo.java new file mode 100644 index 0000000..10ddfd2 --- /dev/null +++ b/gear-mat/src/main/java/com/gear/mat/domain/bo/MatProductOutsourceOrderBo.java @@ -0,0 +1,45 @@ +package com.gear.mat.domain.bo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.gear.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springframework.format.annotation.DateTimeFormat; + +import java.math.BigDecimal; +import java.util.Date; + +@Data +@EqualsAndHashCode(callSuper = true) +public class MatProductOutsourceOrderBo extends BaseEntity { + + private Long orderId; + + private String orderNo; + + private Long productId; + + private Long customerId; + + private String customerName; + + private BigDecimal quantity; + + private Integer receiveFlag; + + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date outTime; + + private String operator; + + private String remark; + + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date beginTime; + + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date endTime; +} diff --git a/gear-mat/src/main/java/com/gear/mat/domain/vo/MatProductInDetailVo.java b/gear-mat/src/main/java/com/gear/mat/domain/vo/MatProductInDetailVo.java new file mode 100644 index 0000000..804517b --- /dev/null +++ b/gear-mat/src/main/java/com/gear/mat/domain/vo/MatProductInDetailVo.java @@ -0,0 +1,52 @@ +package com.gear.mat.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.math.BigDecimal; +import java.util.Date; + +@Data +@ExcelIgnoreUnannotated +public class MatProductInDetailVo { + + private static final long serialVersionUID = 1L; + + @ExcelProperty(value = "入库明细ID") + private Long detailId; + + @ExcelProperty(value = "产品ID") + private Long productId; + + @ExcelProperty(value = "入库数量") + private BigDecimal inNum; + + @ExcelProperty(value = "入库时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date inTime; + + @ExcelProperty(value = "操作人") + private String operator; + + @ExcelProperty(value = "备注") + private String remark; + + @ExcelProperty(value = "产品名称") + private String productName; + + @ExcelProperty(value = "产品规格") + private String spec; + + @ExcelProperty(value = "产品型号") + private String model; + + @ExcelProperty(value = "产品类型") + private String productType; + + @ExcelProperty(value = "当前库存") + private BigDecimal currentStock; +} diff --git a/gear-mat/src/main/java/com/gear/mat/domain/vo/MatProductOutsourceOrderVo.java b/gear-mat/src/main/java/com/gear/mat/domain/vo/MatProductOutsourceOrderVo.java new file mode 100644 index 0000000..85a1869 --- /dev/null +++ b/gear-mat/src/main/java/com/gear/mat/domain/vo/MatProductOutsourceOrderVo.java @@ -0,0 +1,72 @@ +package com.gear.mat.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.math.BigDecimal; +import java.util.Date; + +@Data +@ExcelIgnoreUnannotated +public class MatProductOutsourceOrderVo { + + private static final long serialVersionUID = 1L; + + @ExcelProperty(value = "委外单ID") + private Long orderId; + + @ExcelProperty(value = "委外单号") + private String orderNo; + + @ExcelProperty(value = "产品ID") + private Long productId; + + @ExcelProperty(value = "产品名称") + private String productName; + + @ExcelProperty(value = "产品规格") + private String spec; + + @ExcelProperty(value = "产品型号") + private String model; + + @ExcelProperty(value = "产品类型") + private String productTypeSnapshot; + + @ExcelProperty(value = "委托公司ID") + private Long customerId; + + @ExcelProperty(value = "委托公司") + private String customerName; + + @ExcelProperty(value = "委派数量") + private BigDecimal quantity; + + @ExcelProperty(value = "已收回数量") + private BigDecimal receivedQty; + + @ExcelProperty(value = "收回标志") + private Integer receiveFlag; + + @ExcelProperty(value = "委外时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date outTime; + + @ExcelProperty(value = "收回时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date receiveTime; + + @ExcelProperty(value = "收回人") + private String receiveBy; + + @ExcelProperty(value = "操作人") + private String operator; + + @ExcelProperty(value = "备注") + private String remark; +} diff --git a/gear-mat/src/main/java/com/gear/mat/domain/vo/MatProductVo.java b/gear-mat/src/main/java/com/gear/mat/domain/vo/MatProductVo.java index 57c7be9..d8f8fd8 100644 --- a/gear-mat/src/main/java/com/gear/mat/domain/vo/MatProductVo.java +++ b/gear-mat/src/main/java/com/gear/mat/domain/vo/MatProductVo.java @@ -52,6 +52,12 @@ public class MatProductVo { @ExcelProperty(value = "产品单价 可手动维护") private BigDecimal unitPrice; + @ExcelProperty(value = "产品类型") + private String productType; + + @ExcelProperty(value = "库存") + private BigDecimal currentStock; + /** * 备注 */ diff --git a/gear-mat/src/main/java/com/gear/mat/domain/vo/MatProductWithMaterialsVo.java b/gear-mat/src/main/java/com/gear/mat/domain/vo/MatProductWithMaterialsVo.java index d9f948b..5d44c0e 100644 --- a/gear-mat/src/main/java/com/gear/mat/domain/vo/MatProductWithMaterialsVo.java +++ b/gear-mat/src/main/java/com/gear/mat/domain/vo/MatProductWithMaterialsVo.java @@ -51,6 +51,12 @@ public class MatProductWithMaterialsVo { @ExcelProperty(value = "产品单价 可手动维护") private BigDecimal unitPrice; + @ExcelProperty(value = "产品类型") + private String productType; + + @ExcelProperty(value = "库存") + private BigDecimal currentStock; + /** * 备注 */ diff --git a/gear-mat/src/main/java/com/gear/mat/mapper/MatProductInDetailMapper.java b/gear-mat/src/main/java/com/gear/mat/mapper/MatProductInDetailMapper.java new file mode 100644 index 0000000..f1c0d72 --- /dev/null +++ b/gear-mat/src/main/java/com/gear/mat/mapper/MatProductInDetailMapper.java @@ -0,0 +1,14 @@ +package com.gear.mat.mapper; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.gear.common.core.mapper.BaseMapperPlus; +import com.gear.mat.domain.MatProductInDetail; +import com.gear.mat.domain.vo.MatProductInDetailVo; +import org.apache.ibatis.annotations.Param; + +public interface MatProductInDetailMapper extends BaseMapperPlus { + + Page selectVoPagePlus(Page page, @Param("ew") QueryWrapper qw); +} + diff --git a/gear-mat/src/main/java/com/gear/mat/mapper/MatProductOutsourceOrderMapper.java b/gear-mat/src/main/java/com/gear/mat/mapper/MatProductOutsourceOrderMapper.java new file mode 100644 index 0000000..6f675d1 --- /dev/null +++ b/gear-mat/src/main/java/com/gear/mat/mapper/MatProductOutsourceOrderMapper.java @@ -0,0 +1,14 @@ +package com.gear.mat.mapper; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.gear.common.core.mapper.BaseMapperPlus; +import com.gear.mat.domain.MatProductOutsourceOrder; +import com.gear.mat.domain.vo.MatProductOutsourceOrderVo; +import org.apache.ibatis.annotations.Param; + +public interface MatProductOutsourceOrderMapper extends BaseMapperPlus { + + Page selectVoPagePlus(Page page, @Param("ew") QueryWrapper qw); +} + diff --git a/gear-mat/src/main/java/com/gear/mat/service/IMatProductInDetailService.java b/gear-mat/src/main/java/com/gear/mat/service/IMatProductInDetailService.java new file mode 100644 index 0000000..d181180 --- /dev/null +++ b/gear-mat/src/main/java/com/gear/mat/service/IMatProductInDetailService.java @@ -0,0 +1,25 @@ +package com.gear.mat.service; + +import com.gear.common.core.domain.PageQuery; +import com.gear.common.core.page.TableDataInfo; +import com.gear.mat.domain.bo.MatProductInDetailBo; +import com.gear.mat.domain.vo.MatProductInDetailVo; + +import java.util.Collection; +import java.util.List; + +public interface IMatProductInDetailService { + + MatProductInDetailVo queryById(Long detailId); + + TableDataInfo queryPageList(MatProductInDetailBo bo, PageQuery pageQuery); + + List queryList(MatProductInDetailBo bo); + + Boolean insertByBoWithInventory(MatProductInDetailBo bo); + + Boolean updateByBo(MatProductInDetailBo bo); + + Boolean deleteWithValidByIdsWithInventory(Collection ids, Boolean isValid); +} + diff --git a/gear-mat/src/main/java/com/gear/mat/service/IMatProductOutsourceOrderService.java b/gear-mat/src/main/java/com/gear/mat/service/IMatProductOutsourceOrderService.java new file mode 100644 index 0000000..656bb22 --- /dev/null +++ b/gear-mat/src/main/java/com/gear/mat/service/IMatProductOutsourceOrderService.java @@ -0,0 +1,24 @@ +package com.gear.mat.service; + +import com.gear.common.core.domain.PageQuery; +import com.gear.common.core.page.TableDataInfo; +import com.gear.mat.domain.bo.MatProductOutsourceOrderBo; +import com.gear.mat.domain.vo.MatProductOutsourceOrderVo; + +import java.util.Collection; +import java.util.List; + +public interface IMatProductOutsourceOrderService { + + MatProductOutsourceOrderVo queryById(Long orderId); + + TableDataInfo queryPageList(MatProductOutsourceOrderBo bo, PageQuery pageQuery); + + List queryList(MatProductOutsourceOrderBo bo); + + Boolean insertByBoWithInventory(MatProductOutsourceOrderBo bo); + + Boolean receive(Long orderId, java.math.BigDecimal receiveQty, java.util.Date receiveTime, String receiveBy); + + Boolean deleteWithValidByIdsWithInventory(Collection ids, Boolean isValid); +} diff --git a/gear-mat/src/main/java/com/gear/mat/service/impl/MatProductInDetailServiceImpl.java b/gear-mat/src/main/java/com/gear/mat/service/impl/MatProductInDetailServiceImpl.java new file mode 100644 index 0000000..cba13f9 --- /dev/null +++ b/gear-mat/src/main/java/com/gear/mat/service/impl/MatProductInDetailServiceImpl.java @@ -0,0 +1,163 @@ +package com.gear.mat.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +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.utils.StringUtils; +import com.gear.mat.domain.MatProduct; +import com.gear.mat.domain.MatProductInDetail; +import com.gear.mat.domain.bo.MatProductInDetailBo; +import com.gear.mat.domain.vo.MatProductInDetailVo; +import com.gear.mat.mapper.MatProductInDetailMapper; +import com.gear.mat.mapper.MatProductMapper; +import com.gear.mat.service.IMatProductInDetailService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.Date; +import java.util.List; + +@RequiredArgsConstructor +@Service +public class MatProductInDetailServiceImpl implements IMatProductInDetailService { + + private final MatProductInDetailMapper baseMapper; + private final MatProductMapper matProductMapper; + + @Override + public MatProductInDetailVo queryById(Long detailId) { + return baseMapper.selectVoById(detailId); + } + + @Override + public TableDataInfo queryPageList(MatProductInDetailBo bo, PageQuery pageQuery) { + QueryWrapper qw = buildQueryWrapperPlus(bo); + Page result = baseMapper.selectVoPagePlus(pageQuery.build(), qw); + return TableDataInfo.build(result); + } + + private QueryWrapper buildQueryWrapperPlus(MatProductInDetailBo bo) { + QueryWrapper qw = Wrappers.query(); + qw.eq(bo.getProductId() != null, "mpid.product_id", bo.getProductId()); + qw.eq(bo.getInNum() != null, "mpid.in_num", bo.getInNum()); + qw.ge(bo.getBeginTime() != null, "mpid.in_time", bo.getBeginTime()); + qw.le(bo.getEndTime() != null, "mpid.in_time", bo.getEndTime()); + qw.eq(StringUtils.isNotBlank(bo.getOperator()), "mpid.operator", bo.getOperator()); + qw.eq("mpid.del_flag", 0); + qw.orderByDesc("mpid.in_time"); + return qw; + } + + @Override + public List queryList(MatProductInDetailBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(MatProductInDetailBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(bo.getProductId() != null, MatProductInDetail::getProductId, bo.getProductId()); + lqw.eq(bo.getInNum() != null, MatProductInDetail::getInNum, bo.getInNum()); + lqw.eq(bo.getInTime() != null, MatProductInDetail::getInTime, bo.getInTime()); + lqw.eq(StringUtils.isNotBlank(bo.getOperator()), MatProductInDetail::getOperator, bo.getOperator()); + return lqw; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean insertByBoWithInventory(MatProductInDetailBo bo) { + if (bo.getProductId() == null) { + throw new IllegalArgumentException("产品不能为空"); + } + if (bo.getInNum() == null || bo.getInNum().compareTo(BigDecimal.ZERO) <= 0) { + throw new IllegalArgumentException("入库数量必须大于0"); + } + if (bo.getInTime() == null) { + bo.setInTime(new Date()); + } + if (StringUtils.isBlank(bo.getOperator())) { + bo.setOperator("-"); + } + + MatProductInDetail add = BeanUtil.toBean(bo, MatProductInDetail.class); + boolean ok = baseMapper.insert(add) > 0; + if (!ok) { + throw new IllegalStateException("入库记录保存失败"); + } + bo.setDetailId(add.getDetailId()); + + updateProductStock(bo.getProductId(), bo.getInNum()); + return true; + } + + @Override + public Boolean updateByBo(MatProductInDetailBo bo) { + MatProductInDetail update = BeanUtil.toBean(bo, MatProductInDetail.class); + return baseMapper.updateById(update) > 0; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIdsWithInventory(Collection ids, Boolean isValid) { + if (CollectionUtils.isEmpty(ids)) { + return false; + } + List records = baseMapper.selectVoBatchIds(ids); + if (records == null || records.isEmpty()) { + return false; + } + + boolean ok = baseMapper.deleteBatchIds(ids) > 0; + if (!ok) { + return false; + } + + for (MatProductInDetailVo r : records) { + if (r.getProductId() == null || r.getInNum() == null) { + continue; + } + revertProductStock(r.getProductId(), r.getInNum()); + } + return true; + } + + private void updateProductStock(Long productId, BigDecimal qty) { + MatProduct product = matProductMapper.selectById(productId); + if (product == null) { + throw new IllegalArgumentException("产品不存在,productId=" + productId); + } + BigDecimal current = product.getCurrentStock() == null ? BigDecimal.ZERO : product.getCurrentStock(); + BigDecimal next = current.add(qty); + product.setCurrentStock(next); + int affected = matProductMapper.updateById(product); + if (affected <= 0) { + throw new IllegalStateException("更新产品库存失败"); + } + } + + private void revertProductStock(Long productId, BigDecimal qty) { + MatProduct product = matProductMapper.selectById(productId); + if (product == null) { + throw new IllegalArgumentException("产品不存在,productId=" + productId); + } + BigDecimal current = product.getCurrentStock() == null ? BigDecimal.ZERO : product.getCurrentStock(); + BigDecimal next = current.subtract(qty); + if (next.compareTo(BigDecimal.ZERO) < 0) { + throw new IllegalArgumentException("库存不足,无法撤回入库"); + } + product.setCurrentStock(next); + int affected = matProductMapper.updateById(product); + if (affected <= 0) { + throw new IllegalStateException("更新产品库存失败"); + } + } +} + diff --git a/gear-mat/src/main/java/com/gear/mat/service/impl/MatProductOutsourceOrderServiceImpl.java b/gear-mat/src/main/java/com/gear/mat/service/impl/MatProductOutsourceOrderServiceImpl.java new file mode 100644 index 0000000..d1c310e --- /dev/null +++ b/gear-mat/src/main/java/com/gear/mat/service/impl/MatProductOutsourceOrderServiceImpl.java @@ -0,0 +1,215 @@ +package com.gear.mat.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +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.utils.StringUtils; +import com.gear.mat.domain.MatProduct; +import com.gear.mat.domain.MatProductOutsourceOrder; +import com.gear.mat.domain.bo.MatProductOutsourceOrderBo; +import com.gear.mat.domain.vo.MatProductOutsourceOrderVo; +import com.gear.mat.mapper.MatProductMapper; +import com.gear.mat.mapper.MatProductOutsourceOrderMapper; +import com.gear.mat.service.IMatProductOutsourceOrderService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; + +import java.math.BigDecimal; +import java.text.SimpleDateFormat; +import java.util.Collection; +import java.util.Date; +import java.util.List; + +@RequiredArgsConstructor +@Service +public class MatProductOutsourceOrderServiceImpl implements IMatProductOutsourceOrderService { + + private static final String PRODUCT_TYPE_SEMI = "semi"; + + private final MatProductOutsourceOrderMapper baseMapper; + private final MatProductMapper matProductMapper; + + @Override + public MatProductOutsourceOrderVo queryById(Long orderId) { + return baseMapper.selectVoById(orderId); + } + + @Override + public TableDataInfo queryPageList(MatProductOutsourceOrderBo bo, PageQuery pageQuery) { + QueryWrapper qw = buildQueryWrapperPlus(bo); + Page result = baseMapper.selectVoPagePlus(pageQuery.build(), qw); + return TableDataInfo.build(result); + } + + private QueryWrapper buildQueryWrapperPlus(MatProductOutsourceOrderBo bo) { + QueryWrapper qw = Wrappers.query(); + qw.eq(bo.getProductId() != null, "mo.product_id", bo.getProductId()); + qw.eq(bo.getCustomerId() != null, "mo.customer_id", bo.getCustomerId()); + qw.like(StringUtils.isNotBlank(bo.getCustomerName()), "mo.customer_name", bo.getCustomerName()); + qw.eq(StringUtils.isNotBlank(bo.getOperator()), "mo.operator", bo.getOperator()); + qw.ge(bo.getBeginTime() != null, "mo.out_time", bo.getBeginTime()); + qw.le(bo.getEndTime() != null, "mo.out_time", bo.getEndTime()); + qw.eq("mo.del_flag", 0); + qw.orderByDesc("mo.out_time"); + return qw; + } + + @Override + public List queryList(MatProductOutsourceOrderBo bo) { + QueryWrapper qw = buildQueryWrapperPlus(bo); + return baseMapper.selectVoList(qw); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean insertByBoWithInventory(MatProductOutsourceOrderBo bo) { + if (bo.getProductId() == null) { + throw new IllegalArgumentException("半成品不能为空"); + } + if (bo.getQuantity() == null || bo.getQuantity().compareTo(BigDecimal.ZERO) <= 0) { + throw new IllegalArgumentException("委派数量必须大于0"); + } + if (StringUtils.isBlank(bo.getCustomerName()) && bo.getCustomerId() == null) { + throw new IllegalArgumentException("委托公司不能为空"); + } + + MatProduct product = matProductMapper.selectById(bo.getProductId()); + if (product == null) { + throw new IllegalArgumentException("半成品不存在"); + } + if (!PRODUCT_TYPE_SEMI.equals(product.getProductType())) { + throw new IllegalArgumentException("只能委外半成品"); + } + + BigDecimal current = product.getCurrentStock() == null ? BigDecimal.ZERO : product.getCurrentStock(); + if (current.compareTo(bo.getQuantity()) < 0) { + throw new IllegalArgumentException("库存不足,无法委外出库"); + } + + if (bo.getOutTime() == null) { + bo.setOutTime(new Date()); + } + if (StringUtils.isBlank(bo.getOperator())) { + bo.setOperator("-"); + } + if (StringUtils.isBlank(bo.getOrderNo())) { + bo.setOrderNo(generateOrderNo()); + } + + MatProductOutsourceOrder add = BeanUtil.toBean(bo, MatProductOutsourceOrder.class); + add.setProductTypeSnapshot(product.getProductType()); + add.setReceivedQty(BigDecimal.ZERO); + add.setReceiveFlag(0); + boolean ok = baseMapper.insert(add) > 0; + if (!ok) { + throw new IllegalStateException("委外单保存失败"); + } + bo.setOrderId(add.getOrderId()); + + product.setCurrentStock(current.subtract(bo.getQuantity())); + int affected = matProductMapper.updateById(product); + if (affected <= 0) { + throw new IllegalStateException("扣减库存失败"); + } + return true; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean receive(Long orderId, BigDecimal receiveQty, Date receiveTime, String receiveBy) { + if (orderId == null) { + throw new IllegalArgumentException("委外单不能为空"); + } + if (receiveQty == null || receiveQty.compareTo(BigDecimal.ZERO) <= 0) { + throw new IllegalArgumentException("收回数量必须大于0"); + } + MatProductOutsourceOrder order = baseMapper.selectById(orderId); + if (order == null) { + throw new IllegalArgumentException("委外单不存在"); + } + if (order.getDelFlag() != null && order.getDelFlag() != 0) { + throw new IllegalArgumentException("委外单已撤回"); + } + if (!PRODUCT_TYPE_SEMI.equals(order.getProductTypeSnapshot())) { + throw new IllegalArgumentException("只能收回半成品委外单"); + } + BigDecimal total = order.getQuantity() == null ? BigDecimal.ZERO : order.getQuantity(); + BigDecimal received = order.getReceivedQty() == null ? BigDecimal.ZERO : order.getReceivedQty(); + BigDecimal remaining = total.subtract(received); + if (remaining.compareTo(BigDecimal.ZERO) <= 0) { + throw new IllegalArgumentException("已全部收回"); + } + if (receiveQty.compareTo(remaining) > 0) { + throw new IllegalArgumentException("收回数量不能大于未收回数量"); + } + + MatProduct product = matProductMapper.selectById(order.getProductId()); + if (product == null) { + throw new IllegalArgumentException("半成品不存在"); + } + BigDecimal current = product.getCurrentStock() == null ? BigDecimal.ZERO : product.getCurrentStock(); + product.setCurrentStock(current.add(receiveQty)); + int affected = matProductMapper.updateById(product); + if (affected <= 0) { + throw new IllegalStateException("更新库存失败"); + } + + BigDecimal nextReceived = received.add(receiveQty); + order.setReceivedQty(nextReceived); + order.setReceiveTime(receiveTime == null ? new Date() : receiveTime); + order.setReceiveBy(StringUtils.isBlank(receiveBy) ? "-" : receiveBy); + order.setReceiveFlag(nextReceived.compareTo(total) >= 0 ? 1 : 0); + int updated = baseMapper.updateById(order); + if (updated <= 0) { + throw new IllegalStateException("更新委外单失败"); + } + return true; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIdsWithInventory(Collection ids, Boolean isValid) { + if (CollectionUtils.isEmpty(ids)) { + return false; + } + List records = baseMapper.selectBatchIds(ids); + if (records == null || records.isEmpty()) { + return false; + } + for (MatProductOutsourceOrder r : records) { + if (r.getProductId() == null || r.getQuantity() == null) { + continue; + } + BigDecimal received = r.getReceivedQty() == null ? BigDecimal.ZERO : r.getReceivedQty(); + if (received.compareTo(BigDecimal.ZERO) > 0) { + throw new IllegalArgumentException("已收回的委外单不可撤回"); + } + revertStock(r.getProductId(), r.getQuantity()); + } + return baseMapper.deleteBatchIds(ids) > 0; + } + + private void revertStock(Long productId, BigDecimal qty) { + MatProduct product = matProductMapper.selectById(productId); + if (product == null) { + throw new IllegalArgumentException("半成品不存在"); + } + BigDecimal current = product.getCurrentStock() == null ? BigDecimal.ZERO : product.getCurrentStock(); + product.setCurrentStock(current.add(qty)); + int affected = matProductMapper.updateById(product); + if (affected <= 0) { + throw new IllegalStateException("回滚库存失败"); + } + } + + private String generateOrderNo() { + String ts = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()); + int rnd = (int) (Math.random() * 9000) + 1000; + return "WW" + ts + rnd; + } +} diff --git a/gear-mat/src/main/java/com/gear/mat/service/impl/MatProductServiceImpl.java b/gear-mat/src/main/java/com/gear/mat/service/impl/MatProductServiceImpl.java index 925ccf6..ed59903 100644 --- a/gear-mat/src/main/java/com/gear/mat/service/impl/MatProductServiceImpl.java +++ b/gear-mat/src/main/java/com/gear/mat/service/impl/MatProductServiceImpl.java @@ -23,6 +23,7 @@ import com.gear.mat.service.IMatProductMaterialRelationService; import com.gear.mat.domain.vo.MatMaterialVo; import com.gear.mat.domain.vo.MatProductMaterialRelationVo; +import java.math.BigDecimal; import java.util.List; import java.util.Map; import java.util.Collection; @@ -40,6 +41,9 @@ import java.util.ArrayList; @Service public class MatProductServiceImpl implements IMatProductService { + private static final String PRODUCT_TYPE_PRODUCT = "product"; + private static final String PRODUCT_TYPE_SEMI = "semi"; + private final MatProductMapper baseMapper; private final IMatMaterialService matMaterialService; private final IMatProductMaterialRelationService productMaterialRelationService; @@ -73,12 +77,12 @@ public class MatProductServiceImpl implements IMatProductService { } private LambdaQueryWrapper buildQueryWrapper(MatProductBo bo) { - Map params = bo.getParams(); LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); lqw.like(StringUtils.isNotBlank(bo.getProductName()), MatProduct::getProductName, bo.getProductName()); lqw.eq(StringUtils.isNotBlank(bo.getSpec()), MatProduct::getSpec, bo.getSpec()); lqw.eq(StringUtils.isNotBlank(bo.getModel()), MatProduct::getModel, bo.getModel()); lqw.eq(bo.getUnitPrice() != null, MatProduct::getUnitPrice, bo.getUnitPrice()); + lqw.eq(StringUtils.isNotBlank(bo.getProductType()), MatProduct::getProductType, bo.getProductType()); return lqw; } @@ -113,6 +117,8 @@ public class MatProductServiceImpl implements IMatProductService { productWithMaterialsVo.setSpec(productVo.getSpec()); productWithMaterialsVo.setModel(productVo.getModel()); productWithMaterialsVo.setUnitPrice(productVo.getUnitPrice()); + productWithMaterialsVo.setProductType(productVo.getProductType()); + productWithMaterialsVo.setCurrentStock(productVo.getCurrentStock()); productWithMaterialsVo.setRemark(productVo.getRemark()); productWithMaterialsVo.setProductImages(productVo.getProductImages()); productWithMaterialsVo.setProductPdfs(productVo.getProductPdfs()); @@ -174,6 +180,8 @@ public class MatProductServiceImpl implements IMatProductService { public Boolean insertByBo(MatProductBo bo) { System.out.println("插入产品,productPdfs: " + bo.getProductPdfs()); MatProduct add = BeanUtil.toBean(bo, MatProduct.class); + add.setProductType(normalizeProductType(add.getProductType())); + add.setCurrentStock(normalizeCurrentStock(add.getCurrentStock())); System.out.println("转换后,productPdfs: " + add.getProductPdfs()); validEntityBeforeSave(add); boolean flag = baseMapper.insert(add) > 0; @@ -190,6 +198,8 @@ public class MatProductServiceImpl implements IMatProductService { public Boolean updateByBo(MatProductBo bo) { System.out.println("修改产品,productPdfs: " + bo.getProductPdfs()); MatProduct update = BeanUtil.toBean(bo, MatProduct.class); + update.setProductType(normalizeProductType(update.getProductType())); + update.setCurrentStock(normalizeCurrentStock(update.getCurrentStock())); System.out.println("转换后,productPdfs: " + update.getProductPdfs()); validEntityBeforeSave(update); return baseMapper.updateById(update) > 0; @@ -245,6 +255,8 @@ public class MatProductServiceImpl implements IMatProductService { data.setModel(model); data.setUnitPrice(row.getUnitPrice()); data.setRemark(row.getRemark()); + data.setProductType(normalizeProductType(data.getProductType())); + data.setCurrentStock(normalizeCurrentStock(data.getCurrentStock())); if (exist == null) { baseMapper.insert(data); } else { @@ -254,4 +266,22 @@ public class MatProductServiceImpl implements IMatProductService { } return "导入完成,成功 " + success + " 条,跳过 " + skipped + " 条"; } + + private String normalizeProductType(String productType) { + String val = StringUtils.trim(productType); + if (StringUtils.isBlank(val)) { + return PRODUCT_TYPE_PRODUCT; + } + if (PRODUCT_TYPE_SEMI.equals(val)) { + return PRODUCT_TYPE_SEMI; + } + if (PRODUCT_TYPE_PRODUCT.equals(val)) { + return PRODUCT_TYPE_PRODUCT; + } + return PRODUCT_TYPE_PRODUCT; + } + + private BigDecimal normalizeCurrentStock(BigDecimal currentStock) { + return currentStock == null ? BigDecimal.ZERO : currentStock; + } } diff --git a/gear-mat/src/main/resources/mapper/MatProductInDetailMapper.xml b/gear-mat/src/main/resources/mapper/MatProductInDetailMapper.xml new file mode 100644 index 0000000..56e4a13 --- /dev/null +++ b/gear-mat/src/main/resources/mapper/MatProductInDetailMapper.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/gear-mat/src/main/resources/mapper/MatProductOutsourceOrderMapper.xml b/gear-mat/src/main/resources/mapper/MatProductOutsourceOrderMapper.xml new file mode 100644 index 0000000..b268c8b --- /dev/null +++ b/gear-mat/src/main/resources/mapper/MatProductOutsourceOrderMapper.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 index 27e6097..4347b4f 100644 --- a/gear-oa/src/main/java/com/gear/oa/controller/GearStockIoOrderController.java +++ b/gear-oa/src/main/java/com/gear/oa/controller/GearStockIoOrderController.java @@ -15,14 +15,19 @@ 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 com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.fasterxml.jackson.annotation.JsonFormat; import lombok.RequiredArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletResponse; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; -import org.springframework.format.annotation.DateTimeFormat; +import java.math.BigDecimal; +import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; @@ -55,6 +60,187 @@ public class GearStockIoOrderController extends BaseController { return R.ok(stockIoOrderService.queryMaterialFlow(itemId, startTime, endTime)); } + @Log(title = "物料出入库统计", businessType = BusinessType.EXPORT) + @PostMapping("/materialFlow/export") + public void exportMaterialFlow(@NotNull(message = "物料ID不能为空") @RequestParam Long itemId, + @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date startTime, + @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date endTime, + HttpServletResponse response) { + IGearStockIoOrderService.MaterialFlowResp resp = stockIoOrderService.queryMaterialFlow(itemId, startTime, endTime); + List exportRows = new ArrayList<>(); + + MaterialFlowExportRow summary = new MaterialFlowExportRow(); + summary.setItemId(resp.getItemId()); + summary.setStartTime(resp.getStartTime()); + summary.setEndTime(resp.getEndTime()); + summary.setAction("汇总"); + summary.setConfirmInQty(nz(resp.getConfirmInQty())); + summary.setOutQty(nz(resp.getOutQty())); + summary.setRevokeInQty(nz(resp.getRevokeInQty())); + summary.setRevokeOutQty(nz(resp.getRevokeOutQty())); + summary.setNetQty(nz(resp.getNetQty())); + exportRows.add(summary); + + if (resp.getRows() != null) { + for (IGearStockIoOrderService.MaterialFlowRow r : resp.getRows()) { + MaterialFlowExportRow row = new MaterialFlowExportRow(); + row.setItemId(resp.getItemId()); + row.setTime(r.getTime()); + row.setAction(r.getAction()); + row.setOrderCode(r.getOrderCode()); + row.setIoType(r.getIoType()); + row.setQtyChange(r.getQtyChange()); + exportRows.add(row); + } + } + + ExcelUtil.exportExcel(exportRows, "物料出入库统计", MaterialFlowExportRow.class, response); + } + + private static BigDecimal nz(BigDecimal v) { + return v == null ? BigDecimal.ZERO : v; + } + + @ExcelIgnoreUnannotated + public static class MaterialFlowExportRow { + @ExcelProperty(value = "物料ID") + private Long itemId; + @ExcelProperty(value = "开始时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date startTime; + @ExcelProperty(value = "结束时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date endTime; + @ExcelProperty(value = "确认入库汇总") + private BigDecimal confirmInQty; + @ExcelProperty(value = "出库汇总") + private BigDecimal outQty; + @ExcelProperty(value = "撤回入库汇总") + private BigDecimal revokeInQty; + @ExcelProperty(value = "撤回出库汇总") + private BigDecimal revokeOutQty; + @ExcelProperty(value = "净变动汇总") + private BigDecimal netQty; + @ExcelProperty(value = "明细时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date time; + @ExcelProperty(value = "动作") + private String action; + @ExcelProperty(value = "单号") + private String orderCode; + @ExcelProperty(value = "类型") + private String ioType; + @ExcelProperty(value = "数量变化") + private BigDecimal qtyChange; + + public Long getItemId() { + return itemId; + } + + public void setItemId(Long itemId) { + this.itemId = itemId; + } + + public Date getStartTime() { + return startTime; + } + + public void setStartTime(Date startTime) { + this.startTime = startTime; + } + + public Date getEndTime() { + return endTime; + } + + public void setEndTime(Date endTime) { + this.endTime = endTime; + } + + public BigDecimal getConfirmInQty() { + return confirmInQty; + } + + public void setConfirmInQty(BigDecimal confirmInQty) { + this.confirmInQty = confirmInQty; + } + + public BigDecimal getOutQty() { + return outQty; + } + + public void setOutQty(BigDecimal outQty) { + this.outQty = outQty; + } + + public BigDecimal getRevokeInQty() { + return revokeInQty; + } + + public void setRevokeInQty(BigDecimal revokeInQty) { + this.revokeInQty = revokeInQty; + } + + public BigDecimal getRevokeOutQty() { + return revokeOutQty; + } + + public void setRevokeOutQty(BigDecimal revokeOutQty) { + this.revokeOutQty = revokeOutQty; + } + + public BigDecimal getNetQty() { + return netQty; + } + + public void setNetQty(BigDecimal netQty) { + this.netQty = netQty; + } + + public Date getTime() { + return time; + } + + public void setTime(Date time) { + this.time = time; + } + + public String getAction() { + return action; + } + + public void setAction(String action) { + this.action = action; + } + + public String getOrderCode() { + return orderCode; + } + + public void setOrderCode(String orderCode) { + this.orderCode = orderCode; + } + + public String getIoType() { + return ioType; + } + + public void setIoType(String ioType) { + this.ioType = ioType; + } + + public BigDecimal getQtyChange() { + return qtyChange; + } + + public void setQtyChange(BigDecimal qtyChange) { + this.qtyChange = qtyChange; + } + } + @GetMapping("/{orderId}") public R getInfo(@NotNull(message = "主键不能为空") @PathVariable Long orderId) { return R.ok(stockIoOrderService.queryById(orderId)); diff --git a/gear-ui3/src/api/mat/productInDetail.js b/gear-ui3/src/api/mat/productInDetail.js new file mode 100644 index 0000000..055792c --- /dev/null +++ b/gear-ui3/src/api/mat/productInDetail.js @@ -0,0 +1,40 @@ +import request from '@/utils/request' + +export function listProductInDetail(query) { + return request({ + url: '/mat/productInDetail/list', + method: 'get', + params: query + }) +} + +export function getProductInDetail(detailId) { + return request({ + url: '/mat/productInDetail/' + detailId, + method: 'get' + }) +} + +export function addProductInDetail(data) { + return request({ + url: '/mat/productInDetail', + method: 'post', + data: data + }) +} + +export function updateProductInDetail(data) { + return request({ + url: '/mat/productInDetail', + method: 'put', + data: data + }) +} + +export function delProductInDetail(detailId) { + return request({ + url: '/mat/productInDetail/' + detailId, + method: 'delete' + }) +} + diff --git a/gear-ui3/src/api/mat/productOutsourceOrder.js b/gear-ui3/src/api/mat/productOutsourceOrder.js new file mode 100644 index 0000000..693c111 --- /dev/null +++ b/gear-ui3/src/api/mat/productOutsourceOrder.js @@ -0,0 +1,39 @@ +import request from '@/utils/request' + +export function listProductOutsourceOrder(query) { + return request({ + url: '/mat/productOutsourceOrder/list', + method: 'get', + params: query + }) +} + +export function getProductOutsourceOrder(orderId) { + return request({ + url: '/mat/productOutsourceOrder/' + orderId, + method: 'get' + }) +} + +export function addProductOutsourceOrder(data) { + return request({ + url: '/mat/productOutsourceOrder', + method: 'post', + data: data + }) +} + +export function delProductOutsourceOrder(orderId) { + return request({ + url: '/mat/productOutsourceOrder/' + orderId, + method: 'delete' + }) +} + +export function receiveProductOutsourceOrder(orderId, data) { + return request({ + url: '/mat/productOutsourceOrder/receive/' + orderId, + method: 'post', + data + }) +} diff --git a/gear-ui3/src/views/mat/product/detail.vue b/gear-ui3/src/views/mat/product/detail.vue index 6012eca..52fbe13 100644 --- a/gear-ui3/src/views/mat/product/detail.vue +++ b/gear-ui3/src/views/mat/product/detail.vue @@ -17,6 +17,14 @@ {{ productDetail.productName || '-' }} + + + {{ productTypeLabel(productDetail.productType) }} + + + + {{ formatDecimal(productDetail.currentStock) }} + {{ formatDecimal(productDetail.unitPrice) }} 元 @@ -188,6 +196,9 @@ import { Document } from '@element-plus/icons-vue'; const router = useRouter(); const route = useRoute(); +const productTypeLabel = (val) => (val === 'semi' ? '半成品' : '产品'); +const productTypeTagType = (val) => (val === 'semi' ? 'warning' : 'success'); + const productDetail = ref({}); const loading = ref(true); const materialLoading = ref(false); diff --git a/gear-ui3/src/views/mat/product/index.vue b/gear-ui3/src/views/mat/product/index.vue index 26512c6..6cb5b47 100644 --- a/gear-ui3/src/views/mat/product/index.vue +++ b/gear-ui3/src/views/mat/product/index.vue @@ -40,6 +40,13 @@ + + + @@ -47,6 +54,11 @@ {{ formatDecimal(scope.row.unitPrice) }} + + +