Merge pull request #20530 from eileenmcnaughton/val
[civicrm-core.git] / CRM / Batch / BAO / Batch.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
bc77d7c0 4 | Copyright CiviCRM LLC. All rights reserved. |
6a488035 5 | |
bc77d7c0
TO
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
6a488035
TO
9 +--------------------------------------------------------------------+
10 */
11
12/**
13 *
14 * @package CRM
ca5cec67 15 * @copyright CiviCRM LLC https://civicrm.org/licensing
6a488035
TO
16 */
17
18/**
ce064e4f 19 * Batch BAO class.
6a488035
TO
20 */
21class CRM_Batch_BAO_Batch extends CRM_Batch_DAO_Batch {
22
23 /**
eceb18cc 24 * Cache for the current batch object.
62d3ee27 25 * @var object
6a488035 26 */
62d3ee27 27 public static $_batch = NULL;
6a488035
TO
28
29 /**
30 * Not sure this is the best way to do this. Depends on how exportFinancialBatch() below gets called.
31 * Maybe a parameter to that function is better.
62d3ee27 32 * @var string
6a488035 33 */
62d3ee27 34 public static $_exportFormat = NULL;
6a488035
TO
35
36 /**
eceb18cc 37 * Create a new batch.
6a488035 38 *
82d480a5 39 * @param array $params
6a488035 40 *
a6c01b45
CW
41 * @return object
42 * $batch batch object
f294ab85 43 * @throws \Exception
6a488035 44 */
92e088c9 45 public static function create(&$params) {
0419bf7b 46 if (empty($params['id']) && empty($params['name'])) {
f294ab85 47 $params['name'] = CRM_Utils_String::titleToVar($params['title'] ?? 'batch_ref_' . random_int(0, 100000));
6a488035 48 }
0419bf7b 49 return self::writeRecord($params);
6a488035
TO
50 }
51
52 /**
eceb18cc 53 * Retrieve the information about the batch.
6a488035 54 *
82d480a5
TO
55 * @param array $params
56 * (reference ) an assoc array of name/value pairs.
57 * @param array $defaults
58 * (reference ) an assoc array to hold the flattened values.
6a488035 59 *
a6c01b45
CW
60 * @return array
61 * CRM_Batch_BAO_Batch object on success, null otherwise
6a488035 62 */
00be9182 63 public static function retrieve(&$params, &$defaults) {
6a488035
TO
64 $batch = new CRM_Batch_DAO_Batch();
65 $batch->copyValues($params);
66 if ($batch->find(TRUE)) {
67 CRM_Core_DAO::storeValues($batch, $defaults);
68 return $batch;
69 }
70 return NULL;
71 }
72
73 /**
eceb18cc 74 * Get profile id associated with the batch type.
6a488035 75 *
82d480a5
TO
76 * @param int $batchTypeId
77 * Batch type id.
6a488035 78 *
a6c01b45
CW
79 * @return int
80 * $profileId profile id
6a488035 81 */
00be9182 82 public static function getProfileId($batchTypeId) {
6a488035
TO
83 //retrieve the profile specific to batch type
84 switch ($batchTypeId) {
85 case 1:
9fa00ed1 86 case 3:
87 //batch profile used for pledges
6a488035
TO
88 $profileName = "contribution_batch_entry";
89 break;
90
91 case 2:
92 //batch profile used for memberships
93 $profileName = "membership_batch_entry";
04e6444d 94 break;
6a488035
TO
95 }
96
97 // get and return the profile id
98 return CRM_Core_DAO::getFieldValue('CRM_Core_BAO_UFGroup', $profileName, 'id', 'name');
99 }
100
101 /**
eceb18cc 102 * Generate batch name.
6a488035 103 *
72b3a70c
CW
104 * @return string
105 * batch name
6a488035 106 */
00be9182 107 public static function generateBatchName() {
6a488035
TO
108 $sql = "SELECT max(id) FROM civicrm_batch";
109 $batchNo = CRM_Core_DAO::singleValueQuery($sql) + 1;
be2fb01f 110 return ts('Batch %1', [1 => $batchNo]) . ': ' . date('Y-m-d');
6a488035
TO
111 }
112
6a488035 113 /**
eceb18cc 114 * Delete batch entry.
6a488035 115 *
82d480a5
TO
116 * @param int $batchId
117 * Batch id.
6a488035 118 *
72b3a70c 119 * @return bool
6a488035 120 */
00be9182 121 public static function deleteBatch($batchId) {
6a488035 122 // delete entry from batch table
be12df5a 123 CRM_Utils_Hook::pre('delete', 'Batch', $batchId);
6a488035
TO
124 $batch = new CRM_Batch_DAO_Batch();
125 $batch->id = $batchId;
126 $batch->delete();
8f30d0b9 127 CRM_Utils_Hook::post('delete', 'Batch', $batch->id, $batch);
691df66d 128 return TRUE;
6a488035
TO
129 }
130
6a488035 131 /**
eceb18cc 132 * wrapper for ajax batch selector.
6a488035 133 *
82d480a5
TO
134 * @param array $params
135 * Associated array for params record id.
6a488035 136 *
a6c01b45
CW
137 * @return array
138 * associated array of batch list
6a488035 139 */
3fab79d8 140 public static function getBatchListSelector(&$params) {
6a488035
TO
141 // format the params
142 $params['offset'] = ($params['page'] - 1) * $params['rp'];
143 $params['rowCount'] = $params['rp'];
9c1bc317 144 $params['sort'] = $params['sortBy'] ?? NULL;
6a488035
TO
145
146 // get batches
147 $batches = self::getBatchList($params);
148
149 // get batch totals for open batches
be2fb01f
CW
150 $fetchTotals = [];
151 $batchStatus = CRM_Core_PseudoConstant::get('CRM_Batch_DAO_Batch', 'status_id', ['labelColumn' => 'name']);
152 $batchStatus = [
2d818e4a
PN
153 array_search('Open', $batchStatus),
154 array_search('Reopened', $batchStatus),
be2fb01f 155 ];
6a488035
TO
156 if ($params['context'] == 'financialBatch') {
157 foreach ($batches as $id => $batch) {
2d818e4a 158 if (in_array($batch['status_id'], $batchStatus)) {
6a488035
TO
159 $fetchTotals[] = $id;
160 }
161 }
162 }
163 $totals = self::batchTotals($fetchTotals);
164
165 // add count
166 $params['total'] = self::getBatchCount($params);
167
168 // format params and add links
be2fb01f 169 $batchList = [];
6a488035
TO
170
171 foreach ($batches as $id => $value) {
be2fb01f 172 $batch = [];
6a488035
TO
173 if ($params['context'] == 'financialBatch') {
174 $batch['check'] = $value['check'];
175 }
176 $batch['batch_name'] = $value['title'];
957bbb1d 177 $batch['total'] = '';
6a488035 178 $batch['payment_instrument'] = $value['payment_instrument'];
9c1bc317
CW
179 $batch['item_count'] = $value['item_count'] ?? NULL;
180 $batch['type'] = $value['batch_type'] ?? NULL;
a7488080 181 if (!empty($value['total'])) {
def0f6ae
BS
182 // CRM-21205
183 $batch['total'] = CRM_Utils_Money::format($value['total'], $value['currency']);
6a488035
TO
184 }
185
186 // Compare totals with actuals
187 if (isset($totals[$id])) {
188 $batch['item_count'] = self::displayTotals($totals[$id]['item_count'], $batch['item_count']);
189 $batch['total'] = self::displayTotals(CRM_Utils_Money::format($totals[$id]['total']), $batch['total']);
190 }
191 $batch['status'] = $value['batch_status'];
192 $batch['created_by'] = $value['created_by'];
193 $batch['links'] = $value['action'];
194 $batchList[$id] = $batch;
195 }
196 return $batchList;
197 }
198
199 /**
eceb18cc 200 * Get list of batches.
6a488035 201 *
82d480a5
TO
202 * @param array $params
203 * Associated array for params.
102fe859
EM
204 *
205 * @return array
6a488035 206 */
00be9182 207 public static function getBatchList(&$params) {
857236d0 208 $apiParams = self::whereClause($params);
6a488035
TO
209
210 if (!empty($params['rowCount']) && is_numeric($params['rowCount'])
211 && is_numeric($params['offset']) && $params['rowCount'] > 0
212 ) {
be2fb01f 213 $apiParams['options'] = ['offset' => $params['offset'], 'limit' => $params['rowCount']];
6a488035 214 }
857236d0 215 $apiParams['options']['sort'] = 'id DESC';
6a488035 216 if (!empty($params['sort'])) {
857236d0 217 $apiParams['options']['sort'] = CRM_Utils_Type::escape($params['sort'], 'String');
6a488035
TO
218 }
219
be2fb01f 220 $return = [
857236d0
PN
221 "id",
222 "name",
223 "title",
224 "description",
225 "created_date",
226 "status_id",
227 "modified_id",
228 "modified_date",
229 "type_id",
230 "mode_id",
231 "total",
232 "item_count",
233 "exported_date",
234 "payment_instrument_id",
235 "created_id.sort_name",
236 "created_id",
be2fb01f 237 ];
857236d0
PN
238 $apiParams['return'] = $return;
239 $batches = civicrm_api3('Batch', 'get', $apiParams);
3fab79d8 240 $obj = new CRM_Batch_BAO_Batch();
a7488080 241 if (!empty($params['context'])) {
3fab79d8 242 $links = $obj->links($params['context']);
6a488035
TO
243 }
244 else {
3fab79d8 245 $links = $obj->links();
6a488035
TO
246 }
247
97afa853
AS
248 $batchTypes = CRM_Core_PseudoConstant::get('CRM_Batch_DAO_Batch', 'type_id');
249 $batchStatus = CRM_Core_PseudoConstant::get('CRM_Batch_DAO_Batch', 'status_id');
be2fb01f 250 $batchStatusByName = CRM_Core_PseudoConstant::get('CRM_Batch_DAO_Batch', 'status_id', ['labelColumn' => 'name']);
6a488035
TO
251 $paymentInstrument = CRM_Contribute_PseudoConstant::paymentInstrument();
252
be2fb01f 253 $results = [];
857236d0 254 foreach ($batches['values'] as $values) {
6a488035 255 $newLinks = $links;
6a488035
TO
256 $action = array_sum(array_keys($newLinks));
257
2d818e4a 258 if ($values['status_id'] == array_search('Closed', $batchStatusByName) && $params['context'] != 'financialBatch') {
be2fb01f 259 $newLinks = [];
6a488035
TO
260 }
261 elseif ($params['context'] == 'financialBatch') {
6c552737 262 $values['check'] = "<input type='checkbox' id='check_" .
857236d0 263 $values['id'] .
0b0941e2 264 "' name='check_" .
857236d0 265 $values['id'] .
0b0941e2 266 "' value='1' data-status_id='" .
92fcb95f 267 $values['status_id'] . "' class='select-row'></input>";
6a488035 268
2d818e4a
PN
269 switch ($batchStatusByName[$values['status_id']]) {
270 case 'Open':
ca0e2dda 271 case 'Reopened':
6a488035
TO
272 CRM_Utils_Array::remove($newLinks, 'reopen', 'download');
273 break;
691df66d 274
2d818e4a 275 case 'Closed':
6a488035
TO
276 CRM_Utils_Array::remove($newLinks, 'close', 'edit', 'download');
277 break;
691df66d 278
2d818e4a 279 case 'Exported':
6a488035
TO
280 CRM_Utils_Array::remove($newLinks, 'close', 'edit', 'reopen', 'export');
281 }
ca0e2dda 282 if (!CRM_Batch_BAO_Batch::checkBatchPermission('edit', $values['created_id'])) {
f07fc4c9
PN
283 CRM_Utils_Array::remove($newLinks, 'edit');
284 }
285 if (!CRM_Batch_BAO_Batch::checkBatchPermission('close', $values['created_id'])) {
286 CRM_Utils_Array::remove($newLinks, 'close', 'export');
287 }
288 if (!CRM_Batch_BAO_Batch::checkBatchPermission('reopen', $values['created_id'])) {
289 CRM_Utils_Array::remove($newLinks, 'reopen');
ca0e2dda
PN
290 }
291 if (!CRM_Batch_BAO_Batch::checkBatchPermission('export', $values['created_id'])) {
292 CRM_Utils_Array::remove($newLinks, 'export', 'download');
293 }
294 if (!CRM_Batch_BAO_Batch::checkBatchPermission('delete', $values['created_id'])) {
295 CRM_Utils_Array::remove($newLinks, 'delete');
296 }
6a488035 297 }
a7488080 298 if (!empty($values['type_id'])) {
6a488035
TO
299 $values['batch_type'] = $batchTypes[$values['type_id']];
300 }
301 $values['batch_status'] = $batchStatus[$values['status_id']];
857236d0 302 $values['created_by'] = $values['created_id.sort_name'];
6a488035 303 $values['payment_instrument'] = '';
857236d0
PN
304 if (!empty($values['payment_instrument_id'])) {
305 $values['payment_instrument'] = $paymentInstrument[$values['payment_instrument_id']];
6a488035 306 }
be2fb01f 307 $tokens = ['id' => $values['id'], 'status' => $values['status_id']];
2d818e4a 308 if ($values['status_id'] == array_search('Exported', $batchStatusByName)) {
857236d0 309 $aid = CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Export Accounting Batch');
be2fb01f 310 $activityParams = ['source_record_id' => $values['id'], 'activity_type_id' => $aid];
6a488035 311 $exportActivity = CRM_Activity_BAO_Activity::retrieve($activityParams, $val);
83cab05a
JG
312 if ($exportActivity) {
313 $fid = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_EntityFile', $exportActivity->id, 'file_id', 'entity_id');
314 $fileHash = CRM_Core_BAO_File::generateFileHash($exportActivity->id, $fid);
315 $tokens = array_merge(['eid' => $exportActivity->id, 'fid' => $fid, 'fcs' => $fileHash], $tokens);
316 }
317 else {
318 CRM_Utils_Array::remove($newLinks, 'export', 'download');
319 }
6a488035
TO
320 }
321 $values['action'] = CRM_Core_Action::formLink(
322 $newLinks,
323 $action,
c51d1602 324 $tokens,
87dab4a4
AH
325 ts('more'),
326 FALSE,
327 'batch.selector.row',
328 'Batch',
857236d0 329 $values['id']
6a488035 330 );
def0f6ae
BS
331 // CRM-21205
332 $values['currency'] = CRM_Core_DAO::singleValueQuery("
333 SELECT GROUP_CONCAT(DISTINCT ft.currency)
334 FROM civicrm_batch batch
335 JOIN civicrm_entity_batch eb
336 ON batch.id = eb.batch_id
337 JOIN civicrm_financial_trxn ft
338 ON eb.entity_id = ft.id
339 WHERE batch.id = %1
340 GROUP BY batch.id
be2fb01f 341 ", [1 => [$values['id'], 'Positive']]);
857236d0 342 $results[$values['id']] = $values;
6a488035
TO
343 }
344
345 return $results;
346 }
347
348 /**
eceb18cc 349 * Get count of batches.
6a488035 350 *
82d480a5
TO
351 * @param array $params
352 * Associated array for params.
102fe859
EM
353 *
354 * @return null|string
6a488035 355 */
b11c92be 356 public static function getBatchCount(&$params) {
857236d0
PN
357 $apiParams = self::whereClause($params);
358 return civicrm_api3('Batch', 'getCount', $apiParams);
6a488035
TO
359 }
360
361 /**
eceb18cc 362 * Format where clause for getting lists of batches.
6a488035 363 *
82d480a5
TO
364 * @param array $params
365 * Associated array for params.
102fe859
EM
366 *
367 * @return string
6a488035 368 */
b11c92be 369 public static function whereClause($params) {
be2fb01f 370 $clauses = [];
6a488035 371 // Exclude data-entry batches
be2fb01f 372 $batchStatus = CRM_Core_PseudoConstant::get('CRM_Batch_DAO_Batch', 'status_id', ['labelColumn' => 'name']);
6a488035 373 if (empty($params['status_id'])) {
be2fb01f 374 $clauses['status_id'] = ['NOT IN' => ["Data Entry"]];
6a488035
TO
375 }
376
be2fb01f 377 $return = [
857236d0
PN
378 "id",
379 "name",
380 "title",
381 "description",
382 "created_date",
383 "status_id",
384 "modified_id",
385 "modified_date",
386 "type_id",
387 "mode_id",
388 "total",
389 "item_count",
390 "exported_date",
391 "payment_instrument_id",
392 "created_id.sort_name",
393 "created_id",
be2fb01f 394 ];
d2738983
PN
395 if (!CRM_Core_Permission::check("view all manual batches")) {
396 if (CRM_Core_Permission::check("view own manual batches")) {
397 $loggedInContactId = CRM_Core_Session::singleton()->get('userID');
398 $params['created_id'] = $loggedInContactId;
399 }
400 else {
401 $params['created_id'] = 0;
402 }
403 }
857236d0
PN
404 foreach ($return as $field) {
405 if (!isset($params[$field])) {
406 continue;
407 }
408 $value = CRM_Utils_Type::escape($params[$field], 'String', FALSE);
be2fb01f
CW
409 if (in_array($field, ['name', 'title', 'description', 'created_id.sort_name'])) {
410 $clauses[$field] = ['LIKE' => "%{$value}%"];
857236d0
PN
411 }
412 elseif ($field == 'status_id' && $value == array_search('Open', $batchStatus)) {
be2fb01f 413 $clauses['status_id'] = ['IN' => ["Open", 'Reopened']];
857236d0
PN
414 }
415 else {
416 $clauses[$field] = $value;
6a488035
TO
417 }
418 }
857236d0 419 return $clauses;
6a488035
TO
420 }
421
422 /**
eceb18cc 423 * Define action links.
6a488035 424 *
102fe859
EM
425 * @param null $context
426 *
a6c01b45
CW
427 * @return array
428 * array of action links
6a488035 429 */
00be9182 430 public function links($context = NULL) {
6a488035 431 if ($context == 'financialBatch') {
be2fb01f
CW
432 $links = [
433 'transaction' => [
353ffa53
TO
434 'name' => ts('Transactions'),
435 'url' => 'civicrm/batchtransaction',
436 'qs' => 'reset=1&bid=%%id%%',
6a488035 437 'title' => ts('View/Add Transactions to Batch'),
be2fb01f
CW
438 ],
439 'edit' => [
353ffa53
TO
440 'name' => ts('Edit'),
441 'url' => 'civicrm/financial/batch',
442 'qs' => 'reset=1&action=update&id=%%id%%&context=1',
6a488035 443 'title' => ts('Edit Batch'),
be2fb01f
CW
444 ],
445 'close' => [
353ffa53 446 'name' => ts('Close'),
6a488035 447 'title' => ts('Close Batch'),
353ffa53 448 'url' => '#',
6a488035 449 'extra' => 'rel="close"',
be2fb01f
CW
450 ],
451 'export' => [
353ffa53 452 'name' => ts('Export'),
6a488035 453 'title' => ts('Export Batch'),
10c5467b
JG
454 'url' => 'civicrm/financial/batch/export',
455 'qs' => 'reset=1&id=%%id%%&status=1',
be2fb01f
CW
456 ],
457 'reopen' => [
353ffa53 458 'name' => ts('Re-open'),
6a488035 459 'title' => ts('Re-open Batch'),
353ffa53 460 'url' => '#',
6a488035 461 'extra' => 'rel="reopen"',
be2fb01f
CW
462 ],
463 'delete' => [
353ffa53 464 'name' => ts('Delete'),
6a488035 465 'title' => ts('Delete Batch'),
353ffa53 466 'url' => '#',
6a488035 467 'extra' => 'rel="delete"',
be2fb01f
CW
468 ],
469 'download' => [
353ffa53
TO
470 'name' => ts('Download'),
471 'url' => 'civicrm/file',
ff9aeadb 472 'qs' => 'reset=1&id=%%fid%%&eid=%%eid%%&fcs=%%fcs%%',
6a488035 473 'title' => ts('Download Batch'),
be2fb01f
CW
474 ],
475 ];
6a488035
TO
476 }
477 else {
be2fb01f
CW
478 $links = [
479 CRM_Core_Action::COPY => [
6a488035
TO
480 'name' => ts('Enter records'),
481 'url' => 'civicrm/batch/entry',
482 'qs' => 'id=%%id%%&reset=1',
483 'title' => ts('Batch Data Entry'),
be2fb01f
CW
484 ],
485 CRM_Core_Action::UPDATE => [
6a488035
TO
486 'name' => ts('Edit'),
487 'url' => 'civicrm/batch',
488 'qs' => 'action=update&id=%%id%%&reset=1',
489 'title' => ts('Edit Batch'),
be2fb01f
CW
490 ],
491 CRM_Core_Action::DELETE => [
6a488035
TO
492 'name' => ts('Delete'),
493 'url' => 'civicrm/batch',
494 'qs' => 'action=delete&id=%%id%%',
495 'title' => ts('Delete Batch'),
be2fb01f
CW
496 ],
497 ];
6a488035
TO
498 }
499 return $links;
500 }
501
502 /**
eceb18cc 503 * Get batch list.
6a488035 504 *
a6c01b45 505 * @return array
72b3a70c 506 * all batches excluding batches with data entry in progress
6a488035 507 */
00be9182 508 public static function getBatches() {
a28ce73f 509 $dataEntryStatusId = CRM_Core_PseudoConstant::getKey('CRM_Batch_BAO_Batch', 'status_id', 'Data Entry');
acb4ca2f 510 $query = "SELECT id, title
6a488035 511 FROM civicrm_batch
acb4ca2f
DG
512 WHERE item_count >= 1
513 AND status_id != {$dataEntryStatusId}
433465bc 514 ORDER BY title";
6a488035 515
be2fb01f 516 $batches = [];
6a488035 517 $dao = CRM_Core_DAO::executeQuery($query);
481a74f4 518 while ($dao->fetch()) {
6a488035
TO
519 $batches[$dao->id] = $dao->title;
520 }
521 return $batches;
522 }
523
6a488035 524 /**
eceb18cc 525 * Calculate sum of all entries in a batch.
6a488035
TO
526 * Used to validate and update item_count and total when closing an accounting batch
527 *
528 * @param array $batchIds
529 * @return array
530 */
00be9182 531 public static function batchTotals($batchIds) {
be2fb01f 532 $totals = array_fill_keys($batchIds, ['item_count' => 0, 'total' => 0]);
6a488035
TO
533 if ($batchIds) {
534 $sql = "SELECT eb.batch_id, COUNT(tx.id) AS item_count, SUM(tx.total_amount) AS total
535 FROM civicrm_entity_batch eb
536 INNER JOIN civicrm_financial_trxn tx ON tx.id = eb.entity_id AND eb.entity_table = 'civicrm_financial_trxn'
537 WHERE eb.batch_id IN (" . implode(',', $batchIds) . ")
538 GROUP BY eb.batch_id";
539 $dao = CRM_Core_DAO::executeQuery($sql);
540 while ($dao->fetch()) {
541 $totals[$dao->batch_id] = (array) $dao;
542 }
6a488035
TO
543 }
544 return $totals;
545 }
546
547 /**
eceb18cc 548 * Format markup for comparing two totals.
6a488035 549 *
72b3a70c
CW
550 * @param $actual
551 * calculated total
552 * @param $expected
553 * user-entered total
6a488035
TO
554 * @return array
555 */
00be9182 556 public static function displayTotals($actual, $expected) {
6a488035
TO
557 $class = 'actual-value';
558 if ($expected && $expected != $actual) {
559 $class .= ' crm-error';
560 }
561 $actualTitle = ts('Current Total');
562 $output = "<span class='$class' title='$actualTitle'>$actual</span>";
563 if ($expected) {
564 $expectedTitle = ts('Expected Total');
565 $output .= " / <span class='expected-value' title='$expectedTitle'>$expected</span>";
566 }
567 return $output;
568 }
569
570 /**
571 * Function for exporting financial accounts, currently we support CSV and IIF format
572 * @see http://wiki.civicrm.org/confluence/display/CRM/CiviAccounts+Specifications+-++Batches#CiviAccountsSpecifications-Batches-%C2%A0Overviewofimplementation
573 *
82d480a5
TO
574 * @param array $batchIds
575 * Associated array of batch ids.
576 * @param string $exportFormat
577 * Export format.
f3d529fc
PN
578 * @param bool $downloadFile
579 * Download export file?.
6a488035 580 */
f3d529fc 581 public static function exportFinancialBatch($batchIds, $exportFormat, $downloadFile) {
6a488035 582 if (empty($batchIds)) {
4cf017d1 583 throw new CRM_Core_Exception(ts('No batches were selected.'));
6a488035
TO
584 }
585 if (empty($exportFormat)) {
4cf017d1 586 throw new CRM_Core_Exception(ts('No export format selected.'));
6a488035
TO
587 }
588 self::$_exportFormat = $exportFormat;
589
590 // Instantiate appropriate exporter based on user-selected format.
591 $exporterClass = "CRM_Financial_BAO_ExportFormat_" . self::$_exportFormat;
481a74f4 592 if (class_exists($exporterClass)) {
6a488035
TO
593 $exporter = new $exporterClass();
594 }
595 else {
4cf017d1 596 throw new CRM_Core_Exception("Could not locate exporter: $exporterClass");
6a488035 597 }
be2fb01f 598 $export = [];
f3d529fc 599 $exporter->_isDownloadFile = $downloadFile;
9b05de29 600 foreach ($batchIds as $batchId) {
f091b037 601 // export only batches whose status is set to Exported.
be2fb01f 602 $result = civicrm_api3('Batch', 'getcount', [
f091b037
PN
603 'id' => $batchId,
604 'status_id' => "Exported",
be2fb01f 605 ]);
f091b037
PN
606 if (!$result) {
607 continue;
608 }
9b05de29 609 $export[$batchId] = $exporter->generateExportQuery($batchId);
6a488035 610 }
f091b037
PN
611 if ($export) {
612 $exporter->makeExport($export);
613 }
6a488035
TO
614 }
615
e0ef6999
EM
616 /**
617 * @param array $batchIds
618 * @param $status
619 */
cf348a5e 620 public static function closeReOpen($batchIds, $status) {
f0ebbc90 621 $batchStatus = CRM_Core_PseudoConstant::get('CRM_Batch_DAO_Batch', 'status_id');
481a74f4
TO
622 $params['status_id'] = CRM_Utils_Array::key($status, $batchStatus);
623 $session = CRM_Core_Session::singleton();
6a488035 624 $params['modified_date'] = date('YmdHis');
481a74f4 625 $params['modified_id'] = $session->get('userID');
6a488035
TO
626 foreach ($batchIds as $key => $value) {
627 $params['id'] = $ids['batchID'] = $value;
628 self::create($params, $ids);
629 }
691df66d 630 $url = CRM_Utils_System::url('civicrm/financial/financialbatches', "reset=1&batchStatus={$params['status_id']}");
6a488035
TO
631 CRM_Utils_System::redirect($url);
632 }
633
634 /**
eceb18cc 635 * Retrieve financial items assigned for a batch.
6a488035
TO
636 *
637 * @param int $entityID
638 * @param array $returnValues
72b3a70c 639 * @param bool $notPresent
100fef9d 640 * @param array $params
102fe859
EM
641 * @param bool $getCount
642 *
72b3a70c 643 * @return CRM_Core_DAO
6a488035 644 */
00be9182 645 public static function getBatchFinancialItems($entityID, $returnValues, $notPresent = NULL, $params = NULL, $getCount = FALSE) {
6a488035
TO
646 if (!$getCount) {
647 if (!empty($params['rowCount']) &&
648 $params['rowCount'] > 0
649 ) {
650 $limit = " LIMIT {$params['offset']}, {$params['rowCount']} ";
651 }
652 }
653 // action is taken depending upon the mode
654 $select = 'civicrm_financial_trxn.id ';
481a74f4 655 if (!empty($returnValues)) {
92fcb95f 656 $select .= " , " . implode(' , ', $returnValues);
6a488035
TO
657 }
658
659 $orderBy = " ORDER BY civicrm_financial_trxn.id";
21d32567
DL
660 if (!empty($params['sort'])) {
661 $orderBy = ' ORDER BY ' . CRM_Utils_Type::escape($params['sort'], 'String');
6a488035
TO
662 }
663
664 $from = "civicrm_financial_trxn
c4b067f6
PN
665INNER JOIN civicrm_entity_financial_trxn ON civicrm_entity_financial_trxn.financial_trxn_id = civicrm_financial_trxn.id
666INNER JOIN civicrm_contribution ON (civicrm_contribution.id = civicrm_entity_financial_trxn.entity_id
667 AND civicrm_entity_financial_trxn.entity_table='civicrm_contribution')
cc55c603
DG
668LEFT JOIN civicrm_entity_batch ON civicrm_entity_batch.entity_table = 'civicrm_financial_trxn'
669AND civicrm_entity_batch.entity_id = civicrm_financial_trxn.id
6a488035
TO
670LEFT JOIN civicrm_financial_type ON civicrm_financial_type.id = civicrm_contribution.financial_type_id
671LEFT JOIN civicrm_contact contact_a ON contact_a.id = civicrm_contribution.contact_id
672LEFT JOIN civicrm_contribution_soft ON civicrm_contribution_soft.contribution_id = civicrm_contribution.id
673";
674
be2fb01f 675 $searchFields = [
6c552737
TO
676 'sort_name',
677 'financial_type_id',
678 'contribution_page_id',
5712c3b9 679 'contribution_payment_instrument_id',
30d46f2f 680 'contribution_trxn_id',
6c552737
TO
681 'contribution_source',
682 'contribution_currency_type',
683 'contribution_pay_later',
684 'contribution_recurring',
685 'contribution_test',
686 'contribution_thankyou_date_is_not_null',
687 'contribution_receipt_date_is_not_null',
688 'contribution_pcp_made_through_id',
689 'contribution_pcp_display_in_roll',
6c552737
TO
690 'contribution_amount_low',
691 'contribution_amount_high',
692 'contribution_in_honor_of',
693 'contact_tags',
694 'group',
5d7e6440
SL
695 'receive_date_relative',
696 'receive_date_high',
697 'receive_date_low',
6c552737
TO
698 'contribution_check_number',
699 'contribution_status_id',
eb71b3f2 700 'financial_trxn_card_type_id',
701 'financial_trxn_pan_truncation',
be2fb01f
CW
702 ];
703 $values = [];
6a488035
TO
704 foreach ($searchFields as $field) {
705 if (isset($params[$field])) {
706 $values[$field] = $params[$field];
707 if ($field == 'sort_name') {
708 $from .= " LEFT JOIN civicrm_contact contact_b ON contact_b.id = civicrm_contribution.contact_id
709 LEFT JOIN civicrm_email ON contact_b.id = civicrm_email.contact_id";
710 }
711 if ($field == 'contribution_in_honor_of') {
712 $from .= " LEFT JOIN civicrm_contact contact_b ON contact_b.id = civicrm_contribution.contact_id";
713 }
714 if ($field == 'contact_tags') {
715 $from .= " LEFT JOIN civicrm_entity_tag `civicrm_entity_tag-{$params[$field]}` ON `civicrm_entity_tag-{$params[$field]}`.entity_id = contact_a.id";
716 }
717 if ($field == 'group') {
718 $from .= " LEFT JOIN civicrm_group_contact `civicrm_group_contact-{$params[$field]}` ON contact_a.id = `civicrm_group_contact-{$params[$field]}`.contact_id ";
719 }
5d7e6440 720 if ($field == 'receive_date_relative') {
6a488035
TO
721 $relativeDate = explode('.', $params[$field]);
722 $date = CRM_Utils_Date::relativeToAbsolute($relativeDate[0], $relativeDate[1]);
5d7e6440
SL
723 $values['receive_date_low'] = $date['from'];
724 $values['receive_date_high'] = $date['to'];
6a488035 725 }
6a488035
TO
726 }
727 }
639e74e5 728
977196f2
PN
729 $searchParams = CRM_Contact_BAO_Query::convertFormValues(
730 $values,
731 0,
732 FALSE,
733 NULL,
734 [
735 'financial_type_id',
736 'contribution_soft_credit_type_id',
737 'contribution_status_id',
738 'contribution_page_id',
739 'financial_trxn_card_type_id',
740 'contribution_payment_instrument_id',
741 ]
742 );
639e74e5
PN
743 // @todo the use of defaultReturnProperties means the search will be inefficient
744 // as slow-unneeded properties are included.
745 $query = new CRM_Contact_BAO_Query($searchParams,
746 CRM_Contribute_BAO_Query::defaultReturnProperties(CRM_Contact_BAO_Query::MODE_CONTRIBUTE,
747 FALSE
748 ), NULL, FALSE, FALSE, CRM_Contact_BAO_Query::MODE_CONTRIBUTE
749 );
750
6a488035 751 if (!empty($query->_where[0])) {
0b0941e2 752 $where = implode(' AND ', $query->_where[0]) .
c4b067f6 753 " AND civicrm_entity_batch.batch_id IS NULL ";
30d46f2f 754 $where = str_replace('civicrm_contribution.payment_instrument_id', 'civicrm_financial_trxn.payment_instrument_id', $where);
6a488035
TO
755 }
756 else {
6a488035 757 if (!$notPresent) {
c4b067f6 758 $where = " civicrm_entity_batch.batch_id = {$entityID} ";
6a488035
TO
759 }
760 else {
c4b067f6 761 $where = " civicrm_entity_batch.batch_id IS NULL ";
6a488035
TO
762 }
763 }
764
0b0941e2
DL
765 $sql = "
766SELECT {$select}
767FROM {$from}
768WHERE {$where}
769 {$orderBy}
6a488035
TO
770";
771
772 if (isset($limit)) {
773 $sql .= "{$limit}";
774 }
775
776 $result = CRM_Core_DAO::executeQuery($sql);
777 return $result;
778 }
779
780 /**
eceb18cc 781 * Get batch names.
6a488035
TO
782 * @param string $batchIds
783 *
a6c01b45
CW
784 * @return array
785 * array of batches
6a488035 786 */
00be9182 787 public static function getBatchNames($batchIds) {
6a488035
TO
788 $query = 'SELECT id, title
789 FROM civicrm_batch
86bfa4f6 790 WHERE id IN (' . $batchIds . ')';
6a488035 791
be2fb01f 792 $batches = [];
6a488035 793 $dao = CRM_Core_DAO::executeQuery($query);
481a74f4 794 while ($dao->fetch()) {
6a488035
TO
795 $batches[$dao->id] = $dao->title;
796 }
797 return $batches;
798 }
799
800 /**
eceb18cc 801 * Function get batch statuses.
6a488035
TO
802 *
803 * @param string $batchIds
804 *
a6c01b45
CW
805 * @return array
806 * array of batches
6a488035 807 */
00be9182 808 public static function getBatchStatuses($batchIds) {
6a488035
TO
809 $query = 'SELECT id, status_id
810 FROM civicrm_batch
92fcb95f 811 WHERE id IN (' . $batchIds . ')';
6a488035 812
be2fb01f 813 $batches = [];
6a488035 814 $dao = CRM_Core_DAO::executeQuery($query);
481a74f4 815 while ($dao->fetch()) {
6a488035
TO
816 $batches[$dao->id] = $dao->status_id;
817 }
818 return $batches;
819 }
96025800 820
ca0e2dda
PN
821 /**
822 * Function to check permission for batch.
823 *
824 * @param string $action
825 * @param int $batchCreatedId
826 * batch created by contact id
827 *
828 * @return bool
829 */
830 public static function checkBatchPermission($action, $batchCreatedId = NULL) {
ca0e2dda
PN
831 if (CRM_Core_Permission::check("{$action} all manual batches")) {
832 return TRUE;
833 }
834 if (CRM_Core_Permission::check("{$action} own manual batches")) {
835 $loggedInContactId = CRM_Core_Session::singleton()->get('userID');
836 if ($batchCreatedId == $loggedInContactId) {
837 return TRUE;
838 }
839 elseif (CRM_Utils_System::isNull($batchCreatedId)) {
840 return TRUE;
841 }
842 }
843 return FALSE;
844 }
845
6a488035 846}