> For the complete documentation index, see [llms.txt](https://lmile.gitbook.io/lmile-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lmile.gitbook.io/lmile-docs/fulfillment-api/shipment-collect.md).

# Shipment Collect — 出荷準備中（一括集荷）

出荷（shipment）配下の全単位（[Units](/lmile-docs/fulfillment-api/units.md)）を、スキャン操作なしでまとめて**集荷済み**にし、出荷を**出荷準備中**へ進めます。倉庫アプリ（QR スキャン）を使わない運用向けで、確保済みの出荷を Web 操作だけで出荷準備中にでき、必要なら配送ラベルの発行も同時に行えます。

> **Base URL** `https://api.lmile.io` · **認証** `x-ingest-secret` ヘッダー または operator JWT（`Authorization: Bearer`）（[詳細](/lmile-docs/getting-started/authentication.md)） · `shop` はリクエストボディに含めます（API キーで呼ぶ場合は省略できます）

> 「出荷準備中」は出荷のステータス値ではなく、**配下の全単位（取消済みを除く）が集荷済みになった状態**の呼び名です。1 単位ずつスキャンで集荷する場合は倉庫アプリの集荷（Shelf Pick）を使います。本 API はそれを出荷単位で一括に行う操作です。

## エンドポイント

| Method | Path                            | 用途                              |
| ------ | ------------------------------- | ------------------------------- |
| `POST` | `/api/routing/shipment/collect` | 出荷配下の全単位を集荷済みにする（配送ラベル発行はオプション） |

***

## `POST` /api/routing/shipment/collect

指定 shipment の未集荷の単位をすべて集荷済みにします。`issueLabel` で配送ラベルの発行を同時に行うかを指定します。

### リクエスト

```http
POST https://api.lmile.io/api/routing/shipment/collect
x-ingest-secret: {INGEST_SECRET}
Content-Type: application/json
```

```json
{
  "shop": "demo-store.myshopify.com",
  "shipmentId": "11494bc4-f45f-4d0b-9d68-fd26c1a503ec",
  "issueLabel": true,
  "actorEmail": "ops@demo-store.example"
}
```

### ボディパラメータ

| パラメータ                  | 型                       |  必須 | 説明                                                              |
| ---------------------- | ----------------------- | :-: | --------------------------------------------------------------- |
| `shop`                 | string                  |  ✓  | 店舗ドメイン（API キーで呼ぶ場合は省略できます）                                      |
| `shipmentId`           | string (uuid)           |  ✓  | 対象 shipment。同一 shop に実在すること                                     |
| `issueLabel`           | boolean                 |  ✓  | `true` で集荷確定後に配送ラベルを発行（発行済みなら再発行しません）。`false` はラベルに触れません        |
| `actorEmail`           | string                  |     | 操作者のメール（操作ログ用・任意）                                               |
| `suppressCustomerMail` | boolean                 |     | `true` にすると、この操作ではお届け状況メールの「出荷準備」を送りません。省略時は店舗の通知設定どおり          |
| `trackingNumber`       | string                  |     | 手書きの送り状の追跡番号（1〜200 文字）。`issueLabel: true` とは一緒に送れません            |
| `carrierCode`          | string                  |     | 配送業者のコード（1〜100 文字）。配送状況の自動取得に使います。`trackingNumber` と一緒のときだけ送れます |
| `trackingCompany`      | string                  |     | 配送業者の名前（1〜100 文字）。`trackingNumber` と一緒のときだけ送れます                 |
| `trackingUrl`          | string (http/https URL) |     | 追跡ページの URL。`trackingNumber` と一緒のときだけ送れます                        |

### レスポンス

```json
{
  "ok": true,
  "shipmentId": "11494bc4-f45f-4d0b-9d68-fd26c1a503ec",
  "collected": 3,
  "alreadyCollected": false,
  "units": { "total": 3, "picked": 3 },
  "shelf": { "decremented": 2, "markedWithoutDecrement": 1 },
  "label": {
    "issued": true,
    "shipmentId": "11494bc4-f45f-4d0b-9d68-fd26c1a503ec",
    "trackingNumber": "123456789012",
    "labelPdfPath": "labels/..."
  }
}
```

| フィールド                          | 説明                                                                                                                                                                                 |
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `collected`                    | 今回のリクエストで集荷済みにした単位数                                                                                                                                                                |
| `alreadyCollected`             | 全単位が既に集荷済みだった場合 `true`（集荷の更新なし）                                                                                                                                                    |
| `customerMailSuppressed`       | `suppressCustomerMail: true` を受け付けたか                                                                                                                                               |
| `trackingSaved`                | `trackingNumber` を受け付けて保存したか。送ったのに `true` が返らない場合は保存されていません                                                                                                                        |
| `units.total` / `units.picked` | 集荷対象の単位数（取消済み・倉庫間移動中を除く）と、うち集荷済みの数                                                                                                                                                 |
| `shelf.decremented`            | 集荷と同時に保管棚の在庫を 1 つ減らせた単位数（MFC 自己在庫のみ対象）                                                                                                                                             |
| `shelf.markedWithoutDecrement` | 棚に現物が無く、在庫を減らさず集荷だけ確定した単位数（黙って無視せずここで返します）                                                                                                                                         |
| `transferRequiredUnits`        | 倉庫間移動（出荷元変更）フロー中で対象外にした単位の id（混在時のみ）                                                                                                                                               |
| `label`                        | `issueLabel: true` のときのみ。`issued: false` の場合は `reason`（`already_issued` = 発行済み / `group_not_collected` = 集約グループの他レグが未集荷 / `engraved` = 刻印注文 / `failed` = 発行失敗）と、失敗時は `error` を返します |

### 挙動・冪等性

* **集荷済みにできるのは確保済（`secured` / `oversell_secured`）の出荷のみ**です。未確保（引き当てのみ）・出荷済み・取消済みは `409 invalid_state` で拒否します。
* 取消済みの単位は対象外です。倉庫間移動（出荷元変更）フロー中の単位も対象外で、対象にできる単位が 1 つも無い場合は `409 transfer_required`、混在する場合は残りを進めて `transferRequiredUnits` で対象外を知らせます。
* **再送は冪等です**: 集荷済みの単位はそのまま維持し、未集荷の単位だけを進めます。全単位が集荷済みなら `alreadyCollected: true` を返します（このとき `issueLabel: true` ならラベル処理だけを実行するため、**ラベル発行だけが失敗した出荷の再試行**にも同じリクエストを使えます）。
* **MFC 自己在庫の単位は、集荷と同時に保管棚の在庫を 1 つ減らします**（スキャン集荷と同じ帳簿処理）。棚に現物が見つからない場合も集荷は成立し、減らせなかった数を `shelf.markedWithoutDecrement` で返します。棚の減算処理そのものが失敗した場合は `409` で中断し、処理済みの単位は集荷済みのまま残ります（再送で残りだけ前進します）。
* `suppressCustomerMail: true` で送ると、この注文の「出荷準備」のお届け状況メールを送りません。止まるのはその段だけで、発送完了などのメールは店舗の通知設定どおり送られます。全単位が集荷済み（`alreadyCollected: true`）の再送では何もしません。
* **手書きの送り状の追跡番号**: 配送ラベルを発行しない出荷では、送り状を箱に付けるときに `trackingNumber`（と `trackingCompany` / `trackingUrl`）を送ると、その出荷の追跡番号として保存します。
  * 保存した番号は、[出荷済みにする](/lmile-docs/fulfillment-api/fulfillment.md) で追跡番号を送らなかったときにそのまま使われます。配送業者の窓口で番号をもらう運用なら、ここでは送らず出荷済みにするときに送ってください。
  * もう一度送ると、追跡番号・配送業者の名前・URL をまとめて置き換えます（送らなかった名前・URL は空になります。`carrierCode` は送ったときだけ置き換えます）。
  * 送れるのは確保済みの出荷だけです。出荷済みなど、出荷準備中にできない状態の出荷には送れません。
  * 配送ラベルを発行済みの出荷と、複数店舗分割の 1 箱をまとめる MFC 集約グループの出荷には送れません（下の「エラー」）。
* **`issueLabel: true` のラベル発行**:
  * 発行済み（追跡番号あり）の出荷には再発行しません（`reason: "already_issued"`）。
  * 複数店舗分割の 1 箱をまとめる **MFC 集約グループ**は、グループ**全レグが集荷済みになった時点**でグループ先頭の出荷（追跡番号の保有者）に 1 枚だけ発行します。他レグが未集荷の間は `reason: "group_not_collected"` で発行を保留します（残りのレグを集荷すると発行されます）。
  * 刻印注文には発行しません（`reason: "engraved"`。刻印品の顧客ラベルは転送先の倉庫レグで発行される運用のため）。
  * 発行に失敗しても**集荷自体は成功**し、`label.error` で理由を返します（出荷詳細にもエラーとして表示され、本 API の再送または [Address Recovery](/lmile-docs/fulfillment-api/address-recovery.md) の `retry-label` で再試行できます）。

## エラー

エンドポイント固有:

| Status | 条件                                                                                                                                                                   | レスポンス例                                                                                                                  |
| :----: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
|  `400` | バリデーション失敗（`shipmentId` が uuid でない / `issueLabel` 欠落 等）                                                                                                               | `{ "ok": false, "error_kind": "invalid_input", "details": [...] }`                                                      |
|  `400` | 追跡番号の組み合わせが受けられない（`trackingNumber` なしで `carrierCode` / `trackingCompany` / `trackingUrl` / `issueLabel: true` と `trackingNumber` を一緒に / 集約グループの出荷に `trackingNumber`） | `{ "ok": false, "error_kind": "invalid_input", "error": "trackingNumber cannot be set with issueLabel" }`               |
|  `409` | 確保済み以外（出荷済みなど）の出荷に `trackingNumber` を送った                                                                                                                             | `{ "ok": false, "error_kind": "invalid_state", "error": "trackingNumber cannot be set on a 'shipped' shipment" }`       |
|  `409` | 配送ラベルを発行済みの出荷に `trackingNumber` を送った                                                                                                                                 | `{ "ok": false, "error_kind": "label_already_issued", "error": "shipment already has a shipping label" }`               |
|  `404` | `shipmentId` が同一 shop に存在しない                                                                                                                                         | `{ "ok": false, "error_kind": "shipment_not_found", "error": "shipment not found for shop" }`                           |
|  `409` | 確保済み以外からの集荷 / 集荷対象の単位が無い                                                                                                                                             | `{ "ok": false, "error_kind": "invalid_state", "error": "shipment status 'allocated' cannot transition to collected" }` |
|  `409` | 全単位が倉庫間移動（出荷元変更）フロー中                                                                                                                                                 | `{ "ok": false, "error_kind": "transfer_required", "units": [...] }`                                                    |
|  `409` | 棚の減算処理が失敗（処理済みの単位は集荷済みのまま。再送で残りだけ前進）                                                                                                                                 | `{ "ok": false, "error_kind": "collect_depart_failed", "unitId": "..." }`                                               |

共通エラー（`401` / `400` / `403` / `405` / `500` / `503`）は [Error Codes](/lmile-docs/reference/error-codes.md) を参照。

## データモデル

* `sot.lm_fulfillment_units.picked_at` / `picked_by` — 集荷完了の正本（単位ごと）。本 API は未集荷の対象単位にこれを立てます。operator JWT 経由は検証済スタッフ ID、機械間 secret 経由は `"manual_collect"` を記録します。
* `public.lm_v_fulfillment_shipments.is_collected` — 出荷単位の「出荷準備中」判定（取消済みを除く全単位に `picked_at` がある = `true`）。出荷作業一覧の表示はこの列を使います。
* `sot.lm_shelf_inventory` / `sot.lm_shelf_inventory_logs` — MFC 自己在庫の保管棚。集荷と同時の棚 −1 は原子処理（RPC `lm_self_inventory_unit_depart`）で行い、消費ログに単位・注文が記録されます。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://lmile.gitbook.io/lmile-docs/fulfillment-api/shipment-collect.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
