array('numeric'), 'name' => array('notempty'), ); var $belongsTo = array( 'Account', 'PriorLedger' => array('className' => 'Ledger'), 'Close', ); var $hasMany = array( 'LedgerEntry' => array( 'foreignKey' => false, // conditions will be used when JOINing tables // (such as find with LinkableBehavior) 'conditions' => array('OR' => array('LedgerEntry.debit_ledger_id = %{MODEL_ALIAS}.id', 'LedgerEntry.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 `LedgerEntry`.* FROM pmgr_ledger_entries AS `LedgerEntry` WHERE LedgerEntry.debit_ledger_id = ({$__cakeID__$}) OR LedgerEntry.credit_ledger_id = ({$__cakeID__$})', 'counterQuery' => '' ), 'DebitLedgerEntry' => array( 'className' => 'LedgerEntry', 'foreignKey' => 'debit_ledger_id', 'dependent' => false, ), 'CreditLedgerEntry' => array( 'className' => 'LedgerEntry', 'foreignKey' => 'credit_ledger_id', 'dependent' => false, ), ); /************************************************************************** ************************************************************************** ************************************************************************** * 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 LedgerEntry(); $carry_entry->create(); if (!$carry_entry->save($carry_entry_data, false)) { return null; } return $this->id; } /************************************************************************** ************************************************************************** ************************************************************************** * function: findLedgerEntries * - Returns an array of ledger entries that belong to a given * ledger. There is extra work done... see the LedgerEntry model. */ function findLedgerEntries($id, $account_type = null, $cond = null, $link = null) { /* pr(array('function' => 'Ledger::findLedgerEntries', */ /* 'args' => compact('id', 'account_type', 'cond', 'link'), */ /* )); */ if (!isset($account_type)) { $ledger = $this->find('first', array ('contain' => array ('Account' => array ('fields' => array('type'), ), ), 'fields' => array(), 'conditions' => array(array('Ledger.id' => $id)), )); $account_type = $ledger['Account']['type']; } // If the requested entries are limited by date, we must calculate // a balance forward, or the resulting balance will be thrown off. // // REVISIT : This obviously is more general than date. // As such, it will not work (or, only work if the // condition only manages to exclude the first parts // of the ledger, nothing in the middle or at the // end. For now, I'll just create an 'other' entry, // not necessarily a balance forward. $bf = array(); if (0 && isset($cond)) { //$date = ''; $stats = $this->stats($id, array('NOT' => array($cond))); $bf = array(array(array('debit' => $stats['debits'], 'credit' => $stats['credits'], 'balance' => $stats['balance']), 'LedgerEntry' => array('id' => null, //'comment' => "Balance Forward from $date"), 'comment' => "-- SUMMARY OF EXCLUDED ENTRIES --"), 'Transaction' => array('id' => null, //'stamp' => $date, 'stamp' => null, 'comment' => null), )); } $entries = $this->LedgerEntry->findInLedgerContext($id, $account_type, $cond, $link); /* pr(array('function' => 'Ledger::findLedgerEntries', */ /* 'args' => compact('id', 'account_type', 'cond', 'link'), */ /* 'vars' => compact('ledger'), */ /* 'return' => 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()), //'LedgerEntry' => array('fields' => array()), 'LedgerEntry' => array('fields' => array(), 'Transaction' => array('fields' => array('stamp')), ), ), 'fields' => array("SUM(IF(LedgerEntry.debit_ledger_id = Ledger.id, LedgerEntry.amount, NULL)) AS debits", "SUM(IF(LedgerEntry.credit_ledger_id = Ledger.id, LedgerEntry.amount, NULL)) AS credits", "SUM(IF(Account.type IN ('ASSET', 'EXPENSE'), IF(LedgerEntry.debit_ledger_id = Ledger.id, 1, -1), IF(LedgerEntry.credit_ledger_id = Ledger.id, 1, -1) ) * IF(LedgerEntry.amount, LedgerEntry.amount, 0) ) AS balance", "COUNT(LedgerEntry.id) AS entries"), 'conditions' => $cond, 'group' => 'Ledger.id', )); // The fields are all tucked into the [0] index, // and the rest of the array is useless (empty). return $stats[0]; } } ?>