179 lines
5.7 KiB
Dart
179 lines
5.7 KiB
Dart
import 'dart:typed_data';
|
|
|
|
import 'package:equatable/equatable.dart';
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
import 'package:flux/core/blocs/session/session_cubit.dart';
|
|
import 'package:flux/features/tickets/data/tickets_shipment_repository.dart';
|
|
import 'package:flux/features/tickets/models/shipment_document_model.dart';
|
|
import 'package:flux/features/master_data/providers/models/provider_location_model.dart';
|
|
import 'package:flux/features/master_data/providers/models/provider_model.dart';
|
|
import 'package:flux/features/settings/document_sequence/data/document_sequence_repository.dart';
|
|
import 'package:flux/features/settings/document_sequence/models/document_sequence_model.dart';
|
|
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';
|
|
|
|
class TicketShippingCubit extends Cubit<TicketShippingState> {
|
|
final TicketsShipmentRepository _repository =
|
|
GetIt.I<TicketsShipmentRepository>();
|
|
final DocumentSequenceRepository _sequenceRepository =
|
|
GetIt.I<DocumentSequenceRepository>();
|
|
TicketShippingCubit({required List<TicketModel> tickets})
|
|
: super(
|
|
TicketShippingState(
|
|
// Inizializziamo il modello direttamente nello stato!
|
|
document: ShipmentDocumentModel(
|
|
companyId: GetIt.I.get<SessionCubit>().state.company!.id!,
|
|
ticketIds: tickets.map((t) => t.id!).toList(),
|
|
providerId: '', // Sarà riempito alla selezione
|
|
destinationLocationId: '', // Sarà riempito alla selezione
|
|
docNumber: '',
|
|
docDate: DateTime.now(),
|
|
),
|
|
tickets: tickets,
|
|
),
|
|
);
|
|
|
|
Future<void> loadRepairCenters() async {
|
|
emit(state.copyWith(status: TicketShippingStatus.loading));
|
|
try {
|
|
final repairCenters = await _repository.fetchRepairCenters();
|
|
emit(
|
|
state.copyWith(
|
|
status: TicketShippingStatus.initial,
|
|
availableProviders: repairCenters,
|
|
),
|
|
);
|
|
} catch (e) {
|
|
emit(
|
|
state.copyWith(
|
|
status: TicketShippingStatus.failure,
|
|
errorMessage: e.toString(),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
void selectProvider(String providerId) {
|
|
final ProviderModel provider = state.availableProviders.firstWhere(
|
|
(p) => p.id == providerId,
|
|
);
|
|
final locations = provider.locations ?? [];
|
|
|
|
String destinationId = '';
|
|
if (locations.length == 1) {
|
|
destinationId = locations.first.id ?? '';
|
|
} else if (locations.any((l) => l.isMain)) {
|
|
destinationId = locations.firstWhere((l) => l.isMain).id ?? '';
|
|
}
|
|
|
|
emit(
|
|
state.copyWith(
|
|
availableLocations: locations,
|
|
document: state.document.copyWith(
|
|
providerId: providerId,
|
|
destinationLocationId: destinationId,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
void selectLocation(String locationId) {
|
|
emit(
|
|
state.copyWith(
|
|
document: state.document.copyWith(destinationLocationId: locationId),
|
|
),
|
|
);
|
|
}
|
|
|
|
Future<void> toggleAutoNumber(bool value) async {
|
|
// Aggiorniamo subito l'UI per mostrare che lo switch si è acceso
|
|
emit(state.copyWith(isAutoNumber: value));
|
|
}
|
|
|
|
// Metodo unico e pulito per aggiornare i campi testuali/numerici del documento
|
|
void updateDocument({
|
|
String? docNumber,
|
|
DateTime? docDate,
|
|
int? packageCount,
|
|
double? weight,
|
|
String? shippingReason,
|
|
String? notes,
|
|
}) {
|
|
emit(
|
|
state.copyWith(
|
|
document: state.document.copyWith(
|
|
docNumber: docNumber,
|
|
docDate: docDate,
|
|
packageCount: packageCount,
|
|
weight: weight,
|
|
shippingReason: shippingReason,
|
|
notes: notes,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Future<void> confirmShipment({required TicketStatus newTicketStatus}) async {
|
|
if (state.document.providerId.isEmpty ||
|
|
state.document.destinationLocationId.isEmpty) {
|
|
emit(
|
|
state.copyWith(
|
|
status: TicketShippingStatus.failure,
|
|
errorMessage: 'Seleziona laboratorio e sede.',
|
|
),
|
|
);
|
|
return;
|
|
}
|
|
if (!state.isAutoNumber && state.document.docNumber.trim().isEmpty) {
|
|
emit(
|
|
state.copyWith(
|
|
status: TicketShippingStatus.failure,
|
|
errorMessage: 'Inserisci il numero DDT.',
|
|
),
|
|
);
|
|
return;
|
|
}
|
|
|
|
emit(state.copyWith(status: TicketShippingStatus.loading));
|
|
if (state.isAutoNumber) {
|
|
try {
|
|
final nextNumber = await _sequenceRepository.getNextDocumentNumber(
|
|
DocumentType.shipment.name,
|
|
);
|
|
updateDocument(docNumber: nextNumber);
|
|
// 3. GENERIAMO I BYTES DEL PDF
|
|
final provider = state.availableProviders.firstWhere(
|
|
(p) => p.id == state.document.providerId,
|
|
);
|
|
final location = state.availableLocations.firstWhere(
|
|
(l) => l.id == state.document.destinationLocationId,
|
|
);
|
|
final pdfBytes = await TicketShippingPdfService.generateDdt(
|
|
company: GetIt.I.get<SessionCubit>().state.company!,
|
|
provider: provider,
|
|
location: location,
|
|
document: state.document,
|
|
tickets: state.tickets,
|
|
);
|
|
await _repository.createShipmentWithPdf(
|
|
document: state.document,
|
|
pdfBytes: pdfBytes,
|
|
newTicketStatus: newTicketStatus.value,
|
|
);
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|