refactor providers e basi per spedizioni
This commit is contained in:
@@ -1,176 +0,0 @@
|
||||
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/master_data/providers/data/provider_repository.dart';
|
||||
import 'package:flux/features/master_data/store/models/store_model.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import '../models/provider_model.dart';
|
||||
|
||||
class ProvidersState extends Equatable {
|
||||
final List<ProviderModel> allProviders;
|
||||
final List<String> associatedIds;
|
||||
// NUOVO CAMPO: Lista dei provider pronti per essere usati nel form pratiche
|
||||
final List<ProviderModel> activeProviders;
|
||||
final bool isLoading;
|
||||
final String? errorMessage;
|
||||
|
||||
const ProvidersState({
|
||||
this.allProviders = const [],
|
||||
this.associatedIds = const [],
|
||||
this.activeProviders = const [], // Inizializza
|
||||
this.isLoading = false,
|
||||
this.errorMessage,
|
||||
});
|
||||
|
||||
ProvidersState copyWith({
|
||||
List<ProviderModel>? allProviders,
|
||||
List<String>? associatedIds,
|
||||
List<ProviderModel>? activeProviders, // Aggiungi qui
|
||||
bool? isLoading,
|
||||
String? errorMessage,
|
||||
}) {
|
||||
return ProvidersState(
|
||||
allProviders: allProviders ?? this.allProviders,
|
||||
associatedIds: associatedIds ?? this.associatedIds,
|
||||
activeProviders: activeProviders ?? this.activeProviders, // Aggiungi qui
|
||||
isLoading: isLoading ?? this.isLoading,
|
||||
errorMessage:
|
||||
errorMessage ??
|
||||
this.errorMessage, // Correzione bug: mancava "?? this.errorMessage" nel tuo originale
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
allProviders,
|
||||
associatedIds,
|
||||
activeProviders, // Aggiungi qui
|
||||
isLoading,
|
||||
errorMessage,
|
||||
];
|
||||
}
|
||||
|
||||
class ProvidersCubit extends Cubit<ProvidersState> {
|
||||
final ProviderRepository _repository = GetIt.I<ProviderRepository>();
|
||||
final SessionCubit _sessionCubit = GetIt.I<SessionCubit>();
|
||||
|
||||
ProvidersCubit() : super(const ProvidersState());
|
||||
|
||||
// Carica i provider della company e quelli associati a uno store specifico
|
||||
Future<void> loadProviders({StoreModel? store}) async {
|
||||
emit(state.copyWith(isLoading: true));
|
||||
try {
|
||||
final all = await _repository.fetchAllCompanyProviders(
|
||||
_sessionCubit.state.company!.id!,
|
||||
);
|
||||
List<String> associated = [];
|
||||
|
||||
if (store != null) {
|
||||
associated = await _repository.fetchAssociatedProviderIds(store.id!);
|
||||
}
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
allProviders: all,
|
||||
associatedIds: associated,
|
||||
isLoading: false,
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
emit(state.copyWith(isLoading: false, errorMessage: e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> loadActiveProvidersForStore(String storeId) async {
|
||||
emit(state.copyWith(isLoading: true));
|
||||
try {
|
||||
final activeList = await _repository.fetchActiveProvidersForStore(
|
||||
storeId,
|
||||
);
|
||||
emit(state.copyWith(activeProviders: activeList, isLoading: false));
|
||||
} catch (e) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: "Errore caricamento gestori: $e",
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Aggiunge o rimuove l'associazione con lo store
|
||||
Future<void> toggleProviderAssociation({
|
||||
required String providerId,
|
||||
required String storeId,
|
||||
required bool isCurrentlyAssociated,
|
||||
}) async {
|
||||
try {
|
||||
if (isCurrentlyAssociated) {
|
||||
await _repository.disassociateProviderFromStore(
|
||||
providerId: providerId,
|
||||
storeId: storeId,
|
||||
);
|
||||
// Aggiorniamo lo stato locale rimuovendo l'ID
|
||||
final newIds = List<String>.from(state.associatedIds)
|
||||
..remove(providerId);
|
||||
emit(state.copyWith(associatedIds: newIds));
|
||||
} else {
|
||||
await _repository.associateProviderToStore(
|
||||
providerId: providerId,
|
||||
storeId: storeId,
|
||||
);
|
||||
// Aggiorniamo lo stato locale aggiungendo l'ID
|
||||
final newIds = List<String>.from(state.associatedIds)..add(providerId);
|
||||
emit(state.copyWith(associatedIds: newIds));
|
||||
}
|
||||
} catch (e) {
|
||||
emit(state.copyWith(errorMessage: "Errore durante l'aggiornamento: $e"));
|
||||
}
|
||||
}
|
||||
|
||||
// Salvataggio/Update anagrafica (nuovo o modifica)
|
||||
Future<void> saveProvider(
|
||||
ProviderModel provider,
|
||||
List<String> selectedStoreIds,
|
||||
) async {
|
||||
emit(state.copyWith(isLoading: true));
|
||||
// Assicuriamoci di settare la companyId prima di salvare
|
||||
provider = provider.copyWith(companyId: _sessionCubit.state.company!.id);
|
||||
try {
|
||||
// 1. Salviamo l'anagrafica (upsert)
|
||||
// Se è un nuovo provider, l'ID potrebbe essere generato qui dal DB
|
||||
// Quindi carichiamo il risultato del salvataggio per avere l'ID
|
||||
final response = await _repository.saveProvider(provider);
|
||||
|
||||
// Assumiamo che il saveProvider restituisca l'oggetto salvato con l'ID
|
||||
final pId = provider.id ?? response.id;
|
||||
|
||||
// 2. Sincronizziamo i negozi
|
||||
await _repository.syncProviderStores(pId!, selectedStoreIds);
|
||||
|
||||
// 3. Ricarichiamo tutto
|
||||
await loadProviders();
|
||||
} catch (e) {
|
||||
emit(state.copyWith(isLoading: false, errorMessage: e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> saveProviderWithStores(
|
||||
ProviderModel provider,
|
||||
List<String> storeIds,
|
||||
) async {
|
||||
emit(state.copyWith(isLoading: true));
|
||||
try {
|
||||
// 1. Salva l'anagrafica provider
|
||||
await _repository.saveProvider(provider);
|
||||
|
||||
// 2. Sincronizza i negozi (la via più semplice è cancellare e reinserire
|
||||
// o fare un confronto tra i presenti e i nuovi)
|
||||
await _repository.syncProviderStores(provider.id!, storeIds);
|
||||
|
||||
await loadProviders();
|
||||
} catch (e) {
|
||||
emit(state.copyWith(isLoading: false, errorMessage: e.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart'; // Per estrarre gli store
|
||||
import '../models/provider_model.dart';
|
||||
import '../models/provider_role.dart';
|
||||
import '../models/provider_location_model.dart';
|
||||
import '../data/provider_repository.dart';
|
||||
part 'provider_form_state.dart';
|
||||
|
||||
class ProviderFormCubit extends Cubit<ProviderFormState> {
|
||||
final ProviderRepository _repository = GetIt.I.get<ProviderRepository>();
|
||||
final _client = Supabase.instance.client; // Lo usiamo al volo per gli store
|
||||
|
||||
ProviderFormCubit()
|
||||
: super(ProviderFormState(provider: ProviderModel.empty(companyId: '')));
|
||||
|
||||
// --- INIZIALIZZAZIONE ---
|
||||
Future<void> initForm({
|
||||
required String companyId,
|
||||
ProviderModel? existingProvider,
|
||||
}) async {
|
||||
emit(state.copyWith(status: ProviderFormStatus.loading));
|
||||
|
||||
try {
|
||||
// 1. Scarichiamo tutti i negozi dell'azienda
|
||||
final storesResponse = await _client
|
||||
.from('store')
|
||||
.select('id, name')
|
||||
.eq('company_id', companyId);
|
||||
|
||||
// 2. Se stiamo modificando, carichiamo gli store collegati
|
||||
List<String> linkedStoreIds = [];
|
||||
if (existingProvider != null && existingProvider.id != null) {
|
||||
// ... (Vecchio codice di recupero)
|
||||
final links = await _client
|
||||
.from('providers_in_stores')
|
||||
.select('store_id')
|
||||
.eq('provider_id', existingProvider.id!);
|
||||
linkedStoreIds = (links as List)
|
||||
.map((l) => l['store_id'] as String)
|
||||
.toList();
|
||||
} else {
|
||||
// --- IL TOCCO NINJA: AUTO-SELEZIONE ---
|
||||
// Se stiamo creando un nuovo fornitore e c'è 1 solo negozio in tutto il DB, accendilo!
|
||||
if ((storesResponse as List).length == 1) {
|
||||
linkedStoreIds.add(storesResponse.first['id'] as String);
|
||||
}
|
||||
}
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
status: ProviderFormStatus.initial,
|
||||
provider: existingProvider ?? ProviderModel.empty(companyId: ''),
|
||||
availableStores: storesResponse as List<dynamic>,
|
||||
selectedStoreIds: linkedStoreIds,
|
||||
localLocations: existingProvider?.locations ?? [],
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
status: ProviderFormStatus.failure,
|
||||
errorMessage: 'Errore durante l\'inizializzazione: $e',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// --- AGGIORNAMENTO CAMPI ---
|
||||
void updateFields({
|
||||
String? name,
|
||||
String? businessName,
|
||||
String? vatNumber,
|
||||
String? fiscalCode,
|
||||
String? sdiCode,
|
||||
String? emailPec,
|
||||
}) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
provider: state.provider.copyWith(
|
||||
name: name,
|
||||
businessName: businessName,
|
||||
vatNumber: vatNumber,
|
||||
fiscalCode: fiscalCode,
|
||||
sdiCode: sdiCode,
|
||||
emailPec: emailPec,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// --- GESTIONE RUOLI (CHIPS) ---
|
||||
void toggleRole(ProviderRole role) {
|
||||
final currentRoles = List<ProviderRole>.from(state.provider.roles);
|
||||
if (currentRoles.contains(role)) {
|
||||
currentRoles.remove(role);
|
||||
} else {
|
||||
currentRoles.add(role);
|
||||
}
|
||||
emit(
|
||||
state.copyWith(provider: state.provider.copyWith(roles: currentRoles)),
|
||||
);
|
||||
}
|
||||
|
||||
// --- GESTIONE NEGOZI ABILITATI (CHECKBOX) ---
|
||||
void toggleStore(String storeId) {
|
||||
final currentStoreIds = List<String>.from(state.selectedStoreIds);
|
||||
if (currentStoreIds.contains(storeId)) {
|
||||
currentStoreIds.remove(storeId);
|
||||
} else {
|
||||
currentStoreIds.add(storeId);
|
||||
}
|
||||
emit(state.copyWith(selectedStoreIds: currentStoreIds));
|
||||
}
|
||||
|
||||
Future<void> addLocationLocal(ProviderLocationModel location) async {
|
||||
final currentLocations = List<ProviderLocationModel>.from(
|
||||
state.localLocations,
|
||||
);
|
||||
currentLocations.add(location);
|
||||
emit(state.copyWith(localLocations: currentLocations));
|
||||
}
|
||||
|
||||
void removeLocationLocal(int index) {
|
||||
final currentLocations = List<ProviderLocationModel>.from(
|
||||
state.localLocations,
|
||||
);
|
||||
if (index >= 0 && index < currentLocations.length) {
|
||||
currentLocations.removeAt(index);
|
||||
emit(state.copyWith(localLocations: currentLocations));
|
||||
}
|
||||
}
|
||||
|
||||
// --- SALVATAGGIO FINALE ---
|
||||
Future<void> save() async {
|
||||
// Sicurezza di base
|
||||
if (state.provider.name.trim().isEmpty) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
status: ProviderFormStatus.failure,
|
||||
errorMessage: 'Il nome è obbligatorio',
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
emit(state.copyWith(status: ProviderFormStatus.loading));
|
||||
|
||||
try {
|
||||
// Passiamo provider e storeId al repository che farà la magia
|
||||
final savedProvider = await _repository.saveProvider(
|
||||
state.provider,
|
||||
state.selectedStoreIds,
|
||||
);
|
||||
|
||||
if (state.localLocations.isNotEmpty) {
|
||||
for (var loc in state.localLocations) {
|
||||
final locToSave = loc.copyWith(
|
||||
providerId: savedProvider.id!,
|
||||
companyId: savedProvider.companyId,
|
||||
);
|
||||
await _repository.saveLocation(locToSave);
|
||||
}
|
||||
}
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
status: ProviderFormStatus.success,
|
||||
provider: savedProvider,
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
status: ProviderFormStatus.failure,
|
||||
errorMessage: 'Errore di salvataggio: $e',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
part of 'provider_form_cubit.dart';
|
||||
|
||||
// Importa il tuo StoreModel se lo hai
|
||||
|
||||
enum ProviderFormStatus { initial, loading, success, failure }
|
||||
|
||||
class ProviderFormState extends Equatable {
|
||||
final ProviderFormStatus status;
|
||||
final ProviderModel provider;
|
||||
|
||||
// Dati di supporto per l'interfaccia
|
||||
final List<dynamic>
|
||||
availableStores; // Metti List<StoreModel> se hai il modello
|
||||
final List<String> selectedStoreIds; // IDs dei negozi in cui è attivo
|
||||
final List<ProviderLocationModel>
|
||||
localLocations; // Sedi aggiunte prima del salvataggio
|
||||
final String? errorMessage;
|
||||
|
||||
const ProviderFormState({
|
||||
this.status = ProviderFormStatus.initial,
|
||||
required this.provider,
|
||||
this.availableStores = const [],
|
||||
this.selectedStoreIds = const [],
|
||||
this.localLocations = const [],
|
||||
this.errorMessage,
|
||||
});
|
||||
|
||||
ProviderFormState copyWith({
|
||||
ProviderFormStatus? status,
|
||||
ProviderModel? provider,
|
||||
List<dynamic>? availableStores,
|
||||
List<String>? selectedStoreIds,
|
||||
List<ProviderLocationModel>? localLocations,
|
||||
String? errorMessage,
|
||||
}) {
|
||||
return ProviderFormState(
|
||||
status: status ?? this.status,
|
||||
provider: provider ?? this.provider,
|
||||
availableStores: availableStores ?? this.availableStores,
|
||||
selectedStoreIds: selectedStoreIds ?? this.selectedStoreIds,
|
||||
localLocations: localLocations ?? this.localLocations,
|
||||
errorMessage: errorMessage ?? this.errorMessage,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
status,
|
||||
provider,
|
||||
availableStores,
|
||||
selectedStoreIds,
|
||||
localLocations,
|
||||
errorMessage,
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import '../models/provider_model.dart';
|
||||
import '../data/provider_repository.dart';
|
||||
|
||||
part 'provider_list_state.dart';
|
||||
|
||||
class ProviderListCubit extends Cubit<ProviderListState> {
|
||||
final ProviderRepository _repository = GetIt.I.get<ProviderRepository>();
|
||||
|
||||
ProviderListCubit() : super(const ProviderListState());
|
||||
|
||||
Future<void> loadProviders(String storeId) async {
|
||||
emit(state.copyWith(status: ProviderListStatus.loading));
|
||||
try {
|
||||
final providers = await _repository.getProvidersByStore(storeId);
|
||||
emit(
|
||||
state.copyWith(
|
||||
status: ProviderListStatus.success,
|
||||
providers: providers,
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
status: ProviderListStatus.failure,
|
||||
errorMessage: e.toString(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> loadAllProviders() async {
|
||||
emit(state.copyWith(status: ProviderListStatus.loading));
|
||||
try {
|
||||
final allProviders = await _repository.getAllCompanyProviders();
|
||||
emit(
|
||||
state.copyWith(
|
||||
status: ProviderListStatus.success,
|
||||
allProviders: allProviders,
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
status: ProviderListStatus.failure,
|
||||
errorMessage: e.toString(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
part of 'provider_list_cubit.dart';
|
||||
|
||||
enum ProviderListStatus { initial, loading, success, failure }
|
||||
|
||||
class ProviderListState extends Equatable {
|
||||
final ProviderListStatus status;
|
||||
final List<ProviderModel> providers;
|
||||
final List<ProviderModel> allProviders;
|
||||
final String? errorMessage;
|
||||
|
||||
const ProviderListState({
|
||||
this.status = ProviderListStatus.initial,
|
||||
this.providers = const [],
|
||||
this.allProviders = const [],
|
||||
this.errorMessage,
|
||||
});
|
||||
|
||||
ProviderListState copyWith({
|
||||
ProviderListStatus? status,
|
||||
List<ProviderModel>? providers,
|
||||
List<ProviderModel>? allProviders,
|
||||
String? errorMessage,
|
||||
}) {
|
||||
return ProviderListState(
|
||||
status: status ?? this.status,
|
||||
providers: providers ?? this.providers,
|
||||
allProviders: allProviders ?? this.allProviders,
|
||||
errorMessage: errorMessage ?? this.errorMessage,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object?> get props => [status, providers, allProviders, errorMessage];
|
||||
}
|
||||
Reference in New Issue
Block a user