import 'dart:developer'; import 'package:cloud_firestore/cloud_firestore.dart'; class PorterTransactionModel { final String id; final String kodePorter; final String porterUserId; final String idPassenger; final String locationPassenger; final String locationPorter; final String porterOnlineId; final String status; final String normalizedStatus; final String ticketId; final String transactionId; final DateTime createdAt; final DateTime? updatedAt; final RejectionInfo? rejectionInfo; PorterTransactionModel({ required this.id, required this.kodePorter, this.porterUserId = '', required this.idPassenger, required this.locationPassenger, required this.locationPorter, required this.porterOnlineId, required this.status, required this.ticketId, required this.transactionId, required this.createdAt, this.updatedAt, this.rejectionInfo, }) : normalizedStatus = _normalizeStatus(status, rejectionInfo); static String _normalizeStatus(String status, RejectionInfo? rejectionInfo) { if (rejectionInfo != null) { return "rejected"; } final lowercaseStatus = status.toLowerCase().trim(); // Status standar if (lowercaseStatus == "pending") return "pending"; if (lowercaseStatus == "proses") return "proses"; if (lowercaseStatus == "selesai") return "selesai"; if (lowercaseStatus == "rejected" || lowercaseStatus == "ditolak") return "rejected"; // Logic fallback untuk menangani potensi status yang tidak konsisten if (lowercaseStatus.contains("pend")) return "pending"; if (lowercaseStatus.contains("pros")) return "proses"; if (lowercaseStatus.contains("sele") || lowercaseStatus.contains("done")) return "selesai"; if (lowercaseStatus.contains("rej") || lowercaseStatus.contains("tol")) return "rejected"; return "pending"; } factory PorterTransactionModel.fromJson(Map json, String id) { RejectionInfo? rejectionInfo; if (json.containsKey('rejectionInfo')) { try { final rejectionData = json['rejectionInfo']; if (rejectionData is Map) { final Map safeRejectionData = Map.from(rejectionData.map((key, value) => MapEntry(key.toString(), value))); rejectionInfo = RejectionInfo( reason: safeRejectionData['reason']?.toString() ?? 'Tidak ada alasan', timestamp: safeRejectionData.containsKey('timestamp') ? (safeRejectionData['timestamp'] is int ? DateTime.fromMillisecondsSinceEpoch(safeRejectionData['timestamp']) : DateTime.now()) : DateTime.now(), status: safeRejectionData['status']?.toString() ?? 'rejected', ); } } catch (e) { log('[Transaction Porter Model] Error parsing rejectionInfo: $e'); rejectionInfo = RejectionInfo( reason: 'Data tidak valid', timestamp: DateTime.now(), status: 'rejected', ); } } return PorterTransactionModel( id: id, kodePorter: json['kodePorter'] ?? '', porterUserId: json['porterUserId'] ?? '', idPassenger: json['idPassenger'] as String? ?? '', locationPassenger: json['locationPassenger'] as String? ?? '', locationPorter: json['locationPorter'] as String? ?? '', porterOnlineId: json['porterOnlineId'] as String? ?? '', status: json['status'] as String? ?? 'Data Not Found', ticketId: json['ticketId'] as String? ?? '', transactionId: json['transactionId'] as String? ?? '', createdAt: json['createdAt'] is int ? DateTime.fromMillisecondsSinceEpoch(json['createdAt'] as int) : (json['createdAt'] is Timestamp) ? (json['createdAt'] as Timestamp).toDate() : DateTime.now(), updatedAt: json['updatedAt'] != null ? (json['updatedAt'] is int ? DateTime.fromMillisecondsSinceEpoch(json['updatedAt']) : (json['updatedAt'] is DateTime ? json['updatedAt'] : null)) : null, rejectionInfo: rejectionInfo, ); } Map toJson() { final Map data = { 'id': id, 'kodePorter': kodePorter, 'porterUserId': porterUserId, 'idPassenger': idPassenger, 'locationPassenger': locationPassenger, 'locationPorter': locationPorter, 'porterOnlineId': porterOnlineId, 'status': status, 'ticketId': ticketId, 'transactionId': transactionId, 'createdAt': createdAt.millisecondsSinceEpoch, }; if (updatedAt != null) { data['updatedAt'] = updatedAt!.millisecondsSinceEpoch; } if (rejectionInfo != null) { data['rejectionInfo'] = rejectionInfo!.toJson(); } return data; } // Membuat salinan model dengan nilai baru PorterTransactionModel copyWith({ String? id, String? kodePorter, String? porterUserId, String? idPassenger, String? locationPassenger, String? locationPorter, String? porterOnlineId, String? status, String? ticketId, String? transactionId, DateTime? createdAt, DateTime? updatedAt, RejectionInfo? rejectionInfo, }) { return PorterTransactionModel( id: id ?? this.id, kodePorter: kodePorter ?? this.kodePorter, porterUserId: porterUserId ?? this.porterUserId, idPassenger: idPassenger ?? this.idPassenger, locationPassenger: locationPassenger ?? this.locationPassenger, locationPorter: locationPorter ?? this.locationPorter, porterOnlineId: porterOnlineId ?? this.porterOnlineId, status: status ?? this.status, ticketId: ticketId ?? this.ticketId, transactionId: transactionId ?? this.transactionId, createdAt: createdAt ?? this.createdAt, updatedAt: updatedAt ?? this.updatedAt, rejectionInfo: rejectionInfo ?? this.rejectionInfo, ); } } class RejectionInfo { final String reason; final DateTime timestamp; final String status; RejectionInfo({required this.reason, required this.timestamp, this.status = 'rejected'}); factory RejectionInfo.fromJson(Map json) { return RejectionInfo( reason: json['reason'] ?? 'Tidak ada alasan', timestamp: json['timestamp'] is Timestamp ? (json['timestamp'] as Timestamp).toDate() : DateTime.fromMillisecondsSinceEpoch(json['timestamp'] ?? 0), status: json['status'] ?? 'rejected', ); } Map toJson() { return { 'reason': reason, 'timestamp': timestamp.millisecondsSinceEpoch, 'status': status, }; } }