Update: 2026-06-10 02:44:54
This commit is contained in:
36
backend/migration_referral_system.sql
Normal file
36
backend/migration_referral_system.sql
Normal file
@@ -0,0 +1,36 @@
|
||||
-- 1. Table for storing the unified 6-digit referral code for each user (Driver/Passenger)
|
||||
CREATE TABLE `user_referral_codes` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`user_id` VARCHAR(100) NOT NULL,
|
||||
`user_type` ENUM('driver', 'passenger') NOT NULL,
|
||||
`referral_code` VARCHAR(6) NOT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `idx_user_type_id` (`user_id`, `user_type`),
|
||||
UNIQUE KEY `idx_referral_code` (`referral_code`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
-- 2. Table for tracking the referral relationship and trip counts
|
||||
CREATE TABLE `unified_referrals` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`inviter_code` VARCHAR(6) NOT NULL,
|
||||
`invited_user_id` VARCHAR(100) NOT NULL,
|
||||
`invited_user_type` ENUM('driver', 'passenger') NOT NULL,
|
||||
`status` ENUM('registered', 'active', 'completed') NOT NULL DEFAULT 'registered',
|
||||
`trip_count` INT NOT NULL DEFAULT 0,
|
||||
`is_reward_claimed` TINYINT(1) NOT NULL DEFAULT 0,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `idx_invited_user` (`invited_user_id`, `invited_user_type`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
-- 3. Table for Driver Cash Claims (when a driver requests to receive their reward as manual cash)
|
||||
CREATE TABLE `driver_cash_claims` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`driver_id` VARCHAR(100) NOT NULL,
|
||||
`referral_id` INT NOT NULL,
|
||||
`amount_syp` INT NOT NULL,
|
||||
`status` ENUM('pending', 'paid') NOT NULL DEFAULT 'pending',
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
37
backend/ride/invitor/add_unified_invite.php
Normal file
37
backend/ride/invitor/add_unified_invite.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../../connect.php';
|
||||
|
||||
$inviterCode = filterRequest("inviter_code");
|
||||
|
||||
// Use JWT token variables provided by connect.php
|
||||
if (!$inviterCode || !$user_id || !in_array($role, ['driver', 'passenger'])) {
|
||||
jsonError("Invalid parameters or unauthorized token");
|
||||
}
|
||||
|
||||
// Ensure the code exists and get the inviter details
|
||||
$stmtCheck = $con->prepare("SELECT user_id, user_type FROM user_referral_codes WHERE referral_code = ?");
|
||||
$stmtCheck->execute([$inviterCode]);
|
||||
|
||||
if ($stmtCheck->rowCount() == 0) {
|
||||
jsonError("Invalid referral code");
|
||||
}
|
||||
$inviterData = $stmtCheck->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
// Check if user was already invited
|
||||
$stmtExisting = $con->prepare("SELECT id FROM unified_referrals WHERE invited_user_id = ? AND invited_user_type = ?");
|
||||
$stmtExisting->execute([$user_id, $role]);
|
||||
|
||||
if ($stmtExisting->rowCount() > 0) {
|
||||
jsonError("User already registered with a referral code");
|
||||
}
|
||||
|
||||
// Insert new referral
|
||||
$insertStmt = $con->prepare("INSERT INTO unified_referrals (inviter_code, invited_user_id, invited_user_type, status, trip_count, is_reward_claimed) VALUES (?, ?, ?, 'registered', 0, 0)");
|
||||
|
||||
try {
|
||||
$insertStmt->execute([$inviterCode, $user_id, $role]);
|
||||
printSuccess(["message" => "Referral linked successfully"]);
|
||||
} catch (PDOException $e) {
|
||||
jsonError("Database error: " . $e->getMessage());
|
||||
}
|
||||
?>
|
||||
80
backend/ride/invitor/claim_driver_reward.php
Normal file
80
backend/ride/invitor/claim_driver_reward.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../../connect.php';
|
||||
|
||||
$referralId = filterRequest("referral_id");
|
||||
$claimType = filterRequest("claim_type"); // 'wallet' or 'cash'
|
||||
|
||||
// Use JWT token variables provided by connect.php
|
||||
if (!$user_id || $role != 'driver' || !$referralId || !in_array($claimType, ['wallet', 'cash'])) {
|
||||
jsonError("Invalid parameters or unauthorized token");
|
||||
}
|
||||
|
||||
// 1. Get the referral info
|
||||
$stmt = $con->prepare("
|
||||
SELECT r.id, r.inviter_code, r.invited_user_id, r.invited_user_type, r.trip_count, r.is_reward_claimed, c.user_id as inviter_id, c.user_type as inviter_type
|
||||
FROM unified_referrals r
|
||||
JOIN user_referral_codes c ON r.inviter_code = c.referral_code
|
||||
WHERE r.id = ? AND c.user_id = ? AND c.user_type = 'driver'
|
||||
");
|
||||
$stmt->execute([$referralId, $user_id]);
|
||||
|
||||
if ($stmt->rowCount() == 0) {
|
||||
jsonError("Referral not found or unauthorized");
|
||||
}
|
||||
|
||||
$referral = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($referral['is_reward_claimed'] == 1) {
|
||||
jsonError("Reward already claimed");
|
||||
}
|
||||
|
||||
// Logic:
|
||||
// Driver -> Driver: 50 trips = 500 SYP (example)
|
||||
// Driver -> Passenger: 10 trips = 30 SYP per trip. This could be progressive, but for manual claim we assume completed
|
||||
$amountSyp = 0;
|
||||
|
||||
if ($referral['invited_user_type'] == 'driver') {
|
||||
if ($referral['trip_count'] >= 50) {
|
||||
$amountSyp = 500;
|
||||
} else {
|
||||
jsonError("Requirement not met (50 trips required)");
|
||||
}
|
||||
} else if ($referral['invited_user_type'] == 'passenger') {
|
||||
if ($referral['trip_count'] >= 1) {
|
||||
// Here, user gets 30 SYP per trip, max 10. Let's assume claim all at once up to 10.
|
||||
$tripsToClaim = min($referral['trip_count'], 10);
|
||||
$amountSyp = $tripsToClaim * 30;
|
||||
} else {
|
||||
jsonError("Requirement not met (At least 1 trip required)");
|
||||
}
|
||||
}
|
||||
|
||||
if ($amountSyp <= 0) {
|
||||
jsonError("No reward available to claim");
|
||||
}
|
||||
|
||||
try {
|
||||
$con->beginTransaction();
|
||||
|
||||
// Mark as claimed
|
||||
$updateStmt = $con->prepare("UPDATE unified_referrals SET is_reward_claimed = 1, status = 'claimed' WHERE id = ?");
|
||||
$updateStmt->execute([$referralId]);
|
||||
|
||||
if ($claimType == 'wallet') {
|
||||
// Add to driver wallet
|
||||
$walletStmt = $con->prepare("UPDATE driver SET wallet = wallet + ? WHERE id = ?");
|
||||
$walletStmt->execute([$amountSyp, $user_id]);
|
||||
} else if ($claimType == 'cash') {
|
||||
// Request manual cash out
|
||||
$cashStmt = $con->prepare("INSERT INTO driver_cash_claims (driver_id, referral_id, amount_syp, status) VALUES (?, ?, ?, 'pending')");
|
||||
$cashStmt->execute([$user_id, $referralId, $amountSyp]);
|
||||
}
|
||||
|
||||
$con->commit();
|
||||
printSuccess(["message" => "Reward claimed successfully as $claimType"]);
|
||||
|
||||
} catch (PDOException $e) {
|
||||
$con->rollBack();
|
||||
jsonError("Database error: " . $e->getMessage());
|
||||
}
|
||||
?>
|
||||
60
backend/ride/invitor/get_driver_referrals.php
Normal file
60
backend/ride/invitor/get_driver_referrals.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../../connect.php';
|
||||
|
||||
// Use JWT token variables provided by connect.php
|
||||
if (!$user_id || $role != 'driver') {
|
||||
jsonError("Invalid parameters or unauthorized token");
|
||||
}
|
||||
|
||||
// 1. Get the driver's referral code
|
||||
$stmtCode = $con->prepare("SELECT referral_code FROM user_referral_codes WHERE user_id = ? AND user_type = 'driver'");
|
||||
$stmtCode->execute([$user_id]);
|
||||
|
||||
if ($stmtCode->rowCount() == 0) {
|
||||
// If no code exists, return empty stats
|
||||
printSuccess([
|
||||
"referral_code" => null,
|
||||
"total_invited_drivers" => 0,
|
||||
"total_invited_passengers" => 0,
|
||||
"referrals" => []
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$referralCode = $stmtCode->fetchColumn();
|
||||
|
||||
// 2. Fetch all referrals made by this code
|
||||
$stmtRefs = $con->prepare("
|
||||
SELECT id, invited_user_id, invited_user_type, status, trip_count, is_reward_claimed, created_at
|
||||
FROM unified_referrals
|
||||
WHERE inviter_code = ?
|
||||
ORDER BY created_at DESC
|
||||
");
|
||||
$stmtRefs->execute([$referralCode]);
|
||||
$referrals = $stmtRefs->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$totalDrivers = 0;
|
||||
$totalPassengers = 0;
|
||||
|
||||
// Format data and calculate stats
|
||||
foreach ($referrals as &$ref) {
|
||||
if ($ref['invited_user_type'] == 'driver') {
|
||||
$totalDrivers++;
|
||||
$ref['target_trips'] = 50;
|
||||
$ref['reward_syp'] = 500;
|
||||
$ref['can_claim'] = ($ref['trip_count'] >= 50 && $ref['is_reward_claimed'] == 0) ? true : false;
|
||||
} else {
|
||||
$totalPassengers++;
|
||||
$ref['target_trips'] = 1;
|
||||
$ref['reward_syp'] = 30 * min($ref['trip_count'], 10); // Or max depending on logic
|
||||
$ref['can_claim'] = ($ref['trip_count'] >= 1 && $ref['is_reward_claimed'] == 0) ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
printSuccess([
|
||||
"referral_code" => $referralCode,
|
||||
"total_invited_drivers" => $totalDrivers,
|
||||
"total_invited_passengers" => $totalPassengers,
|
||||
"referrals" => $referrals
|
||||
]);
|
||||
?>
|
||||
60
backend/ride/invitor/get_passenger_referrals.php
Normal file
60
backend/ride/invitor/get_passenger_referrals.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../../connect.php';
|
||||
|
||||
// Use JWT token variables provided by connect.php
|
||||
if (!$user_id || $role != 'passenger') {
|
||||
jsonError("Invalid parameters or unauthorized token");
|
||||
}
|
||||
|
||||
// 1. Get the passenger's referral code
|
||||
$stmtCode = $con->prepare("SELECT referral_code FROM user_referral_codes WHERE user_id = ? AND user_type = 'passenger'");
|
||||
$stmtCode->execute([$user_id]);
|
||||
|
||||
if ($stmtCode->rowCount() == 0) {
|
||||
// If no code exists, return empty stats
|
||||
printSuccess([
|
||||
"referral_code" => null,
|
||||
"total_invited_drivers" => 0,
|
||||
"total_invited_passengers" => 0,
|
||||
"referrals" => []
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$referralCode = $stmtCode->fetchColumn();
|
||||
|
||||
// 2. Fetch all referrals made by this code
|
||||
$stmtRefs = $con->prepare("
|
||||
SELECT id, invited_user_id, invited_user_type, status, trip_count, is_reward_claimed, created_at
|
||||
FROM unified_referrals
|
||||
WHERE inviter_code = ?
|
||||
ORDER BY created_at DESC
|
||||
");
|
||||
$stmtRefs->execute([$referralCode]);
|
||||
$referrals = $stmtRefs->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$totalDrivers = 0;
|
||||
$totalPassengers = 0;
|
||||
|
||||
// Format data and calculate stats
|
||||
foreach ($referrals as &$ref) {
|
||||
if ($ref['invited_user_type'] == 'driver') {
|
||||
$totalDrivers++;
|
||||
$ref['target_trips'] = 50;
|
||||
$ref['reward_syp'] = 500;
|
||||
$ref['can_claim'] = ($ref['trip_count'] >= 50 && $ref['is_reward_claimed'] == 0) ? true : false;
|
||||
} else {
|
||||
$totalPassengers++;
|
||||
$ref['target_trips'] = 1;
|
||||
$ref['reward_syp'] = 30; // Just illustrative, rewards are automatic
|
||||
$ref['can_claim'] = ($ref['trip_count'] >= 1 && $ref['is_reward_claimed'] == 0) ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
printSuccess([
|
||||
"referral_code" => $referralCode,
|
||||
"total_invited_drivers" => $totalDrivers,
|
||||
"total_invited_passengers" => $totalPassengers,
|
||||
"referrals" => $referrals
|
||||
]);
|
||||
?>
|
||||
41
backend/ride/invitor/get_unified_code.php
Normal file
41
backend/ride/invitor/get_unified_code.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../../connect.php';
|
||||
|
||||
function generateUnifiedCode($con) {
|
||||
while (true) {
|
||||
$letters = substr(str_shuffle("ABCDEFGHJKLMNPQRSTUVWXYZ"), 0, 2);
|
||||
$numbers = substr(str_shuffle("23456789"), 0, 4);
|
||||
$code = $letters . $numbers;
|
||||
|
||||
$stmt = $con->prepare("SELECT COUNT(*) FROM user_referral_codes WHERE referral_code = ?");
|
||||
$stmt->execute([$code]);
|
||||
|
||||
if ($stmt->fetchColumn() == 0) {
|
||||
return $code;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the JWT values exist
|
||||
if (!$user_id || !in_array($role, ['driver', 'passenger'])) {
|
||||
jsonError("Invalid or missing user information in token");
|
||||
}
|
||||
|
||||
$stmt = $con->prepare("SELECT referral_code FROM user_referral_codes WHERE user_id = ? AND user_type = ?");
|
||||
$stmt->execute([$user_id, $role]);
|
||||
|
||||
if ($stmt->rowCount() > 0) {
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
printSuccess(["referral_code" => $row['referral_code']]);
|
||||
} else {
|
||||
$newCode = generateUnifiedCode($con);
|
||||
$insertStmt = $con->prepare("INSERT INTO user_referral_codes (user_id, user_type, referral_code) VALUES (?, ?, ?)");
|
||||
|
||||
try {
|
||||
$insertStmt->execute([$user_id, $role, $newCode]);
|
||||
printSuccess(["referral_code" => $newCode]);
|
||||
} catch (PDOException $e) {
|
||||
jsonError("Database error: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -1782,3 +1782,45 @@ CREATE TABLE `write_argument_after_applied_from_background` (
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
|
||||
-- Dump completed on 2026-04-22 19:40:54
|
||||
|
||||
--
|
||||
-- Table structure for table `user_referral_codes`
|
||||
--
|
||||
CREATE TABLE IF NOT EXISTS `user_referral_codes` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`user_id` varchar(100) NOT NULL,
|
||||
`user_type` enum('driver','passenger') NOT NULL,
|
||||
`referral_code` varchar(20) NOT NULL UNIQUE,
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
--
|
||||
-- Table structure for table `unified_referrals`
|
||||
--
|
||||
CREATE TABLE IF NOT EXISTS `unified_referrals` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`inviter_code` varchar(20) NOT NULL,
|
||||
`invited_user_id` varchar(100) NOT NULL,
|
||||
`invited_user_type` enum('driver','passenger') NOT NULL,
|
||||
`status` enum('registered','first_trip','claimed') DEFAULT 'registered',
|
||||
`trip_count` int DEFAULT 0,
|
||||
`is_reward_claimed` tinyint(1) DEFAULT 0,
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
--
|
||||
-- Table structure for table `driver_cash_claims`
|
||||
--
|
||||
CREATE TABLE IF NOT EXISTS `driver_cash_claims` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`driver_id` varchar(100) NOT NULL,
|
||||
`referral_id` int NOT NULL,
|
||||
`amount_syp` decimal(10,2) NOT NULL,
|
||||
`status` enum('pending','paid','rejected') DEFAULT 'pending',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
@@ -208,8 +208,8 @@ CREATE TABLE `car_locations` (
|
||||
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
|
||||
/*!50003 SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO' */ ;
|
||||
DELIMITER ;;
|
||||
/*!50003 CREATE*/ /*!50017 DEFINER=`intaleq-rides`@`%`*/ /*!50003 TRIGGER `trg_before_insert_car_locations` BEFORE INSERT ON `car_locations` FOR EACH ROW BEGIN
|
||||
SET NEW.location_point = ST_PointFromText(CONCAT('POINT(', NEW.longitude, ' ', NEW.latitude, ')'), 4326);
|
||||
/*!50003 CREATE*/ /*!50017 DEFINER=`intaleq-rides`@`%`*/ /*!50003 TRIGGER `trg_before_insert_car_locations` BEFORE INSERT ON `car_locations` FOR EACH ROW BEGIN
|
||||
SET NEW.location_point = ST_PointFromText(CONCAT('POINT(', NEW.longitude, ' ', NEW.latitude, ')'), 4326);
|
||||
END */;;
|
||||
DELIMITER ;
|
||||
/*!50003 SET sql_mode = @saved_sql_mode */ ;
|
||||
@@ -225,10 +225,10 @@ DELIMITER ;
|
||||
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
|
||||
/*!50003 SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO' */ ;
|
||||
DELIMITER ;;
|
||||
/*!50003 CREATE*/ /*!50017 DEFINER=`intaleq-rides`@`%`*/ /*!50003 TRIGGER `trg_before_update_car_locations` BEFORE UPDATE ON `car_locations` FOR EACH ROW BEGIN
|
||||
IF NEW.latitude <> OLD.latitude OR NEW.longitude <> OLD.longitude THEN
|
||||
SET NEW.location_point = ST_PointFromText(CONCAT('POINT(', NEW.longitude, ' ', NEW.latitude, ')'), 4326);
|
||||
END IF;
|
||||
/*!50003 CREATE*/ /*!50017 DEFINER=`intaleq-rides`@`%`*/ /*!50003 TRIGGER `trg_before_update_car_locations` BEFORE UPDATE ON `car_locations` FOR EACH ROW BEGIN
|
||||
IF NEW.latitude <> OLD.latitude OR NEW.longitude <> OLD.longitude THEN
|
||||
SET NEW.location_point = ST_PointFromText(CONCAT('POINT(', NEW.longitude, ' ', NEW.latitude, ')'), 4326);
|
||||
END IF;
|
||||
END */;;
|
||||
DELIMITER ;
|
||||
/*!50003 SET sql_mode = @saved_sql_mode */ ;
|
||||
|
||||
Reference in New Issue
Block a user