Skip to content

Jobs Module

FSM (Field Service Management) job management and digital signature capture.

Overview

The Jobs module provides field technicians with:

  • Active job list with stage filtering
  • Job details with customer information
  • Stage workflow management
  • Digital signature capture with S3 storage
  • Activity logging and comments
  • Parts and warranty acknowledgments

Routes

Job List

GET /jobs/active

Lists all active (non-closed) FSM orders grouped by stage.

Parameter Type Description
type string Filter by job type: install or service
period string Filter by date: today, this_week, next_week

Job Detail

GET /jobs/{fsm_id}

Displays full job details including:

  • Customer information
  • Scheduled date/time
  • Stage and signature status
  • Parts summary
  • Activity log

Signature Page

GET /jobs/{fsm_id}/signature

Digital signature capture page for customer sign-off.

API Endpoints

Change Stage

POST /api/jobs/{fsm_id}/stage

Move job to a different stage.

{
  "stage_id": 5
}

Response:

{
  "success": true,
  "stage_id": 5,
  "stage_name": "In Progress"
}

Complete Job

POST /api/jobs/{fsm_id}/complete

Mark job as done using Odoo's action_complete.

Response:

{
  "success": true,
  "stage_name": "Done"
}

Submit Signature

POST /api/jobs/{fsm_id}/signature

Submit customer signature and complete the job.

{
  "signer_name": "John Doe",
  "signer_relationship": "Owner",
  "signature_image": "data:image/png;base64,...",
  "warranty_ack": true,
  "parts_ack": true,
  "payment_method": "Credit Card",
  "completion_notes": "Job completed successfully"
}

Response:

{
  "success": true,
  "message": "Signature saved successfully",
  "email_sent": true
}

Load Parts Summary

POST /api/jobs/{fsm_id}/load-parts

Load parts summary from linked sale order.

Response:

{
  "success": true,
  "parts_summary": "2x Window Blinds 48x72\n1x Motorized System",
  "removed_items_summary": "1x Old blinds removed"
}

Load Warranty

POST /api/jobs/{fsm_id}/load-warranty

Load warranty text from template.

Response:

{
  "success": true,
  "warranty_text": "This product is covered by a 5-year limited warranty..."
}

Post Comment

POST /api/jobs/{fsm_id}/comment

Add a comment to the job's activity log.

{
  "comment": "Customer requested installation in morning"
}

Response:

{
  "success": true,
  "message_id": 12345
}

Get Stages

GET /api/stages

Get all FSM stages for workflow buttons.

Response:

{
  "success": true,
  "stages": [
    {"id": 1, "name": "New", "sequence": 1, "is_closed": false},
    {"id": 2, "name": "Scheduled", "sequence": 2, "is_closed": false},
    {"id": 3, "name": "In Progress", "sequence": 3, "is_closed": false},
    {"id": 4, "name": "Done", "sequence": 10, "is_closed": true}
  ]
}

Signature Flow

sequenceDiagram
    participant Tech as Technician
    participant PWA
    participant S3
    participant Odoo

    Tech->>PWA: Open signature page
    PWA->>Odoo: Load parts/warranty
    Odoo-->>PWA: Display data

    Tech->>Tech: Customer signs on canvas
    Tech->>PWA: Submit signature

    PWA->>S3: Upload PNG image
    S3-->>PWA: bucket/key path

    PWA->>Odoo: Update FSM fields
    Note over Odoo: x_signature_url<br/>x_signed_name<br/>x_signed_datetime<br/>x_warranty_ack<br/>x_parts_ack

    PWA->>Odoo: mark_signature_complete()
    PWA->>Odoo: send_completion_report()
    Odoo-->>PWA: Email sent

    PWA-->>Tech: Success message

FSM Custom Fields

The signature flow uses these custom fields on fsm.order:

Field Type Description
x_signature_url Char S3 path (bucket/key)
x_signed_name Char Signer's name
x_signer_relationship Char Relationship (Owner, Tenant, etc.)
x_signed_datetime Datetime When signed
x_signature_state Selection pending or signed
x_warranty_text Text Warranty terms
x_warranty_ack Boolean Warranty acknowledged
x_warranty_ack_datetime Datetime When acknowledged
x_parts_summary Text Parts list from SO
x_removed_items_summary Text Removed items
x_parts_ack Boolean Parts acknowledged
x_parts_ack_datetime Datetime When acknowledged
x_completion_notes Text Tech notes
x_payment_method Char Payment method used

Job Type Filtering

Jobs are categorized as:

  • Install: Regular installation jobs
  • Service (A/S): After-service/warranty jobs

Detection logic:

def _is_service_job(job):
    type_name = job.get('type', [None, ''])[1] if job.get('type') else ''
    return 'A/S' in type_name or 'AS' in type_name or 'Service' in type_name

Period Filtering

Jobs can be filtered by scheduled date:

Period Range
today Current date only
this_week Monday to Sunday of current week
next_week Monday to Sunday of next week

Stage Grouping

Jobs are displayed grouped by stage, sorted by stage sequence:

# Sort stages by sequence (priority)
stages_list = sorted(stages.values(), key=lambda s: s['sequence'])

Activity Attribution

Stage changes and comments are properly attributed to the user:

# Use write_as_user for proper activity attribution
odoo_api.write_as_user('fsm.order', fsm_id, {'stage_id': stage_id}, partner_id)

This ensures the activity log shows the correct user who made the change, not the service account.

S3 Signature Storage

Signatures are stored in S3 with the path format:

signatures/fsm_{fsm_id}_{timestamp}.png

The path is stored in Odoo's x_signature_url field. To display the signature, a pre-signed URL is generated:

signature_url = s3_service.get_presigned_url(job['x_signature_url'])

Pre-signed URLs expire after 1 hour.

Completion Report

After signature submission, a completion report email is sent:

odoo_api.send_completion_report(fsm_id)

This calls action_send_completion_report_auto on the FSM order, which:

  1. Generates a PDF report
  2. Sends email to customer
  3. Sets x_completion_report_sent = True

Email sending is non-blocking - signature is saved even if email fails.

Attachment Downloads

Job attachments can be downloaded through the PWA:

GET /api/attachment/{attachment_id}

Proxies attachment download from Odoo with proper content type.

Offline Support

Job list and detail pages are cached by the service worker:

  • API GET requests: Network-first with 1-hour cache fallback
  • Static assets: Cache-first with 30-day TTL
  • HTML pages: Network-first with offline fallback

This allows technicians to view job information even without connectivity.