git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@392 97e9348a-65ac-dc4b-aefc-98561f571b83
610 lines
22 KiB
PHP
610 lines
22 KiB
PHP
<?php
|
|
class StatementEntry extends AppModel {
|
|
|
|
var $belongsTo = array(
|
|
'Transaction',
|
|
'Customer',
|
|
'Lease',
|
|
'Account',
|
|
|
|
// The charge to which this payment applies (if it is one)
|
|
'ChargeEntry' => array(
|
|
'className' => 'StatementEntry',
|
|
),
|
|
);
|
|
|
|
var $hasMany = array(
|
|
// The payments that apply to this charge (if it is one)
|
|
'PaymentEntry' => array(
|
|
'className' => 'StatementEntry',
|
|
'foreignKey' => 'charge_entry_id',
|
|
),
|
|
|
|
);
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: chargePaymentFields
|
|
*/
|
|
|
|
|
|
function chargePaymentFields($sum = false, $entry_name = 'StatementEntry') {
|
|
$fields = array
|
|
(
|
|
($sum ? 'SUM(' : '') .
|
|
"IF({$entry_name}.type = 'CHARGE'," .
|
|
" {$entry_name}.amount, NULL)" .
|
|
($sum ? ')' : '') . ' AS charge' . ($sum ? 's' : ''),
|
|
|
|
($sum ? 'SUM(' : '') .
|
|
"IF({$entry_name}.type = 'PAYMENT' OR {$entry_name}.type = 'CREDIT'," .
|
|
" {$entry_name}.amount, NULL)" .
|
|
($sum ? ')' : '') . ' AS payment' . ($sum ? 's' : ''),
|
|
|
|
($sum ? 'SUM(' : '') .
|
|
"IF({$entry_name}.type = 'CHARGE', 1, -1)" .
|
|
" * IF({$entry_name}.amount, {$entry_name}.amount, 0)" .
|
|
($sum ? ')' : '') . ' AS balance',
|
|
);
|
|
|
|
if ($sum)
|
|
$fields[] = "COUNT({$entry_name}.id) AS entries";
|
|
|
|
return $fields;
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: addCharge
|
|
* - Adds a new charge
|
|
*/
|
|
|
|
function addCharge($data, $transaction, $customer_id, $lease_id = null) {
|
|
// Create some models for convenience
|
|
$A = new Account();
|
|
|
|
// Assume this will succeed
|
|
$ret = true;
|
|
|
|
// Establish the key charge parameters
|
|
$charge = array_intersect_key($data, array('stamp'=>1, 'amount'=>1, 'account_id'=>1));
|
|
|
|
$charge['customer_id'] = $customer_id;
|
|
$charge['lease_id'] = $lease_id;
|
|
$charge['type'] = 'CHARGE';
|
|
|
|
$ids = $this->Entry->Ledger->Account->postLedgerEntry
|
|
($transaction,
|
|
$charge,
|
|
array('debit_ledger_id' => $A->currentLedgerID($data['account_id']),
|
|
'credit_ledger_id' => $A->currentLedgerID($A->accountReceivableAccountID())
|
|
) + $data
|
|
);
|
|
|
|
if ($ids['error'])
|
|
$ret = false;
|
|
|
|
return $ids['charge_id'];
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: addPayment
|
|
* - Adds a new payment
|
|
*/
|
|
|
|
function addPayment($data, $transaction, $customer_id, $lease_id = null) {
|
|
// Create some models for convenience
|
|
$A = new Account();
|
|
|
|
// Assume this will succeed
|
|
$ret = true;
|
|
|
|
// Establish the key payment parameters
|
|
$payment = array_intersect_key($data, array('stamp'=>1, 'name'=>1, 'monetary_type'=>1,
|
|
'data1'=>1, 'data2'=>1, 'data3'=>1, 'data4'=>1,
|
|
'amount'=>1, 'account_id'=>1));
|
|
$payment['customer_id'] = $customer_id;
|
|
$payment['type'] = 'PAYMENT';
|
|
|
|
$ids = $this->Entry->Ledger->Account->postLedgerEntry
|
|
($transaction,
|
|
$payment,
|
|
array('debit_ledger_id' => $A->currentLedgerID($data['account_id']),
|
|
'credit_ledger_id' => $A->currentLedgerID($A->accountReceivableAccountID())
|
|
) + $data
|
|
);
|
|
|
|
if ($ids['error'])
|
|
$ret = false;
|
|
|
|
return $ids['payment_id'];
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: reverse
|
|
* - Reverses the charges
|
|
*
|
|
* SAMPLE MOVE IN w/ PRE PAYMENT
|
|
* DEPOSIT RENT A/R RECEIPT CHECK PETTY BANK
|
|
* ------- ------- ------- ------- ------- ------- -------
|
|
* |25 | 25| | | | |
|
|
* | |20 20| | | | |
|
|
* | |20 20| | | | |
|
|
* | |20 20| | | | |
|
|
* | | |25 25| | | |
|
|
* | | |20 20| | | |
|
|
* | | |20 20| | | |
|
|
* | | |20 20| | | |
|
|
* | | | |85 85| | |
|
|
* | | | | |85 | 85|
|
|
|
|
* MOVE OUT and REFUND FINAL MONTH
|
|
* DEPOSIT RENT C/P RECEIPT CHECK PETTY BANK
|
|
* ------- ------- ------- ------- ------- ------- -------
|
|
* 25| | |25 | | | | t20 e20a
|
|
* | 20| |20 | | | | t20 e20b
|
|
|
|
* -ONE REFUND CHECK-
|
|
* | | 25| |25 | | | t30 e30a
|
|
* | | 20| |20 | | | t30 e30b
|
|
* | | | 45| | | |45 t40 e40
|
|
* -OR MULTIPLE-
|
|
* | | 15| |15 | | | t50a e50a
|
|
* | | | 15| | |15 | t60a e60a
|
|
* | | 30| |30 | | | t50b e50b
|
|
* | | | 30| | | |30 t60b e60b
|
|
* | | | | | | |
|
|
|
|
|
|
OPTION 1
|
|
* |-25 | -25| | | | |
|
|
* | |-20 -20| | | | |
|
|
* | | |-25 -25| | | |
|
|
* | | |-20 -20| | | |
|
|
|
|
OPTION 2
|
|
* |-25 | | -25| | | |
|
|
* | |-20 | -20| | | |
|
|
* | | | |-15 | -15| |
|
|
* | | | |-30 | | -30|
|
|
* | | | | | | |
|
|
*
|
|
*/
|
|
function reverse($ledger_entries, $stamp = null) {
|
|
pr(array('Entry::reverse',
|
|
compact('ledger_entries', 'stamp')));
|
|
|
|
// If the user only wants to reverse one ID, we'll allow it
|
|
if (!is_array($ledger_entries))
|
|
$ledger_entries = $this->find
|
|
('all', array
|
|
('contain' => false,
|
|
'conditions' => array('Entry.id' => $ledger_entries)));
|
|
|
|
$A = new Account();
|
|
|
|
$ar_account_id = $A->accountReceivableAccountID();
|
|
$receipt_account_id = $A->receiptAccountID();
|
|
|
|
$transaction_id = null;
|
|
foreach ($ledger_entries AS $entry) {
|
|
$entry = $entry['Entry'];
|
|
$amount = -1*$entry['amount'];
|
|
|
|
if (isset($entry['credit_account_id']))
|
|
$refund_account_id = $entry['credit_account_id'];
|
|
elseif (isset($entry['CreditLedger']['Account']['id']))
|
|
$refund_account_id = $entry['CreditLedger']['Account']['id'];
|
|
elseif (isset($entry['credit_ledger_id']))
|
|
$refund_account_id = $this->Ledger->accountID($entry['credit_ledger_id']);
|
|
else
|
|
return null;
|
|
|
|
// post new refund in the income account
|
|
$ids = $A->postEntry
|
|
(array('transaction_id' => $transaction_id),
|
|
null,
|
|
array('debit_ledger_id' => $A->currentLedgerID($ar_account_id),
|
|
'credit_ledger_id' => $A->currentLedgerID($refund_account_id),
|
|
'effective_date' => $entry['effective_date'],
|
|
'through_date' => $entry['through_date'],
|
|
'amount' => $amount,
|
|
'lease_id' => $entry['lease_id'],
|
|
'customer_id' => $entry['customer_id'],
|
|
'comment' => "Refund; Entry #{$entry['id']}",
|
|
),
|
|
array('debit' => array
|
|
(array('Entry' =>
|
|
array('id' => $entry['id'],
|
|
'amount' => $amount))),
|
|
)
|
|
);
|
|
|
|
if ($ids['error'])
|
|
return null;
|
|
$transaction_id = $ids['transaction_id'];
|
|
|
|
pr(array('checkpoint' => 'Posted Refund Ledger Entry',
|
|
compact('ids', 'amount', 'refund_account_id', 'ar_account_id')));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: reconciledSet
|
|
* - Returns the set of entries satisfying the given conditions,
|
|
* along with any entries that they reconcile
|
|
*/
|
|
function reconciledSetQuery($set, $query) {
|
|
$this->queryInit($query);
|
|
|
|
if ($set == 'CHARGE' || $set == 'PAYMENT')
|
|
$query['conditions'][] = array('StatementEntry.type' => $set);
|
|
else
|
|
die("INVALID RECONCILE SET");
|
|
|
|
if ($set == 'CHARGE')
|
|
$query['link']['PaymentEntry'] = array('fields' => array("SUM(PaymentEntry.amount) AS reconciled"));
|
|
if ($set == 'PAYMENT')
|
|
$query['link']['ChargeEntry'] = array('fields' => array("SUM(ChargeEntry.amount) AS reconciled"));
|
|
|
|
$query['group'] = 'StatementEntry.id';
|
|
|
|
// REVISIT: TESTING
|
|
//$query['link']['PaymentEntry'] = array('fields' => array("(`PaymentEntry.amount`+0) AS reconciled"));
|
|
//$query['group'] = null;
|
|
// END REVISIT
|
|
|
|
return $query;
|
|
}
|
|
|
|
function reconciledSet($set, $query = null, $unrec = false) {
|
|
$lquery = $this->reconciledSetQuery($set, $query);
|
|
$result = $this->find('all', $lquery);
|
|
|
|
//pr(array('StatementEntry::reconciledSet' => compact('set', 'unrec', 'lquery', 'result')));
|
|
|
|
$resultset = array();
|
|
foreach ($result AS $i => $entry) {
|
|
//pr(compact('entry'));
|
|
if (!empty($entry[0]))
|
|
$entry['StatementEntry'] = $entry[0] + $entry['StatementEntry'];
|
|
unset($entry[0]);
|
|
|
|
$entry['StatementEntry']['balance'] =
|
|
$entry['StatementEntry']['amount'] - $entry['StatementEntry']['reconciled'];
|
|
|
|
// Since HAVING isn't a builtin feature of CakePHP,
|
|
// we'll have to post-process to get the desired entries
|
|
if ($entry['StatementEntry']['balance'] == 0) {
|
|
if (!$unrec)
|
|
$resultset[] = $entry;
|
|
}
|
|
else {
|
|
if ($unrec)
|
|
$resultset[] = $entry;
|
|
}
|
|
}
|
|
|
|
//pr(array('StatementEntry::reconciledSet' => compact('resultset')));
|
|
|
|
//$resultset['stats'] = $this->stats(null, $query);
|
|
//pr($this->stats(null, $query));
|
|
return array('entries' => $resultset,
|
|
'summary' => $this->stats(null, $query));
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: reconciledEntries
|
|
* - Returns a list of entries that reconcile against the given entry.
|
|
* (such as payments towards a charge).
|
|
*/
|
|
function reconciledEntriesQuery($id, $query = null) {
|
|
$this->queryInit($query, false);
|
|
|
|
$this->id = $id;
|
|
$this->recursive = -1;
|
|
$this->read();
|
|
|
|
$query['conditions'][] = array('StatementEntry.id' => $id);
|
|
|
|
if ($this->data['StatementEntry']['type'] == 'CHARGE')
|
|
$query['link']['PaymentEntry'] = array();
|
|
if ($this->data['StatementEntry']['type'] == 'PAYMENT')
|
|
$query['link']['ChargeEntry'] = array();
|
|
|
|
return $query;
|
|
}
|
|
|
|
function reconciledEntries($id, $query = null) {
|
|
$lquery = $this->reconciledEntriesQuery($id, $query);
|
|
|
|
//pr(array('reconciledEntries', compact('entry', 'contain')));
|
|
$result = $this->find('all', $lquery);
|
|
foreach (array_keys($result) AS $i)
|
|
unset($result[$i]['StatementEntry']);
|
|
|
|
//pr(array('StatementEntry::reconciledEntries()' => compact('result')));
|
|
return array('entries' => $result);
|
|
//'summary' => $this->stats($id, $query));
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: assignCredits
|
|
* - Assigns all credits to existing charges
|
|
*/
|
|
function assignCredits($query = null, $receipt_id = null) {
|
|
pr(array('StatementEntry::assignCredits' => compact('query')));
|
|
$this->queryInit($query);
|
|
|
|
// First, find all known credits
|
|
$lquery = $query;
|
|
$lquery['conditions'][] = array('StatementEntry.type' => 'CREDIT');
|
|
$credits = $this->find('all', $lquery);
|
|
pr(compact('lquery', 'credits'));
|
|
|
|
// Then, find all receipts that have not had all
|
|
// monies dispursed for either payments or credits
|
|
// REVISIT <AP>: If we implement CREDITS as we're
|
|
// anticipating, then this concept of "anonymous"
|
|
// credits won't exists (i.e. credits that are
|
|
// not explicitly specified with a statement entry
|
|
// of type CREDIT). All transactions MUST balance
|
|
// out to the sum of their statement entries, so
|
|
// we'll be able to just delete all the anon_credit
|
|
// code.
|
|
$lquery = $query;
|
|
$lquery['link'] = array('StatementEntry' => array('fields' => array()) + $lquery['link']);
|
|
$lquery['conditions'][] = array('Transaction.type' => 'RECEIPT');
|
|
$lquery['fields'] = array('Transaction.id', 'Transaction.stamp', 'Transaction.amount',
|
|
//'SUM(StatementEntry.amount) AS applied_amount',
|
|
'Transaction.amount - SUM(StatementEntry.amount) AS balance');
|
|
$lquery['group'] = 'Transaction.id HAVING balance > 0';
|
|
$anon_credits = $this->Transaction->find('all', $lquery);
|
|
foreach ($anon_credits AS &$ac) {
|
|
$ac['Transaction'] += $ac[0];
|
|
unset($ac[0]);
|
|
}
|
|
pr(compact('lquery', 'anon_credits'));
|
|
|
|
// REVISIT <AP>: 20090726
|
|
// This algorithm shouldn't be hardcoded. We need to allow
|
|
// the user to specify how payments should be applied.
|
|
|
|
// Now find all unpaid charges
|
|
$lquery = $query;
|
|
$lquery['order'] = 'StatementEntry.effective_date ASC';
|
|
$charges = $this->reconciledSet('CHARGE', $query, true);
|
|
pr(compact('lquery', 'charges'));
|
|
|
|
// Initialize our list of used credits
|
|
$used_credits = array();
|
|
$used_anon_credits = array();
|
|
|
|
// Work through all unpaid charges, applying payments as we go
|
|
foreach ($charges['entries'] AS $charge) {
|
|
|
|
pr(array('StatementEntry::assignCredits' =>
|
|
array('checkpoint' => 'Process Charge')
|
|
+ compact('charge')));
|
|
|
|
// Check that we have available credits.
|
|
// Technically, this isn't necessary, since the loop
|
|
// will handle everything just fine. However, this
|
|
// just saves extra processing if/when there is no
|
|
// means to resolve a charge anyway.
|
|
if (count($credits) == 0 && count($anon_credits) == 0) {
|
|
pr(array('StatementEntry::assignCredits' =>
|
|
array('checkpoint' => 'No available credits')));
|
|
break;
|
|
}
|
|
|
|
$charge['balance'] = $charge['StatementEntry']['balance'];
|
|
while ($charge['balance'] > 0 &&
|
|
(count($credits) || count($anon_credits))) {
|
|
|
|
pr(array('StatementEntry::assignCredits' =>
|
|
array('checkpoint' => 'Attempt Charge Reconciliation')
|
|
+ compact('charge')));
|
|
|
|
// Use explicit credits before using implicit credits
|
|
// (Not sure it matters though).
|
|
if (count($credits)) {
|
|
// Peel off the first credit available
|
|
$credit =& $credits[0];
|
|
$payment_date = $credit['StatementEntry']['effective_date'];
|
|
$payment_transaction_id = $credit['StatementEntry']['transaction_id'];
|
|
|
|
if (!isset($credit['balance']))
|
|
$credit['balance'] = $credit['StatementEntry']['amount'];
|
|
}
|
|
elseif (count($anon_credits)) {
|
|
// Peel off the first credit available
|
|
$credit =& $anon_credits[0];
|
|
$payment_date = $credit['Transaction']['stamp'];
|
|
$payment_transaction_id = $credit['Transaction']['id'];
|
|
|
|
if (!isset($credit['balance']))
|
|
$credit['balance'] = $credit['Transaction']['balance'];
|
|
|
|
}
|
|
else {
|
|
die("HOW DID WE GET HERE WITH NO CREDITS?");
|
|
}
|
|
|
|
// Set the payment amount to the maximum amount
|
|
// possible without exceeding the charge or credit balance
|
|
$payment_amount = min($charge['balance'], $credit['balance']);
|
|
if (!isset($credit['applied']))
|
|
$credit['applied'] = 0;
|
|
|
|
$credit['applied'] += $payment_amount;
|
|
$credit['balance'] -= $payment_amount;
|
|
|
|
pr(array('StatementEntry::assignCredits' =>
|
|
array('checkpoint' => (($credit['balance'] > 0 ? 'Utilized' : 'Exhausted')
|
|
. (count($credits) ? '' : ' Anon')
|
|
. ' Credit'))
|
|
+ compact('credit')));
|
|
|
|
if ($credit['balance'] < 0)
|
|
die("HOW DID WE END UP WITH NEGATIVE CREDIT BALANCE?");
|
|
|
|
// If we've exhaused the credit, get it out of the
|
|
// available credit pool (but keep track of it for later).
|
|
if ($credit['balance'] <= 0) {
|
|
if (count($credits))
|
|
$used_credits[] = array_shift($credits);
|
|
else
|
|
$used_anon_credits[] = array_shift($anon_credits);
|
|
}
|
|
|
|
// Add a payment that uses the available credit to pay the charge
|
|
$payment = array('type' => 'PAYMENT',
|
|
'account_id' => $this->Account->accountReceivableAccountID(),
|
|
'amount' => $payment_amount,
|
|
'effective_date' => $payment_date,
|
|
'transaction_id' => $payment_transaction_id,
|
|
'customer_id' => $charge['StatementEntry']['customer_id'],
|
|
'lease_id' => $charge['StatementEntry']['lease_id'],
|
|
'charge_entry_id' => $charge['StatementEntry']['id'],
|
|
'comment' => null,
|
|
);
|
|
|
|
pr(array('StatementEntry::assignCredits' =>
|
|
array('checkpoint' => 'New Payment Entry')
|
|
+ compact('payment')));
|
|
|
|
$SE = new StatementEntry();
|
|
$SE->create();
|
|
if (!$SE->save($payment))
|
|
die("UNABLE TO SAVE NEW PAYMENT ENTRY");
|
|
|
|
// Adjust the charge balance to reflect the new payment
|
|
$charge['balance'] -= $payment_amount;
|
|
if ($charge['balance'] < 0)
|
|
die("HOW DID WE GET A NEGATIVE CHARGE AMOUNT?");
|
|
|
|
if ($charge['balance'] <= 0)
|
|
pr(array('StatementEntry::assignCredits' =>
|
|
array('checkpoint' => 'Fully Paid Charge')));
|
|
}
|
|
|
|
}
|
|
|
|
// Make partially used credits are added to the used list
|
|
if (isset($credits[0]['applied']))
|
|
$used_credits[] = array_shift($credits);
|
|
if (isset($anon_credits[0]['applied']))
|
|
$used_anon_credits[] = array_shift($anon_credits);
|
|
|
|
pr(array('StatementEntry::assignCredits' =>
|
|
array('checkpoint' => 'Payments added')
|
|
+ compact('credits', 'used_credits', 'anon_credits', 'used_anon_credits')));
|
|
|
|
// Finally, clean up any credits that have been used
|
|
foreach ($used_credits AS $credit) {
|
|
if ($credit['balance'] > 0) {
|
|
pr(array('StatementEntry::assignCredits' =>
|
|
array('checkpoint' => 'Update Credit Entry')
|
|
+ compact('credit')));
|
|
|
|
$this->id = $credit['StatementEntry']['id'];
|
|
$this->saveField('amount', $credit['balance']);
|
|
}
|
|
else {
|
|
pr(array('StatementEntry::assignCredits' =>
|
|
array('checkpoint' => 'Delete Exhausted Credit Entry')
|
|
+ compact('credit')));
|
|
|
|
$this->del($credit['StatementEntry']['id'], false);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: stats
|
|
* - Returns summary data from the requested statement entry
|
|
*/
|
|
function stats($id = null, $query = null) {
|
|
$this->queryInit($query);
|
|
unset($query['group']);
|
|
|
|
/* pr(array('StatementEntry::stats' => compact('id', 'query'))); */
|
|
|
|
$stats = array();
|
|
if (isset($id))
|
|
$query['conditions'][] = array('StatementEntry.id' => $id);
|
|
|
|
$rquery = $query;
|
|
unset($rquery['link']['ChargeEntry']);
|
|
$rquery['link']['PaymentEntry'] = array('fields' => array());
|
|
|
|
$rquery['fields'] = array();
|
|
$rquery['fields'][] = "SUM(StatementEntry.amount) AS total";
|
|
$rquery['fields'][] = "SUM(PaymentEntry.amount) AS reconciled";
|
|
$rquery['fields'][] = "SUM(StatementEntry.amount - COALESCE(PaymentEntry.amount,0)) AS balance";
|
|
|
|
$rquery['conditions'][] = array('StatementEntry.type' => 'CHARGE');
|
|
$result = $this->find('first', $rquery);
|
|
if (!isset($result[0]['balance']))
|
|
$result[0]['balance'] = 0;
|
|
$stats['Charge'] = $result[0];
|
|
|
|
/* pr(array('StatementEntry::stats' => */
|
|
/* array('checkpoint' => 'Charges') */
|
|
/* + compact('query', 'result'))); */
|
|
|
|
$rquery = $query;
|
|
unset($rquery['link']['PaymentEntry']);
|
|
$rquery['link']['ChargeEntry'] = array('fields' => array());
|
|
|
|
$rquery['fields'] = array();
|
|
$rquery['fields'][] = "SUM(StatementEntry.amount) AS total";
|
|
$rquery['fields'][] = "SUM(IF(ChargeEntry.id IS NULL, 0, StatementEntry.amount)) AS reconciled";
|
|
$rquery['fields'][] = "SUM(IF(ChargeEntry.id IS NULL, StatementEntry.amount, 0)) AS balance";
|
|
|
|
$rquery['conditions'][] = array('StatementEntry.type' => 'PAYMENT');
|
|
$result = $this->find('first', $rquery);
|
|
if (!isset($result[0]['balance']))
|
|
$result[0]['balance'] = 0;
|
|
$stats['Payment'] = $result[0];
|
|
|
|
/* pr(array('StatementEntry::stats' => */
|
|
/* array('checkpoint' => 'Payments') */
|
|
/* + compact('rquery', 'result'))); */
|
|
|
|
|
|
/* pr(array('StatementEntry::stats' => */
|
|
/* array('checkpoint' => 'return') */
|
|
/* + compact('stats'))); */
|
|
|
|
return $stats;
|
|
}
|
|
|
|
}
|