refactor shipping attachments and changed shipment to shipping for coherence
This commit is contained in:
@@ -41,6 +41,7 @@ class AttachmentsBloc extends Bloc<AttachmentsEvent, AttachmentsState> {
|
||||
add(LoadAttachmentsEvent(parentId: parentId));
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> _onParentEntitySaved(
|
||||
ParentEntitySavedEvent event,
|
||||
Emitter<AttachmentsState> emit,
|
||||
@@ -67,6 +68,7 @@ class AttachmentsBloc extends Bloc<AttachmentsEvent, AttachmentsState> {
|
||||
parentType: state.parentType,
|
||||
pickedFile: fakePlatformFile,
|
||||
companyId: companyId!,
|
||||
bucket: _getBucketForParentType,
|
||||
);
|
||||
}).toList();
|
||||
|
||||
@@ -156,6 +158,7 @@ class AttachmentsBloc extends Bloc<AttachmentsEvent, AttachmentsState> {
|
||||
parentType: state.parentType,
|
||||
pickedFile: file,
|
||||
companyId: companyId!,
|
||||
bucket: _getBucketForParentType,
|
||||
);
|
||||
}).toList();
|
||||
|
||||
@@ -192,6 +195,7 @@ class AttachmentsBloc extends Bloc<AttachmentsEvent, AttachmentsState> {
|
||||
parentType: state.parentType,
|
||||
pickedFile: file,
|
||||
companyId: event.companyId,
|
||||
bucket: _getBucketForParentType,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -218,6 +222,7 @@ class AttachmentsBloc extends Bloc<AttachmentsEvent, AttachmentsState> {
|
||||
parentType: state.parentType,
|
||||
pickedFile: fakePlatformFile,
|
||||
companyId: event.companyId,
|
||||
bucket: _getBucketForParentType,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -242,6 +247,7 @@ class AttachmentsBloc extends Bloc<AttachmentsEvent, AttachmentsState> {
|
||||
await _repository.deleteFiles(
|
||||
files: state.selectedFiles,
|
||||
currentContextType: state.parentType,
|
||||
bucket: _getBucketForParentType,
|
||||
);
|
||||
emit(state.copyWith(status: AttachmentsStatus.ready, selectedFiles: []));
|
||||
} catch (e) {
|
||||
@@ -298,6 +304,8 @@ class AttachmentsBloc extends Bloc<AttachmentsEvent, AttachmentsState> {
|
||||
return file.copyWith(ticketId: event.targetId);
|
||||
case AttachmentParentType.operation:
|
||||
return file.copyWith(operationId: event.targetId);
|
||||
case AttachmentParentType.shippingDocument:
|
||||
return file.copyWith(shippingDocumentId: event.targetId);
|
||||
}
|
||||
}
|
||||
return file;
|
||||
@@ -386,4 +394,17 @@ class AttachmentsBloc extends Bloc<AttachmentsEvent, AttachmentsState> {
|
||||
emit(state.copyWith(localFiles: updatedLocalFiles));
|
||||
}
|
||||
}
|
||||
|
||||
Bucket get _getBucketForParentType {
|
||||
switch (state.parentType) {
|
||||
case AttachmentParentType.customer:
|
||||
return Bucket.documents;
|
||||
case AttachmentParentType.ticket:
|
||||
return Bucket.documents;
|
||||
case AttachmentParentType.operation:
|
||||
return Bucket.documents;
|
||||
case AttachmentParentType.shippingDocument:
|
||||
return Bucket.companyDocuments;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@ enum AttachmentsStatus { initial, loading, ready, uploading, success, failure }
|
||||
enum AttachmentParentType {
|
||||
operation('operation_id'),
|
||||
ticket('ticket_id'),
|
||||
customer('customer_id');
|
||||
customer('customer_id'),
|
||||
shippingDocument('shipping_document_id');
|
||||
|
||||
final String dbColumn;
|
||||
const AttachmentParentType(this.dbColumn);
|
||||
|
||||
@@ -4,17 +4,27 @@ import 'package:flux/features/attachments/models/attachment_model.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
import 'package:flux/features/attachments/blocs/attachments_bloc.dart';
|
||||
|
||||
enum Bucket {
|
||||
documents('documents'),
|
||||
companyDocuments('company_documents');
|
||||
|
||||
final String value;
|
||||
const Bucket(this.value);
|
||||
}
|
||||
|
||||
class AttachmentsRepository {
|
||||
final _supabase = Supabase.instance.client;
|
||||
static const String _bucketName = 'documents';
|
||||
static const String _tableName =
|
||||
'attachment'; // Cambia col vero nome della tua tabella se diverso!
|
||||
|
||||
/// Scarica i byte di un file direttamente da Supabase Storage
|
||||
Future<Uint8List> downloadAttachmentBytes(String storagePath) async {
|
||||
Future<Uint8List> downloadAttachmentBytes({
|
||||
required String storagePath,
|
||||
required Bucket bucket,
|
||||
}) async {
|
||||
try {
|
||||
final Uint8List bytes = await _supabase.storage
|
||||
.from(_bucketName)
|
||||
.from(bucket.value)
|
||||
.download(storagePath);
|
||||
return bytes;
|
||||
} catch (e) {
|
||||
@@ -31,6 +41,8 @@ class AttachmentsRepository {
|
||||
return 'ticket_id';
|
||||
case AttachmentParentType.customer:
|
||||
return 'customer_id';
|
||||
case AttachmentParentType.shippingDocument:
|
||||
return 'shipping_document_id';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,41 +67,70 @@ class AttachmentsRepository {
|
||||
Future<void> uploadAndRegisterFile({
|
||||
required String parentId,
|
||||
required AttachmentParentType parentType,
|
||||
required PlatformFile pickedFile,
|
||||
required String companyId,
|
||||
required Bucket bucket,
|
||||
PlatformFile? pickedFile, // Ora è opzionale
|
||||
Uint8List? rawBytes, // Alternativa: bytes grezzi
|
||||
String? rawFileName, // Alternativa: nome del file
|
||||
}) async {
|
||||
// 🛡️ L'ASSERT NINJA: O c'è il pickedFile, o ci sono i byte e il nome.
|
||||
// L'assert funziona solo in debug, ma è perfetto per beccare subito errori di chiamata!
|
||||
assert(
|
||||
pickedFile != null || (rawBytes != null && rawFileName != null),
|
||||
'Devi passare o un PlatformFile, oppure rawBytes e rawFileName!',
|
||||
);
|
||||
|
||||
try {
|
||||
if (pickedFile.bytes == null) {
|
||||
throw Exception(
|
||||
"I bytes del file sono vuoti! Ricarica la pagina senza cache.",
|
||||
);
|
||||
// 1. Normalizziamo i dati in base a cosa ci è stato passato
|
||||
final Uint8List finalBytes;
|
||||
final String finalFileName;
|
||||
final int finalFileSize;
|
||||
|
||||
if (pickedFile != null) {
|
||||
if (pickedFile.bytes == null) {
|
||||
throw Exception(
|
||||
"I bytes del file sono vuoti! Ricarica la pagina senza cache.",
|
||||
);
|
||||
}
|
||||
finalBytes = pickedFile.bytes!;
|
||||
finalFileName = pickedFile.name;
|
||||
finalFileSize = pickedFile.size;
|
||||
} else {
|
||||
// Se pickedFile è null, grazie all'assert sappiamo che questi non lo sono
|
||||
finalBytes = rawBytes!;
|
||||
finalFileName = rawFileName!;
|
||||
finalFileSize = finalBytes.length; // Calcoliamo la size dai byte reali
|
||||
}
|
||||
|
||||
final extension = pickedFile.extension ?? pickedFile.name.split('.').last;
|
||||
final cleanName = pickedFile.name
|
||||
// 2. Estraiamo l'estensione e puliamo il nome
|
||||
final extension = finalFileName.contains('.')
|
||||
? finalFileName.split('.').last
|
||||
: ''; // Fallback se il file non ha estensione
|
||||
|
||||
final cleanName = finalFileName
|
||||
.replaceAll(RegExp(r'[^\w\s\.-]'), '')
|
||||
.replaceAll(' ', '_');
|
||||
|
||||
// Creiamo un path ordinato: idAzienda/tipoEntita/idEntita/timestamp_nomefile
|
||||
// 3. Creiamo un path ordinato: idAzienda/tipoEntita/idEntita/timestamp_nomefile
|
||||
final timestamp = DateTime.now().millisecondsSinceEpoch;
|
||||
final storagePath =
|
||||
'$companyId/${parentType.name}/$parentId/${timestamp}_$cleanName';
|
||||
|
||||
// 1. Upload su Supabase Storage
|
||||
// 4. Upload su Supabase Storage
|
||||
await _supabase.storage
|
||||
.from(_bucketName)
|
||||
.from(bucket.value)
|
||||
.uploadBinary(
|
||||
storagePath,
|
||||
pickedFile.bytes!,
|
||||
finalBytes,
|
||||
fileOptions: FileOptions(contentType: _guessContentType(extension)),
|
||||
);
|
||||
|
||||
// 2. Creiamo la mappa per il DB dinamicamente
|
||||
// 5. Creiamo la mappa per il DB dinamicamente
|
||||
final Map<String, dynamic> insertData = {
|
||||
'company_id': companyId,
|
||||
'name': pickedFile.name.replaceAll('.$extension', ''),
|
||||
'name': finalFileName.replaceAll('.$extension', ''),
|
||||
'extension': extension,
|
||||
'file_size': pickedFile.size,
|
||||
'file_size': finalFileSize,
|
||||
'storage_path': storagePath,
|
||||
};
|
||||
|
||||
@@ -97,7 +138,7 @@ class AttachmentsRepository {
|
||||
final columnName = _getColumnNameForParent(parentType);
|
||||
insertData[columnName] = parentId;
|
||||
|
||||
// 3. Salviamo su Postgres
|
||||
// 6. Salviamo su Postgres
|
||||
await _supabase.from(_tableName).insert(insertData);
|
||||
} catch (e) {
|
||||
throw Exception("Errore caricamento: $e");
|
||||
@@ -108,6 +149,7 @@ class AttachmentsRepository {
|
||||
Future<void> deleteFiles({
|
||||
required List<AttachmentModel> files,
|
||||
required AttachmentParentType currentContextType,
|
||||
required Bucket bucket,
|
||||
}) async {
|
||||
if (files.isEmpty) return;
|
||||
|
||||
@@ -120,6 +162,7 @@ class AttachmentsRepository {
|
||||
AttachmentParentType.operation: file.operationId,
|
||||
AttachmentParentType.ticket: file.ticketId,
|
||||
AttachmentParentType.customer: file.customerId,
|
||||
AttachmentParentType.shippingDocument: file.shippingDocumentId,
|
||||
};
|
||||
|
||||
// 2. Simuliamo la rimozione del collegamento per il contesto attuale
|
||||
@@ -142,7 +185,7 @@ class AttachmentsRepository {
|
||||
await _supabase.from(_tableName).delete().eq('id', file.id!);
|
||||
|
||||
if (file.storagePath != null) {
|
||||
await _supabase.storage.from(_bucketName).remove([
|
||||
await _supabase.storage.from(bucket.value).remove([
|
||||
file.storagePath!,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ class AttachmentModel extends Equatable {
|
||||
final String? customerId;
|
||||
final String? operationId;
|
||||
final String? ticketId;
|
||||
final String? shippingDocumentId;
|
||||
final String name;
|
||||
final String extension;
|
||||
final String? storagePath;
|
||||
@@ -21,6 +22,7 @@ class AttachmentModel extends Equatable {
|
||||
this.customerId,
|
||||
this.operationId,
|
||||
this.ticketId,
|
||||
this.shippingDocumentId,
|
||||
required this.name,
|
||||
required this.extension,
|
||||
this.storagePath,
|
||||
@@ -36,6 +38,7 @@ class AttachmentModel extends Equatable {
|
||||
customerId,
|
||||
operationId,
|
||||
ticketId,
|
||||
shippingDocumentId,
|
||||
name,
|
||||
extension,
|
||||
storagePath,
|
||||
@@ -63,6 +66,7 @@ class AttachmentModel extends Equatable {
|
||||
String? customerId,
|
||||
String? operationId,
|
||||
String? ticketId,
|
||||
String? shippingDocumentId,
|
||||
String? name,
|
||||
String? extension,
|
||||
String? storagePath,
|
||||
@@ -75,6 +79,7 @@ class AttachmentModel extends Equatable {
|
||||
customerId: customerId ?? this.customerId,
|
||||
operationId: operationId ?? this.operationId,
|
||||
ticketId: ticketId ?? this.ticketId,
|
||||
shippingDocumentId: shippingDocumentId ?? this.shippingDocumentId,
|
||||
name: name ?? this.name,
|
||||
extension: extension ?? this.extension,
|
||||
storagePath: storagePath ?? this.storagePath,
|
||||
@@ -92,6 +97,7 @@ class AttachmentModel extends Equatable {
|
||||
customerId: map['customer_id'] as String?,
|
||||
operationId: map['operation_id'] as String?,
|
||||
ticketId: map['ticket_id'] as String?,
|
||||
shippingDocumentId: map['shipping_document_id'] as String?,
|
||||
name: map['name'] as String,
|
||||
extension: map['extension'] as String,
|
||||
storagePath: map['storage_path'] as String?,
|
||||
@@ -111,6 +117,7 @@ class AttachmentModel extends Equatable {
|
||||
'customer_id': customerId,
|
||||
'operation_id': operationId,
|
||||
'ticket_id': ticketId,
|
||||
'shipping_document_id': shippingDocumentId,
|
||||
'file_size': fileSize,
|
||||
'company_id': companyId,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user