Commit 15236b1f by 杨浩

下单到采购分单

parent 2588cc91
package cn.iocoder.foodnexus.module.erp.api.enums;
import cn.iocoder.foodnexus.framework.common.core.ArrayValuable;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.util.Arrays;
/**
* ERP 发货状态枚举
*/
@RequiredArgsConstructor
@Getter
public enum ErpDeliveryStatus implements ArrayValuable<String> {
MATCHED("MATCHED", "已匹配"),
NOT_YET("NOT_YET", "未发货"),
ALREADY("ALREADY", "已发货"),
;
public static final String[] ARRAYS = Arrays.stream(values()).map(ErpDeliveryStatus::getStatus).toArray(String[]::new);
/**
* 状态
*/
private final String status;
/**
* 状态名
*/
private final String name;
@Override
public String[] array() {
return ARRAYS;
}
}
package cn.iocoder.foodnexus.module.erp.api.service;
import cn.iocoder.foodnexus.module.erp.api.vo.warehouse.WarehouseInfo;
/**
* @author : yanghao
* create at: 2025/9/5 17:25
......@@ -10,4 +12,5 @@ public interface ErpWarehouseApi {
boolean existsById(Long warehouseId);
WarehouseInfo getInfoByWarehouseAreaId(Long warehouseAreaId);
}
......@@ -70,6 +70,11 @@
<artifactId>foodnexus-module-product</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>foodnexus-module-order-api</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
......
package cn.iocoder.foodnexus.module.erp.api;
import lombok.Data;
/**
* @author : yanghao
* create at: 2025/9/22 14:50
* @description: 客户订单拆分采购订单
*/
@Data
public class PurchaseOrderSplitEvent {
/**
* 客户订单id
*/
private Long customerOrderId;
}
......@@ -52,8 +52,6 @@ public class ErpPurchaseOrderController {
@Resource
private ErpStockService stockService;
@Resource
private ErpProductService productService;
@Resource
private ErpSupplierService supplierService;
@Resource
......@@ -102,14 +100,14 @@ public class ErpPurchaseOrderController {
return success(null);
}
List<ErpPurchaseOrderItemDO> purchaseOrderItemList = purchaseOrderService.getPurchaseOrderItemListByOrderId(id);
Map<Long, ErpProductRespVO> productMap = productService.getProductVOMap(
convertSet(purchaseOrderItemList, ErpPurchaseOrderItemDO::getProductId));
/*Map<Long, ErpProductRespVO> productMap = productService.getProductVOMap(
convertSet(purchaseOrderItemList, ErpPurchaseOrderItemDO::getProductId));*/
return success(BeanUtils.toBean(purchaseOrder, ErpPurchaseOrderRespVO.class, purchaseOrderVO ->
purchaseOrderVO.setItems(BeanUtils.toBean(purchaseOrderItemList, ErpPurchaseOrderRespVO.Item.class, item -> {
BigDecimal purchaseCount = stockService.getStockCount(item.getProductId());
item.setStockCount(purchaseCount != null ? purchaseCount : BigDecimal.ZERO);
MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName())
.setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName()));
/*MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName())
.setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName()));*/
}))));
}
......@@ -142,8 +140,8 @@ public class ErpPurchaseOrderController {
convertSet(pageResult.getList(), ErpPurchaseOrderDO::getId));
Map<Long, List<ErpPurchaseOrderItemDO>> purchaseOrderItemMap = convertMultiMap(purchaseOrderItemList, ErpPurchaseOrderItemDO::getOrderId);
// 1.2 产品信息
Map<Long, ErpProductRespVO> productMap = productService.getProductVOMap(
convertSet(purchaseOrderItemList, ErpPurchaseOrderItemDO::getProductId));
/*Map<Long, ErpProductRespVO> productMap = productService.getProductVOMap(
convertSet(purchaseOrderItemList, ErpPurchaseOrderItemDO::getProductId));*/
// 1.3 供应商信息
Map<Long, ErpSupplierDO> supplierMap = supplierService.getSupplierMap(
convertSet(pageResult.getList(), ErpPurchaseOrderDO::getSupplierId));
......@@ -152,9 +150,10 @@ public class ErpPurchaseOrderController {
convertSet(pageResult.getList(), purchaseOrder -> Long.parseLong(purchaseOrder.getCreator())));
// 2. 开始拼接
return BeanUtils.toBean(pageResult, ErpPurchaseOrderRespVO.class, purchaseOrder -> {
purchaseOrder.setItems(BeanUtils.toBean(purchaseOrderItemMap.get(purchaseOrder.getId()), ErpPurchaseOrderRespVO.Item.class,
purchaseOrder.setItems(BeanUtils.toBean(purchaseOrderItemMap.get(purchaseOrder.getId()), ErpPurchaseOrderRespVO.Item.class
/*,
item -> MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName())
.setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName()))));
.setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName()))*/));
purchaseOrder.setProductNames(CollUtil.join(purchaseOrder.getItems(), ",", ErpPurchaseOrderRespVO.Item::getProductName));
MapUtils.findAndThen(supplierMap, purchaseOrder.getSupplierId(), supplier -> purchaseOrder.setSupplierName(supplier.getName()));
MapUtils.findAndThen(userMap, Long.parseLong(purchaseOrder.getCreator()), user -> purchaseOrder.setCreatorName(user.getNickname()));
......
......@@ -67,7 +67,7 @@ public class ErpPurchaseInRespVO {
@Schema(description = "优惠金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127")
private BigDecimal discountPrice;
@Schema(description = "定金金额,单位:", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127")
@Schema(description = "定金金额,单位:", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127")
private BigDecimal otherPrice;
@Schema(description = "附件地址", example = "https://www.iocoder.cn")
......
......@@ -2,6 +2,7 @@ package cn.iocoder.foodnexus.module.erp.controller.admin.purchase.vo.order;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import cn.iocoder.foodnexus.module.erp.api.enums.ErpDeliveryStatus;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
......@@ -60,8 +61,8 @@ public class ErpPurchaseOrderRespVO {
@Schema(description = "优惠金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127")
private BigDecimal discountPrice;
@Schema(description = "定金金额,单位:", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127")
private BigDecimal depositPrice;
@Schema(description = "定金金额,单位:", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127")
private Integer depositPrice;
@Schema(description = "附件地址", example = "https://www.iocoder.cn")
@ExcelProperty("附件地址")
......@@ -97,6 +98,17 @@ public class ErpPurchaseOrderRespVO {
@Schema(description = "采购退货数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
private BigDecimal returnCount;
@Schema(description = "客户订单id")
private Long customerId;
/**
* 发货状态
*
* 枚举 {@link ErpDeliveryStatus}
*/
@Schema(description = "发货状态")
private String deliveryStatus;
@Data
public static class Item {
......@@ -107,14 +119,14 @@ public class ErpPurchaseOrderRespVO {
private Long productId;
@Schema(description = "产品单位单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113")
private Long productUnitId;
private String productUnit;
@Schema(description = "产品单价", example = "100.00")
private BigDecimal productPrice;
private Integer productPrice;
@Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
@NotNull(message = "产品数量不能为空")
private BigDecimal count;
private Integer count;
@Schema(description = "税率,百分比", example = "99.88")
private BigDecimal taxPercent;
......@@ -147,6 +159,11 @@ public class ErpPurchaseOrderRespVO {
@Schema(description = "库存数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
private BigDecimal stockCount; // 该字段仅仅在“详情”和“编辑”时使用
@Schema(description = "客户订单id")
private Long customerId;
}
}
package cn.iocoder.foodnexus.module.erp.controller.admin.purchase.vo.order;
import cn.iocoder.foodnexus.module.erp.api.enums.ErpDeliveryStatus;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Schema(description = "管理后台 - ERP 采购订单新增/修改 Request VO")
@Data
@AllArgsConstructor
public class ErpPurchaseOrderSaveReqVO {
public ErpPurchaseOrderSaveReqVO() {
this.items = new ArrayList<>();
}
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17386")
private Long id;
......@@ -29,8 +38,8 @@ public class ErpPurchaseOrderSaveReqVO {
@Schema(description = "优惠率,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "99.88")
private BigDecimal discountPercent;
@Schema(description = "定金金额,单位:", example = "7127")
private BigDecimal depositPrice;
@Schema(description = "定金金额,单位:", example = "7127")
private Integer depositPrice;
@Schema(description = "附件地址", example = "https://www.iocoder.cn")
private String fileUrl;
......@@ -38,6 +47,17 @@ public class ErpPurchaseOrderSaveReqVO {
@Schema(description = "备注", example = "你猜")
private String remark;
@Schema(description = "客户订单id")
private Long customerOrderId;
/**
* 发货状态
*
* 枚举 {@link ErpDeliveryStatus}
*/
@Schema(description = "发货状态")
private String deliveryStatus;
@Schema(description = "订单清单列表")
private List<Item> items;
......@@ -47,20 +67,22 @@ public class ErpPurchaseOrderSaveReqVO {
@Schema(description = "订单项编号", example = "11756")
private Long id;
@Schema(description = "客户订单id")
private Long customerOrderId;
@Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113")
@NotNull(message = "产品编号不能为空")
private Long productId;
@Schema(description = "产品单位单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113")
@NotNull(message = "产品单位单位不能为空")
private Long productUnitId;
private String productUnit;
@Schema(description = "产品单价", example = "100.00")
private BigDecimal productPrice;
private Integer productPrice;
@Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
@NotNull(message = "产品数量不能为空")
private BigDecimal count;
private Integer count;
@Schema(description = "税率,百分比", example = "99.88")
private BigDecimal taxPercent;
......@@ -70,4 +92,7 @@ public class ErpPurchaseOrderSaveReqVO {
}
public void put(Item item) {
this.getItems().add(item);
}
}
\ No newline at end of file
......@@ -67,7 +67,7 @@ public class ErpPurchaseReturnRespVO {
@Schema(description = "优惠金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127")
private BigDecimal discountPrice;
@Schema(description = "定金金额,单位:", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127")
@Schema(description = "定金金额,单位:", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127")
private BigDecimal otherPrice;
@Schema(description = "附件地址", example = "https://www.iocoder.cn")
......
......@@ -64,7 +64,7 @@ public class ErpSaleOrderRespVO {
private BigDecimal discountPrice;
@Schema(description = "定金金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127")
private BigDecimal depositPrice;
private Integer depositPrice;
@Schema(description = "附件地址", example = "https://www.iocoder.cn")
@ExcelProperty("附件地址")
......
......@@ -33,7 +33,7 @@ public class ErpSaleOrderSaveReqVO {
private BigDecimal discountPercent;
@Schema(description = "定金金额,单位:元", example = "7127")
private BigDecimal depositPrice;
private Integer depositPrice;
@Schema(description = "附件地址", example = "https://www.iocoder.cn")
private String fileUrl;
......
package cn.iocoder.foodnexus.module.erp.controller.app;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.foodnexus.framework.common.enums.UserSystemEnum;
import cn.iocoder.foodnexus.framework.common.pojo.CommonResult;
import cn.iocoder.foodnexus.framework.common.pojo.PageResult;
import cn.iocoder.foodnexus.framework.common.util.collection.MapUtils;
import cn.iocoder.foodnexus.framework.common.util.object.BeanUtils;
import cn.iocoder.foodnexus.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.foodnexus.module.erp.api.enums.ErpDeliveryStatus;
import cn.iocoder.foodnexus.module.erp.api.service.ErpSupplierApi;
import cn.iocoder.foodnexus.module.erp.controller.admin.purchase.vo.order.ErpPurchaseOrderPageReqVO;
import cn.iocoder.foodnexus.module.erp.controller.admin.purchase.vo.order.ErpPurchaseOrderRespVO;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.purchase.ErpPurchaseOrderDO;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.purchase.ErpPurchaseOrderItemDO;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.purchase.ErpSupplierDO;
import cn.iocoder.foodnexus.module.erp.service.purchase.ErpPurchaseOrderService;
import cn.iocoder.foodnexus.module.erp.service.purchase.ErpSupplierService;
import cn.iocoder.foodnexus.module.erp.service.stock.ErpStockService;
import cn.iocoder.foodnexus.module.order.enums.CustomerOrderStatus;
import cn.iocoder.foodnexus.module.system.annotations.AppSystemAuth;
import cn.iocoder.foodnexus.module.system.api.user.AdminUserApi;
import cn.iocoder.foodnexus.module.system.api.user.dto.AdminUserRespDTO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import static cn.iocoder.foodnexus.framework.common.pojo.CommonResult.success;
import static cn.iocoder.foodnexus.framework.common.util.collection.CollectionUtils.convertMultiMap;
import static cn.iocoder.foodnexus.framework.common.util.collection.CollectionUtils.convertSet;
/**
* @author : yanghao
* create at: 2025/9/23 11:11
* @description: 采购订单
*/
@Tag(name = "管理后台 - ERP 采购订单")
@RestController
@RequestMapping("/supplier/purchase-order")
@Validated
@AppSystemAuth(UserSystemEnum.SUPPLIER)
public class AppPurchaseOrderController {
@Resource
private ErpPurchaseOrderService purchaseOrderService;
@Resource
private ErpStockService stockService;
@Resource
private ErpSupplierService supplierService;
@Resource
private AdminUserApi adminUserApi;
@Autowired
private ErpSupplierApi supplierApi;
@GetMapping("/get")
@Operation(summary = "获得采购订单")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
public CommonResult<ErpPurchaseOrderRespVO> getPurchaseOrder(@RequestParam("id") Long id) {
ErpPurchaseOrderDO purchaseOrder = purchaseOrderService.getPurchaseOrder(id);
if (purchaseOrder == null) {
return success(null);
}
List<ErpPurchaseOrderItemDO> purchaseOrderItemList = purchaseOrderService.getPurchaseOrderItemListByOrderId(id);
/*Map<Long, ErpProductRespVO> productMap = productService.getProductVOMap(
convertSet(purchaseOrderItemList, ErpPurchaseOrderItemDO::getProductId));*/
return success(BeanUtils.toBean(purchaseOrder, ErpPurchaseOrderRespVO.class, purchaseOrderVO ->
purchaseOrderVO.setItems(BeanUtils.toBean(purchaseOrderItemList, ErpPurchaseOrderRespVO.Item.class, item -> {
BigDecimal purchaseCount = stockService.getStockCount(item.getProductId());
item.setStockCount(purchaseCount != null ? purchaseCount : BigDecimal.ZERO);
/*MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName())
.setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName()));*/
}))));
}
@GetMapping("/page")
@Operation(summary = "获得采购订单分页")
public CommonResult<PageResult<ErpPurchaseOrderRespVO>> getPurchaseOrderPage(@Valid ErpPurchaseOrderPageReqVO pageReqVO) {
pageReqVO.setSupplierId(supplierApi.querySupplierIdByUserId(SecurityFrameworkUtils.getLoginUserId()));
PageResult<ErpPurchaseOrderDO> pageResult = purchaseOrderService.getPurchaseOrderPage(pageReqVO);
return success(buildPurchaseOrderVOPageResult(pageResult));
}
@PostMapping("/accepting-orders")
@Operation(summary = "接单")
@Parameter(name = "ids", description = "编号", required = true)
public CommonResult<Boolean> acceptingOrders(@RequestParam("ids") List<Long> ids) {
purchaseOrderService.delivery(ids, supplierApi.querySupplierIdByUserId(SecurityFrameworkUtils.getLoginUserId()),
ErpDeliveryStatus.MATCHED, ErpDeliveryStatus.NOT_YET, CustomerOrderStatus.SUPPLIER_ACCEPT_ORDER);
return success(Boolean.TRUE);
}
@PostMapping("/delivery")
@Operation(summary = "发货")
@Parameter(name = "ids", description = "编号", required = true)
public CommonResult<Boolean> purchaseOrderDelivery(@RequestParam("ids") List<Long> ids) {
purchaseOrderService.delivery(ids, supplierApi.querySupplierIdByUserId(SecurityFrameworkUtils.getLoginUserId()),
ErpDeliveryStatus.NOT_YET, ErpDeliveryStatus.ALREADY, CustomerOrderStatus.SUPPLIER_SHIP);
return success(Boolean.TRUE);
}
private PageResult<ErpPurchaseOrderRespVO> buildPurchaseOrderVOPageResult(PageResult<ErpPurchaseOrderDO> pageResult) {
if (CollUtil.isEmpty(pageResult.getList())) {
return PageResult.empty(pageResult.getTotal());
}
// 1.1 订单项
List<ErpPurchaseOrderItemDO> purchaseOrderItemList = purchaseOrderService.getPurchaseOrderItemListByOrderIds(
convertSet(pageResult.getList(), ErpPurchaseOrderDO::getId));
Map<Long, List<ErpPurchaseOrderItemDO>> purchaseOrderItemMap = convertMultiMap(purchaseOrderItemList, ErpPurchaseOrderItemDO::getOrderId);
// 1.2 产品信息
/*Map<Long, ErpProductRespVO> productMap = productService.getProductVOMap(
convertSet(purchaseOrderItemList, ErpPurchaseOrderItemDO::getProductId));*/
// 1.3 供应商信息
Map<Long, ErpSupplierDO> supplierMap = supplierService.getSupplierMap(
convertSet(pageResult.getList(), ErpPurchaseOrderDO::getSupplierId));
// 1.4 管理员信息
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
convertSet(pageResult.getList(), purchaseOrder -> Long.parseLong(purchaseOrder.getCreator())));
// 2. 开始拼接
return BeanUtils.toBean(pageResult, ErpPurchaseOrderRespVO.class, purchaseOrder -> {
purchaseOrder.setItems(BeanUtils.toBean(purchaseOrderItemMap.get(purchaseOrder.getId()), ErpPurchaseOrderRespVO.Item.class
/*,
item -> MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName())
.setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName()))*/));
purchaseOrder.setProductNames(CollUtil.join(purchaseOrder.getItems(), ",", ErpPurchaseOrderRespVO.Item::getProductName));
MapUtils.findAndThen(supplierMap, purchaseOrder.getSupplierId(), supplier -> purchaseOrder.setSupplierName(supplier.getName()));
MapUtils.findAndThen(userMap, Long.parseLong(purchaseOrder.getCreator()), user -> purchaseOrder.setCreatorName(user.getNickname()));
});
}
}
......@@ -2,6 +2,7 @@ package cn.iocoder.foodnexus.module.erp.dal.dataobject.purchase;
import cn.iocoder.foodnexus.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.foodnexus.module.erp.api.enums.ErpAuditStatus;
import cn.iocoder.foodnexus.module.erp.api.enums.ErpDeliveryStatus;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.finance.ErpAccountDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
......@@ -61,36 +62,36 @@ public class ErpPurchaseOrderDO extends BaseDO {
/**
* 合计数量
*/
private BigDecimal totalCount;
private Integer totalCount;
/**
* 最终合计价格,单位:
* 最终合计价格,单位:
*
* totalPrice = totalProductPrice + totalTaxPrice - discountPrice
*/
private BigDecimal totalPrice;
private Integer totalPrice;
/**
* 合计产品价格,单位:
* 合计产品价格,单位:
*/
private BigDecimal totalProductPrice;
private Integer totalProductPrice;
/**
* 合计税额,单位:
* 合计税额,单位:
*/
private BigDecimal totalTaxPrice;
private Integer totalTaxPrice;
/**
* 优惠率,百分比
*/
private BigDecimal discountPercent;
private Integer discountPercent;
/**
* 优惠金额,单位:
* 优惠金额,单位:
*
* discountPrice = (totalProductPrice + totalTaxPrice) * discountPercent
*/
private BigDecimal discountPrice;
private Integer discountPrice;
/**
* 定金金额,单位:
* 定金金额,单位:
*/
private BigDecimal depositPrice;
private Integer depositPrice;
/**
* 附件地址
......@@ -113,4 +114,17 @@ public class ErpPurchaseOrderDO extends BaseDO {
*/
private BigDecimal returnCount;
/**
* 客户订单id
*/
private Long customerOrderId;
/**
* 发货状态
*
* 枚举 {@link ErpDeliveryStatus}
*/
private String deliveryStatus;
}
\ No newline at end of file
......@@ -44,34 +44,33 @@ public class ErpPurchaseOrderItemDO extends BaseDO {
/**
* 产品单位单位
*
* 冗余 {@link ErpProductDO#getUnitId()}
*/
private Long productUnitId;
private String productUnit;
/**
* 产品单位单价,单位:
* 产品单位单价,单位:
*/
private BigDecimal productPrice;
private Integer productPrice;
/**
* 数量
*/
private BigDecimal count;
private Integer count;
/**
* 总价,单位:元
*
* totalPrice = productPrice * count
*/
private BigDecimal totalPrice;
private Integer totalPrice;
/**
* 税率,百分比
*/
private BigDecimal taxPercent;
/**
* 税额,单位:
* 税额,单位:
*
* taxPrice = totalPrice * taxPercent
*/
private BigDecimal taxPrice;
private Integer taxPrice;
/**
* 备注
......@@ -90,4 +89,12 @@ public class ErpPurchaseOrderItemDO extends BaseDO {
*/
private BigDecimal returnCount;
/**
* 客户订单id
*/
private Long customerId;
}
\ No newline at end of file
......@@ -96,7 +96,7 @@ public class ErpSaleOrderDO extends BaseDO {
/**
* 定金金额,单位:元
*/
private BigDecimal depositPrice;
private Integer depositPrice;
/**
* 附件地址
......
......@@ -28,6 +28,7 @@ public interface ErrorCodeConstants {
ErrorCode PURCHASE_ORDER_PROCESS_FAIL_EXISTS_IN = new ErrorCode(1_030_101_008, "反审核失败,已存在对应的采购入库单");
ErrorCode PURCHASE_ORDER_ITEM_RETURN_FAIL_IN_EXCEED = new ErrorCode(1_030_101_009, "采购订单项({})超过最大允许退货数量({})");
ErrorCode PURCHASE_ORDER_PROCESS_FAIL_EXISTS_RETURN = new ErrorCode(1_030_101_010, "反审核失败,已存在对应的采购退货单");
ErrorCode PURCHASE_DELIVERY_STATUS_ERROR = new ErrorCode(1_030_101_011, "采购订单发货状态异常");
// ========== ERP 采购入库(1-030-102-000) ==========
ErrorCode PURCHASE_IN_NOT_EXISTS = new ErrorCode(1_030_102_000, "采购入库单不存在");
......
package cn.iocoder.foodnexus.module.erp.service.purchase;
import cn.iocoder.foodnexus.framework.common.pojo.PageResult;
import cn.iocoder.foodnexus.module.erp.api.enums.ErpDeliveryStatus;
import cn.iocoder.foodnexus.module.erp.controller.admin.purchase.vo.order.ErpPurchaseOrderPageReqVO;
import cn.iocoder.foodnexus.module.erp.controller.admin.purchase.vo.order.ErpPurchaseOrderSaveReqVO;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.purchase.ErpPurchaseOrderDO;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.purchase.ErpPurchaseOrderItemDO;
import cn.iocoder.foodnexus.module.order.enums.CustomerOrderStatus;
import jakarta.validation.Valid;
import java.math.BigDecimal;
......@@ -107,4 +109,11 @@ public interface ErpPurchaseOrderService {
*/
List<ErpPurchaseOrderItemDO> getPurchaseOrderItemListByOrderIds(Collection<Long> orderIds);
/**
* 发货
* @param ids
* @param supplierId
*/
void delivery(List<Long> ids, Long supplierId, ErpDeliveryStatus oriStatus, ErpDeliveryStatus updateStatus, CustomerOrderStatus updateOrderStatus);
}
\ No newline at end of file
......@@ -3,8 +3,11 @@ package cn.iocoder.foodnexus.module.erp.service.purchase;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.foodnexus.framework.common.pojo.PageResult;
import cn.iocoder.foodnexus.framework.common.util.CommonUtil;
import cn.iocoder.foodnexus.framework.common.util.number.MoneyUtils;
import cn.iocoder.foodnexus.framework.common.util.object.BeanUtils;
import cn.iocoder.foodnexus.module.erp.api.PurchaseOrderSplitEvent;
import cn.iocoder.foodnexus.module.erp.api.enums.ErpDeliveryStatus;
import cn.iocoder.foodnexus.module.erp.controller.admin.purchase.vo.order.ErpPurchaseOrderPageReqVO;
import cn.iocoder.foodnexus.module.erp.controller.admin.purchase.vo.order.ErpPurchaseOrderSaveReqVO;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.product.ErpProductDO;
......@@ -14,18 +17,28 @@ import cn.iocoder.foodnexus.module.erp.dal.mysql.purchase.ErpPurchaseOrderItemMa
import cn.iocoder.foodnexus.module.erp.dal.mysql.purchase.ErpPurchaseOrderMapper;
import cn.iocoder.foodnexus.module.erp.dal.redis.no.ErpNoRedisDAO;
import cn.iocoder.foodnexus.module.erp.api.enums.ErpAuditStatus;
import cn.iocoder.foodnexus.module.erp.enums.ErrorCodeConstants;
import cn.iocoder.foodnexus.module.erp.service.finance.ErpAccountService;
import cn.iocoder.foodnexus.module.erp.service.product.ErpProductService;
import cn.iocoder.foodnexus.module.order.api.CustomerOrderApi;
import cn.iocoder.foodnexus.module.order.api.CustomerOrderRecordApi;
import cn.iocoder.foodnexus.module.order.dto.CustomerOrderDTO;
import cn.iocoder.foodnexus.module.order.dto.CustomerOrderItemDTO;
import cn.iocoder.foodnexus.module.order.dto.CustomerOrderRecordEvent;
import cn.iocoder.foodnexus.module.order.enums.CustomerOrderStatus;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;
import org.springframework.validation.annotation.Validated;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.*;
import static cn.iocoder.foodnexus.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.foodnexus.framework.common.util.collection.CollectionUtils.*;
......@@ -40,6 +53,7 @@ import static cn.iocoder.foodnexus.module.erp.enums.ErrorCodeConstants.*;
*/
@Service
@Validated
@Slf4j
public class ErpPurchaseOrderServiceImpl implements ErpPurchaseOrderService {
@Resource
......@@ -51,12 +65,16 @@ public class ErpPurchaseOrderServiceImpl implements ErpPurchaseOrderService {
private ErpNoRedisDAO noRedisDAO;
@Resource
private ErpProductService productService;
@Resource
private ErpSupplierService supplierService;
@Resource
private ErpAccountService accountService;
@Autowired
private CustomerOrderApi customerOrderApi;
@Autowired
private CustomerOrderRecordApi orderRecordApi;
@Override
@Transactional(rollbackFor = Exception.class)
public Long createPurchaseOrder(ErpPurchaseOrderSaveReqVO createReqVO) {
......@@ -111,16 +129,16 @@ public class ErpPurchaseOrderServiceImpl implements ErpPurchaseOrderService {
}
private void calculateTotalPrice(ErpPurchaseOrderDO purchaseOrder, List<ErpPurchaseOrderItemDO> purchaseOrderItems) {
purchaseOrder.setTotalCount(getSumValue(purchaseOrderItems, ErpPurchaseOrderItemDO::getCount, BigDecimal::add));
purchaseOrder.setTotalProductPrice(getSumValue(purchaseOrderItems, ErpPurchaseOrderItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO));
purchaseOrder.setTotalTaxPrice(getSumValue(purchaseOrderItems, ErpPurchaseOrderItemDO::getTaxPrice, BigDecimal::add, BigDecimal.ZERO));
purchaseOrder.setTotalPrice(purchaseOrder.getTotalProductPrice().add(purchaseOrder.getTotalTaxPrice()));
purchaseOrder.setTotalCount(getSumValue(purchaseOrderItems, ErpPurchaseOrderItemDO::getCount, Integer::sum));
purchaseOrder.setTotalProductPrice(getSumValue(purchaseOrderItems, ErpPurchaseOrderItemDO::getTotalPrice, Integer::sum, 0));
purchaseOrder.setTotalTaxPrice(getSumValue(purchaseOrderItems, ErpPurchaseOrderItemDO::getTaxPrice, Integer::sum, 0));
purchaseOrder.setTotalPrice(purchaseOrder.getTotalProductPrice() + (purchaseOrder.getTotalTaxPrice()));
// 计算优惠价格
if (purchaseOrder.getDiscountPercent() == null) {
purchaseOrder.setDiscountPercent(BigDecimal.ZERO);
purchaseOrder.setDiscountPercent(0);
}
purchaseOrder.setDiscountPrice(MoneyUtils.priceMultiplyPercent(purchaseOrder.getTotalPrice(), purchaseOrder.getDiscountPercent()));
purchaseOrder.setTotalPrice(purchaseOrder.getTotalPrice().subtract(purchaseOrder.getDiscountPrice()));
// purchaseOrder.setDiscountPrice(MoneyUtils.priceMultiplyPercent(purchaseOrder.getTotalPrice(), purchaseOrder.getDiscountPercent()));
purchaseOrder.setTotalPrice(purchaseOrder.getTotalPrice()/*.subtract(purchaseOrder.getDiscountPrice())*/);
}
@Override
......@@ -152,18 +170,17 @@ public class ErpPurchaseOrderServiceImpl implements ErpPurchaseOrderService {
private List<ErpPurchaseOrderItemDO> validatePurchaseOrderItems(List<ErpPurchaseOrderSaveReqVO.Item> list) {
// 1. 校验产品存在
List<ErpProductDO> productList = productService.validProductList(
/*List<ErpProductDO> productList = productService.validProductList(
convertSet(list, ErpPurchaseOrderSaveReqVO.Item::getProductId));
Map<Long, ErpProductDO> productMap = convertMap(productList, ErpProductDO::getId);
Map<Long, ErpProductDO> productMap = convertMap(productList, ErpProductDO::getId);*/
// 2. 转化为 ErpPurchaseOrderItemDO 列表
return convertList(list, o -> BeanUtils.toBean(o, ErpPurchaseOrderItemDO.class, item -> {
item.setProductUnitId(productMap.get(item.getProductId()).getUnitId());
item.setTotalPrice(MoneyUtils.priceMultiply(item.getProductPrice(), item.getCount()));
item.setTotalPrice((item.getProductPrice() * item.getCount()));
if (item.getTotalPrice() == null) {
return;
}
if (item.getTaxPercent() != null) {
item.setTaxPrice(MoneyUtils.priceMultiplyPercent(item.getTotalPrice(), item.getTaxPercent()));
// item.setTaxPrice(MoneyUtils.priceMultiplyPercent(item.getTotalPrice(), item.getTaxPercent()));
}
}));
}
......@@ -196,10 +213,10 @@ public class ErpPurchaseOrderServiceImpl implements ErpPurchaseOrderService {
if (item.getInCount().equals(inCount)) {
return;
}
if (inCount.compareTo(item.getCount()) > 0) {
/*if (inCount.compareTo(BigDecimal.valueOf(item.getCount())) > 0) {
throw exception(PURCHASE_ORDER_ITEM_IN_FAIL_PRODUCT_EXCEED,
productService.getProduct(item.getProductId()).getName(), item.getCount());
}
}*/
purchaseOrderItemMapper.updateById(new ErpPurchaseOrderItemDO().setId(item.getId()).setInCount(inCount));
});
// 2. 更新采购订单
......@@ -216,10 +233,10 @@ public class ErpPurchaseOrderServiceImpl implements ErpPurchaseOrderService {
if (item.getReturnCount().equals(returnCount)) {
return;
}
if (returnCount.compareTo(item.getInCount()) > 0) {
/*if (returnCount.compareTo(item.getInCount()) > 0) {
throw exception(PURCHASE_ORDER_ITEM_RETURN_FAIL_IN_EXCEED,
productService.getProduct(item.getProductId()).getName(), item.getInCount());
}
}*/
purchaseOrderItemMapper.updateById(new ErpPurchaseOrderItemDO().setId(item.getId()).setReturnCount(returnCount));
});
// 2. 更新采购订单
......@@ -292,4 +309,85 @@ public class ErpPurchaseOrderServiceImpl implements ErpPurchaseOrderService {
return purchaseOrderItemMapper.selectListByOrderIds(orderIds);
}
/**
* 发货/接单
*
* @param ids
* @param supplierId
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void delivery(List<Long> ids, Long supplierId, ErpDeliveryStatus oriStatus, ErpDeliveryStatus updateStatus, CustomerOrderStatus updateOrderStatus) {
List<ErpPurchaseOrderDO> orderList = purchaseOrderMapper.selectList(Wrappers.<ErpPurchaseOrderDO>lambdaQuery()
.in(ErpPurchaseOrderDO::getId, ids)
.eq(ErpPurchaseOrderDO::getSupplierId, supplierId));
if (CommonUtil.isEmpty(orderList)) {
throw exception(PURCHASE_ORDER_NOT_EXISTS);
}
Set<Long> customerOrderSet = new HashSet<>();
for (ErpPurchaseOrderDO item : orderList) {
if (!oriStatus.getStatus().equals(item.getDeliveryStatus())) {
throw exception(PURCHASE_DELIVERY_STATUS_ERROR);
}
CustomerOrderDTO customerOrder = customerOrderApi.queryById(item.getCustomerOrderId());
if (CommonUtil.isEmpty(customerOrder)) {
throw exception("订单不存在");
}
if (!customerOrderSet.contains(item.getCustomerOrderId())) {
customerOrderApi.updateOrderStatus(item.getCustomerOrderId(), updateOrderStatus);
// 添加订单进度记录
CustomerOrderRecordEvent event = new CustomerOrderRecordEvent();
event.setOrderStatus(updateOrderStatus);
event.setCustomerOrderId(item.getCustomerOrderId());
event.setSupplierId(supplierId);
event.setCopyWriter(CommonUtil.asList(supplierService.getSupplier(supplierId).getName()));
orderRecordApi.recordEvent(event);
customerOrderSet.add(item.getCustomerOrderId());
}
}
purchaseOrderMapper.update(Wrappers.<ErpPurchaseOrderDO>lambdaUpdate()
.set(ErpPurchaseOrderDO::getDeliveryStatus, updateStatus)
.in(ErpPurchaseOrderDO::getId, ids));
}
@Async
@TransactionalEventListener(classes = PurchaseOrderSplitEvent.class, phase = TransactionPhase.AFTER_COMMIT)
public void orderSplit(PurchaseOrderSplitEvent event) {
log.warn("采购订单拆分:{}", event);
Long orderId = event.getCustomerOrderId();
CustomerOrderDTO customerOrderDTO = customerOrderApi.queryById(orderId);
List<CustomerOrderItemDTO> customerOrderItemDTOS = customerOrderApi.queryItemsByOrderId(orderId);
if (CommonUtil.isEmpty(customerOrderItemDTOS) || CommonUtil.isEmpty(customerOrderDTO)) {
return ;
}
Map<Long, List<CustomerOrderItemDTO>> supplierMap = CommonUtil.listConvertListMap(customerOrderItemDTOS, CustomerOrderItemDTO::getSupplierId);
for (Map.Entry<Long, List<CustomerOrderItemDTO>> entry : supplierMap.entrySet()) {
Long supplierId = entry.getKey();
List<CustomerOrderItemDTO> list = entry.getValue();
ErpPurchaseOrderSaveReqVO purchaseOrder = new ErpPurchaseOrderSaveReqVO();
purchaseOrder.setSupplierId(supplierId);
purchaseOrder.setOrderTime(customerOrderDTO.getCreateTime());
purchaseOrder.setDepositPrice(list.stream().mapToInt(CustomerOrderItemDTO::getOrderItemTotal).sum());
purchaseOrder.setCustomerOrderId(orderId);
purchaseOrder.setDeliveryStatus(ErpDeliveryStatus.MATCHED.getStatus());
for (CustomerOrderItemDTO customerOrderItem : list) {
ErpPurchaseOrderSaveReqVO.Item purhcaseOrderItem = new ErpPurchaseOrderSaveReqVO.Item();
purhcaseOrderItem.setProductId(customerOrderItem.getProductId());
purhcaseOrderItem.setProductUnit(customerOrderItem.getProductInfo().getUnitName());
purhcaseOrderItem.setProductPrice(customerOrderItem.getOrderItemPrice());
purhcaseOrderItem.setCount(customerOrderItem.getOrderItemQuantity());
purhcaseOrderItem.setCustomerOrderId(orderId);
purchaseOrder.put(purhcaseOrderItem);
}
this.createPurchaseOrder(purchaseOrder);
}
}
}
......@@ -3,8 +3,10 @@ package cn.iocoder.foodnexus.module.erp.service.stock;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.foodnexus.framework.common.enums.CommonStatusEnum;
import cn.iocoder.foodnexus.framework.common.pojo.PageResult;
import cn.iocoder.foodnexus.framework.common.util.CommonUtil;
import cn.iocoder.foodnexus.framework.common.util.object.BeanUtils;
import cn.iocoder.foodnexus.module.erp.api.service.ErpWarehouseApi;
import cn.iocoder.foodnexus.module.erp.api.vo.warehouse.WarehouseInfo;
import cn.iocoder.foodnexus.module.erp.controller.admin.stock.vo.warehouse.ErpWarehouseSaveReqVO;
import cn.iocoder.foodnexus.module.erp.controller.admin.stock.vo.warehouse.ErpWarehousePageReqVO;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.stock.ErpWarehouseDO;
......@@ -127,6 +129,21 @@ public class ErpWarehouseServiceImpl implements ErpWarehouseService, ErpWarehous
@Override
public boolean existsById(Long warehouseId) {
return warehouseMapper.exists(Wrappers.<ErpWarehouseDO>lambdaQuery()
.eq(ErpWarehouseDO::getId, warehouseId));
.eq(ErpWarehouseDO::getId, warehouseId)
.eq(ErpWarehouseDO::getStatus, CommonStatusEnum.ENABLE.getStatus()));
}
@Override
public WarehouseInfo getInfoByWarehouseAreaId(Long warehouseAreaId) {
ErpWarehouseDO erpWarehouseDO = warehouseMapper.selectOne(Wrappers.<ErpWarehouseDO>lambdaQuery()
.eq(ErpWarehouseDO::getId, warehouseAreaId)
.eq(ErpWarehouseDO::getStatus, CommonStatusEnum.ENABLE.getStatus()));
if (CommonUtil.isNotEmpty(erpWarehouseDO)) {
WarehouseInfo info = BeanUtils.toBean(erpWarehouseDO, WarehouseInfo.class);
info.setWarehouseId(erpWarehouseDO.getParentId());
info.setWarehouseId(erpWarehouseDO.getId());
return info;
}
return null;
}
}
......@@ -71,10 +71,9 @@ public class DeliveryStaffController {
@PutMapping("bind-customer-release")
@Operation(summary = "配送员解绑客户")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('operation:delivery-staff:update')")
public CommonResult<Boolean> bindCustomerRelease(@RequestParam("id") Long id) {
deliveryStaffService.bindCustomerRelease(id);
public CommonResult<Boolean> bindCustomerRelease(@Valid @RequestBody DeliveryStaffBindCustomerReqVO updateReqVO) {
deliveryStaffService.bindCustomerRelease(updateReqVO);
return success(true);
}
......
package cn.iocoder.foodnexus.module.operations.controller.admin.deliverystaff.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
import java.util.List;
......@@ -13,9 +15,12 @@ import java.util.List;
@Data
public class DeliveryStaffBindCustomerReqVO {
@Schema(description = "配送员id")
@NotNull(message = "配送员不能为空")
private Long staffId;
@Schema(description = "客户id集合")
@NotNull(message = "客户id不能为空")
private List<Long> customerIdList;
}
......@@ -61,5 +61,5 @@ public interface DeliveryStaffService {
void bindCustomer(DeliveryStaffBindCustomerReqVO updateReqVO);
void bindCustomerRelease(Long id);
void bindCustomerRelease(DeliveryStaffBindCustomerReqVO updateReqVO);
}
\ No newline at end of file
......@@ -5,6 +5,7 @@ import cn.hutool.core.stream.StreamUtil;
import cn.iocoder.foodnexus.framework.common.util.CommonUtil;
import cn.iocoder.foodnexus.module.operations.dal.dataobject.deliverystaffcustomer.DeliveryStaffCustomerDO;
import cn.iocoder.foodnexus.module.operations.dal.mysql.deliverystaffcustomer.DeliveryStaffCustomerMapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
......@@ -105,9 +106,11 @@ public class DeliveryStaffServiceImpl implements DeliveryStaffService {
}
@Override
public void bindCustomerRelease(Long id) {
validateDeliveryStaffExists(id);
deliveryStaffCustomerMapper.delete(DeliveryStaffCustomerDO::getDeliveryStaffId, id);
public void bindCustomerRelease(DeliveryStaffBindCustomerReqVO updateReqVO) {
validateDeliveryStaffExists(updateReqVO.getStaffId());
deliveryStaffCustomerMapper.delete(Wrappers.<DeliveryStaffCustomerDO>lambdaQuery()
.eq(DeliveryStaffCustomerDO::getDeliveryStaffId, updateReqVO.getStaffId())
.in(DeliveryStaffCustomerDO::getCustomerId, updateReqVO.getCustomerIdList()));
}
}
\ No newline at end of file
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.iocoder.boot</groupId>
<artifactId>foodnexus-module-mall</artifactId>
<version>${revision}</version>
</parent>
<artifactId>foodnexus-module-order-api</artifactId>
<name>${project.artifactId}</name>
<packaging>jar</packaging>
<description>
客户订单api
</description>
<dependencies>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>foodnexus-common</artifactId>
</dependency>
<!-- 参数校验 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>foodnexus-module-erp-api</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>foodnexus-module-product-api</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
</project>
package cn.iocoder.foodnexus.module.order.api;
import cn.iocoder.foodnexus.module.order.dto.CustomerOrderDTO;
import cn.iocoder.foodnexus.module.order.dto.CustomerOrderItemDTO;
import cn.iocoder.foodnexus.module.order.enums.CustomerOrderStatus;
import java.util.List;
/**
* @author : yanghao
* create at: 2025/9/22 15:31
* @description: 客户订单
*/
public interface CustomerOrderApi {
CustomerOrderDTO queryById(Long customerOrderId);
List<CustomerOrderItemDTO> queryItemsByOrderId(Long customerOrderId);
void updateOrderStatus(Long customerOrderId, CustomerOrderStatus updateOrderStatus);
}
package cn.iocoder.foodnexus.module.order.api;
import cn.iocoder.foodnexus.module.order.dto.CustomerOrderRecordEvent;
/**
* @author : yanghao
* create at: 2025/9/23 15:44
* @description: 客户订单进度记录
*/
public interface CustomerOrderRecordApi {
void recordEvent(CustomerOrderRecordEvent event);
}
package cn.iocoder.foodnexus.module.order.dto;
import cn.iocoder.foodnexus.module.erp.api.vo.warehouse.WarehouseInfo;
import cn.iocoder.foodnexus.module.order.enums.CustomerOrderStatus;
import cn.iocoder.foodnexus.module.order.enums.DeliveryMode;
import lombok.Data;
import java.time.LocalDateTime;
/**
* @author : yanghao
* create at: 2025/9/22 15:32
* @description: 客户信息
*/
@Data
public class CustomerOrderDTO {
/**
* id
*/
private Long id;
/**
* 订单编号
*/
private String code;
/**
* 订单状态
*
* 枚举 {@link CustomerOrderStatus}
*/
private CustomerOrderStatus orderStatus;
/**
* 客户id
*/
private Long customerId;
/**
* 收获仓库id
*/
private Long warehouseId;
/**
* 收获库区id
*/
private Long warehouseAreaId;
/**
* 仓库信息
*/
private WarehouseInfo warehouseInfo;
/**
* 配送模式
*
* 枚举 {@link DeliveryMode}
*/
private DeliveryMode deliveryMode;
/**
* 采购订单数
*/
private Integer productCount;
/**
* 供应商数
*/
private Integer supplierCount;
/**
* 预计配送开始时间
*/
private LocalDateTime planDeliveryStartTime;
/**
* 预计配送结束时间
*/
private LocalDateTime planDeliveryEndTime;
/**
* 订单总金额(分)
*/
private Integer orderAmount;
/**
* 实际支付总金额(分)
*/
private Integer actualAmount;
/**
* 配送公司
*/
private String operCompany;
/**
* 创建时间
*/
private LocalDateTime createTime;
private String creator;
}
package cn.iocoder.foodnexus.module.order.dto;
import cn.iocoder.foodnexus.module.product.api.dto.ProductInfo;
import lombok.Data;
/**
* @author : yanghao
* create at: 2025/9/22 15:36
* @description: 客户子订单
*/
@Data
public class CustomerOrderItemDTO {
/**
* id
*/
private Long id;
/**
* 客户订单id
*/
private Long orderId;
/**
* 客户id
*/
private Long customerId;
/**
* 商品id
*/
private Long productId;
/**
* 商品名称
*/
private String productName;
/**
* 商品信息
*/
private ProductInfo productInfo;
/**
* 商品对应供应商id
*/
private Long supplierId;
/**
* 供应商名称
*/
private String supplierName;
/**
* 订单商品单价,单位:分
*/
private Integer orderItemPrice;
/**
* 订单商品总价,单位:分
*/
private Integer orderItemTotal;
/**
* 订单商品数量
*/
private Integer orderItemQuantity;
/**
* 签收数量
*/
private Integer signedQuantity;
/**
* 签收总价,单位:分
*/
private Integer signedTotal;
}
package cn.iocoder.foodnexus.module.order.dto;
import cn.iocoder.foodnexus.module.order.enums.CustomerOrderStatus;
import lombok.Data;
import java.util.List;
/**
* @author : yanghao
* create at: 2025/9/23 16:26
* @description: 客户订单记录事件
*/
@Data
public class CustomerOrderRecordEvent {
private CustomerOrderStatus orderStatus;
private Long customerOrderId;
private Long supplierId;
private List<String> copyWriter;
}
package cn.iocoder.foodnexus.module.order.enums;
import cn.iocoder.foodnexus.framework.common.core.ArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* @author : yanghao
* create at: 2025/9/5 17:12
* @description: 客户 - 订单 - 状态
*/
@Getter
@AllArgsConstructor
public enum CustomerOrderStatus implements ArrayValuable<String> {
// 下单成功
ORDER_SUCCESS("下单成功", "order_success") {
@Override
public String getText() {
return "您已成功下单\n" +
"订单信息:订单金额:%s元,商品数量:%s件;";
}
},
// 订单匹配
ORDER_MATCH("订单匹配", "order_match") {
@Override
public String getText() {
return "【%s】供应商 匹配成功";
}
},
// 供应商接单
SUPPLIER_ACCEPT_ORDER("供应商接单", "supplier_accept_order") {
@Override
public String getText() {
return "【%s】供应商 已接单";
}
},
// 供应商发货
SUPPLIER_SHIP("供应商发货", "supplier_ship") {
@Override
public String getText() {
return "【%s】供应商 已发货";
}
},
// 供应商到货
SUPPLIER_ARRIVE("供应商到货", "supplier_arrive") {
@Override
public String getText() {
return "【%s】供应商 已到货";
}
},
// 分仓质检
WAREHOUSE_INSPECTION("分仓质检", "warehouseInspection") {
@Override
public String getText() {
return "您的商品已到达【%s】分仓,已完成质检入库;查看质检报告【%s】";
}
},
// 商品分拣
SORTING("商品分拣", "sorting") {
@Override
public String getText() {
return "您的商品在【%s】分仓已完成分拣,【%s】正在进行配送";
}
},
// 商品配送
DELIVERY("商品配送", "delivery") {
@Override
public String getText() {
return "您的商品将在16小时内完成配送,请保持电话畅通,配送员【%s】联系方式:【%s】";
}
},
// 商品到货
ARRIVAL("商品到货", "arrival") {
@Override
public String getText() {
return "您的商品已送到收货地址,请前往签收;配送员【%s】 联系方式:【%s】";
}
},
// 商品签收
SIGN_RECEIPT("商品签收", "signReceipt") {
@Override
public String getText() {
return "您的商品完成签收查看签收单【%s】";
}
},
;
private final String label;
private final String key;
public static final String[] ARRAYS = Arrays.stream(values()).map(CustomerOrderStatus::getKey).toArray(String[]::new);
/**
* @return 数组
*/
@Override
public String[] array() {
return ARRAYS;
}
// 声明抽象方法
public abstract String getText();
}
......@@ -35,5 +35,10 @@
<artifactId>foodnexus-module-operations</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>foodnexus-module-order-api</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
</project>
package cn.iocoder.foodnexus.module.order.controller.admin.customerorder;
import cn.iocoder.foodnexus.module.order.api.CustomerOrderApi;
import cn.iocoder.foodnexus.module.order.controller.admin.customerorderitem.vo.CustomerOrderItemRespVO;
import cn.iocoder.foodnexus.module.order.service.customerorderitem.CustomerOrderItemService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
......@@ -38,22 +42,11 @@ public class CustomerOrderController {
@Resource
private CustomerOrderService customerOrderService;
@PostMapping("/create")
@Operation(summary = "创建客户总订单")
@PreAuthorize("@ss.hasPermission('order:customer-order:create')")
public CommonResult<Long> createCustomerOrder(@Valid @RequestBody CustomerOrderSaveReqVO createReqVO) {
return success(customerOrderService.createCustomerOrder(createReqVO));
}
@Autowired
private CustomerOrderApi customerOrderApi;
@PutMapping("/update")
@Operation(summary = "更新客户总订单")
@PreAuthorize("@ss.hasPermission('order:customer-order:update')")
public CommonResult<Boolean> updateCustomerOrder(@Valid @RequestBody CustomerOrderSaveReqVO updateReqVO) {
customerOrderService.updateCustomerOrder(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
/* @DeleteMapping("/delete")
@Operation(summary = "删除客户总订单")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('order:customer-order:delete')")
......@@ -70,14 +63,16 @@ public class CustomerOrderController {
customerOrderService.deleteCustomerOrderListByIds(ids);
return success(true);
}
*/
@GetMapping("/get")
@Operation(summary = "获得客户总订单")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('order:customer-order:query')")
public CommonResult<CustomerOrderRespVO> getCustomerOrder(@RequestParam("id") Long id) {
public CommonResult<CustomerOrderDetailsVO> getCustomerOrder(@RequestParam("id") Long id) {
CustomerOrderDO customerOrder = customerOrderService.getCustomerOrder(id);
return success(BeanUtils.toBean(customerOrder, CustomerOrderRespVO.class));
return success(BeanUtils.toBean(customerOrder, CustomerOrderDetailsVO.class, item -> item.setOrderItems(
BeanUtils.toBean(customerOrderApi.queryItemsByOrderId(item.getId()), CustomerOrderItemRespVO.class))));
}
@GetMapping("/page")
......
package cn.iocoder.foodnexus.module.order.controller.admin.customerorder.vo;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import cn.iocoder.foodnexus.framework.excel.core.annotations.DictFormat;
import cn.iocoder.foodnexus.framework.excel.core.convert.DictConvert;
import cn.iocoder.foodnexus.module.erp.api.vo.warehouse.WarehouseInfo;
import cn.iocoder.foodnexus.module.order.controller.admin.customerorderitem.vo.CustomerOrderItemRespVO;
import cn.iocoder.foodnexus.module.order.enums.CustomerOrderStatus;
import cn.iocoder.foodnexus.module.order.enums.DeliveryMode;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
@Schema(description = "管理后台 - 客户总订单 Response VO")
@Data
@ExcelIgnoreUnannotated
public class CustomerOrderDetailsVO {
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "19291")
@ExcelProperty("id")
private Long id;
@Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("订单编号")
private String code;
@Schema(description = "订单状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@ExcelProperty(value = "订单状态", converter = DictConvert.class)
@DictFormat("order_customer_order_status") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
private CustomerOrderStatus orderStatus;
@Schema(description = "客户id", requiredMode = Schema.RequiredMode.REQUIRED, example = "20189")
@ExcelProperty("客户id")
private Long customerId;
@Schema(description = "收获仓库id", requiredMode = Schema.RequiredMode.REQUIRED, example = "27065")
@ExcelProperty("收获仓库id")
private Long warehouseId;
@Schema(description = "收获库区id", requiredMode = Schema.RequiredMode.REQUIRED, example = "26507")
@ExcelProperty("收获库区id")
private Long warehouseAreaId;
@Schema(description = "仓库信息")
@ExcelProperty("仓库信息")
private WarehouseInfo warehouseInfo;
@Schema(description = "配送模式", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty(value = "配送模式", converter = DictConvert.class)
@DictFormat("order_delivery_mode") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
private DeliveryMode deliveryMode;
@Schema(description = "采购订单数", requiredMode = Schema.RequiredMode.REQUIRED, example = "12099")
@ExcelProperty("采购订单数")
private Integer productCount;
@Schema(description = "供应商数", example = "8062")
@ExcelProperty("供应商数")
private Integer supplierCount;
@Schema(description = "预计配送开始时间")
@ExcelProperty("预计配送开始时间")
private LocalDateTime planDeliveryStartTime;
@Schema(description = "预计配送结束时间")
@ExcelProperty("预计配送结束时间")
private LocalDateTime planDeliveryEndTime;
@Schema(description = "订单总金额(分)", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("订单总金额(分)")
private Integer orderAmount;
@Schema(description = "实际支付总金额(分)")
@ExcelProperty("实际支付总金额(分)")
private Integer actualAmount;
@Schema(description = "配送公司")
@ExcelProperty("配送公司")
private String operCompany;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
@Schema(description = "子订单")
private List<CustomerOrderItemRespVO> orderItems;
}
\ No newline at end of file
......@@ -6,7 +6,6 @@ import cn.iocoder.foodnexus.module.order.enums.DeliveryMode;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.extension.handlers.Fastjson2TypeHandler;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
import cn.iocoder.foodnexus.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat;
......
......@@ -5,8 +5,7 @@ import cn.iocoder.foodnexus.module.order.enums.CustomerOrderStatus;
import cn.iocoder.foodnexus.module.order.enums.DeliveryMode;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import cn.idev.excel.annotation.*;
import cn.iocoder.foodnexus.framework.excel.core.annotations.DictFormat;
......
......@@ -5,9 +5,8 @@ import cn.iocoder.foodnexus.module.order.enums.CustomerOrderStatus;
import cn.iocoder.foodnexus.module.order.enums.DeliveryMode;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import jakarta.validation.constraints.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 客户总订单新增/修改 Request VO")
......
package cn.iocoder.foodnexus.module.order.controller.admin.customerorderrecord.vo;
import cn.iocoder.foodnexus.module.order.enums.CustomerOrderStatus;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
import cn.iocoder.foodnexus.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.foodnexus.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 客户订单进度记录分页 Request VO")
@Data
public class CustomerOrderRecordPageReqVO extends PageParam {
@Schema(description = "客户订单id", example = "14294")
private Long customerOrderId;
@Schema(description = "订单状态", example = "1")
private CustomerOrderStatus orderStatus;
@Schema(description = "客户id", example = "28995")
private Long customerId;
@Schema(description = "供应商id", example = "8073")
private Long supplierId;
@Schema(description = "信息")
private String messageInfo;
@Schema(description = "扩展信息")
private String extendInfo;
@Schema(description = "创建者")
private String creator;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}
\ No newline at end of file
package cn.iocoder.foodnexus.module.order.controller.admin.customerorderrecord.vo;
import cn.iocoder.foodnexus.module.order.enums.CustomerOrderStatus;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import cn.idev.excel.annotation.*;
import cn.iocoder.foodnexus.framework.excel.core.annotations.DictFormat;
import cn.iocoder.foodnexus.framework.excel.core.convert.DictConvert;
@Schema(description = "管理后台 - 客户订单进度记录 Response VO")
@Data
@ExcelIgnoreUnannotated
public class CustomerOrderRecordRespVO {
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "19592")
@ExcelProperty("id")
private Long id;
@Schema(description = "客户订单id", requiredMode = Schema.RequiredMode.REQUIRED, example = "14294")
@ExcelProperty("客户订单id")
private Long customerOrderId;
@Schema(description = "订单状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@ExcelProperty(value = "订单状态", converter = DictConvert.class)
@DictFormat("order_customer_order_status") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
private CustomerOrderStatus orderStatus;
@Schema(description = "客户id", requiredMode = Schema.RequiredMode.REQUIRED, example = "28995")
@ExcelProperty("客户id")
private Long customerId;
@Schema(description = "供应商id", example = "8073")
@ExcelProperty("供应商id")
private Long supplierId;
@Schema(description = "信息")
@ExcelProperty("信息")
private String messageInfo;
@Schema(description = "扩展信息")
@ExcelProperty("扩展信息")
private String extendInfo;
@Schema(description = "创建者")
@ExcelProperty("创建者")
private String creator;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}
\ No newline at end of file
package cn.iocoder.foodnexus.module.order.controller.admin.customerorderrecord.vo;
import cn.iocoder.foodnexus.module.order.enums.CustomerOrderStatus;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import jakarta.validation.constraints.*;
@Schema(description = "管理后台 - 客户订单进度记录新增/修改 Request VO")
@Data
public class CustomerOrderRecordSaveReqVO {
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "19592")
private Long id;
@Schema(description = "客户订单id", requiredMode = Schema.RequiredMode.REQUIRED, example = "14294")
@NotNull(message = "客户订单id不能为空")
private Long customerOrderId;
@Schema(description = "订单状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotEmpty(message = "订单状态不能为空")
private CustomerOrderStatus orderStatus;
@Schema(description = "客户id", requiredMode = Schema.RequiredMode.REQUIRED, example = "28995")
@NotNull(message = "客户id不能为空")
private Long customerId;
@Schema(description = "供应商id", example = "8073")
private Long supplierId;
@Schema(description = "信息")
private String messageInfo;
@Schema(description = "扩展信息")
private String extendInfo;
}
\ No newline at end of file
......@@ -14,15 +14,10 @@ public class AppCustomerOrderItemSaveReqVO {
@NotNull(message = "商品id不能为空")
private Long productId;
@Schema(description = "商品名称", example = "李四")
private String productName;
@Schema(description = "订单商品单价,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "29922")
@NotNull(message = "订单商品单价,单位:分不能为空")
@Schema(description = "订单商品单价,单位:分", hidden = true)
private Integer orderItemPrice;
@Schema(description = "订单商品总价,单位:分", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "订单商品总价,单位:分不能为空")
@Schema(description = "订单商品总价,单位:分", hidden = true)
private Integer orderItemTotal;
@Schema(description = "订单商品数量", requiredMode = Schema.RequiredMode.REQUIRED)
......
package cn.iocoder.foodnexus.module.order.controller.app.customerOrder.vo;
import cn.iocoder.foodnexus.framework.common.validation.InEnum;
import cn.iocoder.foodnexus.module.erp.api.vo.warehouse.WarehouseInfo;
import cn.iocoder.foodnexus.module.order.enums.CustomerOrderStatus;
import cn.iocoder.foodnexus.module.order.enums.DeliveryMode;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
......@@ -26,18 +24,12 @@ public class AppCustomerOrderSaveReqVO {
@NotNull(message = "收获库区id不能为空")
private Long warehouseAreaId;
@Schema(description = "仓库信息")
private WarehouseInfo warehouseInfo;
@Schema(description = "配送模式", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "配送模式不能为空")
@InEnum(DeliveryMode.class)
private DeliveryMode deliveryMode;
@Schema(description = "采购订单数", requiredMode = Schema.RequiredMode.REQUIRED, example = "12099")
@NotNull(message = "采购订单数不能为空")
@Size(min = 1, message = "采购订单数不能小于1")
private Integer productCount;
@Schema(description = "预计配送开始时间")
private LocalDateTime planDeliveryStartTime;
......
......@@ -5,11 +5,9 @@ import cn.iocoder.foodnexus.module.order.enums.CustomerOrderStatus;
import cn.iocoder.foodnexus.module.order.enums.DeliveryMode;
import com.baomidou.mybatisplus.extension.handlers.Fastjson2TypeHandler;
import lombok.*;
import java.util.*;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.foodnexus.framework.mybatis.core.dataobject.BaseDO;
......
package cn.iocoder.foodnexus.module.order.dal.dataobject.customerorderrecord;
import cn.iocoder.foodnexus.module.order.enums.CustomerOrderStatus;
import lombok.*;
import java.util.*;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.foodnexus.framework.mybatis.core.dataobject.BaseDO;
/**
* 客户订单进度记录 DO
*
* @author 超级管理员
*/
@TableName(value = "order_customer_order_record", autoResultMap = true)
@KeySequence("order_customer_order_record_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CustomerOrderRecordDO extends BaseDO {
/**
* id
*/
@TableId
private Long id;
/**
* 客户订单id
*/
private Long customerOrderId;
/**
* 订单状态
*
* 枚举 {@link CustomerOrderStatus}
*/
private CustomerOrderStatus orderStatus;
/**
* 客户id
*/
private Long customerId;
/**
* 供应商id
*/
private Long supplierId;
/**
* 信息
*/
private String messageInfo;
/**
* 扩展信息
*/
private String extendInfo;
}
\ No newline at end of file
package cn.iocoder.foodnexus.module.order.dal.mysql.customerorderrecord;
import java.util.*;
import cn.iocoder.foodnexus.framework.common.pojo.PageResult;
import cn.iocoder.foodnexus.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.foodnexus.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.foodnexus.module.order.dal.dataobject.customerorderrecord.CustomerOrderRecordDO;
import org.apache.ibatis.annotations.Mapper;
import cn.iocoder.foodnexus.module.order.controller.admin.customerorderrecord.vo.*;
/**
* 客户订单进度记录 Mapper
*
* @author 超级管理员
*/
@Mapper
public interface CustomerOrderRecordMapper extends BaseMapperX<CustomerOrderRecordDO> {
default PageResult<CustomerOrderRecordDO> selectPage(CustomerOrderRecordPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<CustomerOrderRecordDO>()
.eqIfPresent(CustomerOrderRecordDO::getCustomerOrderId, reqVO.getCustomerOrderId())
.eqIfPresent(CustomerOrderRecordDO::getOrderStatus, reqVO.getOrderStatus())
.eqIfPresent(CustomerOrderRecordDO::getCustomerId, reqVO.getCustomerId())
.eqIfPresent(CustomerOrderRecordDO::getSupplierId, reqVO.getSupplierId())
.eqIfPresent(CustomerOrderRecordDO::getMessageInfo, reqVO.getMessageInfo())
.eqIfPresent(CustomerOrderRecordDO::getExtendInfo, reqVO.getExtendInfo())
.eqIfPresent(CustomerOrderRecordDO::getCreator, reqVO.getCreator())
.betweenIfPresent(CustomerOrderRecordDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(CustomerOrderRecordDO::getId));
}
}
\ No newline at end of file
package cn.iocoder.foodnexus.module.order.enums;
import cn.iocoder.foodnexus.framework.common.core.ArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* @author : yanghao
* create at: 2025/9/5 17:12
* @description: 客户 - 订单 - 状态
*/
@Getter
@AllArgsConstructor
public enum CustomerOrderStatus implements ArrayValuable<String> {
// 下单成功
ORDER_SUCCESS("下单成功", "order_success"),
// 订单匹配
ORDER_MATCH("订单匹配", "order_match"),
// 供应商接单
SUPPLIER_ACCEPT_ORDER("供应商接单", "supplier_accept_order"),
// 供应商发货
SUPPLIER_SHIP("供应商发货", "supplier_ship"),
// 供应商到货
SUPPLIER_ARRIVE("供应商到货", "supplier_arrive"),
;
private final String label;
private final String key;
public static final String[] ARRAYS = Arrays.stream(values()).map(CustomerOrderStatus::getKey).toArray(String[]::new);
/**
* @return 数组
*/
@Override
public String[] array() {
return ARRAYS;
}
}
......@@ -19,4 +19,8 @@ public interface ErrorCodeConstants {
// ========== 客户订单-子订单 1_020_100_0001 ==========
ErrorCode CUSTOMER_ORDER_ITEM_NOT_EXISTS = new ErrorCode(1_020_100_001, "客户订单-子订单不存在");
// ========== 客户订单进度记录 1_021_100_001 ==========
ErrorCode CUSTOMER_ORDER_RECORD_NOT_EXISTS = new ErrorCode(1_021_100_001, "客户订单进度记录不存在");
}
package cn.iocoder.foodnexus.module.order.service.customerorder;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.foodnexus.framework.common.util.CommonUtil;
import cn.iocoder.foodnexus.framework.common.util.spring.SpringUtils;
import cn.iocoder.foodnexus.framework.security.core.LoginUser;
import cn.iocoder.foodnexus.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.foodnexus.module.customerpermission.core.annotation.CustomerVisible;
import cn.iocoder.foodnexus.module.erp.api.PurchaseOrderSplitEvent;
import cn.iocoder.foodnexus.module.erp.api.service.ErpCustomerApi;
import cn.iocoder.foodnexus.module.erp.api.service.ErpSupplierApi;
import cn.iocoder.foodnexus.module.erp.api.service.ErpWarehouseApi;
import cn.iocoder.foodnexus.module.erp.service.customerwarehouse.CustomerWarehouseService;
import cn.iocoder.foodnexus.module.erp.service.purchase.ErpPurchaseOrderServiceImpl;
import cn.iocoder.foodnexus.module.operations.dal.dataobject.inquiresupplierpush.InquireSupplierPushDO;
import cn.iocoder.foodnexus.module.operations.service.inquiresupplierpush.InquireSupplierPushService;
import cn.iocoder.foodnexus.module.order.api.CustomerOrderApi;
import cn.iocoder.foodnexus.module.order.api.CustomerOrderRecordApi;
import cn.iocoder.foodnexus.module.order.controller.app.customerOrder.vo.AppCustomerOrderItemSaveReqVO;
import cn.iocoder.foodnexus.module.order.controller.app.customerOrder.vo.AppCustomerOrderSaveReqVO;
import cn.iocoder.foodnexus.module.order.dal.dataobject.customerorderitem.CustomerOrderItemDO;
import cn.iocoder.foodnexus.module.order.dal.mysql.customerorderitem.CustomerOrderItemMapper;
import cn.iocoder.foodnexus.module.order.dto.CustomerOrderDTO;
import cn.iocoder.foodnexus.module.order.dto.CustomerOrderItemDTO;
import cn.iocoder.foodnexus.module.order.dto.CustomerOrderRecordEvent;
import cn.iocoder.foodnexus.module.order.enums.CustomerOrderStatus;
import cn.iocoder.foodnexus.module.order.service.customerorderitem.CustomerOrderItemService;
import cn.iocoder.foodnexus.module.product.api.InquireCustomerApi;
import cn.iocoder.foodnexus.module.product.api.dto.CustomerVisibleProductRespDTO;
import cn.iocoder.foodnexus.module.system.annotations.AppSystemAuth;
import cn.iocoder.foodnexus.module.product.api.dto.ProductInfo;
import cn.iocoder.foodnexus.module.product.service.spu.ProductSpuService;
import cn.iocoder.foodnexus.module.system.util.GenCodeUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
......@@ -24,17 +37,18 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import cn.iocoder.foodnexus.module.order.controller.admin.customerorder.vo.*;
import cn.iocoder.foodnexus.module.order.dal.dataobject.customerorder.CustomerOrderDO;
import cn.iocoder.foodnexus.framework.common.pojo.PageResult;
import cn.iocoder.foodnexus.framework.common.pojo.PageParam;
import cn.iocoder.foodnexus.framework.common.util.object.BeanUtils;
import cn.iocoder.foodnexus.module.order.dal.mysql.customerorder.CustomerOrderMapper;
import static cn.iocoder.foodnexus.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.foodnexus.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.foodnexus.framework.common.util.collection.CollectionUtils.diffList;
import static cn.iocoder.foodnexus.module.order.enums.ErrorCodeConstants.*;
/**
......@@ -44,7 +58,7 @@ import static cn.iocoder.foodnexus.module.order.enums.ErrorCodeConstants.*;
*/
@Service
@Validated
public class CustomerOrderServiceImpl implements CustomerOrderService {
public class CustomerOrderServiceImpl implements CustomerOrderService, CustomerOrderApi {
@Resource
private CustomerOrderMapper customerOrderMapper;
......@@ -53,6 +67,9 @@ public class CustomerOrderServiceImpl implements CustomerOrderService {
private CustomerOrderItemService customerOrderItemService;
@Autowired
private CustomerOrderItemMapper customerOrderItemMapper;
@Autowired
private CustomerWarehouseService customerWarehouseService;
@Autowired
......@@ -70,6 +87,15 @@ public class CustomerOrderServiceImpl implements CustomerOrderService {
@Autowired
private ErpSupplierApi supplierApi;
@Autowired
private CustomerOrderRecordApi orderRecordApi;
@Autowired
private ProductSpuService productSpuService;
@Autowired
private GenCodeUtils genCodeUtils;
@Override
public Long createCustomerOrder(CustomerOrderSaveReqVO createReqVO) {
// 插入
......@@ -135,25 +161,72 @@ public class CustomerOrderServiceImpl implements CustomerOrderService {
Long customerId = customerApi.queryCustomerIdByUserId(loginUser.getId());
CustomerVisibleProductRespDTO dto = inquireCustomerApi.queryCustomerIdByCustomerId(customerId);
Map<Long, CustomerVisibleProductRespDTO.CustomerProduct> customerProductMap = CommonUtil.listConvertMap(dto.getItems(), CustomerVisibleProductRespDTO.CustomerProduct::getProductId);
Set<Long> supplierSet = new HashSet<>();
Set<Long> procuctSet = new HashSet<>();
for (AppCustomerOrderItemSaveReqVO item : createReqVO.getOrderItems()) {
if (customerProductMap.containsKey(item.getProductId())) {
CustomerVisibleProductRespDTO.CustomerProduct customerProduct = customerProductMap.get(item.getProductId());
item.setOrderItemPrice(customerProduct.getSupplierQuote());
item.setOrderItemTotal(customerProduct.getSupplierQuote() * item.getOrderItemQuantity());
InquireSupplierPushDO inquireSupplierPush = inquireSupplierPushService.getInquireSupplierPush(customerProduct.getInquireSupplierId());
procuctSet.add(inquireSupplierPush.getProductId());
item.setSupplierId(inquireSupplierPush.getSupplierId());
item.setSupplierName(supplierApi.queryNameById(inquireSupplierPush.getSupplierId()));
supplierSet.add(inquireSupplierPush.getSupplierId());
}
}
Long customerOrderId = this.createCustomerOrder(BeanUtils.toBean(createReqVO, CustomerOrderSaveReqVO.class));
// 数据补全
CustomerOrderSaveReqVO createOrder = BeanUtils.toBean(createReqVO, CustomerOrderSaveReqVO.class);
createOrder.setCode(genCodeUtils.createAmBatch("XS"));
createOrder.setOrderStatus(CustomerOrderStatus.ORDER_SUCCESS);
createOrder.setCustomerId(customerId);
createOrder.setWarehouseInfo(warehouseApi.getInfoByWarehouseAreaId(createOrder.getWarehouseAreaId()));
createOrder.setSupplierCount(supplierSet.size());
createOrder.setProductCount(procuctSet.size());
// 子订单补全
AtomicReference<Integer> orderAmount = new AtomicReference<>(0);
List<CustomerOrderItemDO> collect = createReqVO.getOrderItems().stream().map(orderItem -> {
CustomerOrderItemDO item = BeanUtils.toBean(orderItem, CustomerOrderItemDO.class);
item.setCustomerId(customerId);
item.setProductInfo(BeanUtils.toBean(productSpuService.getSpu(item.getProductId()),
ProductInfo.class));
item.setProductName(item.getProductInfo().getName());
item.setSignedQuantity(0);
item.setSignedTotal(0);
orderAmount.updateAndGet(v -> v + item.getOrderItemTotal());
return item;
}).collect(Collectors.toList());
createOrder.setOrderAmount(orderAmount.get());
customerOrderItemService.createBatch(createReqVO.getOrderItems(), customerOrderId, customerId);
Long customerOrderId = this.createCustomerOrder(createOrder);
customerOrderItemService.createBatch(collect, customerOrderId);
// 拆分采购订单
orderSplitPurchase(customerOrderId);
// 订单记录
CustomerOrderRecordEvent event = new CustomerOrderRecordEvent();
event.setOrderStatus(CustomerOrderStatus.ORDER_SUCCESS);
event.setCustomerOrderId(customerOrderId);
event.setCopyWriter(CommonUtil.asList(String.valueOf(createOrder.getOrderAmount()),
String.valueOf(createOrder.getProductCount())));
orderRecordApi.recordEvent(event);
return customerOrderId;
}
/**
* {@link ErpPurchaseOrderServiceImpl#orderSplit(PurchaseOrderSplitEvent)}
*/
private void orderSplitPurchase(Long customerOrderId) {
PurchaseOrderSplitEvent event = new PurchaseOrderSplitEvent();
event.setCustomerOrderId(customerOrderId);
SpringUtils.getApplicationContext().publishEvent(event);
}
private void validCustomerOrder(AppCustomerOrderSaveReqVO createReqVO, Long customerId) {
if (!warehouseApi.existsById(createReqVO.getWarehouseId())) {
throw exception(CUSTOMER_ORDER_WAREHOUSE_NOEXISTS);
......@@ -165,4 +238,22 @@ public class CustomerOrderServiceImpl implements CustomerOrderService {
throw exception(CUSTOMER_WAREHOUSE_NOT_BIND);
}
}
@Override
public CustomerOrderDTO queryById(Long customerOrderId) {
return BeanUtils.toBean(customerOrderMapper.selectById(customerOrderId), CustomerOrderDTO.class);
}
@Override
public List<CustomerOrderItemDTO> queryItemsByOrderId(Long customerOrderId) {
return BeanUtils.toBean(customerOrderItemMapper.selectList(CustomerOrderItemDO::getOrderId, customerOrderId),
CustomerOrderItemDTO.class);
}
@Override
public void updateOrderStatus(Long customerOrderId, CustomerOrderStatus updateOrderStatus) {
customerOrderMapper.update(Wrappers.<CustomerOrderDO>lambdaUpdate()
.set(CustomerOrderDO::getOrderStatus, updateOrderStatus)
.eq(CustomerOrderDO::getId, customerOrderId));
}
}
\ No newline at end of file
......@@ -61,5 +61,5 @@ public interface CustomerOrderItemService {
*/
PageResult<CustomerOrderItemDO> getCustomerOrderItemPage(CustomerOrderItemPageReqVO pageReqVO);
void createBatch(List<AppCustomerOrderItemSaveReqVO> orderItems, Long customerOrderId, Long customerId);
void createBatch(List<CustomerOrderItemDO> orderItems, Long orderId);
}
\ No newline at end of file
......@@ -91,16 +91,11 @@ public class CustomerOrderItemServiceImpl implements CustomerOrderItemService {
}
@Override
public void createBatch(List<AppCustomerOrderItemSaveReqVO> orderItems, Long customerOrderId, Long customerId) {
List<CustomerOrderItemDO> items = BeanUtils.toBean(orderItems, CustomerOrderItemDO.class, item -> {
item.setOrderId(customerOrderId);
item.setCustomerId(customerId);
item.setProductInfo(BeanUtils.toBean(productSpuService.getSpu(item.getProductId()),
ProductInfo.class));
item.setSignedQuantity(0);
item.setSignedTotal(0);
});
customerOrderItemMapper.insertBatch(items);
public void createBatch(List<CustomerOrderItemDO> orderItems, Long orderId) {
for (CustomerOrderItemDO item : orderItems) {
item.setOrderId(orderId);
}
customerOrderItemMapper.insertBatch(orderItems);
}
}
\ No newline at end of file
package cn.iocoder.foodnexus.module.order.service.customerorderrecord;
import java.util.*;
import jakarta.validation.*;
import cn.iocoder.foodnexus.module.order.controller.admin.customerorderrecord.vo.*;
import cn.iocoder.foodnexus.module.order.dal.dataobject.customerorderrecord.CustomerOrderRecordDO;
import cn.iocoder.foodnexus.framework.common.pojo.PageResult;
import cn.iocoder.foodnexus.framework.common.pojo.PageParam;
/**
* 客户订单进度记录 Service 接口
*
* @author 超级管理员
*/
public interface CustomerOrderRecordService {
/**
* 创建客户订单进度记录
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createCustomerOrderRecord(@Valid CustomerOrderRecordSaveReqVO createReqVO);
/**
* 更新客户订单进度记录
*
* @param updateReqVO 更新信息
*/
void updateCustomerOrderRecord(@Valid CustomerOrderRecordSaveReqVO updateReqVO);
/**
* 删除客户订单进度记录
*
* @param id 编号
*/
void deleteCustomerOrderRecord(Long id);
/**
* 批量删除客户订单进度记录
*
* @param ids 编号
*/
void deleteCustomerOrderRecordListByIds(List<Long> ids);
/**
* 获得客户订单进度记录
*
* @param id 编号
* @return 客户订单进度记录
*/
CustomerOrderRecordDO getCustomerOrderRecord(Long id);
/**
* 获得客户订单进度记录分页
*
* @param pageReqVO 分页查询
* @return 客户订单进度记录分页
*/
PageResult<CustomerOrderRecordDO> getCustomerOrderRecordPage(CustomerOrderRecordPageReqVO pageReqVO);
}
\ No newline at end of file
package cn.iocoder.foodnexus.module.order.service.customerorderrecord;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.foodnexus.framework.common.util.spring.SpringUtils;
import cn.iocoder.foodnexus.module.erp.api.PurchaseOrderSplitEvent;
import cn.iocoder.foodnexus.module.order.api.CustomerOrderApi;
import cn.iocoder.foodnexus.module.order.api.CustomerOrderRecordApi;
import cn.iocoder.foodnexus.module.order.dto.CustomerOrderDTO;
import cn.iocoder.foodnexus.module.order.dto.CustomerOrderRecordEvent;
import cn.iocoder.foodnexus.module.order.enums.CustomerOrderStatus;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import cn.iocoder.foodnexus.module.order.controller.admin.customerorderrecord.vo.*;
import cn.iocoder.foodnexus.module.order.dal.dataobject.customerorderrecord.CustomerOrderRecordDO;
import cn.iocoder.foodnexus.framework.common.pojo.PageResult;
import cn.iocoder.foodnexus.framework.common.pojo.PageParam;
import cn.iocoder.foodnexus.framework.common.util.object.BeanUtils;
import cn.iocoder.foodnexus.module.order.dal.mysql.customerorderrecord.CustomerOrderRecordMapper;
import static cn.iocoder.foodnexus.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.foodnexus.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.foodnexus.framework.common.util.collection.CollectionUtils.diffList;
import static cn.iocoder.foodnexus.module.order.enums.ErrorCodeConstants.*;
/**
* 客户订单进度记录 Service 实现类
*
* @author 超级管理员
*/
@Service
@Validated
@Slf4j
public class CustomerOrderRecordServiceImpl implements CustomerOrderRecordService, CustomerOrderRecordApi {
@Resource
private CustomerOrderRecordMapper customerOrderRecordMapper;
@Autowired
private CustomerOrderApi customerOrderApi;
@Override
public Long createCustomerOrderRecord(CustomerOrderRecordSaveReqVO createReqVO) {
// 插入
CustomerOrderRecordDO customerOrderRecord = BeanUtils.toBean(createReqVO, CustomerOrderRecordDO.class);
customerOrderRecordMapper.insert(customerOrderRecord);
// 返回
return customerOrderRecord.getId();
}
@Override
public void updateCustomerOrderRecord(CustomerOrderRecordSaveReqVO updateReqVO) {
// 校验存在
validateCustomerOrderRecordExists(updateReqVO.getId());
// 更新
CustomerOrderRecordDO updateObj = BeanUtils.toBean(updateReqVO, CustomerOrderRecordDO.class);
customerOrderRecordMapper.updateById(updateObj);
}
@Override
public void deleteCustomerOrderRecord(Long id) {
// 校验存在
validateCustomerOrderRecordExists(id);
// 删除
customerOrderRecordMapper.deleteById(id);
}
@Override
public void deleteCustomerOrderRecordListByIds(List<Long> ids) {
// 删除
customerOrderRecordMapper.deleteByIds(ids);
}
private void validateCustomerOrderRecordExists(Long id) {
if (customerOrderRecordMapper.selectById(id) == null) {
throw exception(CUSTOMER_ORDER_RECORD_NOT_EXISTS);
}
}
@Override
public CustomerOrderRecordDO getCustomerOrderRecord(Long id) {
return customerOrderRecordMapper.selectById(id);
}
@Override
public PageResult<CustomerOrderRecordDO> getCustomerOrderRecordPage(CustomerOrderRecordPageReqVO pageReqVO) {
return customerOrderRecordMapper.selectPage(pageReqVO);
}
@Override
public void recordEvent(CustomerOrderRecordEvent event) {
SpringUtils.getApplicationContext().publishEvent(event);
}
@Async
@TransactionalEventListener(classes = CustomerOrderRecordEvent.class, phase = TransactionPhase.AFTER_COMMIT)
public void addRecordEvent(CustomerOrderRecordEvent event) {
log.info("客户订单记录:{}", event);
Long orderId = event.getCustomerOrderId();
CustomerOrderStatus orderStatus = event.getOrderStatus();
CustomerOrderDTO orderInfo = customerOrderApi.queryById(orderId);
if (!orderStatus.equals(orderInfo.getOrderStatus())) {
return ;
}
String message = String.format(orderStatus.getText(), event.getCopyWriter().toArray(new String[0]));
CustomerOrderRecordSaveReqVO saveReqVO = new CustomerOrderRecordSaveReqVO();
saveReqVO.setCustomerId(orderInfo.getCustomerId());
saveReqVO.setCustomerOrderId(orderId);
saveReqVO.setOrderStatus(orderStatus);
saveReqVO.setSupplierId(event.getSupplierId());
saveReqVO.setMessageInfo(message);
this.createCustomerOrderRecord(saveReqVO);
}
}
\ No newline at end of file
......@@ -22,6 +22,7 @@
<module>foodnexus-module-operations</module>
<module>foodnexus-module-product-api</module>
<module>foodnexus-module-order</module>
<module>foodnexus-module-order-api</module>
</modules>
</project>
package cn.iocoder.foodnexus.module.system.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
/**
* @author : yanghao
* create at: 2024/11/29 11:41
* @description: code生成
*/
@Component
public class GenCodeUtils {
// 表示最大位数(10的三次方表示最大四位数)
private static final Long MAX = Double.valueOf(Math.pow(10, 3)).longValue();
@Autowired
private RedisTemplate redisTemplate;
public String createAmBatch(String type) {
String monthDay = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
String key = String.format("CODE:%s:%s", monthDay, type);
Boolean flag = redisTemplate.hasKey(key);
Long increment = redisTemplate.opsForValue().increment(key, 1);
if (Boolean.FALSE.equals(flag)) {
redisTemplate.expire(key, Duration.ofHours(24));
}
return this.getCode(type, monthDay, increment);
}
private String getCode(String type, String monthDay, Long increment) {
if (increment < MAX) {
return String.format("%s%s0%s", type, monthDay, String.valueOf(increment + MAX).substring(1));
}
return String.format("%s%s%s", type, monthDay, increment);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment