array('className' => 'Ledger'), 'Close', ); var $hasMany = array( 'Entry', 'DoubleEntry' => array( 'foreignKey' => false, // conditions will be used when JOINing tables // (such as find with LinkableBehavior) 'conditions' => array('OR' => array('DoubleEntry.debit_ledger_id = %{MODEL_ALIAS}.id', 'DoubleEntry.credit_ledger_id = %{MODEL_ALIAS}.id')), // finderQuery will be used when tables are put // together across several querys, not with JOIN. // (such as find with ContainableBehavior) 'finderQuery' => 'SELECT `DoubleEntry`.* FROM pmgr_double_entries AS `DoubleEntry` WHERE DoubleEntry.debit_ledger_id = ({$__cakeID__$}) OR DoubleEntry.credit_ledger_id = ({$__cakeID__$})', 'counterQuery' => '' ), ); /************************************************************************** ************************************************************************** ************************************************************************** * function: accountID * - Returns the account ID for the given ledger */ function accountID($id) { $this->cacheQueries = true; $item = $this->find('first', array ('contain' => 'Account.id', 'conditions' => array('Ledger.id' => $id), )); $this->cacheQueries = false; return $item['Account']['id']; } /************************************************************************** ************************************************************************** ************************************************************************** * function: currentLedgerID * - Returns the current ledger ID of the account for the given ledger. */ function currentLedgerID($id) { return $this->Account->currentLedgerID($this->accountID($id)); } /************************************************************************** ************************************************************************** ************************************************************************** * function: closeLedger * - Closes the current ledger, and returns a fresh one */ function closeLedger($id, $close_id) { $this->recursive = -1; $stamp = date('Y-m-d G:i:s'); $this->id = $id; $this->read(); $this->data['Ledger']['close_id'] = $close_id; $this->save($this->data, false); $stats = $this->stats($id); $this->read(); $this->data['Ledger']['id'] = null; $this->data['Ledger']['close_id'] = null; $this->data['Ledger']['prior_ledger_id'] = $id; $this->data['Ledger']['comment'] = null; ++$this->data['Ledger']['sequence']; $this->id = null; $this->save($this->data, false); //pr($this->data); if ($stats['balance'] == 0) return $this->id; $this->read(); $ftype = $this->Account->fundamentalType($this->data['Ledger']['account_id']); $otype = $this->Account->fundamentalOpposite($ftype); // Create a transaction for balance transfer $transaction = new Transaction(); $transaction->create(); if (!$transaction->save(array(), false)) { return null; } // Create an entry to carry the balance forward $carry_entry_data = array ($ftype.'_ledger_id' => $this->id, $otype.'_ledger_id' => $id, 'transaction_id' => $transaction->id, 'amount' => $stats['balance'], 'comment' => "Ledger Balance Forward", ); $carry_entry = new DoubleEntry(); $carry_entry->create(); if (!$carry_entry->save($carry_entry_data, false)) { return null; } return $this->id; } function debitCreditFields($id, $sum = false, $entry_name = 'Entry', $double_name = 'DoubleEntry') { $ftype = strtoupper($this->Account->fundamentalType($this->accountID($id))); $fields = array ( ($sum ? 'SUM(' : '') . "IF({$entry_name}.crdr = 'DEBIT', {$double_name}.amount, NULL)" . ($sum ? ')' : '') . ' AS debit' . ($sum ? 's' : ''), ($sum ? 'SUM(' : '') . "IF({$entry_name}.crdr = 'CREDIT', {$double_name}.amount, NULL)" . ($sum ? ')' : '') . ' AS credit' . ($sum ? 's' : ''), ($sum ? 'SUM(' : '') . "IF({$entry_name}.crdr = '$ftype', 1, -1) * {$double_name}.amount" . // IF({$double_name}.amount, {$double_name}.amount, 0)" . ($sum ? ')' : '') . ' AS balance', ); if ($sum) $fields[] = "COUNT({$entry_name}.id) AS entries"; return $fields; } /************************************************************************** ************************************************************************** ************************************************************************** * function: ledgerEntries * - Returns an array of ledger entries that belong to a given * ledger. There is extra work done to establish debit/credit */ function ledgerEntries($ids, $cond = null, $link = null) { if (empty($ids)) return null; /* $id = (is_array($ids) ? $ids[0] : $ids); */ /* $ftype = strtoupper($this->Account->fundamentalType($this->accountID($id))); */ $entries = $this->Entry->find ('all', array ('contain' => array('DoubleEntry' => array('fields' => array('amount'))), 'fields' => array_merge(array("Entry.*"), $this->debitCreditFields(is_array($ids) ? $ids[0] : $ids)), /* "IF(Entry.crdr = 'CREDIT', DoubleEntry.amount, NULL) AS credit", */ /* "IF(Entry.crdr = 'DEBIT', DoubleEntry.amount, NULL) AS debit", */ /* "IF(Entry.crdr = '$ftype', 1, -1) * DoubleEntry.amount AS balance", */ 'conditions' => array('Entry.ledger_id' => $ids), )); pr(compact('entries')); return $entries; } /************************************************************************** ************************************************************************** ************************************************************************** * function: stats * - Returns summary data from the requested ledger. */ function stats($id, $cond = null) { if (!isset($cond)) $cond = array(); $cond[] = array('Ledger.id' => $id); $stats = $this->find ('first', array ('link' => array(// Models 'Account' => array('fields' => array()), 'Entry' => array ('DoubleEntry' => array('fields' => array(), 'Transaction' => array('fields' => array('stamp')), ), ), ), 'fields' => $this->debitCreditFields($id, true), 'conditions' => $cond, 'group' => 'Ledger.id', )); // The fields are all tucked into the [0] index, // and the rest of the array is useless (empty). $stats = $stats[0]; // Make sure we have a non-null balance if (!isset($stats['balance'])) $stats['balance'] = 0; return $stats; } } ?>