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 | 331 | // CRM-21205 |
df33c0cd | 332 | $values['currency'] = CRM_Batch_BAO_EntityBatch::getBatchCurrency($values['id']); |
857236d0 | 333 | $results[$values['id']] = $values; |
6a488035 TO |
334 | } |
335 | ||
336 | return $results; | |
337 | } | |
338 | ||
339 | /** | |
eceb18cc | 340 | * Get count of batches. |
6a488035 | 341 | * |
82d480a5 TO |
342 | * @param array $params |
343 | * Associated array for params. | |
102fe859 EM |
344 | * |
345 | * @return null|string | |
6a488035 | 346 | */ |
b11c92be | 347 | public static function getBatchCount(&$params) { |
857236d0 PN |
348 | $apiParams = self::whereClause($params); |
349 | return civicrm_api3('Batch', 'getCount', $apiParams); | |
6a488035 TO |
350 | } |
351 | ||
352 | /** | |
eceb18cc | 353 | * Format where clause for getting lists of batches. |
6a488035 | 354 | * |
82d480a5 TO |
355 | * @param array $params |
356 | * Associated array for params. | |
102fe859 EM |
357 | * |
358 | * @return string | |
6a488035 | 359 | */ |
b11c92be | 360 | public static function whereClause($params) { |
be2fb01f | 361 | $clauses = []; |
6a488035 | 362 | // Exclude data-entry batches |
be2fb01f | 363 | $batchStatus = CRM_Core_PseudoConstant::get('CRM_Batch_DAO_Batch', 'status_id', ['labelColumn' => 'name']); |
6a488035 | 364 | if (empty($params['status_id'])) { |
be2fb01f | 365 | $clauses['status_id'] = ['NOT IN' => ["Data Entry"]]; |
6a488035 TO |
366 | } |
367 | ||
be2fb01f | 368 | $return = [ |
857236d0 PN |
369 | "id", |
370 | "name", | |
371 | "title", | |
372 | "description", | |
373 | "created_date", | |
374 | "status_id", | |
375 | "modified_id", | |
376 | "modified_date", | |
377 | "type_id", | |
378 | "mode_id", | |
379 | "total", | |
380 | "item_count", | |
381 | "exported_date", | |
382 | "payment_instrument_id", | |
383 | "created_id.sort_name", | |
384 | "created_id", | |
be2fb01f | 385 | ]; |
d2738983 PN |
386 | if (!CRM_Core_Permission::check("view all manual batches")) { |
387 | if (CRM_Core_Permission::check("view own manual batches")) { | |
388 | $loggedInContactId = CRM_Core_Session::singleton()->get('userID'); | |
389 | $params['created_id'] = $loggedInContactId; | |
390 | } | |
391 | else { | |
392 | $params['created_id'] = 0; | |
393 | } | |
394 | } | |
857236d0 PN |
395 | foreach ($return as $field) { |
396 | if (!isset($params[$field])) { | |
397 | continue; | |
398 | } | |
399 | $value = CRM_Utils_Type::escape($params[$field], 'String', FALSE); | |
be2fb01f CW |
400 | if (in_array($field, ['name', 'title', 'description', 'created_id.sort_name'])) { |
401 | $clauses[$field] = ['LIKE' => "%{$value}%"]; | |
857236d0 PN |
402 | } |
403 | elseif ($field == 'status_id' && $value == array_search('Open', $batchStatus)) { | |
be2fb01f | 404 | $clauses['status_id'] = ['IN' => ["Open", 'Reopened']]; |
857236d0 PN |
405 | } |
406 | else { | |
407 | $clauses[$field] = $value; | |
6a488035 TO |
408 | } |
409 | } | |
857236d0 | 410 | return $clauses; |
6a488035 TO |
411 | } |
412 | ||
413 | /** | |
eceb18cc | 414 | * Define action links. |
6a488035 | 415 | * |
102fe859 EM |
416 | * @param null $context |
417 | * | |
a6c01b45 CW |
418 | * @return array |
419 | * array of action links | |
6a488035 | 420 | */ |
00be9182 | 421 | public function links($context = NULL) { |
6a488035 | 422 | if ($context == 'financialBatch') { |
be2fb01f CW |
423 | $links = [ |
424 | 'transaction' => [ | |
353ffa53 TO |
425 | 'name' => ts('Transactions'), |
426 | 'url' => 'civicrm/batchtransaction', | |
427 | 'qs' => 'reset=1&bid=%%id%%', | |
6a488035 | 428 | 'title' => ts('View/Add Transactions to Batch'), |
be2fb01f CW |
429 | ], |
430 | 'edit' => [ | |
353ffa53 TO |
431 | 'name' => ts('Edit'), |
432 | 'url' => 'civicrm/financial/batch', | |
433 | 'qs' => 'reset=1&action=update&id=%%id%%&context=1', | |
6a488035 | 434 | 'title' => ts('Edit Batch'), |
be2fb01f CW |
435 | ], |
436 | 'close' => [ | |
353ffa53 | 437 | 'name' => ts('Close'), |
6a488035 | 438 | 'title' => ts('Close Batch'), |
353ffa53 | 439 | 'url' => '#', |
6a488035 | 440 | 'extra' => 'rel="close"', |
be2fb01f CW |
441 | ], |
442 | 'export' => [ | |
353ffa53 | 443 | 'name' => ts('Export'), |
6a488035 | 444 | 'title' => ts('Export Batch'), |
10c5467b JG |
445 | 'url' => 'civicrm/financial/batch/export', |
446 | 'qs' => 'reset=1&id=%%id%%&status=1', | |
be2fb01f CW |
447 | ], |
448 | 'reopen' => [ | |
353ffa53 | 449 | 'name' => ts('Re-open'), |
6a488035 | 450 | 'title' => ts('Re-open Batch'), |
353ffa53 | 451 | 'url' => '#', |
6a488035 | 452 | 'extra' => 'rel="reopen"', |
be2fb01f CW |
453 | ], |
454 | 'delete' => [ | |
353ffa53 | 455 | 'name' => ts('Delete'), |
6a488035 | 456 | 'title' => ts('Delete Batch'), |
353ffa53 | 457 | 'url' => '#', |
6a488035 | 458 | 'extra' => 'rel="delete"', |
be2fb01f CW |
459 | ], |
460 | 'download' => [ | |
353ffa53 TO |
461 | 'name' => ts('Download'), |
462 | 'url' => 'civicrm/file', | |
ff9aeadb | 463 | 'qs' => 'reset=1&id=%%fid%%&eid=%%eid%%&fcs=%%fcs%%', |
6a488035 | 464 | 'title' => ts('Download Batch'), |
be2fb01f CW |
465 | ], |
466 | ]; | |
6a488035 TO |
467 | } |
468 | else { | |
be2fb01f CW |
469 | $links = [ |
470 | CRM_Core_Action::COPY => [ | |
6a488035 TO |
471 | 'name' => ts('Enter records'), |
472 | 'url' => 'civicrm/batch/entry', | |
473 | 'qs' => 'id=%%id%%&reset=1', | |
474 | 'title' => ts('Batch Data Entry'), | |
be2fb01f CW |
475 | ], |
476 | CRM_Core_Action::UPDATE => [ | |
6a488035 TO |
477 | 'name' => ts('Edit'), |
478 | 'url' => 'civicrm/batch', | |
479 | 'qs' => 'action=update&id=%%id%%&reset=1', | |
480 | 'title' => ts('Edit Batch'), | |
be2fb01f CW |
481 | ], |
482 | CRM_Core_Action::DELETE => [ | |
6a488035 TO |
483 | 'name' => ts('Delete'), |
484 | 'url' => 'civicrm/batch', | |
485 | 'qs' => 'action=delete&id=%%id%%', | |
486 | 'title' => ts('Delete Batch'), | |
be2fb01f CW |
487 | ], |
488 | ]; | |
6a488035 TO |
489 | } |
490 | return $links; | |
491 | } | |
492 | ||
493 | /** | |
eceb18cc | 494 | * Get batch list. |
6a488035 | 495 | * |
a6c01b45 | 496 | * @return array |
72b3a70c | 497 | * all batches excluding batches with data entry in progress |
6a488035 | 498 | */ |
00be9182 | 499 | public static function getBatches() { |
a28ce73f | 500 | $dataEntryStatusId = CRM_Core_PseudoConstant::getKey('CRM_Batch_BAO_Batch', 'status_id', 'Data Entry'); |
acb4ca2f | 501 | $query = "SELECT id, title |
6a488035 | 502 | FROM civicrm_batch |
acb4ca2f DG |
503 | WHERE item_count >= 1 |
504 | AND status_id != {$dataEntryStatusId} | |
433465bc | 505 | ORDER BY title"; |
6a488035 | 506 | |
be2fb01f | 507 | $batches = []; |
6a488035 | 508 | $dao = CRM_Core_DAO::executeQuery($query); |
481a74f4 | 509 | while ($dao->fetch()) { |
6a488035 TO |
510 | $batches[$dao->id] = $dao->title; |
511 | } | |
512 | return $batches; | |
513 | } | |
514 | ||
6a488035 | 515 | /** |
eceb18cc | 516 | * Calculate sum of all entries in a batch. |
6a488035 TO |
517 | * Used to validate and update item_count and total when closing an accounting batch |
518 | * | |
519 | * @param array $batchIds | |
520 | * @return array | |
521 | */ | |
00be9182 | 522 | public static function batchTotals($batchIds) { |
be2fb01f | 523 | $totals = array_fill_keys($batchIds, ['item_count' => 0, 'total' => 0]); |
6a488035 TO |
524 | if ($batchIds) { |
525 | $sql = "SELECT eb.batch_id, COUNT(tx.id) AS item_count, SUM(tx.total_amount) AS total | |
526 | FROM civicrm_entity_batch eb | |
527 | INNER JOIN civicrm_financial_trxn tx ON tx.id = eb.entity_id AND eb.entity_table = 'civicrm_financial_trxn' | |
528 | WHERE eb.batch_id IN (" . implode(',', $batchIds) . ") | |
529 | GROUP BY eb.batch_id"; | |
530 | $dao = CRM_Core_DAO::executeQuery($sql); | |
531 | while ($dao->fetch()) { | |
532 | $totals[$dao->batch_id] = (array) $dao; | |
533 | } | |
6a488035 TO |
534 | } |
535 | return $totals; | |
536 | } | |
537 | ||
538 | /** | |
eceb18cc | 539 | * Format markup for comparing two totals. |
6a488035 | 540 | * |
72b3a70c CW |
541 | * @param $actual |
542 | * calculated total | |
543 | * @param $expected | |
544 | * user-entered total | |
6a488035 TO |
545 | * @return array |
546 | */ | |
00be9182 | 547 | public static function displayTotals($actual, $expected) { |
6a488035 TO |
548 | $class = 'actual-value'; |
549 | if ($expected && $expected != $actual) { | |
550 | $class .= ' crm-error'; | |
551 | } | |
552 | $actualTitle = ts('Current Total'); | |
553 | $output = "<span class='$class' title='$actualTitle'>$actual</span>"; | |
554 | if ($expected) { | |
555 | $expectedTitle = ts('Expected Total'); | |
556 | $output .= " / <span class='expected-value' title='$expectedTitle'>$expected</span>"; | |
557 | } | |
558 | return $output; | |
559 | } | |
560 | ||
561 | /** | |
562 | * Function for exporting financial accounts, currently we support CSV and IIF format | |
563 | * @see http://wiki.civicrm.org/confluence/display/CRM/CiviAccounts+Specifications+-++Batches#CiviAccountsSpecifications-Batches-%C2%A0Overviewofimplementation | |
564 | * | |
82d480a5 TO |
565 | * @param array $batchIds |
566 | * Associated array of batch ids. | |
567 | * @param string $exportFormat | |
568 | * Export format. | |
f3d529fc PN |
569 | * @param bool $downloadFile |
570 | * Download export file?. | |
6a488035 | 571 | */ |
f3d529fc | 572 | public static function exportFinancialBatch($batchIds, $exportFormat, $downloadFile) { |
6a488035 | 573 | if (empty($batchIds)) { |
4cf017d1 | 574 | throw new CRM_Core_Exception(ts('No batches were selected.')); |
6a488035 TO |
575 | } |
576 | if (empty($exportFormat)) { | |
4cf017d1 | 577 | throw new CRM_Core_Exception(ts('No export format selected.')); |
6a488035 TO |
578 | } |
579 | self::$_exportFormat = $exportFormat; | |
580 | ||
581 | // Instantiate appropriate exporter based on user-selected format. | |
582 | $exporterClass = "CRM_Financial_BAO_ExportFormat_" . self::$_exportFormat; | |
481a74f4 | 583 | if (class_exists($exporterClass)) { |
6a488035 TO |
584 | $exporter = new $exporterClass(); |
585 | } | |
586 | else { | |
4cf017d1 | 587 | throw new CRM_Core_Exception("Could not locate exporter: $exporterClass"); |
6a488035 | 588 | } |
be2fb01f | 589 | $export = []; |
f3d529fc | 590 | $exporter->_isDownloadFile = $downloadFile; |
9b05de29 | 591 | foreach ($batchIds as $batchId) { |
f091b037 | 592 | // export only batches whose status is set to Exported. |
be2fb01f | 593 | $result = civicrm_api3('Batch', 'getcount', [ |
f091b037 PN |
594 | 'id' => $batchId, |
595 | 'status_id' => "Exported", | |
be2fb01f | 596 | ]); |
f091b037 PN |
597 | if (!$result) { |
598 | continue; | |
599 | } | |
9b05de29 | 600 | $export[$batchId] = $exporter->generateExportQuery($batchId); |
6a488035 | 601 | } |
f091b037 PN |
602 | if ($export) { |
603 | $exporter->makeExport($export); | |
604 | } | |
6a488035 TO |
605 | } |
606 | ||
e0ef6999 EM |
607 | /** |
608 | * @param array $batchIds | |
609 | * @param $status | |
610 | */ | |
cf348a5e | 611 | public static function closeReOpen($batchIds, $status) { |
f0ebbc90 | 612 | $batchStatus = CRM_Core_PseudoConstant::get('CRM_Batch_DAO_Batch', 'status_id'); |
481a74f4 TO |
613 | $params['status_id'] = CRM_Utils_Array::key($status, $batchStatus); |
614 | $session = CRM_Core_Session::singleton(); | |
6a488035 | 615 | $params['modified_date'] = date('YmdHis'); |
481a74f4 | 616 | $params['modified_id'] = $session->get('userID'); |
6a488035 TO |
617 | foreach ($batchIds as $key => $value) { |
618 | $params['id'] = $ids['batchID'] = $value; | |
619 | self::create($params, $ids); | |
620 | } | |
691df66d | 621 | $url = CRM_Utils_System::url('civicrm/financial/financialbatches', "reset=1&batchStatus={$params['status_id']}"); |
6a488035 TO |
622 | CRM_Utils_System::redirect($url); |
623 | } | |
624 | ||
625 | /** | |
eceb18cc | 626 | * Retrieve financial items assigned for a batch. |
6a488035 TO |
627 | * |
628 | * @param int $entityID | |
629 | * @param array $returnValues | |
72b3a70c | 630 | * @param bool $notPresent |
100fef9d | 631 | * @param array $params |
102fe859 EM |
632 | * @param bool $getCount |
633 | * | |
72b3a70c | 634 | * @return CRM_Core_DAO |
6a488035 | 635 | */ |
00be9182 | 636 | public static function getBatchFinancialItems($entityID, $returnValues, $notPresent = NULL, $params = NULL, $getCount = FALSE) { |
6a488035 TO |
637 | if (!$getCount) { |
638 | if (!empty($params['rowCount']) && | |
639 | $params['rowCount'] > 0 | |
640 | ) { | |
641 | $limit = " LIMIT {$params['offset']}, {$params['rowCount']} "; | |
642 | } | |
643 | } | |
644 | // action is taken depending upon the mode | |
645 | $select = 'civicrm_financial_trxn.id '; | |
481a74f4 | 646 | if (!empty($returnValues)) { |
92fcb95f | 647 | $select .= " , " . implode(' , ', $returnValues); |
6a488035 TO |
648 | } |
649 | ||
650 | $orderBy = " ORDER BY civicrm_financial_trxn.id"; | |
21d32567 DL |
651 | if (!empty($params['sort'])) { |
652 | $orderBy = ' ORDER BY ' . CRM_Utils_Type::escape($params['sort'], 'String'); | |
6a488035 TO |
653 | } |
654 | ||
655 | $from = "civicrm_financial_trxn | |
c4b067f6 PN |
656 | INNER JOIN civicrm_entity_financial_trxn ON civicrm_entity_financial_trxn.financial_trxn_id = civicrm_financial_trxn.id |
657 | INNER JOIN civicrm_contribution ON (civicrm_contribution.id = civicrm_entity_financial_trxn.entity_id | |
658 | AND civicrm_entity_financial_trxn.entity_table='civicrm_contribution') | |
cc55c603 DG |
659 | LEFT JOIN civicrm_entity_batch ON civicrm_entity_batch.entity_table = 'civicrm_financial_trxn' |
660 | AND civicrm_entity_batch.entity_id = civicrm_financial_trxn.id | |
6a488035 TO |
661 | LEFT JOIN civicrm_financial_type ON civicrm_financial_type.id = civicrm_contribution.financial_type_id |
662 | LEFT JOIN civicrm_contact contact_a ON contact_a.id = civicrm_contribution.contact_id | |
663 | LEFT JOIN civicrm_contribution_soft ON civicrm_contribution_soft.contribution_id = civicrm_contribution.id | |
664 | "; | |
665 | ||
be2fb01f | 666 | $searchFields = [ |
6c552737 TO |
667 | 'sort_name', |
668 | 'financial_type_id', | |
669 | 'contribution_page_id', | |
5712c3b9 | 670 | 'contribution_payment_instrument_id', |
30d46f2f | 671 | 'contribution_trxn_id', |
6c552737 TO |
672 | 'contribution_source', |
673 | 'contribution_currency_type', | |
674 | 'contribution_pay_later', | |
675 | 'contribution_recurring', | |
676 | 'contribution_test', | |
677 | 'contribution_thankyou_date_is_not_null', | |
678 | 'contribution_receipt_date_is_not_null', | |
679 | 'contribution_pcp_made_through_id', | |
680 | 'contribution_pcp_display_in_roll', | |
6c552737 TO |
681 | 'contribution_amount_low', |
682 | 'contribution_amount_high', | |
683 | 'contribution_in_honor_of', | |
684 | 'contact_tags', | |
685 | 'group', | |
5d7e6440 SL |
686 | 'receive_date_relative', |
687 | 'receive_date_high', | |
688 | 'receive_date_low', | |
6c552737 TO |
689 | 'contribution_check_number', |
690 | 'contribution_status_id', | |
eb71b3f2 | 691 | 'financial_trxn_card_type_id', |
692 | 'financial_trxn_pan_truncation', | |
be2fb01f | 693 | ]; |
bf374fbe DM |
694 | $values = $customJoins = []; |
695 | ||
696 | // If a custom field was passed as a param, | |
697 | // we'll take it into account. | |
698 | $customSearchFields = []; | |
699 | if (!empty($params)) { | |
700 | foreach ($params as $name => $param) { | |
701 | if (substr($name, 0, 6) == 'custom') { | |
702 | $searchFields[] = $name; | |
703 | } | |
704 | } | |
705 | } | |
706 | ||
6a488035 TO |
707 | foreach ($searchFields as $field) { |
708 | if (isset($params[$field])) { | |
709 | $values[$field] = $params[$field]; | |
710 | if ($field == 'sort_name') { | |
711 | $from .= " LEFT JOIN civicrm_contact contact_b ON contact_b.id = civicrm_contribution.contact_id | |
712 | LEFT JOIN civicrm_email ON contact_b.id = civicrm_email.contact_id"; | |
713 | } | |
714 | if ($field == 'contribution_in_honor_of') { | |
715 | $from .= " LEFT JOIN civicrm_contact contact_b ON contact_b.id = civicrm_contribution.contact_id"; | |
716 | } | |
717 | if ($field == 'contact_tags') { | |
718 | $from .= " LEFT JOIN civicrm_entity_tag `civicrm_entity_tag-{$params[$field]}` ON `civicrm_entity_tag-{$params[$field]}`.entity_id = contact_a.id"; | |
719 | } | |
720 | if ($field == 'group') { | |
721 | $from .= " LEFT JOIN civicrm_group_contact `civicrm_group_contact-{$params[$field]}` ON contact_a.id = `civicrm_group_contact-{$params[$field]}`.contact_id "; | |
722 | } | |
5d7e6440 | 723 | if ($field == 'receive_date_relative') { |
6a488035 TO |
724 | $relativeDate = explode('.', $params[$field]); |
725 | $date = CRM_Utils_Date::relativeToAbsolute($relativeDate[0], $relativeDate[1]); | |
5d7e6440 SL |
726 | $values['receive_date_low'] = $date['from']; |
727 | $values['receive_date_high'] = $date['to']; | |
6a488035 | 728 | } |
bf374fbe DM |
729 | |
730 | // Add left joins as they're needed to consider | |
731 | // conditions over custom fields. | |
732 | if (substr($field, 0, 6) == 'custom') { | |
733 | $customFieldParams = ['id' => explode('_', $field)[1]]; | |
734 | $customFieldDefaults = []; | |
735 | $customField = CRM_Core_BAO_CustomField::retrieve($customFieldParams, $customFieldDefaults); | |
736 | ||
737 | $customGroupParams = ['id' => $customField->custom_group_id]; | |
738 | $customGroupDefaults = []; | |
739 | $customGroup = CRM_Core_BAO_CustomGroup::retrieve($customGroupParams, $customGroupDefaults); | |
740 | ||
741 | $columnName = $customField->column_name; | |
742 | $tableName = $customGroup->table_name; | |
743 | ||
744 | if (!array_key_exists($tableName, $customJoins)) { | |
745 | $customJoins[$tableName] = "LEFT JOIN $tableName ON $tableName.entity_id = civicrm_contribution.id"; | |
746 | } | |
747 | } | |
6a488035 TO |
748 | } |
749 | } | |
639e74e5 | 750 | |
977196f2 PN |
751 | $searchParams = CRM_Contact_BAO_Query::convertFormValues( |
752 | $values, | |
753 | 0, | |
754 | FALSE, | |
755 | NULL, | |
756 | [ | |
757 | 'financial_type_id', | |
758 | 'contribution_soft_credit_type_id', | |
759 | 'contribution_status_id', | |
760 | 'contribution_page_id', | |
761 | 'financial_trxn_card_type_id', | |
762 | 'contribution_payment_instrument_id', | |
763 | ] | |
764 | ); | |
639e74e5 PN |
765 | // @todo the use of defaultReturnProperties means the search will be inefficient |
766 | // as slow-unneeded properties are included. | |
767 | $query = new CRM_Contact_BAO_Query($searchParams, | |
768 | CRM_Contribute_BAO_Query::defaultReturnProperties(CRM_Contact_BAO_Query::MODE_CONTRIBUTE, | |
769 | FALSE | |
770 | ), NULL, FALSE, FALSE, CRM_Contact_BAO_Query::MODE_CONTRIBUTE | |
771 | ); | |
772 | ||
bf374fbe DM |
773 | if (count($customJoins) > 0) { |
774 | $from .= " " . implode(" ", $customJoins); | |
775 | } | |
776 | ||
6a488035 | 777 | if (!empty($query->_where[0])) { |
0b0941e2 | 778 | $where = implode(' AND ', $query->_where[0]) . |
c4b067f6 | 779 | " AND civicrm_entity_batch.batch_id IS NULL "; |
30d46f2f | 780 | $where = str_replace('civicrm_contribution.payment_instrument_id', 'civicrm_financial_trxn.payment_instrument_id', $where); |
6a488035 TO |
781 | } |
782 | else { | |
6a488035 | 783 | if (!$notPresent) { |
c4b067f6 | 784 | $where = " civicrm_entity_batch.batch_id = {$entityID} "; |
6a488035 TO |
785 | } |
786 | else { | |
c4b067f6 | 787 | $where = " civicrm_entity_batch.batch_id IS NULL "; |
6a488035 TO |
788 | } |
789 | } | |
790 | ||
0b0941e2 DL |
791 | $sql = " |
792 | SELECT {$select} | |
793 | FROM {$from} | |
794 | WHERE {$where} | |
795 | {$orderBy} | |
6a488035 TO |
796 | "; |
797 | ||
798 | if (isset($limit)) { | |
799 | $sql .= "{$limit}"; | |
800 | } | |
801 | ||
802 | $result = CRM_Core_DAO::executeQuery($sql); | |
803 | return $result; | |
804 | } | |
805 | ||
806 | /** | |
eceb18cc | 807 | * Get batch names. |
6a488035 TO |
808 | * @param string $batchIds |
809 | * | |
a6c01b45 CW |
810 | * @return array |
811 | * array of batches | |
6a488035 | 812 | */ |
00be9182 | 813 | public static function getBatchNames($batchIds) { |
6a488035 TO |
814 | $query = 'SELECT id, title |
815 | FROM civicrm_batch | |
86bfa4f6 | 816 | WHERE id IN (' . $batchIds . ')'; |
6a488035 | 817 | |
be2fb01f | 818 | $batches = []; |
6a488035 | 819 | $dao = CRM_Core_DAO::executeQuery($query); |
481a74f4 | 820 | while ($dao->fetch()) { |
6a488035 TO |
821 | $batches[$dao->id] = $dao->title; |
822 | } | |
823 | return $batches; | |
824 | } | |
825 | ||
826 | /** | |
eceb18cc | 827 | * Function get batch statuses. |
6a488035 TO |
828 | * |
829 | * @param string $batchIds | |
830 | * | |
a6c01b45 CW |
831 | * @return array |
832 | * array of batches | |
6a488035 | 833 | */ |
00be9182 | 834 | public static function getBatchStatuses($batchIds) { |
6a488035 TO |
835 | $query = 'SELECT id, status_id |
836 | FROM civicrm_batch | |
92fcb95f | 837 | WHERE id IN (' . $batchIds . ')'; |
6a488035 | 838 | |
be2fb01f | 839 | $batches = []; |
6a488035 | 840 | $dao = CRM_Core_DAO::executeQuery($query); |
481a74f4 | 841 | while ($dao->fetch()) { |
6a488035 TO |
842 | $batches[$dao->id] = $dao->status_id; |
843 | } | |
844 | return $batches; | |
845 | } | |
96025800 | 846 | |
ca0e2dda PN |
847 | /** |
848 | * Function to check permission for batch. | |
849 | * | |
850 | * @param string $action | |
851 | * @param int $batchCreatedId | |
852 | * batch created by contact id | |
853 | * | |
854 | * @return bool | |
855 | */ | |
856 | public static function checkBatchPermission($action, $batchCreatedId = NULL) { | |
ca0e2dda PN |
857 | if (CRM_Core_Permission::check("{$action} all manual batches")) { |
858 | return TRUE; | |
859 | } | |
860 | if (CRM_Core_Permission::check("{$action} own manual batches")) { | |
861 | $loggedInContactId = CRM_Core_Session::singleton()->get('userID'); | |
862 | if ($batchCreatedId == $loggedInContactId) { | |
863 | return TRUE; | |
864 | } | |
865 | elseif (CRM_Utils_System::isNull($batchCreatedId)) { | |
866 | return TRUE; | |
867 | } | |
868 | } | |
869 | return FALSE; | |
870 | } | |
871 | ||
6a488035 | 872 | } |