updated to add country membership, singles and honorary recognition
This commit is contained in:
@@ -30,6 +30,7 @@ RewriteRule ^membership$ src/pages/memberships/membership.php [L]
|
||||
RewriteRule ^membership_details$ src/pages/memberships/membership_details.php [L]
|
||||
RewriteRule ^membership_application$ src/pages/memberships/membership_application.php [L]
|
||||
RewriteRule ^membership_payment$ src/pages/memberships/membership_payment.php [L]
|
||||
RewriteRule ^renewal_payment$ src/pages/memberships/renewal_payment.php [L]
|
||||
RewriteRule ^renew_membership$ src/pages/memberships/renew_membership.php [L]
|
||||
RewriteRule ^member_info$ src/pages/memberships/member_info.php [L]
|
||||
|
||||
|
||||
@@ -50,6 +50,11 @@ if ($showRenewModal) {
|
||||
if ($payment_status === 'PENDING RENEWAL') {
|
||||
$showRenewModal = false;
|
||||
}
|
||||
if (isMembershipExpiringSoon($user_id)) {
|
||||
$showRenewModal = true;
|
||||
} else {
|
||||
$showRenewModal = false;
|
||||
}
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
@@ -742,7 +747,7 @@ if (countUpcomingTrips() > 0) { ?>
|
||||
</div> -->
|
||||
<div class="modal-body">
|
||||
Your membership will be expiring soon. Click below to renew now.
|
||||
<a style="width:100%; display:block;" href="renew_membership" class="theme-btn style-two style-three mt-3">Renew Now</a>
|
||||
<a style="width:100%; display:block;" href="renewal_payment" class="theme-btn style-two style-three mt-3">Renew Now</a>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" style="width:100%; display:block;" class="theme-btn" data-bs-dismiss="modal">Remind Me Later</button>
|
||||
|
||||
@@ -29,6 +29,106 @@ function openDatabaseConnection()
|
||||
return $conn;
|
||||
}
|
||||
|
||||
//function to determine whether membership_end_date is within 3 months from current date where user_id = ?, if so return true, else false
|
||||
function isMembershipExpiringSoon($user_id)
|
||||
{
|
||||
$conn = openDatabaseConnection();
|
||||
if ($conn === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$stmt = $conn->prepare("SELECT membership_end_date FROM membership_fees WHERE user_id = ? LIMIT 1");
|
||||
if (!$stmt) {
|
||||
$conn->close();
|
||||
return false;
|
||||
}
|
||||
|
||||
$stmt->bind_param('i', $user_id);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
if ($result->num_rows === 0) {
|
||||
$stmt->close();
|
||||
$conn->close();
|
||||
return false;
|
||||
}
|
||||
|
||||
$row = $result->fetch_assoc();
|
||||
$membership_end_date = new DateTime($row['membership_end_date']);
|
||||
$current_date = new DateTime();
|
||||
$interval = $current_date->diff($membership_end_date);
|
||||
|
||||
$stmt->close();
|
||||
$conn->close();
|
||||
|
||||
return ($interval->days <= 90 && $membership_end_date > $current_date);
|
||||
}
|
||||
|
||||
function normalizeName($name) {
|
||||
$name = strtolower($name);
|
||||
$name = preg_replace("/[^a-z\s]/", "", $name); // remove punctuation
|
||||
$name = preg_replace("/\s+/", " ", $name); // normalize spaces
|
||||
return trim($name);
|
||||
}
|
||||
|
||||
// function to checkif first name + last name matches names in an array. names may have slight variations or spelling mistakes.
|
||||
function validateHonoraryMemberName($first_name, $last_name)
|
||||
{
|
||||
$honorary_names = [
|
||||
"robin hood",
|
||||
"marc rademaker",
|
||||
"clive robinson",
|
||||
"joern kuebler",
|
||||
"maurice compton",
|
||||
"jenny cole",
|
||||
"geoff joubert",
|
||||
"alan exton",
|
||||
"dave bell",
|
||||
"karl hoffman",
|
||||
"gerald obrian"
|
||||
// Add more honorary member names as needed
|
||||
];
|
||||
|
||||
$full_name = normalizeName($first_name . ' ' . $last_name);
|
||||
$full_name = strtolower($full_name);
|
||||
foreach ($honorary_names as $name) {
|
||||
similar_text($full_name, strtolower(normalizeName($name)), $percent);
|
||||
if ($percent >= 80) { // 80% similarity threshold
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//get membership_type from membership_applications table for user_id = ?
|
||||
function getMembershipType($user_id)
|
||||
{
|
||||
$conn = openDatabaseConnection();
|
||||
if ($conn === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$stmt = $conn->prepare("SELECT membership_type FROM membership_applications WHERE user_id = ? ORDER BY id DESC LIMIT 1");
|
||||
if (!$stmt) {
|
||||
$conn->close();
|
||||
return null;
|
||||
}
|
||||
|
||||
$stmt->bind_param('i', $user_id);
|
||||
$stmt->execute();
|
||||
$stmt->bind_result($membership_type);
|
||||
if ($stmt->fetch()) {
|
||||
$stmt->close();
|
||||
$conn->close();
|
||||
return $membership_type;
|
||||
} else {
|
||||
$stmt->close();
|
||||
$conn->close();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function progress_log($message, $context = null)
|
||||
{
|
||||
try {
|
||||
|
||||
@@ -221,7 +221,7 @@ if (empty($application['id_number'])) {
|
||||
|
||||
if (strtotime($today) >= strtotime($threeMonthsBefore)) {
|
||||
echo '
|
||||
<a href="renew_membership" class="theme-btn style-two bgc-secondary" style="width:100%; margin-top: 20px; background-color: #63ab45; padding: 10px 20px; color: white; text-decoration: none; border-radius: 25px;">
|
||||
<a href="renewal_payment" class="theme-btn style-two bgc-secondary" style="width:100%; margin-top: 20px; background-color: #63ab45; padding: 10px 20px; color: white; text-decoration: none; border-radius: 25px;">
|
||||
<span data-hover="Renew Membership">Renew Membership</span>
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</a>';
|
||||
|
||||
@@ -14,6 +14,37 @@ if (isset($_SESSION['user_id'])) {
|
||||
|
||||
$full_name = getFullName($user_id);
|
||||
|
||||
if (isset($_POST['membership_type'])) {
|
||||
$membership_type = $_POST['membership_type'];
|
||||
echo $membership_type;
|
||||
//update membership_type in membership_application
|
||||
$stmt = $conn->prepare("UPDATE membership_application SET membership_type = ? WHERE user_id = ? ");
|
||||
$stmt->bind_param("si", $membership_type, $user_id);
|
||||
$stmt->execute();
|
||||
$stmt->close();
|
||||
} else {
|
||||
//get user membership type from membership_applications
|
||||
$stmt = $conn->prepare("SELECT membership_type FROM membership_application WHERE user_id = ? ");
|
||||
$stmt->bind_param("i", $user_id);
|
||||
$stmt->execute();
|
||||
$stmt->bind_result($membership_type);
|
||||
$stmt->fetch();
|
||||
$stmt->close();
|
||||
}
|
||||
|
||||
//check memberhsip_applications for user_id, if 0 rows, redirect to membership_application.php
|
||||
$stmt = $conn->prepare("SELECT COUNT(*) AS cnt FROM membership_application WHERE user_id = ? LIMIT 1");
|
||||
$stmt->bind_param("i", $user_id);
|
||||
|
||||
$stmt->execute();
|
||||
$stmt->bind_result($application_count);
|
||||
$stmt->fetch();
|
||||
$stmt->close();
|
||||
if ($application_count == 0) {
|
||||
header("Location: membership_application.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
//if membership_fees payment_status is PENDING RENEWAL, redirect to membership_details.php
|
||||
$stmt = $conn->prepare("SELECT payment_status FROM membership_fees WHERE user_id = ? LIMIT 1");
|
||||
$stmt->bind_param("i", $user_id);
|
||||
@@ -27,8 +58,25 @@ if ($payment_status === 'PENDING RENEWAL') {
|
||||
exit();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if ($membership_type === 'country') {
|
||||
$payment_amount = getPriceByDescription('country_membership');
|
||||
} elseif ($membership_type === 'single') {
|
||||
$payment_amount = getPriceByDescription('single');
|
||||
} else {
|
||||
$payment_amount = getPriceByDescription('membership_fees');
|
||||
}
|
||||
|
||||
if ($membership_type === 'honorary') {
|
||||
// Honorary members do not pay fees, redirect to membership details
|
||||
header("Location: membership_details.php");
|
||||
exit();
|
||||
|
||||
}
|
||||
|
||||
$payment_id = generatePaymentRef('SUBS', null, $user_id);
|
||||
$payment_amount = getPriceByDescription('membership_fees');
|
||||
$payment_date = date('Y-m-d');
|
||||
$renewal_period_end = getMembershipEndDate($user_id);
|
||||
// Hardcode membership start date to 2026-03-01 per request
|
||||
|
||||
182
src/pages/memberships/renewal_payment.php
Normal file
182
src/pages/memberships/renewal_payment.php
Normal file
@@ -0,0 +1,182 @@
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
$rootPath = dirname(dirname(dirname(__DIR__)));
|
||||
include_once($rootPath . '/header.php');
|
||||
// Assuming you have the user ID stored in the session
|
||||
if (isset($_SESSION['user_id'])) {
|
||||
$user_id = $_SESSION['user_id'];
|
||||
} else {
|
||||
header('Location: login.php');
|
||||
exit(); // Stop further script execution
|
||||
}
|
||||
|
||||
// Initialize variables
|
||||
$payment_amount = null;
|
||||
$membership_start_date = null;
|
||||
$membership_end_date = null;
|
||||
|
||||
$continue_processing = isMembershipExpiringSoon($user_id);
|
||||
if (!$continue_processing) {
|
||||
header("Location: membership_details.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
// Determine current membership type (default) and available renewal prices
|
||||
$membership_type = getMembershipType($user_id);
|
||||
if ($membership_type === 'honorary') {
|
||||
// Honorary members do not renew
|
||||
header("Location: membership_details.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
// Fetch prices for all types so we can show dynamic updates client-side
|
||||
$price_full = getPriceByDescription('membership_fees');
|
||||
$price_single = getPriceByDescription('single');
|
||||
$price_country = getPriceByDescription('country_membership');
|
||||
|
||||
// Set the initially displayed renewal amount based on current membership type
|
||||
switch ($membership_type) {
|
||||
case 'country':
|
||||
$current_renewal_amount = $price_country;
|
||||
break;
|
||||
case 'single':
|
||||
$current_renewal_amount = $price_single;
|
||||
break;
|
||||
default:
|
||||
$current_renewal_amount = $price_full;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Get the user_id from the session
|
||||
$user_id = isset($_SESSION['user_id']) ? $_SESSION['user_id'] : null;
|
||||
|
||||
if ($user_id) {
|
||||
// Prepare the SQL query to fetch data
|
||||
$query = "SELECT payment_amount, membership_start_date, membership_end_date, payment_id
|
||||
FROM membership_fees
|
||||
WHERE user_id = ?";
|
||||
|
||||
if ($stmt = $conn->prepare($query)) {
|
||||
// Bind the user_id parameter to the query
|
||||
$stmt->bind_param("i", $user_id);
|
||||
|
||||
// Execute the query
|
||||
$stmt->execute();
|
||||
|
||||
// Bind the results to variables
|
||||
$stmt->bind_result($payment_amount, $membership_start_date, $membership_end_date, $eft_id);
|
||||
|
||||
// Fetch the data
|
||||
if ($stmt->fetch()) {
|
||||
// Values are now assigned to $payment_amount, $membership_start_date, and $membership_end_date
|
||||
} else {
|
||||
// Handle case where no records are found
|
||||
$error_message = "No records found for the given user ID.";
|
||||
}
|
||||
|
||||
// Close the statement
|
||||
$stmt->close();
|
||||
} else {
|
||||
// Handle query preparation failure
|
||||
$error_message = "Query preparation failed: " . $conn->error;
|
||||
}
|
||||
} else {
|
||||
// Handle case where user_id is not found in session
|
||||
$error_message = "User ID not found in session.";
|
||||
}
|
||||
?>
|
||||
|
||||
<?php
|
||||
$pageTitle = 'Membership Renewal';
|
||||
$breadcrumbs = [['Home' => 'index.php']];
|
||||
require_once($rootPath . '/components/banner.php');
|
||||
?>
|
||||
<!-- Contact Form Area start -->
|
||||
<section class="about-us-area py-100 rpb-90 rel z-1">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<div class="section-title mb-25">
|
||||
<span class="h2 mb-15">Membership Renewal:</span>
|
||||
<?php echo
|
||||
'<h5>Membership Expiration Date: ' . $membership_end_date . '</h5>'; ?>
|
||||
</div>
|
||||
|
||||
<h5>Renewal Amount:</h5>
|
||||
|
||||
<form method="post" action="renew_membership" id="renewForm">
|
||||
<input type="hidden" name="csrf_token" value="<?php echo generateCSRFToken(); ?>">
|
||||
|
||||
<div class="mb-3">
|
||||
<div class="form-check">
|
||||
<input type="radio" name="membership_type" id="radio_full" value="full" <?php echo ($membership_type === 'full' || $membership_type === 'member' || $membership_type === null) ? 'checked' : ''; ?>>
|
||||
<label class="form-check-label" for="radio_full">Family Membership</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="radio" name="membership_type" id="radio_single" value="single" <?php echo ($membership_type === 'single') ? 'checked' : ''; ?>>
|
||||
<label class="form-check-label" for="radio_single">Single Membership</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="radio" name="membership_type" id="radio_country" value="country" <?php echo ($membership_type === 'country') ? 'checked' : ''; ?>>
|
||||
<label class="form-check-label" for="radio_country">Country Membership</label>
|
||||
<small>You need to reside more than 150km from BASE4 to qualify.</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h5>Amount:</h5>
|
||||
|
||||
<h2>R <span id="renewAmount"><?php echo number_format($current_renewal_amount, 2); ?></span></h2>
|
||||
|
||||
<button type="submit" class="theme-btn style-two style-three" style="width:100%;">
|
||||
<span data-hover="Renew Membership">Renew Membership</span>
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</button>
|
||||
<div class="text-center mt-2">
|
||||
<p>You will be redirected to iKhokha's Secure payment gateway.</p>
|
||||
</div>
|
||||
<img src="assets/images/logos/ikhokha.png" alt="Secure Payment Badges" style="max-width: 200px; display: block; margin: 10px auto 0;">
|
||||
</form>
|
||||
|
||||
<script>
|
||||
(function(){
|
||||
// Prices from server
|
||||
var prices = {
|
||||
full: <?php echo json_encode((float)$price_full); ?>,
|
||||
single: <?php echo json_encode((float)$price_single); ?>,
|
||||
country: <?php echo json_encode((float)$price_country); ?>
|
||||
};
|
||||
|
||||
function updateAmount(type){
|
||||
var amt = prices[type] !== undefined ? prices[type] : prices.full;
|
||||
document.getElementById('renewAmount').textContent = amt.toFixed(2);
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function(){
|
||||
var radios = document.querySelectorAll('input[name="membership_type"]');
|
||||
radios.forEach(function(r){
|
||||
r.addEventListener('change', function(){
|
||||
updateAmount(this.value);
|
||||
});
|
||||
});
|
||||
// initialize
|
||||
var checked = document.querySelector('input[name="membership_type"]:checked');
|
||||
if(checked) updateAmount(checked.value);
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6" data-aos="fade-right" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="about-us-image">
|
||||
<img src="assets/images/logos/weblogo.png" alt="About">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<?php include_once(dirname(dirname(dirname(__DIR__))) . '/components/insta_footer.php'); ?>
|
||||
@@ -8,7 +8,7 @@ require_once($rootPath . "/src/helpers/notification_helper.php");
|
||||
|
||||
$user_id = isset($_SESSION['user_id']) ? $_SESSION['user_id'] : null;
|
||||
$payment_id = generatePaymentRef('SUBS', null, $user_id);
|
||||
$status = 'AWAITING PAYMENT';
|
||||
|
||||
// If current month is December, attribute the membership year to the next year
|
||||
$currentYear = intval(date('Y'));
|
||||
$month = intval(date('n'));
|
||||
@@ -96,13 +96,17 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
//MEMBERSHIP TYPE
|
||||
$country_membership = isset($_POST['country_membership']) ? 1 : 0;
|
||||
$membership_type = in_array($_POST['membership_type'] ?? '', ['full', 'single']) ? $_POST['membership_type'] : 'full';
|
||||
|
||||
if ($country_membership) {
|
||||
$honorary_member = validateHonoraryMemberName($first_name, $last_name);
|
||||
if ($honorary_member) {
|
||||
$membership_type = 'honorary';
|
||||
} elseif ($country_membership) {
|
||||
$membership_type = 'country';
|
||||
}else{
|
||||
} else {
|
||||
$membership_type = $membership_type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Spouse or Partner details (optional)
|
||||
$spouse_first_name = !empty($_POST['spouse_first_name']) ? validateName($_POST['spouse_first_name']) : null;
|
||||
$spouse_last_name = !empty($_POST['spouse_last_name']) ? validateName($_POST['spouse_last_name']) : null;
|
||||
@@ -199,7 +203,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$year = (int)$today->format('Y');
|
||||
$payment_date = $today->format('Y-m-d');
|
||||
$membership_start_date = $payment_date;
|
||||
if ($membership_type === 'country') {
|
||||
$status = 'AWAITING PAYMENT';
|
||||
if ($membership_type === 'honorary') {
|
||||
// Honorary members do not pay fees, set amount to 0 and end date far in future
|
||||
$payment_amount = 0.00;
|
||||
$status = 'PAID';
|
||||
} elseif ($membership_type === 'country') {
|
||||
$payment_amount = getPriceByDescription('country_membership');
|
||||
$prorata_amount = calculateProrata(getPriceByDescription('country_prorata'));
|
||||
} elseif ($membership_type === 'single') {
|
||||
@@ -233,10 +242,14 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
->modify('last day of this month')
|
||||
->format('Y-m-d');
|
||||
}
|
||||
if ($membership_type === 'honorary') {
|
||||
// Honorary members do not pay fees, set amount to 0 and end date far in future
|
||||
$membership_end_date = '2099-12-31';
|
||||
}
|
||||
|
||||
$stmt = $conn->prepare("INSERT INTO membership_fees (user_id, payment_amount, payment_date, membership_start_date, membership_end_date, renewal_period_end, payment_status, payment_id)
|
||||
VALUES (?, ?, ?, ?, ?, ?, 'AWAITING PAYMENT', ?)");
|
||||
$stmt->bind_param("idsssss", $user_id, $payment_amount, $payment_date, $membership_start_date, $membership_end_date, $membership_end_date, $payment_id);
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
$stmt->bind_param("idssssss", $user_id, $payment_amount, $payment_date, $membership_start_date, $membership_end_date, $membership_end_date, $status, $payment_id);
|
||||
|
||||
if ($stmt->execute()) {
|
||||
// Commit the transaction
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 4.9 KiB |
Reference in New Issue
Block a user