Update: 2026-08-08 12:58:16
This commit is contained in:
@@ -0,0 +1,226 @@
|
||||
// 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'] ?? {})),
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user