37241-vm/api/bills_post.php
2026-01-03 08:40:36 +00:00

103 lines
3.6 KiB
PHP

<?php
require_once __DIR__ . '/../includes/uuid.php';
require_once __DIR__ . '/../db/config.php';
require_once __DIR__ . '/../includes/journal_helpers.php';
require_once __DIR__ . '/../includes/audit_helpers.php';
header('Content-Type: application/json');
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo json_encode(['error' => 'Method not allowed']);
exit();
}
$data = json_decode(file_get_contents('php://input'), true);
// Basic validation
if (empty($data['vendor_id']) || empty($data['bill_date']) || empty($data['due_date']) || empty($data['lines']) || !is_array($data['lines'])) {
http_response_code(400);
echo json_encode(['error' => 'Missing required fields: vendor_id, bill_date, due_date, and lines array.']);
exit();
}
$pdo = db();
try {
$pdo->beginTransaction();
// 1. Calculate total amount and prepare journal entry lines
$total_amount = 0;
$journal_lines = [];
$ap_account_code = '2100-AP'; // Accounts Payable
foreach ($data['lines'] as $line) {
if (empty($line['expense_account_code']) || empty($line['amount'])) {
throw new Exception('Each bill line must have expense_account_code and amount.');
}
$amount = (float)$line['amount'];
$total_amount += $amount;
// Debit the expense account for this line
$journal_lines[] = [
'account_code' => $line['expense_account_code'],
'type' => 'DEBIT',
'amount' => $amount
];
}
// Credit Accounts Payable for the total amount
$journal_lines[] = [
'account_code' => $ap_account_code,
'type' => 'CREDIT',
'amount' => $total_amount
];
// 2. Create the Journal Entry
$journal_entry_payload = [
'entry_date' => $data['bill_date'],
'description' => 'Vendor bill from ' . ($data['vendor_name'] ?? $data['vendor_id']),
'lines' => $journal_lines
];
// Use a function to post the journal entry
$journal_entry_result = post_journal_entry($pdo, $journal_entry_payload);
if (empty($journal_entry_result['journal_entry_id'])) {
throw new Exception("Failed to post journal entry: " . ($journal_entry_result['error'] ?? 'Unknown error'));
}
$journal_entry_id = $journal_entry_result['journal_entry_id'];
// 3. Create the Bill
$bill_id = uuid_v4();
$stmt = $pdo->prepare(
"INSERT INTO bills (bill_id, vendor_id, journal_entry_id, bill_date, due_date, total_amount, status) VALUES (?, ?, ?, ?, ?, ?, 'SUBMITTED')"
);
$stmt->execute([$bill_id, $data['vendor_id'], $journal_entry_id, $data['bill_date'], $data['due_date'], $total_amount]);
// 4. Create Bill Lines
$stmt_lines = $pdo->prepare(
"INSERT INTO bill_lines (bill_line_id, bill_id, expense_account_code, description, amount) VALUES (?, ?, ?, ?, ?)"
);
foreach ($data['lines'] as $line) {
$stmt_lines->execute([uuid_v4(), $bill_id, $line['expense_account_code'], $line['description'] ?? null, $line['amount']]);
}
// Log audit trail
log_audit_trail($pdo, 'create_bill', ['bill_id' => $bill_id, 'vendor_id' => $data['vendor_id'], 'total_amount' => $total_amount]);
$pdo->commit();
// 5. Fetch and return the created bill
$stmt = $pdo->prepare("SELECT * FROM bills WHERE bill_id = ?");
$stmt->execute([$bill_id]);
$new_bill = $stmt->fetch(PDO::FETCH_ASSOC);
http_response_code(201);
echo json_encode($new_bill);
} catch (Exception $e) {
$pdo->rollBack();
http_response_code(500);
echo json_encode(['error' => 'Operation failed: ' . $e->getMessage()]);
}