# 機能設計書 55-税率管理

## 概要

本ドキュメントは、Medusa ECプラットフォームにおける税率管理機能の設計を記述する。税率の設定・管理機能の詳細仕様を定義する。

### 本機能の処理概要

税率管理機能は、税地域（TaxRegion）に紐づく税率（TaxRate）の作成・更新・削除を行う機能である。各税率には税率（rate）、コード（code）、名前（name）、デフォルトフラグ（is_default）、結合フラグ（is_combinable）を設定できる。また、税率ルール（TaxRateRule）により、特定の商品や商品タイプ、配送オプションに対して異なる税率を適用できる。

**業務上の目的・背景**：国や地域によって税率や税制度が異なるため、ECサイトでは柔軟な税率設定が必要である。消費税、付加価値税（VAT）、軽減税率など、多様な税制に対応するための管理基盤が求められる。

**機能の利用シーン**：
1. 新しい国・地域への展開時の税率設定
2. 税制改正時の税率更新
3. 軽減税率対象商品への特別税率設定
4. 配送料への税率設定
5. 州・都道府県ごとの税率設定

**主要な処理内容**：
1. TaxRateの作成・更新・削除
2. TaxRateRuleの作成・更新・削除
3. デフォルト税率の設定
4. 結合可能税率の設定（州税+連邦税など）
5. 税率ルールによる条件付き税率設定

**関連システム・外部連携**：税率は税計算機能で使用され、カートや注文の税額計算に適用される。外部の税計算プロバイダーとも連携可能。

**権限による制御**：税率管理は管理者のみが実行可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 161 | 税リージョン作成画面 | 補助機能 | デフォルト税率の設定 |
| 162 | 税リージョン詳細画面 | 補助機能 | 税率一覧の表示 |
| 165 | 都道府県詳細画面 | 補助機能 | 都道府県別税率の表示 |
| 166 | 税率作成画面 | 主機能 | 新規税率の作成 |
| 167 | 税率編集画面 | 主機能 | 税率の編集 |
| 168 | 税オーバーライド作成画面 | 主機能 | 税オーバーライドの作成 |
| 169 | 税オーバーライド編集画面 | 主機能 | 税オーバーライドの編集 |

## 機能種別

CRUD操作

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| id | string | No | TaxRateのID（更新時） | txr_プレフィックス |
| tax_region_id | string | Yes | 税地域ID | 存在チェック |
| rate | number | No | 税率（%） | 0以上の数値 |
| code | string | Yes | 税率コード | 1文字以上 |
| name | string | Yes | 税率名 | 1文字以上 |
| is_default | boolean | No | デフォルトフラグ | - |
| is_combinable | boolean | No | 結合可能フラグ | - |
| rules | TaxRateRuleDTO[] | No | 税率ルールの配列 | - |
| created_by | string | No | 作成者ID | - |

### 入力データソース

- リクエストパラメータ（API経由）
- 管理画面からの入力

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | string | TaxRateのID |
| rate | number | 税率 |
| code | string | 税率コード |
| name | string | 税率名 |
| is_default | boolean | デフォルトフラグ |
| is_combinable | boolean | 結合可能フラグ |
| tax_region_id | string | 税地域ID |
| rules | TaxRateRuleDTO[] | 税率ルールの配列 |
| metadata | object | メタデータ |
| created_by | string | 作成者ID |

### 出力先

- API レスポンス（JSON形式）

## 処理フロー

### 処理シーケンス

```
1. 入力データの検証
   └─ tax_region_idの存在確認
2. TaxRateの作成/更新
   └─ taxRateService_.createまたはupdate
3. TaxRateRuleの処理
   └─ rulesが指定されている場合はルールを作成/更新
4. 結果の返却
   └─ シリアライズしてDTO形式で返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[入力データの検証]
    B --> C{税地域が存在?}
    C -->|No| D[エラー返却]
    C -->|Yes| E{作成 or 更新?}
    E -->|作成| F[TaxRate作成]
    E -->|更新| G[TaxRate更新]
    F --> H{rulesが指定?}
    G --> I{rulesが指定?}
    H -->|Yes| J[TaxRateRule作成]
    H -->|No| K[結果を返却]
    I -->|Yes| L[TaxRateRule更新]
    I -->|No| K
    J --> K
    L --> K
    D --> M[終了]
    K --> M
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-55-01 | デフォルト税率唯一性 | 同一税地域にデフォルト税率は1つのみ | is_default=trueの税率作成時 |
| BR-55-02 | 結合可能税率 | is_combinable=trueの場合、親税地域の税率と結合 | 州税と連邦税の組み合わせなど |
| BR-55-03 | ルール優先度 | 商品ID > 商品タイプID > デフォルト税率の順で適用 | 税計算時 |
| BR-55-04 | 州・都道府県税 | 州税は親の国税と結合可能 | 親税地域が存在する場合 |

### 計算ロジック

```typescript
// 税率適用の優先度
priorityScore = {
  productMatch + province: 1,
  productTypeMatch + province: 2,
  default + province: 3,
  productMatch + country: 4,
  productTypeMatch + country: 5,
  default + country: 6
}

// 結合可能税率の処理
if (rate.is_combinable && rate.tax_region.parent_id) {
  applicableRates = [rate, parentRate]
}
```

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 税率作成 | tax_rate | INSERT | 税率の新規作成 |
| ルール作成 | tax_rate_rule | INSERT | 税率ルールの作成 |
| 税率更新 | tax_rate | UPDATE | 税率の更新 |
| ルール更新 | tax_rate_rule | UPDATE/DELETE/INSERT | ルールの更新 |
| 税率削除 | tax_rate | DELETE | カスケードでルールも削除 |

### テーブル別操作詳細

#### tax_rate

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | id, rate, code, name, is_default, is_combinable, tax_region_id, created_by | リクエストパラメータから | - |
| UPDATE | rate, code, name, is_default, is_combinable | WHERE id = :id | - |

#### tax_rate_rule

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | id, reference, reference_id, tax_rate_id, created_by | rulesから変換 | - |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| NOT_FOUND | MedusaError | 税地域が存在しない | 正しいtax_region_idを指定 |
| INVALID_DATA | MedusaError | デフォルト税率が既に存在 | 既存のデフォルト税率を解除 |

### リトライ仕様

データベース一時エラー時はアプリケーション層でリトライ可能。

## トランザクション仕様

TaxRate、TaxRateRuleの操作は同一トランザクション内で実行される。@InjectTransactionManagerデコレータによりトランザクション管理される。

## パフォーマンス要件

- 単一TaxRate作成: 100ms以内
- インデックス: IDX_tax_rate_tax_region_id, IDX_single_default_regionを使用

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

- 認証: Admin API認証必須
- 認可: 管理者ロールが必要
- 監査ログ: created_byで作成者を記録

## 備考

- デフォルト税率はユニークインデックスで一意性を保証
- カスケード削除でrulesも自動削除

---

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

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

### 推奨読解順序

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

まず、税率関連のデータモデルを理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | tax-rate.ts | `packages/modules/tax/src/models/tax-rate.ts` | TaxRateの構造、rate, code, name, is_default, is_combinableを確認 |
| 1-2 | tax-rate-rule.ts | `packages/modules/tax/src/models/tax-rate-rule.ts` | TaxRateRuleの構造、reference, reference_idを確認 |

**読解のコツ**: is_defaultのユニークインデックスに注目。同一税地域で1つのデフォルト税率のみ許可される。

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

税率管理のメインメソッドを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | tax-module-service.ts | `packages/modules/tax/src/services/tax-module-service.ts` | createTaxRates, updateTaxRatesメソッドの実装 |

**主要処理フロー**:
1. **84-111行目**: createTaxRates - 税率の作成
2. **113-155行目**: createTaxRates_ - 内部実装（ルール作成含む）
3. **157-216行目**: updateTaxRates - 税率の更新
4. **218-261行目**: setTaxRateRulesForTaxRates - ルールの設定

#### Step 3: 優先度計算を理解する

税率適用の優先度計算を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | tax-module-service.ts | `packages/modules/tax/src/services/tax-module-service.ts` | prioritizeRatesの実装 |

**主要処理フロー**:
- **802-840行目**: prioritizeRates - 優先度スコアの計算

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

```
TaxModuleService.createTaxRates()
    │
    ├─ createTaxRates_()
    │      ├─ taxRateService_.create()
    │      │      └─ TaxRateの作成
    │      │
    │      └─ taxRateRuleService_.create()
    │             └─ TaxRateRuleの作成
    │
    └─ baseRepository_.serialize()
           └─ DTO形式にシリアライズ

TaxModuleService.updateTaxRates()
    │
    ├─ updateTaxRates_()
    │      ├─ setTaxRateRulesForTaxRates()
    │      │      └─ ルールの更新
    │      │
    │      └─ taxRateService_.update()
    │             └─ TaxRateの更新
    │
    └─ baseRepository_.serialize()
           └─ DTO形式にシリアライズ
```

### データフロー図

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

CreateTaxRateDTO ───▶ taxRateService_.create() ───▶ TaxRateDTO
        │
        ▼
rules[] ────────────▶ taxRateRuleService_      ───▶ TaxRateRuleDTO[]
                      .create()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| tax-module-service.ts | `packages/modules/tax/src/services/tax-module-service.ts` | ソース | 税モジュールのメインサービス |
| tax-rate.ts | `packages/modules/tax/src/models/tax-rate.ts` | ソース | TaxRateのデータモデル |
| tax-rate-rule.ts | `packages/modules/tax/src/models/tax-rate-rule.ts` | ソース | TaxRateRuleのデータモデル |
