# 帳票設計書 1-注文エクスポートCSV

## 概要

本ドキュメントは、Medusaプラットフォームにおける注文エクスポートCSV機能の帳票設計書である。注文データをCSV形式でエクスポートし、外部システムとの連携や分析用途に使用される。

### 本帳票の処理概要

注文エクスポートCSV帳票は、管理者が注文データを一括でCSV形式にエクスポートする機能を提供する。エクスポート処理はバックグラウンドで非同期に実行され、完了時に管理者へ通知が送信される。

**業務上の目的・背景**：ECサイト運営において、注文データを外部の会計システム、分析ツール、倉庫管理システムなどと連携させる必要がある。また、定期的な売上分析やレポート作成のために、注文データを一括でダウンロードできることが求められる。本帳票は、これらの業務要件を満たすために、注文情報を標準的なCSV形式でエクスポートする機能を提供する。

**帳票の利用シーン**：月次・週次の売上レポート作成時、外部会計システムへのデータ連携時、顧客分析・購買傾向分析時、倉庫・物流システムへの出荷データ連携時、税務申告用データ準備時に利用される。

**主要な出力内容**：
1. 注文基本情報（注文ID、表示ID、ステータス、作成日時）
2. 顧客情報（氏名、メールアドレス、顧客ID）
3. 配送先住所情報（住所、市区町村、郵便番号、国コード）
4. フルフィルメント・支払いステータス
5. 金額情報（小計、配送料、割引額、ギフトカード額、返金額、税額、合計、通貨コード）

**帳票の出力タイミング**：管理画面の注文一覧から「エクスポート」操作を実行した際に非同期で生成される。生成完了後、通知フィードを通じて管理者にダウンロードリンクが提供される。

**帳票の利用者**：ECサイト管理者、経理担当者、データ分析担当者、倉庫・物流担当者

## 帳票種別

一覧表（注文データの一覧エクスポート）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| 41 | 注文一覧画面 | /admin/orders | エクスポートボタン |
| 42 | 注文エクスポート画面 | /admin/orders/export | エクスポート実行 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | CSV |
| 用紙サイズ | 該当なし |
| 向き | 該当なし |
| ファイル名 | `{timestamp}-order-exports.csv`（例：1708785600000-order-exports.csv） |
| 出力方法 | ダウンロード（通知フィード経由） |
| 文字コード | UTF-8 |

### CSV固有設定

| 項目 | 内容 |
|-----|------|
| 区切り文字 | カンマ（,） |
| 囲み文字 | ダブルクォート（"） |
| ヘッダー行 | あり |
| CSVインジェクション対策 | 有効（preventCsvInjection: true） |
| 空フィールド値 | 空文字列 |

## 帳票レイアウト

### レイアウト概要

CSVファイルは1行目にヘッダー、2行目以降にデータ行が出力される。各注文が1行として出力される。

```
┌─────────────────────────────────────────────────────────────┐
│ ヘッダー行（カラム名）                                        │
├─────────────────────────────────────────────────────────────┤
│ データ行1（注文1）                                           │
│ データ行2（注文2）                                           │
│ ...                                                         │
│ データ行N（注文N）                                           │
└─────────────────────────────────────────────────────────────┘
```

### ヘッダー部（CSVカラム定義）

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | Order_ID | 注文の一意識別子 | order.id | 文字列 |
| 2 | Display_ID | 表示用注文番号 | order.display_id | 数値 |
| 3 | Order status | 注文ステータス | order.status | 文字列（draft/pending/completed/canceled） |
| 4 | Date | 注文作成日時 | order.created_at | ISO8601形式 |
| 5 | Customer First name | 顧客の名 | order.customer.first_name | 文字列 |
| 6 | Customer Last name | 顧客の姓 | order.customer.last_name | 文字列 |
| 7 | Customer Email | 顧客メールアドレス | order.customer.email | 文字列 |
| 8 | Customer ID | 顧客ID | order.customer.id | 文字列 |
| 9 | Shipping Address 1 | 配送先住所1 | order.shipping_address.address_1 | 文字列 |
| 10 | Shipping Address 2 | 配送先住所2 | order.shipping_address.address_2 | 文字列 |
| 11 | Shipping Country Code | 配送先国コード | order.shipping_address.country_code | ISO 3166-1 alpha-2 |
| 12 | Shipping City | 配送先市区町村 | order.shipping_address.city | 文字列 |
| 13 | Shipping Postal Code | 配送先郵便番号 | order.shipping_address.postal_code | 文字列 |
| 14 | Shipping Region ID | 配送先リージョンID | order.region_id | 文字列 |
| 15 | Fulfillment Status | フルフィルメントステータス | 計算値（getLastFulfillmentStatus） | 文字列 |
| 16 | Payment Status | 支払いステータス | 計算値（getLastPaymentStatus） | 文字列 |
| 17 | Subtotal | 小計 | order.subtotal | 数値 |
| 18 | Shipping Total | 配送料合計 | order.shipping_total | 数値 |
| 19 | Discount Total | 割引合計 | order.discount_total | 数値 |
| 20 | Gift Card Total | ギフトカード使用額 | order.gift_card_total | 数値 |
| 21 | Refunded Total | 返金合計 | order.refunded_total | 数値 |
| 22 | Tax Total | 税額合計 | order.tax_total | 数値 |
| 23 | Total | 総合計 | order.total | 数値 |
| 24 | Currency Code | 通貨コード | order.currency_code | ISO 4217 |

### 明細部

該当なし（各注文が1行として出力される）

### フッター部

該当なし（CSVファイルのためフッターなし）

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| ステータスフィルタ | draft以外の注文のみ抽出（status: { $ne: "draft" }） | Yes（固定） |
| カスタムフィルタ | API呼び出し時に指定されたフィルタ条件 | No |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| - | Query Graphのデフォルト順序 | - |

### 改ページ条件

該当なし（CSVファイルのため改ページなし）
ただし、データ取得は50件ずつページング処理される（バッチサイズ: 50）

## データベース参照仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| order | 注文基本情報 | メインエンティティ |
| customer | 顧客情報 | order.customer経由 |
| address | 配送先住所 | order.shipping_address経由 |
| payment_collection | 支払い情報 | order.payment_collections経由 |
| fulfillment | フルフィルメント情報 | order.fulfillments経由 |

### テーブル別参照項目詳細

#### order

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| id | Order_ID | - | - |
| display_id | Display_ID | - | - |
| status | Order status | status != 'draft' | draftは除外 |
| created_at | Date | - | - |
| region_id | Shipping Region ID | - | - |
| subtotal | Subtotal | - | - |
| shipping_total | Shipping Total | - | - |
| discount_total | Discount Total | - | - |
| gift_card_total | Gift Card Total | - | - |
| tax_total | Tax Total | - | - |
| total | Total | - | - |
| currency_code | Currency Code | - | - |

#### customer

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| id | Customer ID | - | - |
| first_name | Customer First name | - | 未設定時は空文字 |
| last_name | Customer Last name | - | 未設定時は空文字 |
| email | Customer Email | - | 未設定時は空文字 |

#### address（shipping_address）

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| address_1 | Shipping Address 1 | - | 未設定時は空文字 |
| address_2 | Shipping Address 2 | - | 未設定時は空文字 |
| country_code | Shipping Country Code | - | 未設定時は空文字 |
| city | Shipping City | - | 未設定時は空文字 |
| postal_code | Shipping Postal Code | - | 未設定時は空文字 |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| Fulfillment Status | getLastFulfillmentStatus(order) | - | フルフィルメントの最新ステータスを算出 |
| Payment Status | getLastPaymentStatus(order) | - | 支払いコレクションの最新ステータスを算出 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[POST /admin/orders/export] --> B[exportOrdersWorkflow開始]
    B --> C[exportOrdersStep実行]
    C --> D{バックグラウンド処理}
    D --> E[Query Graphでデータ取得]
    E --> F{データあり?}
    F -->|Yes| G[normalizeOrderForExport]
    G --> H[json2csvでCSV変換]
    H --> I[ファイルストリームに書き込み]
    I --> J{次ページあり?}
    J -->|Yes| E
    J -->|No| K[ファイルアップロード完了]
    F -->|No| K
    K --> L[sendNotificationsStep]
    L --> M[通知送信]
    M --> N[完了]
    D -->|失敗時| O[notifyOnFailureStep]
    O --> P[エラー通知送信]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| エクスポート失敗 | バックグラウンド処理での予期せぬエラー | "Failed to export orders, please try again later." | 通知フィードに表示、再試行を促す |
| データなし | 条件に合致する注文がない場合 | - | 空のCSVファイルが生成される |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 数千〜数万件 |
| 目標出力時間 | バックグラウンド処理のため制限なし |
| 同時出力数上限 | ワークフローエンジンの設定に依存 |
| バッチサイズ | 50件（デフォルト、カスタマイズ可能） |

## セキュリティ考慮事項

- CSVインジェクション対策が有効化されている（preventCsvInjection: true）
- Admin API認証が必要（AuthenticatedMedusaRequest）
- 出力ファイルは一時的なストレージに保存され、URLを通じてアクセス
- 顧客の個人情報（メールアドレス、住所）が含まれるため、ダウンロード後の取り扱いに注意が必要

## 備考

- 非同期処理のため、即座にCSVファイルは返却されない
- 処理完了後、通知フィード（admin-ui）を通じてダウンロードリンクが提供される
- MIMEタイプは "text/csv" として設定される
- version フィールドは出力から除外される
- payment_collections と fulfillments は計算処理後に除外される

---

## コードリーディングガイド

本帳票を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

まず、エクスポートされるデータの構造と型定義を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | export-orders.ts | `packages/core/core-flows/src/order/steps/export-orders.ts` | ExportOrdersStepInput型（行19-23）とExportOrdersStepOutput型（行25-28）で入出力の構造を確認 |
| 1-2 | export-orders.ts | `packages/core/core-flows/src/order/workflows/export-orders.ts` | ExportOrdersDTO型（行14-25）でワークフローへの入力パラメータを確認 |

**読解のコツ**: TypeScriptの型定義を最初に確認することで、データの流れと構造を把握できる。FilterableOrderPropsは@medusajs/framework/typesからインポートされている。

#### Step 2: エントリーポイントを理解する

処理の起点となるAPIルートを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | route.ts | `packages/medusa/src/api/admin/orders/export/route.ts` | POST関数（行11-23）がエントリーポイント |

**主要処理フロー**:
1. **行15-16**: リクエストからselectFieldsとfilterを抽出
2. **行18-20**: exportOrdersWorkflowを実行
3. **行22**: トランザクションIDをレスポンスとして返却（202 Accepted）

#### Step 3: ワークフローの構成を理解する

ワークフローの全体像と各ステップの役割を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | export-orders.ts | `packages/core/core-flows/src/order/workflows/export-orders.ts` | ワークフロー定義（行89-142）、async: true, backgroundExecution: trueの設定（行93-95）に注目 |

**主要処理フロー**:
- **行92-95**: exportOrdersStepをバックグラウンドで実行
- **行97-111**: 失敗時の通知設定
- **行113-118**: ファイル情報の取得（useRemoteQueryStep）
- **行120-140**: 成功時の通知送信

#### Step 4: CSV出力ステップの詳細を理解する

実際のCSV生成ロジックを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | export-orders.ts | `packages/core/core-flows/src/order/steps/export-orders.ts` | normalizeOrderForExport関数（行32-65）でCSVカラムへの変換ロジックを確認 |
| 4-2 | export-orders.ts | `packages/core/core-flows/src/order/steps/export-orders.ts` | exportOrdersStep（行67-178）でページング処理とストリーム出力を確認 |

**主要処理フロー**:
- **行70-71**: DIコンテナからQueryとFileModuleを取得
- **行73-77**: ファイルアップロードストリームを取得
- **行86-101**: fieldsの定義（必須フィールドとリレーションの指定）
- **行103-159**: ページングループでデータ取得・変換・書き込み
- **行127-128**: ステータス計算（getLastPaymentStatus, getLastFulfillmentStatus）
- **行137-145**: json2csvでCSV変換（CSVインジェクション対策有効）

#### Step 5: ステータス計算ロジックを理解する

フルフィルメントと支払いのステータス計算を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | aggregate-status.ts | `packages/core/core-flows/src/order/utils/aggregate-status.ts` | getLastFulfillmentStatusとgetLastPaymentStatus関数 |

### プログラム呼び出し階層図

```
POST /admin/orders/export (route.ts:11)
    │
    └─ exportOrdersWorkflow (export-orders.ts:89)
           │
           ├─ exportOrdersStep (export-orders.ts:67) [async, background]
           │      ├─ query.graph() - データ取得
           │      ├─ normalizeOrderForExport() (export-orders.ts:32) - データ正規化
           │      │      ├─ getLastPaymentStatus() - 支払いステータス計算
           │      │      └─ getLastFulfillmentStatus() - フルフィルメントステータス計算
           │      ├─ json2csv() - CSV変換
           │      └─ writeStream.write() - ファイル出力
           │
           ├─ notifyOnFailureStep - 失敗時通知設定
           │
           ├─ useRemoteQueryStep - ファイル情報取得
           │
           └─ sendNotificationsStep - 成功通知送信
```

### データフロー図

```
[入力]                      [処理]                              [出力]

API Request            exportOrdersWorkflow                  通知 + CSVファイル
(filter, select)       ┌──────────────────────┐
       │               │                      │
       ▼               │  exportOrdersStep    │
┌────────────┐         │  ┌────────────────┐  │              ┌─────────────┐
│ フィルタ   │──────────│▶│ Query Graph    │  │              │ CSVファイル  │
│ 条件       │         │  └───────┬────────┘  │              │ (text/csv)  │
└────────────┘         │          │           │              └──────┬──────┘
                       │          ▼           │                     │
                       │  ┌────────────────┐  │                     │
                       │  │ normalize +    │  │                     │
                       │  │ json2csv       │──│─────────────────────┘
                       │  └────────────────┘  │
                       │          │           │
                       │          ▼           │              ┌─────────────┐
                       │  ┌────────────────┐  │              │ 通知         │
                       │  │ File Upload    │  │              │ (admin-ui)  │
                       │  └────────────────┘  │              └──────┬──────┘
                       │                      │                     │
                       │  sendNotifications   │─────────────────────┘
                       └──────────────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| route.ts | `packages/medusa/src/api/admin/orders/export/route.ts` | ソース | APIエンドポイント定義 |
| export-orders.ts | `packages/core/core-flows/src/order/workflows/export-orders.ts` | ソース | ワークフロー定義 |
| export-orders.ts | `packages/core/core-flows/src/order/steps/export-orders.ts` | ソース | CSV出力ステップ |
| aggregate-status.ts | `packages/core/core-flows/src/order/utils/aggregate-status.ts` | ソース | ステータス計算ユーティリティ |
| middlewares.ts | `packages/medusa/src/api/admin/orders/middlewares.ts` | ソース | ルートミドルウェア設定 |
| order.ts | `packages/core/js-sdk/src/admin/order.ts` | ソース | クライアントSDK |
