# 画面設計書 335-マイ休暇作成

## 概要

本ドキュメントは、休暇管理モジュールにおける自分の休暇申請作成画面に関する設計書です。

### 本画面の処理概要

**業務上の目的・背景**：従業員が自分自身の休暇申請を行うための画面です。有給休暇、病欠、特別休暇などの休暇タイプを選択し、日付範囲や半日休暇などの詳細を指定して申請を行います。申請後は承認フローに従って管理者による承認が行われます。

**画面へのアクセス方法**：マイ休暇一覧画面の「作成」ボタンをクリックすることでアクセスできます。URLパス: `/my-time/my-time-offs/create`

**主要な操作・処理内容**：
1. 休暇タイプを選択
2. 申請開始日を入力
3. 申請終了日を入力（半日休暇でない場合）
4. 半日休暇の場合は期間（午前/午後）を選択
5. 説明を入力（任意）
6. 期間の自動計算表示を確認
7. 「作成」ボタンで休暇申請を保存

**画面遷移**：マイ休暇一覧画面から遷移し、作成完了後は作成された休暇申請の詳細画面へリダイレクトされます。

**権限による表示制御**：ログインユーザーとして従業員情報が登録されている場合のみ申請が可能です。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| FN-TOFF-009 | 自分の休暇申請 | 主機能 | 新規休暇申請の作成 |
| FN-TOFF-005 | 休暇タイプ選択 | 補助機能 | 休暇タイプの選択 |
| FN-TOFF-006 | 期間計算 | 補助機能 | 営業日ベースの期間自動計算 |
| FN-TOFF-007 | 重複チェック | 補助機能 | 既存申請との重複検証 |
| FN-TOFF-008 | 残日数チェック | 補助機能 | 休暇残日数の検証 |

## 画面種別

登録画面

## URL/ルーティング

`/my-time/my-time-offs/create`

## 画面構成

- ヘッダーセクション: ページタイトル「休暇申請作成」
- サブナビゲーション: MyTimeクラスターのナビゲーション
- メインコンテンツ（セクション形式）
  - 休暇タイプ選択
  - 日付範囲選択（2カラム）
  - 半日休暇トグル
  - 期間選択（半日休暇時）
  - 期間表示（自動計算）
  - 説明入力
- フッター: 作成ボタン

## 入出力項目

| 項目名 | 項目ID | データ型 | 必須 | 入力形式 | 最大桁数 | デフォルト値 | バリデーション |
|--------|--------|----------|------|----------|----------|--------------|----------------|
| 休暇タイプ | holiday_status_id | integer | ○ | セレクト | - | - | time_off_leave_typesテーブルに存在するID |
| 申請開始日 | request_date_from | date | ○ | 日付ピッカー | - | - | 日付形式 |
| 申請終了日 | request_date_to | date | ○* | 日付ピッカー | - | - | 開始日以降、半日休暇時は不要 |
| 半日休暇 | request_unit_half | boolean | - | トグル | - | false | - |
| 期間 | request_date_from_period | enum | ○* | セレクト | - | morning | 半日休暇時のみ必須 |
| 説明 | private_name | text | - | テキストエリア | - | - | - |

*: 条件付き必須

## 表示項目

| 項目名 | 項目ID | データ型 | 表示形式 | 備考 |
|--------|--------|----------|----------|------|
| 期間情報 | duration_info | string | テキスト | 自動計算されたX営業日を表示 |

## イベント仕様

### 1-作成ボタン押下

フォーム入力内容のバリデーションを実行し、以下の処理を行います：
1. 従業員情報の取得（ログインユーザーから）
2. 重複チェック（同一従業員・同一期間の既存申請がないか確認）
3. 休暇残日数チェック（割当が必要な休暇タイプの場合）
4. 営業日計算（土日を除いた日数を計算）
5. time_off_leavesテーブルへINSERT
6. ステータスは'confirm'（確認待ち）として登録
7. 作成成功後、詳細画面へリダイレクト

### 2-申請開始日変更

開始日が変更されると、終了日との組み合わせで期間情報が自動計算されます。終了日がクリアされます（開始日より前の場合）。

### 3-申請終了日変更

終了日が変更されると、期間情報が自動計算されて表示されます。最小日付は開始日に設定されます。

### 4-半日休暇トグル変更

半日休暇がONの場合：
- 終了日フィールドが非表示
- 期間選択フィールド（午前/午後）が表示
- 期間情報は「0.5 day」と表示

半日休暇がOFFの場合：
- 終了日フィールドが表示
- 期間選択フィールドが非表示
- 期間情報は営業日ベースで計算

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 作成ボタン押下 | time_off_leaves | INSERT | 新規休暇申請の登録 |
| 作成ボタン押下 | time_off_leave_allocations | SELECT | 休暇残日数の確認 |

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

#### time_off_leaves

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | user_id | ログインユーザーID | Auth::user()->id |
| INSERT | employee_id | ログインユーザーの従業員ID | - |
| INSERT | department_id | 従業員の部署ID | リレーションから取得 |
| INSERT | company_id | ログインユーザーのデフォルト会社ID | - |
| INSERT | employee_company_id | ログインユーザーのデフォルト会社ID | - |
| INSERT | calendar_id | 従業員のカレンダーID | リレーションから取得 |
| INSERT | holiday_status_id | フォーム選択値 | 休暇タイプID |
| INSERT | request_date_from | フォーム入力値 | 申請開始日 |
| INSERT | request_date_to | フォーム入力値 | 申請終了日（半日休暇時はnull） |
| INSERT | request_unit_half | フォーム選択値 | 半日休暇フラグ |
| INSERT | request_date_from_period | フォーム選択値 | 期間（半日休暇時） |
| INSERT | private_name | フォーム入力値 | 説明 |
| INSERT | state | 'confirm' | State::CONFIRM |
| INSERT | date_from | フォーム入力値 | 開始日 |
| INSERT | date_to | フォーム入力値 | 終了日 |
| INSERT | duration_display | 計算値 | 期間表示文字列 |
| INSERT | number_of_days | 計算値 | 営業日数 |
| INSERT | number_of_hours | 計算値 | カレンダーの1日あたり時間数 |
| INSERT | creator_id | ログインユーザーID | 作成者 |
| INSERT | created_at | 現在日時 | 自動設定 |
| INSERT | updated_at | 現在日時 | 自動設定 |

## メッセージ仕様

| メッセージID | メッセージ種別 | メッセージ内容 | 表示条件 |
|-------------|---------------|---------------|---------|
| notification.success.title | 成功 | 休暇申請が正常に作成されました | 作成成功時 |
| notification.success.body | 成功 | 休暇申請の作成が完了しました | 作成成功時 |
| notification.overlap.title | エラー | 休暇申請が重複しています | 重複検出時 |
| notification.overlap.body | エラー | 指定された期間に既に休暇申請があります | 重複検出時 |
| notification.leave_request_denied_no_allocation.title | エラー | 休暇割当がありません | 割当なし時 |
| notification.leave_request_denied_no_allocation.body | エラー | {leaveType}の休暇割当が存在しません | 割当なし時 |
| notification.leave_request_denied_insufficient_balance.title | エラー | 休暇残日数が不足しています | 残日数不足時 |
| notification.leave_request_denied_insufficient_balance.body | エラー | 利用可能残日数: {available_balance}日、申請日数: {requested_days}日 | 残日数不足時 |
| employee-not-found.notification.title | エラー | 従業員が見つかりません | 従業員未登録時 |
| employee-not-found.notification.body | エラー | 従業員情報が登録されていません | 従業員未登録時 |
| validation.required | エラー | この項目は必須です | 必須項目未入力時 |

## 例外処理

| 例外ケース | 対応処理 | 表示メッセージ |
|-----------|---------|---------------|
| 従業員情報未登録 | 処理中断、エラー通知表示 | 従業員情報が登録されていません |
| 期間が重複 | 処理中断、エラー通知表示 | 指定された期間に既に休暇申請があります |
| 休暇残日数不足 | 処理中断、エラー通知表示 | 残日数が不足しています |
| 休暇割当なし | 処理中断、エラー通知表示 | 休暇割当が存在しません |
| 必須項目未入力 | フォームバリデーションエラー表示 | 該当項目に必須エラー表示 |
| データベース登録失敗 | トランザクションロールバック | システムエラー通知 |

## 備考

- 本画面はFilament PHPのCreateRecordページを継承して実装されています
- TimeOffHelperトレイトを使用して、期間計算・重複チェック・残日数チェックを行います
- 営業日計算は土日を除いた日数を計算します（祝日は考慮されません）
- 期間情報はリアルタイムで計算されて表示されます（TextEntry::makeのstateメソッド使用）
- 半日休暇の場合、申請日数は0.5日として計算されます
- サブナビゲーションにはMyTimeクラスターの他のリソースへのリンクが表示されます
- 休暇タイプによっては割当（allocation）が必要で、割当がない場合は申請できません
