Proposals¶
| Status | Shipped |
|---|---|
| Linear | PIN-134 ↗ |
| Module | Bids ↗ |
One proposal per bid, versioned append-only. Each Save & Generate PDF freezes a snapshot of the active estimate revision (contract total, CSI groups) and renders a deterministic PDF — regenerating an old version always reproduces the numbers captured at its creation, never today's estimate. No AI in the generation path.
Prerequisites¶
- Role: Estimator, Chief Estimator, Senior PM, Executive, or Owner. (PM and below are read-only — but note the button isn't hidden for them, see Known Issues.)
- Bid state: a bid whose Estimate has an active revision — the Proposal toolbar button is disabled with "Generate an estimate revision first" otherwise.
- Environment: no special setup needed — PDF generation runs on a pure-Go renderer (PIN-504), so it works the same on staging as anywhere else.
1. Open the drawer¶
Bid → Estimate tab. In the toolbar's total strip, click Proposal (tooltip "Generate Proposal"). The Generate Proposal drawer opens.
2. Fill the proposal fields¶
Editable fields: Cover Letter, Scope Summary, Inclusions (one per line), Exclusions (one per line), Payment Terms (default Net 30), Valid for (days) (default 30), Terms & Conditions.
Under Previous Versions, existing revisions list as v{N} + date with a Download PDF pill (or "No PDF yet").
3. Generate¶
Click Save & Generate PDF (busy state "Generating PDF..."). On success: toast "Proposal PDF generated successfully", a new v{N} row appears with Download PDF, and the file also lands in the bid's Documents → 08 Proposal folder as proposal-v{N}.pdf.
Branding on the PDF (company name/logo/address/phone/email) comes from Settings → AppSettings, not from any Organization — default company name is "HVAC Construction Inc." A missing logo degrades to no logo, not an error.
4. Verify snapshot semantics¶
This is the core invariant worth testing:
- Generate
v1. Note the contract total on the PDF. - Change the estimate (add a line item, push takeoff, or activate a different estimate revision).
- Generate
v2— it must reflect the new numbers. - Re-download
v1— it must still show the old numbers. Old versions never re-read live estimate data.
Verification Checklist¶
- Proposal button disabled (with tooltip) until an estimate revision is active
- Generate creates
v1, toast fires, Download PDF works - PDF appears in Documents → 08 Proposal as
proposal-v{N}.pdf - PDF shows AppSettings branding and the estimate's CSI table / inclusions / exclusions
- Snapshot test above passes (v1 keeps old numbers after the estimate changes)
- Versions only ever grow — no edit/delete of an existing version anywhere
- No console errors throughout
Known Issues / Current Gaps¶
The Proposal button is not permission-gated client-side — a read-only role can open the drawer and only fails server-side on generate. Check the rejection is a clean error, not a broken state.
- Budget masking (PIN-432): roles without budget visibility get materials/labor/CSI cost breakdowns zeroed when reading proposal data; the client-facing contract total always shows. Masked zeros for a Financial-restricted role are intended.
Related docs¶
- End-to-End — Preconstruction Lifecycle — why the frozen-snapshot semantics matter, in context
- Detailed Reference — Sample Project A — produces the estimate this feeds on
- Change Orders — shares the same PDF export path
Updating this walkthrough
Run the full flow yourself end-to-end. If it passes, bump last_verified: in the frontmatter to today's date. If any step fails, fix the doc or the code in the same PR — drift is the enemy.