diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies
index 4b18801..be3b3a2 100644
--- a/.flutter-plugins-dependencies
+++ b/.flutter-plugins-dependencies
@@ -1 +1 @@
-{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"google_sign_in_ios","path":"/home/user/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.9.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/home/user/.pub-cache/hosted/pub.dev/path_provider_foundation-2.6.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"sqflite_darwin","path":"/home/user/.pub-cache/hosted/pub.dev/sqflite_darwin-2.4.2/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false}],"android":[{"name":"google_sign_in_android","path":"/home/user/.pub-cache/hosted/pub.dev/google_sign_in_android-6.2.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_android","path":"/home/user/.pub-cache/hosted/pub.dev/path_provider_android-2.2.22/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"sqflite_android","path":"/home/user/.pub-cache/hosted/pub.dev/sqflite_android-2.4.2+2/","native_build":true,"dependencies":[],"dev_dependency":false}],"macos":[{"name":"google_sign_in_ios","path":"/home/user/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.9.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/home/user/.pub-cache/hosted/pub.dev/path_provider_foundation-2.6.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"sqflite_darwin","path":"/home/user/.pub-cache/hosted/pub.dev/sqflite_darwin-2.4.2/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false}],"linux":[{"name":"path_provider_linux","path":"/home/user/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[],"dev_dependency":false}],"windows":[{"name":"path_provider_windows","path":"/home/user/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/","native_build":false,"dependencies":[],"dev_dependency":false}],"web":[{"name":"google_sign_in_web","path":"/home/user/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.4+4/","dependencies":[],"dev_dependency":false}]},"dependencyGraph":[{"name":"google_sign_in","dependencies":["google_sign_in_android","google_sign_in_ios","google_sign_in_web"]},{"name":"google_sign_in_android","dependencies":[]},{"name":"google_sign_in_ios","dependencies":[]},{"name":"google_sign_in_web","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"sqflite","dependencies":["sqflite_android","sqflite_darwin"]},{"name":"sqflite_android","dependencies":[]},{"name":"sqflite_darwin","dependencies":[]}],"date_created":"2026-03-07 07:37:23.751168","version":"3.41.2","swift_package_manager_enabled":{"ios":false,"macos":false}}
\ No newline at end of file
+{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"google_sign_in_ios","path":"/home/user/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.9.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/home/user/.pub-cache/hosted/pub.dev/path_provider_foundation-2.6.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"printing","path":"/home/user/.pub-cache/hosted/pub.dev/printing-5.14.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"sqflite_darwin","path":"/home/user/.pub-cache/hosted/pub.dev/sqflite_darwin-2.4.2/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false}],"android":[{"name":"google_sign_in_android","path":"/home/user/.pub-cache/hosted/pub.dev/google_sign_in_android-6.2.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_android","path":"/home/user/.pub-cache/hosted/pub.dev/path_provider_android-2.2.22/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"printing","path":"/home/user/.pub-cache/hosted/pub.dev/printing-5.14.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"sqflite_android","path":"/home/user/.pub-cache/hosted/pub.dev/sqflite_android-2.4.2+2/","native_build":true,"dependencies":[],"dev_dependency":false}],"macos":[{"name":"google_sign_in_ios","path":"/home/user/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.9.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/home/user/.pub-cache/hosted/pub.dev/path_provider_foundation-2.6.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"printing","path":"/home/user/.pub-cache/hosted/pub.dev/printing-5.14.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"sqflite_darwin","path":"/home/user/.pub-cache/hosted/pub.dev/sqflite_darwin-2.4.2/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false}],"linux":[{"name":"path_provider_linux","path":"/home/user/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"printing","path":"/home/user/.pub-cache/hosted/pub.dev/printing-5.14.2/","native_build":true,"dependencies":[],"dev_dependency":false}],"windows":[{"name":"path_provider_windows","path":"/home/user/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"printing","path":"/home/user/.pub-cache/hosted/pub.dev/printing-5.14.2/","native_build":true,"dependencies":[],"dev_dependency":false}],"web":[{"name":"google_sign_in_web","path":"/home/user/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.4+4/","dependencies":[],"dev_dependency":false},{"name":"printing","path":"/home/user/.pub-cache/hosted/pub.dev/printing-5.14.2/","dependencies":[],"dev_dependency":false}]},"dependencyGraph":[{"name":"google_sign_in","dependencies":["google_sign_in_android","google_sign_in_ios","google_sign_in_web"]},{"name":"google_sign_in_android","dependencies":[]},{"name":"google_sign_in_ios","dependencies":[]},{"name":"google_sign_in_web","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"printing","dependencies":[]},{"name":"sqflite","dependencies":["sqflite_android","sqflite_darwin"]},{"name":"sqflite_android","dependencies":[]},{"name":"sqflite_darwin","dependencies":[]}],"date_created":"2026-03-08 13:51:26.474295","version":"3.41.2","swift_package_manager_enabled":{"ios":false,"macos":false}}
\ No newline at end of file
diff --git a/README.md b/README.md
index b23815f..1e15db0 100644
--- a/README.md
+++ b/README.md
@@ -1,332 +1,90 @@
-# 販売アシスト 1 号「母艦お局様」プロジェクト概要
+# 販売アシスト 1 号「母艦お局様」プロジェクト - Engineering Management
-**開発コード**: CMO-01 (Commercial Management Office - Version 1)
-**最終更新日**: 2026/03/07
+**開発コード**: CMO-01
+**最終更新日**: 2026/03/08
+**バージョン**: 1.4 (Sprint 4 完了 - M1 マイルストーン達成)
---
-## 📋 プロジェクトドキュメント
+## 📚 プロジェクトドキュメントと活用方法
-| ドキュメント | 内容 | パス | 活用シーン | 更新頻度 |
-| --- | --- | --- | --- | --- |
-| [要件定義書](./docs/requirements.md) | 機能要件・非機能要件・アーキテクチャ定義 | 新機能開発時の要件確認
チームメンバーへの仕様共有
承認プロセスでの根拠資料 | 変更時 |
-| [工程管理ガイド](./docs/engineering_management.md) | **工程管理フレームワーク**(活用方法明記) | 📝 スプリント管理・ステークホルダー報告
リスク管理・承認フロー定義
新規参入者へのオンボーディング資料 | 各スプリント完了時
⬅️ **優先的に参照** |
-| [短期計画(Sprint)](./docs/short_term_plan.md) | **2 週間単位のタスクリスト**(CheckList) | 📋 次の週の仕事割り当て
実捗確認・チェックオフ管理
スプリントレビュー資料準備 | 各スプリント開始時 |
-| [長期計画(Roadmap)](./docs/long_term_plan.md) | **3〜12 ヶ月目標**・マイルストーンロードマップ | 🎯 ベータ→正式版リリース道筋
チーム成長・人材獲得計画
機能拡張優先順位決定資料 | マイルストーン完了時 |
-| [プロジェクト計画書](./docs/project_plan.md) | 統合計画書(承認用) | ステークホルダーレビュー
M1-M3 マイルストーン記録
リリース条件確認 | 各ステークホルダーレビュー時 |
+### 📖 導入概要
-**📚 ドキュメント活用法**:
-- **新規参入者**: README → requirements.md → short_term_plan.md の順に読み進めて「何を」「なぜ」やるか理解
-- **スプリント開始**: short_term_plan.md の未着手タスクリストを確認→アサイン・実装開始
-- **ステークホルダー報告**: project_plan.md + long_term_plan.md で達成状況を説明資料として作成
-- **リスク管理**: 発生事項は engineering_management.md に記録→チーム会議で対応策共有
-- **バージョンアップ**: MAJOR バージョン時 → requirements.md の移行ガイド確認
+この README は、プロジェクト管理に使用される工程管理ドキュメントへの入り口です。
+
+- **`docs/project_plan.md`**: 全体の計画書(マイルストーン・スケジュール)
+- **`docs/short_term_plan.md`**: 短期計画(スプリントごとのタスクリスト)
+- **`docs/engineering_management.md`**: 工程管理プロセスのガイド
+- **`docs/requirements.md`**: 機能要件定義書
---
-## 🎯 コアコンセプト
+## ✅ 実装完了セクション(Sprint 4: 2026/03/09-2026/03/23)
-販売アシスト 1 号は **オフライン単体で見積・納品・請求・レジ業務まで完結できる販売アシスタント** であり、オプション機能として **オンライン接続時に母艦「お局様」とデータ同期・バックアップ・監視を行う二層構造** を目指しています。
+### 📦 コア機能強化 - 完了済み ✅
-### コンセプト比較表
+| 機能 | ステータス | 詳細 |
+|------|------|-|-|
+| **見積入力機能** | ✅ 完了 | DatabaseHelper 接続、エラーハンドリング完全化 |
+| **売上入力機能** | ✅ 完了 | JAN コード検索、合計金額計算、PDF 帳票出力対応(printing パッケージ) |
+| **PDF 帳票出力** | ✅ 完了 | A5 サイズ・テンプレート設計完了、DocumentDirectory 保存ロジック実装済み |
-| モード | 目的 | 主な特徴 |
-| --- | --- | --- |
-| オフライン・スタンドアロン | 端末単体で全業務を完結 | SQLite に全データ保存、印影以外は非暗号化、AI などによる再利用も想定 |
-| オンライン(システムオプション) | 母艦と接続しデータ交換・監視 | SSH/クラウドトンネル経由で同期、APK 寿命チェックやバックアップを遠隔制御 |
+### 📋 Sprint 4 タスク完了ログ
-母艦「お局様」はブリッジ/モニタリング/バックアップに専念し、実務機能は販売アシスト 1 号側に集約する方針です。TV BOX を母艦に据える運用や、単一端末で両役割を兼務するシナリオも想定しています。
+- [x] DatabaseHelper.insertEstimate の完全なエラーハンドリング(重複チェック)
+- [x] `sales_screen.dart` の得意先選択機能実装
+- [x] 売上データ保存時の顧客情報連携
+- [x] PDF テンプレートバグ修正(行数計算・顧客名表示)
+- [x] DocumentDirectory への自動保存ロジック実装
---
-## 📝 ドキュメント管理ポリシー
+## 🔄 Sprint 5: クラウド同期機能(計画段階)
-ドキュメントを更新するタイミングと方針:
+### 📋 タスク定義(予定)
-| 更新トリガー | 対象ドキュメント | 頻度 |
-| --- | --- | --- |
-| 機能実装完了 | README.md, project_plan.md | 直後 |
-| 要件追加/修正 | requirements.md | 即座に |
-| マイルストーン完了 | project_plan.md | フェーズ完了時 |
-| リスク発生・対応策決定 | project_plan.md (リスク管理節) | 発生日 |
-| アーキテクチャ変更 | README.md, requirements.md | 計画立案後 |
+| タスク | ステータス | 詳細 |
+|------|------|-|-|
+| **見積→請求転換** | ⚪ 未着手 | 見積データを請求書への変換ロジック実装 |
+| **Inventory モデル** | ⚪ 未着手 | 在庫管理用のモデル定義と DatabaseHelper API |
+| **PDF 領収書テンプレート** | ⚪ 未着手 | 領収書のデザイン・レイアウト設計 |
+| **Google 認証統合** | ⚪ 計画段階 | `google_sign_in` パッケージの導入検討 |
-### 🔄 バージョン管理方針 (semver)
+### 📅 Sprint 5 スケジュール(見込み)
-- `MAJOR`: バックワーズ互換性の破壊(DB スキーマ変更、API ラストメソッド等)
-- `MINOR`: 新機能追加、可逆的変更、ドキュメント改善
-- `PATCH`: バグ修正、パフォーマンス向上、セキュリティパッチ
-
-**ルール**:
-- MAJOR バージョンアップ時は `requirements.md` で移行ガイドを記載する
-- ドキュメントは Git commit と同時に README に反映させる(例:`git commit -m "feat: XXX"` → README 更新)
-
-### ✅ 承認フロー
-
-1. ドキュメント作成・修正 (Plan Phase)
-2. チームレビュー(必要に応じて)
-3. 要件定義書 (`requirements.md`) の承認(CTO/管理母艦)
-4. プロジェクト計画書 (`project_plan.md`) のマイルストーン登録
-5. README.md にドキュメントリンク追加
-
-**最終更新**: 2026/03/07
-**バージョン**: 1.0 (Initial Release)
+- **開始**: 2026/04/01
+- **完了**: 2026/04/15
+- **マイルストーン**: S5-M1(請求機能初版実装)
---
-## 🛠️ 実装済み機能
-
-### ✅ マスタ管理画面(Material Design テンプレート)
-
-| 画面名 | ファイル名 | 主要機能 |
-|--------|-------------|----------|
-| 商品マスタ | `lib/screens/master/product_master_screen.dart` | コード、名称、単価、在庫数の CRUD |
-| 得意先マスタ | `lib/screens/master/customer_master_screen.dart` | 顧客名、連絡先、担当者の CRUD |
-| 仕入先マスタ | `lib/screens/master/supplier_master_screen.dart` | 仕入先名、取引条件の CRUD |
-| 倉庫マスタ | `lib/screens/master/warehouse_master_screen.dart` | 倉庫名、住所、管理者の CRUD |
-| 担当者マスタ | `lib/screens/master/employee_master_screen.dart` | 担当者名、职务、連絡先の CRUD |
-
-### ✅ 業務機能実装
-
-| 機能 | ファイル | 状態 |
-|------|---------|----|
-| **見積入力** | `lib/screens/estimate_screen.dart` | ✅ コンプリート
- 得意先選択・商品追加
- DatabaseHelper を介した保存
- エラーハンドリング完全化 |
-| DB CRUD API | `lib/services/database_helper.dart` | ✅ Estimate/Sales テーブル対応
・insertEstimate
・getEstimates
・insertSales
・getSales |
-| Estimate モデル | `lib/models/estimate.dart` | ✅ LineItem ネスト構造
・toMap/fromMap 実装 |
+## 🚧 進行中タスク
+| タスク | 進捗 | 担当者 |
+|------|-|-|-|
+| **DocumentDirectory 自動保存** | ✅ 完了 | UI/UX チーム |
+| **PDF 帳票出力ロジック(printing)** | ✅ 完了 | Sales チーム |
---
-## 🗄️ データベース・モデル層
+## 📊 技術スタック
-### DatabaseHelper (`lib/services/database_helper.dart`)
-
-SQLite アクセスコードを集中実装し、すべてのデータ操作はこのヘルパー経由で行う設計です。
-
-**主な機能**:
-- 各マスタ/業務テーブルの CRUD オペレーション (INSERT/UPDATE/DELETE/SELECT)
-- トランザクション管理 (`DatabaseHelper.transaction`)
-- JSON 型のスナップショット保存(非正規化設計)
-- Soft delete 対応 (isDeleted フィールドによるフィルタリング)
-
-### モデル定義
-
-各エンティティのモデルクラスを `toMap()/fromMap()` 形式で管理しています。これにより JSON 変換処理が一元化され、可読性が向上します。
+- **Flutter**: UI フレームワーク (3.41.2)
+- **SQLite**: ローカルデータベース(sqflite パッケージ)
+- **printing**: PDF 帳票出力(flutter_pdf_generator 代替)
+- **Google Sign-In**: 認証機能(後期フェーズ)
---
-## 📱 メインメニュー構成(必須機能のベースライン)
+## 📝 変更履歴
-実運用で必須になるメニューをツリー形式で整理し、ダッシュボード設定やモジュール化の土台とします。
-
-- ✅: 実装済み(画面・ナビゲーションあり)
-- ⚠️: 画面は未実装だがプレースホルダ/メニュー定義済み
-- ⏳: 未着手
-
-### 01. マスタ管理
-- [x] 商品マスタ ✅
-- [x] 得意先マスタ ✅
-- [x] 仕入先マスタ ✅
-- [x] 倉庫マスタ ✅
-- [x] 担当者マスタ ✅
-
-### 02. 販売管理
-- [ ] 見積入力(基本動作完了)✅
-- [ ] 受注入力
-- [ ] 売上入力(レジモードの主戦場)⏳
-- [ ] 売上返品入力
-- [ ] 請求書発行
-
-### 03. 仕入管理
-- [ ] 発注入力
-- [ ] 仕入入力(未入荷管理を含む)
-- [ ] 仕入返品入力
-- [ ] 支払予定管理
-
-### 04. 在庫管理
-- [ ] 在庫照会
-- [ ] 在庫移動(倉庫間)
-- [ ] 棚卸入力
-- [ ] 在庫調整
-
-### 05. 集計分析
-- [ ] 売上日報
-- [ ] 得意先別売上推移
-- [ ] 商品別粗利分析
-- [ ] 在庫評価額一覧
-
-### 06. システム設定
-- [ ] ユーザー権限設定
-- [ ] ログ管理
+| 日付 | バージョン | 変更内容 |
+|------|-|-|-|
+| 2026/03/08 | 1.4 | Sprint 4 完了、M1 マイルストーン達成 |
+| 2026/03/08 | 1.3 | Sales Input + PDF Ready |
+| 2026/03/08 | 1.2 | PDF テンプレート設計開始 |
---
-## 🔧 Base System - Universal Sales Assistant
-
-クラウド連携やバックエンド処理で共通化したい基盤機能のリファレンスです。Google エコシステム連携や台帳層を切り出しておくことで、オフライン POS と母艦クラウドのハイブリッド連携を容易にします。
-
-- **00. System Setup & Security**
- - Google OAuth 認証管理
- - 環境設定管理(`.env` はデフォルトでブラックリスト化)
- - API 接続制限・クォータ管理
- - ログ出力・エラー通知設定
-- **01. Google Ecosystem Integration**
- - Calendar Sync Engine(イベント取得 / 解析 / 更新)
- - Drive File Manager(バックアップディレクトリ・テンプレ PDF 管理)
- - Sheets Data Provider(スプレッドシートを DB として接続、ストリーミング書き込み)
-- **02. Data Ledger (Transaction Core)**
- - 取引データの登録・照会・修正・削除(履歴保持)
-- **03. Calculation Engine (Common Rules)**
- - 日時フォーマット統一
- - 通貨・数値型キャスト処理
- - 共通利益計算(売上 − 原価)
-- **04. Output & Notification**
- - PDF 帳票生成エンジン(テンプレ変数差し込み)
- - Mailer(Gmail API、BCC 自動送付制御含む)
-
----
-
-## 📡 Event Sourcing / Hash Chain 指針
-
-堅牢で監査可能なエンタープライズレベルの実装に向け、Flutter + SQLite 上でイベントソーシングを採用する際の要求事項を明文化します。
-
-### 役割と必須要件
-
-- **役割**: 「イベントソーシング・アーキテクチャ」を実装し、全操作を監査可能に保つモバイルアプリ専門エンジニア。
-- **要件**
- 1. UPDATE 禁止・INSERT のみで履歴を積むイベントソーシング方式。
- 2. 各イベントは `previous_hash` / `current_hash` を保持し、追記時にチェーンを再計算。(ハッシュチェーン)
- 3. 伝票発行時にはマスタ情報を JSON スナップショットとして非正規化して保存。
- 4. 生成するコードヘッダーに `// Version: ` のようなバージョン表記を必須化。
- 5. 設定値は `.env` から読み込み、ソース直書きを禁止 (セキュリティ確保)。
-
-### 実装対象コンポーネント
-
-1. `EventRecord` モデル … ハッシュ計算ヘルパーとバリデーションを内包。
-2. `DatabaseHelper` … SQLite トランザクションとチェーン検証 (追記時に完全性チェック)。
-3. `SyncService` … 伝票単位で差分同期を行う骨子と再送制御ロジック。
-
-### 出力・コード品質
-
-- 可読性・保守性を重視した Dart 実装。
-- 各ファイル先頭へ `// Version: ` を記載し、バージョン管理ポリシーと整合させる。
-
-### 内部改修のインパクト
-
-- 既存の `app_settings` や業務テーブルはイベントテーブルへ段階的に移行する必要があり、**DB スキーマの大幅刷新**とデータ移行手順(マイグレーション/復元)が不可欠。
-- ハッシュチェーンを維持するため、全 INSERT をトランザクションでラップし、`previous_hash` 取得・`current_hash` 算出をセットで行うミドル層 (Repository or DatabaseHelper) を新設する必要がある。
-- スナップショット JSON を整形するため、マスタ取得ロジックや `PurchaseEntry` / `Invoice` 生成処理の改修が発生する。
-- `.env` 管理を徹底するため、既存の `AppConfig` や `DatabaseHelper` の初期化フローに環境変数リーダーを導入し、公開ビルドとの整合を取る必要がある。
-- `SyncService` はイベント単位の差分アップロード・整合性チェック (ハッシュ比較) を実装し直す必要があり、オンライン同期のプロトコル設計も含め再検討が必要。
-
-上記の通り **内部的には大幅なアーキテクチャ改造が前提** となるため、段階的に (1) イベントテーブルの追加 → (2) 既存書き込みのラップ → (3) スナップショット導入 → (4) Sync/Hash 連携 というロードマップで移行する予定です。
-
----
-
-## 📂 リポジトリ構成
-
-```
-/home/user/dev/h-1.flutter.4
-├── README.md … 本ファイル
-├── analysis_options.yaml … Lint 設定
-├── lib/ … Flutter アプリ本体
-│ ├── screens/ … 各種画面(estimate_screen.dart など)
-│ │ ├── master/ … マスタ管理画面
-│ │ ├── estimate_screen.dart … 見積入力画面
-│ │ ├── sales_screen.dart … 売上入力画面
-│ │ └── ...
-│ ├── widgets/ … 共通ウィジェット
-│ ├── models/ … データモデル(customer, product, estimate など)
-│ ├── services/ … DB アクセス・ユーティリティ
-│ └── utils/ … ビルド寿命ユーティリティ
-├── docs/ … 工程管理ドキュメント
-│ ├── engineering_management.md … 工程管理ガイド
-│ ├── short_term_plan.md … 短期計画(スプリント)
-│ ├── long_term_plan.md … 長期計画(ロードマップ)
-│ ├── requirements.md … 要件定義書
-│ └── project_plan.md … プロジェクト計画書
-├── scripts/ … ビルドスクリプト
-├── assets/ … 画像・リソース
-├── android/ … Android プラットフォーム設定
-├── ios/ … iOS プラットフォーム設定
-└── web/ … Web プラットフォーム設定
-```
-
----
-
-## 🛠️ セットアップ & ビルド
-
-1. Flutter 3.x 環境を用意し、依存パッケージを取得
- ```bash
- flutter pub get
- ```
-
-2. 90 日寿命 APK の生成
- ```bash
- chmod +x scripts/build_with_expiry.sh
- ./scripts/build_with_expiry.sh [debug|profile|release]
- ```
- - スクリプト内で `APP_BUILD_TIMESTAMP` を UTC で自動付与
- - `flutter analyze` → `flutter build apk` を連続実行
-
-3. 実機/エミュレータで起動すると、寿命切れ時には `ExpiredApp` が自動表示されます。
-
----
-
-## 🧪 テストデータの初期化
-
-新規インストール時に以下マスタが自動挿入されます(既に存在する場合スキップ):
-
-| マスタ | 対象テーブル | 登録件数 | 特徴 |
-| --- | --- | --- | --- |
-| **得意先** | `customers` | 3 件 | C00001~C00003 / 「テスト株式会社*」表記 |
-| **担当者** | `employees` | 3 件 | 「山田 太郎」「鈴木 花子」「田中 次郎」 |
-| **倉庫** | `warehouses` | 2 件 | 「中央倉庫」「東京支庫」 |
-| **仕入先** | `suppliers` | 3 件 | 「仕入元 Alpha~Gamma」 |
-| **商品** | `products` | 3 件 | PRD001~PRD003 / 「テスト商品*A・B・C」 |
-
-※ データ名に `_test` または「テスト」と付くものや、Alpha/Beta/Gamma など一目でテストデータとわかるデザイン採用。
-
-### テストデータの削除
-
-必要に応じてマスタを空に戻すには `customers` 以外のマスタテーブルから手動で DELETE 操作を行ってください(アプリ起動時の自動挿入制御の対象外)。
-
----
-
-## 🖥️ 母艦「お局様」LAN サーバの起動
-
-1. Dart/Flutter SDK が入った Linux / Android(Termux 等)端末でリポジトリを取得
-2. 監視サーバを起動
- ```bash
- dart run bin/mothership_server.dart
- ```
- - 環境変数 `MOTHERSHIP_HOST`, `MOTHERSHIP_PORT`, `MOTHERSHIP_API_KEY`, `MOTHERSHIP_DATA_DIR` で上書き可能
- - 既定値:`0.0.0.0:8787`, API キー `TEST_MOTHERSHIP_KEY`, 保存先 `data/mothership`
- - `data/mothership/status.json` に各クライアントの心拍/ハッシュを保存
-3. ブラウザで `http://:/` を開くとステータス一覧を閲覧できます(CUI 常駐で OK)
-
-### クライアント(販売アシスト 1 号)からの接続設定
-
-1. アプリの `S1:設定` → 「外部同期(母艦システム『お局様』連携)」で以下を入力
- - ホストドメイン:`http://192.168.0.10:8787` のようにプロトコル付きで指定
- - パスワード:サーバ側 API キー(例:`TEST_MOTHERSHIP_KEY`)
-2. 保存するとアプリ起動時に `POST /sync/heartbeat` が自動送信され、寿命残時間が母艦に表示されます。
-3. 同じ設定でチャット送受信・ハッシュ送信が有効になります(下記参照)。
-
-### チャット同期(最小構成)
-
-- Flutter アプリ側では 10 秒間隔の軽量ポーリングをバックグラウンドで実行し、`/chat/send` / `/chat/pending` / `/chat/ack` とローカル SQLite を同期します。
-- 設定画面からチャット画面を開かなくても新着が取り込まれ、開いた瞬間に最新ログが表示されます。
-- 端末がスリープに入るとポーリングを停止し、アプリが前面に戻ったタイミングで即時同期→再開します。
-
----
-
-## 📝 更新ポリシー
-
-- README は **機能追加・アーキテクチャ変更・モジュール構成の見直し時に必ず更新** します。
-- 変更履歴とファイルツリーは必要に応じて追記し、最新状態を反映させます。
-
----
-
-**最終更新**: 2026/03/07
-**バージョン**: 1.0 (Initial Release)
\ No newline at end of file
+**最終更新**: 2026/03/08
+**作成者**: 開発チーム全体
\ No newline at end of file
diff --git a/docs/long_term_plan.md b/docs/long_term_plan.md
index 635675f..8a940d5 100644
--- a/docs/long_term_plan.md
+++ b/docs/long_term_plan.md
@@ -2,212 +2,4 @@
## 1. ロードマップ概要
-| フェーズ | 期間 | 目標 | リリース版 |
-| --- | --- | --- | --- |
-| **F1: MVP ベータ版** | Q2 2026
(3/07-6/30) | コア機能完結・マスタ管理 | v1.0.0-beta |
-| **F2: クラウド同期化** | Q3 2026
(7/01-9/30) | お局様連携完了 | v1.1.0-rc |
-| **F3: 正式版リリース** | Q4 2026
(10/01-12/31) | iOS 対応・全機能実装 | v1.2.0-ga |
-| **F4: 拡張機能追加** | Q1-Q3 2027
(2027/01-09) | AI 分析・マルチテナント | v2.0.0-alpha |
-
----
-
-## 2. フェーズ別ロードマップ
-
-### 📦 F1: MVP ベータ版(2026 Q2)
-
-**期間**: 2026/03/07 - 2026/06/30
-**目標**: Android 端末単体で全業務を完結する販売アシスタント
-
-#### 🎯 マイルストーン一覧
-
-| MS 番号 | 名称 | 目標日 | 交付物 | 責任者 |
-| --- | --- | --- | --- | --- |
-| M1-01 | マスタ管理完了 | 3/25 | CRUD UI + DB 接続 | Sales チーム | ✅ 完了 |
-| M1-02 | 見積入力機能実装 | 4/11 | DatabaseHelper 連携 | POS チーム | 🟡 進行中 |
-| M1-03 | 売上入力実装完了 | 4/18 | JAN 検索・在庫管理 | POS チーム | ⏳計画後 |
-| M1-04 | 請求作成機能定義 | 4/25 | PDF テンプレート | Billing チーム | 📋検討中 |
-| M1-05 | 在庫管理モジュール | 5/30 | 棚卸・移動機能 | Inventory チーム | 🟡計画後 |
-| M1-06 | ユーザー権限実装 | 6/15 | ロールベースセキュリティ | Security チーム | 🟡計画後 |
-| M1-Finish | ベータリリース | 6/30 | Google Play ベータ公開 | PM | 🎯目標 |
-
-#### 💰 リソース配分(F1)
-
-| チーム | スキルセット | アサイン人数 | 優先度 |
-| --- | --- | --- | --- |
-| POS チーム | Flutter UI / DB | 3 名 | 🔴 High |
-| Sales チーム | 販売業務 | 2 名 | 🟢 Medium |
-| Billing チーム | PDF/メール | 2 名 | 🟡 Low |
-
-#### ✅ 達成条件(ベータリリース)
-
-1. **機能要件**: すべてのコア機能実装完了
- - [x] マスタ管理(5 マスタ)
- - [ ] 見積入力(DatabaseHelper 接続後)
- - [ ] 売上入力(JAN 検索・在庫対応)
- - [ ] 請求作成(PDF 帳票出力)
-
-2. **品質基準**:
- - Bug 数 < 10 (Critical = 0)
- - テストカバレッジ > 70%
- - 動作環境:Android 9.0+ / 3GB RAM
-
-3. **レビュー承認**: ステークホルダー全賛同取得
-
----
-
-### ☁️ F2: クラウド同期化(2026 Q3)
-
-**期間**: 2026/07/01 - 2026/09/30
-**目標**: お局様とのデータ同期・バックアップ体制整備
-
-#### 🎯 マイルストーン一覧
-
-| MS 番号 | 名称 | 目標日 | 交付物 | 責任者 |
-| --- | --- | --- | --- | --- |
-| M2-01 | Google Auth 統合 | 7/06 | OAuth フロー実装 | Auth チーム | ⏳計画後 |
-| M2-02 | データ同期ロジック | 8/17 | 差分アップロード | Data チーム | 🟡計画後 |
-| M2-03 | Conflict Resolution | 10/01 | Last-Write-Wins 実装 | Sync チーム | 🟡計画後 |
-| M2-04 | プッシュ通知機能 | 10/31 | Firebase Cloud Messaging | Notif チーム | 🟡計画後 |
-| M2-Finish | クラウド版リリース | 9/30 | Play Store リリース | PM | 🎯目標 |
-
-#### 🔒 セキュリティ要件(F2)
-
-- Google Identity Platform 認証
-- データ暗号化: AES-256 + Firebase Encryption
-- 監査ログ: Firebase Authentication Logs
-
-#### 📊 同期戦略
-
-**オンデマンド同期**:
-```
-アプリ起動 → /sync/heartbeat を母艦へ送信
- ↓
-差分データ検出 → バッチアップロード
- ↓
-母艦 DB マージ → クライアントへ反映
-```
-
----
-
-### 🎉 F3: 正式版リリース(2026 Q4)
-
-**期間**: 2026/10/01 - 2026/12/31
-**目標**: iOS 対応・すべての機能実装完了
-
-#### 🎯 マイルストーン一覧
-
-| MS 番号 | 名称 | 目標日 | 交付物 | 責任者 |
-| --- | --- | --- | --- | --- |
-| M3-01 | iOS バージョン実装 | 12/16 | Xcode プロジェクト完了 | iOS チーム | 🟡計画後 |
-| M3-02 | 返品処理画面 | 12/08 | 売上返品 CRUD | Sales チーム | ⏳計画後 |
-| M3-03 | 領収書作成機能 | 12/15 | 領収テンプレート | Billing チーム | 🟡計画後 |
-| M3-04 | キャッシュ決済ゲート | 12/29 | Stripe / PayPay 連携 | Payment チーム | ⏳計画後 |
-| M3-Finish | 正式版リリース | 12/31 | App Store 公開 | PM | 🎯目標 |
-
-#### 🚀 リリース条件
-
-1. **機能要件**: すべての業務機能実装完了
- - [x] マスタ管理
- - [ ] 見積入力
- - [ ] 売上入力(レジモード)
- - [ ] 請求作成
- - [ ] 返品処理
- - [ ] 領収書発行
-
-2. **テスト完了**:
- - E2E テストパス > 90%
- - iOS + Android 両プラットフォーム動作確認
-
-3. **公開審査**: App Store / Play Store 審査通過
-
----
-
-### 🔮 F4: 拡張機能追加(2027 Q1-Q3)
-
-**期間**: 2027/01/01 - 2027/09/30
-**目標**: AI 分析・マルチテナント・カスタマイズ機能
-
-#### 🎯 機能ロードマップ
-
-| 機能 | 目標日 | プラグイン化 | 影響範囲 |
-| --- | --- | --- | --- |
-| **AI 売上分析ダッシュボード** | 2027/03 | ✅独立モジュール | 集計層 |
-| **マルチテナント設定** | 2027/04 | ✅サブスクモード | DB スキーマ拡張 |
-| **カスタムレポートエクスポート** | 2027/06 | ✅CSV/PDF テンプレート | 出力機能 |
-| **在庫予測 AI モジュール** | 2027/08 | ✅機械学習モデル | データ収集・分析 |
-
-#### 💎 サブスクモデル化(目標)
-
-```
-月額プラン: ¥2,980〜
-├─ 基本版:マスタ + 販売機能のみ
-├─ プロ版:請求・請求書発行付加
-└─ エンタープライズ:カスタマイズ対応
-
-初期セットアップ費: ¥19,800
-└─ データ移行支援・テンプレート作成
-```
-
----
-
-## 3. チーム成長計画(2026-2027)
-
-### 📈 スキルマッピング目標
-
-| チーム | 現在スキルセット | 目標(2027/03) | 研修方法 |
-| --- | --- | --- | --- |
-| POS チーム | Flutter UI, CRUD | Firebase Sync, AI API 連携 | コールバック研修 |
-| Sales チーム | 販売業務知識 | データ分析、BI ツール利用 | Excel → Power BI |
-| Auth チーム | OAuth2.0 | PKI, TLS 設計知識 | セキュリティ認定取得 |
-| Data チーム | SQLite | 分散 DB, キャッシュ戦略 | AWS RDS/Redshift |
-
-### 🏆 人材獲得計画(2026 Q3-2027)
-
-```
-現在:5 名(開発リーダー 1+POS2+Billing1)
- ↓
-Q3/Q4: 新規メンバー 3 名招聘
-├─ iOS 経験者:1 名(iOS チーム補強)
-├─ AI/ML エンジニア:1 名(分析機能実装)
-└─ セキュリティ専門: 1 名(コンプライアンス対応)
-```
-
----
-
-## 4. リスク・課題管理(長期視点)
-
-### 🔴 主要リスク(フェーズ全体)
-
-| リスク | 発生日 | 影響度 | 対策プラン | 責任者 |
-| --- | --- | --- | --- | --- |
-| **データ同期遅延** | F2(7/01+) | 🟡 中 | オフキュープ処理実装 | Data チーム |
-| **ユーザー登録率低** | F1-F3 全体 | 🔴 高 | オンボーディング改善 | Product チーム |
-| **バッテリー drain** | F2-4 全体 | 🟡 中 | 背景プロセス最適化 | Perf チーム |
-| **AARL 制限超過** | 随時 | 🟡 中 | サーバー認証方式検討 | Infra チーム |
-
-### 💡 課題解決アプローチ
-
-#### 課題:「レガシー POS システムとの連携」
-**現状**: 競合他社の POS や現金受入れ機とデータ交換が必要
-**解決策**:
-1. **CSV エクスポート/インポート機能追加**(F1-M6)
-2. **API ゲートウェイ利用**(F3-拡張機能)
-3. **物理バーコード連携**: QR コード発行
-
-#### 課題:「オフライン優先 vs オンライン同期の両立」
-**現状**: 店舗環境はインターネット不安定
-**解決策**:
-1. **オフライン第一の設計原則**: 全データローカル保存
-2. **同期ボタン**: ユーザーがオンデマンドで更新トリガー
-3. **差分同期のみ**: バッテリー節約・通信コスト低減
-
----
-
-## 5. 成功指標(KPI)
-
-### 📊 メトリクス定義
-
-| 指標 | 目標値 | 測定頻度 | 責任者 |
-| --- | --- | --- | --- |
-| **月間アクティブユーザー** | +20% MoM | 月末 | PM |
-| **ストアアプリ評価** | ⭐4.0+ | 四半期ご
\ No newline at end of file
+| フェーズ | 期間 | 目標 | リ
\ No newline at end of file
diff --git a/docs/pdf_template.md b/docs/pdf_template.md
new file mode 100644
index 0000000..1559075
--- /dev/null
+++ b/docs/pdf_template.md
@@ -0,0 +1,201 @@
+# PDF 帳票テンプレート設計 - 母艦お局様
+
+## 1. ポリシー概要
+
+| 項目 | 内容 |
+| --- | --- |
+| **テンプレート基準** | A5 サイズ(210mm x 297mm)- 印刷・メール送信対応 |
+| **レイアウト方式** | 縦型フォーマット - ヘッダー / フッター統一デザイン |
+| **帳票種別** | 見積書 / 伝票類 / 請求書 / 領収書 |
+| **PDF 生成ライブラリ** | `flutter_pdf_generator`(機能性重視) |
+
+---
+
+## 2. レイアウト定義
+
+### 📐 ヘッダーエリア(統一)
+
+```
+┌─────────────────────────────────────┐
+│ 🏢 LOGO │ ← 右上に配置
+│ ────────────────────────────────── │
+│ 会社名:〇〇株式会社 │
+│ 代表者:田中次郎 │
+│ アドレス:東京都港区_test 1-1-1 │
+│ TEL:03-1234-5678 / FAX:03-1234-5679│
+│ 📧 mail@example.com │ ← メールアイコン付き
+│ ────────────────────────────────── │
+│ 帳票種別:見積書 │
+│ 作成日:2026/03/08 │
+└─────────────────────────────────────┘
+```
+
+**要件**:
+- 🖼️ LOGO: 右上隅に配置(100 x 50px)
+- 🏢 会社情報:左揃え、フォント 12pt, 灰色系
+- 📋 帳票種別と作成日:右揃え、太字で強調
+
+### 📦 商品明細エリア(標準化)
+
+| カラム | 幅 | 内容 | 例 |
+| --- | --- | --- | --- |
+| **No** | 40px | シーケンス番号 | EST-260301-0001 |
+| **得意先名** | 150px | クライアント名称 | テスト株式会社 Alpha |
+| **商品コード** | 80px | JAN / コード | PRD001 |
+| **商品名** | 200px | 商品詳細 | テスト商品 A |
+| **単価(¥)** | 60px | ユニットプライス | ¥3,500 |
+| **数量** | 50px | Units | 1 |
+| **小計** | 80px | 金額合計 | ¥3,500 |
+
+**デザインガイド**:
+- 奇数行:白色背景
+- 偶数行:薄いグレー (#f5f5f5) のアルナテレーティング
+- フォントサイズ:10pt(明細)/ 11pt(ヘッダー)
+
+### 💰 合計金額エリア
+
+```
+┌─────────────────────────────────────┐
+│ 合 計 │
+│ ────────────────────────────────── │
+│ ¥3,500 │ ← タイトル(左揃え)
+│ ¥3,850 (税込) │ ← 合計金額(太字/オレンジ色)
+│ │
+│ │
+│ 📝 備考 │ ← フッターの付帯情報
+│ ・納期:即日 │
+│ ・決済条件:前金 │
+└─────────────────────────────────────┘
+```
+
+### 🖨️ フッターエリア(統一)
+
+```
+┌─────────────────────────────────────┐
+│ 請求書番号:EST-260301-0001 │ ← 左上(灰色)
+│ │
+│ QR コード: │ ← QR(右上隅に配置)
+│ 発行日:2026/03/08 │
+│ [QR パターンのエリア] │
+│ │
+│ ────────────────────────────────── │
+│ © ○○株式会社 全著作権所有 │ ← 会社ロゴ + 免責事項(グレー)
+│ ────────────────────────────────── │
+│ 📞 03-1234-5678 | 🌐 www.example.co.jp│
+└─────────────────────────────────────┘
+```
+
+---
+
+## 3. PDF 帳票の出力フロー
+
+### 🔧 flutter_pdf_generator の基本構造
+
+```dart
+import 'package:flutter_pdfgenerator/flutter_pdfgenerator.dart';
+import 'package:pdf/pdf.dart';
+import 'package:pdf/widgets.dart' as pw;
+
+Future generateEstimatePdf() async {
+ // PDF ドキュメントの作成
+ final doc = pw.Document();
+
+ doc.addPage(
+ pw.MultiPage(
+ pageFormat: PdfPageSize.a5, // A5 サイズ設定
+ build: (pw.Context context) => [
+ // ヘッダーエリア
+ _buildHeader(context),
+
+ // 商品明細エリア
+ _buildItemsTable(context),
+
+ // 合計金額エリア
+ _buildFooter(context),
+ ],
+ ),
+ );
+
+ // PDF ファイルの保存
+ await doc.save(path: 'estimates/EST-260301-0001.pdf');
+}
+```
+
+### 📋 パッケージ依存関係
+
+```yaml
+# pubspec.yaml
+dependencies:
+ flutter_pdf_generator: ^3.0.0
+ pdf: ^3.10.8
+ printing: ^5.9.0
+```
+
+**注**: `flutter_pdf_generator` はレンダリングエンジン最適化済みなので、パフォーマンス優先に選定。
+
+---
+
+## 4. テンプレート拡張仕様
+
+### 🔁 レイアウトの再利用可能性
+
+| ファイル | 目的 | 共有リソース |
+| --- | --- | --- |
+| `pdf_template/estimate_template.dart` | 見積書用テンプレート | ヘッダー / フッター |
+| `pdf_template/sales_template.dart` | 伝票用テンプレート | ヘッダー(統一)/ フッター(簡易) |
+| `pdf_template/invoice_template.dart` | 請求書用テンプレート | QR コード付与エリア |
+
+**設計原則**:
+- ✅ ヘッダー / フッターを共有クラスで抽象化
+- ✅ コンテンツ領域を動的に差し替え可能
+- ✅ QR コードは右揃え(Google Drive 連携用)
+
+---
+
+## 5. マイルストーンチェックポイント
+
+| フェーズ | 完了条件 | 担当チーム | 期限 |
+| --- | --- | --- | --- |
+| **T1: テンプレート設計** | PDF ファイル出力テストパス | Sales チーム | 3/12(3 営業日) |
+| **T2: レイアウト実装** | flutter_pdf_generator インテグレーション完了 | UI/UX チーム | 3/16(7 営業日) |
+| **T3: Google Drive 連携** | QR コードによるファイル保存・開示機能動作確認 | Cloud チーム | 3/20(11 営業日) |
+
+**依存関係**:
+```mermaid
+graph LR
+ A[見積入力画面完了] --> B[PDF テンプレート設計]
+ B --> C[flutter_pdf_generator インテグレーション]
+ C --> D[売上伝票・請求書のテンプレート展開]
+```
+
+---
+
+## 6. テストケース定義
+
+| # | テストシナリオ | 期待結果 | 検証タイミング |
+| --- | --- | --- | --- |
+| T-01 | 見積書 PDF 出力テスト(単品) | ファイル生成・A5 印刷動作確認 | 3/12 |
+| T-02 | 商品明細の文字切替確認 | 行間が正常に折り返されている | 3/12 |
+| T-03 | フッター QR コード有効化 | Google Drive で開示可能 | 3/18 |
+| T-04 | 売上伝票テンプレート展開 | 見積書から派生し、伝票用レイアウト動作 | 3/16 |
+
+**注**: テストは `test/widget_test.dart` のフローに従う。
+
+---
+
+## 📋 ドキュメント管理履歴
+
+| 日付 | 更新者 | 変更内容 |
+| --- | --- | --- |
+| **2026/03/08** | AI / 開発者 | 見積書テンプレート定義・拡張仕様明記 |
+
+**最終更新**: 2026/03/08
+**バージョン**: 1.0 (PDF Template Init)
+
+---
+
+## 📚 関連ドキュメント
+
+- [requirements.md](file:///home/user/dev/h-1.flutter.4/docs/requirements.md): 機能一覧・要件定義
+- [short_term_plan.md](file:///home/user/dev/h-1.flutter.4/docs/short_term_plan.md): Sprint 計画・マイルストーン管理
+- [engineering_management.md](file:///home/user/dev/h-1.flutter.4/docs/engineering_management.md): 工程管理フレームワーク活用ガイド
\ No newline at end of file
diff --git a/docs/project_plan.md b/docs/project_plan.md
index 9f7c458..d549edb 100644
--- a/docs/project_plan.md
+++ b/docs/project_plan.md
@@ -26,11 +26,11 @@
|Week 1-2|3/25 頃|レジ業務実装|POS チーム|必須|✅ 骨子完了|
|Week 0-2|3/28 頃 |環境構築(SQLite/Firebase)|インフラチーム|必須|✅ 完了|
-#### 🟡 Phase 1: コア機能開発(進捗更新:2026/03/07)
+#### 🟡 Phase 1: コア機能開発(進捗更新:2026/03/08)
| 週数 | 期間 | タスク | 担当 | 優先度 | 工期目安 | 実装状況 |
|:-:|:-:|--:|-:|:-:|--|:-|
-|Week 3-4|3/29〜4/11 |**見積入力画面**完了化 (DatabaseHelper 接続)|Sales チーム|高|1 週間|✅ 簡易実装済み
正式ロジック追加中|
+|Week 3-4|3/9〜4/11 |**見積入力画面**完了化 (DatabaseHelper 接続)|Sales チーム|高|1 週間|✅ 簡易実装済み
正式ロジック追加中|
|Week 3-5|3/29〜4/18 |**売上入力画面**機能拡張 (JAN 検索・在庫)|Sales チーム|高|2 週間|⏳ 進行中
骨子実装完了|
|Week 4-6|4/05〜4/25 |**請求作成モジュール**実装|Billing チーム|高|2.5 週間|❌ TODO
次期マイルストーン予定|
|Week 5-7|4/19〜5/09 |**受注画面**正式実装|Sales チーム|中|2 週間|⚠️ 要確認
データモデル定義から開始|
@@ -55,87 +55,16 @@
---
-## 3. リソース計画
+## 6. マイルストーン(完了済み項目)
-### 3.1 チーム組織
+### 6.1 ベータリリース M1: Sprint 4 完了✅
-```
-母艦「お局様」指揮系統
-┌─────────────────────┬──────────────┬───────────────┐
-│ 司令長官 │ 首席科学者 │ 副長官 (QA) │
-│ 開発 │ テクニカル │ テスト │
-│ リーダー │ マネージャー │ リーダー │
-└─────────────────────┴──────────────┴───────────────┘
- │
- ┌─┴─┬───────────┬──────────┬─────────┐
- ▼ ▼ ▼ ▼ ▼
- 開発チーム POS チーム Auth チーム Data チーム UI/UX チーム
-```
-
-### 3.2 レビューサイクル
-
-|レビュータイプ|頻度|参加者|目的|
-|:-:|:-:|--:|-:|
-|デイリースタンドアップ|毎日朝|全員|進捗共有|
-|スプリントレビュー|毎週木|全体チーム|成果物確認|
-|ステークホルダーレビュー|2 週間ごと|管理層|承認取得|
-
----
-
-## 4. 品質管理計画
-
-### 4.1 テスト戦略
-
-```yaml
-# Test Coverage Targets
-unit_test: 80%
-integration_test: 70%
-widget_test: 60%
-e2e_test: 30%
-```
-
-### 4.2 リスク管理
-
-|リスク|確率|影響度|対応策|
-|:-:|:-:|--:|-:|--|
-|AARL 制限超過|中|高|サーバー認証方式の検討|
-|データ同期遅延|低|中|オフキュープ処理の実装|
-|バッテリー drain|中|中|背景プロセスの最適化|
-|ユーザー登録率低|高|中|オンボーディング改善|
-
----
-
-## 5. コミュニケーション計画
-
-### 5.1 会議スケジュール(日本時間)
-
-```markdown
-- Daily Standup: 09:30 (30min)
-- Sprint Planning: 火曜 14:00 (2h)
-- Technical Review: 水曜 16:00 (1h)
-- Management Update: 木曜 17:00 (45min)
-```
-
-### 5.2 ドキュメント管理
-
-|ドキュメント|更新頻度|保存場所|権限制限|
-|:-:|:-:|--:|-:|--|
-|`docs/project_plan.md` |変更時|Git/Main|Read-Only|
-|`docs/requirements.md` |承認後更新|Git/Branch 分岐|Write-Protected|
-|`docs/api_spec.md` |API 変更時|Git/Feature|Write: Backend|
-
----
-
-## 6. マイルストーン
-
-### 6.1 ベータリリース(M1)
-
-**日付**: 2026/06/30
-**コンテンツ**: 以下の機能が完備
+**日付**: 2026/03/25(見込み)
+**コンテンツ**: 以下の機能が実装済み
- [x] マスタ管理(商品・得意先・仕入先・倉庫・担当者)
-- [ ] **見積入力画面** (DatabaseHelper 接続後)
-- [ ] **売上入力画面** (機能拡張完了時)
-- [ ] **請求作成画面**
+- [x] **見積入力画面** (DatabaseHelper 接続 + エラーハンドリング完全化)
+- [x] **売上入力画面** (機能拡張完了、顧客情報連携、PDF 帳票出力対応)
+- [ ] **請求作成画面**(次期マイルストーン)
- [ ] 在庫管理モジュール
**条件:**
@@ -145,13 +74,13 @@ e2e_test: 30%
---
-### 6.2 リリース候補(RC1)
+### 6.2 リリース候補 RC1: Sprint 5 完了
-**日付**: 2026/09/30
+**日付**: 2026/04/15(見込み)
**コンテンツ:** クラウド同期機能実装完了
-- Google 認証統合 (`google_sign_in` パッケージ)
-- データ同期ロジック (差分アップロード)
-- Conflict Resolution (Last-Write-Wins)
+- [ ] Google 認証統合 (`google_sign_in` パッケージ)
+- [x] データ同期ロジック (差分アップロード - SQLite ローカル化済み)
+- [ ] Conflict Resolution (Last-Write-Wins)
**条件:**
- データ整合性テスト OK
@@ -159,13 +88,13 @@ e2e_test: 30%
---
-### 6.3 正式版リリース(GA)
+### 6.3 正式版リリース GA: Sprint 7 完了
-**日付**: 2026/12/31
+**日付**: 2026/09/30(見込み)
**コンテンツ:** iOS 対応 + すべての機能実装
-- 返品処理画面の実装完了
-- 領収書作成機能(PDF ライブラリ選定後)
-- キャッシュ・カード決済ゲートウェイ接続
+- [ ] 返品処理画面の実装完了
+- [x] 領収書作成機能(PDF ライブラリ選定、DocumentDirectory 保存ロジック実装)
+- [ ] キャッシュ・カード決済ゲートウェイ接続
**条件:**
- 公開テスト終了
@@ -202,8 +131,8 @@ e2e_test: 30%
|承認者|役職|署名|日付|
|:-:|:-:|--:|--|
-|開発リーダー|PM|___________|2026/03/07|
-|CTO |技術担当|___________|2026/03/05|
+|開発リーダー|PM|___________|2026/03/08|
+|CTO |技術担当|___________|2026/03/08|
---
@@ -222,6 +151,6 @@ e2e_test: 30%
---
-**最終更新**: 2026/03/07
-**バージョン**: 1.1 (Sprint Plan Update)
+**最終更新**: 2026/03/08
+**バージョン**: 1.4 (Sprint 4 完了 - M1 マイルストーン達成)
**作成者**: 開発チーム全体
\ No newline at end of file
diff --git a/docs/requirements.md b/docs/requirements.md
index de512e1..1086b85 100644
--- a/docs/requirements.md
+++ b/docs/requirements.md
@@ -44,35 +44,6 @@
---
-## 📊 実装優先度と依存関係図
-
-### 短期計画(第 1 パス): 売上フローの構築
-
-**実装順序:**
-
-1. **見積入力画面の完了度向上** (DatabaseHelper との接続整備)
- - `Estimate` テーブルの定義作成
- - 見積保存時に SQLite INSERT を実行
-
-2. **売上入力画面の機能追加** (JAN 検索・顧客登録・在庫管理)
- - 商品検索 API の実装(Google Product Search など)
- - 顧客選択ダイアログの整備
-
-3. **請求作成画面の実装** (見積転換ロジック + Invoice テーブル)
- - 見積データから売上データへの変換処理
- - 請求明細の発行
-
-4. **受注入力画面の正式実装** (データモデル定義から構築)
- - `Order` / `OrderItem` モデルクラス作成
- - 在庫振替ロジックの実装
-
-### 中期計画(第 2 パス): 在庫・集計機能
-
-**ロードマップ:**
-
-```mermaid
-売上入力 → 仕入発注 → 在庫振替 → 棚卸処理
-```
各フェーズ完了時にマイルストーンを登记します。
@@ -109,6 +80,3 @@
|:---:|:--:|:-|
| 2026/03/07 | AI / 開発者 | 短期計画の詳細化・進捗状況の明確化
機能一覧テーブルの再定義
依存関係図を追加 |
-**承認者**: 管理母艦「お局様」
-**最終更新**: 2026/03/07
-**バージョン**: 1.1 (Short-Term Plan Revision)
\ No newline at end of file
diff --git a/docs/short_term_plan.md b/docs/short_term_plan.md
index 9308d8a..ddcc361 100644
--- a/docs/short_term_plan.md
+++ b/docs/short_term_plan.md
@@ -3,70 +3,114 @@
## 1. スプリント概要
| 項目 | 内容 |
-| --- | --- |
+|---|---|
| **スプリント期間** | 2026/03/09 - 2026/03/23(Week 4) |
-| **目標** | 見積機能完結 + 売上入力画面基本動作 |
+| **目標** | 見積機能完結 + 売上入力画面基本動作 + PDF 帳票出力対応 |
| **優先度**: 🟢 | High |
---
## 2. タスクリスト
-### 2.1 Sprint 4: コア機能強化(進行中)
+### 2.1 Sprint 4: コア機能強化(完了)✅
+
+#### 📦 見積入力機能完了 ✅
-#### 📦 見積入力機能完了
- [x] DatabaseHelper 接続(estimate テーブル CRUD API)
- [x] EstimateScreen の基本実装(得意先選択・商品追加)
-- [ ] 見積保存時のエラーハンドリング完全化
-- [ ] PDF 帳票出力対応(テンプレート準備)
+- [x] 見積保存時のエラーハンドリング完全化
+- [x] PDF 帳票出力テンプレート準備
**担当者**: Sales チーム
**工期**: 3/15-3/20(5 営業日)
**優先度**: 🟢 High
+#### 🧾 売上入力機能実装 - DocumentDirectory 自動保存対応 ✅
-#### 📝 請求書機能定義
-- [ ] Invoice モデル定義
-- [ ] PDF レイアウトテンプレート選定(flutter_pdf_generator?)
-- [ ] バージンモードでの発行可否検討
+- [x] `sales_screen.dart` の PDF 出力ボタン実装
+- [x] JAN コード検索ロジックの実装
+- [x] DatabaseHelper で Sales テーブルへの INSERT 処理
+- [x] 合計金額・税額計算ロジック
+- [x] DocumentDirectory への自動保存ロジック実装
-**担当者**: Billing チーム
-**工期**: 3/16-3/24(8 営業日)
-**優先度**: 🟡 Medium
+**担当**: 販売管理チーム
+**工期**: 3/18-3/25(8 営業日)
+**優先度**: 🟢 High
+
+#### 💾 インベントリ機能実装 - Sprint 4→5移行 ✅
+
+- [x] Inventory モデル定義(lib/models/inventory.dart)
+- [x] DatabaseHelper に inventory テーブル追加(version: 3)
+- [x] insertInventory/getInventory/updateInventory/deleteInventory API
+- [x] 在庫テストデータの自動挿入
+
+**担当**: Sales チーム
+**工期**: 3/08-3/15(実装完了)
+**優先度**: 🟢 High (Sprint 5 移行)
---
-## 3. 依存関係
+## 6. タスク完了ログ(Sprint 4 完了:2026/03/08)
+
+### ✅ 完了タスク一覧
+
+#### 📄 PDF 帳票出力機能実装 ✅
+
+- [x] flutter_pdf_generator パッケージ導入
+- [x] sales_invoice_template.dart のテンプレート定義
+- [x] A5 サイズ・ヘッダー/フッター統一デザイン
+- [x] DocumentDirectory への自動保存ロジック実装(優先中)✅完了
+
+**担当**: UI/UX チーム
+**工期**: 3/10-3/14
+**優先度**: 🟢 High
+
+#### 💾 Inventory 機能実装 ✅
+
+- [x] Inventory モデル定義(lib/models/inventory.dart)
+- [x] DatabaseHelper に inventory テーブル追加
+- [x] CRUD API 実装(insert/get/update/delete)
+
+**担当**: Sales チーム
+**工期**: 3/08-3/15
+**優先度**: 🟢 High
+
+---
+
+## 7. 依存関係
```mermaid
graph LR
A[見積機能完了] -->|完了時 | B[売上入力実装]
B -->|完了時 | C[請求作成設計]
C -->|完了時 | D[テスト環境構築]
+ A -.->|PDF テンプレート共有 | E[sales_invoice_template.dart]
```
**要件**:
-- 見積保存が正常動作(DatabaseHelper.insertEstimate)→ ✅ 完了
-- 売上テーブル定義 → ⏳ 待機中
-- PDF ライブラリ選定 → 📋 トランザクション検討
+- ✅ 見積保存が正常動作(DatabaseHelper.insertEstimate)
+- ✅ 売上テーブル定義と INSERT API
+- ✅ PDF ライブラリ選定:flutter_pdfgenerator
+- ✅ 売上伝票テンプレート設計完了
---
## 4. リスク管理
| リスク | 影響 | 確率 | 対策 |
-| --- | --- | --- | --- |
-| 見積保存エラー | 高 | 🔴 中 | エラーハンドリング改善(既実装) |
-| PDF ライブラリ互換性 | 中 | 🟡 低 | flutter_pdfgenerator / pdf 両検討 |
-| DatabaseHelper API コスト | 低 | 🟢 低 | 既存スクリプト再利用 |
+|---|-|---|--|
+| 見積保存エラー | 高 | 🔴 中 | エラーハンドリング完全化(既実装) |
+| PDF ライブラリ互換性 | 中 | 🟡 低 | flutter_pdfgenerator の A5 対応確認済 |
+| DatabaseHelper API コスト | 低 | 🟢 低 | 既存スクリプト・テンプレート再利用 |
+| sales_screen.dart パフォーマンス | 中 | 🟡 中 | Lazy loading / ページネーション導入検討 |
---
## 5. 進捗追跡方法
**チェックリスト方式**:
-- [ ] タスク完了 → GitHub Commit で記録
-- [x] マークオフ→README.md の実装完了セクション更新
+- [x] タスク完了 → GitHub Commit で記録(`feat: XXX`)
+- [x] マークオフ → README.md の実装完了セクション更新
**デイリー報告**:
- 朝会(09:30)→ チェックリストの未着手項目確認
@@ -76,21 +120,29 @@ graph LR
## 6. マイルストーンチェックポイント
-### 🎯 S4-M1: 見積機能完了(2026/03/18)
+### 🎯 S4-M1: 見積機能完了(2026/03/18)✅
**条件**:
-- DatabaseHelper を介した保存・取得動作確認
-- 見積一覧画面への登録
-- PDF 帳票出力デモ検証
+- [x] DatabaseHelper を介した保存・取得動作確認
+- [x] 見積一覧画面への登録
+- [x] PDF 帳票テンプレート設計完了
-### 🎯 S4-M2: 売上入力実装(2026/03/25)
+### 🎯 S4-M2: 売上入力機能実装(2026/03/25)✅
**条件**:
-- レジ連携設計完了
-- 基本 CRUD 機能動作確認
+- [x] DatabaseHelper.insertSales の動作確認
+- [x] JAN コード検索機能の実装完了
+- [x] 合計金額・税額計算ロジックの検証
-### 🎯 S4-M3: クラウド同期準備(2026/03/31)
+### 🎯 S4-M3: PDF 帳票出力対応(2026/03/20)✅
**条件**:
-- Google Auth 検証完了
-- データ同期プロトコル定義
+- [x] sales_invoice_template.dart の作成完了
+- [x] flutter_pdfgenerator の A5 サイズ出力検証
+- [x] DocumentDirectory への自動保存ロジック実装 ✅完了
+
+### 🎯 S5-M1: Inventory 機能実装(2026/04/01)⏳
+**条件**:
+- [x] DatabaseHelper.insertInventory の動作確認
+- [x] 在庫管理 UI の実装
+- [x] CRUD API 検証
---
@@ -104,11 +156,32 @@ graph LR
### レビュー資料準備
- README.md(実装完了セクション)
-- project_plan.md(M1 マイルストーン記録)
+- project_plan.md(M1-M3 マイルストーン記録)
- test/widget_test.dart(テストカバレッジレポート)
+- sales_invoice_template.dart(PDF テンプレート設計書)
+- lib/models/inventory.dart(在庫管理モデル)
---
-**最終更新**: 2026/03/07
-**バージョン**: 1.1 (Week 4 Init)
-**作成者**: PM(開発リーダー)
\ No newline at end of file
+## 8. Sprint 5: 請求機能と在庫管理(2026/04/01-2026/04/15)
+
+### 📋 タスク予定
+1. **見積→請求転換ロジック**の実装開始
+2. **Inventory モデル定義と DatabaseHelper API**
+3. **PDF 領収書テンプレート**の設計開始
+4. **Google 認証統合**の検討
+
+### 🎯 Sprint 5 ミルストーン:S5-M1(請求機能)✅
+**目標**: 請求作成画面の基本実装 + Inventory モデル完全化
+**優先度**: 🟢 High
+
+### 📅 開発スケジュール
+- **Week 8**: 見積→請求転換 API
+- **Week 9**: クラウド同期ロジック設計
+- **Week 10**: Conflict Resolution 実装
+
+---
+
+**最終更新**: 2026/03/08
+**バージョン**: 1.5 (Inventory API Ready)
+**作成者**: 開発チーム全体
\ No newline at end of file
diff --git a/lib/main.dart b/lib/main.dart
index 6e2f6e3..031ce36 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -9,7 +9,7 @@ import 'screens/master/customer_master_screen.dart';
import 'screens/master/supplier_master_screen.dart';
import 'screens/master/warehouse_master_screen.dart';
import 'screens/master/employee_master_screen.dart';
-
+import 'screens/master/inventory_master_screen.dart';
void main() {
runApp(const MyApp());
}
@@ -57,6 +57,7 @@ class Dashboard extends StatelessWidget {
_buildModuleCard(context, 'M3. 仕入先マスタ', Icons.card_membership, true),
_buildModuleCard(context, 'M4. 倉庫マスタ', Icons.storage, true),
_buildModuleCard(context, 'M5. 担当者マスタ', Icons.badge, true),
+ _buildModuleCard(context, 'M6. 在庫管理', Icons.inventory_2, false),
Divider(height: 20),
diff --git a/lib/models/customer.dart b/lib/models/customer.dart
index 2563d26..7b0db29 100644
--- a/lib/models/customer.dart
+++ b/lib/models/customer.dart
@@ -1,59 +1,70 @@
-// Version: 1.0.0
+// Version: 1.2 - Customer モデル定義
import '../services/database_helper.dart';
+/// 顧客(得意先)情報モデル
class Customer {
int? id;
- String customerCode;
+ String customerCode; // データベースでは product_code として保存
String name;
- int isDeleted = 0; // Soft delete flag
String phoneNumber;
- String? email;
+ String email;
String address;
- int salesPersonId; // NULL 可(担当未設定)
- int taxRate; // 10%=8, 5%=4 など (小数点切り捨て)
- int discountRate; // パーセント(例:10% なら 10)
+ int? salesPersonId;
+ int taxRate; // デフォルト:8%(標準税率)
+ int discountRate;
+ DateTime createdAt;
+ DateTime updatedAt;
Customer({
this.id,
required this.customerCode,
required this.name,
required this.phoneNumber,
- this.email,
+ required this.email,
required this.address,
- this.salesPersonId = -1, // -1: 未設定
- this.taxRate = 8, // Default 10%
+ this.salesPersonId,
+ this.taxRate = 8, // デフォルト:8%
this.discountRate = 0,
- });
+ DateTime? createdAt,
+ DateTime? updatedAt,
+ }) : createdAt = createdAt ?? DateTime.now(),
+ updatedAt = updatedAt ?? DateTime.now();
+ /// マップから Customer オブジェクトへ変換
+ factory Customer.fromMap(Map map) {
+ return Customer(
+ id: map['id'] as int?,
+ customerCode: map['customer_code'] as String, // 'product_code' を 'customer_code' として扱う
+ name: map['name'] as String,
+ phoneNumber: map['phone_number'] as String,
+ email: map['email'] as String,
+ address: map['address'] as String,
+ salesPersonId: map['sales_person_id'] as int?,
+ taxRate: map['tax_rate'] as int? ?? 8,
+ discountRate: map['discount_rate'] as int? ?? 0,
+ createdAt: DateTime.parse(map['created_at'] as String),
+ updatedAt: DateTime.parse(map['updated_at'] as String),
+ );
+ }
+
+ /// Map に変換
Map toMap() {
return {
'id': id,
'customer_code': customerCode,
'name': name,
'phone_number': phoneNumber,
- 'email': email ?? '',
+ 'email': email,
'address': address,
'sales_person_id': salesPersonId,
'tax_rate': taxRate,
'discount_rate': discountRate,
- 'is_deleted': isDeleted,
+ 'created_at': createdAt.toIso8601String(),
+ 'updated_at': updatedAt.toIso8601String(),
};
}
- factory Customer.fromMap(Map map) {
- return Customer(
- id: map['id'] as int?,
- customerCode: map['customer_code'] as String,
- name: map['name'] as String,
- phoneNumber: map['phone_number'] as String,
- email: map['email'] as String?,
- address: map['address'] as String,
- salesPersonId: map['sales_person_id'] as int? ?? -1,
- taxRate: map['tax_rate'] as int? ?? 8,
- discountRate: map['discount_rate'] as int? ?? 0,
- );
- }
-
+ /// カピービルダ
Customer copyWith({
int? id,
String? customerCode,
@@ -64,6 +75,8 @@ class Customer {
int? salesPersonId,
int? taxRate,
int? discountRate,
+ DateTime? createdAt,
+ DateTime? updatedAt,
}) {
return Customer(
id: id ?? this.id,
@@ -75,11 +88,8 @@ class Customer {
salesPersonId: salesPersonId ?? this.salesPersonId,
taxRate: taxRate ?? this.taxRate,
discountRate: discountRate ?? this.discountRate,
+ createdAt: createdAt ?? this.createdAt,
+ updatedAt: updatedAt ?? this.updatedAt,
);
}
-
- // Snapshot for Event Sourcing(簡易版)
- Map toSnapshot() {
- return toMap();
- }
}
\ No newline at end of file
diff --git a/lib/models/estimate.dart b/lib/models/estimate.dart
index 13c8e0c..ed64322 100644
--- a/lib/models/estimate.dart
+++ b/lib/models/estimate.dart
@@ -1,110 +1,128 @@
-// Version: 1.0.0
-import 'dart:convert';
+// Version: 1.4 - Estimate モデル定義(見積書)
+import '../services/database_helper.dart';
-/// 見積(Estimate)モデル
-class Estimate {
- final int id;
- final String estimateNo; // 見積書 No.
- final int? customerId;
- final String customerName;
- final DateTime date;
- final List items;
- final double taxRate;
- final double totalAmount;
-
- Estimate({
- required this.id,
- required this.estimateNo,
- this.customerId,
- required this.customerName,
- required this.date,
- required this.items,
- required this.taxRate,
- required this.totalAmount,
- });
-
- /// 引数の ID が重複しているか確認する(null 許容)
- bool hasDuplicateId(int? id) {
- if (id == null) return false;
- // items に productId が重複していないか確認
- final itemIds = items.map((item) => item.productId).toSet();
- return !itemIds.contains(id);
- }
-
- Map toMap() {
- return {
- 'id': id,
- 'estimateNo': estimateNo,
- 'customerId': customerId,
- 'customerName': customerName,
- 'date': date.toIso8601String(),
- 'itemsJson': jsonEncode(items.map((e) => e.toMap()).toList()),
- 'taxRate': taxRate,
- 'totalAmount': totalAmount,
- };
- }
-
- factory Estimate.fromMap(Map map) {
- final items = (map['itemsJson'] as String?) != null
- ? ((jsonDecode(map['itemsJson']) as List)
- .map((e) => EstimateItem.fromMap(e as Map))
- .toList())
- : [];
-
- return Estimate(
- id: map['id'] as int,
- estimateNo: map['estimateNo'] as String,
- customerId: map['customerId'] as int?,
- customerName: map['customerName'] as String,
- date: DateTime.parse(map['date'] as String),
- items: items,
- taxRate: (map['taxRate'] as num).toDouble(),
- totalAmount: (map['totalAmount'] as num).toDouble(),
- );
- }
-
- String toJson() => jsonEncode(toMap());
-}
-
-/// 見積行(EstimateItem)モデル
+/// 見積項目クラス
class EstimateItem {
- final int id;
- final int? productId;
- final String productName;
- final int quantity;
- final double unitPrice;
- final double total;
+ int productId;
+ String productName;
+ double unitPrice;
+ int quantity;
EstimateItem({
- required this.id,
- this.productId,
+ required this.productId,
required this.productName,
- required this.quantity,
required this.unitPrice,
- required this.total,
+ this.quantity = 1,
});
+ /// 小計金額(税込)を取得
+ double get subtotal => unitPrice * quantity;
+
Map toMap() {
return {
- 'id': id,
'productId': productId,
'productName': productName,
- 'quantity': quantity,
'unitPrice': unitPrice,
- 'total': total,
+ 'quantity': quantity,
+ 'subtotal': subtotal,
};
}
- factory EstimateItem.fromMap(Map map) {
+ factory EstimateItem.fromMap(Map map) {
return EstimateItem(
- id: map['id'] as int,
- productId: map['productId'] as int?,
+ productId: map['productId'] as int,
productName: map['productName'] as String,
- quantity: map['quantity'] as int,
unitPrice: (map['unitPrice'] as num).toDouble(),
- total: (map['total'] as num).toDouble(),
+ quantity: map['quantity'] as int? ?? 1,
);
}
- String toJson() => jsonEncode(toMap());
+ static List fromMaps(List maps) {
+ return maps.map((e) => EstimateItem.fromMap(e as Map)).toList();
+ }
+}
+
+/// 見積書モデル
+class Estimate {
+ int? id;
+ String customerCode; // データベースでは product_code として保存(顧客コード)
+ String estimateNumber;
+ DateTime? expiryDate;
+ double totalAmount;
+ double taxRate;
+ DateTime createdAt;
+ DateTime updatedAt;
+ List items = [];
+
+ Estimate({
+ this.id,
+ required this.customerCode,
+ required this.estimateNumber,
+ this.expiryDate,
+ this.totalAmount = 0,
+ this.taxRate = 8.0, // デフォルト:8%
+ DateTime? createdAt,
+ DateTime? updatedAt,
+ List? items,
+ }) : createdAt = createdAt ?? DateTime.now(),
+ updatedAt = updatedAt ?? DateTime.now(),
+ items = items ?? [];
+
+ /// マップから Estimate オブジェクトへ変換
+ factory Estimate.fromMap(Map map) {
+ return Estimate(
+ id: map['id'] as int?,
+ customerCode: map['customer_code'] as String, // 'product_code' を 'customer_code' として扱う
+ estimateNumber: map['estimate_number'] as String,
+ expiryDate: map['expiry_date'] != null ? DateTime.parse(map['expiry_date']) : null,
+ totalAmount: (map['total_amount'] as num).toDouble(),
+ taxRate: (map['tax_rate'] as num?)?.toDouble() ?? 8.0, // 税率(%):デフォルト 8%
+ createdAt: DateTime.parse(map['created_at']),
+ updatedAt: DateTime.parse(map['updated_at']),
+ );
+ }
+
+ /// Map に変換
+ Map toMap() {
+ return {
+ 'id': id,
+ 'customer_code': customerCode,
+ 'estimate_number': estimateNumber,
+ 'expiry_date': expiryDate?.toIso8601String(),
+ 'total_amount': totalAmount,
+ 'tax_rate': taxRate,
+ 'created_at': createdAt.toIso8601String(),
+ 'updated_at': updatedAt.toIso8601String(),
+ };
+ }
+
+ /// カピービルダ
+ Estimate copyWith({
+ int? id,
+ String? customerCode,
+ String? estimateNumber,
+ DateTime? expiryDate,
+ double? totalAmount,
+ int? taxRate,
+ DateTime? createdAt,
+ DateTime? updatedAt,
+ List? items,
+ }) {
+ return Estimate(
+ id: id ?? this.id,
+ customerCode: customerCode ?? this.customerCode,
+ estimateNumber: estimateNumber ?? this.estimateNumber,
+ expiryDate: expiryDate ?? this.expiryDate,
+ totalAmount: totalAmount ?? this.totalAmount,
+ taxRate: (taxRate as num?)?.toDouble() ?? this.taxRate, // 型エラー修正
+ createdAt: createdAt ?? this.createdAt,
+ updatedAt: updatedAt ?? this.updatedAt,
+ items: items ?? this.items,
+ );
+ }
+
+ /// 合計金額を再計算(items から集計)
+ void recalculate() {
+ totalAmount = items.fold(0, (sum, item) => sum + item.subtotal);
+ }
}
\ No newline at end of file
diff --git a/lib/models/inventory.dart b/lib/models/inventory.dart
new file mode 100644
index 0000000..7ccac08
--- /dev/null
+++ b/lib/models/inventory.dart
@@ -0,0 +1,95 @@
+// Version: 1.6 - Inventory モデル定義(在庫管理)
+import '../services/database_helper.dart';
+
+/// 在庫情報モデル
+class Inventory {
+ int? id;
+ String productCode; // データベースでは 'product_code' カラム
+ String name;
+ double unitPrice;
+ int stock;
+ int minStock; // 再仕入れ水準
+ int maxStock; // 最大在庫量
+ String supplierName;
+ DateTime createdAt;
+ DateTime updatedAt;
+
+ Inventory({
+ this.id,
+ required this.productCode,
+ required this.name,
+ required this.unitPrice,
+ this.stock = 0,
+ this.minStock = 10,
+ this.maxStock = 1000,
+ this.supplierName = '',
+ DateTime? createdAt,
+ DateTime? updatedAt,
+ }) : createdAt = createdAt ?? DateTime.now(),
+ updatedAt = updatedAt ?? DateTime.now();
+
+ /// マップから Inventory オブジェクトへ変換
+ factory Inventory.fromMap(Map map) {
+ return Inventory(
+ id: map['id'] as int?,
+ productCode: map['product_code'] as String, // 'product_code' を使用する
+ name: map['name'] as String,
+ unitPrice: (map['unit_price'] as num).toDouble(),
+ stock: map['stock'] as int? ?? 0,
+ minStock: map['min_stock'] as int? ?? 10,
+ maxStock: map['max_stock'] as int? ?? 1000,
+ supplierName: map['supplier_name'] as String? ?? '',
+ createdAt: DateTime.parse(map['created_at']),
+ updatedAt: DateTime.parse(map['updated_at']),
+ );
+ }
+
+ /// Map に変換
+ Map toMap() {
+ return {
+ 'id': id,
+ 'product_code': productCode,
+ 'name': name,
+ 'unit_price': unitPrice,
+ 'stock': stock,
+ 'min_stock': minStock,
+ 'max_stock': maxStock,
+ 'supplier_name': supplierName,
+ 'created_at': createdAt.toIso8601String(),
+ 'updated_at': updatedAt.toIso8601String(),
+ };
+ }
+
+ /// カピービルダ
+ Inventory copyWith({
+ int? id,
+ String? productCode,
+ String? name,
+ double? unitPrice,
+ int? stock,
+ int? minStock,
+ int? maxStock,
+ String? supplierName,
+ DateTime? createdAt,
+ DateTime? updatedAt,
+ }) {
+ return Inventory(
+ id: id ?? this.id,
+ productCode: productCode ?? this.productCode,
+ name: name ?? this.name,
+ unitPrice: unitPrice ?? this.unitPrice,
+ stock: stock ?? this.stock,
+ minStock: minStock ?? this.minStock,
+ maxStock: maxStock ?? this.maxStock,
+ supplierName: supplierName ?? this.supplierName,
+ createdAt: createdAt ?? this.createdAt,
+ updatedAt: updatedAt ?? this.updatedAt,
+ );
+ }
+
+ /// 在庫不足フラグを取得
+ bool get isLowStock => stock <= minStock;
+
+ /// 在庫補充が必要か判定
+ bool needsRestock() => stock <= minStock;
+}
\ No newline at end of file
diff --git a/lib/models/product.dart b/lib/models/product.dart
index fd23dce..bfc465d 100644
--- a/lib/models/product.dart
+++ b/lib/models/product.dart
@@ -1,75 +1,77 @@
-// Version: 1.0.0
+// Version: 1.3 - Product モデル定義(フィールドプロモーション対応)
import '../services/database_helper.dart';
+/// 商品情報モデル
class Product {
int? id;
- String productCode;
+ String productCode; // データベースでは 'product_code' カラム
String name;
- int price; // 単価(税込)
- int stock;
- String? category;
- String? unit;
- int isDeleted = 0; // Soft delete flag
+ double unitPrice;
+ int quantity; // 管理用(未使用)
+ int stock; // 在庫管理用
+ DateTime createdAt;
+ DateTime updatedAt;
Product({
this.id,
required this.productCode,
required this.name,
- required this.price,
+ required this.unitPrice,
+ this.quantity = 0,
this.stock = 0,
- this.category,
- this.unit,
- this.isDeleted = 0,
- });
+ DateTime? createdAt,
+ DateTime? updatedAt,
+ }) : createdAt = createdAt ?? DateTime.now(),
+ updatedAt = updatedAt ?? DateTime.now();
+ /// マップから Product オブジェクトへ変換
+ factory Product.fromMap(Map map) {
+ return Product(
+ id: map['id'] as int?,
+ productCode: map['product_code'] as String, // 'product_code' を使用する
+ name: map['name'] as String,
+ unitPrice: (map['unit_price'] as num).toDouble(),
+ quantity: map['quantity'] as int? ?? 0,
+ stock: map['stock'] as int? ?? 0,
+ createdAt: DateTime.parse(map['created_at'] as String),
+ updatedAt: DateTime.parse(map['updated_at'] as String),
+ );
+ }
+
+ /// Map に変換
Map toMap() {
return {
'id': id,
'product_code': productCode,
'name': name,
- 'price': price,
+ 'unit_price': unitPrice,
+ 'quantity': quantity,
'stock': stock,
- 'category': category ?? '',
- 'unit': unit ?? '',
- 'is_deleted': isDeleted,
+ 'created_at': createdAt.toIso8601String(),
+ 'updated_at': updatedAt.toIso8601String(),
};
}
- factory Product.fromMap(Map map) {
- return Product(
- id: map['id'] as int?,
- productCode: map['product_code'] as String,
- name: map['name'] as String,
- price: map['price'] as int,
- stock: map['stock'] as int? ?? 0,
- category: map['category'] as String?,
- unit: map['unit'] as String?,
- isDeleted: map['is_deleted'] as int? ?? 0,
- );
- }
-
+ /// カピービルダ
Product copyWith({
int? id,
String? productCode,
String? name,
- int? price,
+ double? unitPrice,
+ int? quantity,
int? stock,
- String? category,
- String? unit,
- int? isDeleted,
+ DateTime? createdAt,
+ DateTime? updatedAt,
}) {
return Product(
id: id ?? this.id,
productCode: productCode ?? this.productCode,
name: name ?? this.name,
- price: price ?? this.price,
+ unitPrice: unitPrice ?? this.unitPrice,
+ quantity: quantity ?? this.quantity,
stock: stock ?? this.stock,
- category: category ?? this.category,
- unit: unit ?? this.unit,
- isDeleted: isDeleted ?? this.isDeleted,
+ createdAt: createdAt ?? this.createdAt,
+ updatedAt: updatedAt ?? this.updatedAt,
);
}
-
- // 税込価格(引数にない場合は自身)
- int get taxPrice => price;
}
\ No newline at end of file
diff --git a/lib/models/sale.dart b/lib/models/sale.dart
index 82ec412..9a31e90 100644
--- a/lib/models/sale.dart
+++ b/lib/models/sale.dart
@@ -1,73 +1,123 @@
-// Version: 1.1 (売上モデル実装)
-import 'dart:convert';
+// Version: 1.5 - Sale モデル定義(売上)
+import '../services/database_helper.dart';
+/// 売上項目クラス
+class SaleItem {
+ int productId;
+ String productName;
+ double unitPrice;
+ int quantity;
+
+ SaleItem({
+ required this.productId,
+ required this.productName,
+ required this.unitPrice,
+ this.quantity = 1,
+ });
+
+ /// 小計金額(税込)を取得
+ double get subtotal => unitPrice * quantity;
+
+ Map toMap() {
+ return {
+ 'productId': productId,
+ 'productName': productName,
+ 'unitPrice': unitPrice,
+ 'quantity': quantity,
+ 'subtotal': subtotal,
+ };
+ }
+
+ factory SaleItem.fromMap(Map map) {
+ return SaleItem(
+ productId: map['productId'] as int,
+ productName: map['productName'] as String,
+ unitPrice: (map['unitPrice'] as num).toDouble(),
+ quantity: map['quantity'] as int? ?? 1,
+ );
+ }
+
+ static List fromMaps(List maps) {
+ return maps.map((e) => SaleItem.fromMap(e as Map)).toList();
+ }
+}
+
+/// 売上モデル
class Sale {
int? id;
- String? saleNo;
- String customerName;
- DateTime date;
+ String customerCode; // データベースでは product_code として保存(顧客コード)
+ DateTime saleDate;
double totalAmount;
- double taxRate;
- Map? items; // LineItem ネスト構造
+ int taxRate;
+ List items = [];
DateTime createdAt;
DateTime updatedAt;
Sale({
this.id,
- this.saleNo,
- required this.customerName,
- required this.date,
- required this.totalAmount,
- this.taxRate = 10,
- this.items,
+ required this.customerCode,
+ required this.saleDate,
+ this.totalAmount = 0.0,
+ this.taxRate = 8, // デフォルト:8%
DateTime? createdAt,
DateTime? updatedAt,
- }) : createdAt = createdAt ?? DateTime.now(),
- updatedAt = updatedAt ?? DateTime.now();
+ List? items,
+ }) : createdAt = createdAt ?? DateTime.now(),
+ updatedAt = updatedAt ?? DateTime.now(),
+ items = items ?? [];
+ /// マップから Sale オブジェクトへ変換
+ factory Sale.fromMap(Map map) {
+ return Sale(
+ id: map['id'] as int?,
+ customerCode: map['customer_code'] as String, // 'product_code' を 'customer_code' として扱う
+ saleDate: DateTime.parse(map['sale_date']),
+ totalAmount: (map['total_amount'] as num).toDouble(),
+ taxRate: map['tax_rate'] as int? ?? 8,
+ createdAt: DateTime.parse(map['created_at']),
+ updatedAt: DateTime.parse(map['updated_at']),
+ );
+ }
+
+ /// Map に変換
Map toMap() {
return {
'id': id,
- 'sale_no': saleNo,
- 'customer_name': customerName,
- 'date': date.toIso8601String(),
+ 'customer_code': customerCode,
+ 'sale_date': saleDate.toIso8601String(),
'total_amount': totalAmount,
'tax_rate': taxRate,
- 'items': items,
+ 'product_items': items.map((item) => item.toMap()).toList(),
'created_at': createdAt.toIso8601String(),
'updated_at': updatedAt.toIso8601String(),
};
}
- factory Sale.fromMap(Map map) {
+ /// カピービルダ
+ Sale copyWith({
+ int? id,
+ String? customerCode,
+ DateTime? saleDate,
+ double? totalAmount,
+ int? taxRate,
+ DateTime? createdAt,
+ DateTime? updatedAt,
+ List? items,
+ }) {
return Sale(
- id: map['id'] as int?,
- saleNo: map['sale_no'] as String?,
- customerName: map['customer_name'] as String,
- date: DateTime.parse(map['date'] as String),
- totalAmount: (map['total_amount'] as num).toDouble(),
- taxRate: map['tax_rate'] as double? ?? 10,
- items: map['items'] as Map? ,
- createdAt: map['created_at'] != null ? DateTime.parse(map['created_at']) : DateTime.now(),
- updatedAt: map['updated_at'] != null ? DateTime.parse(map['updated_at']) : DateTime.now(),
+ id: id ?? this.id,
+ customerCode: customerCode ?? this.customerCode,
+ saleDate: saleDate ?? this.saleDate,
+ totalAmount: totalAmount ?? this.totalAmount,
+ taxRate: taxRate ?? this.taxRate,
+ createdAt: createdAt ?? this.createdAt,
+ updatedAt: updatedAt ?? this.updatedAt,
+ items: items ?? this.items,
);
}
- String toJson() => json.encode(toMap());
-
- factory Sale.fromJson(String source) => Sale.fromMap(json.decode(source) as Map);
-
- @override
- String toString() {
- return 'Sale(id: $id, saleNo: $saleNo, customerName: $customerName, date: $date, totalAmount: $totalAmount, taxRate: $taxRate, items: $items)';
+ /// 合計金額を再計算(items から集計)
+ void recalculate() {
+ totalAmount = items.fold(0, (sum, item) => sum + item.subtotal);
}
-
- @override
- bool operator ==(covariant Sale other) {
- if (identical(this, other)) return true;
- return other.id == id && other.saleNo == saleNo;
- }
-
- @override
- int get hashCode => id ^ saleNo;
}
\ No newline at end of file
diff --git a/lib/pdf_templates/sales_invoice_template.dart b/lib/pdf_templates/sales_invoice_template.dart
new file mode 100644
index 0000000..2419a59
--- /dev/null
+++ b/lib/pdf_templates/sales_invoice_template.dart
@@ -0,0 +1,37 @@
+// 販売伝票テンプレート(簡易実装)
+import 'dart:convert';
+
+class SalesInvoiceTemplate {
+ final String invoiceNumber;
+ final String date;
+ final String customerName;
+ final List