116 lines
4.6 KiB
PHP
116 lines
4.6 KiB
PHP
<?php
|
|
// api/invoices_post.php
|
|
|
|
header('Content-Type: application/json');
|
|
|
|
require_once __DIR__ . '/../db/config.php';
|
|
require_once __DIR__ . '/../includes/uuid.php';
|
|
require_once __DIR__ . '/../includes/journal_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['fee_structure_id'])) {
|
|
$response['message'] = 'Invalid JSON payload or missing student_id/fee_structure_id.';
|
|
http_response_code(400);
|
|
echo json_encode($response);
|
|
exit;
|
|
}
|
|
|
|
$pdo = db();
|
|
|
|
try {
|
|
$pdo->beginTransaction();
|
|
|
|
// 1. Fetch Fee Structure details
|
|
$stmt_fsl = $pdo->prepare("SELECT fsl.amount, a.account_code FROM fee_structure_lines fsl JOIN accounts a ON fsl.revenue_account_id = a.id WHERE fsl.fee_structure_id = ?");
|
|
$stmt_fsl->execute([$input['fee_structure_id']]);
|
|
$fee_structure_lines = $stmt_fsl->fetchAll(PDO::FETCH_ASSOC);
|
|
if (empty($fee_structure_lines)) throw new Exception('Fee structure has no lines or revenue accounts not found.');
|
|
|
|
// 2. Create Invoice
|
|
$total_amount = array_sum(array_column($fee_structure_lines, 'amount'));
|
|
$invoice_id = uuid_v4();
|
|
$invoice_number = 'INV-' . time();
|
|
$invoice_date = $input['invoice_date'] ?? date('Y-m-d');
|
|
$due_date = $input['due_date'] ?? date('Y-m-d', strtotime('+30 days'));
|
|
|
|
$stmt_inv = $pdo->prepare(
|
|
"INSERT INTO invoices (id, student_id, invoice_number, invoice_date, due_date, total_amount, status) VALUES (?, ?, ?, ?, ?, ?, 'Posted')"
|
|
);
|
|
$stmt_inv->execute([$invoice_id, $input['student_id'], $invoice_number, $invoice_date, $due_date, $total_amount]);
|
|
|
|
// Don't need to insert invoice lines manually if they are based on fee structure, can be joined.
|
|
// For simplicity, let's assume the previous logic of creating them was desired.
|
|
// Re-creating invoice lines for atomicity.
|
|
foreach ($fee_structure_lines as $line) {
|
|
$stmt_inv_line = $pdo->prepare(
|
|
"INSERT INTO invoice_lines (id, invoice_id, description, amount, revenue_account_id) VALUES (?, ?, ?, ?, (SELECT id from accounts where account_code = ?))"
|
|
);
|
|
$stmt_inv_line->execute([uuid_v4(), $invoice_id, 'Fee', $line['amount'], $line['account_code']]);
|
|
}
|
|
|
|
|
|
// 3. Prepare and Create Journal Entry
|
|
$journal_lines = [];
|
|
// Debit AR
|
|
$journal_lines[] = [
|
|
'account_code' => '1200-AR-STUDENTS',
|
|
'type' => 'DEBIT',
|
|
'amount' => $total_amount
|
|
];
|
|
// Credit Revenue accounts
|
|
foreach ($fee_structure_lines as $line) {
|
|
$journal_lines[] = [
|
|
'account_code' => $line['account_code'],
|
|
'type' => 'CREDIT',
|
|
'amount' => $line['amount']
|
|
];
|
|
}
|
|
|
|
$journal_payload = [
|
|
'entry_date' => $invoice_date,
|
|
'description' => "Invoice {$invoice_number} for student {$input['student_id']}",
|
|
'lines' => $journal_lines
|
|
];
|
|
|
|
$journal_result = post_journal_entry($pdo, $journal_payload);
|
|
if (empty($journal_result['journal_entry_id'])) {
|
|
throw new Exception("Failed to post journal entry: " . ($journal_result['error'] ?? 'Unknown error'));
|
|
}
|
|
$journal_entry_id = $journal_result['journal_entry_id'];
|
|
|
|
// Link Invoice to Journal Entry
|
|
$stmt_inv_update = $pdo->prepare("UPDATE invoices SET journal_entry_id = ? WHERE id = ?");
|
|
$stmt_inv_update->execute([$journal_entry_id, $invoice_id]);
|
|
|
|
// Log audit trail
|
|
log_audit_trail($pdo, 'create_invoice', ['invoice_id' => $invoice_id, 'student_id' => $input['student_id'], 'total_amount' => $total_amount]);
|
|
|
|
$pdo->commit();
|
|
|
|
$response = [
|
|
'status' => 'success',
|
|
'message' => 'Invoice created and journal entry posted successfully.',
|
|
'data' => [
|
|
'invoice_id' => $invoice_id,
|
|
'invoice_number' => $invoice_number,
|
|
'journal_entry_id' => $journal_entry_id
|
|
]
|
|
];
|
|
http_response_code(201);
|
|
|
|
} catch (Exception $e) {
|
|
if ($pdo->inTransaction()) $pdo->rollBack();
|
|
$response['message'] = 'Error creating invoice: ' . $e->getMessage();
|
|
http_response_code(500);
|
|
}
|
|
}
|
|
|
|
echo json_encode($response);
|