diff --git a/lib/core/blocs/session/session_cubit.dart b/lib/core/blocs/session/session_cubit.dart index 46d6927..eaf1c6a 100644 --- a/lib/core/blocs/session/session_cubit.dart +++ b/lib/core/blocs/session/session_cubit.dart @@ -247,4 +247,13 @@ class SessionCubit extends Cubit { void setIsSingleUserMode(bool isSingleUser) { emit(state.copyWith(isSingleUserMode: isSingleUser)); } + + void updateCurrentStoreLocally(StoreModel updatedStore) { + // Verifichiamo che l'utente stia effettivamente lavorando nel negozio appena modificato + if (state.currentStore != null && + state.currentStore!.id == updatedStore.id) { + // Emettiamo il nuovo stato sovrascrivendo solo il negozio corrente + emit(state.copyWith(currentStore: updatedStore)); + } + } } diff --git a/lib/features/master_data/providers/models/provider_model_extensions.dart b/lib/features/master_data/providers/models/provider_model_extensions.dart new file mode 100644 index 0000000..9813a5d --- /dev/null +++ b/lib/features/master_data/providers/models/provider_model_extensions.dart @@ -0,0 +1,28 @@ +import 'package:flux/features/master_data/providers/models/provider_model.dart'; +import 'package:flux/features/master_data/providers/models/provider_role.dart'; + +extension ProviderCompatibility on ProviderModel { + bool supportsOperation(String operationType) { + if (operationType == 'Altro') return true; + + switch (operationType) { + case 'AL' || 'MNP': + return roles.contains(ProviderRole.mobile); + case 'NIP' || 'FWA': + return roles.contains(ProviderRole.landline); + case 'UNICA': + return roles.contains(ProviderRole.landline) || + roles.contains(ProviderRole.mobile); + case 'Energy': + return roles.contains(ProviderRole.energy); + case 'Fin': + return roles.contains(ProviderRole.financing); + case 'Entertainment': + return roles.contains(ProviderRole.entertainment); + case 'TELEPASS': + return roles.contains(ProviderRole.telepass); + default: + return true; + } + } +} diff --git a/lib/features/master_data/store/bloc/store_cubit.dart b/lib/features/master_data/store/bloc/store_cubit.dart index ea85d01..43fb9f2 100644 --- a/lib/features/master_data/store/bloc/store_cubit.dart +++ b/lib/features/master_data/store/bloc/store_cubit.dart @@ -17,14 +17,18 @@ class StoreCubit extends Cubit { StoreCubit() : super(const StoreState(stores: [])); - Future createStore(final StoreModel store) async { + Future saveStore(final StoreModel store) async { emit(state.copyWith(status: StoreStatus.loading)); try { - await _repository.createStore(store); - emit(state.copyWith(status: StoreStatus.success)); + final savedStore = await _repository.saveStore(store); + emit(state.copyWith(status: StoreStatus.success, savedStore: savedStore)); } catch (e) { emit( - state.copyWith(status: StoreStatus.failure, errorMessage: e.toString()), + state.copyWith( + status: StoreStatus.failure, + errorMessage: e.toString(), + savedStore: null, + ), ); } } @@ -70,6 +74,7 @@ class StoreCubit extends Cubit { state.copyWith( status: StoreStatus.failure, errorMessage: "Errore nel salvataggio dei provider: $e", + savedStore: null, ), ); } @@ -90,6 +95,7 @@ class StoreCubit extends Cubit { state.copyWith( status: StoreStatus.failure, errorMessage: "Errore nel salvataggio dello staff: $e", + savedStore: null, ), ); } @@ -110,6 +116,7 @@ class StoreCubit extends Cubit { state.copyWith( status: StoreStatus.failure, errorMessage: "Errore nell'associazione: $e", + savedStore: null, ), ); } @@ -130,6 +137,7 @@ class StoreCubit extends Cubit { state.copyWith( status: StoreStatus.failure, errorMessage: "Errore nella rimozione: $e", + savedStore: null, ), ); } @@ -142,7 +150,11 @@ class StoreCubit extends Cubit { loadStores(); } catch (e) { emit( - state.copyWith(status: StoreStatus.failure, errorMessage: e.toString()), + state.copyWith( + status: StoreStatus.failure, + errorMessage: e.toString(), + savedStore: null, + ), ); } } @@ -157,6 +169,7 @@ class StoreCubit extends Cubit { state.copyWith( status: StoreStatus.failure, errorMessage: "Errore nella rimozione: $e", + savedStore: null, ), ); } diff --git a/lib/features/master_data/store/bloc/store_state.dart b/lib/features/master_data/store/bloc/store_state.dart index 772e8c6..b672f44 100644 --- a/lib/features/master_data/store/bloc/store_state.dart +++ b/lib/features/master_data/store/bloc/store_state.dart @@ -7,6 +7,8 @@ class StoreState extends Equatable { final StoreModel? store; final String? errorMessage; final List stores; + final StoreModel? + savedStore; // Per tenere traccia del negozio appena salvato (utile per aggiornare la sessione) final Map> staffByStore; const StoreState({ @@ -14,6 +16,7 @@ class StoreState extends Equatable { this.store, this.errorMessage, required this.stores, + this.savedStore, this.staffByStore = const {}, }); @@ -22,6 +25,7 @@ class StoreState extends Equatable { StoreModel? store, String? errorMessage, List? stores, + StoreModel? savedStore, Map>? staffByStore, }) { return StoreState( @@ -29,6 +33,7 @@ class StoreState extends Equatable { store: store ?? this.store, errorMessage: errorMessage ?? this.errorMessage, stores: stores ?? this.stores, + savedStore: savedStore ?? this.savedStore, staffByStore: staffByStore ?? this.staffByStore, ); } @@ -39,6 +44,7 @@ class StoreState extends Equatable { store, errorMessage, stores, + savedStore, staffByStore, ]; } diff --git a/lib/features/master_data/store/data/store_repository.dart b/lib/features/master_data/store/data/store_repository.dart index d34ecbc..2e63619 100644 --- a/lib/features/master_data/store/data/store_repository.dart +++ b/lib/features/master_data/store/data/store_repository.dart @@ -9,7 +9,7 @@ class StoreRepository { final SupabaseClient _supabase = GetIt.I.get(); /// Crea un nuovo negozio associato alla compagnia dell'utente - Future createStore(StoreModel store) async { + /* Future createStore(StoreModel store) async { try { await _supabase.from(Tables.stores).insert(store.toMap()); } on PostgrestException catch (e) { @@ -18,7 +18,7 @@ class StoreRepository { } catch (e) { throw 'Errore imprevisto durante la creazione del negozio: $e'; } - } + } */ Future saveStore(StoreModel store) async { try { diff --git a/lib/features/master_data/store/models/store_model.dart b/lib/features/master_data/store/models/store_model.dart index 988d256..526226e 100644 --- a/lib/features/master_data/store/models/store_model.dart +++ b/lib/features/master_data/store/models/store_model.dart @@ -16,6 +16,7 @@ class StoreModel extends Equatable { final List associatedProviders; // Provider associati final List associatedStaffMembers; // Membri dello staff associati + final String? defaultProviderId; // ID del provider di default (opzionale) const StoreModel({ this.id, @@ -30,6 +31,7 @@ class StoreModel extends Equatable { required this.province, this.associatedProviders = const [], this.associatedStaffMembers = const [], + this.defaultProviderId, }); // Fondamentale per Equatable: definisce quali proprietà determinano l'uguaglianza @@ -47,6 +49,7 @@ class StoreModel extends Equatable { province, associatedProviders, associatedStaffMembers, + defaultProviderId, ]; // Il mitico copyWith per creare nuove istanze modificando solo ciò che serve @@ -63,6 +66,7 @@ class StoreModel extends Equatable { String? province, List? associatedProviders, List? associatedStaffMembers, + String? Function()? defaultProviderId, }) { return StoreModel( id: id ?? this.id, @@ -78,6 +82,9 @@ class StoreModel extends Equatable { associatedProviders: associatedProviders ?? this.associatedProviders, associatedStaffMembers: associatedStaffMembers ?? this.associatedStaffMembers, + defaultProviderId: defaultProviderId != null + ? defaultProviderId() + : this.defaultProviderId, ); } @@ -131,6 +138,7 @@ class StoreModel extends Equatable { province: map['province'], associatedProviders: providers, associatedStaffMembers: staffMembers, + defaultProviderId: map['default_provider_id'] as String?, ); } @@ -147,6 +155,7 @@ class StoreModel extends Equatable { 'zip_code': zipCode, 'city': city, 'province': province, + 'default_provider_id': defaultProviderId, }; } } diff --git a/lib/features/master_data/store/ui/create_store_screen.dart b/lib/features/master_data/store/ui/create_store_screen.dart index 918ecc7..de20168 100644 --- a/lib/features/master_data/store/ui/create_store_screen.dart +++ b/lib/features/master_data/store/ui/create_store_screen.dart @@ -76,7 +76,7 @@ class _CreateStoreScreenState extends State { province: _provinciaController.text.trim().toUpperCase(), ); - context.read().createStore(store); + context.read().saveStore(store); } } diff --git a/lib/features/master_data/store/ui/store_form.dart b/lib/features/master_data/store/ui/store_form.dart index 131009f..801491b 100644 --- a/lib/features/master_data/store/ui/store_form.dart +++ b/lib/features/master_data/store/ui/store_form.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flux/core/blocs/session/session_cubit.dart'; import 'package:flux/core/widgets/flux_text_field.dart'; +import 'package:flux/features/master_data/providers/blocs/provider_list_cubit.dart'; import 'package:flux/features/master_data/store/bloc/store_cubit.dart'; import 'package:flux/features/master_data/store/models/store_model.dart'; @@ -19,6 +20,8 @@ class _StoreFormState extends State { final capController = TextEditingController(); final comuneController = TextEditingController(); final provinciaController = TextEditingController(); + String? + _selectedDefaultProviderId; // Per tenere traccia del provider di default selezionato @override void initState() { @@ -29,129 +32,241 @@ class _StoreFormState extends State { capController.text = widget.store!.zipCode; comuneController.text = widget.store!.city; provinciaController.text = widget.store!.province; + _selectedDefaultProviderId = widget.store!.defaultProviderId; } + context.read().loadProviders( + widget.store!.id!, + ); // Carichiamo i gestori per la dropdown } @override Widget build(BuildContext context) { - return Container( - decoration: BoxDecoration( - color: Theme.of(context).scaffoldBackgroundColor, - borderRadius: const BorderRadius.vertical(top: Radius.circular(24)), - ), - padding: EdgeInsets.only( - top: 24, - left: 24, - right: 24, - bottom: MediaQuery.of(context).viewInsets.bottom + 24, - ), - child: SingleChildScrollView( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - widget.store == null ? "Nuovo Punto Vendita" : "Modifica Negozio", - style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + return BlocListener( + listener: (context, state) { + if (state.status == StoreStatus.success) { + // 1. Diciamo alla schermata di ricaricare la lista generale dei negozi (se serve) + context.read().loadStores(); + + // 🥷 2. IL TOCCO FINALE: Aggiorniamo la sessione globale se stiamo modificando il negozio attivo! + if (state.savedStore != null) { + context.read().updateCurrentStoreLocally( + state.savedStore!, + ); + } + + // 3. Chiudiamo il form + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text( + 'Negozio aggiornato con successo!', + style: TextStyle(color: Colors.white), + ), + backgroundColor: Colors.green, ), - const SizedBox(height: 24), + ); + Navigator.pop(context); + } - // --- DATI PRINCIPALI --- - FluxTextField( - controller: nomeController, - label: "Nome Negozio (es. Flux Milano)", - icon: Icons.storefront_rounded, - keyboardType: TextInputType.name, + if (state.status == StoreStatus.failure) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(state.errorMessage ?? 'Errore di salvataggio'), + backgroundColor: Colors.red, ), - const SizedBox(height: 16), - FluxTextField( - controller: indirizzoController, - label: "Indirizzo", - icon: Icons.map_outlined, - keyboardType: TextInputType.streetAddress, - ), - const SizedBox(height: 16), - - // --- CAP, COMUNE, PROVINCIA (In riga) --- - Row( - children: [ - Expanded( - flex: 2, - child: FluxTextField( - controller: capController, - label: "CAP", - icon: Icons.post_add_rounded, - keyboardType: TextInputType.number, - maxLength: 5, - ), - ), - const SizedBox(width: 8), - Expanded( - flex: 4, - child: FluxTextField( - controller: comuneController, - label: "Comune", - icon: Icons.location_city_rounded, - keyboardType: TextInputType.name, - ), - ), - const SizedBox(width: 8), - Expanded( - flex: 2, - child: FluxTextField( - controller: provinciaController, - label: "Prov", - icon: Icons.explore_outlined, - keyboardType: TextInputType.name, - onChanged: (value) => value.toUpperCase(), - maxLength: 2, - ), - ), - ], - ), - - const SizedBox(height: 32), - - // --- TASTO SALVA --- - SizedBox( - width: double.infinity, - height: 50, - child: ElevatedButton( - onPressed: () { - if (nomeController.text.isEmpty) return; - - final storeData = StoreModel( - id: widget - .store - ?.id, // Se nullo, Supabase ne crea uno nuovo - name: nomeController.text, - address: indirizzoController.text, - zipCode: capController.text, - city: comuneController.text, - province: provinciaController.text, - companyId: context - .read() - .state - .company! - .id!, // Recuperiamo la companyId - isActive: widget.store?.isActive ?? true, - isPaid: widget.store?.isPaid ?? false, - paymentExpiration: widget.store?.paymentExpiration, - ); - - // Chiamata al Bloc per il salvataggio - context.read().createStore(storeData); - - Navigator.pop(context); - }, - child: Text( - widget.store == null ? "CREA NEGOZIO" : "AGGIORNA DATI", + ); + } + }, + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).scaffoldBackgroundColor, + borderRadius: const BorderRadius.vertical(top: Radius.circular(24)), + ), + padding: EdgeInsets.only( + top: 24, + left: 24, + right: 24, + bottom: MediaQuery.of(context).viewInsets.bottom + 24, + ), + child: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.store == null + ? "Nuovo Punto Vendita" + : "Modifica Negozio", + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, ), ), - ), - ], + const SizedBox(height: 24), + + // --- DATI PRINCIPALI --- + FluxTextField( + controller: nomeController, + label: "Nome Negozio (es. Flux Milano)", + icon: Icons.storefront_rounded, + keyboardType: TextInputType.name, + ), + const SizedBox(height: 16), + FluxTextField( + controller: indirizzoController, + label: "Indirizzo", + icon: Icons.map_outlined, + keyboardType: TextInputType.streetAddress, + ), + const SizedBox(height: 16), + + // --- CAP, COMUNE, PROVINCIA (In riga) --- + Row( + children: [ + Expanded( + flex: 2, + child: FluxTextField( + controller: capController, + label: "CAP", + icon: Icons.post_add_rounded, + keyboardType: TextInputType.number, + maxLength: 5, + ), + ), + const SizedBox(width: 8), + Expanded( + flex: 4, + child: FluxTextField( + controller: comuneController, + label: "Comune", + icon: Icons.location_city_rounded, + keyboardType: TextInputType.name, + ), + ), + const SizedBox(width: 8), + Expanded( + flex: 2, + child: FluxTextField( + controller: provinciaController, + label: "Prov", + icon: Icons.explore_outlined, + keyboardType: TextInputType.name, + onChanged: (value) => value.toUpperCase(), + maxLength: 2, + ), + ), + ], + ), + const SizedBox(height: 16), + + // --- GESTORI --- + _defaultProviderDropdown(), + + const SizedBox(height: 32), + + // --- TASTO SALVA --- + SizedBox( + width: double.infinity, + height: 50, + child: ElevatedButton( + onPressed: () { + if (nomeController.text.isEmpty) return; + + final storeData = StoreModel( + id: widget + .store + ?.id, // Se nullo, Supabase ne crea uno nuovo + name: nomeController.text, + address: indirizzoController.text, + zipCode: capController.text, + city: comuneController.text, + province: provinciaController.text, + companyId: context + .read() + .state + .company! + .id!, // Recuperiamo la companyId + isActive: widget.store?.isActive ?? true, + isPaid: widget.store?.isPaid ?? false, + paymentExpiration: widget.store?.paymentExpiration, + defaultProviderId: _selectedDefaultProviderId, + ); + + // Chiamata al Bloc per il salvataggio + context.read().saveStore(storeData); + }, + child: Text( + widget.store == null ? "CREA NEGOZIO" : "AGGIORNA DATI", + ), + ), + ), + ], + ), ), ), ); } + + Widget _defaultProviderDropdown() { + return BlocBuilder( + builder: (context, state) { + if (state.status == ProviderListStatus.loading) { + return const Center(child: CircularProgressIndicator()); + } + + final activeProviders = state.providers + .where((p) => p.isActive) + .toList(); + + // 🥷 SCENARIO ONBOARDING: La lista dei gestori è vuota + if (activeProviders.isEmpty) { + return TextFormField( + enabled: false, // Disabilitiamo il campo + decoration: InputDecoration( + labelText: 'Gestore di Default', + hintText: 'Configura prima i gestori nell\'hub anagrafiche', + hintStyle: TextStyle(color: Colors.grey[500], fontSize: 13), + prefixIcon: const Icon(Icons.star_border, color: Colors.grey), + disabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: Colors.grey[300]!), + ), + fillColor: Colors.grey[50], + filled: true, + ), + ); + } + + // SCENARIO STANDARD: Ci sono gestori censiti, mostriamo la dropdown + return DropdownButtonFormField( + initialValue: _selectedDefaultProviderId, + decoration: InputDecoration( + labelText: 'Gestore di Default (Opzionale)', + hintText: 'Seleziona se questo è un negozio monomarca', + prefixIcon: const Icon(Icons.star_border, color: Colors.amber), + border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)), + ), + items: [ + const DropdownMenuItem( + value: null, + child: Text( + 'Nessun gestore (Multi-brand)', + style: TextStyle(fontStyle: FontStyle.italic), + ), + ), + ...activeProviders.map((p) { + return DropdownMenuItem( + value: p.id, + child: Text(p.name), + ); + }), + ], + onChanged: (val) { + setState(() { + _selectedDefaultProviderId = val; + }); + }, + ); + }, + ); + } } diff --git a/lib/features/operations/blocs/operation_form_cubit.dart b/lib/features/operations/blocs/operation_form_cubit.dart index 0ef7386..886ef31 100644 --- a/lib/features/operations/blocs/operation_form_cubit.dart +++ b/lib/features/operations/blocs/operation_form_cubit.dart @@ -2,6 +2,8 @@ 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/customers/models/customer_model.dart'; +import 'package:flux/features/master_data/providers/models/provider_model.dart'; +import 'package:flux/features/master_data/providers/models/provider_model_extensions.dart'; import 'package:flux/features/master_data/staff/models/staff_member_model.dart'; import 'package:flux/features/operations/data/operations_repository.dart'; import 'package:flux/features/operations/models/operation_model.dart'; @@ -278,27 +280,126 @@ class OperationFormCubit extends Cubit { // --- UTILS --- - void setTypeWithSmartDefault(String type) { + void updateOperationType( + String newType, { + required List allProviders, + String? defaultProviderId, + }) { + // 1. Aggiorniamo il tipo nel modello in canna + // (Presumo tu abbia un metodo copyWith o simile) + final updatedOp = state.operation.copyWith(type: newType, subtype: ''); + + // 2. Prepariamoci ad auto-selezionare il provider + String? newProviderId = updatedOp.providerId; + String? newProviderName = updatedOp.providerDisplayName; + + // 3. LA LOGICA DI DEFAULT + if (defaultProviderId != null) { + // Troviamo il provider di default nella lista + final defaultProvider = allProviders + .where((p) => p.id == defaultProviderId) + .firstOrNull; + + if (defaultProvider != null) { + // Usiamo l'extension appena creata! + if (defaultProvider.supportsOperation(newType)) { + newProviderId = defaultProvider.id; + newProviderName = defaultProvider.name; + } else { + // Se cambi tipo (es. da Mobile a Luce) e il default non lo supporta, sbianchiamo + newProviderId = null; + newProviderName = null; + } + } + } + + // Emettiamo il nuovo stato + emit( + state.copyWith( + operation: updatedOp.copyWith( + providerId: newProviderId, + providerDisplayName: newProviderName, + ), + ), + ); + } + + void setTypeWithSmartDefaults({ + required String newType, + required List allProviders, + String? defaultProviderId, + }) { + final currentOp = state.operation; + + // ----------------------------------------- + // 1. SMART DATES: Calcolo Scadenze Default + // ----------------------------------------- DateTime? defaultDate; final now = DateTime.now(); - if (type == 'Energy') { + if (newType == 'Energy') { defaultDate = DateTime(now.year, now.month + 24, now.day); } - if (type == 'Fin') { + if (newType == 'Fin') { defaultDate = DateTime(now.year, now.month + 30, now.day); } - if (type == 'Entertainment') { + if (newType == 'Entertainment') { defaultDate = DateTime(now.year, now.month + 12, now.day); } - updateFields( - type: type, - expirationDate: defaultDate, - clearProvider: true, - clearSubtype: true, - clearModel: true, - clearQuantity: true, + // ----------------------------------------- + // 2. SMART PROVIDER: Filtro e Auto-Selezione + // ----------------------------------------- + String? newProviderId = currentOp.providerId; + String? newProviderName = currentOp.providerDisplayName; + + // A) Il provider attuale è ancora compatibile col nuovo tipo scelto? + if (newProviderId != null && newProviderId.isNotEmpty) { + final currentProvider = allProviders + .where((p) => p.id == newProviderId) + .firstOrNull; + + if (currentProvider == null || + !currentProvider.supportsOperation(newType)) { + // Non è più compatibile (es. da TIM fisso passo a Energy). Lo sbianchiamo! + newProviderId = null; + newProviderName = null; + } + } + + // B) Se non c'è un provider selezionato, proviamo ad auto-inserire quello di default del negozio + if ((newProviderId == null || newProviderId.isEmpty) && + defaultProviderId != null) { + final defaultProvider = allProviders + .where((p) => p.id == defaultProviderId) + .firstOrNull; + + // Controlliamo che il default del negozio supporti questa specifica operazione + if (defaultProvider != null && + defaultProvider.supportsOperation(newType)) { + newProviderId = defaultProvider.id; + newProviderName = defaultProvider.name; + } + } + + // ----------------------------------------- + // 3. EMISSIONE DELLO STATO PULITO + // ----------------------------------------- + emit( + state.copyWith( + operation: currentOp.copyWith( + type: newType, + subtype: + '', // Resettiamo il sottotipo per evitare incongruenze (es. passo da Luce a DAZN) + expirationDate: + defaultDate, // Impostiamo la scadenza di default se calcolata + providerId: newProviderId, + providerDisplayName: newProviderName, + + modelId: null, + modelDisplayName: null, + ), + ), ); } } diff --git a/lib/features/operations/ui/operation_form_screen.dart b/lib/features/operations/ui/operation_form_screen.dart index f979614..05d97a5 100644 --- a/lib/features/operations/ui/operation_form_screen.dart +++ b/lib/features/operations/ui/operation_form_screen.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flux/core/blocs/session/session_cubit.dart'; import 'package:flux/core/widgets/shared_forms/attachments_section.dart'; import 'package:flux/features/attachments/blocs/attachments_bloc.dart'; +import 'package:flux/features/master_data/providers/blocs/provider_list_cubit.dart'; import 'package:flux/features/operations/blocs/operation_form_cubit.dart'; import 'package:flux/features/operations/models/operation_model.dart'; import 'package:flux/core/widgets/shared_forms/customer_section.dart'; @@ -527,8 +529,24 @@ class _OperationFormScreenState extends State { selected: state.operation.type == type, onSelected: (selected) { if (selected) { - context.read().setTypeWithSmartDefault( - type, + // 1. Recuperiamo i provider caricati in memoria + final allProviders = context + .read() + .state + .providers; + + // 2. Recuperiamo il provider di default del negozio dalla sessione + final defaultProviderId = context + .read() + .state + .currentStore + ?.defaultProviderId; + + // 3. Spariamo tutto nel metodo "tuttofare" + context.read().setTypeWithSmartDefaults( + newType: type, + allProviders: allProviders, + defaultProviderId: defaultProviderId, ); } }, diff --git a/lib/features/operations/ui/widgets/details_section.dart b/lib/features/operations/ui/widgets/details_section.dart index 566ae5f..cce022c 100644 --- a/lib/features/operations/ui/widgets/details_section.dart +++ b/lib/features/operations/ui/widgets/details_section.dart @@ -2,8 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flux/core/widgets/shared_forms/model_section.dart'; import 'package:flux/features/master_data/providers/blocs/provider_list_cubit.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_model_extensions.dart'; import 'package:flux/features/operations/blocs/operation_form_cubit.dart'; import 'package:flux/features/operations/models/operation_model.dart'; @@ -23,34 +22,6 @@ class OperationDetailsSection extends StatelessWidget { required this.durationQuickPicks, }); - bool _doesProviderMatchOperationType( - ProviderModel provider, - String operationType, - ) { - if (operationType == 'Altro') return true; - - // Controlliamo che il fornitore abbia il ruolo specifico nel suo array - switch (operationType) { - case 'AL' || 'MNP': - return provider.roles.contains(ProviderRole.mobile); - case 'NIP' || 'FWA': - return provider.roles.contains(ProviderRole.landline); - case 'UNICA': - return provider.roles.contains(ProviderRole.landline) || - provider.roles.contains(ProviderRole.mobile); - case 'Energy': - return provider.roles.contains(ProviderRole.energy); - case 'Fin': - return provider.roles.contains(ProviderRole.financing); - case 'Entertainment': - return provider.roles.contains(ProviderRole.entertainment); - case 'TELEPASS': - return provider.roles.contains(ProviderRole.telepass); - default: - return true; - } - } - void _showProviderModal(BuildContext context, String operationType) { final OperationFormCubit cubit = context.read(); showModalBottomSheet( @@ -92,14 +63,9 @@ class OperationDetailsSection extends StatelessWidget { return const Center(child: CircularProgressIndicator()); } - // Prendiamo i provider e li filtriamo per ruolo e per stato attivo + // 🥷 IL TOCCO DEL NINJA: Filtriamo usando direttamente l'Extension sul Modello! final filteredProviders = state.providers.where((p) { - final isMatch = _doesProviderMatchOperationType( - p, - operationType, - ); - return isMatch && - p.isActive; // Mostriamo solo quelli attivi! + return p.supportsOperation(operationType) && p.isActive; }).toList(); if (filteredProviders.isEmpty) { diff --git a/pubspec.yaml b/pubspec.yaml index 402b1da..7d0b58f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: flux description: "Gestione attività negozio di telefonia" publish_to: 'none' -version: 1.1.12+30 +version: 1.1.13+31 environment: sdk: ^3.11.3