124 lines
5.5 KiB
PHP
124 lines
5.5 KiB
PHP
<?php
|
|
// api/payments_post.php
|
|
|
|
header('Content-Type: application/json');
|
|
|
|
require_once __DIR__ . '/../db/config.php';
|
|
require_once __DIR__ . '/../includes/uuid.php';
|
|
require_once __DIR__ . '/../includes/audit_helpers.php';
|
|
|
|
$response = [
|
|
'status' => 'error',
|
|
'message' => 'Invalid request.'
|
|
];
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$input = json_decode(file_get_contents('php://input'), true);
|
|
|
|
if (json_last_error() !== JSON_ERROR_NONE || empty($input['student_id']) || empty($input['amount_received']) || empty($input['payment_method']) || empty($input['cash_account_code']) || empty($input['lines'])) {
|
|
$response['message'] = 'Invalid JSON payload or missing required fields.';
|
|
http_response_code(400);
|
|
echo json_encode($response);
|
|
exit;
|
|
}
|
|
|
|
$pdo = db();
|
|
|
|
try {
|
|
$pdo->beginTransaction();
|
|
|
|
// 1. Fetch Student and Accounts
|
|
$stmt_student = $pdo->prepare("SELECT subledger_id FROM students WHERE id = ?");
|
|
$stmt_student->execute([$input['student_id']]);
|
|
$student_subledger_id = $stmt_student->fetchColumn();
|
|
if (!$student_subledger_id) throw new Exception('Student not found.');
|
|
|
|
$stmt_ar = $pdo->prepare("SELECT id FROM accounts WHERE account_code = '1200-AR-STUDENTS'");
|
|
$stmt_ar->execute();
|
|
$ar_account_id = $stmt_ar->fetchColumn();
|
|
if (!$ar_account_id) throw new Exception('AR account not found.');
|
|
|
|
$stmt_cash = $pdo->prepare("SELECT id FROM accounts WHERE account_code = ? AND account_type = 'Asset'");
|
|
$stmt_cash->execute([$input['cash_account_code']]);
|
|
$cash_account_id = $stmt_cash->fetchColumn();
|
|
if (!$cash_account_id) throw new Exception('Invalid cash/asset account code.');
|
|
|
|
// 2. Create Payment
|
|
$payment_id = uuid_v4();
|
|
$payment_date = $input['payment_date'] ?? date('Y-m-d');
|
|
$stmt_payment = $pdo->prepare(
|
|
"INSERT INTO payments (id, student_id, payment_date, amount_received, payment_method, reference_number) VALUES (?, ?, ?, ?, ?, ?)"
|
|
);
|
|
$stmt_payment->execute([$payment_id, $input['student_id'], $payment_date, $input['amount_received'], $input['payment_method'], $input['reference_number'] ?? null]);
|
|
|
|
// 3. Create Payment Lines and Update Invoices
|
|
$total_applied = 0;
|
|
foreach ($input['lines'] as $line) {
|
|
$total_applied += $line['amount_applied'];
|
|
$stmt_pl = $pdo->prepare("INSERT INTO payment_lines (id, payment_id, invoice_id, amount_applied) VALUES (?, ?, ?, ?)");
|
|
$stmt_pl->execute([uuid_v4(), $payment_id, $line['invoice_id'], $line['amount_applied']]);
|
|
|
|
// Check if invoice is fully paid
|
|
$stmt_inv_total = $pdo->prepare("SELECT total_amount FROM invoices WHERE id = ?");
|
|
$stmt_inv_total->execute([$line['invoice_id']]);
|
|
$invoice_total = $stmt_inv_total->fetchColumn();
|
|
|
|
$stmt_paid_total = $pdo->prepare("SELECT SUM(amount_applied) FROM payment_lines WHERE invoice_id = ?");
|
|
$stmt_paid_total->execute([$line['invoice_id']]);
|
|
$total_paid_for_invoice = $stmt_paid_total->fetchColumn();
|
|
|
|
if ($total_paid_for_invoice >= $invoice_total) {
|
|
$stmt_inv_update = $pdo->prepare("UPDATE invoices SET status = 'Paid' WHERE id = ?");
|
|
$stmt_inv_update->execute([$line['invoice_id']]);
|
|
}
|
|
}
|
|
if (bccomp($total_applied, $input['amount_received'], 2) != 0) {
|
|
throw new Exception('Sum of amounts applied does not match amount received.');
|
|
}
|
|
|
|
// 4. Create Journal Entry
|
|
$journal_entry_id = uuid_v4();
|
|
$description = "Payment {$input['reference_number']} for student {$input['student_id']}";
|
|
$stmt_je = $pdo->prepare(
|
|
"INSERT INTO journal_entries (id, entry_date, description, status, posted_at) VALUES (?, ?, ?, 'Posted', NOW())"
|
|
);
|
|
$stmt_je->execute([$journal_entry_id, $payment_date, $description]);
|
|
|
|
// Debit Cash/Bank
|
|
$stmt_jel_dr = $pdo->prepare("INSERT INTO journal_entry_lines (id, journal_entry_id, account_id, debit) VALUES (?, ?, ?, ?)");
|
|
$stmt_jel_dr->execute([uuid_v4(), $journal_entry_id, $cash_account_id, $input['amount_received']]);
|
|
|
|
// Credit AR
|
|
$stmt_jel_cr = $pdo->prepare(
|
|
"INSERT INTO journal_entry_lines (id, journal_entry_id, account_id, subledger_id, credit) VALUES (?, ?, ?, ?, ?)"
|
|
);
|
|
$stmt_jel_cr->execute([uuid_v4(), $journal_entry_id, $ar_account_id, $student_subledger_, $input['amount_received']]);
|
|
|
|
// Link Payment to Journal Entry
|
|
$stmt_payment_update = $pdo->prepare("UPDATE payments SET journal_entry_id = ? WHERE id = ?");
|
|
$stmt_payment_update->execute([$journal_entry_id, $payment_id]);
|
|
|
|
// Log audit trail
|
|
log_audit_trail($pdo, 'record_payment', ['payment_id' => $payment_id, 'student_id' => $input['student_id'], 'amount' => $input['amount_received']]);
|
|
|
|
$pdo->commit();
|
|
|
|
$response = [
|
|
'status' => 'success',
|
|
'message' => 'Payment recorded and journal entry posted successfully.',
|
|
'data' => [
|
|
'payment_id' => $payment_id,
|
|
'journal_entry_id' => $journal_entry_id
|
|
]
|
|
];
|
|
http_response_code(201);
|
|
|
|
} catch (Exception $e) {
|
|
if ($pdo->inTransaction()) $pdo->rollBack();
|
|
$response['message'] = 'Error recording payment: ' . $e->getMessage();
|
|
http_response_code(500);
|
|
}
|
|
}
|
|
|
|
echo json_encode($response, JSON_PRETTY_PRINT);
|