h-1 lebaran
This commit is contained in:
216
lib/app/services/jadwal_update_service.dart
Normal file
216
lib/app/services/jadwal_update_service.dart
Normal file
@ -0,0 +1,216 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'dart:async';
|
||||
import 'package:penyaluran_app/app/data/models/penyaluran_bantuan_model.dart';
|
||||
import 'package:penyaluran_app/app/services/supabase_service.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
import 'package:penyaluran_app/app/modules/petugas_desa/controllers/counter_service.dart';
|
||||
|
||||
/// Service untuk menangani pembaruan jadwal real-time dan sinkronisasi antar halaman
|
||||
class JadwalUpdateService extends GetxService {
|
||||
static JadwalUpdateService get to => Get.find<JadwalUpdateService>();
|
||||
|
||||
final SupabaseService _supabaseService = SupabaseService.to;
|
||||
|
||||
// Stream controller untuk mengirim notifikasi pembaruan jadwal ke seluruh aplikasi
|
||||
final _jadwalUpdateStream =
|
||||
StreamController<Map<String, dynamic>>.broadcast();
|
||||
Stream<Map<String, dynamic>> get jadwalUpdateStream =>
|
||||
_jadwalUpdateStream.stream;
|
||||
|
||||
// Digunakan untuk menyimpan status terakhir pembaruan jadwal
|
||||
final RxMap<String, DateTime> lastUpdateTimestamp = <String, DateTime>{}.obs;
|
||||
|
||||
// Map untuk melacak jadwal yang sedang dalam pengawasan intensif
|
||||
final RxMap<String, DateTime> _watchedJadwal = <String, DateTime>{}.obs;
|
||||
|
||||
// Timer untuk memeriksa jadwal yang sedang dalam pengawasan
|
||||
Timer? _watchTimer;
|
||||
|
||||
// Mencatat controller yang berlangganan untuk pembaruan
|
||||
final List<String> _subscribedControllers = [];
|
||||
|
||||
// Channel untuk realtime subscription
|
||||
RealtimeChannel? _channel;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
_setupRealtimeSubscription();
|
||||
_startWatchTimer();
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
_jadwalUpdateStream.close();
|
||||
_channel?.unsubscribe();
|
||||
_watchTimer?.cancel();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
// Memulai timer untuk jadwal pengawasan
|
||||
void _startWatchTimer() {
|
||||
_watchTimer = Timer.periodic(const Duration(seconds: 3), (_) {
|
||||
_checkWatchedJadwal();
|
||||
});
|
||||
}
|
||||
|
||||
// Memeriksa jadwal yang sedang diawasi
|
||||
void _checkWatchedJadwal() {
|
||||
final now = DateTime.now();
|
||||
final List<String> jadwalToUpdate = [];
|
||||
final List<String> expiredWatches = [];
|
||||
|
||||
_watchedJadwal.forEach((jadwalId, targetTime) {
|
||||
// Jika sudah mencapai atau melewati waktu target
|
||||
if (now.isAtSameMomentAs(targetTime) || now.isAfter(targetTime)) {
|
||||
jadwalToUpdate.add(jadwalId);
|
||||
// Hentikan pengawasan karena sudah waktunya
|
||||
expiredWatches.add(jadwalId);
|
||||
}
|
||||
|
||||
// Jika sudah lebih dari 5 menit dari waktu target, hentikan pengawasan
|
||||
if (now.difference(targetTime).inMinutes > 5) {
|
||||
expiredWatches.add(jadwalId);
|
||||
}
|
||||
});
|
||||
|
||||
// Hapus jadwal yang sudah tidak perlu diawasi
|
||||
for (var jadwalId in expiredWatches) {
|
||||
_watchedJadwal.remove(jadwalId);
|
||||
}
|
||||
|
||||
// Jika ada jadwal yang perlu diperbarui, kirim sinyal untuk memperbarui
|
||||
if (jadwalToUpdate.isNotEmpty) {
|
||||
print('Watched jadwal time reached: ${jadwalToUpdate.join(", ")}');
|
||||
notifyJadwalNeedsCheck();
|
||||
}
|
||||
}
|
||||
|
||||
// Setup langganan ke pembaruan real-time dari Supabase
|
||||
void _setupRealtimeSubscription() {
|
||||
try {
|
||||
// Langganan pembaruan tabel penyaluran_bantuan
|
||||
_channel = _supabaseService.client
|
||||
.channel('penyaluran_bantuan_updates')
|
||||
.onPostgresChanges(
|
||||
event: PostgresChangeEvent.update,
|
||||
schema: 'public',
|
||||
table: 'penyaluran_bantuan',
|
||||
callback: (payload) {
|
||||
if (payload.newRecord != null) {
|
||||
// Dapatkan data jadwal yang diperbarui
|
||||
final jadwalId = payload.newRecord['id'];
|
||||
final newStatus = payload.newRecord['status'];
|
||||
|
||||
print(
|
||||
'Received realtime update for jadwal ID: $jadwalId with status: $newStatus');
|
||||
|
||||
// Kirim notifikasi ke seluruh aplikasi
|
||||
_broadcastUpdate({
|
||||
'type': 'status_update',
|
||||
'jadwal_id': jadwalId,
|
||||
'new_status': newStatus,
|
||||
'timestamp': DateTime.now().toIso8601String(),
|
||||
});
|
||||
|
||||
// Update timestamp
|
||||
lastUpdateTimestamp[jadwalId] = DateTime.now();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// Mulai berlangganan
|
||||
_channel?.subscribe();
|
||||
|
||||
print(
|
||||
'Realtime subscription for penyaluran_bantuan_updates started successfully');
|
||||
} catch (e) {
|
||||
print('Error setting up realtime subscription: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// Mengirim pembaruan ke semua controller yang berlangganan
|
||||
void _broadcastUpdate(Map<String, dynamic> updateData) {
|
||||
_jadwalUpdateStream.add(updateData);
|
||||
}
|
||||
|
||||
// Controller dapat mendaftar untuk menerima pembaruan jadwal
|
||||
void registerForUpdates(String controllerId) {
|
||||
if (!_subscribedControllers.contains(controllerId)) {
|
||||
_subscribedControllers.add(controllerId);
|
||||
}
|
||||
}
|
||||
|
||||
// Controller berhenti menerima pembaruan
|
||||
void unregisterFromUpdates(String controllerId) {
|
||||
_subscribedControllers.remove(controllerId);
|
||||
}
|
||||
|
||||
// Menambahkan jadwal ke pengawasan intensif
|
||||
void addJadwalToWatch(String jadwalId, DateTime targetTime) {
|
||||
print('Adding jadwal $jadwalId to intensive watch for time $targetTime');
|
||||
_watchedJadwal[jadwalId] = targetTime;
|
||||
}
|
||||
|
||||
// Memicu pemeriksaan jadwal segera
|
||||
void notifyJadwalNeedsCheck() {
|
||||
try {
|
||||
// Kirim notifikasi untuk memeriksa jadwal
|
||||
_broadcastUpdate({
|
||||
'type': 'check_required',
|
||||
'timestamp': DateTime.now().toIso8601String(),
|
||||
});
|
||||
} catch (e) {
|
||||
print('Error notifying jadwal check: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// Muat ulang data jadwal di semua controller yang terdaftar
|
||||
Future<void> notifyJadwalUpdate() async {
|
||||
try {
|
||||
// Kirim notifikasi untuk memuat ulang data
|
||||
_broadcastUpdate({
|
||||
'type': 'reload_required',
|
||||
'timestamp': DateTime.now().toIso8601String(),
|
||||
});
|
||||
|
||||
// Perbarui counter juga saat jadwal diperbarui
|
||||
refreshCounters();
|
||||
|
||||
// Tampilkan notifikasi jika user sedang melihat aplikasi
|
||||
if (Get.isDialogOpen != true && Get.context != null) {
|
||||
Get.snackbar(
|
||||
'Jadwal Diperbarui',
|
||||
'Data jadwal telah diperbarui',
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
backgroundColor: Colors.blue.withOpacity(0.8),
|
||||
colorText: Colors.white,
|
||||
duration: const Duration(seconds: 2),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error notifying jadwal update: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// Metode untuk menyegarkan semua counter terkait penyaluran
|
||||
Future<void> refreshCounters() async {
|
||||
try {
|
||||
// Perbarui counter jika CounterService telah terinisialisasi
|
||||
if (Get.isRegistered<CounterService>()) {
|
||||
final counterService = Get.find<CounterService>();
|
||||
|
||||
// Ambil data jumlah jadwal aktif
|
||||
final jadwalAktifData = await _supabaseService.getJadwalAktif();
|
||||
if (jadwalAktifData != null) {
|
||||
counterService.updateJadwalCounter(jadwalAktifData.length);
|
||||
}
|
||||
|
||||
print('Counters refreshed via JadwalUpdateService');
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error refreshing counters: $e');
|
||||
}
|
||||
}
|
||||
}
|
204
lib/app/services/notification_service.dart
Normal file
204
lib/app/services/notification_service.dart
Normal file
@ -0,0 +1,204 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:penyaluran_app/app/services/supabase_service.dart';
|
||||
|
||||
class NotificationService extends GetxService {
|
||||
static NotificationService get to => Get.find<NotificationService>();
|
||||
|
||||
final SupabaseService _supabaseService = SupabaseService.to;
|
||||
|
||||
// Daftar notifikasi yang belum dibaca
|
||||
final RxList<Map<String, dynamic>> unreadNotifications =
|
||||
<Map<String, dynamic>>[].obs;
|
||||
|
||||
// Mengontrol status loading
|
||||
final RxBool isLoading = false.obs;
|
||||
|
||||
// Jumlah notifikasi yang belum dibaca
|
||||
final RxInt unreadCount = 0.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
fetchNotifications();
|
||||
}
|
||||
|
||||
// Mengambil notifikasi dari database
|
||||
Future<void> fetchNotifications() async {
|
||||
try {
|
||||
isLoading.value = true;
|
||||
|
||||
// Ambil notifikasi dari tabel notifikasi di database
|
||||
final userId = _supabaseService.currentUser?.id;
|
||||
if (userId != null) {
|
||||
final response = await _supabaseService.client
|
||||
.from('notifikasi_jadwal')
|
||||
.select('*')
|
||||
.eq('user_id', userId)
|
||||
.eq('is_read', false)
|
||||
.order('created_at', ascending: false)
|
||||
.limit(20);
|
||||
|
||||
if (response != null) {
|
||||
unreadNotifications.value = response;
|
||||
unreadCount.value = unreadNotifications.length;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error fetching notifications: $e');
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Mengirim notifikasi untuk perubahan status jadwal
|
||||
Future<void> sendJadwalStatusNotification({
|
||||
required String jadwalId,
|
||||
required String newStatus,
|
||||
required String jadwalNama,
|
||||
List<String>? targetUserIds,
|
||||
}) async {
|
||||
try {
|
||||
final currentUserId = _supabaseService.currentUser?.id;
|
||||
if (currentUserId == null) return;
|
||||
|
||||
// Buat pesan berdasarkan status
|
||||
String message;
|
||||
String title;
|
||||
|
||||
switch (newStatus) {
|
||||
case 'AKTIF':
|
||||
title = 'Jadwal Aktif';
|
||||
message =
|
||||
'Jadwal "$jadwalNama" sekarang aktif dan siap dilaksanakan.';
|
||||
break;
|
||||
case 'TERLAKSANA':
|
||||
title = 'Jadwal Selesai';
|
||||
message = 'Jadwal "$jadwalNama" telah berhasil dilaksanakan.';
|
||||
break;
|
||||
case 'BATALTERLAKSANA':
|
||||
title = 'Jadwal Terlewat';
|
||||
message =
|
||||
'Jadwal "$jadwalNama" telah terlewat dan dibatalkan secara otomatis.';
|
||||
break;
|
||||
default:
|
||||
title = 'Perubahan Status Jadwal';
|
||||
message = 'Status jadwal "$jadwalNama" berubah menjadi $newStatus.';
|
||||
}
|
||||
|
||||
// Jika tidak ada targetUserIds, notifikasi hanya untuk diri sendiri
|
||||
final users = targetUserIds ?? [currentUserId];
|
||||
|
||||
// Simpan notifikasi ke database untuk setiap user
|
||||
for (final userId in users) {
|
||||
await _supabaseService.client.from('notifikasi_jadwal').insert({
|
||||
'user_id': userId,
|
||||
'title': title,
|
||||
'message': message,
|
||||
'jadwal_id': jadwalId,
|
||||
'status': newStatus,
|
||||
'is_read': false,
|
||||
'created_at': DateTime.now().toUtc().toIso8601String(),
|
||||
'created_by': currentUserId,
|
||||
});
|
||||
}
|
||||
|
||||
// Jika perubahan status dari pengguna saat ini, tampilkan notifikasi
|
||||
if (users.contains(currentUserId)) {
|
||||
showStatusChangeNotification(title, message, newStatus);
|
||||
}
|
||||
|
||||
// Perbarui daftar notifikasi
|
||||
await fetchNotifications();
|
||||
} catch (e) {
|
||||
print('Error sending notification: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// Menampilkan notifikasi status di UI
|
||||
void showStatusChangeNotification(
|
||||
String title, String message, String status) {
|
||||
Color backgroundColor;
|
||||
|
||||
// Pilih warna berdasarkan status
|
||||
switch (status) {
|
||||
case 'AKTIF':
|
||||
backgroundColor = Colors.green;
|
||||
break;
|
||||
case 'TERLAKSANA':
|
||||
backgroundColor = Colors.blue;
|
||||
break;
|
||||
case 'BATALTERLAKSANA':
|
||||
backgroundColor = Colors.orange;
|
||||
break;
|
||||
default:
|
||||
backgroundColor = Colors.grey;
|
||||
}
|
||||
|
||||
// Tampilkan notifikasi
|
||||
Get.snackbar(
|
||||
title,
|
||||
message,
|
||||
snackPosition: SnackPosition.TOP,
|
||||
backgroundColor: backgroundColor.withOpacity(0.8),
|
||||
colorText: Colors.white,
|
||||
duration: const Duration(seconds: 4),
|
||||
margin: const EdgeInsets.all(8),
|
||||
borderRadius: 8,
|
||||
icon: Icon(
|
||||
_getIconForStatus(status),
|
||||
color: Colors.white,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Menandai notifikasi sebagai telah dibaca
|
||||
Future<void> markAsRead(String notificationId) async {
|
||||
try {
|
||||
await _supabaseService.client
|
||||
.from('notifikasi_jadwal')
|
||||
.update({'is_read': true}).eq('id', notificationId);
|
||||
|
||||
// Hapus dari daftar yang belum dibaca
|
||||
unreadNotifications
|
||||
.removeWhere((notification) => notification['id'] == notificationId);
|
||||
unreadCount.value = unreadNotifications.length;
|
||||
} catch (e) {
|
||||
print('Error marking notification as read: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// Menandai semua notifikasi sebagai telah dibaca
|
||||
Future<void> markAllAsRead() async {
|
||||
try {
|
||||
final userId = _supabaseService.currentUser?.id;
|
||||
if (userId == null) return;
|
||||
|
||||
await _supabaseService.client
|
||||
.from('notifikasi_jadwal')
|
||||
.update({'is_read': true})
|
||||
.eq('user_id', userId)
|
||||
.eq('is_read', false);
|
||||
|
||||
// Kosongkan daftar yang belum dibaca
|
||||
unreadNotifications.clear();
|
||||
unreadCount.value = 0;
|
||||
} catch (e) {
|
||||
print('Error marking all notifications as read: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// Mendapatkan ikon berdasarkan status
|
||||
IconData _getIconForStatus(String status) {
|
||||
switch (status) {
|
||||
case 'AKTIF':
|
||||
return Icons.event_available;
|
||||
case 'TERLAKSANA':
|
||||
return Icons.check_circle;
|
||||
case 'BATALTERLAKSANA':
|
||||
return Icons.event_busy;
|
||||
default:
|
||||
return Icons.notifications;
|
||||
}
|
||||
}
|
||||
}
|
@ -562,19 +562,15 @@ class SupabaseService extends GetxService {
|
||||
try {
|
||||
final now = DateTime.now();
|
||||
final today = DateTime(now.year, now.month, now.day);
|
||||
final tomorrow = today.add(const Duration(days: 1));
|
||||
final week = today.add(const Duration(days: 7));
|
||||
|
||||
// Konversi ke UTC untuk query ke database
|
||||
final tomorrowUtc = tomorrow.toUtc().toIso8601String();
|
||||
final weekUtc = week.toUtc().toIso8601String();
|
||||
|
||||
final response = await client
|
||||
.from('penyaluran_bantuan')
|
||||
.select('*')
|
||||
.gte('tanggal_penyaluran', tomorrowUtc)
|
||||
.lt('tanggal_penyaluran', weekUtc)
|
||||
.inFilter('status', ['DIJADWALKAN']);
|
||||
.gte('tanggal_penyaluran', today)
|
||||
.lt('tanggal_penyaluran', week)
|
||||
.inFilter('status', ['DIJADWALKAN']).order('tanggal_penyaluran',
|
||||
ascending: true);
|
||||
|
||||
return response;
|
||||
} catch (e) {
|
||||
@ -651,15 +647,128 @@ class SupabaseService extends GetxService {
|
||||
}
|
||||
|
||||
// Metode untuk memperbarui status jadwal
|
||||
Future<void> updateJadwalStatus(String jadwalId, String status) async {
|
||||
Future<void> updateJadwalStatus(String jadwalId, String newStatus) async {
|
||||
try {
|
||||
await client.from('penyaluran_bantuan').update({
|
||||
'status': status,
|
||||
'updated_at': DateTime.now().toUtc().toIso8601String(),
|
||||
'status': newStatus,
|
||||
'updated_at': DateTime.now().toUtc().toIso8601String()
|
||||
}).eq('id', jadwalId);
|
||||
|
||||
print('Jadwal status updated: $jadwalId -> $newStatus');
|
||||
} catch (e) {
|
||||
print('Error updating jadwal status: $e');
|
||||
throw e.toString();
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
// Update status jadwal penyaluran secara batch untuk efisiensi
|
||||
Future<void> batchUpdateJadwalStatus(
|
||||
Map<String, String> jadwalUpdates) async {
|
||||
if (jadwalUpdates.isEmpty) return;
|
||||
|
||||
try {
|
||||
print('Attempting batch update for ${jadwalUpdates.length} jadwal');
|
||||
final timestamp = DateTime.now().toUtc().toIso8601String();
|
||||
|
||||
// Format data sesuai dengan yang diharapkan oleh SQL function
|
||||
final List<Map<String, dynamic>> formattedUpdates = jadwalUpdates.entries
|
||||
.map((e) => {'id': e.key, 'status': e.value})
|
||||
.toList();
|
||||
|
||||
print('Formatted updates: $formattedUpdates');
|
||||
|
||||
try {
|
||||
// Coba gunakan RPC dulu - kirim sebagai array dari objek JSON
|
||||
final result = await client.rpc('batch_update_jadwal_status', params: {
|
||||
'jadwal_updates': formattedUpdates,
|
||||
'updated_timestamp': timestamp,
|
||||
});
|
||||
|
||||
print('Batch update via RPC response: $result');
|
||||
|
||||
// Periksa hasil untuk mengkonfirmasi berapa banyak yang berhasil diupdate
|
||||
if (result != null) {
|
||||
final bool success = result['success'] == true;
|
||||
final int updatedCount = result['updated_count'] ?? 0;
|
||||
|
||||
if (success) {
|
||||
print('Successfully updated $updatedCount records via RPC');
|
||||
|
||||
// Log ID yang berhasil diupdate
|
||||
final List<String> successIds =
|
||||
List<String>.from(result['success_ids'] ?? []);
|
||||
if (successIds.isNotEmpty) {
|
||||
print(
|
||||
'Successfully updated jadwal IDs: ${successIds.join(", ")}');
|
||||
}
|
||||
|
||||
// Jika ada yang gagal, log untuk debugging
|
||||
if (updatedCount < jadwalUpdates.length) {
|
||||
print(
|
||||
'Warning: ${jadwalUpdates.length - updatedCount} records failed to update');
|
||||
|
||||
// Periksa apakah ada informasi error
|
||||
if (result['errors'] != null) {
|
||||
final int errorCount = result['errors']['count'] ?? 0;
|
||||
if (errorCount > 0) {
|
||||
final List<String> errorIds =
|
||||
List<String>.from(result['errors']['ids'] ?? []);
|
||||
final List<String> errorMessages =
|
||||
List<String>.from(result['errors']['messages'] ?? []);
|
||||
|
||||
for (int i = 0; i < errorCount; i++) {
|
||||
if (i < errorIds.length && i < errorMessages.length) {
|
||||
print(
|
||||
'Error updating jadwal ${errorIds[i]}: ${errorMessages[i]}');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update individual yang gagal menggunakan metode satu per satu
|
||||
for (var entry in jadwalUpdates.entries) {
|
||||
if (!successIds.contains(entry.key)) {
|
||||
try {
|
||||
await updateJadwalStatus(entry.key, entry.value);
|
||||
print('Fallback update successful for jadwal ${entry.key}');
|
||||
} catch (e) {
|
||||
print(
|
||||
'Fallback update also failed for jadwal ${entry.key}: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
print(
|
||||
'Batch update reported failure. Falling back to individual updates.');
|
||||
_fallbackToIndividualUpdates(jadwalUpdates);
|
||||
}
|
||||
} else {
|
||||
print(
|
||||
'Batch update returned null result. Falling back to individual updates.');
|
||||
_fallbackToIndividualUpdates(jadwalUpdates);
|
||||
}
|
||||
} catch (rpcError) {
|
||||
print('RPC batch update failed: $rpcError');
|
||||
print('Falling back to individual updates');
|
||||
_fallbackToIndividualUpdates(jadwalUpdates);
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error in batch update process: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function untuk fallback ke individual updates
|
||||
Future<void> _fallbackToIndividualUpdates(
|
||||
Map<String, String> jadwalUpdates) async {
|
||||
for (var entry in jadwalUpdates.entries) {
|
||||
try {
|
||||
await updateJadwalStatus(entry.key, entry.value);
|
||||
print('Individual update successful: ${entry.key} -> ${entry.value}');
|
||||
} catch (updateError) {
|
||||
print('Failed to update jadwal ${entry.key}: $updateError');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -874,7 +983,7 @@ class SupabaseService extends GetxService {
|
||||
.select('stok_bantuan_id, jumlah')
|
||||
.eq('id', penitipanId);
|
||||
|
||||
if (response == null || response.isEmpty) {
|
||||
if (response.isEmpty) {
|
||||
throw 'Data penitipan tidak ditemukan';
|
||||
}
|
||||
|
||||
@ -1930,8 +2039,8 @@ class SupabaseService extends GetxService {
|
||||
}
|
||||
|
||||
if (jenisPerubahan != null) {
|
||||
filterString += (filterString.isNotEmpty ? ',' : '') +
|
||||
'jenis_perubahan.eq.$jenisPerubahan';
|
||||
filterString +=
|
||||
'${filterString.isNotEmpty ? ',' : ''}jenis_perubahan.eq.$jenisPerubahan';
|
||||
}
|
||||
|
||||
final response = await client.from('riwayat_stok').select('''
|
||||
@ -2006,7 +2115,7 @@ class SupabaseService extends GetxService {
|
||||
print('Stok berhasil ditambahkan dari penitipan');
|
||||
} catch (e) {
|
||||
print('Error adding stok from penitipan: $e');
|
||||
throw e; // Re-throw untuk penanganan di tingkat yang lebih tinggi
|
||||
rethrow; // Re-throw untuk penanganan di tingkat yang lebih tinggi
|
||||
}
|
||||
}
|
||||
|
||||
@ -2058,7 +2167,7 @@ class SupabaseService extends GetxService {
|
||||
print('Stok berhasil dikurangi dari penyaluran');
|
||||
} catch (e) {
|
||||
print('Error reducing stok from penyaluran: $e');
|
||||
throw e; // Re-throw untuk penanganan di tingkat yang lebih tinggi
|
||||
rethrow; // Re-throw untuk penanganan di tingkat yang lebih tinggi
|
||||
}
|
||||
}
|
||||
|
||||
@ -2075,7 +2184,7 @@ class SupabaseService extends GetxService {
|
||||
String fotoBuktiUrl = '';
|
||||
if (fotoBuktiPath.isNotEmpty) {
|
||||
final String fileName =
|
||||
'${DateTime.now().millisecondsSinceEpoch}_${stokBantuanId}.jpg';
|
||||
'${DateTime.now().millisecondsSinceEpoch}_$stokBantuanId.jpg';
|
||||
final fileResponse = await client.storage.from('stok_bukti').upload(
|
||||
fileName,
|
||||
File(fotoBuktiPath),
|
||||
@ -2125,7 +2234,7 @@ class SupabaseService extends GetxService {
|
||||
print('Stok berhasil ditambahkan secara manual');
|
||||
} catch (e) {
|
||||
print('Error adding stok manually: $e');
|
||||
throw e; // Re-throw untuk penanganan di tingkat yang lebih tinggi
|
||||
rethrow; // Re-throw untuk penanganan di tingkat yang lebih tinggi
|
||||
}
|
||||
}
|
||||
|
||||
@ -2164,7 +2273,7 @@ class SupabaseService extends GetxService {
|
||||
String fotoBuktiUrl = '';
|
||||
if (fotoBuktiPath.isNotEmpty) {
|
||||
final String fileName =
|
||||
'${DateTime.now().millisecondsSinceEpoch}_${stokBantuanId}.jpg';
|
||||
'${DateTime.now().millisecondsSinceEpoch}_$stokBantuanId.jpg';
|
||||
final fileResponse = await client.storage.from('stok_bukti').upload(
|
||||
fileName,
|
||||
File(fotoBuktiPath),
|
||||
@ -2198,7 +2307,7 @@ class SupabaseService extends GetxService {
|
||||
print('Stok berhasil dikurangi secara manual');
|
||||
} catch (e) {
|
||||
print('Error reducing stok manually: $e');
|
||||
throw e; // Re-throw untuk penanganan di tingkat yang lebih tinggi
|
||||
rethrow; // Re-throw untuk penanganan di tingkat yang lebih tinggi
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user