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 | |
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 |
665 | INNER JOIN civicrm_entity_financial_trxn ON civicrm_entity_financial_trxn.financial_trxn_id = civicrm_financial_trxn.id |
666 | INNER 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 |
668 | LEFT JOIN civicrm_entity_batch ON civicrm_entity_batch.entity_table = 'civicrm_financial_trxn' |
669 | AND civicrm_entity_batch.entity_id = civicrm_financial_trxn.id | |
6a488035 TO |
670 | LEFT JOIN civicrm_financial_type ON civicrm_financial_type.id = civicrm_contribution.financial_type_id |
671 | LEFT JOIN civicrm_contact contact_a ON contact_a.id = civicrm_contribution.contact_id | |
672 | LEFT 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 = " |
766 | SELECT {$select} | |
767 | FROM {$from} | |
768 | WHERE {$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 | } |