3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.3 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2013 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
31 * @copyright CiviCRM LLC (c) 2004-2013
39 class CRM_Batch_BAO_Batch
extends CRM_Batch_DAO_Batch
{
42 * Cache for the current batch object
44 static $_batch = NULL;
47 * Not sure this is the best way to do this. Depends on how exportFinancialBatch() below gets called.
48 * Maybe a parameter to that function is better.
50 static $_exportFormat = NULL;
55 * @param array $params associated array
56 * @param array $ids associated array of ids
57 * @param string $context string
59 * @return object $batch batch object
62 static function create(&$params, $ids = NULL, $context = NULL) {
63 if (!CRM_Utils_Array
::value('id', $params)) {
64 $params['name'] = CRM_Utils_String
::titleToVar($params['title']);
67 $batch = new CRM_Batch_DAO_Batch();
68 $batch->copyValues($params);
69 if ($context == 'financialBatch' && CRM_Utils_Array
::value('batchID', $ids)) {
70 $batch->id
= $ids['batchID'];
78 * Retrieve the information about the batch
80 * @param array $params (reference ) an assoc array of name/value pairs
81 * @param array $defaults (reference ) an assoc array to hold the flattened values
83 * @return array CRM_Batch_BAO_Batch object on success, null otherwise
87 static function retrieve(&$params, &$defaults) {
88 $batch = new CRM_Batch_DAO_Batch();
89 $batch->copyValues($params);
90 if ($batch->find(TRUE)) {
91 CRM_Core_DAO
::storeValues($batch, $defaults);
98 * Get profile id associated with the batch type
100 * @param int $batchTypeId batch type id
102 * @return int $profileId profile id
105 static function getProfileId($batchTypeId) {
106 //retrieve the profile specific to batch type
107 switch ($batchTypeId) {
109 //batch profile used for contribution
110 $profileName = "contribution_batch_entry";
114 //batch profile used for memberships
115 $profileName = "membership_batch_entry";
118 // get and return the profile id
119 return CRM_Core_DAO
::getFieldValue('CRM_Core_BAO_UFGroup', $profileName, 'id', 'name');
123 * generate batch name
128 static function generateBatchName() {
129 $sql = "SELECT max(id) FROM civicrm_batch";
130 $batchNo = CRM_Core_DAO
::singleValueQuery($sql) +
1;
131 return ts('Batch %1', array(1 => $batchNo)) . ': ' . date('Y-m-d');
135 * create entity batch entry
136 * @param array $params associated array
137 * @return batch array
140 static function addBatchEntity(&$params) {
141 $entityBatch = new CRM_Batch_DAO_EntityBatch();
142 $entityBatch->copyValues($params);
143 $entityBatch->save();
148 * Remove entries from entity batch
149 * @param array $params associated array
150 * @return object CRM_Batch_DAO_EntityBatch
152 static function removeBatchEntity($params) {
153 $entityBatch = new CRM_Batch_DAO_EntityBatch();
154 $entityBatch->copyValues($params);
155 $entityBatch->delete();
160 * function to delete batch entry
162 * @param int $batchId batch id
167 static function deleteBatch($batchId) {
168 //delete batch entries from cache
169 $cacheKeyString = CRM_Batch_BAO_Batch
::getCacheKeyForBatch($batchId);
170 CRM_Core_BAO_Cache
::deleteGroup('batch entry', $cacheKeyString, FALSE);
172 // delete entry from batch table
173 $batch = new CRM_Batch_DAO_Batch();
174 $batch->id
= $batchId;
180 * function to get cachekey for batch
182 * @param int $batchId batch id
184 * @retun string $cacheString
188 static function getCacheKeyForBatch($batchId) {
189 return "batch-entry-{$batchId}";
193 * This function is a wrapper for ajax batch selector
195 * @param array $params associated array for params record id.
197 * @return array $batchList associated array of batch list
200 public function getBatchListSelector(&$params) {
202 $params['offset'] = ($params['page'] - 1) * $params['rp'];
203 $params['rowCount'] = $params['rp'];
204 $params['sort'] = CRM_Utils_Array
::value('sortBy', $params);
207 $batches = self
::getBatchList($params);
209 // get batch totals for open batches
210 $fetchTotals = array();
211 if ($params['context'] == 'financialBatch') {
212 foreach ($batches as $id => $batch) {
213 if ($batch['status_id'] == 1) {
214 $fetchTotals[] = $id;
218 $totals = self
::batchTotals($fetchTotals);
221 $params['total'] = self
::getBatchCount($params);
223 // format params and add links
224 $batchList = array();
226 foreach ($batches as $id => $value) {
228 if ($params['context'] == 'financialBatch') {
229 $batch['check'] = $value['check'];
231 $batch['batch_name'] = $value['title'];
232 $batch['total'] = $batch['item_count'] = '';
233 $batch['payment_instrument'] = $value['payment_instrument'];
234 $batch['item_count'] = CRM_Utils_Array
::value('item_count', $value);
235 if (CRM_Utils_Array
::value('total', $value)) {
236 $batch['total'] = CRM_Utils_Money
::format($value['total']);
239 // Compare totals with actuals
240 if (isset($totals[$id])) {
241 $batch['item_count'] = self
::displayTotals($totals[$id]['item_count'], $batch['item_count']);
242 $batch['total'] = self
::displayTotals(CRM_Utils_Money
::format($totals[$id]['total']), $batch['total']);
244 $batch['status'] = $value['batch_status'];
245 $batch['created_by'] = $value['created_by'];
246 $batch['links'] = $value['action'];
247 $batchList[$id] = $batch;
253 * Get list of batches
255 * @param array $params associated array for params
258 static function getBatchList(&$params) {
259 $whereClause = self
::whereClause($params);
261 if (!empty($params['rowCount']) && is_numeric($params['rowCount'])
262 && is_numeric($params['offset']) && $params['rowCount'] > 0
264 $limit = " LIMIT {$params['offset']}, {$params['rowCount']} ";
267 $orderBy = ' ORDER BY batch.id desc';
268 if (!empty($params['sort'])) {
269 $orderBy = ' ORDER BY ' . $params['sort'];
273 SELECT batch.*, c.sort_name created_by
274 FROM civicrm_batch batch
275 INNER JOIN civicrm_contact c ON batch.created_id = c.id
280 $object = CRM_Core_DAO
::executeQuery($query, $params, TRUE, 'CRM_Batch_DAO_Batch');
281 if (CRM_Utils_Array
::value('context', $params)) {
282 $links = self
::links($params['context']);
285 $links = self
::links();
288 $batchTypes = CRM_Core_PseudoConstant
::getBatchType();
289 $batchStatus = CRM_Core_PseudoConstant
::getBatchStatus();
290 $paymentInstrument = CRM_Contribute_PseudoConstant
::paymentInstrument();
293 while ($object->fetch()) {
296 CRM_Core_DAO
::storeValues($object, $values);
297 $action = array_sum(array_keys($newLinks));
299 if ($values['status_id'] == 2 && $params['context'] != 'financialBatch') {
302 elseif ($params['context'] == 'financialBatch') {
304 "<input type='checkbox' id='check_" .
308 "' value='1' data-status_id='" .
309 $values['status_id']."' class='select-row'></input>";
311 switch ($values['status_id']) {
313 CRM_Utils_Array
::remove($newLinks, 'reopen', 'download');
316 CRM_Utils_Array
::remove($newLinks, 'close', 'edit', 'download');
319 CRM_Utils_Array
::remove($newLinks, 'close', 'edit', 'reopen', 'export');
322 if (CRM_Utils_Array
::value('type_id', $values)) {
323 $values['batch_type'] = $batchTypes[$values['type_id']];
325 $values['batch_status'] = $batchStatus[$values['status_id']];
326 $values['created_by'] = $object->created_by
;
327 $values['payment_instrument'] = '';
328 if (!empty($object->payment_instrument_id
)) {
329 $values['payment_instrument'] = $paymentInstrument[$object->payment_instrument_id
];
331 $tokens = array('id' => $object->id
, 'status' => $values['status_id']);
332 if ($values['status_id'] == CRM_Core_OptionGroup
::getValue('batch_status', 'Exported')) {
333 $aid = CRM_Core_OptionGroup
::getValue('activity_type','Export Accounting Batch');
334 $activityParams = array('source_record_id' => $object->id
, 'activity_type_id' => $aid);
335 $exportActivity = CRM_Activity_BAO_Activity
::retrieve($activityParams, $val);
336 $fid = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_EntityFile', $exportActivity->id
, 'file_id', 'entity_id');
337 $tokens = array_merge(array('eid' => $exportActivity->id
, 'fid' => $fid), $tokens);
339 $values['action'] = CRM_Core_Action
::formLink(
344 $results[$object->id
] = $values;
351 * Get count of batches
353 * @param array $params associated array for params
356 static function getBatchCount(&$params) {
358 $whereClause = self
::whereClause($params, $args);
359 $query = " SELECT COUNT(*) FROM civicrm_batch batch
360 INNER JOIN civicrm_contact c ON batch.created_id = c.id
361 WHERE {$whereClause}";
362 return CRM_Core_DAO
::singleValueQuery($query);
366 * Format where clause for getting lists of batches
368 * @param array $params associated array for params
371 function whereClause($params) {
373 // Exclude data-entry batches
374 if (empty($params['status_id'])) {
375 $clauses[] = 'batch.status_id <> 3';
380 'sort_name' => 'String',
381 'status_id' => 'Integer',
382 'payment_instrument_id' => 'Integer',
383 'item_count' => 'Integer',
387 foreach ($fields as $field => $type) {
388 $table = $field == 'sort_name' ?
'c' : 'batch';
389 if (isset($params[$field])) {
390 $value = CRM_Utils_Type
::escape($params[$field], $type, FALSE);
391 if ($value && $type == 'String') {
392 $clauses[] = "$table.$field LIKE '%$value%'";
394 elseif ($value && $type == 'Float') {
395 $clauses[] = "$table.$field = '$value'";
398 $clauses[] = "$table.$field = $value";
402 return $clauses ?
implode(' AND ', $clauses) : '1';
406 * Function to define action links
408 * @return array $links array of action links
411 function links($context = NULL) {
412 if ($context == 'financialBatch') {
414 'transaction' => array(
415 'name' => ts('Transactions'),
416 'url' => 'civicrm/batchtransaction',
417 'qs' => 'reset=1&bid=%%id%%',
418 'title' => ts('View/Add Transactions to Batch'),
421 'name' => ts('Edit'),
422 'url' => 'civicrm/financial/batch',
423 'qs' => 'reset=1&action=update&id=%%id%%&context=1',
424 'title' => ts('Edit Batch'),
427 'name' => ts('Close'),
428 'title' => ts('Close Batch'),
430 'extra' => 'rel="close"',
433 'name' => ts('Export'),
434 'title' => ts('Export Batch'),
436 'extra' => 'rel="export"',
439 'name' => ts('Re-open'),
440 'title' => ts('Re-open Batch'),
442 'extra' => 'rel="reopen"',
445 'name' => ts('Delete'),
446 'title' => ts('Delete Batch'),
448 'extra' => 'rel="delete"',
451 'name' => ts('Download'),
452 'url' => 'civicrm/file',
453 'qs' => 'reset=1&id=%%fid%%&eid=%%eid%%',
454 'title' => ts('Download Batch'),
460 CRM_Core_Action
::COPY
=> array(
461 'name' => ts('Enter records'),
462 'url' => 'civicrm/batch/entry',
463 'qs' => 'id=%%id%%&reset=1',
464 'title' => ts('Batch Data Entry'),
466 CRM_Core_Action
::UPDATE
=> array(
467 'name' => ts('Edit'),
468 'url' => 'civicrm/batch',
469 'qs' => 'action=update&id=%%id%%&reset=1',
470 'title' => ts('Edit Batch'),
472 CRM_Core_Action
::DELETE
=> array(
473 'name' => ts('Delete'),
474 'url' => 'civicrm/batch',
475 'qs' => 'action=delete&id=%%id%%',
476 'title' => ts('Delete Batch'),
484 * function to get batch list
486 * @return array array of batches
488 static function getBatches() {
489 $query = 'SELECT id, title
491 WHERE type_id IN (1,2)
496 $dao = CRM_Core_DAO
::executeQuery($query);
497 while ( $dao->fetch( ) ) {
498 $batches[$dao->id
] = $dao->title
;
506 * Calculate sum of all entries in a batch
507 * Used to validate and update item_count and total when closing an accounting batch
509 * @param array $batchIds
512 static function batchTotals($batchIds) {
513 $totals = array_fill_keys($batchIds, array('item_count' => 0, 'total' => 0));
515 $sql = "SELECT eb.batch_id, COUNT(tx.id) AS item_count, SUM(tx.total_amount) AS total
516 FROM civicrm_entity_batch eb
517 INNER JOIN civicrm_financial_trxn tx ON tx.id = eb.entity_id AND eb.entity_table = 'civicrm_financial_trxn'
518 WHERE eb.batch_id IN (" . implode(',', $batchIds) . ")
519 GROUP BY eb.batch_id";
520 $dao = CRM_Core_DAO
::executeQuery($sql);
521 while ($dao->fetch()) {
522 $totals[$dao->batch_id
] = (array) $dao;
530 * Format markup for comparing two totals
532 * @param $actual: calculated total
533 * @param $expected: user-entered total
536 static function displayTotals($actual, $expected) {
537 $class = 'actual-value';
538 if ($expected && $expected != $actual) {
539 $class .= ' crm-error';
541 $actualTitle = ts('Current Total');
542 $output = "<span class='$class' title='$actualTitle'>$actual</span>";
544 $expectedTitle = ts('Expected Total');
545 $output .= " / <span class='expected-value' title='$expectedTitle'>$expected</span>";
551 * Function for exporting financial accounts, currently we support CSV and IIF format
552 * @see http://wiki.civicrm.org/confluence/display/CRM/CiviAccounts+Specifications+-++Batches#CiviAccountsSpecifications-Batches-%C2%A0Overviewofimplementation
554 * @param array $batchIds associated array of batch ids
555 * @param string $exportFormat export format
562 static function exportFinancialBatch($batchIds, $exportFormat) {
563 if (empty($batchIds)) {
564 CRM_Core_Error
::fatal(ts('No batches were selected.'));
567 if (empty($exportFormat)) {
568 CRM_Core_Error
::fatal(ts('No export format selected.'));
571 self
::$_exportFormat = $exportFormat;
573 // Instantiate appropriate exporter based on user-selected format.
574 $exporterClass = "CRM_Financial_BAO_ExportFormat_" . self
::$_exportFormat;
575 if ( class_exists( $exporterClass ) ) {
576 $exporter = new $exporterClass();
579 CRM_Core_Error
::fatal("Could not locate exporter: $exporterClass");
581 switch (self
::$_exportFormat) {
583 foreach ($batchIds as $batchId) {
584 $export[$batchId] = $exporter->generateExportQuery($batchId);
586 $exporter->makeCSV($export);
590 foreach ($batchIds as $batchId) {
591 $export[$batchId] = $exporter->generateExportQuery($batchId);
593 $exporter->makeIIF($export);
598 static function closeReOpen($batchIds = array(), $status) {
599 $batchStatus = CRM_Core_PseudoConstant
::accountOptionValues( 'batch_status' );
600 $params['status_id'] = CRM_Utils_Array
::key( $status, $batchStatus );
601 $session = CRM_Core_Session
::singleton( );
602 $params['modified_date'] = date('YmdHis');
603 $params['modified_id'] = $session->get( 'userID' );
604 foreach ($batchIds as $key => $value) {
605 $params['id'] = $ids['batchID'] = $value;
606 self
::create($params, $ids);
608 $url = CRM_Utils_System
::url('civicrm/financial/financialbatches',"reset=1&batchStatus={$params['status_id']}");
609 CRM_Utils_System
::redirect($url);
613 * Function to retrieve financial items assigned for a batch
615 * @param int $entityID
616 * @param array $returnValues
617 * @param null $notPresent
618 * @param null $params
621 static function getBatchFinancialItems($entityID, $returnValues, $notPresent = NULL, $params = NULL, $getCount = FALSE) {
623 if (!empty($params['rowCount']) &&
624 $params['rowCount'] > 0
626 $limit = " LIMIT {$params['offset']}, {$params['rowCount']} ";
629 // action is taken depending upon the mode
630 $select = 'civicrm_financial_trxn.id ';
631 if (!empty( $returnValues)) {
632 $select .= " , ".implode(' , ', $returnValues);
635 $orderBy = " ORDER BY civicrm_financial_trxn.id";
636 if (CRM_Utils_Array
::value('sort', $params)) {
637 $orderBy = ' ORDER BY ' . CRM_Utils_Array
::value('sort', $params);
640 $from = "civicrm_financial_trxn
641 LEFT JOIN civicrm_entity_financial_trxn ON civicrm_entity_financial_trxn.financial_trxn_id = civicrm_financial_trxn.id
642 LEFT JOIN civicrm_entity_batch ON civicrm_entity_batch.entity_id = civicrm_financial_trxn.id
643 LEFT JOIN civicrm_contribution ON civicrm_contribution.id = civicrm_entity_financial_trxn.entity_id
644 LEFT JOIN civicrm_financial_type ON civicrm_financial_type.id = civicrm_contribution.financial_type_id
645 LEFT JOIN civicrm_contact contact_a ON contact_a.id = civicrm_contribution.contact_id
646 LEFT JOIN civicrm_contribution_soft ON civicrm_contribution_soft.contribution_id = civicrm_contribution.id
653 'contribution_page_id',
654 'contribution_payment_instrument_id',
655 'contribution_transaction_id',
656 'contribution_source',
657 'contribution_currency_type',
658 'contribution_pay_later',
659 'contribution_recurring',
661 'contribution_thankyou_date_is_not_null',
662 'contribution_receipt_date_is_not_null',
663 'contribution_pcp_made_through_id',
664 'contribution_pcp_display_in_roll',
665 'contribution_date_relative',
666 'contribution_amount_low',
667 'contribution_amount_high',
668 'contribution_in_honor_of',
671 'contribution_date_relative',
672 'contribution_date_high',
673 'contribution_date_low',
674 'contribution_check_number',
675 'contribution_status_id',
678 foreach ($searchFields as $field) {
679 if (isset($params[$field])) {
680 $values[$field] = $params[$field];
681 if ($field == 'sort_name') {
682 $from .= " LEFT JOIN civicrm_contact contact_b ON contact_b.id = civicrm_contribution.contact_id
683 LEFT JOIN civicrm_email ON contact_b.id = civicrm_email.contact_id";
685 if ($field == 'contribution_in_honor_of') {
686 $from .= " LEFT JOIN civicrm_contact contact_b ON contact_b.id = civicrm_contribution.contact_id";
688 if ($field == 'contact_tags') {
689 $from .= " LEFT JOIN civicrm_entity_tag `civicrm_entity_tag-{$params[$field]}` ON `civicrm_entity_tag-{$params[$field]}`.entity_id = contact_a.id";
691 if ($field == 'group') {
692 $from .= " LEFT JOIN civicrm_group_contact `civicrm_group_contact-{$params[$field]}` ON contact_a.id = `civicrm_group_contact-{$params[$field]}`.contact_id ";
694 if ($field == 'contribution_date_relative') {
695 $relativeDate = explode('.', $params[$field]);
696 $date = CRM_Utils_Date
::relativeToAbsolute($relativeDate[0], $relativeDate[1]);
697 $values['contribution_date_low'] = $date['from'];
698 $values['contribution_date_high'] = $date['to'];
700 $searchParams = CRM_Contact_BAO_Query
::convertFormValues($values);
701 $query = new CRM_Contact_BAO_Query($searchParams,
702 CRM_Contribute_BAO_Query
::defaultReturnProperties(CRM_Contact_BAO_Query
::MODE_CONTRIBUTE
,
704 ),NULL, FALSE, FALSE,CRM_Contact_BAO_Query
::MODE_CONTRIBUTE
706 if ($field == 'contribution_date_high' ||
$field == 'contribution_date_low') {
707 $query->dateQueryBuilder($params[$field], 'civicrm_contribution', 'contribution_date', 'receive_date', 'Contribution Date');
711 if (!empty($query->_where
[0])) {
712 $where = implode(' AND ', $query->_where
[0]) .
713 "AND civicrm_entity_batch.batch_id IS NULL
714 AND civicrm_entity_financial_trxn.entity_table = 'civicrm_contribution'";
718 $searchValue = FALSE;
723 $where = " ( civicrm_entity_batch.batch_id = {$entityID}
724 AND civicrm_entity_batch.entity_table = 'civicrm_financial_trxn'
725 AND civicrm_entity_financial_trxn.entity_table = 'civicrm_contribution') ";
728 $where = " ( civicrm_entity_batch.batch_id IS NULL
729 AND civicrm_entity_financial_trxn.entity_table = 'civicrm_contribution')";
744 $result = CRM_Core_DAO
::executeQuery($sql);
749 * function to get batch names
750 * @param string $batchIds
752 * @return array array of batches
754 static function getBatchNames($batchIds) {
755 $query = 'SELECT id, title
757 WHERE id IN ('. $batchIds . ')';
760 $dao = CRM_Core_DAO
::executeQuery($query);
761 while ( $dao->fetch( ) ) {
762 $batches[$dao->id
] = $dao->title
;
768 * Function get batch statuses
770 * @param string $batchIds
772 * @return array array of batches
774 static function getBatchStatuses($batchIds) {
775 $query = 'SELECT id, status_id
777 WHERE id IN ('.$batchIds.')';
780 $dao = CRM_Core_DAO
::executeQuery($query);
781 while ( $dao->fetch( ) ) {
782 $batches[$dao->id
] = $dao->status_id
;