| Current Path : /var/www/cesa.co.za/php/includes/ |
| Current File : /var/www/cesa.co.za/php/includes/SchoolAttendees.php |
<?php
/*
* Contact otto@igotafrica.com for details
*/
include_once($_SERVER['DOCUMENT_ROOT'] . '/php/includes/BaseTableClass.php');
include_once($_SERVER['DOCUMENT_ROOT'] . '/php/includes/AnonRespondees.php');
include_once($_SERVER['DOCUMENT_ROOT'] . '/php/includes/SchoolEvents.php');
include_once($_SERVER['DOCUMENT_ROOT'] . '/php/includes/SchoolPayments.php');
include_once($_SERVER['DOCUMENT_ROOT'] . '/php/includes/ErrorLog.php');
/**
* Control the SchoolAttendees table
*
* @author Otto Saayman
*/
class SchoolAttendees extends BaseTableClass
{
/** School (SCE) certificate copy / dev test recipient — not CPD (cpdcertificates@). */
const SCHOOL_CERTIFICATE_DEFAULT_EMAIL = 'blessings@cesa.co.za';
public function createTableIfNotExists() {
$createTable = "CREATE TABLE `SchoolAttendees` (
`AttendeeID` int(11) NOT NULL,
`ContactTitle` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`ContactFirstName` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`ContactLastName` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`CompanyName` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`AddressLine1` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`AddressLine2` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`AddressLine3` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`City` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`PostalCode` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`PhoneNumber` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`MobileNumber` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`FaxNumber` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`EmailAddress` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`DietaryReq` longtext CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`EventID` int(11) DEFAULT 0,
`Attended` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT 'y',
`OrderNum` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`OrgVATNum` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`IDNumber` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`SAACEMemNumber` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`ECSANumber` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`Designation` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`Cancelled` int(11) NOT NULL DEFAULT 0,
`DateCancelled` datetime DEFAULT NULL,
`BookingName` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`BookingTel` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`BookingEmail` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`BookingFax` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`DateBooked` datetime DEFAULT NULL,
`KnownAs` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`Comments` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`CertificateSent` datetime DEFAULT NULL,
`CompanyType` varchar(50) DEFAULT NULL,
`SAICEMember` tinyint(1) DEFAULT 0,
`SAICEMemNumber` varchar(50) DEFAULT NULL,
`CESAStaff` tinyint(1) NOT NULL DEFAULT 0,
`BookingForm` longtext DEFAULT NULL,
`ResponsiblePayment` varchar(255) DEFAULT NULL,
`ResponsiblePaymentName` varchar(255) DEFAULT NULL,
`ResponsiblePaymentCellNo` varchar(255) DEFAULT NULL,
`ResponsiblePaymentDesignation` varchar(255) DEFAULT NULL,
`HRManagerName` varchar(255) DEFAULT NULL,
`HRManagerCellNo` varchar(20) DEFAULT NULL,
`HRManagerEMail` varchar(255) DEFAULT NULL,
`MarketingSource` varchar(255) DEFAULT NULL,
`PackageChosen` varchar(255) DEFAULT NULL,
`Parking` tinyint(1) NOT NULL DEFAULT 0,
`DateUpdated` datetime DEFAULT NULL,
`ProfAssoc` varchar(255) DEFAULT NULL,
`Province` varchar(255) DEFAULT NULL,
`Country` varchar(255) DEFAULT NULL,
`ProfAssocMemNum` varchar(255) DEFAULT NULL,
`TestCompleted` tinyint(1) NOT NULL DEFAULT 0,
`TestPassed` tinyint(1) NOT NULL DEFAULT 0,
`YearsExperience` decimal(10,2) DEFAULT NULL,
`Subscribed` char(1) DEFAULT NULL,
`QuizReminderSent` datetime DEFAULT NULL,
`BlockReminderCertSend` tinyint(1) NOT NULL DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci;
--
-- Indexes for dumped tables
--
--
-- Indexes for table `SchoolAttendees`
--
ALTER TABLE `SchoolAttendees`
ADD PRIMARY KEY (`AttendeeID`),
ADD UNIQUE KEY `ContactTitle` (`ContactFirstName`,`ContactLastName`,`PhoneNumber`,`EmailAddress`,`EventID`),
ADD KEY `EventAttended` (`EventID`,`Attended`);
--
-- AUTO_INCREMENT for dumped tables
--
--
-- AUTO_INCREMENT for table `SchoolAttendees`
--
ALTER TABLE `SchoolAttendees`
MODIFY `AttendeeID` int(11) NOT NULL AUTO_INCREMENT;";
}
public function findById($id)
{
$sql = "SELECT * FROM SchoolAttendees sa "
. "INNER JOIN SchoolEvents se ON sa.EventId = se.EventID "
. "WHERE sa.AttendeeID = " . $this->sqlf->qstr($id);
// echo $sql;
return $this->sqlf->getRow($sql);
}
public function findAllIds()
{
return $this->sqlf->getAll("SELECT AttendeeID FROM SchoolAttendees "
. "WHERE EmailAddress IS NOT NULL AND EmailAddress != '' AND EmailAddress NOT LIKE 'no e-mail address%' "
. "AND Cancelled = 0");
}
public function upsert($SchoolAttendees)
{
$action = 'INSERT';
$where = '';
// var_dump($SchoolAttendees);
// exit;
if (isset($SchoolAttendees['AttendeeID']) && $SchoolAttendees['AttendeeID'] > 0) {
$action = 'UPDATE';
$where = 'AttendeeID = ' . $SchoolAttendees['AttendeeID'];
}
if (isset($SchoolAttendees['Cancelled']) && $SchoolAttendees['Cancelled'] > 0) {
$SchoolAttendees['Attended'] = 'n';
}
// var_dump($SchoolAttendees);
// exit;
return $this->sqlf->autoExecute('SchoolAttendees', $SchoolAttendees, $action, $where, 'AttendeeID');
}
public function findToSendCertificates()
{
$findSendCertSQL = "SELECT *, SchoolEvents.Cancelled AS EventCancelled FROM SchoolAttendees "
. "INNER JOIN SchoolEvents ON SchoolAttendees.EventID = SchoolEvents.EventID "
. "WHERE SchoolEvents.Cancelled = 0 AND SchoolEvents.EndDate <= NOW() "
. "AND (SchoolAttendees.CertificateSent IS NULL OR SchoolAttendees.CertificateSent = '' OR SchoolAttendees.CertificateSent = '0000-00-00 00:00:00') "
. "AND SchoolAttendees.Attended = 'y' "
. "AND SchoolAttendees.Cancelled = 0 "
. "AND SchoolEvents.Cancelled = 0 "
. "AND SchoolEvents.EndDate > '2023-07-01' "
. "AND (SchoolEvents.TrainerID IS NULL OR SchoolEvents.TrainerID NOT IN (45, 52)) "
. "AND SchoolAttendees.AttendeeID IN (SELECT AttendeeID FROM SchoolPayments)"
// . "LIMIT 0, 10"
;
// ErrorLog::logInfo('Selecting attendees for events: ' . $findSendCertSQL);
// echo $findSendCertSQL . " <br />\r\n";
return $this->sqlf->getAll($findSendCertSQL);
}
public function findByEventId($eventId)
{
// echo "SELECT * FROM SchoolAttendees "
// . "INNER JOIN SchoolEvents ON SchoolAttendees.EventID = SchoolEvents.EventID "
// . "WHERE SchoolAttendees.EventID = $eventId <br />";
return $this->sqlf->getAll("SELECT * FROM SchoolAttendees "
. "INNER JOIN SchoolEvents ON SchoolAttendees.EventID = SchoolEvents.EventID "
. "WHERE SchoolAttendees.EventID = $eventId");
}
public function chooseAttendedPaid($requestVars)
{
$attendeeIds = array();
if (isset($requestVars['AttendeeIDs']) && strlen($requestVars['AttendeeIDs']) > 0) {
$attendeeIds = json_decode($requestVars['AttendeeIDs'], true);
}
if ((isset($requestVars['markAllAsAttendedPaid']) && $requestVars['markAllAsAttendedPaid'] > 0) || (isset($requestVars['markSelectedAsAttendedPaid']) && $requestVars['markSelectedAsAttendedPaid'] > 0)) {
$this->markAllAsAttendedPaid($requestVars['EventID'], true, true, $attendeeIds);
} elseif ((isset($requestVars['markAllAsAttended']) && $requestVars['markAllAsAttended'] > 0) || (isset($requestVars['markSelectedAsAttended']) && $requestVars['markSelectedAsAttended'] > 0)) {
$this->markAllAsAttendedPaid($requestVars['EventID'], true, false, $attendeeIds);
} elseif ((isset($requestVars['markAllAsPaid']) && $requestVars['markAllAsPaid'] > 0) || (isset($requestVars['markSelectedAsPaid']) && $requestVars['markSelectedAsPaid'] > 0)) {
$this->markAllAsAttendedPaid($requestVars['EventID'], false, true, $attendeeIds);
} elseif ((isset($requestVars['markAllAsNotAttendedPaid']) && $requestVars['markAllAsNotAttendedPaid'] > 0) || (isset($requestVars['markSelectedAsNotAttendedPaid']) && $requestVars['markSelectedAsNotAttendedPaid'] > 0)) {
$this->markAllAsNotAttendedPaid($requestVars['EventID'], true, true, $attendeeIds);
} elseif ((isset($requestVars['markAllAsNotAttended']) && $requestVars['markAllAsNotAttended'] > 0) || (isset($requestVars['markSelectedAsNotAttended']) && $requestVars['markSelectedAsNotAttended'] > 0)) {
$this->markAllAsNotAttendedPaid($requestVars['EventID'], true, false, $attendeeIds);
} elseif ((isset($requestVars['markAllAsNotPaid']) && $requestVars['markAllAsNotPaid'] > 0) || (isset($requestVars['markSelectedAsNotPaid']) && $requestVars['markSelectedAsNotPaid'] > 0)) {
$this->markAllAsNotAttendedPaid($requestVars['EventID'], false, true, $attendeeIds);
}
}
public function markAllAsAttendedPaid($eventId, $attended = true, $paid = true, $attendeeIds = array(), $unpaid = false)
{
global $sqlf;
$eventAttendees = $this->findByEventId($eventId);
$marketingPaymentObject = new SchoolPayments($sqlf);
foreach ($eventAttendees as $eventAttendee) {
if (count($attendeeIds) > 0 && !in_array($eventAttendee['AttendeeID'], $attendeeIds)) {
continue;
}
if ($attended) {
$eventAttendee['Attended'] = 'y';
unset($eventAttendee['EventName']);
unset($eventAttendee['EventDescription']);
unset($eventAttendee['Level']);
unset($eventAttendee['Venue']);
unset($eventAttendee['StartDate']);
unset($eventAttendee['EndDate']);
unset($eventAttendee['StartTime']);
unset($eventAttendee['EndTime']);
unset($eventAttendee['AvailableSpaces']);
unset($eventAttendee['CostPerPerson']);
unset($eventAttendee['FacilitatorID']);
unset($eventAttendee['ProviderID']);
unset($eventAttendee['PresenterID']);
unset($eventAttendee['Hours']);
unset($eventAttendee['CPD']);
unset($eventAttendee['CODE']);
unset($eventAttendee['NQFLevel']);
unset($eventAttendee['AccredNum']);
unset($eventAttendee['RegDeadline']);
unset($eventAttendee['Category']);
unset($eventAttendee['Onceoff']);
unset($eventAttendee['OnceoffSeq']);
unset($eventAttendee['MemberDiscount']);
unset($eventAttendee['EarlyBirdDiscount']);
unset($eventAttendee['EarlyBirdDate']);
unset($eventAttendee['Cancelled']);
unset($eventAttendee['BankAccName']);
unset($eventAttendee['ExternalLink']);
unset($eventAttendee['SchoolCourseID']);
unset($eventAttendee['FileAttachment']);
unset($eventAttendee['WebCategory']);
unset($eventAttendee['CandidateAcademy']);
unset($eventAttendee['BookingConfirmed']);
unset($eventAttendee['AttendanceRegister']);
unset($eventAttendee['SACPCMPNum']);
unset($eventAttendee['AccredNum2']);
unset($eventAttendee['CostPackage']);
unset($eventAttendee['ContactPerson']);
unset($eventAttendee['ContactTel']);
unset($eventAttendee['ContactEmail']);
unset($eventAttendee['CourseType']);
unset($eventAttendee['OnlineCourseLink']);
unset($eventAttendee['QuestionnaireID']);
unset($eventAttendee['TestRequired']);
unset($eventAttendee['TrainerID']);
unset($eventAttendee['AttendanceRegister2']);
unset($eventAttendee['AttendanceRegister3']);
unset($eventAttendee['AttendanceRegister4']);
unset($eventAttendee['AttendanceRegister5']);
unset($eventAttendee['CopyRegFormTo']);
unset($eventAttendee['TrainerInvRecv']);
unset($eventAttendee['ECSACategory']);
unset($eventAttendee['SACPCMPCategory']);
unset($eventAttendee['SACPCMP_CPDPoints']);
unset($eventAttendee['OtherCPDPoints']);
unset($eventAttendee['SendRegistrationConfirmation']);
unset($eventAttendee['PilotCourse']);
unset($eventAttendee['Archived']);
unset($eventAttendee['CertificateSent']);
unset($eventAttendee['DateUpdated']);
unset($eventAttendee['QuizReminderSent']);
unset($eventAttendee['DateCancelled']);
unset($eventAttendee['CESAVerificationNumberDates']);
unset($eventAttendee['SACNASP_ValidationNumber']);
unset($eventAttendee['SACNASP_CPD_Points']);
unset($eventAttendee['YearsExperience']);
$this->sqlf->autoExecute('SchoolAttendees', $eventAttendee, 'UPDATE', 'AttendeeID = ' . $eventAttendee['AttendeeID']);
$this->sqlf->execute("UPDATE SchoolAttendees SET CertificateSent = NULL WHERE CertificateSent = '0000-00-00'");
$this->sqlf->execute("UPDATE SchoolAttendees SET QuizReminderSent = NULL WHERE QuizReminderSent = '0000-00-00'");
}
if ($paid) {
$marketingPaymentObject->markPaidByEventAttendeeId($eventAttendee['AttendeeID'], $eventAttendee['CostPerPerson'], $eventAttendee['EventID']);
} elseif ($unpaid) {
$marketingPaymentObject->markUnpaidByEventAttendeeId($eventAttendee['AttendeeID'], $eventAttendee['EventID']);
}
$this->SchoolAttendeeUpsert($eventAttendee['AttendeeID']);
} //foreach
}
public function markAllAsNotAttendedPaid($eventId, $attended = true, $paid = true, $attendeeIds = array(), $unpaid = false)
{
global $sqlf;
$eventAttendees = $this->findByEventId($eventId);
$marketingPaymentObject = new SchoolPayments($sqlf);
foreach ($eventAttendees as $eventAttendee) {
if (count($attendeeIds) > 0 && !in_array($eventAttendee['AttendeeID'], $attendeeIds)) {
continue;
}
if ($attended) {
$eventAttendee['Attended'] = 'n';
unset($eventAttendee['EventName']);
unset($eventAttendee['EventDescription']);
unset($eventAttendee['Level']);
unset($eventAttendee['Venue']);
unset($eventAttendee['StartDate']);
unset($eventAttendee['EndDate']);
unset($eventAttendee['StartTime']);
unset($eventAttendee['EndTime']);
unset($eventAttendee['AvailableSpaces']);
unset($eventAttendee['CostPerPerson']);
unset($eventAttendee['FacilitatorID']);
unset($eventAttendee['ProviderID']);
unset($eventAttendee['PresenterID']);
unset($eventAttendee['Hours']);
unset($eventAttendee['CPD']);
unset($eventAttendee['CODE']);
unset($eventAttendee['NQFLevel']);
unset($eventAttendee['AccredNum']);
unset($eventAttendee['RegDeadline']);
unset($eventAttendee['Category']);
unset($eventAttendee['Onceoff']);
unset($eventAttendee['OnceoffSeq']);
unset($eventAttendee['MemberDiscount']);
unset($eventAttendee['EarlyBirdDiscount']);
unset($eventAttendee['EarlyBirdDate']);
unset($eventAttendee['Cancelled']);
unset($eventAttendee['BankAccName']);
unset($eventAttendee['ExternalLink']);
unset($eventAttendee['SchoolCourseID']);
unset($eventAttendee['FileAttachment']);
unset($eventAttendee['WebCategory']);
unset($eventAttendee['CandidateAcademy']);
unset($eventAttendee['BookingConfirmed']);
unset($eventAttendee['AttendanceRegister']);
unset($eventAttendee['SACPCMPNum']);
unset($eventAttendee['AccredNum2']);
unset($eventAttendee['CostPackage']);
unset($eventAttendee['ContactPerson']);
unset($eventAttendee['ContactTel']);
unset($eventAttendee['ContactEmail']);
unset($eventAttendee['CourseType']);
unset($eventAttendee['OnlineCourseLink']);
unset($eventAttendee['QuestionnaireID']);
unset($eventAttendee['TestRequired']);
unset($eventAttendee['TrainerID']);
unset($eventAttendee['AttendanceRegister2']);
unset($eventAttendee['AttendanceRegister3']);
unset($eventAttendee['AttendanceRegister4']);
unset($eventAttendee['AttendanceRegister5']);
unset($eventAttendee['CopyRegFormTo']);
unset($eventAttendee['TrainerInvRecv']);
unset($eventAttendee['SACPCMPCategory']);
unset($eventAttendee['SACPCMP_CPDPoints']);
unset($eventAttendee['OtherCPDPoints']);
unset($eventAttendee['SendRegistrationConfirmation']);
unset($eventAttendee['PilotCourse']);
unset($eventAttendee['Archived']);
unset($eventAttendee['CertificateSent']);
unset($eventAttendee['DateUpdated']);
unset($eventAttendee['QuizReminderSent']);
unset($eventAttendee['DateCancelled']);
$this->sqlf->autoExecute('SchoolAttendees', $eventAttendee, 'UPDATE', 'AttendeeID = ' . $eventAttendee['AttendeeID']);
// $this->sqlf->execute("UPDATE SchoolAttendees SET CertificateSent = NULL WHERE CertificateSent = '0000-00-00'");
// $this->sqlf->execute("UPDATE SchoolAttendees SET QuizReminderSent = NULL WHERE QuizReminderSent = '0000-00-00'");
}
if ($paid) {
$marketingPaymentObject->markUnpaidByEventAttendeeId($eventAttendee['AttendeeID'], $eventAttendee['EventID']);
}
$this->SchoolAttendeeUpsert($eventAttendee['AttendeeID']);
} //foreach
}
function SchoolAttendeeUpsert($attendeeId, $attendeeRow = array())
{
global $sqlf;
// Initialize debug array to collect all debug information
$debugInfo = [];
$debugInfo[] = "=== SchoolAttendeeUpsert Debug Log ===";
$debugInfo[] = "Timestamp: " . date('Y-m-d H:i:s');
$debugInfo[] = "AttendeeID: " . $attendeeId;
$hasFailures = false;
// var_dump($attendeeRow);
// exit;
$schoolAttendee = $this->findById($attendeeId);
// If attendee doesn't exist, return early to prevent creating records without EventID
if (!$schoolAttendee || !isset($schoolAttendee['EventID']) || empty($schoolAttendee['EventID'])) {
$debugInfo[] = 'ERROR: Attendee not found or missing EventID. AttendeeID: ' . $attendeeId;
// ErrorLog::logInfo('SchoolAttendeeUpsert: Attendee not found or missing EventID. AttendeeID: ' . $attendeeId);
return;
}
// Check if DateBooked needs to be set - use $schoolAttendee from database, not $attendeeRow
if (is_null($schoolAttendee['DateBooked']) || $schoolAttendee['DateBooked'] == '' || $schoolAttendee['DateBooked'] == '0000-00-00 00:00:00') {
$schoolAttendeeUpdate['AttendeeID'] = $attendeeId; // Use the function parameter, not $attendeeRow
$schoolAttendeeUpdate['DateBooked'] = date('Y-m-d H:i:s');
$this->upsert($schoolAttendeeUpdate);
}
// var_dump($attendeeRow['Cancelled']);
// exit;
if ((isset($attendeeRow['Cancelled']) && !is_null($attendeeRow['Cancelled']) && $attendeeRow['Cancelled'] > 0)
|| (isset($attendeeRow['EventCancelled']) && !is_null($attendeeRow['EventCancelled']) && $attendeeRow['EventCancelled'] > 0)
) {
$schoolAttendeeUpdate['AttendeeID'] = $attendeeId; // Use the function parameter, not $attendeeRow
$schoolAttendeeUpdate['Attended'] = 'n';
$schoolAttendee['Attended'] = 'n';
$this->upsert($schoolAttendeeUpdate);
}
$schoolEvents = new SchoolEvents($sqlf);
$schoolEvent = $schoolEvents->findById($schoolAttendee['EventID']);
$schoolCourses = new SchoolCourses($sqlf);
$schoolCourse = $schoolCourses->findById($schoolEvent['SchoolCourseID']);
$eventEndDate = new DateTime($schoolEvent['EndDate'] . ' ' . $schoolEvent['EndTime']);
$debugInfo[] = 'Event: ' . $schoolEvent['EventName'] . ' (ID: ' . $schoolEvent['EventID'] . ')';
$debugInfo[] = 'Course: ' . $schoolCourse['CourseName'] . ' (ID: ' . $schoolCourse['CourseID'] . ')';
$debugInfo[] = 'Event End Date: ' . $eventEndDate->format('Y-m-d H:i:s');
if ($eventEndDate->getTimestamp() > time()) {
// Event not ended yet
$debugInfo[] = $schoolEvent['EventName'] . ' - Event not ended yet';
// Email debug information and return
// self::emailDebugInfo($debugInfo);
return;
}
$dateBooked = new DateTime($schoolAttendee['DateBooked']);
if ($eventEndDate->getTimestamp() < $dateBooked->getTimestamp()) {
//Use date booked, because attendee was added after the event
$eventEndDate = clone $dateBooked;
}
$mustSend = 0;
$sendReminder = false;
$feedbackCompleted = 0;
$anonRespondeeObj = new AnonRespondees($this->sqlf);
// School Feedback Questionnaire is hard coded in /echasl23rptSchoolFeedbackQues.php
$anonRespondee = $anonRespondeeObj->findBySchoolAttendeeId(225, $schoolAttendee['AttendeeID']);
if (is_array($anonRespondee) && count($anonRespondee) > 0) {
$feedbackCompleted = 1;
$debugInfo[] = 'Feedback found by SchoolAttendeeID';
} else {
// Attempt to find feedback by ID number
$anonRespondee = $anonRespondeeObj->findByIDNumber(225, $schoolAttendee['IDNumber'], $schoolAttendee['EventID']);
if (is_array($anonRespondee) && count($anonRespondee) > 0) {
$feedbackCompleted = 1;
$debugInfo[] = 'Feedback found by ID Number: ' . $schoolAttendee['IDNumber'];
$anonRespondeeRow = $anonRespondeeObj->find($anonRespondee['Anon_RespondeeID']);
$anonRespondeeRow['SchoolAttendeeID'] = $schoolAttendee['AttendeeID'];
$anonRespondeeObj->upsert($anonRespondeeRow);
} else {
// Attempt to find feedback by e-mail address
$anonRespondee = $anonRespondeeObj->findByEMail(225, $schoolAttendee['EmailAddress'], $schoolAttendee['EventID']);
if (is_array($anonRespondee) && count($anonRespondee) > 0) {
$feedbackCompleted = 1;
$debugInfo[] = 'Feedback found by Email: ' . $schoolAttendee['EmailAddress'];
$anonRespondeeRow = $anonRespondeeObj->find($anonRespondee['Anon_RespondeeID']);
$anonRespondeeRow['SchoolAttendeeID'] = $schoolAttendee['AttendeeID'];
$anonRespondeeObj->upsert($anonRespondeeRow);
} else
// Attempt to find feedback by name and surname
$anonRespondee = $anonRespondeeObj->findByNameLastname(225, $schoolAttendee['ContactFirstName'], $schoolAttendee['ContactLastName'], $schoolAttendee['EventID']);
if (is_array($anonRespondee) && count($anonRespondee) > 0) {
$feedbackCompleted = 1;
$debugInfo[] = 'Feedback found by Name: ' . $schoolAttendee['ContactFirstName'] . ' ' . $schoolAttendee['ContactLastName'];
$anonRespondeeRow = $anonRespondeeObj->find($anonRespondee['Anon_RespondeeID']);
$anonRespondeeRow['SchoolAttendeeID'] = $schoolAttendee['AttendeeID'];
$anonRespondeeObj->upsert($anonRespondeeRow);
} else {
$debugInfo[] = 'No feedback found for attendee';
}
}
}
if ($feedbackCompleted > 0) {
$mustSend = 1;
}
if ($mustSend > 0 && $schoolEvent['QuestionnaireID'] > 0 && $schoolAttendee['TestCompleted'] <= 0) {
//Look for a test completed before the event attendee was added
$anonRespondeeObj = new AnonRespondees($this->sqlf);
$anonRespondee = $anonRespondeeObj->findByEMail($schoolEvent['QuestionnaireID'], $schoolAttendee['EmailAddress']);
if ((!is_array($anonRespondee) || count($anonRespondee) <= 0) && strlen($schoolAttendee['IDNumber']) > 0) {
$anonRespondee = $anonRespondeeObj->findByIDNumber($schoolEvent['QuestionnaireID'], $schoolAttendee['IDNumber']);
}
if ((!is_array($anonRespondee) || count($anonRespondee) <= 0) && strlen($schoolAttendee['ContactFirstName']) > 0 && strlen($schoolAttendee['ContactLastName']) > 0) {
$anonRespondee = $anonRespondeeObj->findByNameLastname($schoolEvent['QuestionnaireID'], $schoolAttendee['ContactFirstName'], $schoolAttendee['ContactLastName']);
}
if (is_array($anonRespondee) && count($anonRespondee) > 0) {
$debugInfo[] = 'Quiz found for attendee';
$schoolAttendee['TestPassed'] = 0;
$schoolAttendee['TestCompleted'] = 1;
$scorePerc = $anonRespondee['Score'] / $anonRespondee['TotalScore'] * 100;
if ($scorePerc >= $anonRespondee['PassPerc']) {
$schoolAttendee['TestPassed'] = 1;
$debugInfo[] = 'Test PASSED - Score: ' . $scorePerc . '% (Required: ' . $anonRespondee['PassPerc'] . '%)';
} else {
$debugInfo[] = 'Test FAILED - Score: ' . $scorePerc . '% (Required: ' . $anonRespondee['PassPerc'] . '%)';
}
// $this->upsert($schoolAttendee);
} else {
$debugInfo[] = 'Quiz not found for attendee';
}
// var_dump($anonRespondee);
// echo '<br /><br />';
// var_dump($schoolAttendee['DateBooked']);
// echo '<br /><br />';
}
// exit;
if (
$mustSend > 0
&& $schoolEvent['TestRequired'] > 0
&& $schoolEvent['QuestionnaireID'] > 0
&& $schoolCourse['NonCPDCourse'] <= 0
&& $schoolEvent['CPD'] > 0
) {
// Only check for test passed if it's a CPD event
$mustSend = $schoolAttendee['TestPassed'];
$oneWeeksOn = clone $eventEndDate;
$oneWeeksOn->modify('+1 weeks');
// echo $oneWeeksOn->format('Y-m-d H:i:s') . ': One week on<br />';
if ($mustSend <= 0 && $oneWeeksOn->getTimestamp() <= time()) {
// Test not passed, but one week has passed
$mustSend = 1;
}
} elseif ($feedbackCompleted > 0 && $schoolEvent['TestRequired'] <= 0) {
$mustSend = 1;
}
if ($schoolAttendee['BlockReminderCertSend'] > 0) {
$debugInfo[] = $schoolEvent['EventName'] . ' - ' . $schoolAttendee['ContactFirstName'] . ' '
. $schoolAttendee['ContactLastName'] . ' - '
. 'Sending of Certificates BLOCKED';
// Email debug information and return
// self::emailDebugInfo($debugInfo);
return;
}
if (
$mustSend > 0 && ($schoolAttendee['CertificateSent'] == '' || $schoolAttendee['CertificateSent'] == '0000-00-00 00:00:00') &&
$schoolAttendee['Attended'] == 'y'
) {
$debugInfo[] = $schoolEvent['EventName'] . ' - ' . $schoolAttendee['ContactFirstName'] . ' ' . $schoolAttendee['ContactLastName'] . ' - '
. 'Checking for payment';
$schoolPayments = new SchoolPayments($sqlf);
if ($schoolPayments->isPaid($schoolAttendee['AttendeeID'])) {
$AttendeeID = $schoolAttendee["AttendeeID"];
$EmailAddress = $schoolAttendee["EmailAddress"];
$ContactFirstName = $schoolAttendee["ContactFirstName"];
$ContactLastName = $schoolAttendee["ContactLastName"];
$BookingEmail = $schoolAttendee["BookingEmail"];
include($_SERVER['DOCUMENT_ROOT'] . "/echasl23/inc_gencertificate.php");
$schoolEvent['AttendeeName'] = $schoolAttendee['ContactFirstName'];
$mailData = array(
'NumMessages' => 1,
'AttendeeID1' => $schoolAttendee['AttendeeID'],
'Email1' => $schoolAttendee['EmailAddress'],
'Name1' => $schoolAttendee['ContactFirstName'],
'EmailMessage' => SchoolAttendees::getSendCertificateBody($schoolAttendee['TestPassed'], $schoolEvent, $schoolCourse),
'EventName' => $schoolEvent['EventName'],
'File1' => $sFilename,
'EventDate1' => $eventEndDate->format('Y-m-d'),
);
$debugInfo[] = $eventEndDate->format('Y-m-d') . ',"' . $schoolEvent['EventName'] . '",' . $schoolAttendee["EmailAddress"] . ',Sending certificate';
$this->sendAttendeeCertificates($mailData);
$sendReminder = false;
} else {
$debugInfo[] = $schoolEvent['EventName'] . ' - ' . $schoolAttendee['ContactFirstName'] . ' ' . $schoolAttendee['ContactLastName'] . ' - '
. 'Not paid';
$debugInfo[] = $eventEndDate->format('Y-m-d') . ',"' . $schoolEvent['EventName'] . '",' . $schoolAttendee["EmailAddress"] . ',Not paid';
$sendReminder = true;
}
// exit;
} else {
$debugInfo[] = $eventEndDate->format('Y-m-d') . ' - ' . $schoolAttendee['ContactFirstName'] . ' ' . $schoolAttendee['ContactLastName']
. ',"' . $schoolEvent['EventName'] . '",' . $schoolAttendee["EmailAddress"]
. ',Event not attended, not test complete, not feedback completed, or certificate sent';
}
$threeDaysOn = clone $eventEndDate;
$threeDaysOn->modify('+2 days');
$debugInfo[] = 'Check send reminder: ' . $threeDaysOn->format('Y-m-d H:i:s');
if (
($schoolAttendee['QuizReminderSent'] == '' || $schoolAttendee['QuizReminderSent'] == '0000-00-00 00:00:00')
&& $sendReminder
&& $threeDaysOn->getTimestamp() < time()
&& $schoolAttendee['Attended'] == 'y'
) {
$hasCPD = false;
$schoolPayments = new SchoolPayments($sqlf);
$reminderBody = "Thank you for your attendance of " . $schoolEvent['EventName'] . " which took place on " . SchoolEvents::getEventDatesString($schoolEvent) . ".\r\n\r\n";
if ($schoolEvent['CPD'] > 0) {
$hasCPD = true;
// $reminderBody .= "This is a gentle reminder that the following is still outstanding. There is no time limit for completing the outstanding task(s); however, "
// . "we will be unable to provide you with a CPD certificate until these are completed.\r\n\r\n";
} else {
// $reminderBody .= "This is a gentle reminder that the following is still outstanding. There is no time limit for completing the outstanding task(s); however, "
// . "we will be unable to provide you with a certificate until these are completed.\r\n\r\n";
}
$hasOutstandingItems = false;
$feedbackLink = '';
$courseQuizRequired = false;
$paymentRequired = false;
if ($feedbackCompleted <= 0) {
// $reminderBody .= "- Feedback questionnaire: https://www.cesa.co.za/questionnaire.php?qid=225&attendeeId="
// . $schoolAttendee['AttendeeID'] . '&chk=' . md5($schoolAttendee['AttendeeID'])
// . '&id=' . $schoolEvent['EventID'] . "\r\n";
$feedbackLink = 'https://www.cesa.co.za/questionnaire.php?qid=225&attendeeId='
. $schoolAttendee['AttendeeID'] . '&chk=' . md5($schoolAttendee['AttendeeID'])
. '&id=' . $schoolEvent['EventID'];
$hasOutstandingItems = true;
}
if ($schoolEvent['TestRequired'] > 0 && $schoolEvent['QuestionnaireID'] > 0 && $schoolAttendee['TestPassed'] <= 0) {
// $reminderBody .= "- Course quiz\r\n";
$courseQuizRequired = true;
$hasOutstandingItems = true;
}
if (!$schoolPayments->isPaid($schoolAttendee['AttendeeID'])) {
// $reminderBody .= "- Payment\r\n";
$hasOutstandingItems = true;
$paymentRequired = true;
}
// Only send the reminder if there are actually outstanding items
if ($hasOutstandingItems) {
$hasFeedback = strlen($feedbackLink) > 0;
$tasks = [];
if ($courseQuizRequired) {
$tasks[] = 'complete the Course Quiz';
}
if ($paymentRequired) {
$tasks[] = 'make payment';
}
if ($hasFeedback) {
$tasks[] = 'complete the Feedback Questionnaire';
}
$taskList = count($tasks) === 1
? $tasks[0]
: (count($tasks) === 2
? $tasks[0] . ' and ' . $tasks[1]
: implode(', ', array_slice($tasks, 0, -1)) . ', and ' . $tasks[count($tasks) - 1]);
$certType = $hasCPD ? 'a CPD certificate' : 'a certificate';
$reminderBody .= "This is a gentle reminder that you need to {$taskList} for this course. "
. "There is no time limit for doing this, however, "
. "we will be unable to provide you with {$certType} until these are completed.\r\n\r\n";
$reminderBody .= "If the above information is incorrect or you require further information, please contact Blessings Banda on Blessings@cesa.co.za / "
. "+27 (0) 73 422 0680 or both on +27 (0)11 463-2022.";
$mailData = array(
'NumMessages' => 1,
'AttendeeID1' => $schoolAttendee['AttendeeID'],
'Email1' => $schoolAttendee['EmailAddress'],
'Name1' => $schoolAttendee['ContactFirstName'],
'EmailMessage' => $reminderBody,
'EventName' => $schoolEvent['EventName'],
'EventDate1' => $eventEndDate->format('Y-m-d'),
'subject' => 'SCE Event Reminder ',
);
$this->sendAttendeeCertificates($mailData);
$debugInfo[] = $eventEndDate->format('Y-m-d') . ',"' . $schoolEvent['EventName'] . '",' . $schoolAttendee["EmailAddress"] . ',reminder sent';
} else {
// Debug: Log when reminder is not sent due to no outstanding items
$debugInfo[] = $eventEndDate->format('Y-m-d') . ',"' . $schoolEvent['EventName'] . '",' . $schoolAttendee["EmailAddress"] . ',reminder NOT sent - no outstanding items';
// Email debug information
// self::emailDebugInfo($debugInfo);
}
}
$debugInfo[] = 'SchoolAttendeeUpsert processing completed';
// ErrorLog::logInfo('SchoolAttendeeUpsert processing completed: ' . print_r($debugInfo, true));
// echo 'save done<br />' . "\r\n"
// . '--------------------------------<br /><br />' . "\r\n\r\n";
flush();
// exit;
}
public static function getSendCertificateBody($testPassed = true, $event = array(), $schoolCourse = array())
{
$return = "Attached is your certificate for the course you attended through the School of Consulting Engineering.\r\n\r\n"
. "Regards,\r\n\r\n\r\n"
. "School of Consulting Engineering Consulting Engineers of South Africa\r\n"
. "011 463 2022\r\n"
. "cpdcertificates@cesa.co.za";
if (is_array($event) && count($event) > 0) {
if (!isset($event['AttendeeName'])) {
$event['AttendeeName'] = 'Student';
}
if (!$testPassed && $event['TestRequired'] > 0 && $event['CPD'] > 0 && $schoolCourse['NonCPDCourse'] <= 0) {
$return = "Attached please find your interim Attendance Certificate for the " . $event['EventName'] . " course you attended on " . SchoolEvents::getEventDatesString($event) . ".\r\n\r\n"
. "You have most likely not had time in your busy schedule to complete the outstanding tasks (Course Quiz / Feedback Questionnaire), and therefore we would like to emphasise that this is not a CPD certificate. There is no time limit for completing the outstanding tasks; however, we will be unable to provide you with a CPD certificate until these are completed.\r\n\r\n"
. "Should you require any further information, please don't hesitate to contact Blessings Banda on Blessings@cesa.co.za / +27 (0) 73 422 0680 or both on +27 (0)11 463-2022.";
} elseif (!$testPassed && $event['TestRequired'] <= 0 && $event['CPD'] <= 0 && $schoolCourse['NonCPDCourse'] <= 0) {
$return = "Attached please find your Attendance certificate for the " . $event['EventName'] . " course you attended on " . SchoolEvents::getEventDatesString($event) . ".\r\n\r\n"
. "Please note that this is not a CPD certificate.\r\n\r\n"
. "Should you require any further information, please don't hesitate to contact Blessings Banda on Blessings@cesa.co.za / +27 (0) 73 422 0680 or both on +27 (0)11 463-2022.";
} elseif (($testPassed && $event['CPD'] > 0 && $schoolCourse['NonCPDCourse'] <= 0) ||
($event['TestRequired'] <= 0 && $event['CPD'] > 0 && $schoolCourse['NonCPDCourse'] <= 0)
) {
$return = "Attached please find your CPD certificate for the " . $event['EventName'] . " course you attended on " . SchoolEvents::getEventDatesString($event) . ".\r\n\r\n"
. "Should you require any further information, please don't hesitate to contact Blessings Banda on Blessings@cesa.co.za / +27 (0) 73 422 0680 or both on +27 (0)11 463-2022.";
} elseif ($schoolCourse['NonCPDCourse'] > 0) {
$return = "Attached please find your Attendance certificate for the " . $event['EventName'] . " course you attended on " . SchoolEvents::getEventDatesString($event) . ".\r\n\r\n"
. "Should you require any further information, please don't hesitate to contact Blessings Banda on Blessings@cesa.co.za / +27 (0) 73 422 0680 or both on +27 (0)11 463-2022.";
}
}
return $return;
}
public static function sendAttendeeCertificates($formData)
{
global $conni, $env;
// Initialize debug array to collect all debug information
$debugInfo = [];
$debugInfo[] = "=== Certificate Sending Debug Log ===";
$debugInfo[] = "Timestamp: " . date('Y-m-d H:i:s');
$debugInfo[] = "Environment: " . $env;
$hasFailures = false;
$showDebug = false;
if ($showDebug) {
echo "<pre style='background:#111;color:#0f0;padding:10px;white-space:pre-wrap;'>";
echo "Certificate debug started at " . date('Y-m-d H:i:s') . "\n";
echo "Environment: " . $env . "\n";
flush();
}
$isNewSendRequest = !isset($formData['start']) && isset($formData['go']) && intval($formData['go']) === 1;
if ($isNewSendRequest || !isset($_SESSION['send_cert_data'])) {
// Always refresh payload on a new submit to avoid using stale attendees from a previous screen.
$_SESSION['send_cert_data'] = $formData;
$_SESSION['send_cert_data']['start'] = 1;
unset($_SESSION['sent']);
} elseif (isset($formData['start'])) {
$_SESSION['send_cert_data']['start'] = intval($formData['start']);
}
if (!isset($_SESSION['send_cert_data']['start']) || $_SESSION['send_cert_data']['start'] <= 0) {
$_SESSION['send_cert_data']['start'] = 1;
}
if ((!isset($_SESSION['send_cert_data']) || !isset($_SESSION['send_cert_data']['NumMessages'])) && isset($formData['NumMessages'])
&& $formData['NumMessages'] > 0
) {
$_SESSION['send_cert_data']['NumMessages'] = $formData['NumMessages'];
}
$numMessages = isset($_SESSION['send_cert_data']['NumMessages'])
? intval($_SESSION['send_cert_data']['NumMessages'])
: 0;
if ($numMessages <= 0) {
return 0;
}
$debugInfo[] = 'Session data: ' . print_r($_SESSION['send_cert_data'], true);
if (!isset($_SESSION['sent'])) {
$_SESSION['sent'] = 0;
}
$certificateBatchSize = 5;
if ($numMessages > $certificateBatchSize) {
@set_time_limit(max(300, $numMessages * 15));
}
$isTestOnly = isset($_SESSION['send_cert_data']["sendtestonly"]) && $_SESSION['send_cert_data']["sendtestonly"] === "yes";
$testEmailAddress = isset($_SESSION['send_cert_data']["TestEmailAddress"]) ? trim($_SESSION['send_cert_data']["TestEmailAddress"]) : '';
while ($_SESSION['send_cert_data']['start'] <= $numMessages) {
$batchStart = $_SESSION['send_cert_data']['start'];
$batchEnd = $batchStart + $certificateBatchSize;
if ($batchEnd > $numMessages + 1) {
$batchEnd = $numMessages + 1;
}
$_SESSION['send_cert_data']['end'] = $batchEnd;
$debugInfo[] = 'Batch start=' . $batchStart . ', end=' . $batchEnd;
$iEmailsSent = 0;
for ($i = $batchStart; $i < $batchEnd; $i++) {
if (!isset($_SESSION['send_cert_data']["Email" . $i])) {
ErrorLog::logInfo(
'Certificate send skipped: Missing Email field for index=' . $i
. ', EventID=' . (isset($_SESSION['send_cert_data']['EventID']) ? $_SESSION['send_cert_data']['EventID'] : '')
);
error_log(
'Certificate send skipped: Missing Email field for index=' . $i
. ', EventID=' . (isset($_SESSION['send_cert_data']['EventID']) ? $_SESSION['send_cert_data']['EventID'] : '')
);
if ($showDebug) {
echo "SKIP index {$i}: missing Email{$i}\n";
flush();
}
continue;
}
$SendTo = $_SESSION['send_cert_data']["Email" . $i];
$actualSendTo = $SendTo;
$attendeeId = isset($_SESSION['send_cert_data']["AttendeeID" . $i]) ? $_SESSION['send_cert_data']["AttendeeID" . $i] : '';
$attendeeName = isset($_SESSION['send_cert_data']["Name" . $i]) ? $_SESSION['send_cert_data']["Name" . $i] : '';
$CCTo = "";
if (isset($_SESSION['send_cert_data']["sendcopysce"]) && $_SESSION['send_cert_data']["sendcopysce"] == "yes")
$CCTo = "cpdcertificates@cesa.co.za";
if ((isset($_SESSION['send_cert_data']["sendcopybb"]) && $_SESSION['send_cert_data']["sendcopybb"] == "yes") && !empty($_SESSION['send_cert_data']["BookedBy" . $i]))
$CCTo .= "," . $_SESSION['send_cert_data']["BookedBy" . $i];
if (!empty($_SESSION['send_cert_data']["CopyExtra"]))
$CCTo .= "," . $_SESSION['send_cert_data']["CopyExtra"];
if (is_array($CCTo)) {
$CCTo = array_values(array_filter(array_map('trim', $CCTo), 'strlen'));
} else {
$CCTo = trim((string) $CCTo, ",");
$CCTo = ($CCTo === '') ? [] : array_values(array_filter(array_map('trim', explode(',', $CCTo)), 'strlen'));
}
$MessageBody = "";
$MessageBody .= "Dear " . $_SESSION['send_cert_data']["Name" . $i] . "," . "\r\n\r\n" . $_SESSION['send_cert_data']["EmailMessage"];
if ($isTestOnly) {
if ($testEmailAddress === '') {
ErrorLog::logError(
'Certificate send failed: test-only mode enabled but TestEmailAddress is empty. '
. 'AttendeeID=' . $attendeeId
);
$hasFailures = true;
continue;
}
$SendTo = $testEmailAddress;
$CCTo = [];
}
if (isset($_SESSION['send_cert_data']["File" . $i])) {
$sql = "UPDATE SchoolAttendees SET CertificateSent='" . date("Y-m-d H:i:s") . "' WHERE AttendeeID=" . $_SESSION['send_cert_data']["AttendeeID" . $i];
$debugInfo[] = 'Sent certificate ' . $SendTo . ': ' . $sql;
if (!$isTestOnly) {
mysqli_query($conni, $sql);
}
$Attachment = $_SERVER['DOCUMENT_ROOT'] . "/echasl23/certificates/files/" . $_SESSION['send_cert_data']["File" . $i];
} else {
$sql = "UPDATE SchoolAttendees
SET QuizReminderSent='" . date("Y-m-d H:i:s") . "'
WHERE AttendeeID=" . $_SESSION['send_cert_data']["AttendeeID" . $i];
$debugInfo[] = 'Sent reminder ' . $SendTo . ': ' . $sql;
if (!$isTestOnly) {
mysqli_query($conni, $sql);
}
$Attachment = null;
}
// exit;
if (!isset($_SESSION['send_cert_data']['subject'])) {
$_SESSION['send_cert_data']['subject'] = "CESA Certificate - ";
}
$emailSubject = $_SESSION['send_cert_data']['subject'] . $_SESSION['send_cert_data']["EventName"];
if (trim((string) $SendTo) === '' && count($CCTo) <= 0 && !$isTestOnly) {
ErrorLog::logError(
'Certificate send failed: no attendee email and no alternate recipients selected. '
. 'AttendeeID=' . $attendeeId
. ', Name=' . $attendeeName
. ', Subject=' . $emailSubject
);
$hasFailures = true;
continue;
}
ErrorLog::logInfo(
'Certificate send attempt: Index=' . $i
. ', AttendeeID=' . $attendeeId
. ', Name=' . $attendeeName
. ', ActualRecipient=' . $actualSendTo
. ', SentTo=' . $SendTo
. ', Subject=' . $emailSubject
. ', TestOnly=' . ($isTestOnly ? 'Y' : 'N')
);
if ($showDebug) {
echo "ATTEMPT index {$i}: attendee={$attendeeId}, to={$SendTo}, subject={$emailSubject}\n";
flush();
}
$bcc = ['cpdcertificates@cesa.co.za', 'cesasce-reminders@igotafrica.com'];
if ($env == 'dev') {
$CCTo = [];
$bcc = [];
$SendTo = 'cesa-sce@igotafrica.com';
}
if (!is_array($CCTo)) {
$CCTo = trim((string) $CCTo, ",");
$CCTo = ($CCTo === '') ? [] : array_values(array_filter(array_map('trim', explode(',', $CCTo)), 'strlen'));
}
if (in_array('otto@igotafrica.com', $CCTo, true)) {
$CCTo = [];
$bcc = [];
$SendTo = 'otto@igotafrica.com';
}
$debugInfo[] = 'Sending cert to ' . $_SESSION['send_cert_data']["Name" . $i] . ' on ' . $SendTo . ' and CC ' . print_r($CCTo, true) . ' and BCC ' . print_r($bcc, true);
// Try to send the email and track failures
try {
// var_dump($SendTo);
// var_dump($emailSubject);
// var_dump($MessageBody);
// var_dump($Attachment);
// var_dump($CCTo);
// var_dump($bcc);
// exit;
maill(
$SendTo,
$emailSubject,
$MessageBody,
$Attachment,
array(
'from-address' => 'cpdcertificates@cesa.co.za',
'from-name' => 'CESA CPD Certificates',
'cc' => $CCTo,
'bcc' => $bcc
)
);
$debugInfo[] = 'SUCCESS: Certificate sent to ' . $_SESSION['send_cert_data']["Name" . $i] . ' (' . $SendTo . ')';
ErrorLog::logInfo(
'Certificate send success: AttendeeID=' . $attendeeId
. ', Name=' . $attendeeName
. ', ActualRecipient=' . $actualSendTo
. ', SentTo=' . $SendTo
. ', Subject=' . $emailSubject
. ', TestOnly=' . ($isTestOnly ? 'Y' : 'N')
);
error_log(
'Certificate send success: AttendeeID=' . $attendeeId
. ', Name=' . $attendeeName
. ', ActualRecipient=' . $actualSendTo
. ', SentTo=' . $SendTo
. ', Subject=' . $emailSubject
. ', TestOnly=' . ($isTestOnly ? 'Y' : 'N')
);
if ($showDebug) {
echo "SUCCESS index {$i}: attendee={$attendeeId}, sentTo={$SendTo}\n";
flush();
}
$iEmailsSent++;
} catch (Exception $e) {
// Email failed - add to debug info
$hasFailures = true;
$debugInfo[] = "FAILED to send certificate to: " . $_SESSION['send_cert_data']["Name" . $i] . " (" . $SendTo . ")";
$debugInfo[] = "Error: " . $e->getMessage();
$debugInfo[] = "AttendeeID: " . $_SESSION['send_cert_data']["AttendeeID" . $i];
$debugInfo[] = "---";
ErrorLog::logError(
'Certificate send failed: AttendeeID=' . $attendeeId
. ', Name=' . $attendeeName
. ', ActualRecipient=' . $actualSendTo
. ', SentTo=' . $SendTo
. ', Subject=' . $emailSubject
. ', TestOnly=' . ($isTestOnly ? 'Y' : 'N')
. ', Error=' . $e->getMessage()
);
error_log(
'Certificate send failed: AttendeeID=' . $attendeeId
. ', Name=' . $attendeeName
. ', ActualRecipient=' . $actualSendTo
. ', SentTo=' . $SendTo
. ', Subject=' . $emailSubject
. ', TestOnly=' . ($isTestOnly ? 'Y' : 'N')
. ', Error=' . $e->getMessage()
);
if ($showDebug) {
echo "FAILED index {$i}: attendee={$attendeeId}, error={$e->getMessage()}\n";
flush();
}
}
} // endfor batch loop
$_SESSION['sent'] += $iEmailsSent;
$debugInfo[] = $iEmailsSent . ' mails sent in this batch';
$debugInfo[] = 'Total sent so far: ' . $_SESSION['sent'];
$_SESSION['send_cert_data']['start'] = $batchEnd;
if ($showDebug) {
echo "Batch complete: next start=" . $_SESSION['send_cert_data']['start'] . ", totalSent=" . $_SESSION['sent'] . "\n";
flush();
}
} // endwhile all batches
$totalSent = $_SESSION['sent'];
unset($_SESSION['send_cert_data']);
unset($_SESSION['sent']);
if ($hasFailures) {
$debugInfo[] = 'Certificate sending completed with failures. Total sent: ' . $totalSent;
}
$debugInfo[] = 'Certificate sending finished. Total sent: ' . $totalSent;
if ($showDebug) {
echo "All batches complete. totalSent={$totalSent}\n";
echo "</pre>";
flush();
}
return $totalSent;
}
/**
* Email debug information to cesa@igotafrica.com
* @param array $debugInfo Array of debug messages
*/
private static function emailDebugInfo($debugInfo)
{
if (empty($debugInfo)) {
return;
}
$subject = 'Certificate Sending Debug Log - ' . date('Y-m-d H:i:s');
$messageBody = implode("\n", $debugInfo);
// Add some formatting for better readability
$formattedMessage = "Certificate Sending Debug Information\n";
$formattedMessage .= "=====================================\n\n";
$formattedMessage .= $messageBody;
$formattedMessage .= "\n\n";
$formattedMessage .= "--- End of Debug Log ---\n";
$formattedMessage .= "Generated at: " . date('Y-m-d H:i:s');
try {
maill(
'cesa@igotafrica.com',
$subject,
$formattedMessage,
null,
array(
'from-address' => 'cpdcertificates@cesa.co.za',
'from-name' => 'CESA Certificate System',
'isHTML' => false
)
);
} catch (Exception $e) {
// If email fails, we can't do much about it, but we could log it
error_log('Failed to send debug email: ' . $e->getMessage());
}
}
public static function sendAttendeeRegistrationForm($attendee)
{
global $conni, $env;
$SendTo = $attendee['EmailAddress'];
$MessageBody = "Dear " . $attendee['ContactFirstName'] . "," . "\r\n\r\n" . 'Please find your registration form attached for ' . $attendee['EventName'] . ' on ' . $attendee['StartDate'];
$filePath = $attendee['AttendeeID'] . '-registration-form.html';
GeneratePDF($filePath, $attendee['BookingForm']);
// echo 'Sending to ' . $SendTo . '<br />';
// echo $_SERVER['DOCUMENT_ROOT'] . "/echasl23/downloads/" . $attendee['AttendeeID'] . '-registration-form_html.pdf';
// exit;
maill(
$SendTo,
'Event Registration form for ' . $attendee['EventName'],
$MessageBody,
$_SERVER['DOCUMENT_ROOT'] . "/echasl23/downloads/" . $attendee['AttendeeID'] . '-registration-form_html.pdf',
array('from-address' => 'sce.co.za', 'from-name' => 'CESA SCE', 'bcc' => array('sce@cesa.co.za'))
);
}
/**
* Parse comma-, semicolon-, or whitespace-separated email addresses.
*
* @param string $input
* @return array
*/
public static function parseEmailAddressList($input)
{
if (!is_string($input) || trim($input) === '') {
return array();
}
$parts = preg_split('/[\s,;]+/', trim($input), -1, PREG_SPLIT_NO_EMPTY);
$valid = array();
foreach ($parts as $email) {
$email = trim($email);
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
$valid[] = $email;
}
}
return array_values(array_unique($valid));
}
/**
* Attendees eligible for certificate email on the certificates list (attended + paid).
*
* @param int $eventId
* @param array $attendeeIds Optional filter
* @return array
*/
public function getCertificateEmailAttendees($eventId, array $attendeeIds = array())
{
$eventId = intval($eventId);
if ($eventId <= 0) {
return array();
}
$sql = "SELECT AttendeeID, ContactFirstName, ContactLastName, EmailAddress, BookingEmail
FROM SchoolAttendees
WHERE SchoolAttendees.EventID = " . $eventId . "
AND Attended = 'y'
AND AttendeeID IN (SELECT AttendeeID FROM SchoolPayments WHERE EventID = " . $eventId . ")";
if (count($attendeeIds) > 0) {
$ids = array();
foreach ($attendeeIds as $id) {
$id = intval($id);
if ($id > 0) {
$ids[] = $id;
}
}
if (count($ids) > 0) {
$sql .= " AND AttendeeID IN (" . implode(', ', $ids) . ")";
}
}
$sql .= " ORDER BY ContactLastName, ContactFirstName, AttendeeID";
$rows = $this->sqlf->getAll($sql);
return is_array($rows) ? $rows : array();
}
/**
* Generate certificate PDF for an attendee; returns absolute file path or null.
*
* @param int $attendeeId
* @return string|null
*/
public function generateCertificateFilePath($attendeeId)
{
global $sqlf;
$AttendeeID = intval($attendeeId);
if ($AttendeeID <= 0) {
return null;
}
if (!is_object($sqlf)) {
throw new Exception('Database connection is not available for certificate generation.');
}
$sFilename = '';
include $_SERVER['DOCUMENT_ROOT'] . '/echasl23/inc_gencertificate.php';
if ($sFilename === '') {
return null;
}
$path = rtrim($_SERVER['DOCUMENT_ROOT'], '/') . '/echasl23/certificates/files/' . $sFilename;
return is_file($path) ? $path : null;
}
/**
* Send all eligible event certificates in one email to a single address.
*
* @param array $params event_id, to_address, bcc_addresses, email_message, send_copy_sce, attendee_ids
* @return array sent_count, attachment_count, event_name
* @throws Exception
*/
public function sendAllCertificatesToOneAddress(array $params)
{
global $conni, $env;
$eventId = isset($params['event_id']) ? intval($params['event_id']) : 0;
if ($eventId <= 0) {
throw new Exception('No event specified.');
}
$toAddress = isset($params['to_address']) ? trim((string) $params['to_address']) : '';
if ($toAddress === '' || !filter_var($toAddress, FILTER_VALIDATE_EMAIL)) {
throw new Exception('A valid To e-mail address is required.');
}
$attendeeIds = isset($params['attendee_ids']) && is_array($params['attendee_ids'])
? $params['attendee_ids']
: array();
$attendees = $this->getCertificateEmailAttendees($eventId, $attendeeIds);
if (count($attendees) <= 0) {
throw new Exception('No eligible attendees found for this event.');
}
$event = $this->sqlf->getRow("SELECT EventName FROM SchoolEvents WHERE EventID = " . $eventId . " LIMIT 1");
$eventName = (is_array($event) && isset($event['EventName'])) ? $event['EventName'] : 'School event';
$attachments = array();
$attendeeIdsSent = array();
foreach ($attendees as $attendee) {
$filePath = $this->generateCertificateFilePath($attendee['AttendeeID']);
if ($filePath === null) {
throw new Exception(
'Could not generate certificate for '
. $attendee['ContactFirstName'] . ' ' . $attendee['ContactLastName'] . '.'
);
}
$attachments[] = array(
'path' => $filePath,
'name' => basename($filePath),
);
$attendeeIdsSent[] = intval($attendee['AttendeeID']);
}
$messageBody = isset($params['email_message']) ? trim((string) $params['email_message']) : '';
if ($messageBody === '') {
$messageBody = "Attached are the certificates for attendees of " . $eventName . ".\r\n\r\n"
. SchoolAttendees::getSendCertificateBody();
}
$bcc = self::parseEmailAddressList(isset($params['bcc_addresses']) ? $params['bcc_addresses'] : '');
$sendCopySce = !empty($params['send_copy_sce']) || !empty($params['send_copy_cpdcertificates']);
if ($sendCopySce) {
$bcc[] = self::SCHOOL_CERTIFICATE_DEFAULT_EMAIL;
}
$bcc[] = 'cesasce-reminders@igotafrica.com';
$bcc = array_values(array_unique($bcc));
$sendTo = $toAddress;
if ($env == 'dev') {
$bcc = array();
$sendTo = self::SCHOOL_CERTIFICATE_DEFAULT_EMAIL;
}
if (in_array('otto@igotafrica.com', $bcc, true) || $sendTo === 'otto@igotafrica.com') {
$bcc = array();
$sendTo = 'otto@igotafrica.com';
}
$subject = 'CESA Certificate - ' . $eventName;
maill(
$sendTo,
$subject,
$messageBody,
null,
array(
'from-address' => 'website@cesa.co.za',
'from-name' => 'School of Consulting Engineering',
'bcc' => $bcc,
'attachments' => $attachments,
)
);
$now = date('Y-m-d H:i:s');
if ($env != 'dev' && is_object($conni)) {
foreach ($attendeeIdsSent as $attendeeId) {
mysqli_query(
$conni,
"UPDATE SchoolAttendees SET CertificateSent='" . mysqli_real_escape_string($conni, $now)
. "' WHERE AttendeeID=" . intval($attendeeId)
);
}
}
return array(
'sent_count' => count($attendeeIdsSent),
'attachment_count' => count($attachments),
'event_name' => $eventName,
'sent_to' => $sendTo,
);
}
public function sendAllAttendeeCertificates()
{
// Initialize debug array for bulk certificate sending
$debugInfo = [];
$debugInfo[] = "=== Bulk Certificate Sending Debug Log ===";
$debugInfo[] = "Timestamp: " . date('Y-m-d H:i:s');
$attendees = $this->findToSendCertificates();
$debugInfo[] = 'Found ' . count($attendees) . ' attendees to send certificates';
// exit;
$alreadySent = [];
foreach ($attendees as $attendee) {
unset($_SESSION['send_cert_data']);
if (in_array($attendee['AttendeeID'], $alreadySent)) {
$debugInfo[] = 'Already sent certificate for ' . $attendee['ContactFirstName'] . ' ' . $attendee['ContactLastName'] . ' '
. $attendee['EmailAddress'];
continue;
}
$alreadySent[] = $attendee['AttendeeID'];
// if (count($alreadySent) > 160) {
// $debugInfo[] = 'Already sent certificates for ' . count($alreadySent) . ' attendees';
// continue;
// }
$this->SchoolAttendeeUpsert($attendee['AttendeeID']);
}
$debugInfo[] = 'Bulk certificate sending completed. Total processed: ' . count($alreadySent);
// Email debug information
// self::emailDebugInfo($debugInfo);
}
public function fixCase($attendee)
{
$SchoolAttendee['AttendeeID'] = $attendee['AttendeeID'];
$SchoolAttendee['ContactFirstName'] = ucwords(strtolower($attendee['ContactFirstName']));
$SchoolAttendee['KnownAs'] = ucwords(strtolower($attendee['KnownAs']));
$SchoolAttendee['ContactLastName'] = ucwords(strtolower($attendee['ContactLastName']));
$SchoolAttendee['Organisation'] = str_replace('(pty)', '(Pty)', ucwords(strtolower($attendee['Organisation'])));
$SchoolAttendee['CompanyName'] = str_replace('(pty)', '(Pty)', ucwords(strtolower($attendee['CompanyName'])));
$SchoolAttendee['EmailAddress'] = strtolower($attendee['EmailAddress']);
$this->upsert($SchoolAttendee);
}
}
function SchoolAttendeeUpsert($rsOld, $rsNew = array())
{
global $sqlf;
$schoolAttendees = new SchoolAttendees($sqlf);
$rsUpdate = $rsOld;
if (count($rsNew) > 0) {
$rsUpdate = $rsNew;
}
$schoolAttendees->SchoolAttendeeUpsert($rsOld['AttendeeID'], $rsUpdate);
}
function getSchoolAttendeeRegistrationFormLink($attendeeID)
{
return '<p><a href="/php/templates/school/SchoolAttendeeBookingForm.php?SchoolAttendeeID=' . $attendeeID . '" target="_blank">Registration Form</a></p>'
. '<p><a href="/php/templates/school/SchoolAttendeeBookingFormSend.php?SchoolAttendeeID=' . $attendeeID . '">Resend Registration Form</a></p>'
. '<p><a href="/php/templates/school/SchoolAttendeeFixCase.php?SchoolAttendeeID=' . $attendeeID . '">Fix Case</a></p>';
}
function schoolAttendeeRowRender(&$objThis)
{
if ($objThis->Cancelled->CurrentValue == 0) {
$objThis->Cancelled->CellAttrs["style"] = "background-color: #ccff66";
} elseif ($objThis->Cancelled->CurrentValue == 1) {
$objThis->Cancelled->CellAttrs["style"] = "background-color: #ff9999";
}
$sChangeAtt = "<select name='Attended" . $objThis->AttendeeID->CurrentValue . "' onChange='javascript:if (confirm(\"Save Changes?\")) UpdateAttended(" . $objThis->AttendeeID->CurrentValue . ",this.options[this.selectedIndex].value)'>";
$sChangeAtt .= "<option value='y'";
if ($objThis->Attended->CurrentValue == 'y')
$sChangeAtt .= " selected";
$sChangeAtt .= ">Yes</option>";
$sChangeAtt .= "<option value='n'";
if ($objThis->Attended->CurrentValue == 'n')
$sChangeAtt .= " selected";
$sChangeAtt .= ">No</option>";
$sChangeAtt .= "<option value='u'";
if ($objThis->Attended->CurrentValue == 'u')
$sChangeAtt .= " selected";
$sChangeAtt .= ">Unknown</option></select>";
$objThis->Attended->ViewValue = $sChangeAtt;
}
function schoolAttendeeListOptionsLoad(&$objThis) {
$objThis->ListOptions->Add("paid");
$objThis->ListOptions->Items["paid"]->CssStyle = "white-space: nowrap;";
$objThis->ListOptions->Items["paid"]->OnLeft = FALSE;
$objThis->ListOptions->Items["paid"]->Header="Paid";
$objThis->ListOptions->MoveItem("paid",count($objThis->ListOptions->Items)-1);
$objThis->ListOptions->Add("registration");
$objThis->ListOptions->Items["registration"]->CssStyle = "white-space: nowrap;";
$objThis->ListOptions->Items["registration"]->OnLeft = FALSE;
$objThis->ListOptions->Items["registration"]->Header="Registration Form";
$objThis->ListOptions->MoveItem("registration",count($objThis->ListOptions->Items)-1);
}
function schoolAttendeeListOptionsRendered(&$objThis, &$schoolAttendees) {
global $conn;
$sql = "SELECT AmountPaid, AmountDue FROM SchoolPayments WHERE AttendeeID='".$schoolAttendees->AttendeeID->CurrentValue."'";
$rs = $conn->Execute($sql);
if ($rs && !$rs->EOF) {
$rs->MoveFirst();
if ($rs->fields('AmountPaid') >= $rs->fields('AmountDue')) {
$objThis->ListOptions->Items["paid"]->Body = '<SPAN class=phpmaker>Paid</SPAN>';
} else {
$objThis->ListOptions->Items["paid"]->Body = '<SPAN class=phpmaker>Not Paid</SPAN>';
}
} else {
$objThis->ListOptions->Items["paid"]->Body = '<SPAN class=phpmaker>Not Paid</SPAN>';
}
$rs->Close();
$objThis->ListOptions->Items["registration"]->Body = getSchoolAttendeeRegistrationFormLink($schoolAttendees->AttendeeID->CurrentValue);
}
function schoolAttendeeListPageLoad() {
if (isset($_REQUEST['EventID']) && strlen($_REQUEST['EventID']) > 0) {
if (!isset($_SESSION[EW_SESSION_MESSAGE])) {
$_SESSION[EW_SESSION_MESSAGE] = '';
}
$_SESSION[EW_SESSION_MESSAGE] .= '<span class="phpmaker" style="margin-bottom: 10px;">'
. '<a href="SchoolAttendeesimport.php?EventID=' . $_REQUEST['EventID'] . '">'
. '<img src="images/expand.gif" alt="Import Attendees" title="Import Attendees" width="16" height="16" border="0">'
. ' Import Attendees</a>'
. '</span>';
$_SESSION[EW_SESSION_MESSAGE] .= ' <span class="phpmaker" style="margin-bottom: 10px;">'
. '<a href="/echasl23/SchoolAttendeeBulkEmail.php?EventID=' . $_REQUEST['EventID'] . '">'
. '<img src="images/expand.gif" alt="Email Attendees" title="Email Attendees" width="16" height="16" border="0">'
. ' Email Attendees</a>'
. '</span>';
$_SESSION[EW_SESSION_MESSAGE] .= ' <span class="phpmaker" style="margin-bottom: 10px;">'
. '<a href="/echasl23/SchoolEventInsufficientDelegatesEmail.php?EventID=' . $_REQUEST['EventID'] . '">'
. '<img src="images/expand.gif" alt="Insufficient Delegates Email" title="Insufficient Delegates Email" width="16" height="16" border="0">'
. ' Insufficient Delegates Email</a>'
. '</span>';
$eventId = intval($_REQUEST['EventID']);
$eventCancelled = false;
if (isset($GLOBALS['sqlf']) && is_object($GLOBALS['sqlf'])) {
$eventRow = $GLOBALS['sqlf']->getRow('SELECT Cancelled FROM SchoolEvents WHERE EventID = ' . $eventId . ' LIMIT 1');
if (is_array($eventRow)) {
$eventCancelled = intval(isset($eventRow['Cancelled']) ? $eventRow['Cancelled'] : 0) > 0;
}
} elseif (isset($GLOBALS['conni']) && $GLOBALS['conni']) {
$cancelRec = mysqli_query($GLOBALS['conni'], 'SELECT Cancelled FROM SchoolEvents WHERE EventID=' . $eventId . ' LIMIT 1');
if ($cancelRec && ($cancelRow = mysqli_fetch_assoc($cancelRec))) {
$eventCancelled = intval($cancelRow['Cancelled']) > 0;
}
if ($cancelRec) {
mysqli_free_result($cancelRec);
}
}
if (!$eventCancelled) {
$_SESSION[EW_SESSION_MESSAGE] .= ' <span class="phpmaker" style="margin-bottom: 10px;">'
. '<a href="/echasl23/SchoolEventCoursePostponedEmail.php?EventID=' . $eventId . '">'
. '<img src="images/expand.gif" alt="Postpone" title="Postpone" width="16" height="16" border="0">'
. ' Postpone</a>'
. '</span>';
$_SESSION[EW_SESSION_MESSAGE] .= ' <span class="phpmaker" style="margin-bottom: 10px;">'
. '<a href="/echasl23/SchoolEventCoursePostponedNewDatesEmail.php?EventID=' . $eventId . '">'
. '<img src="images/expand.gif" alt="New Dates - Postpone" title="New Dates - Postpone" width="16" height="16" border="0">'
. ' New Dates – Postpone</a>'
. '</span>';
}
if ($eventCancelled) {
$_SESSION[EW_SESSION_MESSAGE] .= ' <span class="phpmaker" style="margin-bottom: 10px;">'
. '<a href="/echasl23/SchoolEventCourseCancelledEmail.php?EventID=' . $eventId . '">'
. '<img src="images/expand.gif" alt="Course Cancelled Email" title="Course Cancelled Email" width="16" height="16" border="0">'
. ' Course Cancelled Email</a>'
. '</span>';
}
}
}
// Custom code to handle sorting for custom view
function SchoolAttendees_Recordset_Selecting(&$objThis, &$filter) {
// Get the current order by from session
$sOrderBy = $objThis->getSessionOrderBy();
if ($sOrderBy <> "") {
// Replace table references with view column names
$sOrderBy = str_replace("SchoolAttendees.DateBooked", "DateBooked", $sOrderBy);
$sOrderBy = str_replace("SchoolAttendees.AttendeeID", "AttendeeID", $sOrderBy);
$sOrderBy = str_replace("SchoolEvents.EventID", "EventID", $sOrderBy);
$sOrderBy = str_replace("SchoolEvents.StartDate", "StartDate", $sOrderBy);
$sOrderBy = str_replace("SchoolEvents.EndDate", "EndDate", $sOrderBy);
$sOrderBy = str_replace("SchoolCourses.CourseName", "EventName", $sOrderBy);
$sOrderBy = str_replace("SchoolAttendees.CompanyName", "Organisation", $sOrderBy);
$sOrderBy = str_replace("Concat_Ws(' ', SchoolAttendees.ContactFirstName, SchoolAttendees.ContactLastName)", "Delegate", $sOrderBy);
} else {
$sOrderBy = "DateBooked DESC";
}
// Set the corrected order by
$objThis->setSessionOrderBy($sOrderBy);
}