feat(phase-1): complete backend core, savings ledger, multi-channel auth, and dynamic QR verification
This commit is contained in:
@@ -160,4 +160,94 @@ class SubscriptionController
|
||||
|
||||
Response::success($card, 'Digital card details retrieved.');
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/v1/subscription/savings-summary
|
||||
* Returns total cash saved, breakdown by partner type, loyalty tier, and recent savings logs.
|
||||
*/
|
||||
public function getSavingsSummary(Request $request): void
|
||||
{
|
||||
$userId = (int)$request->getHeader('x-user-id');
|
||||
$pdo = Database::getConnection();
|
||||
|
||||
// 1. Get totals
|
||||
$totStmt = $pdo->prepare('
|
||||
SELECT
|
||||
COALESCE(SUM(saved_amount), 0) AS total_saved_iqd,
|
||||
COALESCE(SUM(paid_amount), 0) AS total_paid_iqd,
|
||||
COUNT(id) AS total_services_count
|
||||
FROM savings_ledger
|
||||
WHERE user_id = :uid
|
||||
');
|
||||
$totStmt->execute([':uid' => $userId]);
|
||||
$totals = $totStmt->fetch(PDO::FETCH_ASSOC) ?: [
|
||||
'total_saved_iqd' => 0,
|
||||
'total_paid_iqd' => 0,
|
||||
'total_services_count' => 0,
|
||||
];
|
||||
|
||||
$totalSaved = (float)$totals['total_saved_iqd'];
|
||||
$servicesCount = (int)$totals['total_services_count'];
|
||||
|
||||
// 2. Breakdown by partner type (HOSPITAL, HOTEL, TRAINING_CENTER)
|
||||
$breakdownStmt = $pdo->prepare('
|
||||
SELECT
|
||||
p.type,
|
||||
COUNT(s.id) AS count,
|
||||
COALESCE(SUM(s.saved_amount), 0) AS saved_iqd
|
||||
FROM savings_ledger s
|
||||
JOIN partners p ON p.id = s.partner_id
|
||||
WHERE s.user_id = :uid
|
||||
GROUP BY p.type
|
||||
');
|
||||
$breakdownStmt->execute([':uid' => $userId]);
|
||||
$breakdownRows = $breakdownStmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$breakdown = [
|
||||
'HOSPITAL' => ['count' => 0, 'saved_iqd' => 0.0, 'label' => 'المستشفيات والعيادات'],
|
||||
'HOTEL' => ['count' => 0, 'saved_iqd' => 0.0, 'label' => 'الفنادق والإقامة'],
|
||||
'TRAINING_CENTER' => ['count' => 0, 'saved_iqd' => 0.0, 'label' => 'الدورات والورش الأكاديمية'],
|
||||
];
|
||||
|
||||
foreach ($breakdownRows as $row) {
|
||||
$type = $row['type'];
|
||||
if (isset($breakdown[$type])) {
|
||||
$breakdown[$type]['count'] = (int)$row['count'];
|
||||
$breakdown[$type]['saved_iqd'] = (float)$row['saved_iqd'];
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Loyalty Tier Calculation (Gamification)
|
||||
if ($totalSaved >= 500000) {
|
||||
$tier = ['code' => 'DIAMOND', 'name_ar' => 'عضو ماسي أوروك', 'badge' => '💎', 'level' => 4];
|
||||
} elseif ($totalSaved >= 250000) {
|
||||
$tier = ['code' => 'GOLD', 'name_ar' => 'عضو ذهبي ممتاز', 'badge' => '🥇', 'level' => 3];
|
||||
} elseif ($totalSaved >= 100000) {
|
||||
$tier = ['code' => 'SILVER', 'name_ar' => 'عضو فضي متقدم', 'badge' => '🥈', 'level' => 2];
|
||||
} else {
|
||||
$tier = ['code' => 'BRONZE', 'name_ar' => 'عضو برونزي', 'badge' => '🥉', 'level' => 1];
|
||||
}
|
||||
|
||||
// 4. Fetch last 10 logs
|
||||
$logsStmt = $pdo->prepare('
|
||||
SELECT s.id, s.service_name, s.original_amount, s.discount_percentage, s.saved_amount, s.paid_amount,
|
||||
s.created_at, p.name_ar AS partner_name, p.type AS partner_type
|
||||
FROM savings_ledger s
|
||||
JOIN partners p ON p.id = s.partner_id
|
||||
WHERE s.user_id = :uid
|
||||
ORDER BY s.id DESC
|
||||
LIMIT 10
|
||||
');
|
||||
$logsStmt->execute([':uid' => $userId]);
|
||||
$recentLogs = $logsStmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
Response::success([
|
||||
'total_saved_iqd' => $totalSaved,
|
||||
'total_paid_iqd' => (float)$totals['total_paid_iqd'],
|
||||
'total_services_count' => $servicesCount,
|
||||
'breakdown' => $breakdown,
|
||||
'tier' => $tier,
|
||||
'recent_logs' => $recentLogs,
|
||||
], 'Savings and gamification summary retrieved.');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user