317 lines
8.9 KiB
Dart
317 lines
8.9 KiB
Dart
/// Modello delle lezioni per la scuola YogaSoul.
|
|
///
|
|
/// Rispecchia il JSON prodotto da `public/api/my_lessons.php`.
|
|
/// Nota: questa app è single-school, quindi niente concetti multiscuola
|
|
/// (wallet/entries/recoveries/level) che non esistono nel DB YogaSoul.
|
|
|
|
class LessonsResponse {
|
|
final String month; // "YYYY-MM"
|
|
final LessonsSummary summary;
|
|
final List<Lesson> lessons;
|
|
|
|
LessonsResponse({
|
|
required this.month,
|
|
required this.summary,
|
|
required this.lessons,
|
|
});
|
|
|
|
factory LessonsResponse.fromJson(Map<String, dynamic> j) {
|
|
final rawLessons = (j['lessons'] as List?) ?? const [];
|
|
return LessonsResponse(
|
|
month: (j['month'] ?? '').toString(),
|
|
summary: LessonsSummary.fromJson(
|
|
(j['summary'] as Map?)?.cast<String, dynamic>() ?? const {},
|
|
),
|
|
lessons: rawLessons
|
|
.map((e) => Lesson.fromJson((e as Map).cast<String, dynamic>()))
|
|
.toList(),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// I conteggi della fascia riepilogo (le "card pastello" della webapp).
|
|
class LessonsSummary {
|
|
final int purchased; // acquistate
|
|
final int practiced; // praticate
|
|
final int booked; // prenotate
|
|
final int pending; // da confermare
|
|
final int toSchedule; // da programmare
|
|
final int lost; // perse
|
|
|
|
LessonsSummary({
|
|
required this.purchased,
|
|
required this.practiced,
|
|
required this.booked,
|
|
required this.pending,
|
|
required this.toSchedule,
|
|
required this.lost,
|
|
});
|
|
|
|
factory LessonsSummary.fromJson(Map<String, dynamic> j) {
|
|
int n(dynamic v) => (v as num?)?.toInt() ?? 0;
|
|
return LessonsSummary(
|
|
purchased: n(j['purchased']),
|
|
practiced: n(j['practiced']),
|
|
booked: n(j['booked']),
|
|
pending: n(j['pending']),
|
|
toSchedule: n(j['to_schedule']),
|
|
lost: n(j['lost']),
|
|
);
|
|
}
|
|
}
|
|
|
|
class Lesson {
|
|
final int bookingId;
|
|
final int serviceId;
|
|
final String status;
|
|
|
|
final String datetime; // "YYYY-MM-DD HH:MM:SS"
|
|
final String date; // "YYYY-MM-DD"
|
|
final String time; // "HH:MM"
|
|
|
|
final String className;
|
|
final String color; // es. "#1ebf73"
|
|
final String location;
|
|
|
|
final String? expireOn; // "YYYY-MM-DD" o null
|
|
final bool lostLesson;
|
|
|
|
final bool canReschedule;
|
|
final bool canDelete;
|
|
|
|
Lesson({
|
|
required this.bookingId,
|
|
required this.serviceId,
|
|
required this.status,
|
|
required this.datetime,
|
|
required this.date,
|
|
required this.time,
|
|
required this.className,
|
|
required this.color,
|
|
required this.location,
|
|
required this.expireOn,
|
|
required this.lostLesson,
|
|
required this.canReschedule,
|
|
required this.canDelete,
|
|
});
|
|
|
|
factory Lesson.fromJson(Map<String, dynamic> j) {
|
|
return Lesson(
|
|
bookingId: (j['booking_id'] as num?)?.toInt() ?? 0,
|
|
serviceId: (j['service_id'] as num?)?.toInt() ?? 0,
|
|
status: (j['status'] ?? '').toString(),
|
|
datetime: (j['datetime'] ?? '').toString(),
|
|
date: (j['date'] ?? '').toString(),
|
|
time: (j['time'] ?? '').toString(),
|
|
className: (j['class_name'] ?? '').toString(),
|
|
color: (j['color'] ?? '#1ebf73').toString(),
|
|
location: (j['location'] ?? '').toString(),
|
|
expireOn: j['expire_on']?.toString(),
|
|
lostLesson: j['lost_lesson'] == true,
|
|
canReschedule: j['can_reschedule'] == true,
|
|
canDelete: j['can_delete'] == true,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Uno slot disponibile per riprogrammare o prenotare (da available_slots.php).
|
|
class AvailableSlot {
|
|
final int scheduleId;
|
|
final int serviceId;
|
|
final String datetime;
|
|
final String date;
|
|
final String time;
|
|
final String className;
|
|
final String color;
|
|
final String location;
|
|
final int maxCapacity;
|
|
final int bookedCount;
|
|
final int freePlaces;
|
|
final bool alreadyBooked;
|
|
final bool bookable;
|
|
|
|
AvailableSlot({
|
|
required this.scheduleId,
|
|
required this.serviceId,
|
|
required this.datetime,
|
|
required this.date,
|
|
required this.time,
|
|
required this.className,
|
|
required this.color,
|
|
required this.location,
|
|
required this.maxCapacity,
|
|
required this.bookedCount,
|
|
required this.freePlaces,
|
|
required this.alreadyBooked,
|
|
required this.bookable,
|
|
});
|
|
|
|
factory AvailableSlot.fromJson(Map<String, dynamic> j) {
|
|
int n(dynamic v) => (v as num?)?.toInt() ?? 0;
|
|
return AvailableSlot(
|
|
scheduleId: n(j['schedule_id']),
|
|
serviceId: n(j['service_id']),
|
|
datetime: (j['datetime'] ?? '').toString(),
|
|
date: (j['date'] ?? '').toString(),
|
|
time: (j['time'] ?? '').toString(),
|
|
className: (j['class_name'] ?? '').toString(),
|
|
color: (j['color'] ?? '#1ebf73').toString(),
|
|
location: (j['location'] ?? '').toString(),
|
|
maxCapacity: n(j['max_capacity']),
|
|
bookedCount: n(j['booked_count']),
|
|
freePlaces: n(j['free_places']),
|
|
alreadyBooked: j['already_booked'] == true,
|
|
bookable: j['bookable'] == true,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Un ordine/pacchetto con ticket residui (da orders.php).
|
|
class OrderPackage {
|
|
final int orderId;
|
|
final int serviceId;
|
|
final String serviceName;
|
|
final int tickets;
|
|
final int used;
|
|
final int remaining;
|
|
final String? expireOn;
|
|
final bool isExpired;
|
|
final bool bookable;
|
|
|
|
OrderPackage({
|
|
required this.orderId,
|
|
required this.serviceId,
|
|
required this.serviceName,
|
|
required this.tickets,
|
|
required this.used,
|
|
required this.remaining,
|
|
required this.expireOn,
|
|
required this.isExpired,
|
|
required this.bookable,
|
|
});
|
|
|
|
factory OrderPackage.fromJson(Map<String, dynamic> j) {
|
|
int n(dynamic v) => (v as num?)?.toInt() ?? 0;
|
|
return OrderPackage(
|
|
orderId: n(j['order_id']),
|
|
serviceId: n(j['service_id']),
|
|
serviceName: (j['service_name'] ?? '').toString(),
|
|
tickets: n(j['tickets']),
|
|
used: n(j['used']),
|
|
remaining: n(j['remaining']),
|
|
expireOn: j['expire_on']?.toString(),
|
|
isExpired: j['is_expired'] == true,
|
|
bookable: j['bookable'] == true,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Una lezione dentro un ordine (da orders_detail.php).
|
|
class OrderLesson {
|
|
final int bookingId;
|
|
final String? datetime;
|
|
final String className;
|
|
final String status; // completed / booked / lost / expired / pending
|
|
final bool isReprogrammed;
|
|
|
|
OrderLesson({
|
|
required this.bookingId,
|
|
required this.datetime,
|
|
required this.className,
|
|
required this.status,
|
|
required this.isReprogrammed,
|
|
});
|
|
|
|
factory OrderLesson.fromJson(Map<String, dynamic> j) {
|
|
return OrderLesson(
|
|
bookingId: (j['booking_id'] as num?)?.toInt() ?? 0,
|
|
datetime: j['datetime']?.toString(),
|
|
className: (j['class_name'] ?? '').toString(),
|
|
status: (j['status'] ?? '').toString(),
|
|
isReprogrammed: j['is_reprogrammed'] == true,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Un ordine completo con conteggi e lezioni (da orders_detail.php).
|
|
class OrderDetail {
|
|
final int orderId;
|
|
final int? orderNumber;
|
|
final int serviceId;
|
|
final String serviceName;
|
|
final String day;
|
|
final String time;
|
|
final String? orderDate;
|
|
final String? firstLessonDate;
|
|
final String? expireOn;
|
|
final bool isExpired;
|
|
final int maxReschedule;
|
|
final int reprogrammed;
|
|
final int tickets;
|
|
|
|
final int total;
|
|
final int completed;
|
|
final int lost;
|
|
final int expired;
|
|
final int booked;
|
|
final int pending;
|
|
final int toSchedule;
|
|
|
|
final List<OrderLesson> lessons;
|
|
|
|
OrderDetail({
|
|
required this.orderId,
|
|
required this.orderNumber,
|
|
required this.serviceId,
|
|
required this.serviceName,
|
|
required this.day,
|
|
required this.time,
|
|
required this.orderDate,
|
|
required this.firstLessonDate,
|
|
required this.expireOn,
|
|
required this.isExpired,
|
|
required this.maxReschedule,
|
|
required this.reprogrammed,
|
|
required this.tickets,
|
|
required this.total,
|
|
required this.completed,
|
|
required this.lost,
|
|
required this.expired,
|
|
required this.booked,
|
|
required this.pending,
|
|
required this.toSchedule,
|
|
required this.lessons,
|
|
});
|
|
|
|
factory OrderDetail.fromJson(Map<String, dynamic> j) {
|
|
int n(dynamic v) => (v as num?)?.toInt() ?? 0;
|
|
final s = (j['summary'] as Map?)?.cast<String, dynamic>() ?? const {};
|
|
final rawLessons = (j['lessons'] as List?) ?? const [];
|
|
return OrderDetail(
|
|
orderId: n(j['order_id']),
|
|
orderNumber: (j['order_number'] as num?)?.toInt(),
|
|
serviceId: n(j['service_id']),
|
|
serviceName: (j['service_name'] ?? '').toString(),
|
|
day: (j['day'] ?? '').toString(),
|
|
time: (j['time'] ?? '').toString(),
|
|
orderDate: j['order_date']?.toString(),
|
|
firstLessonDate: j['first_lesson_date']?.toString(),
|
|
expireOn: j['expire_on']?.toString(),
|
|
isExpired: j['is_expired'] == true,
|
|
maxReschedule: n(j['max_reschedule']),
|
|
reprogrammed: n(j['reprogrammed']),
|
|
tickets: n(j['tickets']),
|
|
total: n(s['total']),
|
|
completed: n(s['completed']),
|
|
lost: n(s['lost']),
|
|
expired: n(s['expired']),
|
|
booked: n(s['booked']),
|
|
pending: n(s['pending']),
|
|
toSchedule: n(s['to_schedule']),
|
|
lessons: rawLessons
|
|
.map((e) => OrderLesson.fromJson((e as Map).cast<String, dynamic>()))
|
|
.toList(),
|
|
);
|
|
}
|
|
}
|