Problem
The Contract model is purely time-based: rate x unit (hour/day) x volume. Invoice generation requires timesheets and derives quantities from tracked time. There is no way to model a fixed-price engagement — the workaround is faking a day rate with artificial units, which misrepresents the actual offer.
Proposed changes
- New field
Contract.pricing_model: "time_based" (default) | "fixed_price".
- New field
Contract.fixed_price: Optional[Decimal] — the agreed total price.
rate, unit, volume, units_per_workday become optional / ignored when pricing_model="fixed_price".
generate_invoice gains a code path for fixed-price contracts that creates a single lump-sum invoice item without requiring timesheets.
Scope
- Schema: new fields on
Contract, Alembic migration
- Invoicing logic: fixed-price code path without timesheets
- UI: contract form with pricing model toggle
Problem
The Contract model is purely time-based: rate x unit (hour/day) x volume. Invoice generation requires timesheets and derives quantities from tracked time. There is no way to model a fixed-price engagement — the workaround is faking a day rate with artificial units, which misrepresents the actual offer.
Proposed changes
Contract.pricing_model:"time_based"(default) |"fixed_price".Contract.fixed_price: Optional[Decimal]— the agreed total price.rate,unit,volume,units_per_workdaybecome optional / ignored whenpricing_model="fixed_price".generate_invoicegains a code path for fixed-price contracts that creates a single lump-sum invoice item without requiring timesheets.Scope
Contract, Alembic migration