# 画面設計書 19-支払先管理画面（デスクトップ）

## 概要

本ドキュメントは、Actual Budgetアプリケーションにおけるデスクトップ向け支払先管理画面の設計仕様を定義する。

### 本画面の処理概要

支払先管理画面（デスクトップ）は、支払先（Payee）の一覧表示と管理を行う画面である。支払先の名前編集、お気に入り設定、カテゴリ学習設定、ルール管理、マージ、削除などの機能を提供する。

**業務上の目的・背景**：取引に関連付けられる支払先を一元管理することで、取引入力時の支払先選択を効率化し、ルールによる自動カテゴリ設定を可能にする。また、重複する支払先のマージや未使用支払先の整理により、データの整合性を維持する。

**画面へのアクセス方法**：サイドバーの「Payees」メニューをクリックしてアクセスする。URLパターンは `/payees` である。

**主要な操作・処理内容**：
1. 支払先一覧の表示（フィルタリング対応）
2. 支払先名の編集
3. お気に入り設定の切り替え
4. カテゴリ学習設定の切り替え
5. 支払先に関連するルールの表示/作成
6. 複数支払先のマージ
7. 支払先の削除
8. 未使用支払先のフィルタ表示

**画面遷移**：
- 遷移元：サイドバー
- 遷移先：ルール管理モーダル、ルール編集モーダル、カテゴリ学習設定モーダル

**権限による表示制御**：特になし。認証済みユーザーであれば全機能を利用可能。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 17 | 支払先管理 | 主機能 | 支払先の一覧表示・編集 |
| 18 | ルールエンジン | 補助機能 | 支払先に基づくルール設定 |

## 画面種別

一覧

## URL/ルーティング

`/payees`

## 入出力項目

| 項目名 | 項目ID | 入力/出力 | 型 | 必須 | 説明 |
|--------|--------|----------|-----|------|------|
| フィルタ | filter | 入力 | string | No | 支払先検索用キーワード |
| 初期選択ID | initialSelectedIds | 入力 | string[] | No | 初期選択する支払先ID（location.state経由） |

## 表示項目

| 項目名 | 説明 | データソース |
|--------|------|-------------|
| ページタイトル | 「Payees」固定 | i18n |
| 選択中の支払先数 | 「X payees」または「No payees selected」 | selected.items.size |
| 支払先一覧テーブル | 支払先のリスト | payees |
| 未使用支払先ボタン | 「Show X unused payees」 | orphanedPayees |

### 支払先テーブル列

| 列名 | 説明 |
|------|------|
| 選択チェックボックス | 複数選択用 |
| Name | 支払先名（編集可能） |

## イベント仕様

### 1-フィルタ入力

検索フィールドにキーワードを入力すると、支払先一覧がフィルタリングされる。フィルタはnormalized stringで比較される。

### 2-支払先名編集

支払先行のName列をクリックすると編集モードになり、名前を変更できる。変更はonUpdate関数でpayees-batch-changeを呼び出して保存。

### 3-選択メニュー操作

選択中の支払先がある場合、メニューボタンから以下の操作が可能：
- **Delete**：選択した支払先を削除
- **Merge**：選択した支払先をマージ（最初に選択したものがターゲット）
- **Favorite/Unfavorite**：お気に入り設定切り替え
- **Learn/Unlearn categories**：カテゴリ学習設定切り替え

### 4-ルール関連操作

各支払先行のコンテキストメニューから：
- **View rules**：manage-rulesモーダルを開き、支払先のルールを表示
- **Create rule**：edit-ruleモーダルを開き、支払先条件付きの新規ルールを作成

### 5-未使用支払先フィルタ

「Show X unused payees」ボタンを押下すると、取引に使用されていない支払先（orphans）のみ表示。再度押下で全支払先表示に戻る。

### 6-カテゴリ学習設定

「Category learning settings」ボタンを押下すると、payee-category-learningモーダルが開く。

### 7-全選択/選択解除

テーブルヘッダーのチェックボックスを押下すると、全支払先を選択/選択解除する（Shift押下でrange select）。

## データベース更新仕様

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 画面表示 | payees | SELECT | 全支払先を取得 |
| 画面表示 | payee_mapping | SELECT | 孤児支払先を取得 |
| 名前編集 | payees | UPDATE | 支払先名を更新 |
| お気に入り設定 | payees | UPDATE | favoriteを更新 |
| カテゴリ学習設定 | payees | UPDATE | learn_categoriesを更新 |
| マージ | payees | UPDATE/DELETE | 支払先をマージ |
| マージ | payee_mapping | UPDATE | マッピングを更新 |
| 削除 | payees | DELETE | 支払先を削除 |

### テーブル別更新項目詳細

#### payees

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | name | 新しい名前 | 名前編集時 |
| UPDATE | favorite | true/false | お気に入り切り替え時 |
| UPDATE | learn_categories | true/false | カテゴリ学習切り替え時 |
| DELETE | - | id = 指定ID | 削除時 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|------------|
| M001 | 情報 | Filter payees... | 検索プレースホルダー |
| M002 | 情報 | No payees selected | 支払先未選択時 |
| M003 | 情報 | X payees | X件の支払先選択時 |
| M004 | 情報 | Show all payees | 未使用フィルタON時 |
| M005 | 情報 | Show X unused payees | 未使用支払先がある場合 |
| M006 | 情報 | No payees | 支払先がない場合 |
| M007 | 情報 | Category learning settings | ボタンテキスト |

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| 支払先データなし | 「No payees」を表示 |
| sync-eventでrules変更 | ルールカウントを再取得 |
| undo-eventでpayees/payee_mapping変更 | 孤児支払先を再取得、ルールカウントを再取得 |

## 備考

- usePayeesフックで支払先データを取得
- usePayeeRuleCountsフックで各支払先のルール数を取得
- SelectedProviderで複数選択状態を管理
- 振替口座支払先（transfer_acct != null）は選択不可
- memoizeOneでpayeesById計算をキャッシュ
- PayeeMenuコンポーネントでPopoverメニュー表示
- PayeeTableコンポーネントで一覧表示

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | models/index.d.ts | `packages/loot-core/types/models/` | PayeeEntityの型定義 |

**読解のコツ**: name, favorite, learn_categories, transfer_acctフィールドに注目。transfer_acctがnullでない場合は振替口座用支払先。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ManagePayeesPage.tsx | `packages/desktop-client/src/components/payees/ManagePayeesPage.tsx` | ページコンポーネント |

**主要処理フロー**:
1. **行11-18**: location.stateからinitialSelectedIdsを取得
2. **行19-22**: PageコンポーネントでManagePayeesWithDataをラップ

#### Step 3: データ管理コンポーネントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ManagePayeesWithData.tsx | `packages/desktop-client/src/components/payees/ManagePayeesWithData.tsx` | データ取得・イベント処理 |

**主要処理フロー**:
1. **行24-26**: usePayees, usePayeeRuleCountsでデータ取得
2. **行28-33**: refetchOrphanedPayeesで孤児支払先を取得
3. **行35-53**: useEffectでデータロードとsync-eventリスナー設定
4. **行55-81**: undo-eventリスナーで再取得処理
5. **行83-87**: onViewRulesでmanage-rulesモーダル呼び出し
6. **行89-111**: onCreateRuleでedit-ruleモーダル呼び出し（支払先条件付き）
7. **行119-121**: onBatchChangeでpayees-batch-change呼び出し
8. **行123-143**: onMergeでpayees-merge呼び出し

#### Step 4: UIコンポーネントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | ManagePayees.tsx | `packages/desktop-client/src/components/payees/ManagePayees.tsx` | 一覧UI |

**主要処理フロー**:
1. **行87-92**: フィルタ状態管理
2. **行94-107**: filteredPayeesでフィルタリング（名前、orphanedOnly）
3. **行109**: useSelectedで選択状態管理
4. **行117-133**: onUpdateで名前/favorite/learn_categories更新
5. **行135-139**: getSelectableIdsで振替口座以外を選択可能に
6. **行141-148**: onDeleteで削除処理
7. **行150-168**: onFavoriteでお気に入り切り替え
8. **行170-194**: onLearnでカテゴリ学習切り替え
9. **行196-201**: onMergeでマージ処理
10. **行203-205**: onChangeCategoryLearningでモーダル表示

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

```
ManagePayeesPage (エントリーポイント)
    |
    +-- Page (ヘッダー「Payees」)
    |
    +-- ManagePayeesWithData (データ管理)
            |
            +-- usePayees (支払先データ)
            +-- usePayeeRuleCounts (ルールカウント)
            +-- refetchOrphanedPayees (孤児支払先)
            |
            +-- ManagePayees (UI)
                    |
                    +-- View (ヘッダー行)
                    |       +-- Button (選択メニュー)
                    |       |       +-- Popover
                    |       |               +-- PayeeMenu
                    |       |                       +-- Delete
                    |       |                       +-- Merge
                    |       |                       +-- Favorite
                    |       |                       +-- Learn
                    |       +-- Button (未使用支払先フィルタ)
                    |       +-- Search (フィルタ入力)
                    |
                    +-- SelectedProvider
                    |       +-- PayeeTableHeader
                    |       +-- PayeeTable
                    |               +-- PayeeTableRow (複数)
                    |
                    +-- View (フッター行)
                            +-- Button (Category learning settings)
                                    --> pushModal('payee-category-learning')
```

### データフロー図

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

DB payees         --->  usePayees                  --->  payees array
                        (Redux selector)

DB payee_mapping  --->  payees-get-orphaned        --->  orphans array
                        (send)

DB rules          --->  usePayeeRuleCounts         --->  ruleCounts Map
                        (フック)

User input        --->  getNormalisedString        --->  filteredPayees
(filter)                (正規化比較)

User action       --->  send('payees-batch-change')--->  支払先更新
(Edit/Delete)           {updated/deleted}

User action       --->  send('payees-merge')       --->  支払先マージ
(Merge)                 {targetId, mergeIds}

User action       --->  pushModal                  --->  モーダル表示
(View/Create rule)      ('manage-rules'/'edit-rule')

sync-event        --->  refetchRuleCounts          --->  ルールカウント再取得
(rules table)

undo-event        --->  refetchOrphanedPayees      --->  孤児支払先再取得
(payees table)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ManagePayeesPage.tsx | `packages/desktop-client/src/components/payees/ManagePayeesPage.tsx` | ソース | ページコンポーネント |
| ManagePayeesWithData.tsx | `packages/desktop-client/src/components/payees/ManagePayeesWithData.tsx` | ソース | データ管理 |
| ManagePayees.tsx | `packages/desktop-client/src/components/payees/ManagePayees.tsx` | ソース | 一覧UI |
| PayeeTable.tsx | `packages/desktop-client/src/components/payees/PayeeTable.tsx` | ソース | テーブルコンポーネント |
| PayeeTableRow.tsx | `packages/desktop-client/src/components/payees/PayeeTableRow.tsx` | ソース | テーブル行 |
| PayeeMenu.tsx | `packages/desktop-client/src/components/payees/PayeeMenu.tsx` | ソース | 選択メニュー |
| usePayees.ts | `packages/desktop-client/src/hooks/usePayees.ts` | ソース | 支払先データフック |
| usePayeeRuleCounts.ts | `packages/desktop-client/src/hooks/usePayeeRuleCounts.ts` | ソース | ルールカウントフック |
| useSelected.ts | `packages/desktop-client/src/hooks/useSelected.ts` | ソース | 選択状態管理フック |
| Search.tsx | `packages/desktop-client/src/components/common/Search.tsx` | ソース | 検索コンポーネント |
