← Back to Index
JOB COMPLETED - REPORT DUE
Meter Read & Property Check
REF: GSC-2024-0847 | Birmingham City Council
42 High Street, Birmingham
Completed: 10:45 AM
Duration: 1h 30m
Report must be submitted within
23:45:12
⚠️ Payment will be delayed if late
Submit Report
Complete job documentation
£85.00
Awaiting Report Submission
Job Details
Job Type Meter Read & Property Check
Service Category Utility
Client Birmingham City Council
Location 42 High Street, Birmingham
Status Completed
Completed At 08/12/2024, 10:45 AM
Duration 1h 30m
Our Reference GSC-2024-0847
Customer Info
Property Manager
Birmingham City Council
07700 123456
Email property@birmingham.gov.uk
Customer Ref BHAM-2024-847
Helpdesk 0800 123 4567
Site Access
Property Type 3 bed semi-detached house
Occupancy Vacant
Access Method Key safe
Access Result ✓ Successful - All areas accessed
Work Completed
Visit Reason Routine meter reading and property condition check
Tasks Completed 6/6 ✓ All tasks completed successfully
Start Time 09:15 AM
End Time 10:45 AM
Total Duration 1h 30m
Job Value £85.00
Task Progress
Contact site/tenant if occupied ✓
Access property & verify keys ✓
Complete meter readings ✓
Take required photos ✓
Document property condition ✓
Secure property before leaving ✓
Utility Tasks
Meter Readings Completed
Electric Meter Serial: E123456789
Reading: 12567 (Previous: 12345)
Consumption: 222 kWh
Read at: 09:30 AM
Gas Meter Serial: G987654321
Reading: 6823 (Previous: 6789)
Consumption: 34 units
Read at: 09:35 AM
Water Meter Serial: W555123789
Reading: 3478 (Previous: 3456)
Consumption: 22 units
Read at: 09:40 AM
Photos Taken (8)
Property Front
09:15 AM
Electric Meter
09:30 AM
Gas Meter
09:35 AM
Water Meter
09:40 AM
Kitchen Area
10:20 AM
Water Damage
10:25 AM
Property Rear
10:40 AM
Secured Property
10:45 AM
Job Notes
Added during visit
Water damage visible in kitchen ceiling corner, approx 30cm diameter stain. All meters read successfully. Property secured with all windows and doors locked.
Schedule
Assigned At 08/12/24, 8:00 AM
Accepted At 08/12/24, 8:30 AM
Scheduled Date 08/12/2024
Scheduled Time 9:00 AM - 11:00 AM
Started At 08/12/2024 9:15 AM
Completed At 08/12/2024 10:45 AM
Report Due Today by 11:59 PM

🔧 Developer API Reference - Completed Job (Report Pending)

Primary API Endpoints:

// Get job details
GET /api/subjob/{subJobId}
Authorization: Bearer {token}

// Submit job report
POST /api/subjob/{subJobId}/submitreport
Authorization: Bearer {token}
Content-Type: multipart/form-data
Body: {
    "reportData": { /* job-specific report data */ },
    "finalImages": [files],
    "agentSignature": file,
    "submittedAt": "2024-12-08T14:30:00Z"
}

// Download job report
GET /api/subjob/{subJobId}/report
Authorization: Bearer {token}

// Get report template
GET /api/subjob/{subJobId}/reporttemplate
Authorization: Bearer {token}

// Update meter readings
PUT /api/subjob/{subJobId}/meterreadings
Authorization: Bearer {token}
Body: {
    "electricReading": { "value": "12567", "readAt": "2024-12-08T09:30:00Z" },
    "gasReading": { "value": "6823", "readAt": "2024-12-08T09:35:00Z" },
    "waterReading": { "value": "3478", "readAt": "2024-12-08T09:40:00Z" }
}
        

Data Structure (SubJobDetailDto - Completed):

{
    "subJob": {
        "id": 847,
        "ourJobReference": "GSC-2024-0847",
        "status": "Completed",
        "priority": "Standard",
        "price": 85.00,
        "rateType": "Standard",
        "assignedAt": "2024-12-08T08:00:00Z",
        "acceptedAt": "2024-12-08T08:30:00Z",
        "startedAt": "2024-12-08T09:15:00Z",
        "completedAt": "2024-12-08T10:45:00Z",
        "scheduledDate": "2024-12-08",
        "scheduledTime": "9:00 AM - 11:00 AM",
        "estimatedDurationMinutes": 30,
        "notes": "Water damage visible in kitchen ceiling corner. All meters read successfully. Property secured.",
        "ppeRequirements": "Standard PPE",
        "requiresSpecialEquipment": false,
        "assignedAgentName": "Current User"
    },
    "clientJob": {
        "id": 2847,
        "clientName": "Birmingham City Council",
        "jobType": "Meter Read & Property Check",
        "jobServiceCategory": "Utility",
        "clientJobReference": "BHAM-2024-847",
        "customerName": "Property Manager",
        "customerEmail": "property@birmingham.gov.uk",
        "customerTelephone": "07700 123456",
        "customerAddress": "42 High Street",
        "customerCity": "Birmingham",
        "customerCounty": "West Midlands",
        "customerPostcode": "B1 2LB",
        "customerCountry": "United Kingdom",
        "customerReference": "BHAM-2024-847",
        "companyName": "Birmingham City Council",
        "clientHelpdeskPhone": "0800 123 4567",
        "visitReason": "Routine meter reading and property condition check",
        "propertyDetails": {
            "propertyType": "3 bed semi-detached house",
            "occupancyStatus": "Vacant",
            "keySafeLocation": "Left of front door",
            "keySafeCode": "2847"
        },
        "meters": [
            {
                "product": "Electric",
                "serial": "E123456789",
                "mpan": "1234567890123",
                "type": "Digital",
                "size": "Standard",
                "location": "External meter box",
                "lastReading": "12345",
                "lastReadingDate": "2024-11-01"
            },
            {
                "product": "Gas",
                "serial": "G987654321",
                "mpan": "9876543210987",
                "type": "Credit",
                "size": "U6",
                "location": "External box - front",
                "lastReading": "6789",
                "lastReadingDate": "2024-11-01"
            },
            {
                "product": "Water",
                "serial": "W555123789",
                "type": "Standard",
                "location": "Under kitchen sink",
                "lastReading": "3456",
                "lastReadingDate": "2024-11-01"
            }
        ],
        "jobImages": [
            {
                "id": 301,
                "description": "Property Front",
                "uploadedAt": "2024-12-08T09:15:00Z",
                "isPdf": false,
                "isMandatory": true
            },
            {
                "id": 302,
                "description": "Electric Meter",
                "uploadedAt": "2024-12-08T09:30:00Z",
                "isPdf": false,
                "isMandatory": true
            },
            {
                "id": 303,
                "description": "Gas Meter",
                "uploadedAt": "2024-12-08T09:35:00Z",
                "isPdf": false,
                "isMandatory": true
            },
            {
                "id": 304,
                "description": "Water Meter",
                "uploadedAt": "2024-12-08T09:40:00Z",
                "isPdf": false,
                "isMandatory": true
            },
            {
                "id": 305,
                "description": "Kitchen Area",
                "uploadedAt": "2024-12-08T10:20:00Z",
                "isPdf": false,
                "isMandatory": false
            },
            {
                "id": 306,
                "description": "Water Damage",
                "uploadedAt": "2024-12-08T10:25:00Z",
                "isPdf": false,
                "isMandatory": false
            },
            {
                "id": 307,
                "description": "Property Rear",
                "uploadedAt": "2024-12-08T10:40:00Z",
                "isPdf": false,
                "isMandatory": false
            },
            {
                "id": 308,
                "description": "Secured Property",
                "uploadedAt": "2024-12-08T10:45:00Z",
                "isPdf": false,
                "isMandatory": false
            }
        ]
    }
}
        

Client-Side Calculations Required:

Angular/TypeScript:

// 1. Total duration calculation
const startTime = new Date(subJob.startedAt);
const endTime = new Date(subJob.completedAt);
const durationMs = endTime.getTime() - startTime.getTime();
const totalHours = Math.floor(durationMs / (1000 * 60 * 60));
const totalMinutes = Math.floor((durationMs % (1000 * 60 * 60)) / (1000 * 60));
const totalDuration = `${totalHours}h ${totalMinutes}m`;

// 2. Customer address concatenation
const customerAddress = `${clientJob.customerAddress}, ${clientJob.customerCity}`;

// 3. Image count
const imageCount = clientJob.jobImages?.length || 0;

// 4. Report due countdown
const completedTime = new Date(subJob.completedAt);
const reportDeadline = new Date(completedTime);
reportDeadline.setHours(23, 59, 59, 999); // Same day 11:59 PM
const now = new Date();
const timeRemaining = reportDeadline.getTime() - now.getTime();
const hours = Math.floor(timeRemaining / (1000 * 60 * 60));
const minutes = Math.floor((timeRemaining % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((timeRemaining % (1000 * 60)) / 1000);
const timeRemainingDisplay = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;

// 5. Meter reading calculations
const electricMeterReading = {
    serial: clientJob.meters.find(m => m.product === 'Electric')?.serial,
    currentReading: '12567', // from report submission
    previousReading: '12345',
    consumption: 12567 - 12345
};

// 6. Report submission status
const reportSubmissionStatus = subJob.status === 'Completed' ? 'Awaiting Report Submission' : 'Report Submitted';

// 7. Access result summary
const accessResult = '✓ Successful - All areas accessed'; // based on completion and no issues

// 8. Tasks completed count
const tasksCompleted = '6/6 ✓ All tasks completed successfully'; // calculate from checklist
        

Swift (iOS):

// 1. Total duration calculation
let startTime = ISO8601DateFormatter().date(from: subJob.startedAt) ?? Date()
let endTime = ISO8601DateFormatter().date(from: subJob.completedAt) ?? Date()
let duration = endTime.timeIntervalSince(startTime)
let hours = Int(duration) / 3600
let minutes = (Int(duration) % 3600) / 60
let totalDuration = "\(hours)h \(minutes)m"

// 2. Customer address
let customerAddress = "\(clientJob.customerAddress), \(clientJob.customerCity)"

// 3. Image count
let imageCount = clientJob.jobImages?.count ?? 0

// 4. Report countdown timer
let completedTime = ISO8601DateFormatter().date(from: subJob.completedAt) ?? Date()
var reportDeadline = Calendar.current.startOfDay(for: completedTime)
reportDeadline = Calendar.current.date(bySettingHour: 23, minute: 59, second: 59, of: reportDeadline) ?? completedTime
let timeRemaining = reportDeadline.timeIntervalSinceNow
let remainingHours = Int(timeRemaining) / 3600
let remainingMinutes = (Int(timeRemaining) % 3600) / 60
let remainingSeconds = Int(timeRemaining) % 60
let timeRemainingDisplay = String(format: "%02d:%02d:%02d", remainingHours, remainingMinutes, remainingSeconds)

// 5. Meter reading calculations
let electricMeter = clientJob.meters?.first { $0.product == "Electric" }
let electricReading = MeterReading(
    serial: electricMeter?.serial ?? "",
    current: "12567",
    previous: electricMeter?.lastReading ?? "",
    consumption: 12567 - Int(electricMeter?.lastReading ?? "0") ?? 0
)
        

React Native:

// 1. Total duration calculation
const startTime = new Date(subJob.startedAt);
const endTime = new Date(subJob.completedAt);
const durationMs = endTime - startTime;
const totalHours = Math.floor(durationMs / (1000 * 60 * 60));
const totalMinutes = Math.floor((durationMs % (1000 * 60 * 60)) / (1000 * 60));
const totalDuration = `${totalHours}h ${totalMinutes}m`;

// 2. Report countdown with live updates
const [timeRemaining, setTimeRemaining] = useState('00:00:00');

useEffect(() => {
    const completedTime = new Date(subJob.completedAt);
    const reportDeadline = new Date(completedTime);
    reportDeadline.setHours(23, 59, 59, 999);
    
    const interval = setInterval(() => {
        const now = new Date();
        const remaining = reportDeadline - now;
        
        if (remaining > 0) {
            const hours = Math.floor(remaining / (1000 * 60 * 60));
            const minutes = Math.floor((remaining % (1000 * 60 * 60)) / (1000 * 60));
            const seconds = Math.floor((remaining % (1000 * 60)) / 1000);
            
            setTimeRemaining(
                `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`
            );
        } else {
            setTimeRemaining('00:00:00');
        }
    }, 1000);
    
    return () => clearInterval(interval);
}, [subJob.completedAt]);

// 3. Meter readings with consumption calculation
const processedReadings = clientJob.meters?.map(meter => ({
    ...meter,
    currentReading: getCurrentReading(meter.product), // from report data
    consumption: getCurrentReading(meter.product) - parseInt(meter.lastReading || '0')
}));
        

Key Implementation Notes:

Status Flow:

New → Assigned → Accepted → En Route → In Progress → Completed → Report Submitted → Invoiced
                                                    ↑ Current State
        

Report Submission Requirements: