WorkestraDocs
ModulesField Service

Estimates

Build priced proposals, send for customer approval via a share link, and convert approved estimates into work orders with one click.

An estimate is a priced proposal you send to a customer for approval before doing the work. Unlike a sales quotation (which belongs to the Sales pipeline), an FSM estimate is field-team-owned, optionally parts-aware, and converts directly into a work order with active line items pre-copied.

When to use an estimate

  • The customer asked for a price before you commit (most jobs)
  • You want to offer optional upsell lines the customer can toggle on/off
  • You need a paper trail of what was quoted vs what was charged

When pricing isn't needed (service contracts, repeat customers with agreed rates), skip estimates and convert a request straight to a work order.

Creating an estimate

There are two paths:

From a request: open the request → Convert to estimate. The new estimate inherits the customer, asset, and request summary as notes.

From scratch: go to /fsm/estimatesNew (Phase 4.8 UI; today via the v1 API or AI tool convert_request_to_estimate / create_fsm_request then convert).

Every estimate is auto-numbered EST-YYYY-NNNN.

Adding line items

Open the estimate detail page (/fsm/estimates/[id]) and use the inline line editor at the bottom of the Line items card:

  1. Pick a line type: labor, parts, expense, or flat_fee.
  2. Enter a description.
  3. Fill the price fields:
    • Labor: hours × rate per hour
    • Parts / expense / flat_fee: quantity × unit price
  4. Optionally set a tax %.
  5. Tick Optional if this line is an upsell the customer can choose to include or skip on accept.
  6. Click Add.

Totals update automatically. Optional lines that aren't selected don't count toward the total.

Line item math

Subtotal, tax, and total are computed by the same engine that runs Finance invoices (lib/finance-totals, half-up rounding at 2 decimal places). Each line's tax is amount × (tax_rate / 100).

Sending to the customer

When the estimate is ready:

  1. Click Send to customer. Status flips from draftsent and stamps sent_at.
  2. Generate a customer-facing share link by minting a token (est_… prefix). The customer-facing portal lives at /portal/fsm/estimate/[token] — see Customer Portal.

The automatic "send via email" with a templated body is queued for the next release. For now, copy the portal URL into the email you send.

The customer sees a clean read-only view with line items, optional-line indicators, and Accept / Decline buttons.

Customer accept / reject

The customer either:

  • Accepts → estimate status flips to approved, stamps approved_at. You'll see it appear in the "approved" filter on /fsm/estimates.
  • Declines → status flips to rejected, stamps rejected_at. The lost work is preserved for analytics.

Converting to a work order

Once approved, open the estimate and click Convert to work order. Workestra:

  1. Creates a new draft work order with the customer, asset, currency, and estimated total pre-filled.
  2. Copies every active estimate line into the work order as a fsm_work_order_lines row.
  3. Skips optional lines that the customer didn't select.
  4. Stamps the estimate status as converted and stores the work order ID back on the estimate.

You're now ready to schedule the first appointment on the work order.

Conversion is idempotent: every copied line carries an idempotency_key so a retry (e.g. on a network blip) won't duplicate lines.

Estimate statuses

StatusMeaning
draftBeing built; lines editable
sentEmailed to customer; awaiting response
approvedCustomer accepted via portal
rejectedCustomer declined
expiredPast valid_until without response (manual flip today)
convertedConverted into a work order — terminal

Optional-line upsell pattern

Optional lines let you propose tiered or add-on services without two separate estimates:

[ ] Replace existing motor (mandatory)            — €380
[x] Annual maintenance contract (optional)        — €240
[ ] Upgrade thermostat to smart model (optional)  — €180
                                          Total:    €620

Customer can untick the optional lines on accept; totals recalculate and only chosen lines copy to the work order.