Skip to content
Skip to the article
In Odoo: 7 articles
Odoo

A repair shop workflow on Odoo 18, from inspection to invoice

A design pattern for running an automobile and heavy-truck repair shop on Odoo 18 Community with OCA modules, flat-rate billing and a few small glue modules.

Updated
Applies to
  • Odoo 18 Community (OCB)
  • OCA 18.0 modules
Tags
  • odoo
  • repairs
  • workflow
  • oca
Reading time
11 min

This document describes a repair-order flow for an automobile and heavy-truck repair shop on Odoo 18 Community: intake, inspection, a customer-signed estimate, parts, technician time, and an invoice that matches the approved estimate. Use it when you are designing a shop system and want to know which parts Odoo and the OCA already give you, and where you have to write glue.

See Odoo Community and OCA Overview for how Avunu picks modules, and Migrating from QuickBooks to Odoo for the accounting cutover this design assumes.

This is a design pattern. It describes a system we designed and built, not a product you can install in one step, and it makes no claim about any particular shop running it.

The flow at a glance

The repair order is the anchor for the whole job. Everything else hangs off it, and the sale order is the single billing document.

Customer reports an issue
  Repair order (draft): vehicle, concern, odometer, scheduled date
    Diagnostic template adds the diagnostic fee as a service line
    Inspection: severity grades, measurements, photos
    Estimate: sale order with firm lines and optional recommended jobs
      Customer signs on the portal
        Confirm repair: parts reserve, or RFQs are raised
          Technicians run timers, record Done quantities
            End repair: invoice from the sale order, then payment

Invoicing only flows repair order, then sale order, then invoice. Core Odoo repair has no direct invoicing, so the sale order is both the estimate and the bill. Design everything else around that fact.

Key design decisions

These choices shape every later step. Make them deliberately before you configure anything.

DecisionChoice
Labor billingFlat rate. The invoice equals the approved estimate, using the "Ordered quantities" invoice policy. Timesheets are internal cost data only.
IntakeA draft repair order created directly. No CRM or helpdesk step first.
Chart of accountsThe OCA l10n_us_gaap chart, with income split into parts, labor, diagnostic fees and sublet.
Inventory valuationAutomated FIFO, set on the product category.
Accounting historyA clean cutover from the previous system: chart, partners, active products, open receivables and payables, and an opening trial balance. History stays in the old system.

Why flat rate

Flat-rate billing means the customer pays the book hours on the estimate, however long the wrench time takes. That makes the approved estimate the invoice, which removes a whole class of disputes at pickup.

Technician timesheets still matter, but only for measuring efficiency against book hours. They never change what the customer owes.

What comes from where

A useful way to scope the build is to sort every capability into one of three buckets.

Core Odoo

  • The repair order, parts lines, and the Create Quotation step that turns a repair order into a sale order.

  • Portal online signature on quotations, and optional products on a quote.

  • The purchase_repair link between repair orders and purchase orders, with a Purchase Orders smart button on the repair order.

  • The parts availability indicator on the repair order, which is part of core repair.

OCA modules

  • The OCA repair suite: repair_order_template for job templates, repair_service for labor lines, repair_timesheet for timesheet lines on repair orders, repair_type, and repair_quality_control.

  • project_timesheet_time_control for the start and stop timer.

  • Fleet add-ons for vehicle ownership and inspection templates: fleet_vehicle_ownership, fleet_vehicle_inspection and fleet_vehicle_inspection_template.

  • resource_booking for appointment capacity across several technicians.

  • l10n_us_gaap for the chart of accounts, plus the l10n-usa repository more broadly.

  • account_reconcile_oca for bank reconciliation and MIS Builder for a trial balance comparison at cutover.

Glue you write yourself

The OCA gives you the parts, but several joins are missing. We wrote small modules for these:

  • Vehicle on the repair order. Owner-filtered vehicle selection, odometer-in written to the vehicle history, a customer-concern tab, plate and VIN search, a repair-history smart button, and the vehicle printed on the sale order and invoice. It also hides the "product to repair" field, because a vehicle is not a stock product.

  • Labor lines synced to the sale order. OCA only syncs labor to the sale order at quotation creation. A small module keeps labor lines in step afterward, so a change order lands on the quote.

  • Timers on the repair order. A small module joins repair_timesheet to the OCA timer, so the Start Timer and Stop Timer buttons log hours to the repair order.

  • Service lines on repair templates. This lets the diagnostic template carry the diagnostic fee and job templates carry book hours.

  • Digital inspection with severity grades. Lines graded Good, Today's Services, Future, Needs Attention or Failed State Inspection, with conditions, recommended actions, measurement specs that flag out-of-spec values, photos, and seeded checklists.

  • A customer-facing inspection report. A severity-grouped PDF, an email that attaches it, and portal pages with token access.

  • Findings to estimate. Canned service jobs linked to recommended actions, and a wizard that builds the quote from the findings.

  • Scheduling. A bridge between the core repair order, which has one scheduled date and no capacity model, and resource_booking, which does.

Intake and diagnostic

Start every job as a draft repair order. Pick the customer and the vehicle, enter the odometer reading, and record the customer's concern in their own words. Nothing is reserved or charged at this stage.

Create the vehicle record properly: plate, VIN, and owner. A real vehicle record makes repeat visits fast, because the repair history hangs off it.

Apply a Diagnostic repair template to the order. The template is a service line carrying the diagnostic fee, a flat-fee product with its own income account. The customer owes it even if they decline the repair.

Warning

Applying a template replaces the existing part and service lines on the order. Apply the template first, then add extra lines.

Digital inspection with severity grades

The technician creates one inspection per checklist from the repair order, with the vehicle, odometer and staff pre-filled. Each line gets a severity grade, the conditions found, recommended actions, measurements, notes and photos.

Severity does real work later. It decides which findings the estimate builder treats as must-do and which it offers as optional.

When the checklists are done, send the inspection report. The customer receives a branded PDF by email and a portal link with full-size photos. Keep internal-only observations in the repair notes, which the customer never sees.

Estimate as a sale order with optional jobs

The estimate is a sale order. There are two ways to fill it.

Build it from findings

Link canned service jobs to the recommended actions that should trigger them. A job is either a fixed menu price or labor plus parts, with a customer-facing description.

The estimate builder then lists each unquoted finding with its linked job. Must-do findings (Today's Services and Failed State Inspection) become firm lines. Everything else becomes an optional product on the quote, declined by default.

Build it by hand

Add parts with a Demand quantity, and add labor on the Services tab with the book hours as the quantity. Then create the quotation from the repair order.

Either way, require an online signature on the quote and print the vehicle and VIN on it.

Portal approval and confirmation

The customer opens the quote on the portal, adds the optional jobs they want, and signs. The total updates as they choose. If you configure online payment or a prepayment percentage, they can sign and pay in one flow.

When the sale order confirms, each approved job explodes into the repair order: parts as stock moves and labor as service lines. Both carry a flag linking them back to the flat-rate sale line, so they do not create their own sale lines.

Warning

Never clear that flag on the exploded moves or services. Doing so re-enables the core repair-to-sale sync and bills the customer twice for the same work.

The repair order chatter records which jobs were approved and which were declined. Keep that trail: it is your record if a declined safety item is ever questioned.

Parts, RFQs and the repair itself

Confirming the repair reserves parts on the shelf and raises purchase orders for the rest. Two routes cover both cases:

  • Special-order parts. Give the product the Buy and MTO routes and a vendor. Odoo raises a per-job RFQ the moment the repair order confirms. The "Replenish on Order (MTO)" route ships archived in Odoo 18, so unarchive it first under Inventory, Configuration, Routes. That menu only appears once Multi-Step Routes is switched on in the Inventory settings.

  • Stocked parts. Use a Buy route plus a reordering rule with minimum and maximum both zero, set to auto-trigger. Demand then produces a consolidated RFQ.

The parts availability indicator turns green when everything has arrived, which is the signal to bring the vehicle into the bay. Start the repair when work begins.

Technician timers

Technicians use a Start Timer button on the repair order, which becomes Stop Timer while running. Starting a timer on a second job stops the first, so each person has exactly one clock running. Hours land on the Timesheets tab against an internal "Shop Labor" project.

Technicians must sign in as themselves. The timer belongs to the logged-in user, so a shared tablet login piles everyone's hours on one person.

Note

The OCA hr_timesheet_task_required module forces a task on every timesheet line, which breaks technician time on repair orders. Leave it out of the install set.

Record actual consumption in Done

Record parts actually used in the Done quantity, never in Demand. Editing Demand after approval rewrites the customer-facing sale lines. Editing Done does not.

Work found mid-repair is a change order. Add the parts and labor on the repair order without the flag, and they sync to the sale order. Get the customer's approval before doing the work.

Warning

Do not enable automatic transfer on repair completion (repair.auto_transfer_repair, from repair_picking_after_done). It requires a product on the repair order, and this design leaves that field empty because the vehicle is not a stock product. It blocks Confirm Repair with an error.

End repair and invoice

Click End Repair when the work is done. Parts are consumed at their Done quantities, and removed cores can go to a core-returns location instead of scrap.

Then create the invoice from the sale order and register payment. The invoice equals the approved estimate: flat-rate labor plus quoted parts, with the vehicle and VIN printed on it.

If the customer declines the repair, cancel it. The parts and labor lines on the quote are zeroed and the diagnostic fee line remains, so you invoice only the fee.

Configuration notes

A few setup choices carry more weight than the rest.

  • Services are separate products. Create Diagnostic Fee, Shop Labor, one product per extra hourly rate, Shop Supplies and Sublet Repair as distinct service products with the "Ordered quantities" invoice policy. Do not model rates as variants. Use pricelists if fleet and retail rates diverge later.

  • Parts are storable goods in a category with FIFO costing and automated valuation, with vendor prices on the Purchase tab.

  • Scheduling needs real users. Each technician is an employee linked to a user, on their own shift calendar, with one resource combination each. Without the user link, their own calendar meetings do not mark them busy.

  • Odometer units. Core Odoo defaults to kilometers. Set a user-defined default of miles if your shop works in miles.

For the chart of accounts, apply l10n_us_gaap before any account mapping. Validate a trial balance against the old system at the cutover date. That comparison is your go or no-go gate.

Known risks

  • Module maturity. repair_type is Alpha, and repair_order_template, repair_timesheet and repair_quality_control are young Betas. They are small and readable. Pin the submodule revisions and smoke-test after each update.

  • A field collision. repair_quality_control and a custom inspection module can both define inspection_ids on the repair order. When the custom one wins, Cancel Repair fails and draft inspections can be deleted. Namespace your own field, or skip the QC module.

  • Never add a value to fleet.vehicle.model.vehicle_type. Core fleet views hide about fifteen fields, including the odometer, unless the type is car. Put the car, SUV and truck split in a category instead.

  • Scheduling limits. A technician is busy for the appointment window only, so a job stalled on parts does not free them automatically. Assignment is by sequence or random, never least-loaded.

The system is built but not yet deployed, so this design has not been checked against a running shop. The notes above come from the design and its source code.

Sources

This article is in the public domain (CC0 1.0), code samples included. Use it however helps you.