### 详细入库全流程解析

#### 单据创建阶段 (Creation)

   * 动作: 用户通过 add 接口新增，或 importData 导入 Excel。
   * 数据变更:
     * 插入 TRkWareNotice，状态 ReceivingStatus = "0"。
     * 插入 TRkWareNoticeTab，状态 ReceivingStatus = "0", InStatus = "0"。

#### 收货确认阶段 (Receiving / Task Generation)

    此阶段是“实物清点与任务生成”，并非流程的终点。

   * 接口: confirmNoticeTab
   * 业务逻辑:
     1. 校验: 检查托盘状态、是否冻结（InStatus=="1"）。
     2. 更新收货量: 累加 RecNum (累计收货数量)。
     3. 判定冻结: 如果 RecNum (累计收货) == ReceivingNum (应收总数)，将明细 InStatus 更新为 "1"。这标志着该物料收货动作结束，不能再收了。
     4. 生成任务: 创建 TOngoodsshelf (入库任务)，状态 InStatus = "0"。
     5. 发送通知: 生成 TCallNotice，通知下游（如AGV或搬运工）执行上架任务。
   * 关键点: 此时单据状态 `ReceivingStatus` 依然是 `"0"`，库存表尚未增加库存。

#### 上架确认阶段 (Putaway / Completion)

    此阶段是“任务执行与库存生成”，驱动状态流转。

   * 接口: shelvesConfirm
   * 业务逻辑:
     1. 校验: 检查库位 (LocationId) 有效性。
     2. 更新上架量: 累加 AcceNum (累计上架数量)。
     3. 更新明细状态:
        * 若 AcceNum < RecNum: 设置 ReceivingStatus = "1" (部分上架)。
        * 若 AcceNum >= RecNum: 设置 ReceivingStatus = "2" (全部上架)。
     4. 完成任务: 将 TOngoodsshelf 移入历史表 TOngoodsshelfBak，并从原表删除。
     5. 生成库存:
        * 普通模式: 插入 TMiStock (真实库存)。
        * 虚拟模式 (Fictitious="1"): 插入 TMiStockF (虚拟库存)。
     6. 判断主单完结:
        * 遍历该单据下所有明细。
        * 如果所有明细的状态都为 `"2"` (已上架)，则触发归档流程。

#### 归档流程 (Archiving)

    当上架确认检测到主单完结时自动触发。

   * 更新主单: 将 TRkWareNotice 的 ReceivingStatus 设为 "2"。
   * 同步收货表: 更新或插入 TRkReceivingGoods (收货记录表)。
   * 历史迁移:
     * 将主单数据移入 TRkWareNoticeBak。
     * 将明细数据移入 TRkWareNoticeTabBak。
   * 数据清理: 物理删除 TRkWareNotice 和 TRkWareNoticeTab 中的原数据。
   * 关闭通知: 关闭关联的 TCallNoticeOrder 任务。

### 详细出库流程解析
> TCkOrdersServiceImpl

> TCkPickingwavegoodsServiceImpl

#### 单据创建阶段 (Creation)

   * 动作:
     * 用户通过 add 接口新增主单，或通过 importData 导入 Excel。
     * 用户通过 updateTckOrderDetails 维护出库明细。
   * 数据变更:
     * 插入 TCkOrders，主单状态 Status = "0"（新建）。
     * 插入或更新 TCkOrderdetail，明细 ConfirmStatus = "0"（待执行）。
   * 业务逻辑:
     1. 校验来源单号 DeliveryId 不能重复。
     2. 校验同一单据内不能重复添加相同 GoodsId。
     3. 若对应物料已有锁定库存，则不允许继续追加明细。
     4. 回填价格、总金额、建单人、部门、记录人等基础信息。
   * 关键点: 此阶段只是在系统内形成“出库需求”，还不会锁库存，也不会生成拣货任务。

#### 审核提交流程 (Audit Submission)

    这一步负责把出库申请送入审批链，而不是直接执行出库。

   * 接口: changeStatus / auditCkOrders
   * 业务逻辑:
     1. 查询当前出库单及其全部明细。
     2. 将明细转换成 GoodsVo 列表，组装 OutBound 审批数据。
     3. 把每条明细的 CallShelvesNum 回写为申请数量 ShelvesNum。
     4. 调用钉钉创建审批实例，生成 InstanceId。
     5. 写入本地 OutBound 审批记录，并把 InstanceId 回写到 TCkOrders。
   * 关键点:
     * updateStatus 负责发起审批流。
     * auditCkOrders 是本地审核通过入口。

#### 任务分流阶段 (Dispatch)

    审核通过后，系统会根据仓库类型决定走“推送 IWMS”还是“本地生成出库任务”。

   * 接口: send / sendiwms / issue
   * 业务逻辑:
     1. send 会按仓库是否为 AGV 仓拆分出库明细。
     2. AGV 仓明细调用 sendIwms，向 IWMS 推送出库数据。
     3. 非 AGV 仓明细调用 confirmOut，走本地锁库与任务生成。
     4. 手持出库 issue 会先自动创建一张已审核的普通出库单，再直接调用 confirmOut。
   * 数据变更:
     * sendIwms 成功后，会回写明细 TrNum = GoodsNum、PickNum，并把 CkType 置为普通出库。
   * 关键点: sendOrderNotice 还保留了向手持端补发 TCallNoticeOrder 的能力，但当前控制层入口已注释。

#### IWMS 推送阶段 (AGV Branch)

    该分支只处理 AGV 仓明细，主要目标是把出库需求推送给外部 IWMS。

   * 接口: sendiwms / sendIwms
   * 业务逻辑:
     1. 重新加载当前出库单，筛选出 AGV 仓明细。
     2. 按 GoodsId、GoodsName、Ctl、StorageId、ShelvesNum 匹配库存记录。
     3. 逐条组装推送报文，包含单号、物料、数量、追溯码、仓库、容器类型等字段。
     4. 调用外部接口 `pushOutOrder` 发送数据。
     5. 外部返回“成功”后，回写对应明细的提货数量与出库类型。
   * 关键点: 该分支负责“推送外部系统”，不在本类内创建 TCkPickingwavegoods 本地拣货任务。

#### 本地出库任务生成阶段 (Local Task Generation)

    这一阶段是 TCkOrdersServiceImpl 内最核心的“选库存 + 锁库存 + 生成任务”流程。

   * 接口: confirmOut
   * 业务逻辑:
     1. 校验出库明细不能为空，并跳过 ConfirmStatus = "2" 的已完成明细。
     2. 按物料、仓库、托盘号 Ctl、库位 LocationId 查询可用库存；若未指定仓库，则从当前部门有权限的仓库中查找。
     3. 若指定了 Ctl，则按托盘分组；否则按库位分组，逐组累加库存，直到满足 GoodsNum。
     4. 将本次命中的库位与数量写回明细：累计 PickNum，并把销售单号集合拼接到 BusinessId。
     5. 将主单 TCkOrders.Status 更新为 "1"（已锁定）。
     6. 把“按物料汇总”的结果转换成“按库位汇总”的任务数据，避免同一库位重复创建任务。
     7. 校验该库位是否已存在同单出库任务；若不存在，则进入 createLocationOutboundTasks。
     8. 按仓库维度发送 TCallNotice 出库通知。
   * 关键点: 这里完成的是库存占用与任务拆分，不是最终库存扣减。

#### 库存锁定与拣货任务落地 (Stock Locking / Picking Task Creation)

   * 接口: createLocationOutboundTasks（由 confirmOut 内部调用）
   * 业务逻辑:
     1. 对命中的每条 TMiStock 回写 OccupyNum，并把库存状态设为 "1"（已锁定）。
     2. 逐条生成 TCkPickingwavegoods 拣货任务，带出托盘号、库位、批次、库存主键、来源单号、仓库等信息。
     3. 初始化拣货任务 RecNum = 0、ConfirmStatus = "0"（待执行），并挂接同一个 CallNoticeId。
   * 数据变更:
     * 更新 TMiStock。
     * 插入 TCkPickingwavegoods。
     * 发送 TCallNotice。
   * 关键点: 本类到这里为止，已经完成出库资源占用和任务下发。

#### 调拨联动阶段 (Transfer)

    调拨出库是本类中的另一条专用支路，会同时联动生成一张入库通知单。

   * 接口: create / install
   * 业务逻辑:
     1. 创建一张 TCkOrders 调拨出库单，OrderType 和 CkType 都为调拨出库。
     2. 写入对应的 TCkOrderdetail 调拨明细。
     3. 同步创建一张 TRkWareNotice 调拨入库通知单，以及对应的 TRkWareNoticeTab 明细。
     4. 创建 TransferOrder，把出库单和入库单关联起来。
   * 关键点: 这里完成的是“调拨单据联动建单”，后续实际出库仍要继续走任务分配或确认链路。

#### 流程边界说明 (Boundary)

    从 TCkOrdersServiceImpl 代码来看，它主要负责“建单、审批、分流、锁库、建拣货任务、推送 IWMS”。

   * 关键点:
     * 本类没有完成最终的库存实扣。
     * 本类没有完成拣货任务归档。
     * 本类也没有把主单推进到“出库完成”终态。
   * 结论: 真正的拣货执行、库存扣减、任务完成与归档，发生在后续拣货/出库执行链路，而不是在本类中闭环完成。

### 出库执行闭环补充（TCkPickingwavegoods）

#### 拣货确认阶段 (Picking Confirmation)

    这一阶段对应实际执行出库任务后的确认动作，是本地出库链路真正开始“落账”的地方。

   * 接口: confirm
   * 业务逻辑:
     1. 校验提交的拣货确认明细不能为空。
     2. 按当前托盘/任务条件查询待拣任务，若未查到任务则直接报错。
     3. 要求本次确认必须把同一批待确认任务一起提交，否则拒绝确认。
     4. 先把出库主单 TCkOrders.Status 重置为 "0"，解除前一阶段的锁定态。
     5. 遍历每条 TCkPickingwavegoods，依次执行库存实扣、任务备份、明细累计出库量更新。
   * 关键点: confirm 使用的是拣货任务上的 RecNum（本次实际出库数量），而不是申请数量 ShelvesNum。

#### 库存实扣与资源释放阶段 (Stock Deduction / Resource Release)

   * 内部方法: updateTmiStock
   * 业务逻辑:
     1. 通过 DoctNumber 定位被锁定的 TMiStock 库存记录。
     2. 用库存现存量 ShelvesNum 减去本次实际出库量 RecNum。
     3. 若扣减后库存为 0，则直接删除该库存记录。
     4. 若扣减后仍有余量，则把库存状态恢复为 "0"，并把 OccupyNum 清零。
     5. 若当前库位已无任何库存，则把 TBaseStorageAreaLocation.Status 释放为 "0"。
     6. 若当前托盘号 Ctl 下已无库存，则把托盘 TBasePallet.Status 释放为 "0"。
   * 关键点: confirmOut 负责“占用库存”，confirm 才真正完成“库存实扣”。

#### 任务备份与明细回写阶段 (Task Backup / Detail Update)

   * 业务逻辑:
     1. 每条已确认的 TCkPickingwavegoods 都会复制到 TCkPickingwavegoodsBak。
     2. 备份记录的 ConfirmStatus 会被置为 "3"。
     3. 回写对应的 TCkOrderdetail：TrNum += RecNum，表示累计实际出库量增加。
     4. 清空本次明细上的 GoodsNum，避免旧的申请数量继续参与后续出库。
     5. 若 TrNum == ShelvesNum，则把明细 ConfirmStatus 更新为 "2"（全部完成）。
     6. 若 TrNum < ShelvesNum，则把明细 ConfirmStatus 从 "0" 推进为 "1"（部分完成）。
   * 关键点: 出库明细是否完成，取决于累计实际出库量 TrNum 是否追平申请数量 ShelvesNum。

#### 主单收口与归档阶段 (Order Convergence / Archiving)

    系统会在每次确认后，重新判断整张出库单是否已经全部完成。

   * 业务逻辑:
     1. 重新查询该出库单下全部 TCkOrderdetail。
     2. 只要还有任意一条明细 ConfirmStatus 不是 "2"，则主单仍未完结。
     3. 若主单未完结，则把 TCkOrders.ConfirmStatus 更新为 "1"（部分完成）。
     4. 若主单全部完成，则把 TCkOrders 备份到 TckOrdersBak。
     5. 同时把全部 TCkOrderdetail 备份到 TckOrderdetailBak，并补齐审核人、审核时间、申请人、驳回原因等主单信息。
     6. 备份完成后，物理删除原 TCkOrders 和 TCkOrderdetail 数据。
   * 关键点: 主单是否归档，不取决于是否生成过任务，而取决于所有明细是否都已完成实际出库。

#### 任务删除与通知关闭阶段 (Task Cleanup / Notice Closing)

   * 业务逻辑:
     1. 当前批次确认完成后，会删除对应的原始 TCkPickingwavegoods 任务。
     2. 再按 CallNoticeId 查询是否还存在未完成的同批呼叫任务。
     3. 若同一 CallNoticeId 下已无剩余任务，则关闭对应的 TCallNotice 出库通知。
   * 关键点: 通知关闭的判断粒度是 CallNoticeId，不是单条拣货任务。

#### 设备平台推送阶段 (Device Push)

    当某个呼叫批次下的本地出库任务全部结束后，系统会尝试把出库完成结果推送到设备管理平台。

   * 内部方法: sendDevice
   * 业务逻辑:
     1. 生成签名并组装请求头。
     2. 以已完成的出库主单和明细为基础，拼装外部表单数据。
     3. 调用设备平台 `batchSaveEntity` 接口推送出库完成结果。
     4. 不论成功还是失败，都会记录 DeviceLog 日志。
   * 关键点:
     * 成功时返回“推送成功出库完成”。
     * 失败时返回“出库完成，请求超时或失败”或签名失败提示。

#### 手工撤销补充 (Manual Cleanup)

    除正常确认链路外，代码中还保留了手工删除出库任务的兜底处理。

   * 接口: deleteTCkPickingwavegoodsByIds
   * 业务逻辑:
     1. 按任务查出对应托盘号 Ctl。
     2. 删除该托盘关联的出库任务记录。
     3. 将该托盘关联库存状态释放为 "0"。
   * 关键点: 这是异常处理或人工干预分支，不属于标准的出库完成闭环。