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