From 1115d2cb875e30ea6cdbcaea92534245b84e242c Mon Sep 17 00:00:00 2001 From: mark-cachy Date: Mon, 4 May 2026 19:32:14 +0200 Subject: [PATCH] df --- android/app/build.gradle.kts | 3 + android/app/google-services.json | 86 ++++++++++ .../gradle/wrapper/gradle-wrapper.properties | 2 +- android/settings.gradle.kts | 3 + firebase.json | 1 + .../customers/ui/customers_content.dart | 7 + lib/firebase_options.dart | 88 +++++++++++ lib/main.dart | 5 + lib/temp/migration_tools.dart | 148 ++++++++++++++++++ macos/Flutter/GeneratedPluginRegistrant.swift | 6 + pubspec.lock | 80 ++++++++++ pubspec.yaml | 3 + .../flutter/generated_plugin_registrant.cc | 9 ++ windows/flutter/generated_plugins.cmake | 3 + 14 files changed, 443 insertions(+), 1 deletion(-) create mode 100644 android/app/google-services.json create mode 100644 firebase.json create mode 100644 lib/firebase_options.dart create mode 100644 lib/temp/migration_tools.dart diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 0380795..b381628 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -1,5 +1,8 @@ plugins { id("com.android.application") + // START: FlutterFire Configuration + id("com.google.gms.google-services") + // END: FlutterFire Configuration id("kotlin-android") // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. id("dev.flutter.flutter-gradle-plugin") diff --git a/android/app/google-services.json b/android/app/google-services.json new file mode 100644 index 0000000..682aa3e --- /dev/null +++ b/android/app/google-services.json @@ -0,0 +1,86 @@ +{ + "project_info": { + "project_number": "872447580790", + "project_id": "assistenza-catelli", + "storage_bucket": "assistenza-catelli.firebasestorage.app" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:872447580790:android:193235afcc2920ce5d9d57", + "android_client_info": { + "package_name": "com.catelli.scans2" + } + }, + "oauth_client": [], + "api_key": [ + { + "current_key": "AIzaSyBSxpdLDlPnN0xjejlX_5JL19BDeSzKOr8" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [] + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:872447580790:android:9c6172d77b1d2cae5d9d57", + "android_client_info": { + "package_name": "com.catellisrl.assistenza" + } + }, + "oauth_client": [], + "api_key": [ + { + "current_key": "AIzaSyBSxpdLDlPnN0xjejlX_5JL19BDeSzKOr8" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [] + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:872447580790:android:425d21710d7682005d9d57", + "android_client_info": { + "package_name": "com.catellisrl.catelli_energy_comparator" + } + }, + "oauth_client": [], + "api_key": [ + { + "current_key": "AIzaSyBSxpdLDlPnN0xjejlX_5JL19BDeSzKOr8" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [] + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:872447580790:android:a1d8d57960451f935d9d57", + "android_client_info": { + "package_name": "com.catellisrl.flux" + } + }, + "oauth_client": [], + "api_key": [ + { + "current_key": "AIzaSyBSxpdLDlPnN0xjejlX_5JL19BDeSzKOr8" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 87b6bad..e4ef43f 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://operations.gradle.org/distributions/gradle-8.14-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts index ca7fe06..174f408 100644 --- a/android/settings.gradle.kts +++ b/android/settings.gradle.kts @@ -20,6 +20,9 @@ pluginManagement { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" id("com.android.application") version "8.11.1" apply false + // START: FlutterFire Configuration + id("com.google.gms.google-services") version("4.3.15") apply false + // END: FlutterFire Configuration id("org.jetbrains.kotlin.android") version "2.2.20" apply false } diff --git a/firebase.json b/firebase.json new file mode 100644 index 0000000..898684c --- /dev/null +++ b/firebase.json @@ -0,0 +1 @@ +{"flutter":{"platforms":{"android":{"default":{"projectId":"assistenza-catelli","appId":"1:872447580790:android:a1d8d57960451f935d9d57","fileOutput":"android/app/google-services.json"}},"dart":{"lib/firebase_options.dart":{"projectId":"assistenza-catelli","configurations":{"android":"1:872447580790:android:a1d8d57960451f935d9d57","ios":"1:872447580790:ios:a87d56c718aa61e05d9d57","macos":"1:872447580790:ios:a87d56c718aa61e05d9d57","web":"1:872447580790:web:10745e7f9afb447d5d9d57","windows":"1:872447580790:web:3b1623eda6abdac75d9d57"}}}}}} \ No newline at end of file diff --git a/lib/features/customers/ui/customers_content.dart b/lib/features/customers/ui/customers_content.dart index c52a9a9..fb2a858 100644 --- a/lib/features/customers/ui/customers_content.dart +++ b/lib/features/customers/ui/customers_content.dart @@ -5,6 +5,7 @@ import 'package:flux/core/theme/theme.dart'; import 'package:flux/features/customers/blocs/customers_cubit.dart'; import 'package:flux/features/customers/models/customer_model.dart'; import 'package:flux/features/customers/ui/customer_form.dart'; +import 'package:flux/temp/migration_tools.dart'; import 'package:go_router/go_router.dart'; class CustomersContent extends StatefulWidget { @@ -84,6 +85,12 @@ class _CustomersContentState extends State { ), ), + //TODO cancella quando import finito + ElevatedButton( + onPressed: () => migrateModelsToSupabase(), + child: const Text('migra clienti'), + ), + // LISTA CLIENTI Expanded( child: BlocBuilder( diff --git a/lib/firebase_options.dart b/lib/firebase_options.dart new file mode 100644 index 0000000..36fc443 --- /dev/null +++ b/lib/firebase_options.dart @@ -0,0 +1,88 @@ +// File generated by FlutterFire CLI. +// ignore_for_file: type=lint +import 'package:firebase_core/firebase_core.dart' show FirebaseOptions; +import 'package:flutter/foundation.dart' + show defaultTargetPlatform, kIsWeb, TargetPlatform; + +/// Default [FirebaseOptions] for use with your Firebase apps. +/// +/// Example: +/// ```dart +/// import 'firebase_options.dart'; +/// // ... +/// await Firebase.initializeApp( +/// options: DefaultFirebaseOptions.currentPlatform, +/// ); +/// ``` +class DefaultFirebaseOptions { + static FirebaseOptions get currentPlatform { + if (kIsWeb) { + return web; + } + switch (defaultTargetPlatform) { + case TargetPlatform.android: + return android; + case TargetPlatform.iOS: + return ios; + case TargetPlatform.macOS: + return macos; + case TargetPlatform.windows: + return windows; + case TargetPlatform.linux: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for linux - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + default: + throw UnsupportedError( + 'DefaultFirebaseOptions are not supported for this platform.', + ); + } + } + + static const FirebaseOptions web = FirebaseOptions( + apiKey: 'AIzaSyA8vQbyEt81DoAuRVDc_3W_VIKY-9F-XTw', + appId: '1:872447580790:web:10745e7f9afb447d5d9d57', + messagingSenderId: '872447580790', + projectId: 'assistenza-catelli', + authDomain: 'assistenza-catelli.firebaseapp.com', + storageBucket: 'assistenza-catelli.firebasestorage.app', + measurementId: 'G-HTSSNQJ15P', + ); + + static const FirebaseOptions android = FirebaseOptions( + apiKey: 'AIzaSyBSxpdLDlPnN0xjejlX_5JL19BDeSzKOr8', + appId: '1:872447580790:android:a1d8d57960451f935d9d57', + messagingSenderId: '872447580790', + projectId: 'assistenza-catelli', + storageBucket: 'assistenza-catelli.firebasestorage.app', + ); + + static const FirebaseOptions ios = FirebaseOptions( + apiKey: 'AIzaSyCkjOTW6BlckKIxQdp5TPnHuRfXFoVC3bY', + appId: '1:872447580790:ios:a87d56c718aa61e05d9d57', + messagingSenderId: '872447580790', + projectId: 'assistenza-catelli', + storageBucket: 'assistenza-catelli.firebasestorage.app', + iosBundleId: 'com.catellisrl.flux', + ); + + static const FirebaseOptions macos = FirebaseOptions( + apiKey: 'AIzaSyCkjOTW6BlckKIxQdp5TPnHuRfXFoVC3bY', + appId: '1:872447580790:ios:a87d56c718aa61e05d9d57', + messagingSenderId: '872447580790', + projectId: 'assistenza-catelli', + storageBucket: 'assistenza-catelli.firebasestorage.app', + iosBundleId: 'com.catellisrl.flux', + ); + + static const FirebaseOptions windows = FirebaseOptions( + apiKey: 'AIzaSyA5uJhb8ksqKqdEWbMD5ra6JYXIGoaIdIM', + appId: '1:872447580790:web:3b1623eda6abdac75d9d57', + messagingSenderId: '872447580790', + projectId: 'assistenza-catelli', + authDomain: 'assistenza-catelli.firebaseapp.com', + storageBucket: 'assistenza-catelli.firebasestorage.app', + measurementId: 'G-J8LZTQ9NHB', + ); +} diff --git a/lib/main.dart b/lib/main.dart index 8f62822..4dd6d4a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -7,6 +8,7 @@ import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flux/features/attachments/data/attachments_repository.dart'; import 'package:flux/features/auth/bloc/auth_cubit.dart'; import 'package:flux/features/operations/data/operations_repository.dart'; +import 'package:flux/firebase_options.dart'; import 'package:flux/l10n/app_localizations.dart'; import 'package:get_it/get_it.dart'; import 'package:go_router/go_router.dart'; @@ -102,6 +104,9 @@ Future setupLocator() async { getIt.registerSingleton( SessionCubit(getIt(), getIt()), ); + //TODO rimuovere dopo gli import + WidgetsFlutterBinding.ensureInitialized(); + await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); } class FluxApp extends StatefulWidget { diff --git a/lib/temp/migration_tools.dart b/lib/temp/migration_tools.dart new file mode 100644 index 0000000..89b764a --- /dev/null +++ b/lib/temp/migration_tools.dart @@ -0,0 +1,148 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:supabase_flutter/supabase_flutter.dart'; + +Future migrateCustomersToSupabase() async { + // 1. IL TUO COMPANY ID REALE SU SUPABASE + // Vai nel database Supabase, copia l'UUID della tua azienda e incollalo qui + final String myRealCompanyId = '6c4b2323-2a60-4d33-bf21-c5a8eb6b4a5b'; + + try { + print("Inizio download modello da Firebase..."); + + // 2. Scarichiamo TUTTI i clienti da Firebase + final snapshot = await FirebaseFirestore.instance.collection('marca').get(); + + if (snapshot.docs.isEmpty) { + print("Nessun marca trovato su Firebase!"); + return; + } + + // Questa lista conterrà i dati formattati pronti per Supabase + List> supabaseBrands = []; + + // 3. Cicliamo i documenti di Firebase e li trasformiamo + for (var doc in snapshot.docs) { + final data = doc.data(); + + // Creiamo la riga per Supabase + supabaseBrands.add({ + 'legacy_id': doc.id, // L'ID vecchio di Firebase + //'company_id': myRealCompanyId, // ECCO IL TUO COMPANY ID! + // Mappa i campi (attento a far combaciare i nomi esatti delle colonne Supabase!) + 'name': (data['nome'] as String).trim().toLowerCase(), + + 'company_id': myRealCompanyId, + + // Se avevi una data di creazione su Firebase, convertila, altrimenti ignorala + // e Supabase userà il suo 'default now()' + // 'created_at': (data['createdAt'] as Timestamp?)?.toDate().toIso8601String(), + }); + } + + print("Sto per inviare ${supabaseBrands.length} brand a Supabase..."); + + // 4. Invio a Supabase con UPSERT + await Supabase.instance.client + .from('brand') + .upsert( + supabaseBrands, + onConflict: + 'legacy_id', // Se il legacy_id c'è già, aggiorna invece di duplicare + ); + + print("BOOM! Migrazione brand completata con successo! 🚀"); + } catch (e) { + print("Porca miseria, errore durante la migrazione: $e"); + } +} + +Future migrateModelsToSupabase() async { + final String myRealCompanyId = '6c4b2323-2a60-4d33-bf21-c5a8eb6b4a5b'; + + try { + print("Inizio migrazione Modelli..."); + + // ========================================================== + // FASE 1: CREAZIONE DEL DIZIONARIO DI TRADUZIONE (LA MAGIA) + // ========================================================== + print("Scarico i Brand da Supabase per tradurre gli ID..."); + + // Chiediamo a Supabase solo 2 colonne: il nuovo UUID e il vecchio ID di Firebase + final List brandResponse = await Supabase.instance.client + .from('brand') + .select('id, legacy_id'); + + // Creiamo la mappa: la chiave è il vecchio ID, il valore è il nuovo UUID + Map brandTranslationMap = {}; + for (var b in brandResponse) { + if (b['legacy_firestore_id'] != null) { + brandTranslationMap[b['legacy_id']] = b['id']; + } + } + + print("Dizionario pronto! Trovati ${brandTranslationMap.length} Brand."); + + // ========================================================== + // FASE 2: SCARICAMENTO E TRADUZIONE DEI MODELLI + // ========================================================== + final snapshot = await FirebaseFirestore.instance + .collection('modello') + .get(); // Controlla il nome esatto della collection! + + if (snapshot.docs.isEmpty) { + print("Nessun modello trovato su Firebase!"); + return; + } + + List> supabaseModels = []; + + for (var doc in snapshot.docs) { + final data = doc.data(); + + // 1. Prendiamo il vecchio ID del brand salvato su Firebase + String? oldFirebaseBrandId = data['idMarca']; + + // 2. TRADUZIONE ISTANTANEA! Cerchiamo il nuovo UUID nel nostro dizionario + String? newSupabaseBrandUuid; + if (oldFirebaseBrandId != null) { + newSupabaseBrandUuid = brandTranslationMap[oldFirebaseBrandId]; + } + + // 3. Controllo di sicurezza: se il brand non esiste su Supabase, saltiamo il record o mettiamo null? + // Se nella tua tabella 'model' il 'brand_id' NON PUÒ essere null, devi per forza avere un match! + if (newSupabaseBrandUuid == null && oldFirebaseBrandId != null) { + print( + "ATTENZIONE: Il modello ${data['nome']} ha un brand_id ($oldFirebaseBrandId) che non esiste su Supabase. Salto o metto null.", + ); + continue; // Decommenta questo se vuoi saltare i modelli orfani + } + + // Creiamo la riga per Supabase + supabaseModels.add({ + 'legacy_id': doc.id, + + // ECCO LA CHIAVE ESTERNA TRADOTTA! + 'brand_id': newSupabaseBrandUuid, + + // Mappa gli altri campi + 'name': (data['name'] as String).trim().toLowerCase(), + 'name_with_brand': (data['nomeConMarca'] as String) + .toLowerCase() + .trim(), + }); + } + + // ========================================================== + // FASE 3: INVIO A SUPABASE + // ========================================================== + print("Sto per inviare ${supabaseModels.length} modelli a Supabase..."); + + await Supabase.instance.client + .from('model') + .upsert(supabaseModels, onConflict: 'legacy_id'); + + print("BOOM! Migrazione modelli completata con successo! 🚀"); + } catch (e) { + print("Errore durante la migrazione dei modelli: $e"); + } +} diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 425ee44..2be8b1a 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -6,16 +6,22 @@ import FlutterMacOS import Foundation import app_links +import cloud_firestore import file_picker import file_selector_macos +import firebase_auth +import firebase_core import pdfx import shared_preferences_foundation import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { AppLinksMacosPlugin.register(with: registry.registrar(forPlugin: "AppLinksMacosPlugin")) + FLTFirebaseFirestorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseFirestorePlugin")) FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) + FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin")) + FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) PdfxPlugin.register(with: registry.registrar(forPlugin: "PdfxPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) diff --git a/pubspec.lock b/pubspec.lock index 399aabd..8ce9620 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,14 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + _flutterfire_internals: + dependency: transitive + description: + name: _flutterfire_internals + sha256: bda3b7b55958bfd867addc40d067b4b11f7b8846d57671f5b5a6e7f9a56fe3ad + url: "https://pub.dev" + source: hosted + version: "1.3.69" app_links: dependency: transitive description: @@ -105,6 +113,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.2" + cloud_firestore: + dependency: "direct main" + description: + name: cloud_firestore + sha256: "3ac242332166ae5037bd87bc343744bb96d88d7b13f791492b00958ce5cc6c63" + url: "https://pub.dev" + source: hosted + version: "6.3.0" + cloud_firestore_platform_interface: + dependency: transitive + description: + name: cloud_firestore_platform_interface + sha256: "1bd08b736e1015e8bf5448f5ef67b2087a2380c2c1c7972f8403c1c7b41f5359" + url: "https://pub.dev" + source: hosted + version: "7.2.0" + cloud_firestore_web: + dependency: transitive + description: + name: cloud_firestore_web + sha256: "18617275ffa2331d3ea058c515ef218bcce2ae13a14bee922563ca6ae2507c26" + url: "https://pub.dev" + source: hosted + version: "5.3.0" code_assets: dependency: transitive description: @@ -241,6 +273,54 @@ packages: url: "https://pub.dev" source: hosted version: "0.9.3+5" + firebase_auth: + dependency: "direct main" + description: + name: firebase_auth + sha256: b12cb1e2e87797d27e0041100b73ebf890dbafcff2e7e991d4593f5e8e309808 + url: "https://pub.dev" + source: hosted + version: "6.4.0" + firebase_auth_platform_interface: + dependency: transitive + description: + name: firebase_auth_platform_interface + sha256: c71517b3c78480be42789b05316a7692d69296c17848bd6a9e798300abae1ec7 + url: "https://pub.dev" + source: hosted + version: "8.1.9" + firebase_auth_web: + dependency: transitive + description: + name: firebase_auth_web + sha256: "52b0224eb46b09f387e99710707be2d3f48da67c74fe14202e4b942cbe8ce9fd" + url: "https://pub.dev" + source: hosted + version: "6.1.5" + firebase_core: + dependency: "direct main" + description: + name: firebase_core + sha256: d5a94b884dcb1e6d3430298e94bfe002238094cdfd5e29202d536ee2120f9158 + url: "https://pub.dev" + source: hosted + version: "4.7.0" + firebase_core_platform_interface: + dependency: transitive + description: + name: firebase_core_platform_interface + sha256: "0ecda14c1bfc9ed8cac303dd0f8d04a320811b479362a9a4efb14fd331a473ce" + url: "https://pub.dev" + source: hosted + version: "6.0.3" + firebase_core_web: + dependency: transitive + description: + name: firebase_core_web + sha256: dc5096257cd67292d34d78ceeb90836f02a4be921b5f3934311a02bb2376118c + url: "https://pub.dev" + source: hosted + version: "3.6.0" fixnum: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 017d845..e928893 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -31,6 +31,9 @@ dependencies: uuid: ^4.5.3 pdf: ^3.12.0 universal_io: ^2.3.1 + firebase_core: ^4.7.0 + firebase_auth: ^6.4.0 + cloud_firestore: ^6.3.0 dev_dependencies: flutter_test: diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index b2c13bf..a2953b8 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -7,7 +7,10 @@ #include "generated_plugin_registrant.h" #include +#include #include +#include +#include #include #include #include @@ -15,8 +18,14 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { AppLinksPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("AppLinksPluginCApi")); + CloudFirestorePluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("CloudFirestorePluginCApi")); FileSelectorWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("FileSelectorWindows")); + FirebaseAuthPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FirebaseAuthPluginCApi")); + FirebaseCorePluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); PdfxPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("PdfxPlugin")); PermissionHandlerWindowsPluginRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 668b8b9..d9eefd9 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -4,7 +4,10 @@ list(APPEND FLUTTER_PLUGIN_LIST app_links + cloud_firestore file_selector_windows + firebase_auth + firebase_core pdfx permission_handler_windows url_launcher_windows