255 lines
9.9 KiB
PHP
255 lines
9.9 KiB
PHP
<?php
|
|
require_once __DIR__ . '/db/config.php';
|
|
|
|
/**
|
|
* Fetches the upline for a given user.
|
|
*
|
|
* @param int $userId The ID of the user.
|
|
* @param int $levels The number of levels to fetch.
|
|
* @return array The upline users.
|
|
*/
|
|
function get_upline($userId, $levels = 10) {
|
|
$upline = [];
|
|
$currentUser = $userId;
|
|
|
|
for ($i = 0; $i < $levels; $i++) {
|
|
$db = db();
|
|
$stmt = $db->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')
|
|
]);
|
|
}
|
|
} |