Files
prosappweb/lib/models/service.dart
T
Lizandro GuarnizoandClaude Sonnet 4.6 735d8c2ba0 fix: corregir flujo completo de servicio y geocodificación
- Service.fromJson: lat/lng con Decimal de Prisma llegaban como string y
  el cast 'as num?' lanzaba TypeError silencioso → lista de servicios vacía.
  Mismo patrón que average_score, fix: double.tryParse(?.toString())
- service_status: agregar enumToStringService que mapea el enum de Flutter
  al string que espera el DTO del backend ('pending','accepted', etc.).
  changeServiceStatus enviaba el índice entero → @IsEnum rechazaba → el
  profesional no podía aceptar ni rechazar solicitudes
- maps_service: agregar MapsService.reverseGeocode que usa el Geocoder del
  Maps JS SDK ya cargado, sin requerir la Geocoding API habilitada por separado
- dashboard_view: _reverseGeocode usa el JS Geocoder en vez del endpoint HTTP

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-22 09:15:59 -05:00

128 lines
4.2 KiB
Dart

import 'package:flutter/material.dart';
import 'package:prosapp_web_app/models/service_location_preferences.dart';
import 'package:prosapp_web_app/models/service_status.dart';
class Service {
final String? id;
final String professionalId;
final bool professionalScored;
final String userId;
final bool userScored;
final String address;
final String aditionalAddress;
final double latitude;
final double longitude;
final String day;
final String createdAt;
final String description;
final TimeOfDay range1Hour1;
final TimeOfDay range1Hour2;
final String rate;
final ServiceStatus status;
final ServiceLocationPreferences location;
Service({
required this.id,
required this.professionalId,
required this.professionalScored,
required this.userId,
required this.userScored,
required this.address,
required this.aditionalAddress,
required this.latitude,
required this.longitude,
required this.day,
required this.createdAt,
required this.description,
required this.range1Hour1,
required this.range1Hour2,
required this.rate,
required this.status,
required this.location,
});
static const _statusMap = {
'pending': 0, 'accepted': 1, 'denied': 2, 'active': 3,
'cancelled': 4, 'completed': 5, 'self_booked': 6,
};
static Service fromJson(Map<String, dynamic> doc, String id) {
final rawStatus = doc['status'];
final statusInt = rawStatus is int ? rawStatus
: rawStatus is String ? (_statusMap[rawStatus] ?? 0)
: (rawStatus as num?)?.toInt() ?? 0;
final rawLoc = doc['location_preference'] ?? doc['location'];
final locInt = rawLoc == 'delivery' ? 1
: rawLoc == 'office' ? 0
: (rawLoc as num?)?.toInt() ?? 0;
return Service(
id: id,
professionalId: doc['professional_id'] as String,
professionalScored: doc['professional_scored'] as bool? ?? false,
userId: doc['user_id'] as String,
userScored: doc['user_scored'] as bool? ?? false,
address: doc['address'] as String? ?? '',
aditionalAddress: (doc['additional_address'] ?? doc['aditional_address']) as String? ?? '',
// Prisma Decimal fields serialize as JSON strings — same pattern as average_score
latitude: double.tryParse(doc['latitude']?.toString() ?? '') ?? 0.0,
longitude: double.tryParse(doc['longitude']?.toString() ?? '') ?? 0.0,
day: (doc['day']?.toString() ?? '').split('T').first,
createdAt: doc['created_at']?.toString() ?? '',
description: doc['description'] as String? ?? '',
range1Hour1: _parseTime(doc['range1_hour1']?.toString() ?? '0:0'),
range1Hour2: _parseTime(doc['range1_hour2']?.toString() ?? '0:0'),
status: intToEnumService(statusInt),
rate: doc['rate']?.toString() ?? '',
location: intToEnum(locInt),
);
}
static TimeOfDay _parseTime(String t) {
// Handle ISO8601 (e.g. "1970-01-01T08:30:00.000Z") or "H:M"
final s = t.contains('T') ? t.split('T')[1] : t;
final parts = s.split(':');
return TimeOfDay(
hour: int.tryParse(parts[0]) ?? 0,
minute: int.tryParse(parts.length > 1 ? parts[1] : '0') ?? 0,
);
}
Map<String, dynamic> toDocument() {
return {
'id': id,
'professional_id': professionalId,
'professional_scored': professionalScored,
'user_id': userId,
'user_scored': userScored,
'address': address,
'aditional_address': aditionalAddress,
'latitude': latitude,
'longitude': longitude,
'day': day,
'created_at': createdAt,
'description': description,
'range1_hour1': formatTimeOfDay(range1Hour1),
'range1_hour2': formatTimeOfDay(range1Hour2),
'rate': rate,
'status': enumToIntService(status),
'location': enumToInt(location),
};
}
static TimeOfDay parseTimeOfDay(String timeString) => _parseTime(timeString);
String? formatTimeOfDay(TimeOfDay? time) {
if (time == null) return null;
final h = time.hour.toString().padLeft(2, '0');
final m = time.minute.toString().padLeft(2, '0');
return '$h:$m';
}
@override
String toString() {
return 'Service{professionalId: $professionalId, userId: $userId, day: $day, status: $status}';
}
}