fix macos pdf

This commit is contained in:
2026-05-16 14:30:23 +02:00
parent 9a5d0e33bd
commit b3f463b688
10 changed files with 49 additions and 57 deletions

View File

@@ -1,8 +1,8 @@
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flux/core/blocs/session/session_cubit.dart'; import 'package:flux/core/blocs/session/session_cubit.dart';
import 'package:flux/features/documents/data/tickets_shipment_repository.dart'; import 'package:flux/features/tickets/data/tickets_shipment_repository.dart';
import 'package:flux/features/documents/models/shipment_document_model.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_location_model.dart';
import 'package:flux/features/master_data/providers/models/provider_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/data/document_sequence_repository.dart';

View File

@@ -1,11 +1,15 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flux/core/blocs/session/session_cubit.dart'; import 'package:flux/core/blocs/session/session_cubit.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/models/ticket_model.dart';
import 'package:get_it/get_it.dart'; import 'package:get_it/get_it.dart';
import 'package:supabase_flutter/supabase_flutter.dart'; import 'package:supabase_flutter/supabase_flutter.dart';
class TicketRepository { class TicketRepository {
final SupabaseClient _supabase = GetIt.I.get<SupabaseClient>(); final SupabaseClient _supabase = GetIt.I.get<SupabaseClient>();
final DocumentSequenceRepository _documentSequenceRepository = GetIt.I
.get<DocumentSequenceRepository>();
TicketRepository(); TicketRepository();
@@ -192,29 +196,29 @@ class TicketRepository {
} }
} }
Future<String> generateTicketReference(String companyId) async { // Future<String> generateTicketReference(String companyId) async {
final response = await Supabase.instance.client.rpc( // final response = await Supabase.instance.client.rpc(
'get_next_document_number', // 'get_next_document_number',
params: {'p_company_id': companyId, 'p_doc_type': 'ticket'}, // params: {'p_company_id': companyId, 'p_doc_type': 'ticket'},
); // );
// Estraiamo i dati dal JSON // // Estraiamo i dati dal JSON
final int nextValue = response['next_value']; // final int nextValue = response['next_value'];
final String prefix = response['prefix'] ?? ''; // final String prefix = response['prefix'] ?? '';
final year = DateTime.now().year; // 2026 // final year = DateTime.now().year; // 2026
// Formattazione con zeri iniziali (es. 000125) // // Formattazione con zeri iniziali (es. 000125)
final paddedNumber = nextValue.toString().padLeft(6, '0'); // final paddedNumber = nextValue.toString().padLeft(6, '0');
// Costruiamo la stringa. Se c'è un prefisso mette "TCK-2026-000125", // // Costruiamo la stringa. Se c'è un prefisso mette "TCK-2026-000125",
// altrimenti solo "2026-000125" // // altrimenti solo "2026-000125"
if (prefix.isNotEmpty) { // if (prefix.isNotEmpty) {
return '$prefix-$year-$paddedNumber'; // return '$prefix-$year-$paddedNumber';
} else { // } else {
return '$year-$paddedNumber'; // return '$year-$paddedNumber';
} // }
} // }
/// Salva il ticket /// Salva il ticket
Future<TicketModel> insertTicket(TicketModel ticket) async { Future<TicketModel> insertTicket(TicketModel ticket) async {
@@ -223,7 +227,9 @@ class TicketRepository {
} }
try { try {
final ticketToSave = ticket.copyWith( final ticketToSave = ticket.copyWith(
referenceId: await generateTicketReference(ticket.companyId), referenceId: await _documentSequenceRepository.getNextDocumentNumber(
DocumentType.ticket.name,
),
); );
final response = await _supabase final response = await _supabase
.from(_tableName) .from(_tableName)

View File

@@ -1,15 +1,12 @@
import 'package:flux/core/blocs/session/session_cubit.dart'; import 'package:flux/features/tickets/models/shipment_document_model.dart';
import 'package:flux/features/documents/models/shipment_document_model.dart';
import 'package:flux/features/master_data/providers/models/provider_model.dart'; import 'package:flux/features/master_data/providers/models/provider_model.dart';
import 'package:flux/features/master_data/providers/models/provider_role.dart'; import 'package:flux/features/master_data/providers/models/provider_role.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/models/ticket_model.dart';
import 'package:get_it/get_it.dart'; import 'package:get_it/get_it.dart';
import 'package:supabase_flutter/supabase_flutter.dart'; import 'package:supabase_flutter/supabase_flutter.dart';
class TicketsShipmentRepository { class TicketsShipmentRepository {
final _supabase = GetIt.I.get<SupabaseClient>(); final _supabase = GetIt.I.get<SupabaseClient>();
final _companyId = GetIt.I.get<SessionCubit>().state.company!.id!;
Future<List<ProviderModel>> fetchRepairCenters() async { Future<List<ProviderModel>> fetchRepairCenters() async {
try { try {

View File

@@ -213,8 +213,12 @@ class _TicketFormScreenState extends State<TicketFormScreen> {
.generateTicketReceipt(ticket); .generateTicketReceipt(ticket);
final bytes = await doc.save(); final bytes = await doc.save();
final fileName = 'Ricevuta_${ticket.referenceId}.pdf'; final fileName = 'Ricevuta_${ticket.referenceId}.pdf';
await Printing.layoutPdf(
onLayout: (format) async => bytes,
name: fileName,
);
if (kIsWeb || Platform.isMacOS) { /* if (kIsWeb || Platform.isMacOS) {
// Forza il download/salvataggio senza passare per il print spooler // Forza il download/salvataggio senza passare per il print spooler
await Printing.sharePdf( await Printing.sharePdf(
bytes: bytes, bytes: bytes,
@@ -222,11 +226,8 @@ class _TicketFormScreenState extends State<TicketFormScreen> {
); );
} else { } else {
// Su Android/iOS continuiamo a usare la stampa diretta che funziona // Su Android/iOS continuiamo a usare la stampa diretta che funziona
await Printing.layoutPdf(
onLayout: (format) async => bytes, } */
name: fileName,
);
}
}, },
), ),
if (company.labelFormat != LabelFormat.none) if (company.labelFormat != LabelFormat.none)

View File

@@ -1,8 +1,7 @@
import 'package:flutter/foundation.dart' show kIsWeb, defaultTargetPlatform;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flux/core/blocs/session/session_cubit.dart'; import 'package:flux/core/blocs/session/session_cubit.dart';
import 'package:flux/features/documents/models/shipment_document_model.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_location_model.dart';
import 'package:flux/features/master_data/providers/models/provider_model.dart'; import 'package:flux/features/master_data/providers/models/provider_model.dart';
import 'package:flux/features/tickets/blocs/ticket_list_cubit.dart'; import 'package:flux/features/tickets/blocs/ticket_list_cubit.dart';
@@ -148,24 +147,10 @@ class TicketList extends StatelessWidget {
document: result.document, document: result.document,
tickets: state.selectedTickets.toList(), tickets: state.selectedTickets.toList(),
); );
await Printing.layoutPdf(
// 4. LANCIAMO LA STAMPA (Anteprima nativa / Browser) onLayout: (PdfPageFormat format) async => pdfBytes,
// Check sicuro: se NON siamo sul web E la piattaforma nativa è macOS name: 'ddt_${result.document.docNumber}.pdf',
if (!kIsWeb && );
defaultTargetPlatform == TargetPlatform.macOS) {
// Scialuppa di salvataggio per il Mac
await Printing.sharePdf(
bytes: pdfBytes,
filename: 'ddt_${result.document.docNumber}.pdf',
);
} else {
// Per Web, Windows, Linux, Android e iOS... diamo spettacolo!
await Printing.layoutPdf(
onLayout: (PdfPageFormat format) async =>
pdfBytes,
name: 'ddt_${result.document.docNumber}.pdf',
);
}
// 5. Pulizia finale: Deselezioniamo tutti i ticket e ricarichiamo la lista // 5. Pulizia finale: Deselezioniamo tutti i ticket e ricarichiamo la lista
ticketListCubit.clearSelection(); ticketListCubit.clearSelection();

View File

@@ -185,7 +185,7 @@ class _TicketShippingModalState extends State<TicketShippingModal> {
TicketShippingState state, TicketShippingState state,
) { ) {
return DropdownButtonFormField<String>( return DropdownButtonFormField<String>(
value: state.document.providerId.isEmpty initialValue: state.document.providerId.isEmpty
? null ? null
: state.document.providerId, : state.document.providerId,
decoration: const InputDecoration( decoration: const InputDecoration(
@@ -207,7 +207,7 @@ class _TicketShippingModalState extends State<TicketShippingModal> {
TicketShippingState state, TicketShippingState state,
) { ) {
return DropdownButtonFormField<String>( return DropdownButtonFormField<String>(
value: state.document.destinationLocationId.isEmpty initialValue: state.document.destinationLocationId.isEmpty
? null ? null
: state.document.destinationLocationId, : state.document.destinationLocationId,
decoration: const InputDecoration( decoration: const InputDecoration(
@@ -280,6 +280,7 @@ class _TicketShippingModalState extends State<TicketShippingModal> {
), ),
trailing: const Icon(Icons.calendar_month), trailing: const Icon(Icons.calendar_month),
onTap: () async { onTap: () async {
final ticketShippingCubit = context.read<TicketShippingCubit>();
final newDate = await showDatePicker( final newDate = await showDatePicker(
context: context, context: context,
initialDate: date, initialDate: date,
@@ -287,7 +288,7 @@ class _TicketShippingModalState extends State<TicketShippingModal> {
lastDate: DateTime.now().add(const Duration(days: 365)), lastDate: DateTime.now().add(const Duration(days: 365)),
); );
if (newDate != null) { if (newDate != null) {
context.read<TicketShippingCubit>().updateDocument(docDate: newDate); ticketShippingCubit.updateDocument(docDate: newDate);
} }
}, },
); );

View File

@@ -1,6 +1,6 @@
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:flux/features/company/models/company_model.dart'; import 'package:flux/features/company/models/company_model.dart';
import 'package:flux/features/documents/models/shipment_document_model.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_location_model.dart';
import 'package:flux/features/master_data/providers/models/provider_model.dart'; import 'package:flux/features/master_data/providers/models/provider_model.dart';
import 'package:flux/features/tickets/models/ticket_model.dart'; import 'package:flux/features/tickets/models/ticket_model.dart';

View File

@@ -7,7 +7,7 @@ import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flux/features/attachments/data/attachments_repository.dart'; import 'package:flux/features/attachments/data/attachments_repository.dart';
import 'package:flux/features/auth/bloc/auth_cubit.dart'; import 'package:flux/features/auth/bloc/auth_cubit.dart';
import 'package:flux/features/company/data/company_repository.dart'; import 'package:flux/features/company/data/company_repository.dart';
import 'package:flux/features/documents/data/tickets_shipment_repository.dart'; import 'package:flux/features/tickets/data/tickets_shipment_repository.dart';
import 'package:flux/features/master_data/providers/blocs/provider_list_cubit.dart'; import 'package:flux/features/master_data/providers/blocs/provider_list_cubit.dart';
import 'package:flux/features/operations/blocs/operation_list_cubit.dart'; import 'package:flux/features/operations/blocs/operation_list_cubit.dart';
import 'package:flux/features/operations/data/operations_repository.dart'; import 'package:flux/features/operations/data/operations_repository.dart';

View File

@@ -30,5 +30,7 @@
<string>NSApplication</string> <string>NSApplication</string>
<key>NSCameraUsageDescription</key> <key>NSCameraUsageDescription</key>
<string>FLUX ha bisogno della fotocamera per scansionare i QR Code e acquisire documenti.</string> <string>FLUX ha bisogno della fotocamera per scansionare i QR Code e acquisire documenti.</string>
<key>FLTEnableMergedPlatformUIThread</key>
<false/>
</dict> </dict>
</plist> </plist>