prepare("SELECT sponsor_id FROM users WHERE id = :id"); $stmt->execute([':id' => $currentUser]); $sponsor = $stmt->fetch(PDO::FETCH_ASSOC); if ($sponsor && $sponsor['sponsor_id']) { $upline[] = $sponsor['sponsor_id']; $currentUser = $sponsor['sponsor_id']; } else { break; } } return $upline; } /** * Calculates and distributes commissions for a given booking. * * @param int $bookingId The ID of the booking. */ function calculate_commissions($bookingId) { $db = db(); $db->beginTransaction(); try { // 1. Get booking details $stmt = $db->prepare("SELECT user_id, amount FROM bookings WHERE id = :booking_id AND status = 'approved'"); $stmt->execute([':booking_id' => $bookingId]); $booking = $stmt->fetch(PDO::FETCH_ASSOC); if (!$booking) { throw new Exception("Booking not found or not approved."); } $bookingAmount = $booking['amount']; $bookingUserId = $booking['user_id']; // 2. Get upline $upline = get_upline($bookingUserId, 10); if (empty($upline)) { // No upline, nothing to do $db->commit(); return; } // 3. Direct Commission (Level 10) $directCommission = $bookingAmount * 0.10; $directSponsorId = $upline[0]; // Insert transaction for direct commission $stmt = $db->prepare( "INSERT INTO transactions (user_id, amount, type, description, related_booking_id, related_user_id) VALUES (:user_id, :amount, 'commission_direct', :description, :booking_id, :related_user_id)" ); $stmt->execute([ ':user_id' => $directSponsorId, ':amount' => $directCommission, ':description' => 'Direct commission for booking #' . $bookingId, ':booking_id' => $bookingId, ':related_user_id' => $bookingUserId ]); $directCommissionTransactionId = $db->lastInsertId(); // Schedule passive income for the sponsor schedule_passive_income($directCommissionTransactionId, $directSponsorId, $directCommission, $db); // Update sponsor's wallet and income $stmt = $db->prepare("UPDATE users SET wallet_balance = wallet_balance + :amount, total_direct_income = total_direct_income + :amount WHERE id = :user_id"); $stmt->execute([':amount' => $directCommission, ':user_id' => $directSponsorId]); // 4. Team Commissions (Levels 9 down to 1) $previousLevelCommission = $directCommission; for ($i = 1; $i < count($upline); $i++) { $teamCommission = $previousLevelCommission * 0.50; $uplineMemberId = $upline[$i]; // Insert transaction for team commission $stmt = $db->prepare( "INSERT INTO transactions (user_id, amount, type, description, related_booking_id, related_user_id) VALUES (:user_id, :amount, 'commission_team', :description, :booking_id, :related_user_id)" ); $stmt->execute([ ':user_id' => $uplineMemberId, ':amount' => $teamCommission, ':description' => 'Team commission (Level ' . (10 - ($i + 1) + 1) . ') for booking #' . $bookingId, ':booking_id' => $bookingId, ':related_user_id' => $bookingUserId ]); // Update user's wallet and income $stmt = $db->prepare("UPDATE users SET wallet_balance = wallet_balance + :amount, total_team_income = total_team_income + :amount WHERE id = :user_id"); $stmt->execute([':amount' => $teamCommission, ':user_id' => $uplineMemberId]); $previousLevelCommission = $teamCommission; } // 5. Calculate Leg Match Bonus calculate_leg_match_bonus($bookingUserId, $db); $db->commit(); echo "Commissions calculated and distributed successfully for booking #$bookingId."; } catch (Exception $e) { $db->rollBack(); error_log("Commission calculation failed for booking #$bookingId: " . $e->getMessage()); // Handle or log the error appropriately } } /** * Calculates and distributes leg match bonuses. */ /** * Recursively calculates the total booking volume for a given user and their entire downline. * * @param int $userId The ID of the user at the top of the leg. * @param PDO $db The database connection. * @return float The total volume of the leg. */ function get_leg_volume($userId, $db) { $totalVolume = 0.0; // Get the user's own contribution $stmt = $db->prepare("SELECT cumulative_bookings FROM users WHERE id = :user_id"); $stmt->execute([':user_id' => $userId]); $user = $stmt->fetch(PDO::FETCH_ASSOC); if ($user) { $totalVolume += $user['cumulative_bookings']; } // Get all directly sponsored users $stmt = $db->prepare("SELECT id FROM users WHERE sponsor_id = :sponsor_id"); $stmt->execute([':sponsor_id' => $userId]); $downline = $stmt->fetchAll(PDO::FETCH_ASSOC); foreach ($downline as $downlineUser) { $totalVolume += get_leg_volume($downlineUser['id'], $db); } return $totalVolume; } /** * Calculates and distributes leg match bonuses. * * @param int $bookingUserId The user who made the original booking. * @param PDO $db The database connection. */ function calculate_leg_match_bonus($bookingUserId, $db) { // A leg match bonus is paid to the SPONSOR of the user who made the booking, // based on the performance of their OTHER legs. // The spec is "5% leg-match paid to user for every INR 10,00,000 leg milestone". // This implies we check the sponsor's legs. // Get the sponsor of the person who made the booking $stmt = $db->prepare("SELECT sponsor_id FROM users WHERE id = :id"); $stmt->execute([':id' => $bookingUserId]); $sponsor = $stmt->fetch(PDO::FETCH_ASSOC); if (!$sponsor || !$sponsor['sponsor_id']) { return; // No sponsor, no bonus to calculate } $sponsorId = $sponsor['sponsor_id']; // Get all the direct downlines of the SPONSOR (these are the legs) $stmt = $db->prepare("SELECT id FROM users WHERE sponsor_id = :sponsor_id"); $stmt->execute([':sponsor_id' => $sponsorId]); $legs = $stmt->fetchAll(PDO::FETCH_ASSOC); $milestoneAmount = 1000000.00; $bonusPercentage = 0.05; $bonusAmount = $milestoneAmount * $bonusPercentage; foreach ($legs as $leg) { $legUserId = $leg['id']; $legVolume = get_leg_volume($legUserId, $db); // Find out how many milestones this leg has already been paid for $stmt = $db->prepare("SELECT COUNT(*) as count FROM leg_milestones WHERE user_id = :user_id AND leg_user_id = :leg_user_id"); $stmt->execute([':user_id' => $sponsorId, ':leg_user_id' => $legUserId]); $paidMilestonesCount = $stmt->fetch(PDO::FETCH_ASSOC)['count']; $achievedMilestones = floor($legVolume / $milestoneAmount); if ($achievedMilestones > $paidMilestonesCount) { $newMilestones = $achievedMilestones - $paidMilestonesCount; for ($i = 0; $i < $newMilestones; $i++) { $currentMilestoneNumber = $paidMilestonesCount + $i + 1; $currentMilestoneValue = $currentMilestoneNumber * $milestoneAmount; // 1. Pay the bonus $stmt = $db->prepare( "INSERT INTO transactions (user_id, amount, type, description, related_user_id) VALUES (:user_id, :amount, 'leg_match_bonus', :description, :related_user_id)" ); $stmt->execute([ ':user_id' => $sponsorId, ':amount' => $bonusAmount, ':description' => "Leg match bonus for leg of user #$legUserId reaching milestone ₹" . number_format($currentMilestoneValue), ':related_user_id' => $legUserId ]); // 2. Update wallet $stmt = $db->prepare("UPDATE users SET wallet_balance = wallet_balance + :amount, total_leg_match_income = total_leg_match_income + :amount WHERE id = :user_id"); $stmt->execute([':amount' => $bonusAmount, ':user_id' => $sponsorId]); // 3. Record the milestone payment $stmt = $db->prepare("INSERT INTO leg_milestones (user_id, leg_user_id, milestone_amount, bonus_amount) VALUES (:user_id, :leg_user_id, :milestone_amount, :bonus_amount)"); $stmt->execute([ ':user_id' => $sponsorId, ':leg_user_id' => $legUserId, ':milestone_amount' => $currentMilestoneValue, ':bonus_amount' => $bonusAmount ]); } } } } /** * Schedules passive income payments. */ function schedule_passive_income($directCommissionTransactionId, $userId, $directCommissionAmount, $db) { $passiveIncomeAmount = $directCommissionAmount * 0.005; $startDate = new DateTime(); for ($i = 1; $i <= 12; $i++) { $paymentDate = clone $startDate; $paymentDate->add(new DateInterval("P{$i}M")); $stmt = $db->prepare( "INSERT INTO passive_income_schedule (transaction_id, user_id, amount, payment_date, status) VALUES (:transaction_id, :user_id, :amount, :payment_date, 'pending')" ); $stmt->execute([ ':transaction_id' => $directCommissionTransactionId, ':user_id' => $userId, ':amount' => $passiveIncomeAmount, ':payment_date' => $paymentDate->format('Y-m-d') ]); } }