2026-05-16 19:34:33 +02:00
|
|
|
import 'dart:typed_data';
|
|
|
|
|
|
2026-05-16 14:30:23 +02:00
|
|
|
import 'package:flux/features/tickets/models/shipment_document_model.dart';
|
2026-05-15 19:18:03 +02:00
|
|
|
import 'package:flux/features/master_data/providers/models/provider_model.dart';
|
|
|
|
|
import 'package:flux/features/master_data/providers/models/provider_role.dart';
|
|
|
|
|
import 'package:get_it/get_it.dart';
|
|
|
|
|
import 'package:supabase_flutter/supabase_flutter.dart';
|
|
|
|
|
|
|
|
|
|
class TicketsShipmentRepository {
|
|
|
|
|
final _supabase = GetIt.I.get<SupabaseClient>();
|
|
|
|
|
|
|
|
|
|
Future<List<ProviderModel>> fetchRepairCenters() async {
|
|
|
|
|
try {
|
|
|
|
|
final response = await _supabase
|
|
|
|
|
.from('provider')
|
|
|
|
|
.select('*, provider_locations (*)')
|
|
|
|
|
.eq('is_active', true)
|
|
|
|
|
.order('name');
|
|
|
|
|
|
|
|
|
|
final allProviders = (response as List)
|
|
|
|
|
.map((row) => ProviderModel.fromMap(row as Map<String, dynamic>))
|
|
|
|
|
.toList();
|
|
|
|
|
|
|
|
|
|
// Filtriamo lato client per prendere SOLO i repairCenter
|
|
|
|
|
return allProviders
|
|
|
|
|
.where((p) => p.roles.contains(ProviderRole.repairCenter))
|
|
|
|
|
.toList();
|
|
|
|
|
} catch (e) {
|
|
|
|
|
throw ('Errore caricamento laboratori: $e');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-16 19:34:33 +02:00
|
|
|
/// Salva il DDT nel DB, fa l'upload del PDF nello Storage e aggiorna il path
|
|
|
|
|
Future<String> createShipmentWithPdf({
|
2026-05-15 19:18:03 +02:00
|
|
|
required ShipmentDocumentModel document,
|
2026-05-16 19:34:33 +02:00
|
|
|
required Uint8List pdfBytes,
|
|
|
|
|
required String newTicketStatus,
|
2026-05-15 19:18:03 +02:00
|
|
|
}) async {
|
|
|
|
|
try {
|
2026-05-16 19:34:33 +02:00
|
|
|
// 1. Definiamo un percorso unico e ordinato per il file nello Storage
|
|
|
|
|
// Struttura: company_id / ddt / anno / numero_ddt.pdf
|
|
|
|
|
final year = document.docDate.year;
|
|
|
|
|
final cleanedDocNumber = document.docNumber
|
|
|
|
|
.replaceAll('/', '_')
|
|
|
|
|
.replaceAll(' ', '_');
|
|
|
|
|
final storagePath =
|
|
|
|
|
'${document.companyId}/ddt/$year/$cleanedDocNumber.pdf';
|
|
|
|
|
|
|
|
|
|
// 2. Facciamo l'upload dei bytes grezzi nel bucket 'company_documents'
|
|
|
|
|
await _supabase.storage
|
|
|
|
|
.from('company_documents')
|
|
|
|
|
.uploadBinary(
|
|
|
|
|
storagePath,
|
|
|
|
|
pdfBytes,
|
|
|
|
|
fileOptions: const FileOptions(
|
|
|
|
|
contentType: 'application/pdf',
|
|
|
|
|
upsert: true,
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// 3. Creiamo la mappa del documento includendo il percorso dello storage
|
|
|
|
|
final documentData = document.toMap();
|
|
|
|
|
documentData['storage_path'] = storagePath;
|
2026-05-15 19:18:03 +02:00
|
|
|
|
2026-05-16 19:34:33 +02:00
|
|
|
// 4. Inseriamo il Documento di Trasporto nel DB
|
2026-05-18 08:31:39 +02:00
|
|
|
final savedDocument = await _supabase
|
|
|
|
|
.from('shipment_documents')
|
|
|
|
|
.insert(documentData)
|
|
|
|
|
.select('id')
|
|
|
|
|
.single();
|
|
|
|
|
final documentid = savedDocument['id'];
|
2026-05-16 19:34:33 +02:00
|
|
|
// 5. Aggiorniamo lo stato di TUTTI i ticket inclusi nel DDT
|
2026-05-15 19:18:03 +02:00
|
|
|
await _supabase
|
2026-05-16 11:51:26 +02:00
|
|
|
.from('ticket')
|
2026-05-18 08:31:39 +02:00
|
|
|
.update({
|
|
|
|
|
'ticket_status': newTicketStatus,
|
|
|
|
|
'shipment_document_id': documentid,
|
|
|
|
|
})
|
2026-05-15 19:18:03 +02:00
|
|
|
.inFilter('id', document.ticketIds);
|
2026-05-16 19:34:33 +02:00
|
|
|
|
|
|
|
|
// Restituiamo lo storagePath per usarlo subito nell'interfaccia se serve
|
|
|
|
|
return storagePath;
|
2026-05-15 19:18:03 +02:00
|
|
|
} catch (e) {
|
2026-05-16 19:34:33 +02:00
|
|
|
throw ('Errore durante il salvataggio e upload della spedizione: $e');
|
2026-05-15 19:18:03 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|