feat-ultimi_servizi-contratti_in_scadenza #12

Merged
brontomark merged 18 commits from feat-ultimi_servizi-contratti_in_scadenza into main 2026-05-04 15:36:42 +02:00
13 changed files with 156 additions and 156 deletions
Showing only changes of commit 4559db620d - Show all commits

View File

@@ -45,14 +45,14 @@ class CompanyModel extends Equatable {
final String userId; // Nel DB è user_id (chiave esterna su auth.users) final String userId; // Nel DB è user_id (chiave esterna su auth.users)
// Dati Anagrafici e Fatturazione // Dati Anagrafici e Fatturazione
final String ragioneSociale; final String name;
final String indirizzo; final String address;
final String cap; final String zipCode;
final String citta; final String city;
final String provincia; final String province;
final String partitaIva; final String vatId;
final String codiceFiscale; final String fiscalCode;
final String codiceUnivoco; final String sdi;
final String companyLogo; final String companyLogo;
// Stato Pagamenti (Ibride: manuale + Stripe) // Stato Pagamenti (Ibride: manuale + Stripe)
@@ -70,14 +70,14 @@ class CompanyModel extends Equatable {
this.id, this.id,
this.createdAt, this.createdAt,
required this.userId, required this.userId,
required this.ragioneSociale, required this.name,
required this.indirizzo, required this.address,
required this.cap, required this.zipCode,
required this.citta, required this.city,
required this.provincia, required this.province,
required this.partitaIva, required this.vatId,
required this.codiceFiscale, required this.fiscalCode,
required this.codiceUnivoco, required this.sdi,
this.companyLogo = '', this.companyLogo = '',
this.isPaid = false, this.isPaid = false,
this.paymentExpiration, this.paymentExpiration,
@@ -92,14 +92,14 @@ class CompanyModel extends Equatable {
String? id, String? id,
DateTime? createdAt, DateTime? createdAt,
String? userId, String? userId,
String? ragioneSociale, String? name,
String? indirizzo, String? address,
String? cap, String? zipCode,
String? citta, String? city,
String? provincia, String? province,
String? partitaIva, String? vatId,
String? codiceFiscale, String? fiscalCode,
String? codiceUnivoco, String? sdi,
String? companyLogo, String? companyLogo,
bool? isPaid, bool? isPaid,
DateTime? paymentExpiration, DateTime? paymentExpiration,
@@ -113,14 +113,14 @@ class CompanyModel extends Equatable {
id: id ?? this.id, id: id ?? this.id,
createdAt: createdAt ?? this.createdAt, createdAt: createdAt ?? this.createdAt,
userId: userId ?? this.userId, userId: userId ?? this.userId,
ragioneSociale: ragioneSociale ?? this.ragioneSociale, name: name ?? this.name,
indirizzo: indirizzo ?? this.indirizzo, address: address ?? this.address,
cap: cap ?? this.cap, zipCode: zipCode ?? this.zipCode,
citta: citta ?? this.citta, city: city ?? this.city,
provincia: provincia ?? this.provincia, province: province ?? this.province,
partitaIva: partitaIva ?? this.partitaIva, vatId: vatId ?? this.vatId,
codiceFiscale: codiceFiscale ?? this.codiceFiscale, fiscalCode: fiscalCode ?? this.fiscalCode,
codiceUnivoco: codiceUnivoco ?? this.codiceUnivoco, sdi: sdi ?? this.sdi,
companyLogo: companyLogo ?? this.companyLogo, companyLogo: companyLogo ?? this.companyLogo,
isPaid: isPaid ?? this.isPaid, isPaid: isPaid ?? this.isPaid,
paymentExpiration: paymentExpiration ?? this.paymentExpiration, paymentExpiration: paymentExpiration ?? this.paymentExpiration,
@@ -137,14 +137,14 @@ class CompanyModel extends Equatable {
id: null, id: null,
createdAt: null, createdAt: null,
userId: '', userId: '',
ragioneSociale: '', name: '',
indirizzo: '', address: '',
cap: '', zipCode: '',
citta: '', city: '',
provincia: '', province: '',
partitaIva: '', vatId: '',
codiceFiscale: '', fiscalCode: '',
codiceUnivoco: '', sdi: '',
); );
} }
@@ -155,14 +155,14 @@ class CompanyModel extends Equatable {
? DateTime.tryParse(map['created_at']) ? DateTime.tryParse(map['created_at'])
: null, : null,
userId: map['user_id'] ?? '', userId: map['user_id'] ?? '',
ragioneSociale: map['ragione_sociale'] ?? '', name: map['name'] ?? '',
indirizzo: map['indirizzo'] ?? '', address: map['address'] ?? '',
cap: map['cap'] ?? '', zipCode: map['zip_code'] ?? '',
citta: map['citta'] ?? '', city: map['city'] ?? '',
provincia: map['provincia'] ?? '', province: map['province'] ?? '',
partitaIva: map['partita_iva'] ?? '', vatId: map['vat_id'] ?? '',
codiceFiscale: map['codice_fiscale'] ?? '', fiscalCode: map['fiscal_code'] ?? '',
codiceUnivoco: map['codice_univoco'] ?? '', sdi: map['sdi'] ?? '',
companyLogo: map['company_logo'] ?? '', companyLogo: map['company_logo'] ?? '',
isPaid: map['is_paid'] ?? false, isPaid: map['is_paid'] ?? false,
paymentExpiration: map['payment_expiration'] != null paymentExpiration: map['payment_expiration'] != null
@@ -185,14 +185,14 @@ class CompanyModel extends Equatable {
if (id != null) 'id': id, if (id != null) 'id': id,
// created_at è gestito dal DB di default, di solito non si passa nell'insert // created_at è gestito dal DB di default, di solito non si passa nell'insert
'user_id': userId, 'user_id': userId,
'ragione_sociale': ragioneSociale, 'name': name,
'indirizzo': indirizzo, 'address': address,
'cap': cap, 'zip_code': zipCode,
'citta': citta, 'city': city,
'provincia': provincia, 'province': province,
'partita_iva': partitaIva, 'vat_id': vatId,
'codice_fiscale': codiceFiscale, 'fiscal_code': fiscalCode,
'codice_univoco': codiceUnivoco, 'sdi': sdi,
'company_logo': companyLogo, 'company_logo': companyLogo,
'is_paid': isPaid, 'is_paid': isPaid,
if (paymentExpiration != null) if (paymentExpiration != null)
@@ -213,14 +213,14 @@ class CompanyModel extends Equatable {
id, id,
createdAt, createdAt,
userId, userId,
ragioneSociale, name,
indirizzo, address,
cap, zipCode,
citta, city,
provincia, province,
partitaIva, vatId,
codiceFiscale, fiscalCode,
codiceUnivoco, sdi,
companyLogo, companyLogo,
isPaid, isPaid,
paymentExpiration, paymentExpiration,

View File

@@ -50,14 +50,14 @@ class _CreateCompanyScreenState extends State<CreateCompanyScreen> {
final company = CompanyModel( final company = CompanyModel(
userId: userId, userId: userId,
ragioneSociale: _ragioneSocialeController.text.trim(), name: _ragioneSocialeController.text.trim(),
indirizzo: _indirizzoController.text.trim(), address: _indirizzoController.text.trim(),
cap: _capController.text.trim(), zipCode: _capController.text.trim(),
citta: _cittaController.text.trim(), city: _cittaController.text.trim(),
provincia: _provinciaController.text.trim(), province: _provinciaController.text.trim(),
partitaIva: _pIvaController.text.trim(), vatId: _pIvaController.text.trim(),
codiceFiscale: _cfController.text.trim(), fiscalCode: _cfController.text.trim(),
codiceUnivoco: _univocoController.text.trim().toUpperCase(), sdi: _univocoController.text.trim().toUpperCase(),
// Gli altri campi hanno i default nel modello // Gli altri campi hanno i default nel modello
); );

View File

@@ -149,7 +149,7 @@ class HomeScreen extends StatelessWidget {
Icon(Icons.storefront, size: 16, color: context.primary), Icon(Icons.storefront, size: 16, color: context.primary),
const SizedBox(width: 8), const SizedBox(width: 8),
Text( Text(
currentStore?.nome ?? context.l10n.homeNoStoreFound, currentStore?.name ?? context.l10n.homeNoStoreFound,
style: TextStyle( style: TextStyle(
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: context.primary, color: context.primary,
@@ -352,7 +352,7 @@ class HomeScreen extends StatelessWidget {
: theme.iconTheme.color, : theme.iconTheme.color,
), ),
title: Text( title: Text(
store.nome, store.name,
style: TextStyle( style: TextStyle(
fontWeight: isSelected fontWeight: isSelected
? FontWeight.bold ? FontWeight.bold

View File

@@ -172,7 +172,7 @@ class _ProviderFormSheetState extends State<ProviderFormSheet> {
store.id, store.id,
); );
return CheckboxListTile( return CheckboxListTile(
title: Text(store.nome), title: Text(store.name),
value: isAssociated, value: isAssociated,
onChanged: (val) { onChanged: (val) {
setState(() { setState(() {

View File

@@ -126,7 +126,7 @@ class _StaffScreenState extends State<StaffScreen> {
initialValue: _selectedStoreId, initialValue: _selectedStoreId,
decoration: const InputDecoration(labelText: "Filtra per Negozio"), decoration: const InputDecoration(labelText: "Filtra per Negozio"),
items: state.stores items: state.stores
.map((s) => DropdownMenuItem(value: s.id, child: Text(s.nome))) .map((s) => DropdownMenuItem(value: s.id, child: Text(s.name)))
.toList(), .toList(),
onChanged: (id) { onChanged: (id) {
setState(() => _selectedStoreId = id); setState(() => _selectedStoreId = id);
@@ -355,7 +355,7 @@ class _StaffScreenState extends State<StaffScreen> {
store.id, store.id,
); );
return FilterChip( return FilterChip(
label: Text(store.nome), label: Text(store.name),
selected: isSelected, selected: isSelected,
onSelected: (selected) { onSelected: (selected) {
setModalState(() { setModalState(() {

View File

@@ -4,30 +4,30 @@ import 'package:flux/features/master_data/staff/models/staff_member_model.dart';
class StoreModel extends Equatable { class StoreModel extends Equatable {
final String? id; final String? id;
final String nome; final String name;
final String companyId; final String companyId;
final bool isActive; final bool isActive;
final bool isPaid; final bool isPaid;
final DateTime? paymentExpiration; final DateTime? paymentExpiration;
final String indirizzo; final String address;
final String cap; final String zipCode;
final String comune; final String city;
final String provincia; final String province;
final List<ProviderModel> associatedProviders; // Provider associati final List<ProviderModel> associatedProviders; // Provider associati
final List<StaffMemberModel> final List<StaffMemberModel>
associatedStaffMembers; // Membri dello staff associati associatedStaffMembers; // Membri dello staff associati
const StoreModel({ const StoreModel({
this.id, this.id,
required this.nome, required this.name,
required this.companyId, required this.companyId,
this.isActive = true, this.isActive = true,
this.isPaid = false, this.isPaid = false,
this.paymentExpiration, this.paymentExpiration,
required this.indirizzo, required this.address,
required this.cap, required this.zipCode,
required this.comune, required this.city,
required this.provincia, required this.province,
this.associatedProviders = const [], this.associatedProviders = const [],
this.associatedStaffMembers = const [], this.associatedStaffMembers = const [],
}); });
@@ -36,15 +36,15 @@ class StoreModel extends Equatable {
@override @override
List<Object?> get props => [ List<Object?> get props => [
id, id,
nome, name,
companyId, companyId,
isActive, isActive,
isPaid, isPaid,
paymentExpiration, paymentExpiration,
indirizzo, address,
cap, zipCode,
comune, city,
provincia, province,
associatedProviders, associatedProviders,
associatedStaffMembers, associatedStaffMembers,
]; ];
@@ -52,29 +52,29 @@ class StoreModel extends Equatable {
// Il mitico copyWith per creare nuove istanze modificando solo ciò che serve // Il mitico copyWith per creare nuove istanze modificando solo ciò che serve
StoreModel copyWith({ StoreModel copyWith({
String? id, String? id,
String? nome, String? name,
String? companyId, String? companyId,
bool? isActive, bool? isActive,
bool? isPaid, bool? isPaid,
DateTime? paymentExpiration, DateTime? paymentExpiration,
String? indirizzo, String? address,
String? cap, String? zipCode,
String? comune, String? city,
String? provincia, String? province,
List<ProviderModel>? associatedProviders, List<ProviderModel>? associatedProviders,
List<StaffMemberModel>? associatedStaffMembers, List<StaffMemberModel>? associatedStaffMembers,
}) { }) {
return StoreModel( return StoreModel(
id: id ?? this.id, id: id ?? this.id,
nome: nome ?? this.nome, name: name ?? this.name,
companyId: companyId ?? this.companyId, companyId: companyId ?? this.companyId,
isActive: isActive ?? this.isActive, isActive: isActive ?? this.isActive,
isPaid: isPaid ?? this.isPaid, isPaid: isPaid ?? this.isPaid,
paymentExpiration: paymentExpiration ?? this.paymentExpiration, paymentExpiration: paymentExpiration ?? this.paymentExpiration,
indirizzo: indirizzo ?? this.indirizzo, address: address ?? this.address,
cap: cap ?? this.cap, zipCode: zipCode ?? this.zipCode,
comune: comune ?? this.comune, city: city ?? this.city,
provincia: provincia ?? this.provincia, province: province ?? this.province,
associatedProviders: associatedProviders ?? this.associatedProviders, associatedProviders: associatedProviders ?? this.associatedProviders,
associatedStaffMembers: associatedStaffMembers:
associatedStaffMembers ?? this.associatedStaffMembers, associatedStaffMembers ?? this.associatedStaffMembers,
@@ -83,12 +83,12 @@ class StoreModel extends Equatable {
factory StoreModel.empty() { factory StoreModel.empty() {
return const StoreModel( return const StoreModel(
nome: '', name: '',
companyId: '', companyId: '',
indirizzo: '', address: '',
cap: '', zipCode: '',
comune: '', city: '',
provincia: '', province: '',
); );
} }
@@ -118,17 +118,17 @@ class StoreModel extends Equatable {
} }
return StoreModel( return StoreModel(
id: map['id'] as String, id: map['id'] as String,
nome: map['nome'], name: map['name'],
companyId: map['company_id'] as String, companyId: map['company_id'] as String,
isActive: map['is_active'] ?? true, isActive: map['is_active'] ?? true,
isPaid: map['is_paid'] ?? false, isPaid: map['is_paid'] ?? false,
paymentExpiration: map['payment_expiration'] != null paymentExpiration: map['payment_expiration'] != null
? DateTime.parse(map['payment_expiration']) ? DateTime.parse(map['payment_expiration'])
: null, : null,
indirizzo: map['indirizzo'], address: map['address'],
cap: map['cap'], zipCode: map['zip_code'],
comune: map['comune'], city: map['city'],
provincia: map['provincia'], province: map['province'],
associatedProviders: providers, associatedProviders: providers,
associatedStaffMembers: staffMembers, associatedStaffMembers: staffMembers,
); );
@@ -137,16 +137,16 @@ class StoreModel extends Equatable {
Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
return { return {
if (id != null) 'id': id, if (id != null) 'id': id,
'nome': nome, 'name': name,
'company_id': companyId, 'company_id': companyId,
'is_active': isActive, 'is_active': isActive,
'is_paid': isPaid, 'is_paid': isPaid,
if (paymentExpiration != null) if (paymentExpiration != null)
'payment_expiration': paymentExpiration!.toIso8601String(), 'payment_expiration': paymentExpiration!.toIso8601String(),
'indirizzo': indirizzo, 'address': address,
'cap': cap, 'zip_code': zipCode,
'comune': comune, 'city': city,
'provincia': provincia, 'province': province,
}; };
} }
} }

View File

@@ -37,14 +37,14 @@ class _CreateStoreScreenState extends State<CreateStoreScreen> {
final company = context.read<SessionCubit>().state.company; final company = context.read<SessionCubit>().state.company;
if (company != null) { if (company != null) {
setState(() { setState(() {
_indirizzoController.text = company.indirizzo; _indirizzoController.text = company.address;
_capController.text = company.cap; _capController.text = company.zipCode;
_comuneController.text = _comuneController.text =
company.citta; // Nel DB company è 'citta', store è 'comune' company.city; // Nel DB company è 'citta', store è 'comune'
_provinciaController.text = company.provincia; _provinciaController.text = company.province;
// Suggeriamo anche un nome se vuoto // Suggeriamo anche un nome se vuoto
if (_nomeController.text.isEmpty) { if (_nomeController.text.isEmpty) {
_nomeController.text = '${company.ragioneSociale} - Sede'; _nomeController.text = '${company.name} - Sede';
} }
}); });
@@ -68,12 +68,12 @@ class _CreateStoreScreenState extends State<CreateStoreScreen> {
} }
final store = StoreModel( final store = StoreModel(
nome: _nomeController.text.trim(), name: _nomeController.text.trim(),
companyId: company.id!, companyId: company.id!,
indirizzo: _indirizzoController.text.trim(), address: _indirizzoController.text.trim(),
cap: _capController.text.trim(), zipCode: _capController.text.trim(),
comune: _comuneController.text.trim(), city: _comuneController.text.trim(),
provincia: _provinciaController.text.trim().toUpperCase(), province: _provinciaController.text.trim().toUpperCase(),
); );
context.read<StoreCubit>().createStore(store); context.read<StoreCubit>().createStore(store);

View File

@@ -53,11 +53,11 @@ class _StoreCardState extends State<StoreCard> {
color: widget.store.isActive ? context.accent : Colors.grey, color: widget.store.isActive ? context.accent : Colors.grey,
), ),
title: Text( title: Text(
widget.store.nome, widget.store.name,
style: const TextStyle(fontWeight: FontWeight.bold), style: const TextStyle(fontWeight: FontWeight.bold),
), ),
subtitle: Text( subtitle: Text(
"${widget.store.comune} (${widget.store.provincia}) - ${widget.store.indirizzo}", "${widget.store.city} (${widget.store.province}) - ${widget.store.address}",
), ),
trailing: Switch( trailing: Switch(
value: widget.store.isActive, value: widget.store.isActive,
@@ -129,7 +129,7 @@ class _StoreCardState extends State<StoreCard> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Text( Text(
"Personale di ${store.nome}", "Personale di ${store.name}",
style: context.titleLarge, style: context.titleLarge,
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
@@ -184,7 +184,7 @@ class _StoreCardState extends State<StoreCard> {
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Text("Providers di ${store.nome}", style: context.titleLarge), Text("Providers di ${store.name}", style: context.titleLarge),
const SizedBox(height: 16), const SizedBox(height: 16),
...state.allProviders.map((provider) { ...state.allProviders.map((provider) {
final isAssociated = _tempAssociatedProviders.any( final isAssociated = _tempAssociatedProviders.any(

View File

@@ -24,11 +24,11 @@ class _StoreFormState extends State<StoreForm> {
void initState() { void initState() {
super.initState(); super.initState();
if (widget.store != null) { if (widget.store != null) {
nomeController.text = widget.store!.nome; nomeController.text = widget.store!.name;
indirizzoController.text = widget.store!.indirizzo; indirizzoController.text = widget.store!.address;
capController.text = widget.store!.cap; capController.text = widget.store!.zipCode;
comuneController.text = widget.store!.comune; comuneController.text = widget.store!.city;
provinciaController.text = widget.store!.provincia; provinciaController.text = widget.store!.province;
} }
} }
@@ -124,11 +124,11 @@ class _StoreFormState extends State<StoreForm> {
id: widget id: widget
.store .store
?.id, // Se nullo, Supabase ne crea uno nuovo ?.id, // Se nullo, Supabase ne crea uno nuovo
nome: nomeController.text, name: nomeController.text,
indirizzo: indirizzoController.text, address: indirizzoController.text,
cap: capController.text, zipCode: capController.text,
comune: comuneController.text, city: comuneController.text,
provincia: provinciaController.text, province: provinciaController.text,
companyId: context companyId: context
.read<SessionCubit>() .read<SessionCubit>()
.state .state

View File

@@ -25,7 +25,7 @@ class OnboardingCubit extends Cubit<OnboardingState> {
Future<void> saveCompany(String companyName) async { Future<void> saveCompany(String companyName) async {
emit(state.copyWith(isLoading: true)); emit(state.copyWith(isLoading: true));
final company = CompanyModel.empty().copyWith( final company = CompanyModel.empty().copyWith(
ragioneSociale: companyName, name: companyName,
userId: GetIt.I<SupabaseClient>().auth.currentUser!.id, userId: GetIt.I<SupabaseClient>().auth.currentUser!.id,
subscriptionTier: SubscriptionTier.pro, subscriptionTier: SubscriptionTier.pro,
subscriptionStatus: SubscriptionStatus.trialing, subscriptionStatus: SubscriptionStatus.trialing,

View File

@@ -135,12 +135,12 @@ class _StoreOnboardingFormState extends State<StoreOnboardingForm> {
if (_formKey.currentState!.validate()) { if (_formKey.currentState!.validate()) {
// MIRACOLO DELLA FACTORY EMPTY! // MIRACOLO DELLA FACTORY EMPTY!
final newStore = StoreModel.empty().copyWith( final newStore = StoreModel.empty().copyWith(
nome: _nameCtrl.text.trim(), name: _nameCtrl.text.trim(),
indirizzo: _addressCtrl.text.trim(), address: _addressCtrl.text.trim(),
comune: _cityCtrl.text.trim(), city: _cityCtrl.text.trim(),
cap: _zipCodeCtrl.text.trim(), zipCode: _zipCodeCtrl.text.trim(),
// Formattiamo in maiuscolo qui, al momento del salvataggio! // Formattiamo in maiuscolo qui, al momento del salvataggio!
provincia: _provinceCtrl.text.trim().toUpperCase(), province: _provinceCtrl.text.trim().toUpperCase(),
); );
context.read<OnboardingCubit>().saveStore(newStore); context.read<OnboardingCubit>().saveStore(newStore);
} }

View File

@@ -23,7 +23,7 @@ class OperationsRepository {
staff_member(name), staff_member(name),
provider(name), provider(name),
model(name_with_brand), model(name_with_brand),
attachments(*) attachment(*)
''') ''')
.eq('id', id) .eq('id', id)
.single(); .single();
@@ -52,7 +52,7 @@ class OperationsRepository {
provider(name), provider(name),
model(name_with_brand), model(name_with_brand),
staff_member(name), staff_member(name),
attachments(*) attachment(*)
''') ''')
.eq('company_id', companyId); .eq('company_id', companyId);
@@ -122,7 +122,7 @@ class OperationsRepository {
provider(name), provider(name),
model(name_with_brand), model(name_with_brand),
customer(name), customer(name),
attachments(*) attachment(*)
''') ''')
.eq('id', newId) .eq('id', newId)
.single(); .single();

View File

@@ -1021,12 +1021,12 @@ class _OperationFormScreenState extends State<OperationFormScreen> {
), ),
), ),
onTap: () { onTap: () {
context.read<OperationsCubit>().updateOperationFields( context
modelId: .read<OperationsCubit>()
'id_del_modello_$index', // deviceModel.id .updateOperationFields(
// Assicurati di avere questo campo in _updateOperationFields nel Cubit! modelId: deviceModel.id,
// modelDisplayName: deviceModel.nameWithBrand, modelDisplayName: deviceModel.nameWithBrand,
); );
Navigator.pop(modalContext); Navigator.pop(modalContext);
}, },
); );