k
This commit is contained in:
@@ -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/models/ticket_model.dart';
|
||||||
import 'package:flux/features/tickets/utils/ticket_shipping_pdf_service.dart';
|
import 'package:flux/features/tickets/utils/ticket_shipping_pdf_service.dart';
|
||||||
import 'package:get_it/get_it.dart';
|
import 'package:get_it/get_it.dart';
|
||||||
|
import 'package:printing/printing.dart';
|
||||||
|
|
||||||
part 'ticket_shipping_state.dart';
|
part 'ticket_shipping_state.dart';
|
||||||
|
|
||||||
@@ -163,12 +164,11 @@ class TicketShippingCubit extends Cubit<TicketShippingState> {
|
|||||||
pdfBytes: pdfBytes,
|
pdfBytes: pdfBytes,
|
||||||
newTicketStatus: newTicketStatus.value,
|
newTicketStatus: newTicketStatus.value,
|
||||||
);
|
);
|
||||||
emit(
|
await Printing.layoutPdf(
|
||||||
state.copyWith(
|
onLayout: (format) async => pdfBytes,
|
||||||
status: TicketShippingStatus.success,
|
name: 'DDT_${state.document.docNumber}.pdf',
|
||||||
pdfBytes: pdfBytes,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
emit(state.copyWith(status: TicketShippingStatus.success));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(state.copyWith(isAutoNumber: false, errorMessage: e.toString()));
|
emit(state.copyWith(isAutoNumber: false, errorMessage: e.toString()));
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ class TicketShippingState extends Equatable {
|
|||||||
final TicketShippingStatus status;
|
final TicketShippingStatus status;
|
||||||
final ShipmentDocumentModel document;
|
final ShipmentDocumentModel document;
|
||||||
final List<TicketModel> tickets;
|
final List<TicketModel> tickets;
|
||||||
final Uint8List? pdfBytes; // Per tenere il PDF in memoria dopo la generazione
|
|
||||||
|
|
||||||
// Dati di supporto per la UI
|
// Dati di supporto per la UI
|
||||||
final List<ProviderModel> availableProviders;
|
final List<ProviderModel> availableProviders;
|
||||||
@@ -22,7 +21,6 @@ class TicketShippingState extends Equatable {
|
|||||||
this.availableLocations = const [],
|
this.availableLocations = const [],
|
||||||
this.isAutoNumber = true,
|
this.isAutoNumber = true,
|
||||||
this.errorMessage,
|
this.errorMessage,
|
||||||
this.pdfBytes,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
TicketShippingState copyWith({
|
TicketShippingState copyWith({
|
||||||
@@ -32,7 +30,6 @@ class TicketShippingState extends Equatable {
|
|||||||
List<ProviderLocationModel>? availableLocations,
|
List<ProviderLocationModel>? availableLocations,
|
||||||
bool? isAutoNumber,
|
bool? isAutoNumber,
|
||||||
String? errorMessage,
|
String? errorMessage,
|
||||||
Uint8List? pdfBytes,
|
|
||||||
}) {
|
}) {
|
||||||
return TicketShippingState(
|
return TicketShippingState(
|
||||||
status: status ?? this.status,
|
status: status ?? this.status,
|
||||||
@@ -42,7 +39,6 @@ class TicketShippingState extends Equatable {
|
|||||||
availableLocations: availableLocations ?? this.availableLocations,
|
availableLocations: availableLocations ?? this.availableLocations,
|
||||||
isAutoNumber: isAutoNumber ?? this.isAutoNumber,
|
isAutoNumber: isAutoNumber ?? this.isAutoNumber,
|
||||||
errorMessage: errorMessage ?? this.errorMessage,
|
errorMessage: errorMessage ?? this.errorMessage,
|
||||||
pdfBytes: pdfBytes ?? this.pdfBytes,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,6 +51,5 @@ class TicketShippingState extends Equatable {
|
|||||||
availableLocations,
|
availableLocations,
|
||||||
isAutoNumber,
|
isAutoNumber,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
pdfBytes,
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ class TicketRepository {
|
|||||||
.select('''
|
.select('''
|
||||||
*,
|
*,
|
||||||
customer (*),
|
customer (*),
|
||||||
|
shipment_document (*),
|
||||||
created_by:staff_member!ticket_staff_id_fkey (*),
|
created_by:staff_member!ticket_staff_id_fkey (*),
|
||||||
assigned_to:staff_member!ticket_assigned_to_id_fkey (*),
|
assigned_to:staff_member!ticket_assigned_to_id_fkey (*),
|
||||||
target_model:model!ticket_model_id_1_fkey (*),
|
target_model:model!ticket_model_id_1_fkey (*),
|
||||||
@@ -88,6 +89,7 @@ class TicketRepository {
|
|||||||
.select('''
|
.select('''
|
||||||
*,
|
*,
|
||||||
customer (*),
|
customer (*),
|
||||||
|
shipment_document (*),
|
||||||
created_by:staff_member!ticket_staff_id_fkey (*),
|
created_by:staff_member!ticket_staff_id_fkey (*),
|
||||||
assigned_to:staff_member!ticket_assigned_to_id_fkey (*),
|
assigned_to:staff_member!ticket_assigned_to_id_fkey (*),
|
||||||
target_model:model!ticket_model_id_1_fkey (*),
|
target_model:model!ticket_model_id_1_fkey (*),
|
||||||
@@ -186,6 +188,7 @@ class TicketRepository {
|
|||||||
source_model:model!ticket_model_id_2_fkey (*),
|
source_model:model!ticket_model_id_2_fkey (*),
|
||||||
created_by:staff_member!ticket_staff_id_fkey (*),
|
created_by:staff_member!ticket_staff_id_fkey (*),
|
||||||
assigned_to:staff_member!ticket_assigned_to_id_fkey (*),
|
assigned_to:staff_member!ticket_assigned_to_id_fkey (*),
|
||||||
|
shipment_document (*),
|
||||||
''')
|
''')
|
||||||
.eq('id', ticketId)
|
.eq('id', ticketId)
|
||||||
.single();
|
.single();
|
||||||
|
|||||||
@@ -64,12 +64,19 @@ class TicketsShipmentRepository {
|
|||||||
documentData['storage_path'] = storagePath;
|
documentData['storage_path'] = storagePath;
|
||||||
|
|
||||||
// 4. Inseriamo il Documento di Trasporto nel DB
|
// 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
|
// 5. Aggiorniamo lo stato di TUTTI i ticket inclusi nel DDT
|
||||||
await _supabase
|
await _supabase
|
||||||
.from('ticket')
|
.from('ticket')
|
||||||
.update({'ticket_status': newTicketStatus})
|
.update({
|
||||||
|
'ticket_status': newTicketStatus,
|
||||||
|
'shipment_document_id': documentid,
|
||||||
|
})
|
||||||
.inFilter('id', document.ticketIds);
|
.inFilter('id', document.ticketIds);
|
||||||
|
|
||||||
// Restituiamo lo storagePath per usarlo subito nell'interfaccia se serve
|
// Restituiamo lo storagePath per usarlo subito nell'interfaccia se serve
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:flux/core/utils/extensions.dart';
|
import 'package:flux/core/utils/extensions.dart';
|
||||||
import 'package:flux/features/customers/models/customer_model.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 per il tipo di ticket
|
||||||
enum TicketType {
|
enum TicketType {
|
||||||
@@ -111,6 +112,7 @@ class TicketModel extends Equatable {
|
|||||||
final DateTime? estimatedDeliveryAt;
|
final DateTime? estimatedDeliveryAt;
|
||||||
final TicketResult? ticketResult;
|
final TicketResult? ticketResult;
|
||||||
final String? resolutionNotes;
|
final String? resolutionNotes;
|
||||||
|
final String? shippingDocumentId;
|
||||||
final CustomerModel? customer;
|
final CustomerModel? customer;
|
||||||
final String? targetModelName;
|
final String? targetModelName;
|
||||||
final String? sourceModelName;
|
final String? sourceModelName;
|
||||||
@@ -119,6 +121,8 @@ class TicketModel extends Equatable {
|
|||||||
final String? assignedToId;
|
final String? assignedToId;
|
||||||
final String? assignedToName;
|
final String? assignedToName;
|
||||||
final String? includedAccessories;
|
final String? includedAccessories;
|
||||||
|
final ShipmentDocumentModel?
|
||||||
|
shippingDocument; // Per tenere in memoria i dati del DDT associato al ticket
|
||||||
|
|
||||||
const TicketModel({
|
const TicketModel({
|
||||||
this.id,
|
this.id,
|
||||||
@@ -148,6 +152,7 @@ class TicketModel extends Equatable {
|
|||||||
this.estimatedDeliveryAt,
|
this.estimatedDeliveryAt,
|
||||||
this.ticketResult,
|
this.ticketResult,
|
||||||
this.resolutionNotes,
|
this.resolutionNotes,
|
||||||
|
this.shippingDocumentId,
|
||||||
this.customer,
|
this.customer,
|
||||||
this.targetModelName,
|
this.targetModelName,
|
||||||
this.sourceModelName,
|
this.sourceModelName,
|
||||||
@@ -156,6 +161,7 @@ class TicketModel extends Equatable {
|
|||||||
this.assignedToId,
|
this.assignedToId,
|
||||||
this.assignedToName,
|
this.assignedToName,
|
||||||
this.includedAccessories,
|
this.includedAccessories,
|
||||||
|
this.shippingDocument,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Factory per creare un ticket vuoto (utile per i form di creazione)
|
/// Factory per creare un ticket vuoto (utile per i form di creazione)
|
||||||
@@ -200,6 +206,7 @@ class TicketModel extends Equatable {
|
|||||||
DateTime? estimatedDeliveryAt,
|
DateTime? estimatedDeliveryAt,
|
||||||
TicketResult? ticketResult,
|
TicketResult? ticketResult,
|
||||||
String? resolutionNotes,
|
String? resolutionNotes,
|
||||||
|
String? shippingDocumentId,
|
||||||
CustomerModel? customer,
|
CustomerModel? customer,
|
||||||
String? targetModelName,
|
String? targetModelName,
|
||||||
String? sourceModelName,
|
String? sourceModelName,
|
||||||
@@ -208,6 +215,7 @@ class TicketModel extends Equatable {
|
|||||||
String? assignedToId,
|
String? assignedToId,
|
||||||
String? assignedToName,
|
String? assignedToName,
|
||||||
String? includedAccessories,
|
String? includedAccessories,
|
||||||
|
ShipmentDocumentModel? shippingDocument,
|
||||||
}) {
|
}) {
|
||||||
return TicketModel(
|
return TicketModel(
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
@@ -238,6 +246,7 @@ class TicketModel extends Equatable {
|
|||||||
estimatedDeliveryAt: estimatedDeliveryAt ?? this.estimatedDeliveryAt,
|
estimatedDeliveryAt: estimatedDeliveryAt ?? this.estimatedDeliveryAt,
|
||||||
ticketResult: ticketResult ?? this.ticketResult,
|
ticketResult: ticketResult ?? this.ticketResult,
|
||||||
resolutionNotes: resolutionNotes ?? this.resolutionNotes,
|
resolutionNotes: resolutionNotes ?? this.resolutionNotes,
|
||||||
|
shippingDocumentId: shippingDocumentId ?? this.shippingDocumentId,
|
||||||
customer: customer ?? this.customer,
|
customer: customer ?? this.customer,
|
||||||
targetModelName: targetModelName ?? this.targetModelName,
|
targetModelName: targetModelName ?? this.targetModelName,
|
||||||
sourceModelName: sourceModelName ?? this.sourceModelName,
|
sourceModelName: sourceModelName ?? this.sourceModelName,
|
||||||
@@ -246,6 +255,7 @@ class TicketModel extends Equatable {
|
|||||||
assignedToId: assignedToId ?? this.assignedToId,
|
assignedToId: assignedToId ?? this.assignedToId,
|
||||||
assignedToName: assignedToName ?? this.assignedToName,
|
assignedToName: assignedToName ?? this.assignedToName,
|
||||||
includedAccessories: includedAccessories ?? this.includedAccessories,
|
includedAccessories: includedAccessories ?? this.includedAccessories,
|
||||||
|
shippingDocument: shippingDocument ?? this.shippingDocument,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,6 +298,7 @@ class TicketModel extends Equatable {
|
|||||||
: null,
|
: null,
|
||||||
ticketResult: TicketResult.fromString(map['ticket_result'] as String?),
|
ticketResult: TicketResult.fromString(map['ticket_result'] as String?),
|
||||||
resolutionNotes: map['resolution_notes'] as String?,
|
resolutionNotes: map['resolution_notes'] as String?,
|
||||||
|
shippingDocumentId: map['shipping_document_id'] as String?,
|
||||||
customer: map['customer'] != null
|
customer: map['customer'] != null
|
||||||
? CustomerModel.fromMap(map['customer'] as Map<String, dynamic>)
|
? CustomerModel.fromMap(map['customer'] as Map<String, dynamic>)
|
||||||
: null,
|
: null,
|
||||||
@@ -300,6 +311,11 @@ class TicketModel extends Equatable {
|
|||||||
assignedToId: map['assigned_to_id'] as String?,
|
assignedToId: map['assigned_to_id'] as String?,
|
||||||
assignedToName: (map['assigned_to']?['name'] as String?)?.myFormat(),
|
assignedToName: (map['assigned_to']?['name'] as String?)?.myFormat(),
|
||||||
includedAccessories: map['included_accessories'] as String?,
|
includedAccessories: map['included_accessories'] as String?,
|
||||||
|
shippingDocument: map['shipping_document'] != null
|
||||||
|
? ShipmentDocumentModel.fromMap(
|
||||||
|
map['shipping_document'] as Map<String, dynamic>,
|
||||||
|
)
|
||||||
|
: null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,6 +353,7 @@ class TicketModel extends Equatable {
|
|||||||
if (ticketResult != null) 'ticket_result': ticketResult!.value,
|
if (ticketResult != null) 'ticket_result': ticketResult!.value,
|
||||||
'resolution_notes': resolutionNotes,
|
'resolution_notes': resolutionNotes,
|
||||||
'included_accessories': includedAccessories,
|
'included_accessories': includedAccessories,
|
||||||
|
'shipping_document_id': shippingDocumentId,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,5 +393,7 @@ class TicketModel extends Equatable {
|
|||||||
createdByName,
|
createdByName,
|
||||||
assignedToId,
|
assignedToId,
|
||||||
assignedToName,
|
assignedToName,
|
||||||
|
shippingDocumentId,
|
||||||
|
shippingDocument,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,8 +103,7 @@ class TicketList extends StatelessWidget {
|
|||||||
FilledButton.icon(
|
FilledButton.icon(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
// 1. Apriamo la modale e ASPETTIAMO il risultato (tipizzandolo come Record)
|
// 1. Apriamo la modale e ASPETTIAMO il risultato (tipizzandolo come Record)
|
||||||
final Uint8List? result =
|
final bool? result = await showModalBottomSheet<bool?>(
|
||||||
await showModalBottomSheet<Uint8List>(
|
|
||||||
context: context,
|
context: context,
|
||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
@@ -124,11 +123,6 @@ class TicketList extends StatelessWidget {
|
|||||||
// 2. Se l'utente ha chiuso trascinando giù, result è null.
|
// 2. Se l'utente ha chiuso trascinando giù, result è null.
|
||||||
// Se ha salvato con successo, result contiene il nostro Record!
|
// Se ha salvato con successo, result contiene il nostro Record!
|
||||||
if (result != null && context.mounted) {
|
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
|
// 5. Pulizia finale: Deselezioniamo tutti i ticket e ricarichiamo la lista
|
||||||
context.read<TicketListCubit>().clearSelection();
|
context.read<TicketListCubit>().clearSelection();
|
||||||
// (Se necessario, chiama il metodo per ricaricare la lista dei ticket dal DB)
|
// (Se necessario, chiama il metodo per ricaricare la lista dei ticket dal DB)
|
||||||
|
|||||||
@@ -110,6 +110,24 @@ class TicketListCard extends StatelessWidget {
|
|||||||
overflow: TextOverflow.ellipsis,
|
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
|
// IL BADGE DELLO STATO
|
||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
@@ -123,6 +141,7 @@ class TicketListCard extends StatelessWidget {
|
|||||||
color: statusColor.withValues(alpha: 0.5),
|
color: statusColor.withValues(alpha: 0.5),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@@ -39,21 +39,7 @@ class _TicketShippingModalState extends State<TicketShippingModal> {
|
|||||||
child: BlocConsumer<TicketShippingCubit, TicketShippingState>(
|
child: BlocConsumer<TicketShippingCubit, TicketShippingState>(
|
||||||
listener: (context, state) {
|
listener: (context, state) {
|
||||||
if (state.status == TicketShippingStatus.success) {
|
if (state.status == TicketShippingStatus.success) {
|
||||||
final provider = state.availableProviders.firstWhere(
|
Navigator.pop(context, true);
|
||||||
(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);
|
|
||||||
}
|
}
|
||||||
if (state.status == TicketShippingStatus.failure &&
|
if (state.status == TicketShippingStatus.failure &&
|
||||||
state.errorMessage != null) {
|
state.errorMessage != null) {
|
||||||
|
|||||||
Reference in New Issue
Block a user