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 ]; }