array('date') ); var $belongsTo = array( ); var $hasMany = array( 'LedgerEntry', ); /************************************************************************** ************************************************************************** ************************************************************************** * function: addInvoice * - Adds a new invoice transaction */ function addInvoice($data, $customer_id, $lease_id = null) { // Sanitize the data if (!$data['Transaction']['comment']) $data['Transaction']['comment'] = null; // Automatically figure out the customer if we have the lease if ($lease_id && !$customer_id) { $L = new Lease(); $L->recursive = -1; $lease = $L->read(null, $lease_id); $customer_id = $lease['Lease']['customer_id']; } // Invoice must be attributed to _someone_ if (!$customer_id) return false; // Create some models for convenience $A = new Account(); // Determine the total charges on the invoice $grand_total = 0; foreach ($data['LedgerEntry'] AS $entry) $grand_total += $entry['amount']; // Create a transaction for the invoice $invoice_transaction = new Transaction(); $invoice_transaction->create(); if (!$invoice_transaction->save($data['Transaction'], false)) return false; // Create a transaction for the A/R $ar_transaction = new Transaction(); $ar_transaction->create(); if (!$ar_transaction->save($data['Transaction'], false)) return false; // Create an account receivable entry // I would prefer to do this last, as it feels more // logical to me that the entries would flow from the // charge to the A/R, but in reality it makes no // difference to the end result. Entering the A/R // first allows us to reconcile each charge on the // invoice as we enter them. Otherwise, we would // need to loop again at the end to reconcile, and // would need to save each charge entry id in the // interim. This keeps the logic simple. // debit: A/R credit: Invoice $ar_entry_data = array ('debit_ledger_id' => $A->currentLedgerID($A->accountReceivableAccountID()), 'credit_ledger_id' => $A->currentLedgerID($A->invoiceAccountID()), 'transaction_id' => $ar_transaction->id, 'amount' => $grand_total, 'lease_id' => $lease_id, 'customer_id' => $customer_id, ); // Create a new A/R entry from the data $ar_entry = new LedgerEntry(); $ar_entry->create(); if (!$ar_entry->save($ar_entry_data, false)) return false; // Go through the entered charges foreach ($data['LedgerEntry'] AS $entry) { // Invoice Transaction // debit: Invoice credit: Charge $entry['transaction_id'] = $invoice_transaction->id; // Debit the "invoice" asset... $entry['debit_ledger_id'] = $A->currentLedgerID($A->invoiceAccountID()); // ...and credit the charge ledger $entry['credit_ledger_id'] = $A->currentLedgerID($entry['account_id']); $entry['customer_id'] = $customer_id; $entry['lease_id'] = $lease_id; // Create it $invoice_entry = new LedgerEntry(); $invoice_entry->create(); if (!$invoice_entry->save($entry, false)) return false; // Reconcile the Invoice account. Our two entries are: // debit: Invoice credit: Charge // debit: A/R credit: Invoice // Since this is from the perspective of the Invoice account, // the credit entry is the Invoice<->A/R, and the debit // entry is the actual invoice ledger entry. $R = new Reconciliation(); $R->create(); if (!$R->save(array('debit_ledger_entry_id' => $invoice_entry->id, 'credit_ledger_entry_id' => $ar_entry->id, 'amount' => $entry['amount']), false)) return false; } // Return indication of success return true; } /************************************************************************** ************************************************************************** ************************************************************************** * function: addReceipt * - Adds a new receipt transaction */ function addReceipt($data, $customer_id) { // Sanitize the data if (!$data['Transaction']['comment']) $data['Transaction']['comment'] = null; // Create some models for convenience $A = new Account(); $C = new Customer(); // Receipt must be paid by _someone_ // REVISIT 20090706: // Will we really disallow anonymous payments? if (!$customer_id) return false; // Create a transaction for the receipt $receipt_transaction = new Transaction(); $receipt_transaction->create(); if (!$receipt_transaction->save($data['Transaction'], false)) return false; // Create a transaction for the splits $split_transaction = new Transaction(); $split_transaction->create(); if (!$split_transaction->save($data['Transaction'], false)) return false; // Go through the entered payments foreach ($data['LedgerEntry'] AS $entry) { // Get the Monetary Source squared away if ($entry['account_id'] == $A->cashAccountID()) { // No distinguishing features of Cash, just // use the shared monetary source $entry['monetary_source_id'] = $this->LedgerEntry->MonetarySource->nameToID('Cash'); unset($entry['MonetarySource']); } else { $entry['MonetarySource']['name'] = $A->name($entry['account_id']); // Give it a fancy name based on the check number if ($A->name($entry['account_id']) === 'Check' || $A->name($entry['account_id']) === 'Money Order') { $entry['MonetarySource']['name'] .= ' #' . $entry['MonetarySource']['data1']; } } // This entry of physical money is part of the receipt transaction // debit: Cash/Check/Etc credit: Receipt $entry['transaction_id'] = $receipt_transaction->id; // Receipt must debit the "money" asset (bank, cash, check, etc)... $entry['debit_ledger_id'] = $A->currentLedgerID($entry['account_id']); // ...and credit the Receipt ledger $entry['credit_ledger_id'] = $A->currentLedgerID($A->receiptAccountID()); $entry['customer_id'] = $customer_id; // Create it $receipt_entry = new LedgerEntry(); $receipt_entry->create(); if (!$receipt_entry->saveAll($entry, array('validate' => false, ))) return false; $reconciled = $C->reconcileNewLedgerEntry($customer_id, 'credit', $entry['amount']); foreach (array_merge($reconciled['debit']['entry'], array (array('id' => null, 'applied' => $reconciled['debit']['unapplied'], 'customer_id' => $customer_id, 'lease_id' => null))) AS $rec) { if (!$rec['applied']) continue; // Create an entry to handle the splitting of the funds ("Payment") // Payment must debit the Receipt ledger, and credit the A/R ledger // debit: Receipt credit: A/R $split_entry_data = array ('debit_ledger_id' => $A->currentLedgerID($A->receiptAccountID()), 'credit_ledger_id' => $A->currentLedgerID($A->accountReceivableAccountID()), 'transaction_id' => $split_transaction->id, 'amount' => $rec['applied'], 'lease_id' => $rec['lease_id'], 'customer_id' => $rec['customer_id'], ); // Create a new split entry from the data $split_entry = new LedgerEntry(); $split_entry->create(); if (!$split_entry->save($split_entry_data, false)) return false; // Reconcile the Receipt account. Our two entries are: // debit: Cash/Check/Etc credit: Receipt // debit: Receipt credit: A/R // Since this is from the perspective of the Receipt account, // the debit entry is the Receipt<->A/R, and the credit // entry is the actual receipt ledger entry. $R = new Reconciliation(); $R->create(); if (!$R->save(array('debit_ledger_entry_id' => $split_entry->id, 'credit_ledger_entry_id' => $receipt_entry->id, 'amount' => $rec['applied']), false)) return false; // Only reconcile the A/R account if we have an entry // to reconcile with, otherwise, just go on. if (!$rec['id']) continue; // Reconcile the A/R account. Our two entries look like: // debit: Receipt credit: A/R // debit: A/R credit: Invoice // Since this is from the perspective of the A/R account, // the debit entry is the Invoice<->A/R, and the credit // entry is the Receipt<->A/R. $R = new Reconciliation(); $R->create(); if (!$R->save(array('debit_ledger_entry_id' => $rec['id'], 'credit_ledger_entry_id' => $split_entry->id, 'amount' => $rec['applied']), false)) return false; } } return true; } } ?>