Skip to content

Latest commit

 

History

History
758 lines (614 loc) · 21.5 KB

File metadata and controls

758 lines (614 loc) · 21.5 KB

WMS系统标准化改造实施指南

改造目标

将现有WMS系统改造为生产可用的标准化三方仓储管理系统,解决所有架构问题,实现前后端完美联动。


一、已完成改造

1.1 配置标准化 ✅

Docker配置重构 (docker-compose.yml)

  • ✅ 移除不存在的wms-gateway和odoo服务
  • ✅ 统一端口: 后端8080, 前端3000, 数据库5432
  • ✅ 添加Redis缓存服务
  • ✅ 配置健康检查和依赖管理
  • ✅ 统一数据库为PostgreSQL wms_db

后端配置标准化 (application.yml)

  • ✅ 统一context-path为 /api/v1
  • ✅ 统一端口为 8080
  • ✅ 添加环境变量支持
  • ✅ 配置Redis、JWT、业务参数
  • ✅ 创建docker环境配置文件

前端配置标准化 (api.ts)

  • ✅ 统一API_BASE_URL为 http://localhost:8080/api/v1
  • ✅ 修复入库接口路径: /inbound/orders/*
  • ✅ 修复出库接口路径: /outbound/orders/*

二、待执行改造(按优先级)

阶段一: 接口规范统一 (P0 - 紧急)

1. 后端Controller路径修改

InboundController.java - 修改所有路径

@RequestMapping("/inbound")  // 保持不变
public class InboundController {

    // GET /api/v1/inbound/orders?current=1&size=20&tenantId=1
    @GetMapping("/orders")
    public Result<Page<InboundOrder>> getOrdersByPage(...)

    // GET /api/v1/inbound/orders/{id}
    @GetMapping("/orders/{id}")

    // GET /api/v1/inbound/orders/no/{orderNo}
    @GetMapping("/orders/no/{orderNo}")

    // POST /api/v1/inbound/orders
    @PostMapping("/orders")

    // PUT /api/v1/inbound/orders/{id}
    @PutMapping("/orders/{id}")

    // DELETE /api/v1/inbound/orders/{id}
    @DeleteMapping("/orders/{id}")

    // POST /api/v1/inbound/orders/{id}/confirm
    @PostMapping("/orders/{id}/confirm")

    // POST /api/v1/inbound/orders/{id}/receive
    @PostMapping("/orders/{id}/receive")

    // GET /api/v1/inbound/orders/{orderId}/lines
    @GetMapping("/orders/{orderId}/lines")

    // POST /api/v1/inbound/orders/{id}/complete
    @PostMapping("/orders/{id}/complete")

    // POST /api/v1/inbound/orders/{id}/cancel
    @PostMapping("/orders/{id}/cancel")
}

OutboundController.java - 需要新增或修改的方法

@RequestMapping("/outbound")
public class OutboundController {

    @GetMapping("/orders")  // 分页查询
    @GetMapping("/orders/{id}")  // 详情查询
    @GetMapping("/orders/no/{orderNo}")  // 单号查询
    @PostMapping("/orders")  // 创建
    @PutMapping("/orders/{id}")  // 更新
    @DeleteMapping("/orders/{id}")  // 删除
    @PostMapping("/orders/{id}/confirm")  // 确认
    @PostMapping("/orders/{id}/allocate")  // 分配库存
    @PostMapping("/orders/{id}/start-picking")  // 开始拣货
    @PostMapping("/orders/{id}/complete-picking")  // 完成拣货
    @PostMapping("/orders/{id}/start-checking")  // 开始复核
    @PostMapping("/orders/{id}/complete-checking")  // 完成复核
    @PostMapping("/orders/{id}/ship")  // 发货
    @PostMapping("/orders/{id}/cancel")  // 取消
    @GetMapping("/orders/{orderId}/lines")  // 获取明细
}

其他Controller需统一检查:

  • WarehouseController
  • LocationController
  • ProductController
  • CustomerController
  • SupplierController
  • 等所有Controller

2. 统一响应结构

所有Controller返回统一使用:

public class Result<T> {
    private Integer code;     // 200成功, 其他失败
    private String message;
    private T data;
    private Long timestamp;
}

阶段二: 核心功能完善 (P1 - 高优先级)

1. 库存预留锁定机制 ⚠️ 关键

新增表结构 (database/schema/02_inventory.sql)

-- 库存预留表
CREATE TABLE wms.wms_inventory_reservation (
    id BIGSERIAL PRIMARY KEY,
    reservation_no VARCHAR(50) UNIQUE NOT NULL,
    reservation_type VARCHAR(20) NOT NULL,  -- ORDER, TRANSFER, LOCK
    business_no VARCHAR(50),
    business_id BIGINT,
    warehouse_id BIGINT NOT NULL,
    location_id BIGINT,
    inventory_id BIGINT NOT NULL,
    product_id BIGINT NOT NULL,
    batch_no VARCHAR(50),
    reserved_quantity DECIMAL(15,3) NOT NULL,
    used_quantity DECIMAL(15,3) DEFAULT 0,
    remaining_quantity DECIMAL(15,3),
    status VARCHAR(20) NOT NULL,  -- ACTIVE, USED, RELEASED, EXPIRED
    reservation_time TIMESTAMP NOT NULL,
    expiry_time TIMESTAMP,
    release_time TIMESTAMP,
    operator_id BIGINT,
    operator_name VARCHAR(50),
    remark TEXT,
    tenant_id BIGINT NOT NULL DEFAULT 1,
    created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_reservation_inventory ON wms.wms_inventory_reservation(inventory_id, status);
CREATE INDEX idx_reservation_business ON wms.wms_inventory_reservation(business_no, business_id);
CREATE INDEX idx_reservation_expiry ON wms.wms_inventory_reservation(expiry_time, status);

新增Service (InventoryReservationService.java)

public interface InventoryReservationService {
    // 创建预留
    InventoryReservation reserve(ReservationRequest request);

    // 使用预留
    void use(Long reservationId, BigDecimal quantity);

    // 释放预留
    void release(Long reservationId);

    // 过期预留自动释放(定时任务)
    void autoReleaseExpired();

    // 查询预留
    List<InventoryReservation> findByBusinessNo(String businessNo);
}

OutboundService集成

  • 创建出库单时自动预留库存
  • 拣货完成时使用预留
  • 取消出库单时释放预留

2. ASN预约收货

新增表结构 (database/schema/03_inbound.sql)

-- ASN预约收货通知表
CREATE TABLE wms.wms_asn (
    id BIGSERIAL PRIMARY KEY,
    asn_no VARCHAR(50) UNIQUE NOT NULL,
    warehouse_id BIGINT NOT NULL,
    supplier_id BIGINT,
    customer_id BIGINT,
    asn_type VARCHAR(20) NOT NULL,  -- PURCHASE, RETURN, TRANSFER
    source_no VARCHAR(50),
    appointment_date DATE NOT NULL,
    appointment_time_from TIME,
    appointment_time_to TIME,
    contact_person VARCHAR(50),
    contact_phone VARCHAR(20),
    vehicle_no VARCHAR(20),
    driver_name VARCHAR(50),
    driver_phone VARCHAR(20),
    total_quantity DECIMAL(15,3),
    total_volume DECIMAL(15,3),
    total_weight DECIMAL(15,3),
    status VARCHAR(20) NOT NULL,  -- SUBMITTED, CONFIRMED, ARRIVED, RECEIVING, COMPLETED, CANCELLED
    dock_door VARCHAR(20),
    arrival_time TIMESTAMP,
    start_receive_time TIMESTAMP,
    finish_receive_time TIMESTAMP,
    remark TEXT,
    tenant_id BIGINT NOT NULL DEFAULT 1,
    created_by BIGINT,
    created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_by BIGINT,
    updated_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_asn_date ON wms.wms_asn(warehouse_id, appointment_date, status);

ASN流程:

客户提交ASN → 仓库确认 → 到货签到 → 自动创建入库单 → 收货上架

3. 收货差异处理

在InboundService中增加:

public class ReceiveDifference {
    private Long lineId;
    private BigDecimal plannedQty;      // 计划数量
    private BigDecimal receivedQty;     // 实收数量
    private BigDecimal differenceQty;   // 差异数量
    private String differenceType;      // MORE多收, LESS少收, DAMAGE破损
    private String differenceReason;    // 差异原因
    private String handleMethod;        // 处理方式: ACCEPT接受, REJECT拒收, REPORT上报
}

阶段三: PDA移动端开发 (P1 - 高优先级)

1. PDA后端API

新建PDAController (services/wms-basic-service/src/main/java/com/wms/basic/controller/PDAController.java)

@RestController
@RequestMapping("/pda")
public class PDAController {

    // PDA登录
    @PostMapping("/auth/login")
    public Result<PDASession> login(@RequestBody PDALoginRequest request);

    // 扫描条码解析
    @PostMapping("/barcode/scan")
    public Result<BarcodeInfo> scanBarcode(@RequestBody ScanRequest request);

    // 查询产品信息
    @GetMapping("/products/{code}")
    public Result<ProductInfo> getProductByCode(@PathVariable String code);

    // 查询库位信息
    @GetMapping("/locations/{code}")
    public Result<LocationInfo> getLocationByCode(@PathVariable String code);

    // 查询库存
    @PostMapping("/inventory/query")
    public Result<List<InventoryInfo>> queryInventory(@RequestBody QueryRequest request);

    // === 入库操作 ===
    // 获取待收货任务
    @GetMapping("/inbound/tasks")
    public Result<List<InboundTask>> getInboundTasks();

    // 扫码收货
    @PostMapping("/inbound/receive")
    public Result<ReceiveResult> receive(@RequestBody ReceiveRequest request);

    // 扫码上架
    @PostMapping("/inbound/putaway")
    public Result<PutawayResult> putaway(@RequestBody PutawayRequest request);

    // === 出库操作 ===
    // 获取拣货任务
    @GetMapping("/outbound/picking-tasks")
    public Result<List<PickingTask>> getPickingTasks();

    // 扫码拣货
    @PostMapping("/outbound/pick")
    public Result<PickResult> pick(@RequestBody PickRequest request);

    // 扫码复核
    @PostMapping("/outbound/check")
    public Result<CheckResult> check(@RequestBody CheckRequest request);

    // === 移库操作 ===
    // 获取移库任务
    @GetMapping("/transfer/tasks")
    public Result<List<TransferTask>> getTransferTasks();

    // 扫码移库
    @PostMapping("/transfer/move")
    public Result<MoveResult> move(@RequestBody MoveRequest request);

    // === 盘点操作 ===
    // 获取盘点任务
    @GetMapping("/stocktaking/tasks")
    public Result<List<StocktakingTask>> getStocktakingTasks();

    // 扫码盘点
    @PostMapping("/stocktaking/count")
    public Result<CountResult> count(@RequestBody CountRequest request);

    // 提交盘点结果
    @PostMapping("/stocktaking/submit")
    public Result<Void> submitStocktaking(@RequestBody SubmitRequest request);
}

2. PDA前端开发(可选H5或原生App)

技术选型:

  • H5: React + Vite + Ant Design Mobile
  • 原生: React Native 或 Flutter

核心页面:

/pda/login              # 登录页
/pda/home               # 主菜单
/pda/scan               # 扫码页(通用)
/pda/inbound            # 入库管理
/pda/inbound/receive    # 收货
/pda/inbound/putaway    # 上架
/pda/outbound           # 出库管理
/pda/outbound/pick      # 拣货
/pda/outbound/check     # 复核
/pda/transfer           # 移库
/pda/stocktaking        # 盘点
/pda/query              # 查询

扫码功能实现:

// 使用html5-qrcode库
import { Html5Qrcode } from "html5-qrcode";

const scanner = new Html5Qrcode("reader");
scanner.start(
  { facingMode: "environment" },
  { fps: 10, qrbox: 250 },
  (decodedText) => {
    // 扫码成功,调用后端API解析
    pda.scanBarcode(decodedText);
  }
);

阶段四: 波次智能算法 (P1)

WaveService增强

/**
 * 智能波次算法
 * 根据订单特征自动分波
 */
public class SmartWaveStrategy {

    /**
     * 按区域分波
     * 同一拣货区域的订单分到一个波次
     */
    public List<WaveOrder> allocateByZone(List<OutboundOrder> orders);

    /**
     * 按客户分波
     * 同一客户的多个订单合并
     */
    public List<WaveOrder> allocateByCustomer(List<OutboundOrder> orders);

    /**
     * 按时效分波
     * 紧急订单优先,时效相同的合并
     */
    public List<WaveOrder> allocateByPriority(List<OutboundOrder> orders);

    /**
     * 混合策略
     * 综合考虑区域、时效、订单量
     */
    public List<WaveOrder> allocateBySmart(List<OutboundOrder> orders);
}

拣货路径优化

/**
 * 拣货路径优化算法
 * 基于TSP(旅行商问题)求解最短拣货路径
 */
public class PickingPathOptimizer {

    /**
     * S型路径: 按货架顺序依次拣货
     */
    public List<PickingTask> optimizeBySType(List<Location> locations);

    /**
     * Z型路径: 之字形穿越货架
     */
    public List<PickingTask> optimizeByZType(List<Location> locations);

    /**
     * 最短路径: 使用遗传算法计算
     */
    public List<PickingTask> optimizeByShortestPath(List<Location> locations);
}

阶段五: 打印服务 (P1)

PrintController.java

@RestController
@RequestMapping("/print")
public class PrintController {

    // 打印入库标签
    @PostMapping("/inbound/label")
    public Result<String> printInboundLabel(@RequestBody PrintRequest request);

    // 打印拣货单
    @PostMapping("/picking/list")
    public Result<String> printPickingList(@RequestBody PrintRequest request);

    // 打印发货标签
    @PostMapping("/shipping/label")
    public Result<String> printShippingLabel(@RequestBody PrintRequest request);

    // 打印库位标签
    @PostMapping("/location/label")
    public Result<String> printLocationLabel(@RequestBody PrintRequest request);
}

打印模板设计(使用Jasper Reports或iText)

templates/
  ├── inbound_label.jrxml      # 入库标签
  ├── picking_list.jrxml       # 拣货单
  ├── shipping_label.jrxml     # 发货标签
  └── location_label.jrxml     # 库位标签

阶段六: 三方仓储特色功能 (P2)

1. 计费规则引擎

新增表 (wms_billing_rule)

CREATE TABLE wms.wms_billing_rule (
    id BIGSERIAL PRIMARY KEY,
    rule_code VARCHAR(50) UNIQUE NOT NULL,
    rule_name VARCHAR(100) NOT NULL,
    customer_id BIGINT,                    -- 客户ID(NULL表示通用规则)
    rule_type VARCHAR(20) NOT NULL,        -- STORAGE-仓储费, INBOUND-入库费, OUTBOUND-出库费, OPERATION-作业费
    billing_method VARCHAR(20),            -- FIXED-固定, QUANTITY-按数量, VOLUME-按体积, WEIGHT-按重量, DAYS-按天数
    unit_price DECIMAL(15,2),
    min_charge DECIMAL(15,2),              -- 最低收费
    free_period INT,                        -- 免费期(天)
    calculation_formula TEXT,               -- 计费公式
    enabled BOOLEAN DEFAULT TRUE,
    effective_date DATE,
    expiry_date DATE,
    tenant_id BIGINT NOT NULL DEFAULT 1
);

计费公式示例:

仓储费 = (体积 × 单价 × 天数) + (超出免费期天数 × 超期单价)
入库费 = 件数 × 单价 + (体积 > 阈值 ? 超大件费 : 0)
出库费 = 件数 × 单价 + 拣货费 + 包装费

2. 客户门户

新建模块 (services/wms-portal)

wms-portal/
  ├── pages/
  │   ├── login/              # 客户登录
  │   ├── dashboard/          # 客户仪表板
  │   ├── inventory/          # 库存查询
  │   ├── orders/             # 订单查询
  │   ├── inbound/            # 入库管理
  │   ├── outbound/           # 出库管理
  │   ├── reports/            # 报表查询
  │   └── billing/            # 账单查询

功能清单:

  • 实时库存查询
  • 入库单查询与创建
  • 出库单查询与创建
  • 库龄分析
  • 账单明细查询
  • 数据报表导出

3. 库龄分析

新增视图 (database/views/inventory_aging.sql)

CREATE VIEW wms.v_inventory_aging AS
SELECT
    i.id,
    i.product_id,
    p.product_code,
    p.product_name,
    i.warehouse_id,
    i.batch_no,
    i.available_quantity,
    i.created_time,
    CURRENT_DATE - i.created_time::date AS aging_days,
    CASE
        WHEN CURRENT_DATE - i.created_time::date <= 30 THEN '0-30天'
        WHEN CURRENT_DATE - i.created_time::date <= 60 THEN '31-60天'
        WHEN CURRENT_DATE - i.created_time::date <= 90 THEN '61-90天'
        WHEN CURRENT_DATE - i.created_time::date <= 180 THEN '91-180天'
        ELSE '180天以上'
    END AS aging_range
FROM wms.wms_inventory i
JOIN wms.wms_product p ON i.product_id = p.id
WHERE i.available_quantity > 0;

阶段七: 数据库优化 (P2)

1. 添加关键索引

-- 入库单索引
CREATE INDEX idx_inbound_order_status ON wms.wms_inbound_order(warehouse_id, status, created_time);
CREATE INDEX idx_inbound_order_supplier ON wms.wms_inbound_order(supplier_id, created_time);
CREATE INDEX idx_inbound_line_product ON wms.wms_inbound_order_line(product_id, status);

-- 出库单索引
CREATE INDEX idx_outbound_order_status ON wms.wms_outbound_order(warehouse_id, status, created_time);
CREATE INDEX idx_outbound_order_customer ON wms.wms_outbound_order(customer_id, created_time);
CREATE INDEX idx_outbound_line_product ON wms.wms_outbound_order_line(product_id, status);

-- 库存索引
CREATE INDEX idx_inventory_product ON wms.wms_inventory(product_id, warehouse_id, status);
CREATE INDEX idx_inventory_location ON wms.wms_inventory(location_id, status);
CREATE INDEX idx_inventory_batch ON wms.wms_inventory(batch_no, product_id);
CREATE INDEX idx_inventory_available ON wms.wms_inventory(product_id, available_quantity)
    WHERE available_quantity > 0;

-- 库存事务索引
CREATE INDEX idx_inventory_transaction_time ON wms.wms_inventory_transaction(transaction_time);
CREATE INDEX idx_inventory_transaction_product ON wms.wms_inventory_transaction(product_id, transaction_time);

-- 波次索引
CREATE INDEX idx_wave_status ON wms.wms_wave_order(warehouse_id, status, wave_date);

2. 分区策略

-- 按月分区历史订单表
CREATE TABLE wms.wms_inbound_order_history (
    LIKE wms.wms_inbound_order INCLUDING ALL
) PARTITION BY RANGE (created_time);

-- 创建分区
CREATE TABLE wms.wms_inbound_order_2025_01
    PARTITION OF wms.wms_inbound_order_history
    FOR VALUES FROM ('2025-01-01') TO ('2025-02-01');

-- 自动归档策略(6个月前数据)
CREATE OR REPLACE FUNCTION archive_old_orders()
RETURNS void AS $$
BEGIN
    INSERT INTO wms.wms_inbound_order_history
    SELECT * FROM wms.wms_inbound_order
    WHERE created_time < CURRENT_DATE - INTERVAL '6 months';

    DELETE FROM wms.wms_inbound_order
    WHERE created_time < CURRENT_DATE - INTERVAL '6 months';
END;
$$ LANGUAGE plpgsql;

三、实施步骤

第1天: 接口规范统一

  1. 修改所有后端Controller路径
  2. 测试前后端联调
  3. 更新API文档

第2-3天: 核心功能完善

  1. 实现库存预留锁定机制
  2. 实现ASN预约收货
  3. 完善收货差异处理
  4. 单元测试

第4-6天: PDA移动端开发

  1. 开发PDA后端API
  2. 开发PDA H5前端
  3. 集成扫码功能
  4. 现场测试

第7-8天: 波次算法与打印

  1. 实现智能波次算法
  2. 优化拣货路径
  3. 开发打印服务
  4. 设计打印模板

第9-10天: 三方仓储功能

  1. 实现计费规则引擎
  2. 开发客户门户
  3. 实现库龄分析

第11-12天: 数据库优化与测试

  1. 添加索引
  2. 配置分区
  3. 全功能测试
  4. 性能测试

第13-14天: 部署与上线

  1. Docker镜像构建
  2. 生产环境部署
  3. 数据迁移
  4. 用户培训

四、关键文件清单

需要创建的新文件

后端:

services/wms-basic-service/src/main/java/com/wms/basic/
├── entity/
│   ├── InventoryReservation.java          # 库存预留实体
│   ├── ASN.java                            # ASN实体
│   ├── ASNLine.java                        # ASN明细
│   ├── BillingRule.java                    # 计费规则
│   └── BillingRecord.java                  # 计费记录
├── repository/
│   ├── InventoryReservationRepository.java
│   ├── ASNRepository.java
│   └── BillingRuleRepository.java
├── service/
│   ├── InventoryReservationService.java    # 预留服务
│   ├── ASNService.java                     # ASN服务
│   ├── BillingService.java                 # 计费服务
│   └── PickingPathOptimizer.java           # 路径优化
├── controller/
│   ├── PDAController.java                  # PDA接口
│   ├── PrintController.java                # 打印接口
│   └── PortalController.java               # 客户门户接口
└── dto/
    ├── ReservationRequest.java
    ├── ASNRequest.java
    └── PDA相关DTO...

数据库:

database/schema/
├── 02_inventory_enhancement.sql            # 库存增强
├── 03_inbound_asn.sql                      # ASN表
├── 11_billing.sql                          # 计费模块
├── 12_indexes.sql                          # 索引优化
└── 13_partitions.sql                       # 分区配置

前端PDA(可选独立项目):

services/wms-pda/
├── public/
├── src/
│   ├── pages/                              # 页面组件
│   ├── components/                         # 通用组件
│   ├── services/                           # API调用
│   ├── utils/                              # 工具函数
│   └── App.tsx
├── package.json
└── vite.config.ts

五、验收标准

功能验收

  • 前后端接口100%匹配,无404错误
  • 入库流程完整:ASN→收货→上架
  • 出库流程完整:预留→拣货→复核→发货
  • PDA扫码功能正常
  • 打印服务正常输出
  • 计费规则计算准确

性能验收

  • 接口响应时间 < 500ms (P95)
  • 并发用户数 >= 100
  • 数据库查询使用索引
  • 事务处理无死锁

稳定性验收

  • 7x24小时运行无崩溃
  • 异常处理覆盖完整
  • 日志记录完善
  • 可回滚升级

六、注意事项

  1. 数据备份: 改造前务必全量备份数据库
  2. 灰度发布: 建议先在测试环境验证,再逐步切换生产
  3. 向后兼容: 保留旧接口一段时间,避免客户端无法访问
  4. 文档同步: 及时更新API文档和用户手册
  5. 培训计划: 提前培训仓库操作人员使用新功能

文档版本: v1.0 创建日期: 2025-10-07 维护团队: WMS开发团队