Skip to content

feat: 仕切書と定期請求スケジュール(Phase A〜C) (#54)#56

Merged
strnh merged 19 commits into
mainfrom
feature/54-settlements
Jul 9, 2026
Merged

feat: 仕切書と定期請求スケジュール(Phase A〜C) (#54)#56
strnh merged 19 commits into
mainfrom
feature/54-settlements

Conversation

@strnh

@strnh strnh commented Jul 8, 2026

Copy link
Copy Markdown
Owner

概要 (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_schedules migration(reversible、既存テーブル無変更)
    • settlement_number は nullable + UNIQUE(quote_number と同じ扱い)
    • (settlement_id, sequence_no) UNIQUE、親削除時 cascade
  • Settlement / SettlementSchedule model(casts / relations / $guarded=['id']
  • SettlementPricing: 1回分の明細・小計・税(floor)・税込額のサーバ側再計算
  • SettlementScheduleGenerator:
    • month / year × interval_countend_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_numberRule::unique->ignore、金額はサーバ側再計算(クライアント送信値は無視)
    • store は全回生成、update は過去回を保持して未来回のみ再生成
  • GET /api/settlement-schedules: 各回の請求予定データを JSON で提供(?settlement_id= / ?from= / ?to=、from/to は billing_date の範囲)

Phase C: 型・adapters・バックアップ (3e52ffb)

  • types.ts: Settlement / SettlementSchedule / IntervalUnit / SettlementStatus / BillingTiming / SettlementScheduleFilters
  • api / local 両 adapter に Settlement CRUD と listSettlementSchedules を追加(local は生成規則をブラウザ内で再現。デモ用のため更新時は全回再生成)
  • バックアップ version 2→3: 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 / 手動レビューで指摘された以下を追従修正済み(コミット単位で個別に対応、詳細は各スレッド参照):

  • backup restore の親子ID型不一致・値域検証漏れ
  • store/update のトランザクション原子性
  • status / interval_count 等の nullable→sometimes バリデーション
  • settlement_schedules リレーションの順序保証
  • 部分更新時の金額再計算の既存値マージ
  • local アダプターの金額整数化・終了条件判定の空文字誤判定
  • SettlementForm の未選択時 payload 正規化とスナップショットクリア

影響範囲 (Impact)

  • 新規テーブル 2 つのみで既存スキーマ(quotes 等)は無変更
  • バックアップ形式の version が 3 に上がる(restore は 1/2/3 すべて受け付けるため後方互換)
  • Settlement の一覧/作成/編集/詳細ページ、ナビゲーション追加、見積書一覧への「仕切書として作成」スイッチを含む UI 変更あり(issue feat: 仕切書の入力UI #58、上記参照)

テスト方法 (Testing)

composer test        # すべて成功
npm run type-check   # エラーなし
npm run build        # 成功
npm run test:e2e     # settlements.spec.js を含め全件成功
  • 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 を参照。

strnh and others added 3 commits July 8, 2026 17:16
- 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>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread app/Services/BackupRestorer.php
Comment thread app/Http/Controllers/SettlementController.php
Comment thread app/Http/Controllers/SettlementController.php
Comment thread app/Http/Controllers/SettlementController.php
Comment thread resources/js/types.ts Outdated
Comment thread resources/js/data/adapters/local.ts
strnh and others added 2 commits July 8, 2026 19:47
# 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>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 21 out of 21 changed files in this pull request and generated 3 comments.

Comment thread app/Models/Settlement.php
Comment thread resources/js/types.ts Outdated
Comment thread app/Services/BackupRestorer.php

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 21 out of 21 changed files in this pull request and generated 1 comment.

Comment thread app/Http/Controllers/SettlementScheduleController.php Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 21 out of 21 changed files in this pull request and generated 2 comments.

Comment thread app/Http/Controllers/SettlementController.php
Comment thread resources/js/types.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 21 out of 21 changed files in this pull request and generated 2 comments.

Comment thread resources/js/data/adapters/local.ts
Comment thread app/Services/BackupRestorer.php
@strnh

strnh commented Jul 8, 2026

Copy link
Copy Markdown
Owner Author
  • 出力は不要としたが、では入力(UI) はどう実装するかを詰めていない。

最小限の変更で 見積/仕切を同じ UI で扱えるようにするには

  1. 見積・仕切 のモードスイッチ
  2. 仕切選択時(追加されるUI)⇒ 2-1. 開始日(納品・請求),終了日(納品・請求) 設定、2-2. 納品・請求の頻度(月単位・年単位) 3. 契約の有無(有・無)
    3

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 21 out of 21 changed files in this pull request and generated 2 comments.

Comment thread app/Http/Controllers/SettlementController.php
Comment thread resources/js/data/adapters/local.ts

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 21 out of 21 changed files in this pull request and generated 2 comments.

Comment thread app/Http/Controllers/SettlementController.php Outdated
Comment thread app/Http/Controllers/SettlementController.php Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 21 out of 21 changed files in this pull request and generated 1 comment.

Comment thread app/Support/SettlementScheduleGenerator.php
Phase A〜C で実装済みの仕切書API/型/アダプターに対する入力画面が
無かったため追加。見積書一覧に「仕切書として作成」のスライドスイッチを
置きつつ、仕切書は独立エンティティとして専用の一覧/フォーム/詳細ページ
(請求予定一覧を含む)を新設した。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@strnh

strnh commented Jul 8, 2026

Copy link
Copy Markdown
Owner Author

追加: 仕切書の入力UI (issue #58)

Phase A〜C で実装済みのバックエンド(API/型/adapters)に対して入力画面が未実装だったため追加した。

画面構成

  • 仕切書は独立エンティティ(別テーブル/別API)として実装済みのため、QuoteForm への合体はせず専用ページを新設
  • 一覧: SettlementList.tsx(ステータスタブ・検索・取引先絞り込み)
  • 作成/編集: SettlementForm.tsx(開始日・終了条件[終了日 or 回数]・頻度・請求タイミング/請求日・品目・金額サマリー)
  • 詳細: SettlementPreview.tsx(基本情報・品目・生成済み請求予定一覧・編集/削除)
  • 見積書一覧に「仕切書として作成」のスライドスイッチ(issue の素案文言)を設置し、新規作成の遷移先を切り替え

issue 記載との差分(見送り/読み替え)

  • 「保守契約番号」: 現スキーマに列が無く、追加はバックエンド変更を伴うため今回は見送り
  • 「初回請求基準年月日」: 該当カラムは無く、実装済みの billing_day(1-31) + billing_timing(advance/arrears) で表現。UIもこれに合わせた

検証

  • npm run type-check 通過
  • npm run build 通過
  • tests/e2e/settlements.spec.js を追加(作成・一覧・編集・削除・スイッチ遷移)、既存 e2e 含め全33件通過

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 31 out of 31 changed files in this pull request and generated no new comments.

Copilotレビュー指摘(settlement_schedulesのbilling_date等が不正形式でも
422で弾けない)に対する修正は964fa9fで適用済みだったが、回帰テストが
無かったため追加した。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 31 out of 31 changed files in this pull request and generated 2 comments.

Comment thread resources/js/lib/format.ts
Comment thread resources/js/data/adapters/local.ts Outdated
assertEndCondition() が end_date != null で判定していたため、空文字を
「終了条件あり」と誤判定して通過させ、その後 generateSchedules() の
!s.end_date 判定で空配列になり、終了条件なしでも作成/更新が成功して
しまう経路が残っていた。判定を generateSchedules() 側と揃えた。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 31 out of 31 changed files in this pull request and generated 1 comment.

Comment thread resources/js/App.tsx

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 31 out of 31 changed files in this pull request and generated 3 comments.

Comment thread resources/js/pages/SettlementForm.tsx Outdated
Comment thread resources/js/pages/SettlementForm.tsx
Comment thread resources/js/pages/SettlementForm.tsx
- 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>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 31 out of 31 changed files in this pull request and generated no new comments.

@strnh strnh merged commit 65b265a into main Jul 9, 2026
1 check passed
@strnh strnh deleted the feature/54-settlements branch July 9, 2026 05:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: 仕切書の入力UI 定期性取引「仕切書」と定期請求スケジュール(請求予定データ生成)の設計

2 participants