prepare($sql); $stmt->execute(['teller_number' => $tellerNumber]); $bankStatement = $stmt->fetch(); if (!$bankStatement) { throw new Exception('Bank statement not found for teller number: ' . $tellerNumber); } // Verify unreconciled amount if ($amountToUse > $bankStatement['unreconciled_amount']) { throw new Exception('Amount exceeds unreconciled amount on teller'); } // Extract teller name and number from description $descParts = explode(' ', $bankStatement['description']); $tellerNo = array_pop($descParts); $tellerName = implode(' ', $descParts); // Use the oldest fee's session/term for transaction_id $dominantSession = $selectedFees[0]['academic_session']; $dominantTerm = $selectedFees[0]['term_of_session']; // Generate transaction_id $transactionId = $studentId . $dominantSession . $paymentDate; // STEP 1: Guard check - prevent duplicate payments on same date $sql = "SELECT COUNT(*) AS cnt FROM tb_account_school_fee_sum_payments WHERE student_id = :student_id AND payment_date = :payment_date"; $stmt = $pdo->prepare($sql); $stmt->execute([ 'student_id' => $studentId, 'payment_date' => $paymentDate ]); $duplicateCheck = $stmt->fetch(); if ($duplicateCheck['cnt'] > 0) { throw new Exception('A payment for this student has already been registered on this date (' . $paymentDate . ')'); } // STEP 2: Allocate payment across fees (oldest to newest) $feeAllocations = []; $remainingAmount = $amountToUse; foreach ($selectedFees as $fee) { if ($remainingAmount <= 0) { break; } $outstandingAmount = floatval($fee['outstanding_amount']); if ($remainingAmount >= $outstandingAmount) { // Fully settle this fee $amountForThisFee = $outstandingAmount; $remainingAmount -= $outstandingAmount; } else { // Partially settle this fee $amountForThisFee = $remainingAmount; $remainingAmount = 0; } $feeAllocations[] = [ 'fee_id' => $fee['fee_id'], 'academic_session' => $fee['academic_session'], 'term_of_session' => $fee['term_of_session'], 'amount' => $amountForThisFee ]; } if (count($feeAllocations) === 0) { throw new Exception('No fees could be allocated'); } // Calculate total paid $totalPaid = array_sum(array_column($feeAllocations, 'amount')); // STEP 3: Begin database transaction $pdo->beginTransaction(); try { // Constants $creditBankId = '000001373634585148'; $debitBankId = '514297805530965017'; $paymodeId = '000001373901891416'; $recipientId = 'SS0011441283890434'; $paymentBy = 'SS0011441283890434'; $createdBy = 'SS0011441283890434'; $createdAs = 'school'; $paymentStatus = 'Approved'; $paymodeCategory = 'BANK'; // Generate receipt_no (used across all fee records) $receiptNo = $studentCode . $paymentDate; // 3a) INSERT into tb_account_school_fee_payments (per fee) foreach ($feeAllocations as $allocation) { $schoolFeePaymentId = $studentCode . $allocation['fee_id'] . $paymentDate; //original code //$schoolFeePaymentId = $allocation['fee_id'] . $paymentDate; //Is used to reduce length of id to solve duplicate entry error. $sql = "INSERT INTO tb_account_school_fee_payments ( id, fee_id, student_id, transaction_id, amount_paid, teller_no, teller_name, credit_bank_id, debit_bank_id, paymode_id, payment_status, payment_date, recipient_id, academic_session, term_of_session, payment_by, payment_on ) VALUES ( :id, :fee_id, :student_id, :transaction_id, :amount_paid, :teller_no, :teller_name, :credit_bank_id, :debit_bank_id, :paymode_id, :payment_status, :payment_date, :recipient_id, :academic_session, :term_of_session, :payment_by, NOW() )"; $stmt = $pdo->prepare($sql); $stmt->execute([ 'id' => $schoolFeePaymentId, 'fee_id' => $allocation['fee_id'], 'student_id' => $studentId, 'transaction_id' => $transactionId, 'amount_paid' => $allocation['amount'], 'teller_no' => $tellerNo, 'teller_name' => $tellerName, 'credit_bank_id' => $creditBankId, 'debit_bank_id' => $debitBankId, 'paymode_id' => $paymodeId, 'payment_status' => $paymentStatus, 'payment_date' => $paymentDate, 'recipient_id' => $recipientId, 'academic_session' => $allocation['academic_session'], 'term_of_session' => $allocation['term_of_session'], 'payment_by' => $paymentBy ]); } // 3b) INSERT into tb_account_school_fee_sum_payments (single record) $sumPaymentsId = $studentId . $dominantSession . $paymentDate; $sql = "INSERT INTO tb_account_school_fee_sum_payments ( id, student_id, total_paid, paymode_id, payment_date, credit_bank_id, debit_bank_id, transaction_id, status, academic_session, term_of_session, registered_by, registered_on ) VALUES ( :id, :student_id, :total_paid, :paymode_id, :payment_date, :credit_bank_id, :debit_bank_id, :transaction_id, :status, :academic_session, :term_of_session, :registered_by, NOW() )"; $stmt = $pdo->prepare($sql); $stmt->execute([ 'id' => $sumPaymentsId, 'student_id' => $studentId, 'total_paid' => $totalPaid, 'paymode_id' => $paymodeId, 'payment_date' => $paymentDate, 'credit_bank_id' => $creditBankId, 'debit_bank_id' => $debitBankId, 'transaction_id' => $transactionId, 'status' => $paymentStatus, 'academic_session' => $dominantSession, 'term_of_session' => $dominantTerm, 'registered_by' => $createdBy ]); // 3c) INSERT into tb_account_student_payments (per fee) foreach ($feeAllocations as $allocation) { // Get current payment_to_date (sum of all previous payments for this fee/session/term) $sql = "SELECT SUM(payment_to_date) AS current_total FROM tb_account_student_payments WHERE student_id = :student_id AND fee_id = :fee_id AND academic_session = :academic_session AND term_of_session = :term_of_session"; $stmt = $pdo->prepare($sql); $stmt->execute([ 'student_id' => $studentId, 'fee_id' => $allocation['fee_id'], 'academic_session' => $allocation['academic_session'], 'term_of_session' => $allocation['term_of_session'] ]); $currentPayment = $stmt->fetch(); $currentTotal = floatval($currentPayment['current_total'] ?? 0); $newPaymentToDate = $allocation['amount']; //$newPaymentToDate = $currentTotal + $allocation['amount']; --Old code that added new payment amount to current total (total before payment) $studentPaymentId = $studentCode . $allocation['fee_id'] . $paymentDate; $sql = "INSERT INTO tb_account_student_payments ( id, fee_id, student_id, payment_to_date, transaction_id, academic_session, term_of_session, created_by, created_as, created_on ) VALUES ( :id, :fee_id, :student_id, :payment_to_date, :transaction_id, :academic_session, :term_of_session, :created_by, :created_as, NOW() )"; $stmt = $pdo->prepare($sql); $stmt->execute([ 'id' => $studentPaymentId, 'fee_id' => $allocation['fee_id'], 'student_id' => $studentId, 'payment_to_date' => $newPaymentToDate, 'transaction_id' => $transactionId, 'academic_session' => $allocation['academic_session'], 'term_of_session' => $allocation['term_of_session'], 'created_by' => $createdBy, 'created_as' => $createdAs ]); } // 3d) INSERT into tb_account_payment_registers (per fee) foreach ($feeAllocations as $allocation) { $paymentRegisterId = $studentCode . $allocation['fee_id'] . $paymentDate; $sql = "INSERT INTO tb_account_payment_registers ( id, fee_id, student_id, amount_paid, amount_due, receipt_no, recipient_id, payment_date, paymode_category, transaction_id, academic_session, term_of_session, created_by, created_as, created_on ) VALUES ( :id, :fee_id, :student_id, :amount_paid, :amount_due, :receipt_no, :recipient_id, :payment_date, :paymode_category, :transaction_id, :academic_session, :term_of_session, :created_by, :created_as, NOW() )"; $stmt = $pdo->prepare($sql); $stmt->execute([ 'id' => $paymentRegisterId, 'fee_id' => $allocation['fee_id'], 'student_id' => $studentId, 'amount_paid' => $allocation['amount'], 'amount_due' => $allocation['amount'], 'receipt_no' => $receiptNo, 'recipient_id' => $recipientId, 'payment_date' => $paymentDate, 'paymode_category' => $paymodeCategory, 'transaction_id' => $transactionId, 'academic_session' => $allocation['academic_session'], 'term_of_session' => $allocation['term_of_session'], 'created_by' => $createdBy, 'created_as' => $createdAs ]); } // 3e) UPDATE tb_student_logistics // Group allocations by session/term to update specific records $sessionTermTotals = []; foreach ($feeAllocations as $allocation) { $key = $allocation['academic_session'] . '-' . $allocation['term_of_session']; if (!isset($sessionTermTotals[$key])) { $sessionTermTotals[$key] = [ 'academic_session' => $allocation['academic_session'], 'term_of_session' => $allocation['term_of_session'], 'total' => 0 ]; } $sessionTermTotals[$key]['total'] += $allocation['amount']; } // Update each session/term record foreach ($sessionTermTotals as $st) { $sql = "UPDATE tb_student_logistics SET fees_outstanding = GREATEST(0, fees_outstanding - :total_paid) WHERE student_id = :student_id AND academic_session = :academic_session AND term_of_session = :term_of_session"; $stmt = $pdo->prepare($sql); $stmt->execute([ 'total_paid' => $st['total'], 'student_id' => $studentId, 'academic_session' => $st['academic_session'], 'term_of_session' => $st['term_of_session'] ]); } // Commit transaction $pdo->commit(); $success = true; $message = 'Payment processed successfully!'; // Fetch fee descriptions for display $feeIds = array_column($feeAllocations, 'fee_id'); $placeholders = implode(',', array_fill(0, count($feeIds), '?')); $sql = "SELECT id, description FROM tb_account_school_fees WHERE id IN ($placeholders)"; $stmt = $pdo->prepare($sql); $stmt->execute($feeIds); $feeDescriptions = $stmt->fetchAll(PDO::FETCH_KEY_PAIR); // Prepare payment details for display foreach ($feeAllocations as $key => $allocation) { $feeAllocations[$key]['description'] = $feeDescriptions[$allocation['fee_id']] ?? 'Unknown Fee'; } $paymentDetails = [ 'student_code' => $studentCode, 'payment_date' => $paymentDate, 'teller_no' => $tellerNo, 'teller_name' => $tellerName, 'total_paid' => $totalPaid, 'receipt_no' => $receiptNo, 'transaction_id' => $transactionId, 'allocations' => $feeAllocations, 'remaining_unreconciled' => $bankStatement['unreconciled_amount'] - $totalPaid ]; } catch (Exception $e) { $pdo->rollBack(); throw new Exception('Transaction failed: ' . $e->getMessage()); } } catch (Exception $e) { $success = false; $message = $e->getMessage(); } // Fetch student name for display $studentName = ''; if (!empty($studentId)) { try { $sql = "SELECT CONCAT(last_name, ' ', first_name, ' ', COALESCE(other_name, '')) AS full_name FROM tb_student_registrations WHERE id = :student_id"; $stmt = $pdo->prepare($sql); $stmt->execute(['student_id' => $studentId]); $result = $stmt->fetch(); $studentName = $result['full_name'] ?? 'Unknown Student'; } catch (Exception $e) { $studentName = 'Unknown Student'; } } ?> Payment Processing Result

Payment Processed Successfully!

Student:

Receipt No:

Transaction ID:

Payment Details

Payment Date:
Teller Number:
Bank Narration:
Total Amount Used:
Remaining Unreconciled on Teller:

Fees Settled

Fee Description Session Term Amount Paid
Total:

Payment Processing Failed

Error Details

The payment could not be processed. No changes were made to the database.

Error:

Return to Main Page Download Receipt