TIF_NGANJUK_E41212036/lib/domain/models/transaction_porter_model.dart

278 lines
9.2 KiB
Dart

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;
final ReassignmentInfo? reassignmentInfo;
final String? previousTransactionId;
final bool? isRejected;
final bool? hasAssignedPorter;
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,
this.reassignmentInfo,
this.previousTransactionId,
this.isRejected,
this.hasAssignedPorter,
}) : 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<dynamic, dynamic> json, String id) {
RejectionInfo? rejectionInfo;
if (json.containsKey('rejectionInfo')) {
try {
final rejectionData = json['rejectionInfo'];
if (rejectionData is Map) {
final Map<String, dynamic> safeRejectionData =
Map<String, dynamic>.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',
);
}
}
ReassignmentInfo? reassignmentInfo;
if (json.containsKey('reassignmentInfo') && json['reassignmentInfo'] != null) {
try {
final Map<String, dynamic> reassignmentData;
if (json['reassignmentInfo'] is Map<String, dynamic>) {
reassignmentData = json['reassignmentInfo'];
} else if (json['reassignmentInfo'] is Map) {
// Convert dynamic map to string map
reassignmentData = {};
(json['reassignmentInfo'] as Map).forEach((key, value) {
reassignmentData[key.toString()] = value;
});
} else {
reassignmentData = {'reason': 'Format tidak valid', 'timestamp': DateTime.now().millisecondsSinceEpoch};
}
reassignmentInfo = ReassignmentInfo.fromJson(reassignmentData);
} catch (e) {
print('Error parsing reassignmentInfo: $e');
}
}
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,
reassignmentInfo: reassignmentInfo,
previousTransactionId: json['previousTransactionId'],
isRejected: json['isRejected'] as bool? ?? false,
hasAssignedPorter: json['hasAssignedPorter'] as bool? ?? false,
);
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = {
'id': id,
'kodePorter': kodePorter,
'porterUserId': porterUserId,
'idPassenger': idPassenger,
'locationPassenger': locationPassenger,
'locationPorter': locationPorter,
'porterOnlineId': porterOnlineId,
'status': status,
'ticketId': ticketId,
'transactionId': transactionId,
'createdAt': createdAt.millisecondsSinceEpoch,
'rejectionInfo': rejectionInfo?.toJson(),
'reassignmentInfo': reassignmentInfo?.toJson(),
'previousTransactionId': previousTransactionId,
'isRejected': isRejected,
'hasAssignedPorter': hasAssignedPorter,
};
if (updatedAt != null) {
data['updatedAt'] = updatedAt!.millisecondsSinceEpoch;
}
if (rejectionInfo != null) {
data['rejectionInfo'] = rejectionInfo!.toJson();
}
return data;
}
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<String, dynamic> 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<String, dynamic> toJson() {
return {
'reason': reason,
'timestamp': timestamp.millisecondsSinceEpoch,
'status': status,
};
}
}
class ReassignmentInfo {
final String? previousPorterId;
final String? rejectionId;
final String reason;
final DateTime timestamp;
ReassignmentInfo({
this.previousPorterId,
this.rejectionId,
required this.reason,
required this.timestamp,
});
factory ReassignmentInfo.fromJson(Map<String, dynamic> json) {
var rawTimestamp = json['timestamp'];
DateTime timestamp;
if (rawTimestamp is Timestamp) {
timestamp = rawTimestamp.toDate();
} else if (rawTimestamp is int) {
timestamp = DateTime.fromMillisecondsSinceEpoch(rawTimestamp);
} else {
timestamp = DateTime.now(); // Default fallback
}
return ReassignmentInfo(
previousPorterId: json['previousPorterId'],
rejectionId: json['rejectionId'],
reason: json['reason'] ?? 'Dialihkan ke porter baru',
timestamp: timestamp,
);
}
Map<String, dynamic> toJson() {
return {
'previousPorterId': previousPorterId,
'rejectionId': rejectionId,
'reason': reason,
'timestamp': timestamp.millisecondsSinceEpoch,
};
}
}