Files
Siro/siro_driver/lib/controller/home/statistics/earnings_models.dart
T

227 lines
7.7 KiB
Dart

// earnings_models.dart — نماذج شاشة الأرباح
//
// ‏كل الأرقام تصل من نقطة واحدة (`ride/earnings/summary.php`) بختم زمني
// ‏واحد، فلا مجال لأن يتناقض رقمان في الشاشة نفسها.
class PeriodEarnings {
final int trips;
/// ‏صافي السائق — حصته المثبَّتة لحظة عرض السعر، أي ما وُعد به قبل القبول.
final double net;
/// ‏إجمالي ما دفعه الركاب.
final double gross;
/// ‏عمولة المنصة. تُعرض صراحةً لا تُطرح بصمت: السائق الذي يرى تركيبة
/// ‏المبلغ يفهم، والذي يرى الصافي وحده يخمّن ويشكّ.
final double commission;
final double distance;
final int minutes;
PeriodEarnings({
required this.trips,
required this.net,
required this.gross,
required this.commission,
required this.distance,
required this.minutes,
});
double get hours => minutes / 60.0;
factory PeriodEarnings.fromJson(Map<String, dynamic> j) => PeriodEarnings(
trips: int.tryParse(j['trips']?.toString() ?? '0') ?? 0,
net: double.tryParse(j['net']?.toString() ?? '0') ?? 0,
gross: double.tryParse(j['gross']?.toString() ?? '0') ?? 0,
commission: double.tryParse(j['commission']?.toString() ?? '0') ?? 0,
distance: double.tryParse(j['distance']?.toString() ?? '0') ?? 0,
minutes: int.tryParse(j['minutes']?.toString() ?? '0') ?? 0,
);
static PeriodEarnings empty() => PeriodEarnings(
trips: 0, net: 0, gross: 0, commission: 0, distance: 0, minutes: 0);
}
class DayEarnings {
final String day;
final int trips;
final double net;
final int minutes;
DayEarnings(
{required this.day,
required this.trips,
required this.net,
required this.minutes});
factory DayEarnings.fromJson(Map<String, dynamic> j) => DayEarnings(
day: j['day']?.toString() ?? '',
trips: int.tryParse(j['trips']?.toString() ?? '0') ?? 0,
net: double.tryParse(j['net']?.toString() ?? '0') ?? 0,
minutes: int.tryParse(j['minutes']?.toString() ?? '0') ?? 0,
);
}
class DeductionItem {
final String product;
final String name;
final double outstanding;
DeductionItem(
{required this.product, required this.name, required this.outstanding});
factory DeductionItem.fromJson(Map<String, dynamic> j) => DeductionItem(
product: j['product']?.toString() ?? '',
name: j['name']?.toString() ?? '',
outstanding: double.tryParse(j['outstanding']?.toString() ?? '0') ?? 0,
);
}
/// ‏الاقتطاعات (تأمين، وقود) تُعرض بجانب الأرباح التي اقتُطعت منها.
/// ‏اقتطاعٌ لا يظهر في مكانه يُقرأ سرقةً مهما كان مشروعاً.
class Deductions {
final double today;
final double week;
final double month;
final double outstanding;
final List<DeductionItem> items;
Deductions({
required this.today,
required this.week,
required this.month,
required this.outstanding,
required this.items,
});
bool get hasAny => today > 0 || outstanding > 0;
factory Deductions.fromJson(Map<String, dynamic> j) => Deductions(
today: double.tryParse(j['today']?.toString() ?? '0') ?? 0,
week: double.tryParse(j['week']?.toString() ?? '0') ?? 0,
month: double.tryParse(j['month']?.toString() ?? '0') ?? 0,
outstanding: double.tryParse(j['outstanding']?.toString() ?? '0') ?? 0,
items: (j['items'] is List)
? (j['items'] as List)
.map((i) => DeductionItem.fromJson(Map<String, dynamic>.from(i)))
.toList()
: <DeductionItem>[],
);
}
class EarningsSummary {
final PeriodEarnings today;
final PeriodEarnings week;
final PeriodEarnings month;
final PeriodEarnings prevWeek;
/// ‏نسبة التغيّر عن الأسبوع الماضي، أو null إن لم يكن هناك ما يُقارَن به.
/// ‏المقارنة بالذات لا بالسائقين الآخرين: ترتيبٌ يُحبط أكثر من يحتاج
/// ‏التحفيز — فهو من سيقع في أسفله.
final double? trendPercent;
final List<DayEarnings> daily;
final DayEarnings? bestDay;
final Deductions deductions;
final String asOf;
EarningsSummary({
required this.today,
required this.week,
required this.month,
required this.prevWeek,
required this.daily,
required this.deductions,
required this.asOf,
this.trendPercent,
this.bestDay,
});
factory EarningsSummary.fromJson(Map<String, dynamic> j) => EarningsSummary(
today: PeriodEarnings.fromJson(Map<String, dynamic>.from(j['today'] ?? {})),
week: PeriodEarnings.fromJson(Map<String, dynamic>.from(j['week'] ?? {})),
month: PeriodEarnings.fromJson(Map<String, dynamic>.from(j['month'] ?? {})),
prevWeek:
PeriodEarnings.fromJson(Map<String, dynamic>.from(j['prev_week'] ?? {})),
trendPercent: j['trend_percent'] == null
? null
: double.tryParse(j['trend_percent'].toString()),
daily: (j['daily'] is List)
? (j['daily'] as List)
.map((d) => DayEarnings.fromJson(Map<String, dynamic>.from(d)))
.toList()
: <DayEarnings>[],
bestDay: j['best_day'] is Map
? DayEarnings.fromJson(Map<String, dynamic>.from(j['best_day']))
: null,
deductions:
Deductions.fromJson(Map<String, dynamic>.from(j['deductions'] ?? {})),
asOf: j['as_of']?.toString() ?? '',
);
}
class TripBreakdown {
final double gross;
final double commission;
final double bonus;
final double net;
/// ‏إعفاء العمولة (سلسلة ٠٪) — هدية تدفع المنصة ثمنها ولم تكن تظهر
/// ‏للسائق في أي شاشة. نميّزها لتُعرض مكسباً لا سطراً فارغاً.
final bool zeroCommission;
TripBreakdown({
required this.gross,
required this.commission,
required this.bonus,
required this.net,
required this.zeroCommission,
});
factory TripBreakdown.fromJson(Map<String, dynamic> j) => TripBreakdown(
gross: double.tryParse(j['gross']?.toString() ?? '0') ?? 0,
commission: double.tryParse(j['commission']?.toString() ?? '0') ?? 0,
bonus: double.tryParse(j['bonus']?.toString() ?? '0') ?? 0,
net: double.tryParse(j['net']?.toString() ?? '0') ?? 0,
zeroCommission: j['zero_commission'] == true,
);
}
class TripEarning {
final int rideId;
final String at;
final String from;
final String to;
final String carType;
final String paymentMethod;
final double distanceKm;
final int minutes;
final TripBreakdown breakdown;
TripEarning({
required this.rideId,
required this.at,
required this.from,
required this.to,
required this.carType,
required this.paymentMethod,
required this.distanceKm,
required this.minutes,
required this.breakdown,
});
factory TripEarning.fromJson(Map<String, dynamic> j) => TripEarning(
rideId: int.tryParse(j['ride_id']?.toString() ?? '0') ?? 0,
at: j['at']?.toString() ?? '',
from: j['from']?.toString() ?? '',
to: j['to']?.toString() ?? '',
carType: j['car_type']?.toString() ?? '',
paymentMethod: j['payment_method']?.toString() ?? '',
distanceKm: double.tryParse(j['distance_km']?.toString() ?? '0') ?? 0,
minutes: int.tryParse(j['minutes']?.toString() ?? '0') ?? 0,
breakdown:
TripBreakdown.fromJson(Map<String, dynamic>.from(j['breakdown'] ?? {})),
);
}