# バッチ設計書 21-check_overdue_return_orders

## 概要

本ドキュメントは、期限切れの返品注文をチェックし関係者に通知するバッチ処理「check_overdue_return_orders」の設計仕様を定義する。

### 本バッチの処理概要

このバッチは、InvenTreeシステムにおける返品注文（ReturnOrder）の期限管理を自動化し、期限切れとなった注文を適時に検出して関係者へ通知することで、返品処理の遅延防止と業務効率化を実現する。

**業務上の目的・背景**：返品注文の期限管理は在庫管理および顧客対応において重要な業務である。返品期限を超過した注文は、在庫計画の狂いや顧客満足度の低下につながる可能性がある。本バッチは、返品注文の期限超過を自動検出し、作成者・責任者・購読ユーザーに通知することで、迅速な対応を促進し業務の円滑な遂行を支援する。

**バッチの実行タイミング**：日次（毎日1回）でスケジュール実行される。Django-Qのスケジューラにより自動起動される。

**主要な処理内容**：
1. 昨日が期限日（target_date）であったオープン状態の返品注文を検索
2. 昨日が期限日であった返品注文明細（ReturnOrderLineItem）のうち、未受領のものを検索
3. 検出した期限切れ注文ごとに通知関数（notify_overdue_return_order）を呼び出し
4. 作成者、責任者、購読ユーザーに対して通知を送信
5. プラグインシステムへのイベント発火

**前後の処理との関連**：本バッチは独立して動作し、他のバッチとの直接的な依存関係はない。ただし、同様の期限チェックバッチ（check_overdue_purchase_orders、check_overdue_sales_orders）と同じ設計パターンを採用している。

**影響範囲**：ReturnOrderテーブル、ReturnOrderLineItemテーブルの参照、通知システム（NotificationEntry、NotificationMessage）への書き込み、メール送信、プラグインイベントシステムへの影響がある。

## バッチ種別

通知配信 / データ監視

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | 日次 |
| 実行時刻 | Django-Qスケジューラの設定に依存 |
| 実行曜日 | 毎日 |
| 実行日 | 毎日 |
| トリガー | Django-Q ScheduledTask.DAILY |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| データベース接続 | InvenTreeデータベースに正常に接続できること |
| Django-Qワーカー稼働 | バックグラウンドワーカーが稼働していること |
| 返品注文データ存在 | ReturnOrderテーブルにデータが存在すること |

### 実行可否判定

本バッチには特別な実行可否判定ロジックはなく、スケジュールに従って毎日実行される。

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| なし | - | - | - | 本バッチは入力パラメータを受け取らない |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| order_returnorder | DB | 返品注文テーブル |
| order_returnorderlineitem | DB | 返品注文明細テーブル |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| common_notificationentry | DB | 通知エントリ |
| common_notificationmessage | DB | 通知メッセージ |
| メール | Email | 期限切れ通知メール |
| プラグインイベント | Event | SalesOrderEvents.OVERDUEイベント |

### 出力ファイル仕様

本バッチはファイル出力を行わない。

## 処理フロー

### 処理シーケンス

```
1. 現在日付から昨日の日付を計算
   └─ datetime.now().date() - timedelta(days=1)
2. 期限切れ返品注文の検索
   └─ target_date=yesterday かつ status が OPEN グループに属する ReturnOrder を取得
3. 期限切れ返品注文明細の検索
   └─ target_date=yesterday かつ order.status が OPEN かつ received_date が null の ReturnOrderLineItem を取得
4. 通知済み注文の追跡用セットを初期化
   └─ notified_orders = set()
5. 期限切れ返品注文ごとに通知処理
   └─ 各注文に対して notify_overdue_return_order を呼び出し、notified_orders に追加
6. 期限切れ明細の親注文に対して通知処理
   └─ 親注文が未通知の場合のみ notify_overdue_return_order を呼び出し
7. 通知処理（notify_overdue_return_order）
   └─ 通知対象者（作成者、責任者、購読ユーザー）を収集
   └─ 通知コンテキストを作成
   └─ common.notifications.trigger_notification で通知送信
   └─ plugin.events.trigger_event でプラグインイベント発火
```

### フローチャート

```mermaid
flowchart TD
    A[バッチ開始] --> B[昨日の日付を計算]
    B --> C[期限切れ返品注文を検索]
    C --> D[期限切れ返品注文明細を検索]
    D --> E[通知済みセットを初期化]
    E --> F{期限切れ注文あり?}
    F -->|あり| G[各注文に通知を送信]
    F -->|なし| H{期限切れ明細あり?}
    G --> H
    H -->|あり| I[未通知の親注文に通知を送信]
    H -->|なし| J[バッチ終了]
    I --> J
```

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

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

| 処理 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 期限切れ注文検索 | order_returnorder | SELECT | target_date と status で絞り込み |
| 期限切れ明細検索 | order_returnorderlineitem | SELECT | target_date, order__status, received_date で絞り込み |
| 通知エントリ作成 | common_notificationentry | INSERT | 通知履歴の記録 |
| 通知メッセージ作成 | common_notificationmessage | INSERT | 通知内容の保存 |

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

#### order_returnorder

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | target_date | = yesterday | 昨日が期限日 |
| SELECT | status | IN ReturnOrderStatusGroups.OPEN | オープン状態の注文のみ |

#### order_returnorderlineitem

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | target_date | = yesterday | 昨日が期限日 |
| SELECT | order__status | IN ReturnOrderStatusGroups.OPEN | 親注文がオープン状態 |
| SELECT | received_date | IS NULL | 未受領の明細のみ |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | DatabaseError | データベース接続エラー | Django-Qがリトライを実行 |
| - | NotificationError | 通知送信失敗 | ログ出力、処理継続 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | Django-Qのデフォルト設定に依存 |
| リトライ間隔 | Django-Qのデフォルト設定に依存 |
| リトライ対象エラー | 一時的なデータベースエラー、通信エラー |

### 障害時対応

バッチ失敗時は翌日の実行で再度チェックが行われるため、1日分の遅延が発生する可能性がある。緊急時は手動でバッチを再実行することで対応可能。

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

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | 通知送信ごと |
| コミットタイミング | 各通知処理完了時 |
| ロールバック条件 | 個別通知処理でのエラー発生時 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | 数十件〜数百件/日 |
| 目標処理時間 | 数分以内 |
| メモリ使用量上限 | 通常のDjangoプロセス制限内 |

## 排他制御

同時実行の制御はDjango-Qのスケジューラに委ねられている。同一バッチの重複実行は基本的に発生しない設計。

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| 開始ログ | バッチ開始時 | Django-Qによる自動ログ |
| 進捗ログ | 通知送信時 | 通知対象の返品注文情報 |
| 終了ログ | バッチ終了時 | Django-Qによる自動ログ |
| エラーログ | エラー発生時 | エラー詳細、スタックトレース |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| 処理時間 | Django-Qのタイムアウト設定 | システム管理者 |
| エラー件数 | Django-Q Failure テーブル | システム管理者 |

## 備考

- 本バッチは `@scheduled_task(ScheduledTask.DAILY)` デコレータにより日次実行される
- 通知イベントは `SalesOrderEvents.OVERDUE` を使用（返品注文専用イベントではない点に注意）
- OpenTelemetry によるトレーシングが有効化されている（`@tracer.start_as_current_span`）
