feat: 仕切書と定期請求スケジュール(Phase A〜C) (#54)#56
Merged
Merged
Conversation
- settlements / settlement_schedules の migration を追加 - settlement_number は nullable + UNIQUE - (settlement_id, sequence_no) UNIQUE、親削除時 cascade - Settlement / SettlementSchedule model と casts・relations を追加 - SettlementPricing: 1回分の明細・小計・税・税込額のサーバ側再計算 - SettlementScheduleGenerator: month/year 周期・有限境界・月末クランプ・ advance/arrears・金額スナップショット・基準日以降のみ再生成する sync() - Unit / Feature テストを追加 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- SettlementController (apiResource): QuoteController 踏襲の validation、 settlement_number は Rule::unique->ignore、終了条件 (end_date / occurrences_count のいずれか必須)を required_without で検証 - store/update で SettlementPricing 再計算。store は全回生成、 update は基準日以降のみ SettlementScheduleGenerator::sync で再生成 - SettlementScheduleController#index: ?settlement_id= / ?from= / ?to= (billing_date 範囲)フィルタ付きで各回の請求予定データを JSON 提供 - routes/api.php: auth:sanctum 配下に apiResource と取得ルートを追加 - Feature テスト: CRUD、サーバ側再計算、終了条件 422、番号 UNIQUE、 過去回スナップショット不変の再生成、フィルタ、quotes 回帰 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- types.ts: Settlement / SettlementSchedule / IntervalUnit / SettlementStatus / BillingTiming / SettlementScheduleFilters を追加、BackupPayload に settlements / settlement_schedules を追加(version 3 で追加、旧形式は optional) - api adapter: Settlement CRUD と listSettlementSchedules (settlement_id / from / to フィルタ)を追加 - local adapter: SettlementPricing / ScheduleGenerator 相当をブラウザ内で再現 (アンカー加算・月末クランプ・advance/arrears。デモ用のため更新時は全回再生成) - store.ts: adapter 切替に Settlement 経路を追加 - backup: エクスポート version 2→3。download / backup:export に settlements・settlement_schedules を追加、BackupRestorer で親→子の順に復元 (skip された親の予定は紐付けない、items は JSON encode) - テスト: SettlementBackupTest(download 構造、restore skip/overwrite、 必須カラム 422、旧 version 2 互換)、BackupTest の version 断言を 3 に更新 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
issue #54 の実装として、継続取引向けの 仕切書(settlements) と、そこから生成される 各回の請求予定(settlement_schedules) を追加し、API/フロント/バックアップまで一通り取り扱えるようにするPRです。既存の Quote と同様に「サーバ側を単一の真実」として金額再計算と予定生成を行い、バックアップは version 3 に拡張しています。
Changes:
- settlements / settlement_schedules の追加(migration・Model・Pricing・Schedule 生成/同期ロジック)
- API エンドポイント追加(Settlement CRUD と schedule 一覧取得)およびフロント型/adapter対応
- バックアップ形式を version 3 に拡張し、export/restore・互換性テストを追加
Reviewed changes
Copilot reviewed 21 out of 21 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/Unit/SettlementPricingTest.php | 1回分金額再計算(items→小計/税/合計、端数処理)のユニットテスト追加 |
| tests/Feature/SettlementScheduleGeneratorTest.php | スケジュール生成境界・月末クランプ・advance/arrears・sync の保持/再生成のテスト追加 |
| tests/Feature/SettlementBackupTest.php | バックアップ download/restore に settlements 系が含まれること、互換/skip/overwrite のテスト追加 |
| tests/Feature/SettlementApiTest.php | settlements CRUD・422系・再生成・filters・quotes回帰のテスト追加 |
| tests/Feature/BackupTest.php | バックアップ version 3 への更新に伴う既存テストの期待値更新 |
| routes/api.php | settlements CRUD と settlement-schedules 取得ルートを追加 |
| resources/js/types.ts | Settlement/SettlementSchedule 型と filters、BackupPayload の version 3 拡張を追加 |
| resources/js/data/store.ts | store から Settlement と listSettlementSchedules を公開 |
| resources/js/data/adapters/local.ts | localStorage アダプターに settlements CRUD と schedule 生成/一覧取得を追加 |
| resources/js/data/adapters/api.ts | API アダプターに settlements CRUD と schedule 一覧取得を追加 |
| database/migrations/2026_07_08_000001_create_settlements_table.php | settlements テーブル新規作成(周期/終了条件/スナップショット/1回分金額) |
| database/migrations/2026_07_08_000002_create_settlement_schedules_table.php | settlement_schedules テーブル新規作成(各回の予定・スナップショット) |
| app/Support/SettlementScheduleGenerator.php | 周期ルールから予定生成、未来回のみ再生成する sync を実装 |
| app/Support/SettlementPricing.php | items から 1回分の小計/税/税込をサーバ側で再計算する処理を追加 |
| app/Services/BackupRestorer.php | バックアップ version 3 対応(settlements/settlement_schedules 復元、親子順序) |
| app/Models/Settlement.php | Settlement model(casts / hasMany)追加 |
| app/Models/SettlementSchedule.php | SettlementSchedule model(casts / belongsTo)追加 |
| app/Http/Controllers/SettlementController.php | settlements CRUD と金額再計算・予定生成/同期を実装 |
| app/Http/Controllers/SettlementScheduleController.php | settlement_schedules 一覧取得(filter: settlement_id/from/to)を実装 |
| app/Http/Controllers/BackupController.php | download に settlements/settlement_schedules を含めるよう拡張 |
| app/Console/Commands/BackupExport.php | backup:export に settlements/settlement_schedules を含めるよう拡張 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
# Conflicts: # resources/js/data/adapters/local.ts
- BackupRestorer: 復元IDの親子照合を文字列キーの set で行い、JSON decode の int/string 型不一致で settlement_schedules が全件 skip される不具合を修正 - SettlementController#store: 仕切書作成と各回生成を DB::transaction で包み、 途中失敗時に親だけ残る中途半端な状態を防止 - SettlementController: status/interval_count/billing_timing/tax_rate は DB が NOT NULL + default のため、nullable ではなく sometimes に変更。 明示的な null 送信が 500 ではなく 422 になるようにした - types.ts: DB で nullable な settlement_number/subject/payment_terms/notes/items を `| null` に修正し、API の実レスポンスと型を一致させた - local adapter: 終了条件(end_date/occurrences_count)が無い場合に generateSchedules() が黙って空配列を返していたのを、サーバ同様に 422相当のエラーで弾くよう assertEndCondition を追加 - 各修正を検証する Feature テストを追加 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Owner
Author
最小限の変更で 見積/仕切を同じ UI で扱えるようにするには
|
Phase A〜C で実装済みの仕切書API/型/アダプターに対する入力画面が 無かったため追加。見積書一覧に「仕切書として作成」のスライドスイッチを 置きつつ、仕切書は独立エンティティとして専用の一覧/フォーム/詳細ページ (請求予定一覧を含む)を新設した。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Owner
Author
追加: 仕切書の入力UI (issue #58)Phase A〜C で実装済みのバックエンド(API/型/adapters)に対して入力画面が未実装だったため追加した。 画面構成
issue 記載との差分(見送り/読み替え)
検証
|
Copilotレビュー指摘(settlement_schedulesのbilling_date等が不正形式でも 422で弾けない)に対する修正は964fa9fで適用済みだったが、回帰テストが 無かったため追加した。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
assertEndCondition() が end_date != null で判定していたため、空文字を 「終了条件あり」と誤判定して通過させ、その後 generateSchedules() の !s.end_date 判定で空配列になり、終了条件なしでも作成/更新が成功して しまう経路が残っていた。判定を generateSchedules() 側と揃えた。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- save() で settlement_number/sender_profile_id/customer_id の空文字を null に正規化。空文字のままだと settlement_number の UNIQUE 制約や sender_profile_id/customer_id の integer バリデーションに引っかかり 意図しない422/一意制約違反になっていた。 - 発行者/取引先を未選択に戻した際、対応するスナップショット項目 (sender_*/customer_*)が前回選択値のまま残っていたのをクリアする ように修正。customer_name が残ったままだと save() の必須チェックを すり抜けてしまう経路があった。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概要 (Summary)
issue #54 の実装。継続取引で使う仕切書(見積類似ドキュメント)と、そこから定期的に発生する各回の請求予定データを扱えるようにする。issue の実装ステージング Phase A(コア)/ Phase B(API)/ Phase C(型・adapters・バックアップ)を 3 コミットで実装した。加えて、issue #54 の後続として issue #58(仕切書の入力UI)もこの PR に追記している(理由は下記 Impact 参照)。
スコープは issue の確定事項どおり: 予定データの生成と取り出しのみ(帳票出力・実績台帳・契約管理は対象外)。
Closes #54
Closes #58
変更内容 (Changes)
Phase A: コア (4da96f1)
settlements/settlement_schedulesmigration(reversible、既存テーブル無変更)settlement_numberは nullable + UNIQUE(quote_numberと同じ扱い)(settlement_id, sequence_no)UNIQUE、親削除時 cascadeSettlement/SettlementSchedulemodel(casts / relations /$guarded=['id'])SettlementPricing: 1回分の明細・小計・税(floor)・税込額のサーバ側再計算SettlementScheduleGenerator:interval_count、end_date/occurrences_countの有限境界(先に尽きた方で停止)start_date)から加算し、1/31 起点などの月末周期ドリフトを防止billing_dayの月内日数クランプ、advance(期首)/arrears(期末)sync(): 基準日より前の回のスナップショットを保持し、当日以降のみ現在条件で再生成Phase B: API (29b855f)
Route::apiResource('settlements', ...)(auth:sanctum 配下)end_date/occurrences_countのいずれか必須(両方 null は 422)settlement_numberはRule::unique->ignore、金額はサーバ側再計算(クライアント送信値は無視)GET /api/settlement-schedules: 各回の請求予定データを JSON で提供(?settlement_id=/?from=/?to=、from/to はbilling_dateの範囲)Phase C: 型・adapters・バックアップ (3e52ffb)
types.ts:Settlement/SettlementSchedule/IntervalUnit/SettlementStatus/BillingTiming/SettlementScheduleFilterslistSettlementSchedulesを追加(local は生成規則をブラウザ内で再現。デモ用のため更新時は全回再生成)download/backup:exportに settlements・settlement_schedules を追加、BackupRestorerで親→子の順に復元(skip された親の予定は紐付けない)。version 1/2 の旧ファイルは引き続き復元可能追加: 仕切書の入力UI (issue #58, af3bab9)
Phase A〜C で実装済みのバックエンドに対し、入力画面が未実装だったため追加した。
SettlementList.tsx(ステータスタブ・検索・取引先絞り込み)SettlementForm.tsx(開始日・終了条件・頻度・請求タイミング/請求日・品目・金額サマリー)SettlementPreview.tsx(基本情報・品目・生成済み請求予定一覧・編集/削除)tests/e2e/settlements.spec.jsを追加(作成・一覧・編集・削除・スイッチ遷移)レビュー対応
Copilot / 手動レビューで指摘された以下を追従修正済み(コミット単位で個別に対応、詳細は各スレッド参照):
影響範囲 (Impact)
テスト方法 (Testing)
tests/Unit/SettlementPricingTest.php: 金額再計算tests/Feature/SettlementScheduleGeneratorTest.php: 生成境界・月末クランプ・advance/arrears・sync の過去回保持tests/Feature/SettlementApiTest.php: CRUD、422 系、時間を進めた未来回再生成、フィルタ、quotes 回帰tests/Feature/SettlementBackupTest.php: backup round-trip、skip/overwrite、旧 version 互換、値域検証tests/e2e/settlements.spec.js: 入力UIの作成・一覧・編集・削除・スイッチ遷移🤖 Generated with Claude Code
補足: スコープに関する事後記録 (issue #57)
本PRのマージ差分(
68a7eca..65b265a)に PDF取込機能は含まれない。PDF取込(QuotePdfParser/config/import.php/ImportControllerのPDF対応 /Import.tsx/ 関連テスト)は PR #51(Issue #1)で別途マージ済み。詳細は issue #57 および PR #60 を参照。