# 帳票設計書 5-ZUGFeRD E-Invoice（電子請求書）

## 概要

本ドキュメントは、Shopwareの注文管理システムにおけるZUGFeRD電子請求書（ZUGFeRD E-Invoice）帳票の設計仕様を定義する。ZUGFeRDはEU規格に準拠した電子請求書形式であり、機械可読なXML形式で出力される。

### 本帳票の処理概要

ZUGFeRD E-Invoice帳票は、EU（特にドイツ）の電子請求書規格「ZUGFeRD」に準拠したXML形式の請求書を生成する。人間による可読性よりも、システム間のデータ交換を目的とした構造化データとして出力される。XRechnung 3プロファイルに準拠し、請求書の自動処理や会計システムへの取り込みを可能にする。

**業務上の目的・背景**：EU圏では電子請求書の標準化が進んでおり、特にB2B取引やB2G（企業対政府）取引では電子請求書の使用が義務化されている地域がある。ZUGFeRDはEN 16931（欧州電子請求書標準）に準拠しており、自動処理による経理業務の効率化、入力ミスの削減、処理コストの低減を実現する。

**帳票の利用シーン**：B2B取引での自動請求処理、政府機関への請求、会計システムへの自動取り込み、EDI（電子データ交換）連携時に利用される。

**主要な出力内容**：
1. 請求書番号、発行日、通貨
2. 販売者情報（会社名、住所、VAT番号、税番号、銀行口座情報）
3. 購入者情報（顧客名、住所、メールアドレス）
4. 商品明細（商品名、数量、単価、税率、小計）
5. 配送情報（配送料）
6. 割引・値引き情報
7. 税額サマリー
8. 支払い情報（支払い方法、支払い期限、支払い済み金額）

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

**帳票の利用者**：店舗管理者、経理担当者、取引先システム（自動処理）

## 帳票種別

電子請求書（ZUGFeRD E-Invoice / XML形式）

## 利用画面

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

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | XML |
| ファイル拡張子 | .xml |
| MIMEタイプ | application/xml |
| 規格 | ZUGFeRD / XRechnung 3 |
| プロファイル | PROFILE_XRECHNUNG_3 |
| ファイル名 | {filenamePrefix}{documentNumber}{filenameSuffix}.xml |
| 出力方法 | ダウンロード / システム連携 |
| 文字コード | UTF-8 |

### 準拠規格

| 項目 | 内容 |
|-----|------|
| EN 16931 | 欧州電子請求書標準 |
| ZUGFeRD | ドイツ電子請求書フォーラム規格 |
| XRechnung | ドイツ政府向け電子請求書規格 |
| UN/CEFACT | 国連貿易円滑化センター標準 |

### 番号範囲設定

| 項目 | 内容 |
|-----|------|
| 番号範囲技術名 | document_invoice（Invoiceと共通） |
| 番号生成 | NumberRangeValueGenerator使用 |

## 帳票レイアウト

### レイアウト概要

ZUGFeRD E-Invoiceは視覚的なレイアウトを持たず、構造化されたXMLデータとして出力される。

```xml
<rsm:CrossIndustryInvoice>
    <!-- 請求書メタデータ -->
    <rsm:ExchangedDocumentContext>...</rsm:ExchangedDocumentContext>

    <!-- 請求書ヘッダー情報 -->
    <rsm:ExchangedDocument>
        <ram:ID>請求書番号</ram:ID>
        <ram:TypeCode>380</ram:TypeCode>
        <ram:IssueDateTime>発行日</ram:IssueDateTime>
    </rsm:ExchangedDocument>

    <!-- 取引情報 -->
    <rsm:SupplyChainTradeTransaction>
        <!-- 明細行 -->
        <ram:IncludedSupplyChainTradeLineItem>...</ram:IncludedSupplyChainTradeLineItem>

        <!-- 取引当事者 -->
        <ram:ApplicableHeaderTradeAgreement>
            <ram:SellerTradeParty>販売者</ram:SellerTradeParty>
            <ram:BuyerTradeParty>購入者</ram:BuyerTradeParty>
        </ram:ApplicableHeaderTradeAgreement>

        <!-- 配送情報 -->
        <ram:ApplicableHeaderTradeDelivery>...</ram:ApplicableHeaderTradeDelivery>

        <!-- 支払い・サマリー -->
        <ram:ApplicableHeaderTradeSettlement>
            <ram:SpecifiedTradePaymentTerms>支払い条件</ram:SpecifiedTradePaymentTerms>
            <ram:SpecifiedTradeSettlementHeaderMonetarySummation>金額サマリー</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
        </ram:ApplicableHeaderTradeSettlement>
    </rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>
```

### 販売者情報（SellerTradeParty）

| No | 項目名 | 説明 | データ取得元 | XML要素 |
|----|-------|------|-------------|---------|
| 1 | 会社名 | 販売者名 | config.companyName | ram:Name |
| 2 | 住所 | 会社住所 | config.companyStreet等 | ram:PostalTradeAddress |
| 3 | 税番号 | 税務登録番号 | config.taxNumber | ram:SpecifiedTaxRegistration (FC) |
| 4 | VAT番号 | 付加価値税番号 | config.vatId | ram:SpecifiedTaxRegistration (VA) |
| 5 | メール | 連絡先メール | config.companyEmail | ram:URIUniversalCommunication |
| 6 | 担当者 | 代表者名 | config.executiveDirector | ram:DefinedTradeContact |
| 7 | 電話 | 連絡先電話 | config.companyPhone | ram:TelephoneUniversalCommunication |

### 購入者情報（BuyerTradeParty）

| No | 項目名 | 説明 | データ取得元 | XML要素 |
|----|-------|------|-------------|---------|
| 1 | 顧客名 | 購入者名 | order.orderCustomer | ram:Name |
| 2 | 顧客番号 | 顧客ID | customer.customerNumber | ram:ID |
| 3 | メール | 連絡先メール | customer.email | ram:URIUniversalCommunication |
| 4 | 住所 | 請求先住所 | billingAddress | ram:PostalTradeAddress |

### 明細行（IncludedSupplyChainTradeLineItem）

| No | 項目名 | 説明 | データ取得元 | XML要素 |
|----|-------|------|-------------|---------|
| 1 | 行番号 | 明細行位置 | lineItem.position | ram:AssociatedDocumentLineDocument/ram:LineID |
| 2 | 商品名 | 商品名称 | lineItem.label | ram:SpecifiedTradeProduct/ram:Name |
| 3 | 商品番号 | 商品コード | product.productNumber | ram:SpecifiedTradeProduct/ram:SellerAssignedID |
| 4 | EAN | JANコード | product.ean | ram:SpecifiedTradeProduct/ram:GlobalID |
| 5 | メーカー | 製造者名 | product.manufacturer.name | ram:SpecifiedTradeProduct/ram:BrandName |
| 6 | 数量 | 注文数量 | lineItem.quantity | ram:SpecifiedLineTradeDelivery/ram:BilledQuantity |
| 7 | 単価 | 税抜単価 | lineItem.unitPrice (net) | ram:NetPriceProductTradePrice/ram:ChargeAmount |
| 8 | 税率 | 適用税率 | calculatedTax.taxRate | ram:ApplicableTradeTax/ram:RateApplicablePercent |
| 9 | 小計 | 行合計（税抜） | totalNet | ram:SpecifiedLineTradeSettlement/ram:SpecifiedTradeSettlementLineMonetarySummation |

### 金額サマリー（SpecifiedTradeSettlementHeaderMonetarySummation）

| No | 項目名 | 説明 | データ取得元 | XML要素 |
|----|-------|------|-------------|---------|
| 1 | 明細合計 | 明細行小計合計 | lineTotal | ram:LineTotalAmount |
| 2 | 追加料金 | 配送料等 | chargeAmount | ram:ChargeTotalAmount |
| 3 | 値引き合計 | 割引合計 | allowanceAmount | ram:AllowanceTotalAmount |
| 4 | 税抜合計 | 税抜総額 | order.amountNet | ram:TaxBasisTotalAmount |
| 5 | 税額 | 税額合計 | amountTotal - amountNet | ram:TaxTotalAmount |
| 6 | 税込合計 | 請求総額 | order.amountTotal | ram:GrandTotalAmount |
| 7 | 支払い済み | 既払い金額 | paidAmount | ram:TotalPrepaidAmount |
| 8 | 支払い金額 | 支払い残額 | amountTotal - paidAmount | ram:DuePayableAmount |

## 出力条件

### 抽出条件

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

### バリデーション

ZugferdDocumentValidatorによる出力前検証を実施。検証エラーがある場合は生成失敗となる。

### 対応する明細行タイプ

| タイプ | 処理 |
|-------|------|
| PRODUCT_LINE_ITEM_TYPE | 商品として明細行に追加 |
| CUSTOM_LINE_ITEM_TYPE | 商品として明細行に追加 |
| PROMOTION_LINE_ITEM_TYPE | 割引/追加料金として追加 |
| CREDIT_LINE_ITEM_TYPE | 割引として追加 |

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

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| 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 |
| product_manufacturer | メーカー情報 | product.manufacturer_id = manufacturer.id |
| currency | 通貨情報 | order.currency_id = currency.id |
| document_base_config | 帳票設定 | 販売者情報取得 |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| 税抜単価 | (price - tax) / quantity | 小数点2桁 | isGross=trueの場合 |
| 明細小計 | getPriceWithFallback(tax, price) | - | 税抜金額 |
| 税額 | tax.getTax() | - | 税率別 |
| 追加料金合計 | SUM(chargeAmount) | - | 配送料含む |
| 値引き合計 | SUM(allowanceAmount) | - | プロモーション等 |

### 税カテゴリコード

| 税率 | コード | 説明 |
|-----|--------|------|
| 0% | Z | ZERO_RATED_GOODS（ゼロ税率商品） |
| その他 | S | STANDARD_RATE（標準税率） |

### 支払い方法コード（ZugferdPaymentMeans）

| 支払い方法 | コード | 説明 |
|-----------|--------|------|
| 現金 | 10 | UNTDID_4461_10 |
| 請求書払い/前払い | 30 | UNTDID_4461_30（銀行振込） |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[DocumentGeneratorController::createDocuments] --> B[DocumentGenerator::generate]
    B --> C[DocumentRendererRegistry::render]
    C --> D[ZugferdRenderer::render]
    D --> E[OrderRepository::search]
    E --> F[ZugferdInvoiceOrdersEventイベント]
    F --> G[createDocument]
    G --> H[DocumentConfigLoader::load]
    H --> I[NumberRangeValueGenerator::getValue]
    I --> J[ZugferdBuilder::buildDocument]
    J --> K[ZugferdDocument生成]
    K --> L{各種情報設定}
    L --> M[withBuyerInformation]
    L --> N[withSellerInformation]
    L --> O[withDelivery]
    L --> P[withTaxes]
    L --> Q[withGeneralOrderData]
    L --> R[addLineItems]
    R --> S[withProductLineItem / withDiscountItem]
    S --> T[ZugferdDocument::getContent]
    T --> U[ZugferdDocumentValidator]
    U --> V{バリデーション}
    V -->|成功| W[XMLコンテンツ取得]
    V -->|失敗| X[エラー: electronicInvoiceViolation]
    W --> Y[RenderedDocument生成]
    Y --> Z[終了]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| 請求先住所なし | billingAddressが取得できない | Billing address not found | 注文の請求先住所を設定 |
| 顧客情報なし | orderCustomerが取得できない | Customer not found | 注文の顧客情報を確認 |
| 価格エラー | 価格がnullまたはマイナス | Price can't be negative or null | 明細行の価格を確認 |
| 支払い金額超過 | paidAmount > amountTotal | Paid amount is greater than order total amount | 支払い金額を確認 |
| バリデーションエラー | XML検証失敗 | electronicInvoiceViolation | エラー内容に従って修正 |

## パフォーマンス要件

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

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

- XMLへのアクセスはdeepLinkCodeによる認証が必要
- 管理画面からのアクセスにはdocument:create権限が必要
- VAT番号、税番号などの機密情報を含むため取り扱い注意
- 銀行口座情報（IBAN、BIC）の表示

## 備考

- ZUGFeRD E-InvoiceはInvoice設定（document_invoice）の番号範囲を共有
- A11y（アクセシビリティ）対応HTMLは生成されない（fileTypes: [xml]で上書き）
- horstoeko/zugferdライブラリを使用したXML生成
- 子明細行（getChildren()）の再帰的処理に対応
- ZugferdInvoiceGeneratedEventイベントで生成後のカスタマイズ可能

---

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

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

### 推奨読解順序

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

ZUGFeRD固有のデータ構造とXML生成の仕組みを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ZugferdDocument.php | `src/Core/Checkout/Document/Zugferd/ZugferdDocument.php` | XML生成ラッパー。mappedPrices、withXXXメソッド群、getContent() |
| 1-2 | ZugferdBuilder.php | `src/Core/Checkout/Document/Zugferd/ZugferdBuilder.php` | ビルダークラス。buildDocument()、addLineItems()、matchByType() |

**読解のコツ**: ZugferdDocumentはhorstoeko/zugferdライブラリのZugferdDocumentBuilderをラップし、Shopware固有のデータ構造から変換を行う。

#### Step 2: レンダラー層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ZugferdRenderer.php | `src/Core/Checkout/Document/Renderer/ZugferdRenderer.php` | TYPE='zugferd_invoice'、render()、createDocument() |

**主要処理フロー（ZugferdRenderer）**:
- **24行目**: TYPE = 'zugferd_invoice' 定数定義
- **26-28行目**: FILE_EXTENSION = 'xml'、FILE_CONTENT_TYPE = 'application/xml'
- **55-87行目**: render()メソッド
- **89-132行目**: createDocument()メソッド - ドキュメント生成
- **96行目**: InvoiceRenderer::TYPEの設定を使用（番号範囲共有）
- **117行目**: ZugferdBuilder::buildDocument()呼び出し

#### Step 3: ビルダー層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ZugferdBuilder.php | `src/Core/Checkout/Document/Zugferd/ZugferdBuilder.php` | buildDocument()全体フロー |
| 3-2 | ZugferdDocument.php | `src/Core/Checkout/Document/Zugferd/ZugferdDocument.php` | 各withXXXメソッドの詳細 |

**主要処理フロー（ZugferdBuilder::buildDocument）**:
- **35-84行目**: buildDocument()メソッド
- **60-66行目**: ZugferdDocument生成とチェーンメソッド
- **68行目**: addLineItems()で明細行追加
- **70-79行目**: 支払い情報追加（paid状態、支払い方法）
- **81行目**: ZugferdInvoiceGeneratedEventイベント

**主要処理フロー（ZugferdDocument）**:
- **75-100行目**: getContent() - バリデーション実行とXML取得
- **102-129行目**: withBuyerInformation() - 購入者情報設定
- **138-163行目**: withSellerInformation() - 販売者情報設定
- **165-200行目**: withProductLineItem() - 商品明細追加
- **202-242行目**: withDiscountItem() - 割引/追加料金
- **253-277行目**: withDelivery() - 配送料追加
- **279-298行目**: withTaxes() - 税情報追加
- **392-414行目**: summary() - 金額サマリー設定

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

```
DocumentGeneratorController::createDocuments()
    |
    +-- DocumentGenerator::generate()
            |
            +-- DocumentRendererRegistry::render()
            |       |
            |       +-- ZugferdRenderer::render()
            |               |
            |               +-- getOrdersLanguageId()
            |               +-- OrderDocumentCriteriaFactory::create()
            |               +-- OrderRepository::search()
            |               +-- EventDispatcher::dispatch(ZugferdInvoiceOrdersEvent)
            |               |
            |               +-- createDocument()
            |                       |
            |                       +-- DocumentConfigLoader::load()
            |                       +-- NumberRangeValueGenerator::getValue()
            |                       +-- OrderRepository::createVersion()
            |                       |
            |                       +-- ZugferdBuilder::buildDocument()
            |                               |
            |                               +-- ZugferdDocument生成
            |                               |       |
            |                               |       +-- withBuyerInformation()
            |                               |       +-- withSellerInformation()
            |                               |       +-- withDelivery()
            |                               |       +-- withTaxes()
            |                               |       +-- withGeneralOrderData()
            |                               |       +-- withBuyerReference()
            |                               |
            |                               +-- addLineItems()
            |                               |       |
            |                               |       +-- matchByType()
            |                               |               +-- withProductLineItem()
            |                               |               +-- withDiscountItem()
            |                               |
            |                               +-- addPaymentInfo()
            |                               +-- EventDispatcher::dispatch(ZugferdInvoiceGeneratedEvent)
            |                               |
            |                               +-- ZugferdDocument::getContent()
            |                                       |
            |                                       +-- summary()
            |                                       +-- ZugferdDocumentValidator
            |                                       +-- zugferdBuilder.getContent()
            |
            +-- MediaService::saveFile()
            +-- DocumentRepository::upsert()
```

### データフロー図

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

OrderEntity             ZugferdBuilder
    |                           |
    +-- orderCustomer           v
    +-- billingAddress    ZugferdDocument
    +-- lineItems               |
    +-- deliveries              +-- withBuyerInformation()
    +-- price                   +-- withSellerInformation()
                                +-- withDelivery()
                                +-- withTaxes()
                                +-- withGeneralOrderData()
                                        |
DocumentConfiguration           +-- addLineItems()
    |                                   |
    +-- companyName                     +-- withProductLineItem() x N
    +-- companyStreet                   +-- withDiscountItem() x N
    +-- taxNumber                       |
    +-- vatId                    +-- getContent()
    +-- bankIban/bankBic                |
    +-- paymentDueDate           +-- summary()
                                 +-- ZugferdDocumentValidator
                                        |
                                        v
                                 [XMLコンテンツ]
                                        |
                                        v
                              RenderedDocument
                              (xml, application/xml)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ZugferdRenderer.php | `src/Core/Checkout/Document/Renderer/ZugferdRenderer.php` | ソース | ZUGFeRDレンダラー |
| ZugferdBuilder.php | `src/Core/Checkout/Document/Zugferd/ZugferdBuilder.php` | ソース | XMLビルダー |
| ZugferdDocument.php | `src/Core/Checkout/Document/Zugferd/ZugferdDocument.php` | ソース | XML生成ラッパー |
| ZugferdInvoiceOrdersEvent.php | `src/Core/Checkout/Document/Zugferd/ZugferdInvoiceOrdersEvent.php` | ソース | 注文イベント |
| ZugferdInvoiceGeneratedEvent.php | `src/Core/Checkout/Document/Zugferd/ZugferdInvoiceGeneratedEvent.php` | ソース | 生成完了イベント |
| ZugferdInvoiceItemAddedEvent.php | `src/Core/Checkout/Document/Zugferd/ZugferdInvoiceItemAddedEvent.php` | ソース | 明細追加イベント |
| DocumentConfiguration.php | `src/Core/Checkout/Document/DocumentConfiguration.php` | ソース | 設定データ構造 |
| AmountCalculator.php | `src/Core/Checkout/Cart/Price/AmountCalculator.php` | ソース | 金額計算 |
