updated to add country membership, singles and honorary recognition

This commit is contained in:
twotalesanimation
2025-12-20 00:32:29 +02:00
parent 782d343243
commit 9653443c09
8 changed files with 360 additions and 11 deletions

View File

@@ -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]

View File

@@ -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>

View File

@@ -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 {

View File

@@ -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>';

View File

@@ -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

View 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'); ?>

View File

@@ -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) {
$membership_type = 'country';
}else{
$honorary_member = validateHonoraryMemberName($first_name, $last_name);
if ($honorary_member) {
$membership_type = 'honorary';
} elseif ($country_membership) {
$membership_type = 'country';
} 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