diff --git a/lib/features/tickets/blocs/ticket_shipping_cubit.dart b/lib/features/tickets/blocs/ticket_shipping_cubit.dart index 7a06b83..cba50f3 100644 --- a/lib/features/tickets/blocs/ticket_shipping_cubit.dart +++ b/lib/features/tickets/blocs/ticket_shipping_cubit.dart @@ -12,6 +12,7 @@ import 'package:flux/features/settings/document_sequence/models/document_sequenc import 'package:flux/features/tickets/models/ticket_model.dart'; import 'package:flux/features/tickets/utils/ticket_shipping_pdf_service.dart'; import 'package:get_it/get_it.dart'; +import 'package:printing/printing.dart'; part 'ticket_shipping_state.dart'; @@ -163,12 +164,11 @@ class TicketShippingCubit extends Cubit { pdfBytes: pdfBytes, newTicketStatus: newTicketStatus.value, ); - emit( - state.copyWith( - status: TicketShippingStatus.success, - pdfBytes: pdfBytes, - ), + await Printing.layoutPdf( + onLayout: (format) async => pdfBytes, + name: 'DDT_${state.document.docNumber}.pdf', ); + emit(state.copyWith(status: TicketShippingStatus.success)); } catch (e) { emit(state.copyWith(isAutoNumber: false, errorMessage: e.toString())); return; diff --git a/lib/features/tickets/blocs/ticket_shipping_state.dart b/lib/features/tickets/blocs/ticket_shipping_state.dart index f208131..513b621 100644 --- a/lib/features/tickets/blocs/ticket_shipping_state.dart +++ b/lib/features/tickets/blocs/ticket_shipping_state.dart @@ -6,7 +6,6 @@ class TicketShippingState extends Equatable { final TicketShippingStatus status; final ShipmentDocumentModel document; final List tickets; - final Uint8List? pdfBytes; // Per tenere il PDF in memoria dopo la generazione // Dati di supporto per la UI final List availableProviders; @@ -22,7 +21,6 @@ class TicketShippingState extends Equatable { this.availableLocations = const [], this.isAutoNumber = true, this.errorMessage, - this.pdfBytes, }); TicketShippingState copyWith({ @@ -32,7 +30,6 @@ class TicketShippingState extends Equatable { List? availableLocations, bool? isAutoNumber, String? errorMessage, - Uint8List? pdfBytes, }) { return TicketShippingState( status: status ?? this.status, @@ -42,7 +39,6 @@ class TicketShippingState extends Equatable { availableLocations: availableLocations ?? this.availableLocations, isAutoNumber: isAutoNumber ?? this.isAutoNumber, errorMessage: errorMessage ?? this.errorMessage, - pdfBytes: pdfBytes ?? this.pdfBytes, ); } @@ -55,6 +51,5 @@ class TicketShippingState extends Equatable { availableLocations, isAutoNumber, errorMessage, - pdfBytes, ]; } diff --git a/lib/features/tickets/data/ticket_repository.dart b/lib/features/tickets/data/ticket_repository.dart index b015db1..7081181 100644 --- a/lib/features/tickets/data/ticket_repository.dart +++ b/lib/features/tickets/data/ticket_repository.dart @@ -31,6 +31,7 @@ class TicketRepository { .select(''' *, customer (*), + shipment_document (*), created_by:staff_member!ticket_staff_id_fkey (*), assigned_to:staff_member!ticket_assigned_to_id_fkey (*), target_model:model!ticket_model_id_1_fkey (*), @@ -88,6 +89,7 @@ class TicketRepository { .select(''' *, customer (*), + shipment_document (*), created_by:staff_member!ticket_staff_id_fkey (*), assigned_to:staff_member!ticket_assigned_to_id_fkey (*), target_model:model!ticket_model_id_1_fkey (*), @@ -186,6 +188,7 @@ class TicketRepository { source_model:model!ticket_model_id_2_fkey (*), created_by:staff_member!ticket_staff_id_fkey (*), assigned_to:staff_member!ticket_assigned_to_id_fkey (*), + shipment_document (*), ''') .eq('id', ticketId) .single(); diff --git a/lib/features/tickets/data/tickets_shipment_repository.dart b/lib/features/tickets/data/tickets_shipment_repository.dart index 071779d..3d6164e 100644 --- a/lib/features/tickets/data/tickets_shipment_repository.dart +++ b/lib/features/tickets/data/tickets_shipment_repository.dart @@ -64,12 +64,19 @@ class TicketsShipmentRepository { documentData['storage_path'] = storagePath; // 4. Inseriamo il Documento di Trasporto nel DB - await _supabase.from('shipment_documents').insert(documentData); - + final savedDocument = await _supabase + .from('shipment_documents') + .insert(documentData) + .select('id') + .single(); + final documentid = savedDocument['id']; // 5. Aggiorniamo lo stato di TUTTI i ticket inclusi nel DDT await _supabase .from('ticket') - .update({'ticket_status': newTicketStatus}) + .update({ + 'ticket_status': newTicketStatus, + 'shipment_document_id': documentid, + }) .inFilter('id', document.ticketIds); // Restituiamo lo storagePath per usarlo subito nell'interfaccia se serve diff --git a/lib/features/tickets/models/ticket_model.dart b/lib/features/tickets/models/ticket_model.dart index 0b96707..19f38b4 100644 --- a/lib/features/tickets/models/ticket_model.dart +++ b/lib/features/tickets/models/ticket_model.dart @@ -1,6 +1,7 @@ import 'package:equatable/equatable.dart'; import 'package:flux/core/utils/extensions.dart'; import 'package:flux/features/customers/models/customer_model.dart'; +import 'package:flux/features/tickets/models/shipment_document_model.dart'; /// Enum per il tipo di ticket enum TicketType { @@ -111,6 +112,7 @@ class TicketModel extends Equatable { final DateTime? estimatedDeliveryAt; final TicketResult? ticketResult; final String? resolutionNotes; + final String? shippingDocumentId; final CustomerModel? customer; final String? targetModelName; final String? sourceModelName; @@ -119,6 +121,8 @@ class TicketModel extends Equatable { final String? assignedToId; final String? assignedToName; final String? includedAccessories; + final ShipmentDocumentModel? + shippingDocument; // Per tenere in memoria i dati del DDT associato al ticket const TicketModel({ this.id, @@ -148,6 +152,7 @@ class TicketModel extends Equatable { this.estimatedDeliveryAt, this.ticketResult, this.resolutionNotes, + this.shippingDocumentId, this.customer, this.targetModelName, this.sourceModelName, @@ -156,6 +161,7 @@ class TicketModel extends Equatable { this.assignedToId, this.assignedToName, this.includedAccessories, + this.shippingDocument, }); /// Factory per creare un ticket vuoto (utile per i form di creazione) @@ -200,6 +206,7 @@ class TicketModel extends Equatable { DateTime? estimatedDeliveryAt, TicketResult? ticketResult, String? resolutionNotes, + String? shippingDocumentId, CustomerModel? customer, String? targetModelName, String? sourceModelName, @@ -208,6 +215,7 @@ class TicketModel extends Equatable { String? assignedToId, String? assignedToName, String? includedAccessories, + ShipmentDocumentModel? shippingDocument, }) { return TicketModel( id: id ?? this.id, @@ -238,6 +246,7 @@ class TicketModel extends Equatable { estimatedDeliveryAt: estimatedDeliveryAt ?? this.estimatedDeliveryAt, ticketResult: ticketResult ?? this.ticketResult, resolutionNotes: resolutionNotes ?? this.resolutionNotes, + shippingDocumentId: shippingDocumentId ?? this.shippingDocumentId, customer: customer ?? this.customer, targetModelName: targetModelName ?? this.targetModelName, sourceModelName: sourceModelName ?? this.sourceModelName, @@ -246,6 +255,7 @@ class TicketModel extends Equatable { assignedToId: assignedToId ?? this.assignedToId, assignedToName: assignedToName ?? this.assignedToName, includedAccessories: includedAccessories ?? this.includedAccessories, + shippingDocument: shippingDocument ?? this.shippingDocument, ); } @@ -288,6 +298,7 @@ class TicketModel extends Equatable { : null, ticketResult: TicketResult.fromString(map['ticket_result'] as String?), resolutionNotes: map['resolution_notes'] as String?, + shippingDocumentId: map['shipping_document_id'] as String?, customer: map['customer'] != null ? CustomerModel.fromMap(map['customer'] as Map) : null, @@ -300,6 +311,11 @@ class TicketModel extends Equatable { assignedToId: map['assigned_to_id'] as String?, assignedToName: (map['assigned_to']?['name'] as String?)?.myFormat(), includedAccessories: map['included_accessories'] as String?, + shippingDocument: map['shipping_document'] != null + ? ShipmentDocumentModel.fromMap( + map['shipping_document'] as Map, + ) + : null, ); } @@ -337,6 +353,7 @@ class TicketModel extends Equatable { if (ticketResult != null) 'ticket_result': ticketResult!.value, 'resolution_notes': resolutionNotes, 'included_accessories': includedAccessories, + 'shipping_document_id': shippingDocumentId, }; } @@ -376,5 +393,7 @@ class TicketModel extends Equatable { createdByName, assignedToId, assignedToName, + shippingDocumentId, + shippingDocument, ]; } diff --git a/lib/features/tickets/ui/widgets/ticket_list.dart b/lib/features/tickets/ui/widgets/ticket_list.dart index dab7398..593c9ba 100644 --- a/lib/features/tickets/ui/widgets/ticket_list.dart +++ b/lib/features/tickets/ui/widgets/ticket_list.dart @@ -103,32 +103,26 @@ class TicketList extends StatelessWidget { FilledButton.icon( onPressed: () async { // 1. Apriamo la modale e ASPETTIAMO il risultato (tipizzandolo come Record) - final Uint8List? result = - await showModalBottomSheet( - context: context, - isScrollControlled: true, - builder: (context) { - return BlocProvider( - create: (context) => TicketShippingCubit( - tickets: state.selectedTickets.toList(), - )..loadRepairCenters(), - child: TicketShippingModal( - ticketIds: state.selectedTickets - .map((t) => t.id!) - .toList(), - ), - ); - }, + final bool? result = await showModalBottomSheet( + context: context, + isScrollControlled: true, + builder: (context) { + return BlocProvider( + create: (context) => TicketShippingCubit( + tickets: state.selectedTickets.toList(), + )..loadRepairCenters(), + child: TicketShippingModal( + ticketIds: state.selectedTickets + .map((t) => t.id!) + .toList(), + ), ); + }, + ); // 2. Se l'utente ha chiuso trascinando giù, result è null. // Se ha salvato con successo, result contiene il nostro Record! if (result != null && context.mounted) { - await Printing.layoutPdf( - onLayout: (format) async => result, - name: - 'DDT_${DateTime.now().millisecondsSinceEpoch}.pdf', - ); // 5. Pulizia finale: Deselezioniamo tutti i ticket e ricarichiamo la lista context.read().clearSelection(); // (Se necessario, chiama il metodo per ricaricare la lista dei ticket dal DB) diff --git a/lib/features/tickets/ui/widgets/ticket_list_card.dart b/lib/features/tickets/ui/widgets/ticket_list_card.dart index 20b3738..e3aeedf 100644 --- a/lib/features/tickets/ui/widgets/ticket_list_card.dart +++ b/lib/features/tickets/ui/widgets/ticket_list_card.dart @@ -110,6 +110,24 @@ class TicketListCard extends StatelessWidget { overflow: TextOverflow.ellipsis, ), ), + if (ticket.shippingDocument != null) ...[ + Row( + children: [ + const Text('DDT'), + const SizedBox(width: 4), + InkWell( + borderRadius: BorderRadius.circular(20), + onTap: () {}, + child: const Icon( + Icons.picture_as_pdf, + color: Colors.redAccent, + size: 20, + ), + ), + ], + ), + ], + // IL BADGE DELLO STATO Container( padding: const EdgeInsets.symmetric( @@ -123,6 +141,7 @@ class TicketListCard extends StatelessWidget { color: statusColor.withValues(alpha: 0.5), ), ), + child: Row( mainAxisSize: MainAxisSize.min, children: [ diff --git a/lib/features/tickets/ui/widgets/ticket_shipping_modal.dart b/lib/features/tickets/ui/widgets/ticket_shipping_modal.dart index c57d6c2..236cf90 100644 --- a/lib/features/tickets/ui/widgets/ticket_shipping_modal.dart +++ b/lib/features/tickets/ui/widgets/ticket_shipping_modal.dart @@ -39,21 +39,7 @@ class _TicketShippingModalState extends State { child: BlocConsumer( listener: (context, state) { if (state.status == TicketShippingStatus.success) { - final provider = state.availableProviders.firstWhere( - (p) => p.id == state.document.providerId, - ); - final location = state.availableLocations.firstWhere( - (l) => l.id == state.document.destinationLocationId, - ); - - // Creiamo un Dart Record elegante e lo "spariamo" fuori - final ddtData = ( - document: state.document, - provider: provider, - location: location, - ); - - Navigator.pop(context, ddtData); + Navigator.pop(context, true); } if (state.status == TicketShippingStatus.failure && state.errorMessage != null) {