444 lines
12 KiB
Dart
444 lines
12 KiB
Dart
// Models/client.dart - Version corrigée pour MySQL
|
||
class Client {
|
||
final int? id;
|
||
final String nom;
|
||
final String prenom;
|
||
final String email;
|
||
final String telephone;
|
||
final String? adresse;
|
||
final DateTime dateCreation;
|
||
final bool actif;
|
||
|
||
Client({
|
||
this.id,
|
||
required this.nom,
|
||
required this.prenom,
|
||
required this.email,
|
||
required this.telephone,
|
||
this.adresse,
|
||
required this.dateCreation,
|
||
this.actif = true,
|
||
});
|
||
|
||
Map<String, dynamic> toMap() {
|
||
return {
|
||
'id': id,
|
||
'nom': nom,
|
||
'prenom': prenom,
|
||
'email': email,
|
||
'telephone': telephone,
|
||
'adresse': adresse,
|
||
'dateCreation': dateCreation.toIso8601String(),
|
||
'actif': actif ? 1 : 0,
|
||
};
|
||
}
|
||
|
||
// Fonction helper améliorée pour parser les dates
|
||
static DateTime _parseDateTime(dynamic dateValue) {
|
||
if (dateValue == null) return DateTime.now();
|
||
|
||
if (dateValue is DateTime) return dateValue;
|
||
|
||
if (dateValue is String) {
|
||
try {
|
||
return DateTime.parse(dateValue);
|
||
} catch (e) {
|
||
print("Erreur parsing date string: $dateValue, erreur: $e");
|
||
return DateTime.now();
|
||
}
|
||
}
|
||
|
||
// Pour MySQL qui peut retourner un Timestamp
|
||
if (dateValue is int) {
|
||
return DateTime.fromMillisecondsSinceEpoch(dateValue);
|
||
}
|
||
|
||
print(
|
||
"Type de date non reconnu: ${dateValue.runtimeType}, valeur: $dateValue");
|
||
return DateTime.now();
|
||
}
|
||
|
||
factory Client.fromMap(Map<String, dynamic> map) {
|
||
return Client(
|
||
id: map['id'] as int?,
|
||
nom: map['nom'] as String,
|
||
prenom: map['prenom'] as String,
|
||
email: map['email'] as String,
|
||
telephone: map['telephone'] as String,
|
||
adresse: map['adresse'] as String?,
|
||
dateCreation: _parseDateTime(map['dateCreation']),
|
||
actif: (map['actif'] as int?) == 1,
|
||
);
|
||
}
|
||
|
||
String get nomComplet => '$prenom $nom';
|
||
}
|
||
|
||
enum StatutCommande { enAttente, confirmee, annulee }
|
||
|
||
class Commande {
|
||
final int? id;
|
||
final int clientId;
|
||
final DateTime dateCommande;
|
||
final StatutCommande statut;
|
||
final double montantTotal;
|
||
final String? notes;
|
||
final DateTime? dateLivraison;
|
||
final int? commandeurId;
|
||
final String? commandeurnom;
|
||
final String? commandeurPrenom;
|
||
final int? validateurId;
|
||
final String? clientNom;
|
||
final String? clientPrenom;
|
||
final String? clientEmail;
|
||
final int? pointDeVenteId;
|
||
final String? pointDeVenteDesign;
|
||
|
||
Commande({
|
||
this.id,
|
||
required this.clientId,
|
||
required this.dateCommande,
|
||
required this.statut,
|
||
required this.montantTotal,
|
||
this.notes,
|
||
this.dateLivraison,
|
||
this.commandeurId,
|
||
this.commandeurnom,
|
||
this.commandeurPrenom,
|
||
this.validateurId,
|
||
this.clientNom,
|
||
this.clientPrenom,
|
||
this.clientEmail,
|
||
this.pointDeVenteId,
|
||
this.pointDeVenteDesign,
|
||
});
|
||
|
||
String get clientNomComplet {
|
||
if (clientNom != null && clientPrenom != null) {
|
||
return '$clientPrenom $clientNom';
|
||
}
|
||
return 'Client inconnu';
|
||
}
|
||
|
||
String get statutLibelle {
|
||
switch (statut) {
|
||
case StatutCommande.enAttente:
|
||
return 'En attente';
|
||
case StatutCommande.confirmee:
|
||
return 'Confirmée';
|
||
case StatutCommande.annulee:
|
||
return 'Annulée';
|
||
}
|
||
}
|
||
|
||
Map<String, dynamic> toMap() {
|
||
return {
|
||
'id': id,
|
||
'clientId': clientId,
|
||
'dateCommande': dateCommande.toIso8601String(),
|
||
'statut': statut.index,
|
||
'montantTotal': montantTotal,
|
||
'notes': notes,
|
||
'dateLivraison': dateLivraison?.toIso8601String(),
|
||
'commandeurId': commandeurId,
|
||
'validateurId': validateurId,
|
||
};
|
||
}
|
||
|
||
factory Commande.fromMap(Map<String, dynamic> map) {
|
||
return Commande(
|
||
id: map['id'] as int?,
|
||
clientId: map['clientId'] as int,
|
||
dateCommande: Client._parseDateTime(map['dateCommande']),
|
||
statut: StatutCommande.values[(map['statut'] as int)],
|
||
montantTotal: (map['montantTotal'] as num).toDouble(),
|
||
notes: map['notes'] as String?,
|
||
dateLivraison: map['dateLivraison'] != null
|
||
? Client._parseDateTime(map['dateLivraison'])
|
||
: null,
|
||
commandeurId: map['commandeurId'] as int?,
|
||
commandeurnom: map['commandeurnom'] as String?,
|
||
commandeurPrenom: map['commandeurPrenom'] as String?,
|
||
validateurId: map['validateurId'] as int?,
|
||
clientNom: map['clientNom'] as String?,
|
||
clientPrenom: map['clientPrenom'] as String?,
|
||
clientEmail: map['clientEmail'] as String?,
|
||
pointDeVenteId: map['pointDeVenteId'] as int?,
|
||
pointDeVenteDesign: map['pointDeVenteDesign'] as String?,
|
||
);
|
||
}
|
||
}
|
||
|
||
// REMPLACEZ COMPLÈTEMENT votre classe DetailCommande dans Models/client.dart par celle-ci :
|
||
enum RemiseType { pourcentage, montant }
|
||
|
||
class DetailCommande {
|
||
final int? id;
|
||
final int commandeId;
|
||
final int produitId;
|
||
final int quantite;
|
||
final double prixUnitaire;
|
||
final double sousTotal; // Prix unitaire × quantité (avant remise)
|
||
final RemiseType? remiseType;
|
||
final double remiseValeur; // Valeur de la remise (% ou montant)
|
||
final double montantRemise; // Montant de la remise calculé
|
||
final double prixFinal; // Prix final après remise
|
||
final bool estCadeau; // NOUVEAU : Indique si l'article est un cadeau
|
||
final String? produitNom;
|
||
final String? produitImage;
|
||
final String? produitReference;
|
||
final String? produitImei; // NOUVEAU : IMEI du produit, si applicable
|
||
|
||
DetailCommande({
|
||
this.id,
|
||
required this.commandeId,
|
||
required this.produitId,
|
||
required this.quantite,
|
||
required this.prixUnitaire,
|
||
required this.sousTotal,
|
||
this.remiseType,
|
||
this.remiseValeur = 0.0,
|
||
this.montantRemise = 0.0,
|
||
required this.prixFinal,
|
||
this.estCadeau = false,
|
||
this.produitNom,
|
||
this.produitImage,
|
||
this.produitReference,
|
||
this.produitImei,
|
||
});
|
||
|
||
// Constructeur pour créer un détail sans remise
|
||
factory DetailCommande.sansRemise({
|
||
int? id,
|
||
required int commandeId,
|
||
required int produitId,
|
||
required int quantite,
|
||
required double prixUnitaire,
|
||
bool estCadeau = false,
|
||
String? produitNom,
|
||
String? produitImage,
|
||
String? produitReference,
|
||
String? produitImei,
|
||
}) {
|
||
final sousTotal = quantite * prixUnitaire;
|
||
final prixFinal = estCadeau ? 0.0 : sousTotal;
|
||
|
||
return DetailCommande(
|
||
id: id,
|
||
commandeId: commandeId,
|
||
produitId: produitId,
|
||
quantite: quantite,
|
||
prixUnitaire: prixUnitaire,
|
||
sousTotal: sousTotal,
|
||
prixFinal: prixFinal,
|
||
estCadeau: estCadeau,
|
||
produitNom: produitNom,
|
||
produitImage: produitImage,
|
||
produitReference: produitReference,
|
||
produitImei: produitImei,
|
||
);
|
||
}
|
||
|
||
// NOUVEAU : Constructeur pour créer un cadeau
|
||
factory DetailCommande.cadeau({
|
||
int? id,
|
||
required int commandeId,
|
||
required int produitId,
|
||
required int quantite,
|
||
required double prixUnitaire,
|
||
String? produitNom,
|
||
String? produitImage,
|
||
String? produitReference,
|
||
String? produitImei,
|
||
}) {
|
||
return DetailCommande(
|
||
id: id,
|
||
commandeId: commandeId,
|
||
produitId: produitId,
|
||
quantite: quantite,
|
||
prixUnitaire: prixUnitaire,
|
||
sousTotal: quantite * prixUnitaire,
|
||
prixFinal: 0.0, // Prix final à 0 pour un cadeau
|
||
estCadeau: true,
|
||
produitNom: produitNom,
|
||
produitImage: produitImage,
|
||
produitReference: produitReference,
|
||
produitImei: produitImei,
|
||
);
|
||
}
|
||
|
||
// Méthode pour appliquer une remise (ne s'applique pas aux cadeaux)
|
||
DetailCommande appliquerRemise({
|
||
required RemiseType type,
|
||
required double valeur,
|
||
}) {
|
||
// Les remises ne s'appliquent pas aux cadeaux
|
||
if (estCadeau) return this;
|
||
|
||
double montantRemiseCalcule = 0.0;
|
||
|
||
if (type == RemiseType.pourcentage) {
|
||
final pourcentage = valeur.clamp(0.0, 100.0);
|
||
montantRemiseCalcule = sousTotal * (pourcentage / 100);
|
||
} else {
|
||
montantRemiseCalcule = valeur.clamp(0.0, sousTotal);
|
||
}
|
||
|
||
final prixFinalCalcule = sousTotal - montantRemiseCalcule;
|
||
|
||
return DetailCommande(
|
||
id: id,
|
||
commandeId: commandeId,
|
||
produitId: produitId,
|
||
quantite: quantite,
|
||
prixUnitaire: prixUnitaire,
|
||
sousTotal: sousTotal,
|
||
remiseType: type,
|
||
remiseValeur: valeur,
|
||
montantRemise: montantRemiseCalcule,
|
||
prixFinal: prixFinalCalcule,
|
||
estCadeau: estCadeau,
|
||
produitNom: produitNom,
|
||
produitImage: produitImage,
|
||
produitReference: produitReference,
|
||
produitImei: produitImei,
|
||
);
|
||
}
|
||
|
||
// Méthode pour supprimer la remise
|
||
DetailCommande supprimerRemise() {
|
||
return DetailCommande(
|
||
id: id,
|
||
commandeId: commandeId,
|
||
produitId: produitId,
|
||
quantite: quantite,
|
||
prixUnitaire: prixUnitaire,
|
||
sousTotal: sousTotal,
|
||
remiseType: null,
|
||
remiseValeur: 0.0,
|
||
montantRemise: 0.0,
|
||
prixFinal: estCadeau ? 0.0 : sousTotal,
|
||
estCadeau: estCadeau,
|
||
produitNom: produitNom,
|
||
produitImage: produitImage,
|
||
produitReference: produitReference,
|
||
produitImei: produitImei,
|
||
);
|
||
}
|
||
|
||
// NOUVEAU : Méthode pour convertir en cadeau
|
||
DetailCommande convertirEnCadeau() {
|
||
return DetailCommande(
|
||
id: id,
|
||
commandeId: commandeId,
|
||
produitId: produitId,
|
||
quantite: quantite,
|
||
prixUnitaire: prixUnitaire,
|
||
sousTotal: sousTotal,
|
||
remiseType: null, // Supprimer les remises lors de la conversion en cadeau
|
||
remiseValeur: 0.0,
|
||
montantRemise: 0.0,
|
||
prixFinal: 0.0,
|
||
estCadeau: true,
|
||
produitNom: produitNom,
|
||
produitImage: produitImage,
|
||
produitReference: produitReference,
|
||
produitImei: produitImei,
|
||
);
|
||
}
|
||
|
||
// NOUVEAU : Méthode pour convertir en article normal
|
||
DetailCommande convertirEnArticleNormal() {
|
||
return DetailCommande(
|
||
id: id,
|
||
commandeId: commandeId,
|
||
produitId: produitId,
|
||
quantite: quantite,
|
||
prixUnitaire: prixUnitaire,
|
||
sousTotal: sousTotal,
|
||
remiseType: remiseType,
|
||
remiseValeur: remiseValeur,
|
||
montantRemise: montantRemise,
|
||
prixFinal: estCadeau ? sousTotal - montantRemise : prixFinal,
|
||
estCadeau: false,
|
||
produitNom: produitNom,
|
||
produitImage: produitImage,
|
||
produitReference: produitReference,
|
||
produitImei: produitImei,
|
||
);
|
||
}
|
||
|
||
// Getters utiles
|
||
bool get aRemise => remiseType != null && montantRemise > 0 && !estCadeau;
|
||
bool get aimei => produitImei != null;
|
||
|
||
double get pourcentageRemise {
|
||
if (!aRemise) return 0.0;
|
||
return (montantRemise / sousTotal) * 100;
|
||
}
|
||
|
||
String get remiseDescription {
|
||
if (estCadeau) return 'CADEAU';
|
||
if (!aRemise) return '';
|
||
|
||
if (remiseType == RemiseType.pourcentage) {
|
||
return '-${remiseValeur.toStringAsFixed(0)}%';
|
||
} else {
|
||
return '-${montantRemise.toStringAsFixed(2)} MGA';
|
||
}
|
||
}
|
||
|
||
// NOUVEAU : Description du statut de l'article
|
||
String get statutDescription {
|
||
if (estCadeau) return 'CADEAU OFFERT';
|
||
if (aRemise) return 'AVEC REMISE';
|
||
return 'PRIX NORMAL';
|
||
}
|
||
|
||
Map<String, dynamic> toMap() {
|
||
return {
|
||
'id': id,
|
||
'commandeId': commandeId,
|
||
'produitId': produitId,
|
||
'quantite': quantite,
|
||
'prixUnitaire': prixUnitaire,
|
||
'sousTotal': sousTotal,
|
||
'remise_type': remiseType?.name,
|
||
'remise_valeur': remiseValeur,
|
||
'montant_remise': montantRemise,
|
||
'prix_final': prixFinal,
|
||
'est_cadeau': estCadeau ? 1 : 0,
|
||
};
|
||
}
|
||
|
||
factory DetailCommande.fromMap(Map<String, dynamic> map) {
|
||
RemiseType? type;
|
||
if (map['remise_type'] != null) {
|
||
if (map['remise_type'] == 'pourcentage') {
|
||
type = RemiseType.pourcentage;
|
||
} else if (map['remise_type'] == 'montant') {
|
||
type = RemiseType.montant;
|
||
}
|
||
}
|
||
|
||
return DetailCommande(
|
||
id: map['id'] as int?,
|
||
commandeId: map['commandeId'] as int,
|
||
produitId: map['produitId'] as int,
|
||
quantite: map['quantite'] as int,
|
||
prixUnitaire: (map['prixUnitaire'] as num).toDouble(),
|
||
sousTotal: (map['sousTotal'] as num).toDouble(),
|
||
remiseType: type,
|
||
remiseValeur: (map['remise_valeur'] as num?)?.toDouble() ?? 0.0,
|
||
montantRemise: (map['montant_remise'] as num?)?.toDouble() ?? 0.0,
|
||
prixFinal: (map['prix_final'] as num?)?.toDouble() ??
|
||
(map['sousTotal'] as num).toDouble(),
|
||
estCadeau: (map['est_cadeau'] as int?) == 1,
|
||
produitNom: map['produitNom'] as String?,
|
||
produitImage: map['produitImage'] as String?,
|
||
produitReference: map['produitReference'] as String?,
|
||
produitImei: map['produitImei'] as String?,
|
||
);
|
||
}
|
||
}
|