# 帳票設計書 6-ZUGFeRD Embedded Invoice（埋め込み電子請求書）

## 概要

本ドキュメントは、Shopwareの注文管理システムにおけるZUGFeRD Embedded Invoice（埋め込み電子請求書）帳票の設計仕様を定義する。PDF形式の請求書にZUGFeRD XMLデータを埋め込んだハイブリッド帳票であり、人間可読なPDFと機械可読なXMLの両方を含む。

### 本帳票の処理概要

ZUGFeRD Embedded Invoice帳票は、通常のPDF請求書とZUGFeRD電子請求書（XML）を組み合わせたハイブリッド形式の帳票を生成する。PDFファイル内にXMLデータを埋め込むことで、人間が視覚的に確認できる請求書と、システムが自動処理できる構造化データの両方を単一ファイルで提供する。ZUGFeRD形式の本来の仕様に最も近い形式である。

**業務上の目的・背景**：ZUGFeRD Embedded Invoiceは「ハイブリッド請求書」とも呼ばれ、EU圏での電子請求書標準化において推奨される形式である。人間による確認が必要な場合はPDFとして閲覧し、会計システムへの取り込みが必要な場合は埋め込まれたXMLを抽出して処理できる。これにより、紙の請求書と同様の視認性を維持しながら、電子的な自動処理のメリットも享受できる。

**帳票の利用シーン**：B2B取引での電子請求書送付、政府機関への請求（人間確認とシステム処理の両方が必要な場合）、会計ソフトへの自動取り込み対応、アーカイブ保存時に利用される。

**主要な出力内容**：
1. PDF形式の請求書（人間可読）
   - 請求書番号、発行日
   - 販売者・購入者情報
   - 商品明細、税額、合計金額
2. 埋め込みXMLデータ（機械可読）
   - ZUGFeRD/XRechnung形式の構造化データ
   - システム間データ交換用

**帳票の出力タイミング**：管理画面の注文詳細画面から手動で生成、またはAPIを通じて生成される。

**帳票の利用者**：店舗管理者、経理担当者、取引先（人間・システム両方）

## 帳票種別

埋め込み電子請求書（ZUGFeRD Embedded Invoice / PDF+XML形式）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | 注文詳細画面 | /admin#/sw/order/detail/{orderId} | 「ドキュメント作成」ボタン |
| - | API | POST /api/_action/order/document/zugferd_embedded_invoice/create | API呼び出し |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | PDF（XMLデータ埋め込み） |
| ファイル拡張子 | .pdf |
| MIMEタイプ | application/pdf |
| 規格 | PDF/A-3、ZUGFeRD / XRechnung 3 |
| 埋め込みXML | ZugferdDocumentPdfMergerで結合 |
| ファイル名 | embedded_{filenamePrefix}{documentNumber}{filenameSuffix}.pdf |
| 出力方法 | ダウンロード / メール送付 |
| 文字コード | UTF-8 |

### PDF部分の仕様

| 項目 | 内容 |
|-----|------|
| ベース | InvoiceRenderer出力のPDF |
| 用紙サイズ | A4（デフォルト） |
| 向き | 縦（portrait）/ 横（landscape）設定可能 |
| コンテンツタイプ | application/pdf（必須） |

### 埋め込みXML部分の仕様

| 項目 | 内容 |
|-----|------|
| ベース | ZugferdRenderer出力のXML |
| 規格 | ZUGFeRD / XRechnung 3 |
| 埋め込み方式 | PDF/A-3準拠のファイル添付 |

### 番号範囲設定

| 項目 | 内容 |
|-----|------|
| 番号範囲技術名 | document_invoice（Invoiceと共通） |
| 番号生成 | InvoiceRendererで生成した番号を共有 |

## 帳票レイアウト

### レイアウト概要

ZUGFeRD Embedded Invoiceは、通常のPDF請求書（Invoice）と同じ視覚的レイアウトを持つ。違いは、PDF内部にXMLデータが埋め込まれている点である。

```
+---------------------------------------------+
|              PDF表示部分                     |
|  （Invoiceと同じレイアウト）                 |
|                                             |
|  +---------------------------------------+  |
|  |           ヘッダー部                   |  |
|  |  - ロゴ、請求書番号、日付              |  |
|  |  - 販売者・購入者情報                  |  |
|  +---------------------------------------+  |
|  |           明細部                       |  |
|  |  - 商品明細テーブル                    |  |
|  +---------------------------------------+  |
|  |           サマリー部                   |  |
|  |  - 小計、税額、合計                    |  |
|  +---------------------------------------+  |
|  |           フッター部                   |  |
|  |  - 会社情報、銀行口座情報              |  |
|  +---------------------------------------+  |
|                                             |
+---------------------------------------------+
|              埋め込みXMLデータ               |
|  （不可視・添付ファイルとして格納）          |
|  - ZUGFeRD/XRechnung XMLファイル            |
+---------------------------------------------+
```

### PDF部分

PDF部分のレイアウトはInvoice（請求書）帳票と同一。詳細は「1-Invoice（請求書）.md」を参照。

### 埋め込みXML部分

埋め込みXML部分の構造はZUGFeRD E-Invoice（電子請求書）と同一。詳細は「5-ZUGFeRD E-Invoice（電子請求書）.md」を参照。

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| orderId | 注文ID | Yes |
| deepLinkCode | セキュリティコード | No |
| forceDocumentCreation | 強制作成フラグ | No |

### 前提条件

1. PDF請求書（InvoiceRenderer）の出力が成功すること
2. ZUGFeRD XML（ZugferdRenderer）の出力が成功すること
3. PDF請求書のコンテンツタイプが'application/pdf'であること

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

### 参照テーブル一覧

InvoiceRendererおよびZugferdRendererが参照するテーブルと同一。

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| order | 注文情報 | 主テーブル |
| order_customer | 顧客情報 | order.id = order_customer.order_id |
| order_address | 請求先住所 | order.billing_address_id = order_address.id |
| order_line_item | 明細情報 | order.id = order_line_item.order_id |
| order_delivery | 配送情報 | order.id = order_delivery.order_id |
| product | 商品情報 | order_line_item.product_id = product.id |
| currency | 通貨情報 | order.currency_id = currency.id |
| document_base_config | 帳票設定 | 設定情報取得 |

## 計算仕様

### 計算項目一覧

計算仕様はInvoiceRendererおよびZugferdRendererと同一。PDF部分とXML部分で一貫した金額が表示される。

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| 明細小計 | unitPrice * quantity | 通貨設定に従う | PDF・XML共通 |
| 税額 | 税率別計算 | 通貨設定に従う | PDF・XML共通 |
| 合計 | SUM(明細小計) + 配送料 | - | PDF・XML共通 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[DocumentGeneratorController::createDocuments] --> B[DocumentGenerator::generate]
    B --> C[DocumentRendererRegistry::render]
    C --> D[ZugferdEmbeddedRenderer::render]
    D --> E[InvoiceRenderer::render]
    E --> F{PDF生成成功?}
    F -->|No| G[エラー返却]
    F -->|Yes| H[setSuccessDocumentNumbers]
    H --> I[ZugferdRenderer::render]
    I --> J{XML生成成功?}
    J -->|No| K[エラー: Electronic invoice is null]
    J -->|Yes| L[embedXMLIntoPDF]
    L --> M{コンテンツタイプ確認}
    M -->|非PDF| N[エラー: Application type must be pdf]
    M -->|PDF| O[ZugferdDocumentPdfMerger]
    O --> P[setAdditionalCreatorTool]
    P --> Q[generateDocument]
    Q --> R[downloadString]
    R --> S[ファイル名変更 embedded_]
    S --> T[setContent]
    T --> U[addSuccess]
    U --> V[エラーマージ]
    V --> W[終了]
```

### 処理の特徴

1. **2段階レンダリング**：
   - 最初にInvoiceRendererでPDFを生成
   - 次にZugferdRendererでXMLを生成
   - 最後に両者を結合

2. **番号共有**：
   - InvoiceRendererで生成した請求書番号をZugferdRendererに引き渡し
   - setSuccessDocumentNumbers()で番号を同期

3. **PDFマージ**：
   - horstoeko/zugferdライブラリのZugferdDocumentPdfMergerを使用
   - PDF/A-3形式でXMLを埋め込み

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| PDF生成失敗 | InvoiceRendererエラー | （InvoiceRendererのエラー） | Invoice生成条件を確認 |
| XML生成失敗 | ZugferdRendererエラー | Electronic invoice is null | ZUGFeRD生成条件を確認 |
| 非PDFコンテンツ | コンテンツタイプが非PDF | Application type must be "application/pdf" | PDF形式で出力 |
| マージエラー | PDF結合処理の例外 | （例外メッセージ） | ライブラリエラーを確認 |

### エラーの集約

InvoiceRenderer、ZugferdRenderer、ZugferdEmbeddedRenderer自身のエラーを全て集約して返却。

```php
$renderResult->assign([
    'errors' => array_merge(
        $invoice->getErrors(),
        $electronicInvoice->getErrors(),
        $renderResult->getErrors()
    )
]);
```

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 1注文あたり最大100明細 |
| 目標出力時間 | 単一PDF+XML: 3秒以内 |
| 同時出力数上限 | API経由で一括生成可能 |

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

- PDFへのアクセスはdeepLinkCodeによる認証が必要
- 管理画面からのアクセスにはdocument:create権限が必要
- 埋め込みXMLにVAT番号、税番号、銀行口座情報を含む
- PDF/A-3形式により長期アーカイブに対応

## 備考

- ファイル名には「embedded_」プレフィックスが自動付与
- Shopwareバージョン情報がCreatorToolとして埋め込まれる
- PDF部分とXML部分で同一の請求書番号を使用
- InvoiceRendererとZugferdRendererの両方が成功した場合のみ生成される
- A11y（アクセシビリティ）HTMLは生成されない

---

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

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

### 推奨読解順序

#### Step 1: 全体構造を理解する

ZugferdEmbeddedRendererが2つのレンダラーを組み合わせる仕組みを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ZugferdEmbeddedRenderer.php | `src/Core/Checkout/Document/Renderer/ZugferdEmbeddedRenderer.php` | render()、embedXMLIntoPDF()、setSuccessDocumentNumbers() |

**読解のコツ**: ZugferdEmbeddedRendererは「Composite（合成）」パターンを使用し、InvoiceRendererとZugferdRenderer（electronicRenderer）の2つを組み合わせている。コンストラクタで両方のレンダラーを受け取り、順次呼び出す。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ZugferdEmbeddedRenderer.php | `src/Core/Checkout/Document/Renderer/ZugferdEmbeddedRenderer.php` | TYPE定数、render()メソッド |

**主要処理フロー（ZugferdEmbeddedRenderer）**:
- **15行目**: TYPE = 'zugferd_embedded_invoice' 定数定義
- **20-25行目**: コンストラクタ（invoiceRenderer、electronicRenderer、shopwareVersion）
- **37-42行目**: render()メソッド - InvoiceRenderer呼び出し後、embedXMLIntoPDF()
- **47-86行目**: embedXMLIntoPDF()メソッド - PDF/XML結合処理
- **92-104行目**: setSuccessDocumentNumbers()メソッド - 番号同期

#### Step 3: PDFマージ処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ZugferdEmbeddedRenderer.php | `src/Core/Checkout/Document/Renderer/ZugferdEmbeddedRenderer.php` | embedXMLIntoPDF()の詳細 |

**主要処理フロー（embedXMLIntoPDF）**:
- **50行目**: setSuccessDocumentNumbers()で番号同期
- **51行目**: electronicRenderer.render()でXML生成
- **54-59行目**: コンテンツタイプチェック（application/pdf必須）
- **61-64行目**: XML取得（electronicDoc）
- **69-72行目**: ZugferdDocumentPdfMerger使用
- **70行目**: setAdditionalCreatorTool('Shopware@' + version)
- **71-72行目**: generateDocument(), downloadString()
- **74行目**: ファイル名変更（'embedded_' + 元の名前）
- **75行目**: setContent()でPDF更新

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

```
DocumentGeneratorController::createDocuments()
    |
    +-- DocumentGenerator::generate()
            |
            +-- DocumentRendererRegistry::render()
            |       |
            |       +-- ZugferdEmbeddedRenderer::render()
            |               |
            |               +-- InvoiceRenderer::render()
            |               |       |
            |               |       +-- （Invoice生成処理）
            |               |       +-- PDFレンダリング
            |               |
            |               +-- embedXMLIntoPDF()
            |                       |
            |                       +-- setSuccessDocumentNumbers()
            |                       |       |
            |                       |       +-- 番号をoperations.configに設定
            |                       |
            |                       +-- ZugferdRenderer::render()
            |                       |       |
            |                       |       +-- （ZUGFeRD XML生成処理）
            |                       |
            |                       +-- コンテンツタイプ確認
            |                       |
            |                       +-- ZugferdDocumentPdfMerger
            |                               |
            |                               +-- setAdditionalCreatorTool()
            |                               +-- generateDocument()
            |                               +-- downloadString()
            |
            +-- MediaService::saveFile()
            +-- DocumentRepository::upsert()
```

### データフロー図

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

Request (JSON)
    |
    v
DocumentGenerateOperation
    |
    v
+---------------------------+
|  ZugferdEmbeddedRenderer  |
+---------------------------+
            |
            v
+---------------------------+
|    InvoiceRenderer        |
|    (PDF生成)              |
+---------------------------+
            |
            v
    RenderedDocument (PDF)
            |
            +-- number取得
            |
            v
+---------------------------+
|    setSuccessDocumentNumbers|
|    (番号をconfig設定)      |
+---------------------------+
            |
            v
+---------------------------+
|    ZugferdRenderer        |
|    (XML生成)              |
+---------------------------+
            |
            v
    RenderedDocument (XML)
            |
            +------------------+
                               |
            v                  v
+---------------------------+
|  ZugferdDocumentPdfMerger |
|  (PDF + XML 結合)         |
+---------------------------+
            |
            v
    [PDF+XML ハイブリッドファイル]
    (embedded_xxx.pdf)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ZugferdEmbeddedRenderer.php | `src/Core/Checkout/Document/Renderer/ZugferdEmbeddedRenderer.php` | ソース | ハイブリッドレンダラー |
| InvoiceRenderer.php | `src/Core/Checkout/Document/Renderer/InvoiceRenderer.php` | ソース | PDF請求書レンダラー |
| ZugferdRenderer.php | `src/Core/Checkout/Document/Renderer/ZugferdRenderer.php` | ソース | ZUGFeRD XMLレンダラー |
| ZugferdBuilder.php | `src/Core/Checkout/Document/Zugferd/ZugferdBuilder.php` | ソース | XMLビルダー |
| ZugferdDocument.php | `src/Core/Checkout/Document/Zugferd/ZugferdDocument.php` | ソース | XML生成ラッパー |
| invoice.html.twig | `src/Core/Framework/Resources/views/documents/invoice.html.twig` | テンプレート | PDF請求書テンプレート |
| DocumentGenerator.php | `src/Core/Checkout/Document/Service/DocumentGenerator.php` | ソース | 帳票生成サービス |

### 依存するレンダラー

ZugferdEmbeddedRendererは以下の2つのレンダラーに依存する。各レンダラーの詳細は対応する帳票設計書を参照：

1. **InvoiceRenderer** - PDF請求書
   - 詳細: `1-Invoice（請求書）.md`

2. **ZugferdRenderer** - ZUGFeRD電子請求書
   - 詳細: `5-ZUGFeRD E-Invoice（電子請求書）.md`
