Fab Forward Dev/

DDD ドキュメント

Sales CRM 集約: 見積管理 / Aggregate: Quote Management

バウンデッドコンテキスト: File Management (ファイル管理) — 拡張

知識ベース: knowledge/07-sales-management/sales-process.md (見積プロセス)


集約ルート (Aggregate Roots)

1. QuoteTemplate (見積書テンプレート)

QuoteTemplate (集約ルート)
├── name: string                (テンプレート名)
├── documentTitle: string       (帳票名 — 例: 見積書、御見積書)
├── companyName: string         (自社名 — CompanySettings から取得可)
├── logoUrl: string             (会社ロゴ URL)
├── stampUrl: string            (印影 URL)
├── taxMode: TaxMode            (外税 / 内税)
├── defaultExpiry: number       (有効期限デフォルト日数)
├── remarks: string             (デフォルト備考)
├── isDefault: boolean          (デフォルトテンプレートフラグ)
├── createdBy: → User           (作成者)
├── updatedBy: → User           (最終更新者)
└── version: number             (楽観ロック用)
プロパティ必須説明
namestringテンプレート名 (最大 100 文字)
documentTitlestring帳票タイトル (例: 見積書)
companyNamestring自社名 (未指定時 CompanySettings.company_name を使用)
logoUrlstring会社ロゴ画像 URL
stampUrlstring印影画像 URL
taxModeTaxModeexclusive (外税) / inclusive (内税)
defaultExpirynumber有効期限デフォルト日数 (デフォルト: 30)
remarksstringデフォルト備考テキスト (最大 2000 文字)
isDefaultbooleanデフォルトテンプレートフラグ (デフォルト: false)
createdBy→ User作成者 (読取専用)
updatedBy→ User最終更新者 (読取専用)
versionnumber楽観ロック用バージョン番号

不変条件 (Invariants):

  • name は空文字不可
  • documentTitle は空文字不可
  • taxModeexclusive / inclusive のいずれか
  • isDefault = true のテンプレートはシステム全体で最大 1 件
  • logoUrl, stampUrlhttp: / https: プロトコルのみ
  • 楽観ロック: バージョン不整合で 409 Conflict
  • admin のみ作成・更新・削除可能

2. QuoteDocument (見積書)

QuoteDocument (集約ルート)
├── quoteNumber: string         (見積番号 — 自動採番)
├── template: → QuoteTemplate   (使用テンプレート)
├── deal: → Deal                (関連案件)
├── account: → Account          (宛先取引先)
├── contact: → Contact          (宛先担当者、任意)
├── subject: string             (件名)
├── issueDate: Date             (発行日)
├── expiryDate: Date            (有効期限)
├── message: string             (メッセージ)
├── lineItems[]                 (明細行)
│   ├── itemName: string        (品目名、最大 50 文字)
│   ├── quantity: number        (数量、正の数)
│   ├── unitPrice: number       (単価)
│   ├── unit: string            (単位 — 式、個、セット等)
│   ├── description: string     (明細詳細、最大 200 文字)
│   └── lineTotal: number       (行合計 = quantity × unitPrice)
├── subtotal: number            (小計)
├── taxAmount: number           (消費税額)
├── totalAmount: number         (合計)
├── remarks: string             (備考)
├── status: QuoteStatus         (下書き / 発行済み)
├── file: → File                (生成された PDF ファイル)
├── salesRep: → User            (営業担当)
├── createdBy: → User           (作成者)
├── updatedBy: → User           (最終更新者)
└── version: number             (楽観ロック用)
プロパティ必須説明
quoteNumberstring見積番号 (自動採番、一意)
template→ QuoteTemplate使用テンプレート
deal→ Deal関連案件
account→ Account宛先取引先 (Deal.account から自動設定)
contact→ Contact宛先担当者 (任意)
subjectstring件名 (最大 255 文字)
issueDateDate発行日
expiryDateDate有効期限 (issueDate + template.defaultExpiry)
messagestringメッセージ (最大 2000 文字)
lineItemsQuoteLineItem[]明細行 (最低 1 行)
subtotalnumber小計 (計算値: lineItems の lineTotal 合計)
taxAmountnumber消費税額 (計算値)
totalAmountnumber合計 (計算値: subtotal + taxAmount or subtotal)
remarksstring備考 (最大 2000 文字)
statusQuoteStatusdraft / issued (デフォルト: draft)
file→ File生成 PDF の File 参照 (fileType=quote)
salesRep→ User営業担当
createdBy→ User作成者 (読取専用)
updatedBy→ User最終更新者 (読取専用)
versionnumber楽観ロック用

不変条件 (Invariants):

  • quoteNumber はシステム全体で一意
  • deal は必須。見積書は必ず案件に紐付く
  • lineItems は最低 1 行
  • lineItem.quantity は正の数
  • lineItem.unitPrice は 0 以上
  • lineItem.itemName は空文字不可、最大 50 文字
  • subtotal = Σ(lineItem.lineTotal) (計算値)
  • 外税: taxAmount = subtotal × 税率、totalAmount = subtotal + taxAmount
  • 内税: taxAmount = subtotal - subtotal / (1 + 税率)、totalAmount = subtotal
  • expiryDateissueDate
  • status=issued の見積書は PDF を生成し File (fileType=quote) として保存
  • 楽観ロック: バージョン不整合で 409 Conflict

ライフサイクル (State Machine):

設計判断: issued 後の編集は不可。修正が必要な場合は新規見積書を作成。 TransLead の実装に準拠。


トランザクション境界

操作同一トランザクション結果整合性 (Eventual)
QuoteTemplate 作成QuoteTemplate のみ
QuoteDocument 作成QuoteDocument のみ
QuoteDocument 発行QuoteDocument.status → issued + File 作成Deal との関連更新

関連図

┌──────────────────┐     ┌──────────────┐
│  QuoteTemplate   │     │    Deal      │
│  (テンプレート)    │     │   (案件)     │
└────────┬─────────┘     └──────┬───────┘
         │ 参照                  │ 1
         │                      │
         ▼                     N│
┌──────────────────┐            │
│  QuoteDocument   │◀───────────┘
│  (見積書)         │
│  ├── lineItems[] │
│  └── file → File │──────▶ File (fileType=quote)
└──────────────────┘
  • QuoteTemplate : QuoteDocument = 1 : N
  • Deal : QuoteDocument = 1 : N
  • QuoteDocument : File = 1 : 1 (発行時)