fitur order paket

This commit is contained in:
Andreas Malvino
2025-06-05 17:00:44 +07:00
parent 046eac48e8
commit c4dd4fdfa2
8 changed files with 3503 additions and 1490 deletions

View File

@ -1,54 +1,156 @@
import 'dart:convert';
class PaketModel {
final String? id;
final String? nama;
final String? deskripsi;
final int? harga;
final int? kuantitas;
final String? foto_paket;
final List<dynamic>? satuanWaktuSewa;
final String id;
final String nama;
final String deskripsi;
final double harga;
final int kuantitas;
final List<String> foto;
final List<Map<String, dynamic>> satuanWaktuSewa;
final DateTime createdAt;
final DateTime updatedAt;
final String? foto_paket; // Main photo URL
final List<String>? images; // List of photo URLs
PaketModel({
this.id,
this.nama,
this.deskripsi,
this.harga,
this.kuantitas,
required this.id,
required this.nama,
required this.deskripsi,
required this.harga,
required this.kuantitas,
required this.foto,
required this.satuanWaktuSewa,
this.foto_paket,
this.satuanWaktuSewa,
this.images,
required this.createdAt,
required this.updatedAt,
});
Map<String, dynamic> toMap() {
return {
'id': id,
'nama': nama,
'deskripsi': deskripsi,
'harga': harga,
'kuantitas': kuantitas,
'foto_paket': foto_paket,
'satuanWaktuSewa': satuanWaktuSewa,
};
}
factory PaketModel.fromMap(Map<String, dynamic> map) {
// Alias for fromJson to maintain compatibility
factory PaketModel.fromMap(Map<String, dynamic> json) => PaketModel.fromJson(json);
factory PaketModel.fromJson(Map<String, dynamic> json) {
// Handle different possible JSON structures
final fotoList = <String>[];
// Check for different possible photo field names
if (json['foto'] != null) {
if (json['foto'] is String) {
fotoList.add(json['foto']);
} else if (json['foto'] is List) {
fotoList.addAll((json['foto'] as List).whereType<String>());
}
}
if (json['foto_paket'] != null) {
if (json['foto_paket'] is String) {
fotoList.add(json['foto_paket']);
} else if (json['foto_paket'] is List) {
fotoList.addAll((json['foto_paket'] as List).whereType<String>());
}
}
// Handle satuan_waktu_sewa
List<Map<String, dynamic>> satuanWaktuList = [];
if (json['satuan_waktu_sewa'] != null) {
if (json['satuan_waktu_sewa'] is List) {
satuanWaktuList = List<Map<String, dynamic>>.from(
json['satuan_waktu_sewa'].map((x) => x is Map ? Map<String, dynamic>.from(x) : {})
);
} else if (json['satuan_waktu_sewa'] is Map) {
satuanWaktuList = [Map<String, dynamic>.from(json['satuan_waktu_sewa'])];
}
}
return PaketModel(
id: map['id'],
nama: map['nama'],
deskripsi: map['deskripsi'],
harga: map['harga']?.toInt(),
kuantitas: map['kuantitas']?.toInt(),
foto_paket: map['foto_paket'],
satuanWaktuSewa: map['satuanWaktuSewa'],
id: json['id']?.toString() ?? '',
nama: json['nama']?.toString() ?? '',
deskripsi: json['deskripsi']?.toString() ?? '',
harga: (json['harga'] is num) ? (json['harga'] as num).toDouble() : 0.0,
kuantitas: (json['kuantitas'] is num) ? (json['kuantitas'] as num).toInt() : 1,
foto: fotoList,
satuanWaktuSewa: satuanWaktuList,
foto_paket: json['foto_paket']?.toString(),
images: json['images'] != null ? List<String>.from(json['images']) : null,
createdAt: json['created_at'] != null
? DateTime.parse(json['created_at'].toString())
: DateTime.now(),
updatedAt: json['updated_at'] != null
? DateTime.parse(json['updated_at'].toString())
: DateTime.now(),
);
}
String toJson() => json.encode(toMap());
// Convert to JSON
Map<String, dynamic> toJson() => {
'id': id,
'nama': nama,
'deskripsi': deskripsi,
'harga': harga,
'kuantitas': kuantitas,
'foto': foto,
'foto_paket': foto_paket,
'images': images,
'satuan_waktu_sewa': satuanWaktuSewa,
'created_at': createdAt.toIso8601String(),
'updated_at': updatedAt.toIso8601String(),
};
factory PaketModel.fromJson(String source) => PaketModel.fromMap(json.decode(source));
@override
String toString() {
return 'PaketModel(id: $id, nama: $nama, deskripsi: $deskripsi, harga: $harga, kuantitas: $kuantitas, foto_paket: $foto_paket, satuanWaktuSewa: $satuanWaktuSewa)';
// Create a copy of the model with some fields updated
PaketModel copyWith({
String? id,
String? nama,
String? deskripsi,
double? harga,
int? kuantitas,
List<String>? foto,
List<Map<String, dynamic>>? satuanWaktuSewa,
String? foto_paket,
List<String>? images,
DateTime? createdAt,
DateTime? updatedAt,
}) {
return PaketModel(
id: id ?? this.id,
nama: nama ?? this.nama,
deskripsi: deskripsi ?? this.deskripsi,
harga: harga ?? this.harga,
kuantitas: kuantitas ?? this.kuantitas,
foto: foto ?? List.from(this.foto),
satuanWaktuSewa: satuanWaktuSewa ?? List.from(this.satuanWaktuSewa),
foto_paket: foto_paket ?? this.foto_paket,
images: images ?? (this.images != null ? List.from(this.images!) : null),
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
);
}
// Get the first photo URL or a placeholder
String get firstPhotoUrl => foto.isNotEmpty ? foto.first : '';
// Get the formatted price
String get formattedPrice => 'Rp${harga.toStringAsFixed(0).replaceAllMapped(
RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'),
(Match m) => '${m[1]}.',
)}';
// Check if the package is available
bool get isAvailable => kuantitas > 0;
// Get the first available time unit
Map<String, dynamic>? get defaultTimeUnit =>
satuanWaktuSewa.isNotEmpty ? satuanWaktuSewa.first : null;
// Get the price for a specific time unit
double getPriceForTimeUnit(String timeUnitId) {
try {
final unit = satuanWaktuSewa.firstWhere(
(unit) => unit['id'] == timeUnitId || unit['id'].toString() == timeUnitId,
);
return (unit['harga'] as num?)?.toDouble() ?? 0.0;
} catch (e) {
return 0.0;
}
}
}

View File

@ -846,28 +846,6 @@ class AsetProvider extends GetxService {
return null;
}
}
// Get bank accounts from akun_bank table
Future<List<Map<String, dynamic>>> getBankAccounts() async {
try {
debugPrint('🔍 Fetching bank accounts from akun_bank table');
final response = await client
.from('akun_bank')
.select('*')
.order('nama_bank', ascending: true);
debugPrint('✅ Fetched ${response.length} bank accounts');
// Convert response to List<Map<String, dynamic>>
List<Map<String, dynamic>> accounts = List<Map<String, dynamic>>.from(response);
return accounts;
} catch (e) {
debugPrint('❌ Error fetching bank accounts: $e');
return [];
}
}
// Get sewa_aset details with aset data
Future<Map<String, dynamic>?> getSewaAsetWithAsetData(
@ -967,29 +945,6 @@ class AsetProvider extends GetxService {
return null;
}
}
// Get all photos for a paket using id_paket column
Future<List<dynamic>> getFotoPaket(String paketId) async {
try {
debugPrint('📷 Fetching all photos for paket ID: $paketId');
final response = await client
.from('foto_aset')
.select('*')
.eq('id_paket', paketId);
if (response.isEmpty) {
debugPrint('⚠️ No photos found for paket $paketId');
return [];
}
debugPrint('✅ Found ${response.length} photos for paket $paketId');
return response;
} catch (e) {
debugPrint('❌ Error fetching photos for paket $paketId: $e');
return [];
}
}
// Get paket data with their associated satuan waktu sewa data
Future<List<dynamic>> getPakets() async {
@ -1058,8 +1013,7 @@ class AsetProvider extends GetxService {
// Default to hourly if not specified
String satuanWaktu = 'jam';
if (swsResponse != null &&
swsResponse['satuan_waktu'] != null &&
if (swsResponse['satuan_waktu'] != null &&
swsResponse['satuan_waktu']['nama'] != null) {
satuanWaktu = swsResponse['satuan_waktu']['nama'];
}
@ -1087,7 +1041,7 @@ class AsetProvider extends GetxService {
final response = await client.from('sewa_paket').insert(sewa).select();
if (response != null && response.isNotEmpty) {
if (response.isNotEmpty) {
return true;
}
return false;
@ -1096,4 +1050,189 @@ class AsetProvider extends GetxService {
return false;
}
}
// Get photos for a package
Future<List<String>> getFotoPaket(String paketId) async {
try {
final response = await client
.from('foto_aset')
.select('foto_aset')
.eq('id_paket', paketId)
.order('created_at');
if (response != null && response.isNotEmpty) {
return response.map<String>((item) => item['foto_aset'] as String).toList();
}
return [];
} catch (e) {
debugPrint('Error getting package photos: $e');
return [];
}
}
// Get items included in a package with additional asset details
Future<List<Map<String, dynamic>>> getPaketItems(String paketId) async {
debugPrint('🔄 [1/3] Starting to fetch items for paket ID: $paketId');
try {
// 1. First, get the basic package items (aset_id and kuantitas)
debugPrint('🔍 [2/3] Querying paket_item table for paket_id: $paketId');
final response = await client
.from('paket_item')
.select('''
aset_id,
kuantitas
''')
.eq('paket_id', paketId);
debugPrint('📊 Raw response from paket_item query:');
debugPrint(response.toString());
if (response == null) {
debugPrint('❌ [ERROR] Null response from paket_item query');
return [];
}
if (response.isEmpty) {
debugPrint(' [INFO] No items found in paket_item for paket ID: $paketId');
return [];
}
debugPrint('✅ [SUCCESS] Found ${response.length} items in paket_item');
final List<Map<String, dynamic>> enrichedItems = [];
// Process each item to fetch additional details
debugPrint('🔄 [3/3] Processing ${response.length} items to fetch asset details');
for (var item in response) {
final String? asetId = item['aset_id']?.toString();
final int kuantitas = item['kuantitas'] ?? 1;
debugPrint('\n🔍 Processing item:');
debugPrint(' - Raw item data: $item');
debugPrint(' - aset_id: $asetId');
debugPrint(' - kuantitas: $kuantitas');
if (asetId == null || asetId.isEmpty) {
debugPrint('⚠️ [WARNING] Skipping item with null/empty aset_id');
continue;
}
try {
// 1. Get asset name from aset table
debugPrint(' - Querying aset table for id: $asetId');
final asetResponse = await client
.from('aset')
.select('id, nama, deskripsi')
.eq('id', asetId)
.maybeSingle();
debugPrint(' - Aset response: ${asetResponse?.toString() ?? 'null'}');
if (asetResponse == null) {
debugPrint('⚠️ [WARNING] No asset found with id: $asetId');
enrichedItems.add({
'aset_id': asetId,
'kuantitas': kuantitas,
'nama_aset': 'Item tidak diketahui',
'foto_aset': '',
'semua_foto': <String>[],
'error': 'Asset not found'
});
continue;
}
// 2. Get only the first photo from foto_aset table
debugPrint(' - Querying first photo for id_aset: $asetId');
final fotoResponse = await client
.from('foto_aset')
.select('foto_aset')
.eq('id_aset', asetId)
.order('created_at', ascending: true)
.limit(1);
String? fotoUtama = '';
List<String> semuaFoto = [];
if (fotoResponse.isNotEmpty) {
final firstFoto = fotoResponse.first['foto_aset']?.toString();
if (firstFoto != null && firstFoto.isNotEmpty) {
fotoUtama = firstFoto;
semuaFoto = [firstFoto];
debugPrint(' - Found photo: $firstFoto');
} else {
debugPrint(' - No valid photo URL found');
}
} else {
debugPrint(' - No photos found for asset $asetId');
}
// 4. Combine all data
final enrichedItem = {
'aset_id': asetId,
'kuantitas': kuantitas,
'nama_aset': asetResponse['nama']?.toString() ?? 'Nama tidak tersedia',
'foto_aset': fotoUtama,
'semua_foto': semuaFoto,
'debug': {
'aset_query': asetResponse,
'foto_count': semuaFoto.length
}
};
enrichedItems.add(enrichedItem);
// Debug log
debugPrint('✅ Successfully processed item:');
debugPrint(' - Aset ID: $asetId');
debugPrint(' - Nama: ${enrichedItem['nama_aset']}');
debugPrint(' - Kuantitas: $kuantitas');
debugPrint(' - Jumlah Foto: ${semuaFoto.length}');
if (semuaFoto.isNotEmpty) {
debugPrint(' - Foto Utama: ${semuaFoto.first}');
}
} catch (e) {
debugPrint('❌ Error processing asset $asetId: $e');
// Still add the basic item even if we couldn't fetch additional details
enrichedItems.add({
'aset_id': asetId,
'kuantitas': item['kuantitas'],
'nama_aset': 'Nama Aset Tidak Ditemukan',
'foto_aset': '',
'semua_foto': <String>[],
});
}
}
debugPrint('✅ Successfully fetched ${enrichedItems.length} items with details');
return enrichedItems;
} catch (e, stackTrace) {
debugPrint('❌ Error getting package items for paket $paketId: $e');
debugPrint('Stack trace: $stackTrace');
return [];
}
}
// Get available bank accounts for payment
Future<List<Map<String, dynamic>>> getBankAccounts() async {
try {
final response = await client
.from('bank_accounts')
.select('*')
.eq('is_active', true)
.order('bank_name');
if (response != null && response.isNotEmpty) {
return List<Map<String, dynamic>>.from(response);
}
return [];
} catch (e) {
debugPrint('Error getting bank accounts: $e');
return [];
}
}
}