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