38471-vm/includes/accounting_helper.php
2026-02-18 02:09:29 +00:00

197 lines
7.1 KiB
PHP

<?php
/**
* Accounting Helper for Automatic Journal Entries
*/
function createJournalEntry($date, $description, $reference, $source_type, $source_id, $items) {
$db = db();
try {
$stmt = $db->prepare("INSERT INTO acc_journal_entries (entry_date, description, reference, source_type, source_id) VALUES (?, ?, ?, ?, ?)");
$stmt->execute([$date, $description, $reference, $source_type, $source_id]);
$entryId = $db->lastInsertId();
$stmtLedger = $db->prepare("INSERT INTO acc_ledger (journal_entry_id, account_id, debit, credit) VALUES (?, ?, ?, ?)");
foreach ($items as $item) {
// Find account ID by code
$stmtAcc = $db->prepare("SELECT id FROM acc_accounts WHERE code = ?");
$stmtAcc->execute([$item['code']]);
$accountId = $stmtAcc->fetchColumn();
if ($accountId) {
$stmtLedger->execute([$entryId, $accountId, $item['debit'] ?? 0, $item['credit'] ?? 0]);
}
}
return $entryId;
} catch (Exception $e) {
error_log("Accounting Error: " . $e->getMessage());
return false;
}
}
/**
* Record a Sale
*/
function recordSaleJournal($invoice_id, $amount, $date, $items_data = [], $vat_amount = 0) {
$subtotal = $amount - $vat_amount;
$entries = [
['code' => '1300', 'debit' => $amount], // Accounts Receivable (Asset increases)
['code' => '4100', 'credit' => $subtotal] // Sales Revenue (Revenue increases)
];
if ($vat_amount > 0) {
$entries[] = ['code' => '2300', 'credit' => $vat_amount]; // VAT Payable (Liability increases)
}
// Inventory & COGS
$total_cogs = 0;
foreach ($items_data as $item) {
$stmt = db()->prepare("SELECT purchase_price FROM stock_items WHERE id = ?");
$stmt->execute([$item['id']]);
$cost = (float)$stmt->fetchColumn();
$total_cogs += ($cost * $item['qty']);
}
if ($total_cogs > 0) {
$entries[] = ['code' => '5100', 'debit' => $total_cogs]; // COGS (Expense increases)
$entries[] = ['code' => '1400', 'credit' => $total_cogs]; // Inventory (Asset decreases)
}
return createJournalEntry($date, "Sale Invoice #$invoice_id", "INV-$invoice_id", 'invoice', $invoice_id, $entries);
}
/**
* Record a Purchase
*/
function recordPurchaseJournal($invoice_id, $amount, $date, $items_data = [], $vat_amount = 0) {
$subtotal = $amount - $vat_amount;
$entries = [
['code' => '1400', 'debit' => $subtotal], // Inventory (Asset increases)
['code' => '2100', 'credit' => $amount] // Accounts Payable (Liability increases)
];
if ($vat_amount > 0) {
$entries[] = ['code' => '1500', 'debit' => $vat_amount]; // VAT Input (Asset increases)
}
return createJournalEntry($date, "Purchase Invoice #$invoice_id", "PINV-$invoice_id", 'invoice', $invoice_id, $entries);
}
/**
* Record a Payment Received (from Customer)
*/
function recordPaymentReceivedJournal($payment_id, $amount, $date, $method) {
$code = ($method === 'Bank' || $method === 'Transfer') ? '1200' : '1100';
$entries = [
['code' => $code, 'debit' => $amount], // Cash/Bank (Asset increases)
['code' => '1300', 'credit' => $amount] // Accounts Receivable (Asset decreases)
];
return createJournalEntry($date, "Payment Received #$payment_id", "PAY-$payment_id", 'payment', $payment_id, $entries);
}
/**
* Record a Payment Made (to Supplier)
*/
function recordPaymentMadeJournal($payment_id, $amount, $date, $method) {
$code = ($method === 'Bank' || $method === 'Transfer') ? '1200' : '1100';
$entries = [
['code' => '2100', 'debit' => $amount], // Accounts Payable (Liability decreases)
['code' => $code, 'credit' => $amount] // Cash/Bank (Asset decreases)
];
return createJournalEntry($date, "Payment Made #$payment_id", "PAY-$payment_id", 'payment', $payment_id, $entries);
}
/**
* Record a Sales Return
*/
function recordSalesReturnJournal($return_id, $amount, $date) {
$entries = [
['code' => '4100', 'debit' => $amount], // Sales Revenue (Revenue decreases) - ideally a "Sales Returns" account
['code' => '1300', 'credit' => $amount] // Accounts Receivable (Asset decreases)
];
return createJournalEntry($date, "Sales Return #$return_id", "SRET-$return_id", 'sales_return', $return_id, $entries);
}
/**
* Record a Purchase Return
*/
function recordPurchaseReturnJournal($return_id, $amount, $date) {
$entries = [
['code' => '2100', 'debit' => $amount], // Accounts Payable (Liability decreases)
['code' => '1400', 'credit' => $amount] // Inventory (Asset decreases)
];
return createJournalEntry($date, "Purchase Return #$return_id", "PRET-$return_id", 'purchase_return', $return_id, $entries);
}
/**
* Record an Expense
*/
function recordExpenseJournal($expense_id, $amount, $date, $description, $method = 'Cash') {
$paymentCode = ($method === 'Bank' || $method === 'Transfer') ? '1200' : '1100';
$entries = [
['code' => '5200', 'debit' => $amount], // Operating Expenses (Expense increases)
['code' => $paymentCode, 'credit' => $amount] // Cash/Bank (Asset decreases)
];
return createJournalEntry($date, "Expense: $description", "EXP-$expense_id", 'expense', $expense_id, $entries);
}
/**
* Record Payroll Payment
*/
function recordPayrollJournal($payroll_id, $amount, $date, $emp_name) {
$entries = [
['code' => '5200', 'debit' => $amount], // Using 5200 for now, or could use 5300 if added
['code' => '1100', 'credit' => $amount] // Paid in Cash
];
return createJournalEntry($date, "Payroll Payment - $emp_name", "PAYROLL-$payroll_id", 'payroll', $payroll_id, $entries);
}
/**
* Get Account Balance
*/
function getAccountBalance($code, $start_date = null, $end_date = null) {
$db = db();
$sql = "SELECT SUM(l.debit) - SUM(l.credit) as balance
FROM acc_ledger l
JOIN acc_accounts a ON l.account_id = a.id
JOIN acc_journal_entries e ON l.journal_entry_id = e.id
WHERE a.code LIKE ?";
$params = [$code . '%'];
if ($start_date) {
$sql .= " AND e.entry_date >= ?";
$params[] = $start_date;
}
if ($end_date) {
$sql .= " AND e.entry_date <= ?";
$params[] = $end_date;
}
$stmt = $db->prepare($sql);
$stmt->execute($params);
$balance = (float)$stmt->fetchColumn();
// For Liability, Equity, Revenue: Balance = Credit - Debit
$stmtType = $db->prepare("SELECT type FROM acc_accounts WHERE code = ?");
$stmtType->execute([$code]);
$type = $stmtType->fetchColumn();
if (in_array($type, ['liability', 'equity', 'revenue'])) {
return -$balance;
}
return $balance;
}
/**
* Get VAT Report
*/
function getVatReport($start_date = null, $end_date = null) {
$input_vat = getAccountBalance('1500', $start_date, $end_date);
$output_vat = getAccountBalance('2300', $start_date, $end_date);
return [
'input_vat' => $input_vat,
'output_vat' => $output_vat,
'net_vat' => $output_vat - $input_vat
];
}