Multi-visit jobs and quote-to-job conversion
Not every job fits in a single site visit. A boiler replacement might need one visit to survey and rip out, another to install once the customer's approved a revised quote, and a follow-up to commission. Each visit has its own schedule, technician, notes, and activity log, but they all roll up to a single Job with a single customer-facing reference like JOB-0001.
This page covers two related features:
Quote → Job conversion: turning an accepted quote into a job in one click.
Multi-visit jobs: organising work that spans more than one site visit.
Quote → Job conversion
When a customer accepts a quote (deal moves to quote_status = accepted), the outcome picker on the deal page lets you generate a Job as one of the available outcomes. Picking the Job outcome:
Creates a new Job with the deal's customer + contact + deal link pre-populated
Seeds the job's address from the company's primary site (falling back to the company's flat address)
Builds a description from the quote line items (bulleted list: "• 2× Rip out old boiler", "• 1× Install Worcester Greenstar 30i", etc.): the dispatcher can edit on the Show page
Sets priority to medium, status to scheduled
Sends you to the new job so you can pick a schedule date and assign a technician
The job is created with created_via = deal_outcome_picker for reporting. The deal records each generated outcome's ID, so re-running the picker greys out the Job outcome and never creates a second one.
Multi-visit jobs
Any job can become a multi-visit job by adding a visit from the Visits card on the job detail page. The first visit you add flips the job into multi-visit mode; from then on the Visits card drives the lifecycle.
Adding a visit
Click + Add visit. Pick a start date/time, optional end date/time, technician, and a short note about what's planned for this visit. The visit gets a sub-number like V1, V2, V3, displayed alongside the job number as JOB-0001/V2.
Visit lifecycle
Each visit has its own status, independent of the parent job:
Scheduled: planned but not yet started
In progress: technician is on site (
Startaction)Completed: visit finished successfully (
Completeaction)Waiting for parts: follow-up is blocked pending parts (see fix-on-return below)
Cancelled: visit abandoned (dispatcher action)
The parent Job auto-completes when the last active visit (not cancelled, not waiting_for_parts) completes. Multi-visit jobs skip the per-field form-completion gate, because these jobs typically capture compliance via certificates. Single-visit jobs still use the normal gate.
Fix-on-return workflow
Sometimes a visit can't finish: the engineer arrives and finds a part isn't in stock, access to a plant room is denied, or the scope has grown. Rather than closing the job, click Require return on the active visit. A small modal captures:
Reason: parts needed / access denied / scope expanded / other
Notes: what happened, what's still outstanding
Follow-up date + technician (optional)
Submitting:
Marks the current visit as
waiting_for_parts(for parts-needed reasons) orcompleted(for other reasons)Creates a new visit in
scheduledstate linked back viaparent_visit_idLogs the transition in the job's activity timeline
The follow-up visit inherits the previous visit's technician by default, but the dispatcher can override. Both visits stay on the Job/Show page's Visits list so the history is clear; the follow-up carries a small "follow-up" tag.
Activity, time, and notes per visit
Child records (activities, time entries, notes) carry a nullable visit_id so you can tag each one to a specific visit. V1's UI doesn't surface per-visit filtering explicitly (they all appear in the main activity timeline), but reporting and the mobile app can use the visit_id column to slice later.
Permissions
No new permissions needed: multi-visit operations reuse the existing Jobs permissions:
jobs.create: quote-to-job conversionjobs.dispatch: schedule / require-return / cancel visitsjobs.edit: start / complete visits
Not yet shipped
Dispatch board rendering per-visit blocks: currently shows one block per job regardless of visit count. Planned for a follow-up session (S239b).
Mobile RN "Visit 2 of 3" UI: mobile still presents the job as a whole. Visit-aware mobile screens are a follow-up.
"Schedule all visits" wizard: for now, dispatchers add visits one at a time. A bulk wizard is a sugar layer.