From 617e149fc8ad2532ff2540ddb0f0d8108a2a324a Mon Sep 17 00:00:00 2001 From: 86156 <823267011@qq.com> Date: Tue, 18 Nov 2025 16:45:28 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E5=9F=BA=E7=A1=80=E9=87=87?= =?UTF-8?q?=E8=B4=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ErpPurchaseOrderController.java | 40 ++++++ .../com/klp/erp/domain/ErpPurchaseOrder.java | 13 +- .../klp/erp/domain/bo/ErpPurchaseOrderBo.java | 24 +++- .../klp/erp/domain/vo/ErpPurchaseOrderVo.java | 28 +++- .../erp/service/IErpPurchaseOrderService.java | 28 +++- .../impl/ErpPurchaseOrderServiceImpl.java | 121 ++++++++++++++++-- .../mapper/erp/ErpPurchaseOrderMapper.xml | 2 + 7 files changed, 233 insertions(+), 23 deletions(-) diff --git a/klp-erp/src/main/java/com/klp/erp/controller/ErpPurchaseOrderController.java b/klp-erp/src/main/java/com/klp/erp/controller/ErpPurchaseOrderController.java index f324fcd9..969e1984 100644 --- a/klp-erp/src/main/java/com/klp/erp/controller/ErpPurchaseOrderController.java +++ b/klp-erp/src/main/java/com/klp/erp/controller/ErpPurchaseOrderController.java @@ -85,6 +85,46 @@ public class ErpPurchaseOrderController extends BaseController { return toAjax(iErpPurchaseOrderService.updateByBo(bo)); } + /** + * 下达采购订单 + */ + @Log(title = "采购订单主", businessType = BusinessType.UPDATE) + @PutMapping("/{orderId}/confirm") + public R confirm(@NotNull(message = "主键不能为空") + @PathVariable Long orderId) { + return toAjax(iErpPurchaseOrderService.confirmOrder(orderId, getUsername())); + } + + /** + * 标记部分到货 + */ + @Log(title = "采购订单主", businessType = BusinessType.UPDATE) + @PutMapping("/{orderId}/partial") + public R partial(@NotNull(message = "主键不能为空") + @PathVariable Long orderId) { + return toAjax(iErpPurchaseOrderService.markPartialArrival(orderId)); + } + + /** + * 标记订单完成 + */ + @Log(title = "采购订单主", businessType = BusinessType.UPDATE) + @PutMapping("/{orderId}/complete") + public R complete(@NotNull(message = "主键不能为空") + @PathVariable Long orderId) { + return toAjax(iErpPurchaseOrderService.completeOrder(orderId)); + } + + /** + * 取消采购订单 + */ + @Log(title = "采购订单主", businessType = BusinessType.UPDATE) + @PutMapping("/{orderId}/cancel") + public R cancel(@NotNull(message = "主键不能为空") + @PathVariable Long orderId) { + return toAjax(iErpPurchaseOrderService.cancelOrder(orderId)); + } + /** * 删除采购订单主 * diff --git a/klp-erp/src/main/java/com/klp/erp/domain/ErpPurchaseOrder.java b/klp-erp/src/main/java/com/klp/erp/domain/ErpPurchaseOrder.java index e9ec1cad..215e5e39 100644 --- a/klp-erp/src/main/java/com/klp/erp/domain/ErpPurchaseOrder.java +++ b/klp-erp/src/main/java/com/klp/erp/domain/ErpPurchaseOrder.java @@ -38,10 +38,12 @@ public class ErpPurchaseOrder extends BaseEntity { /** * 下单日期 */ + @JsonFormat(pattern = "yyyy-MM-dd") private Date orderDate; /** * 预计到货日期 */ + @JsonFormat(pattern = "yyyy-MM-dd") private Date expectedArrival; /** * 订单类型 @@ -54,7 +56,16 @@ public class ErpPurchaseOrder extends BaseEntity { /** * 订单状态 */ - private Long orderStatus; + private Integer orderStatus; + /** + * 下达人 + */ + private String confirmBy; + /** + * 下达时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date confirmTime; /** * 删除标志 */ diff --git a/klp-erp/src/main/java/com/klp/erp/domain/bo/ErpPurchaseOrderBo.java b/klp-erp/src/main/java/com/klp/erp/domain/bo/ErpPurchaseOrderBo.java index b2337c76..de02dc35 100644 --- a/klp-erp/src/main/java/com/klp/erp/domain/bo/ErpPurchaseOrderBo.java +++ b/klp-erp/src/main/java/com/klp/erp/domain/bo/ErpPurchaseOrderBo.java @@ -1,13 +1,16 @@ package com.klp.erp.domain.bo; +import com.fasterxml.jackson.annotation.JsonFormat; import com.klp.common.core.domain.BaseEntity; +import com.klp.common.core.validate.AddGroup; +import com.klp.common.core.validate.EditGroup; import lombok.Data; import lombok.EqualsAndHashCode; -import javax.validation.constraints.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; import java.math.BigDecimal; import java.util.Date; -import com.fasterxml.jackson.annotation.JsonFormat; /** * 采购订单主业务对象 erp_purchase_order @@ -28,21 +31,25 @@ public class ErpPurchaseOrderBo extends BaseEntity { /** * 订单编号 */ + @NotBlank(message = "订单编号不能为空", groups = {AddGroup.class, EditGroup.class}) private String orderCode; /** * 供应商ID */ + @NotNull(message = "供应商不能为空", groups = {AddGroup.class, EditGroup.class}) private Long supplierId; /** * 下单日期 */ + @JsonFormat(pattern = "yyyy-MM-dd") private Date orderDate; /** * 预计到货日期 */ + @JsonFormat(pattern = "yyyy-MM-dd") private Date expectedArrival; /** @@ -58,7 +65,18 @@ public class ErpPurchaseOrderBo extends BaseEntity { /** * 订单状态 */ - private Long orderStatus; + private Integer orderStatus; + + /** + * 下达人 + */ + private String confirmBy; + + /** + * 下达时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date confirmTime; /** * 备注 diff --git a/klp-erp/src/main/java/com/klp/erp/domain/vo/ErpPurchaseOrderVo.java b/klp-erp/src/main/java/com/klp/erp/domain/vo/ErpPurchaseOrderVo.java index 1d7fc666..0143c0f9 100644 --- a/klp-erp/src/main/java/com/klp/erp/domain/vo/ErpPurchaseOrderVo.java +++ b/klp-erp/src/main/java/com/klp/erp/domain/vo/ErpPurchaseOrderVo.java @@ -1,14 +1,13 @@ package com.klp.erp.domain.vo; -import java.math.BigDecimal; -import java.util.Date; -import com.fasterxml.jackson.annotation.JsonFormat; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; -import com.klp.common.annotation.ExcelDictFormat; -import com.klp.common.convert.ExcelDictConvert; +import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; /** * 采购订单主视图对象 erp_purchase_order @@ -18,7 +17,7 @@ import lombok.Data; */ @Data @ExcelIgnoreUnannotated -public class ErpPurchaseOrderVo { +public class ErpPurchaseOrderVo implements Serializable { private static final long serialVersionUID = 1L; @@ -44,12 +43,14 @@ public class ErpPurchaseOrderVo { * 下单日期 */ @ExcelProperty(value = "下单日期") + @JsonFormat(pattern = "yyyy-MM-dd") private Date orderDate; /** * 预计到货日期 */ @ExcelProperty(value = "预计到货日期") + @JsonFormat(pattern = "yyyy-MM-dd") private Date expectedArrival; /** @@ -68,7 +69,20 @@ public class ErpPurchaseOrderVo { * 订单状态 */ @ExcelProperty(value = "订单状态") - private Long orderStatus; + private Integer orderStatus; + + /** + * 下达人 + */ + @ExcelProperty(value = "下达人") + private String confirmBy; + + /** + * 下达时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @ExcelProperty(value = "下达时间") + private Date confirmTime; /** * 备注 diff --git a/klp-erp/src/main/java/com/klp/erp/service/IErpPurchaseOrderService.java b/klp-erp/src/main/java/com/klp/erp/service/IErpPurchaseOrderService.java index c2160b9a..ffbb51e5 100644 --- a/klp-erp/src/main/java/com/klp/erp/service/IErpPurchaseOrderService.java +++ b/klp-erp/src/main/java/com/klp/erp/service/IErpPurchaseOrderService.java @@ -1,8 +1,7 @@ package com.klp.erp.service; -import com.klp.erp.domain.ErpPurchaseOrder; -import com.klp.erp.domain.vo.ErpPurchaseOrderVo; import com.klp.erp.domain.bo.ErpPurchaseOrderBo; +import com.klp.erp.domain.vo.ErpPurchaseOrderVo; import com.klp.common.core.page.TableDataInfo; import com.klp.common.core.domain.PageQuery; @@ -46,4 +45,29 @@ public interface IErpPurchaseOrderService { * 校验并批量删除采购订单主信息 */ Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 下达订单 + */ + Boolean confirmOrder(Long orderId, String operator); + + /** + * 标记部分到货 + */ + Boolean markPartialArrival(Long orderId); + + /** + * 标记订单完成 + */ + Boolean completeOrder(Long orderId); + + /** + * 取消订单 + */ + Boolean cancelOrder(Long orderId); + + /** + * 根据收货/退货情况刷新订单状态 + */ + void refreshOrderStatus(Long orderId); } diff --git a/klp-erp/src/main/java/com/klp/erp/service/impl/ErpPurchaseOrderServiceImpl.java b/klp-erp/src/main/java/com/klp/erp/service/impl/ErpPurchaseOrderServiceImpl.java index ce317783..dad60b45 100644 --- a/klp-erp/src/main/java/com/klp/erp/service/impl/ErpPurchaseOrderServiceImpl.java +++ b/klp-erp/src/main/java/com/klp/erp/service/impl/ErpPurchaseOrderServiceImpl.java @@ -1,24 +1,30 @@ package com.klp.erp.service.impl; import cn.hutool.core.bean.BeanUtil; -import com.klp.common.core.page.TableDataInfo; -import com.klp.common.core.domain.PageQuery; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 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.klp.common.core.domain.PageQuery; +import com.klp.common.core.page.TableDataInfo; +import com.klp.common.exception.ServiceException; import com.klp.common.utils.StringUtils; -import lombok.RequiredArgsConstructor; -import org.springframework.cache.annotation.Cacheable; -import org.springframework.stereotype.Service; +import com.klp.erp.domain.ErpPurchaseOrder; +import com.klp.erp.domain.ErpPurchaseOrderItem; +import com.klp.erp.enums.PurchaseOrderStatus; import com.klp.erp.domain.bo.ErpPurchaseOrderBo; import com.klp.erp.domain.vo.ErpPurchaseOrderVo; -import com.klp.erp.domain.ErpPurchaseOrder; +import com.klp.erp.mapper.ErpPurchaseOrderItemMapper; import com.klp.erp.mapper.ErpPurchaseOrderMapper; +import com.klp.erp.mapper.ErpPurchaseReceiptMapper; +import com.klp.erp.mapper.ErpPurchaseReturnItemMapper; import com.klp.erp.service.IErpPurchaseOrderService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; +import java.math.BigDecimal; import java.util.Collection; +import java.util.Date; +import java.util.List; /** * 采购订单主Service业务层处理 @@ -31,6 +37,9 @@ import java.util.Collection; public class ErpPurchaseOrderServiceImpl implements IErpPurchaseOrderService { private final ErpPurchaseOrderMapper baseMapper; + private final ErpPurchaseOrderItemMapper orderItemMapper; + private final ErpPurchaseReceiptMapper receiptMapper; + private final ErpPurchaseReturnItemMapper returnItemMapper; /** * 查询采购订单主 @@ -60,7 +69,6 @@ public class ErpPurchaseOrderServiceImpl implements IErpPurchaseOrderService { } private LambdaQueryWrapper buildQueryWrapper(ErpPurchaseOrderBo bo) { - Map params = bo.getParams(); LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); lqw.eq(StringUtils.isNotBlank(bo.getOrderCode()), ErpPurchaseOrder::getOrderCode, bo.getOrderCode()); lqw.eq(bo.getSupplierId() != null, ErpPurchaseOrder::getSupplierId, bo.getSupplierId()); @@ -69,6 +77,7 @@ public class ErpPurchaseOrderServiceImpl implements IErpPurchaseOrderService { lqw.eq(StringUtils.isNotBlank(bo.getOrderType()), ErpPurchaseOrder::getOrderType, bo.getOrderType()); lqw.eq(bo.getTotalAmount() != null, ErpPurchaseOrder::getTotalAmount, bo.getTotalAmount()); lqw.eq(bo.getOrderStatus() != null, ErpPurchaseOrder::getOrderStatus, bo.getOrderStatus()); + lqw.like(StringUtils.isNotBlank(bo.getConfirmBy()), ErpPurchaseOrder::getConfirmBy, bo.getConfirmBy()); return lqw; } @@ -79,6 +88,9 @@ public class ErpPurchaseOrderServiceImpl implements IErpPurchaseOrderService { public Boolean insertByBo(ErpPurchaseOrderBo bo) { ErpPurchaseOrder add = BeanUtil.toBean(bo, ErpPurchaseOrder.class); validEntityBeforeSave(add); + if (add.getOrderStatus() == null) { + add.setOrderStatus(0); + } boolean flag = baseMapper.insert(add) > 0; if (flag) { bo.setOrderId(add.getOrderId()); @@ -113,4 +125,93 @@ public class ErpPurchaseOrderServiceImpl implements IErpPurchaseOrderService { } return baseMapper.deleteBatchIds(ids) > 0; } + + @Override + public Boolean confirmOrder(Long orderId, String operator) { + ErpPurchaseOrder order = baseMapper.selectById(orderId); + if (order == null) { + return false; + } + if (PurchaseOrderStatus.EXECUTING.getCode() == (order.getOrderStatus() == null ? -1 : order.getOrderStatus())) { + return true; + } + order.setOrderStatus(PurchaseOrderStatus.EXECUTING.getCode()); + order.setConfirmBy(operator); + order.setConfirmTime(new Date()); + return baseMapper.updateById(order) > 0; + } + + @Override + public Boolean markPartialArrival(Long orderId) { + return updateStatus(orderId, PurchaseOrderStatus.PARTIAL_ARRIVAL.getCode()); + } + + @Override + public Boolean completeOrder(Long orderId) { + return updateStatus(orderId, PurchaseOrderStatus.COMPLETED.getCode()); + } + + @Override + public Boolean cancelOrder(Long orderId) { + return updateStatus(orderId, PurchaseOrderStatus.CANCELLED.getCode()); + } + + @Override + public void refreshOrderStatus(Long orderId) { + List items = orderItemMapper.selectList( + Wrappers.lambdaQuery(ErpPurchaseOrderItem.class) + .eq(ErpPurchaseOrderItem::getOrderId, orderId) + .eq(ErpPurchaseOrderItem::getDelFlag, 0L)); + if (items == null || items.isEmpty()) { + return; + } + boolean anyReceived = false; + boolean allReceived = true; + for (ErpPurchaseOrderItem item : items) { + BigDecimal ordered = safe(item.getQuantity()); + BigDecimal qualified = safe(receiptMapper.sumQualifiedQtyByItem(item.getItemId())); + BigDecimal returned = safe(returnItemMapper.sumCompletedReturnQtyByItem(item.getItemId())); + BigDecimal effective = qualified.subtract(returned); + if (effective.compareTo(BigDecimal.ZERO) < 0) { + effective = BigDecimal.ZERO; + } + if (effective.compareTo(ordered) > 0) { + throw new ServiceException("收货数量超过订单明细:" + item.getSpecification()); + } + if (effective.compareTo(BigDecimal.ZERO) > 0) { + anyReceived = true; + } + if (effective.compareTo(ordered) < 0) { + allReceived = false; + } + } + if (allReceived) { + completeOrder(orderId); + } else if (anyReceived) { + markPartialArrival(orderId); + } else { + // 如果没有收货记录且订单曾标记部分/完成,可恢复为执行中 + ErpPurchaseOrder order = baseMapper.selectById(orderId); + if (order != null && !Integer.valueOf(PurchaseOrderStatus.EXECUTING.getCode()).equals(order.getOrderStatus())) { + updateStatus(orderId, PurchaseOrderStatus.EXECUTING.getCode()); + } + } + } + + private Boolean updateStatus(Long orderId, int targetStatus) { + ErpPurchaseOrder order = baseMapper.selectById(orderId); + if (order == null) { + return false; + } + Integer currentStatus = order.getOrderStatus(); + if (currentStatus != null && currentStatus == targetStatus) { + return true; + } + order.setOrderStatus(targetStatus); + return baseMapper.updateById(order) > 0; + } + + private BigDecimal safe(BigDecimal value) { + return value == null ? BigDecimal.ZERO : value; + } } diff --git a/klp-erp/src/main/resources/mapper/erp/ErpPurchaseOrderMapper.xml b/klp-erp/src/main/resources/mapper/erp/ErpPurchaseOrderMapper.xml index 2eccdd13..7d53ce8c 100644 --- a/klp-erp/src/main/resources/mapper/erp/ErpPurchaseOrderMapper.xml +++ b/klp-erp/src/main/resources/mapper/erp/ErpPurchaseOrderMapper.xml @@ -13,6 +13,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + +