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 | 9 | +--------------------------------------------------------------------+ |
d25dd0ee | 10 | */ |
6a488035 TO |
11 | |
12 | /** | |
13 | * | |
14 | * @package CRM | |
ca5cec67 | 15 | * @copyright CiviCRM LLC https://civicrm.org/licensing |
6a488035 TO |
16 | */ |
17 | ||
18 | /** | |
19 | * This class contains payment processor related functions. | |
20 | */ | |
d3e86119 | 21 | class CRM_Financial_BAO_PaymentProcessor extends CRM_Financial_DAO_PaymentProcessor { |
6a488035 | 22 | /** |
100fef9d | 23 | * Static holder for the default payment processor |
7b966967 | 24 | * @var object |
6a488035 | 25 | */ |
7b966967 | 26 | public static $_defaultPaymentProcessor = NULL; |
6a488035 | 27 | |
c490a46a | 28 | /** |
fe482240 | 29 | * Create Payment Processor. |
6a488035 | 30 | * |
ed5dd492 TO |
31 | * @param array $params |
32 | * Parameters for Processor entity. | |
e0ef6999 EM |
33 | * |
34 | * @return CRM_Financial_DAO_PaymentProcessor | |
94178a89 EM |
35 | * |
36 | * @throws \CRM_Core_Exception | |
37 | * @throws \CiviCRM_API3_Exception | |
e0ef6999 | 38 | */ |
94178a89 | 39 | public static function create(array $params): CRM_Financial_DAO_PaymentProcessor { |
5de5c50e SL |
40 | // If we are creating a new PaymentProcessor and have not specified the payment instrument to use, get the default from the Payment Processor Type. |
41 | if (empty($params['id']) && empty($params['payment_instrument_id'])) { | |
42 | $params['payment_instrument_id'] = civicrm_api3('PaymentProcessorType', 'getvalue', [ | |
43 | 'id' => $params['payment_processor_type_id'], | |
44 | 'return' => 'payment_instrument_id', | |
45 | ]); | |
46 | } | |
6a488035 TO |
47 | $processor = new CRM_Financial_DAO_PaymentProcessor(); |
48 | $processor->copyValues($params); | |
49 | ||
29dd4ada JP |
50 | if (empty($params['id'])) { |
51 | $ppTypeDAO = new CRM_Financial_DAO_PaymentProcessorType(); | |
52 | $ppTypeDAO->id = $params['payment_processor_type_id']; | |
53 | if (!$ppTypeDAO->find(TRUE)) { | |
4cf017d1 | 54 | throw new CRM_Core_Exception(ts('Could not find payment processor meta information')); |
29dd4ada | 55 | } |
6a488035 | 56 | |
29dd4ada JP |
57 | // also copy meta fields from the info DAO |
58 | $processor->is_recur = $ppTypeDAO->is_recur; | |
59 | $processor->billing_mode = $ppTypeDAO->billing_mode; | |
60 | $processor->class_name = $ppTypeDAO->class_name; | |
61 | $processor->payment_type = $ppTypeDAO->payment_type; | |
62 | } | |
6a488035 TO |
63 | |
64 | $processor->save(); | |
03e04002 | 65 | // CRM-11826, add entry in civicrm_entity_financial_account |
6a488035 | 66 | // if financial_account_id is not NULL |
a7488080 | 67 | if (!empty($params['financial_account_id'])) { |
f743a6eb | 68 | $relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Asset Account is' ")); |
be2fb01f | 69 | $values = [ |
6a488035 TO |
70 | 'entity_table' => 'civicrm_payment_processor', |
71 | 'entity_id' => $processor->id, | |
72 | 'account_relationship' => $relationTypeId, | |
21dfd5f5 | 73 | 'financial_account_id' => $params['financial_account_id'], |
be2fb01f | 74 | ]; |
03e04002 | 75 | CRM_Financial_BAO_FinancialTypeAccount::add($values); |
6a488035 | 76 | } |
b7e7f943 | 77 | |
46168cb8 MW |
78 | if (isset($params['id']) && isset($params['is_active']) && !isset($params['is_test'])) { |
79 | // check if is_active has changed & if so update test instance is_active too. | |
80 | $test_id = self::getTestProcessorId($params['id']); | |
81 | $testDAO = new CRM_Financial_DAO_PaymentProcessor(); | |
82 | $testDAO->id = $test_id; | |
68483a20 | 83 | if ($testDAO->find(TRUE)) { |
46168cb8 MW |
84 | $testDAO->is_active = $params['is_active']; |
85 | $testDAO->save(); | |
86 | } | |
87 | } | |
88 | ||
d6944518 | 89 | Civi\Payment\System::singleton()->flushProcessors(); |
6a488035 TO |
90 | return $processor; |
91 | } | |
92 | ||
cb5962bd | 93 | /** |
c294dbbc | 94 | * Retrieve array of allowed credit cards for this payment processor. |
94178a89 | 95 | * @param integer|null $paymentProcessorID id of processor. |
cb5962bd SL |
96 | * @return array |
97 | */ | |
98 | public static function getCreditCards($paymentProcessorID = NULL) { | |
99 | if (!empty($paymentProcessorID)) { | |
100 | $processor = new CRM_Financial_DAO_PaymentProcessor(); | |
101 | $processor->id = $paymentProcessorID; | |
102 | $processor->find(TRUE); | |
103 | $cards = json_decode($processor->accepted_credit_cards, TRUE); | |
104 | return $cards; | |
105 | } | |
be2fb01f | 106 | return []; |
cb5962bd SL |
107 | } |
108 | ||
6cc6cb8c | 109 | /** |
110 | * Get options for a given contribution field. | |
111 | * | |
112 | * @param string $fieldName | |
113 | * @param string $context see CRM_Core_DAO::buildOptionsContext. | |
114 | * @param array $props whatever is known about this dao object. | |
115 | * | |
116 | * @return array|bool | |
117 | * @see CRM_Core_DAO::buildOptions | |
118 | * | |
119 | */ | |
120 | public static function buildOptions($fieldName, $context = NULL, $props = []) { | |
121 | $params = []; | |
122 | if ($fieldName === 'financial_account_id') { | |
123 | // Pseudo-field - let's help out. | |
124 | return CRM_Core_BAO_FinancialTrxn::buildOptions('to_financial_account_id', $context, $props); | |
125 | } | |
126 | return CRM_Core_PseudoConstant::get(__CLASS__, $fieldName, $params, $context); | |
127 | } | |
128 | ||
6a488035 | 129 | /** |
fe482240 EM |
130 | * Retrieve DB object based on input parameters. |
131 | * | |
132 | * It also stores all the retrieved values in the default array. | |
6a488035 | 133 | * |
ed5dd492 TO |
134 | * @param array $params |
135 | * (reference ) an assoc array of name/value pairs. | |
136 | * @param array $defaults | |
137 | * (reference ) an assoc array to hold the flattened values. | |
6a488035 | 138 | * |
16b10e64 CW |
139 | * @return CRM_Financial_DAO_PaymentProcessor|null |
140 | * object on success, null otherwise | |
6a488035 | 141 | */ |
00be9182 | 142 | public static function retrieve(&$params, &$defaults) { |
6a488035 TO |
143 | $paymentProcessor = new CRM_Financial_DAO_PaymentProcessor(); |
144 | $paymentProcessor->copyValues($params); | |
145 | if ($paymentProcessor->find(TRUE)) { | |
146 | CRM_Core_DAO::storeValues($paymentProcessor, $defaults); | |
147 | return $paymentProcessor; | |
148 | } | |
149 | return NULL; | |
150 | } | |
151 | ||
152 | /** | |
fe482240 | 153 | * Update the is_active flag in the db. |
6a488035 | 154 | * |
ed5dd492 TO |
155 | * @param int $id |
156 | * Id of the database record. | |
157 | * @param bool $is_active | |
158 | * Value we want to set the is_active field. | |
6a488035 | 159 | * |
8a4fede3 | 160 | * @return bool |
161 | * true if we found and updated the object, else false | |
6a488035 | 162 | */ |
00be9182 | 163 | public static function setIsActive($id, $is_active) { |
6a488035 TO |
164 | return CRM_Core_DAO::setFieldValue('CRM_Financial_DAO_PaymentProcessor', $id, 'is_active', $is_active); |
165 | } | |
166 | ||
167 | /** | |
fe482240 | 168 | * Retrieve the default payment processor. |
6a488035 | 169 | * |
16b10e64 | 170 | * @return CRM_Financial_DAO_PaymentProcessor|null |
a6c01b45 | 171 | * The default payment processor object on success, |
16b10e64 | 172 | * null otherwise |
6a488035 | 173 | */ |
00be9182 | 174 | public static function &getDefault() { |
6a488035 | 175 | if (self::$_defaultPaymentProcessor == NULL) { |
be2fb01f CW |
176 | $params = ['is_default' => 1]; |
177 | $defaults = []; | |
6a488035 TO |
178 | self::$_defaultPaymentProcessor = self::retrieve($params, $defaults); |
179 | } | |
180 | return self::$_defaultPaymentProcessor; | |
181 | } | |
182 | ||
183 | /** | |
fe482240 | 184 | * Delete payment processor. |
6a488035 | 185 | * |
c490a46a | 186 | * @param int $paymentProcessorID |
77b97be7 EM |
187 | * |
188 | * @return null | |
6a488035 | 189 | */ |
00be9182 | 190 | public static function del($paymentProcessorID) { |
6a488035 | 191 | if (!$paymentProcessorID) { |
4cf017d1 | 192 | throw new CRM_Core_Exception(ts('Invalid value passed to delete function.')); |
6a488035 TO |
193 | } |
194 | ||
195 | $dao = new CRM_Financial_DAO_PaymentProcessor(); | |
196 | $dao->id = $paymentProcessorID; | |
197 | if (!$dao->find(TRUE)) { | |
198 | return NULL; | |
199 | } | |
200 | ||
201 | $testDAO = new CRM_Financial_DAO_PaymentProcessor(); | |
202 | $testDAO->name = $dao->name; | |
203 | $testDAO->is_test = 1; | |
204 | $testDAO->delete(); | |
205 | ||
206 | $dao->delete(); | |
d6944518 | 207 | Civi\Payment\System::singleton()->flushProcessors(); |
6a488035 TO |
208 | } |
209 | ||
210 | /** | |
fe482240 | 211 | * Get the payment processor details. |
6a488035 | 212 | * |
9d8f43b1 EM |
213 | * This returns an array whereas Civi\Payment\System::singleton->getByID() returns an object. |
214 | * The object is a key in the array. | |
2c5311b9 | 215 | * |
ed5dd492 TO |
216 | * @param int $paymentProcessorID |
217 | * Payment processor id. | |
218 | * @param string $mode | |
219 | * Payment mode ie test or live. | |
6a488035 | 220 | * |
a6c01b45 CW |
221 | * @return array |
222 | * associated array with payment processor related fields | |
6a488035 | 223 | */ |
aaff4c69 | 224 | public static function getPayment($paymentProcessorID, $mode = 'based_on_id') { |
94178a89 | 225 | $capabilities = ($mode === 'test') ? ['TestMode'] : []; |
be2fb01f | 226 | $processors = self::getPaymentProcessors($capabilities, [$paymentProcessorID]); |
9d8f43b1 | 227 | return $processors[$paymentProcessorID]; |
6a488035 TO |
228 | } |
229 | ||
428e38a4 EM |
230 | /** |
231 | * Given a live processor ID get the test id. | |
232 | * | |
233 | * @param int $id | |
234 | * | |
235 | * @return int | |
236 | * Test payment processor ID. | |
237 | */ | |
238 | public static function getTestProcessorId($id) { | |
be2fb01f | 239 | $liveProcessorName = civicrm_api3('payment_processor', 'getvalue', [ |
428e38a4 EM |
240 | 'id' => $id, |
241 | 'return' => 'name', | |
be2fb01f CW |
242 | ]); |
243 | return civicrm_api3('payment_processor', 'getvalue', [ | |
428e38a4 EM |
244 | 'return' => 'id', |
245 | 'name' => $liveProcessorName, | |
46168cb8 | 246 | 'is_test' => 1, |
428e38a4 | 247 | 'domain_id' => CRM_Core_Config::domainID(), |
be2fb01f | 248 | ]); |
428e38a4 EM |
249 | } |
250 | ||
13ac605f | 251 | /** |
100fef9d | 252 | * Compare 2 payment processors to see which should go first based on is_default |
13ac605f DG |
253 | * (sort function for sortDefaultFirst) |
254 | * @param array $processor1 | |
16b10e64 | 255 | * @param array $processor2 |
79d7553f | 256 | * |
257 | * @return int | |
13ac605f | 258 | */ |
9b873358 | 259 | public static function defaultComparison($processor1, $processor2) { |
9c1bc317 CW |
260 | $p1 = $processor1['is_default'] ?? NULL; |
261 | $p2 = $processor2['is_default'] ?? NULL; | |
045f52a3 TO |
262 | if ($p1 == $p2) { |
263 | return 0; | |
13ac605f | 264 | } |
045f52a3 TO |
265 | return ($p1 > $p2) ? -1 : 1; |
266 | } | |
13ac605f | 267 | |
fbcb6fba | 268 | /** |
100fef9d | 269 | * Get all payment processors as an array of objects. |
fbcb6fba | 270 | * |
52767de0 EM |
271 | * @param string|NULL $mode |
272 | * only return this mode - test|live or NULL for all | |
fbcb6fba | 273 | * @param bool $reset |
4199eb7e SL |
274 | * @param bool $isCurrentDomainOnly |
275 | * Do we only want to load payment processors associated with the current domain. | |
c3408d93 MW |
276 | * @param bool|NULL $isActive |
277 | * Do we only want active processors, only inactive (FALSE) or all processors (NULL) | |
fbcb6fba EM |
278 | * |
279 | * @throws CiviCRM_API3_Exception | |
280 | * @return array | |
281 | */ | |
c3408d93 | 282 | public static function getAllPaymentProcessors($mode = 'all', $reset = FALSE, $isCurrentDomainOnly = TRUE, $isActive = TRUE) { |
7036a6d0 | 283 | |
6689745a | 284 | $cacheKey = 'CRM_Financial_BAO_Payment_Processor_' . $mode . '_' . $isCurrentDomainOnly . '_' . CRM_Core_Config::domainID(); |
7036a6d0 EM |
285 | if (!$reset) { |
286 | $processors = CRM_Utils_Cache::singleton()->get($cacheKey); | |
287 | if (!empty($processors)) { | |
288 | return $processors; | |
289 | } | |
290 | } | |
291 | ||
be2fb01f | 292 | $retrievalParameters = [ |
be2fb01f | 293 | 'options' => ['sort' => 'is_default DESC, name', 'limit' => 0], |
79d7553f | 294 | 'api.payment_processor_type.getsingle' => 1, |
be2fb01f | 295 | ]; |
c3408d93 MW |
296 | if (isset($isActive)) { |
297 | // We use isset because we don't want to set the is_active parameter at all is $isActive is NULL | |
298 | $retrievalParameters['is_active'] = $isActive; | |
299 | } | |
4199eb7e | 300 | if ($isCurrentDomainOnly) { |
5391207b SL |
301 | $retrievalParameters['domain_id'] = CRM_Core_Config::domainID(); |
302 | } | |
94178a89 | 303 | if ($mode === 'test') { |
52767de0 EM |
304 | $retrievalParameters['is_test'] = 1; |
305 | } | |
94178a89 | 306 | elseif ($mode === 'live') { |
fbcb6fba EM |
307 | $retrievalParameters['is_test'] = 0; |
308 | } | |
7036a6d0 | 309 | |
fbcb6fba EM |
310 | $processors = civicrm_api3('payment_processor', 'get', $retrievalParameters); |
311 | foreach ($processors['values'] as $processor) { | |
be2fb01f | 312 | $fieldsToProvide = [ |
742c1119 MW |
313 | 'id', |
314 | 'name', | |
315 | 'payment_processor_type_id', | |
316 | 'user_name', | |
317 | 'password', | |
318 | 'signature', | |
319 | 'url_site', | |
320 | 'url_api', | |
321 | 'url_recur', | |
322 | 'url_button', | |
323 | 'subject', | |
324 | 'class_name', | |
325 | 'is_recur', | |
326 | 'billing_mode', | |
327 | 'is_test', | |
328 | 'payment_type', | |
329 | 'is_default', | |
be2fb01f | 330 | ]; |
52767de0 | 331 | foreach ($fieldsToProvide as $field) { |
7036a6d0 | 332 | // Prevent e-notices in processor classes when not configured. |
52767de0 | 333 | if (!isset($processor[$field])) { |
be74ba34 | 334 | $processors['values'][$processor['id']][$field] = NULL; |
52767de0 EM |
335 | } |
336 | } | |
9d91a9c6 | 337 | $processors['values'][$processor['id']]['payment_processor_type'] = $processor['payment_processor_type'] = $processors['values'][$processor['id']]['api.payment_processor_type.getsingle']['name']; |
1e97777c | 338 | $processors['values'][$processor['id']]['object'] = Civi\Payment\System::singleton()->getByProcessor($processors['values'][$processor['id']]); |
fbcb6fba | 339 | } |
7036a6d0 | 340 | |
1d1fee72 | 341 | // Add the pay-later pseudo-processor. |
be2fb01f | 342 | $processors['values'][0] = [ |
f48e6cf7 | 343 | 'object' => new CRM_Core_Payment_Manual(), |
1d1fee72 | 344 | 'id' => 0, |
345 | 'payment_processor_type_id' => 0, | |
f48e6cf7 | 346 | // This shouldn't be required but there are still some processors hacked into core with nasty 'if's. |
347 | 'payment_processor_type' => 'Manual', | |
1d1fee72 | 348 | 'class_name' => 'Payment_Manual', |
349 | 'name' => 'pay_later', | |
350 | 'billing_mode' => '', | |
fdf4616e | 351 | 'is_default' => 0, |
18135422 | 352 | 'payment_instrument_id' => key(CRM_Core_OptionGroup::values('payment_instrument', FALSE, FALSE, FALSE, 'AND is_default = 1')), |
1d1fee72 | 353 | // Making this optionally recur would give lots of options -but it should |
354 | // be a row in the payment processor table before we do that. | |
355 | 'is_recur' => FALSE, | |
18135422 | 356 | 'is_test' => FALSE, |
be2fb01f | 357 | ]; |
1d1fee72 | 358 | |
7036a6d0 EM |
359 | CRM_Utils_Cache::singleton()->set($cacheKey, $processors['values']); |
360 | ||
fbcb6fba EM |
361 | return $processors['values']; |
362 | } | |
363 | ||
364 | /** | |
100fef9d | 365 | * Get Payment processors with specified capabilities. |
fbcb6fba EM |
366 | * Note that both the singleton & the pseudoconstant function have caching so we don't add |
367 | * arguably this could go on the pseudoconstant class | |
368 | * | |
369 | * @param array $capabilities | |
16b10e64 CW |
370 | * capabilities of processor e.g |
371 | * - BackOffice | |
372 | * - TestMode | |
373 | * - LiveMode | |
374 | * - FutureStartDate | |
fbcb6fba | 375 | * |
93e11927 | 376 | * @param array|bool $ids |
dc913073 | 377 | * |
a6c01b45 CW |
378 | * @return array |
379 | * available processors | |
c3408d93 MW |
380 | * |
381 | * @throws \CiviCRM_API3_Exception | |
fbcb6fba | 382 | */ |
be2fb01f | 383 | public static function getPaymentProcessors($capabilities = [], $ids = FALSE) { |
5391207b | 384 | if (is_array($ids)) { |
c3408d93 MW |
385 | if (in_array('TestMode', $capabilities, TRUE)) { |
386 | $testProcessors = in_array('TestMode', $capabilities) ? self::getAllPaymentProcessors('test') : []; | |
387 | $allProcessors = self::getAllPaymentProcessors('all', FALSE, FALSE, NULL); | |
3833914f | 388 | $possibleLiveIDs = array_diff($ids, array_keys($testProcessors)); |
389 | foreach ($possibleLiveIDs as $possibleLiveID) { | |
c3408d93 | 390 | if (isset($allProcessors[$possibleLiveID]) && ($liveProcessorName = $allProcessors[$possibleLiveID]['name']) != FALSE) { |
3833914f | 391 | foreach ($testProcessors as $index => $testProcessor) { |
c3408d93 | 392 | if ($testProcessor['name'] === $liveProcessorName) { |
3833914f | 393 | $ids[] = $testProcessor['id']; |
394 | } | |
e082c947 | 395 | } |
396 | } | |
397 | } | |
3833914f | 398 | $processors = $testProcessors; |
e082c947 | 399 | } |
c3408d93 MW |
400 | else { |
401 | $processors = self::getAllPaymentProcessors('all', FALSE, FALSE); | |
402 | } | |
3833914f | 403 | } |
404 | else { | |
405 | $processors = self::getAllPaymentProcessors('all'); | |
52767de0 | 406 | } |
7036a6d0 | 407 | |
1b9f9ca3 | 408 | foreach ($processors as $index => $processor) { |
74b91f33 | 409 | if (is_array($ids) && !in_array($processor['id'], $ids)) { |
5391207b | 410 | unset($processors[$index]); |
1b9f9ca3 EM |
411 | continue; |
412 | } | |
413 | // Invalid processors will store a null value in 'object' (e.g. if not all required config fields are present). | |
414 | // This is determined by calling when loading the processor via the $processorObject->checkConfig() function. | |
94178a89 | 415 | if (!$processor['object'] instanceof CRM_Core_Payment) { |
5391207b | 416 | unset($processors[$index]); |
1b9f9ca3 EM |
417 | continue; |
418 | } | |
419 | foreach ($capabilities as $capability) { | |
420 | if (($processor['object']->supports($capability)) == FALSE) { | |
5391207b | 421 | unset($processors[$index]); |
1b9f9ca3 | 422 | continue 1; |
fbcb6fba EM |
423 | } |
424 | } | |
425 | } | |
1b9f9ca3 | 426 | |
fbcb6fba EM |
427 | return $processors; |
428 | } | |
429 | ||
430 | /** | |
fe482240 | 431 | * Is there a processor on this site with the specified capability. |
c1f95567 | 432 | * |
433 | * The capabilities are defined on CRM_Core_Payment and can be extended by | |
434 | * processors. | |
435 | * | |
436 | * examples are | |
437 | * - supportsBackOffice | |
438 | * - supportsLiveMode | |
439 | * - supportsFutureRecurDate | |
54afd8a6 | 440 | * - supportsRecurring |
c1f95567 | 441 | * - supportsCancelRecurring |
442 | * - supportsRecurContributionsForPledges | |
443 | * | |
444 | * They are passed as array('BackOffice'); | |
445 | * | |
446 | * Details of specific functions are in the docblocks on the CRM_Core_Payment class. | |
447 | * | |
fbcb6fba | 448 | * @param array $capabilities |
fbcb6fba EM |
449 | * |
450 | * @return bool | |
451 | */ | |
be2fb01f | 452 | public static function hasPaymentProcessorSupporting($capabilities = []) { |
d09e593c | 453 | $capabilitiesString = implode('', $capabilities); |
454 | if (!isset(\Civi::$statics[__CLASS__]['supported_capabilities'][$capabilitiesString])) { | |
455 | $result = self::getPaymentProcessors($capabilities); | |
f7dbf5d9 | 456 | \Civi::$statics[__CLASS__]['supported_capabilities'][$capabilitiesString] = (!empty($result) && array_keys($result) !== [0]); |
d09e593c | 457 | } |
458 | return \Civi::$statics[__CLASS__]['supported_capabilities'][$capabilitiesString]; | |
fbcb6fba EM |
459 | } |
460 | ||
6a488035 | 461 | /** |
100fef9d | 462 | * Retrieve payment processor id / info/ object based on component-id. |
6a488035 | 463 | * |
0bd096e8 | 464 | * @todo function needs revisiting. The whole 'info / obj' thing is an overload. Recommend creating new functions |
465 | * that are entity specific as there is little shared code specific to obj or info | |
466 | * | |
467 | * Also, it does not accurately derive the processor - for a completed contribution the best place to look is in the | |
468 | * relevant financial_trxn record. For a recurring contribution it is in the contribution_recur table. | |
469 | * | |
470 | * For a membership the relevant contribution_recur should be derived & then resolved as above. The contribution page | |
471 | * is never a reliable place to look as there can be more than one configured. For a pending contribution there is | |
472 | * no way to derive the processor - but hey - what processor? it didn't go through! | |
473 | * | |
474 | * Query for membership might look something like: | |
475 | * SELECT fte.payment_processor_id | |
476 | * FROM civicrm_membership mem | |
477 | * INNER JOIN civicrm_line_item li ON ( mem.id = li.entity_id AND li.entity_table = 'civicrm_membership') | |
478 | * INNER JOIN civicrm_contribution con ON ( li.contribution_id = con.id ) | |
479 | * LEFT JOIN civicrm_entity_financial_trxn ft ON ft.entity_id = con.id AND ft.entity_table = | |
480 | * 'civicrm_contribution' | |
481 | * LEFT JOIN civicrm_financial_trxn fte ON fte.id = ft.financial_trxn_id | |
482 | * | |
100fef9d | 483 | * @param int $entityID |
ed5dd492 TO |
484 | * @param string $component |
485 | * Component. | |
486 | * @param string $type | |
487 | * Type of payment information to be retrieved. | |
6a488035 | 488 | * |
16b10e64 | 489 | * @return int|array|object |
6a488035 | 490 | */ |
00be9182 | 491 | public static function getProcessorForEntity($entityID, $component = 'contribute', $type = 'id') { |
6a488035 | 492 | $result = NULL; |
be2fb01f | 493 | if (!in_array($component, [ |
353ffa53 TO |
494 | 'membership', |
495 | 'contribute', | |
79d7553f | 496 | 'recur', |
be2fb01f | 497 | ]) |
353ffa53 | 498 | ) { |
6a488035 TO |
499 | return $result; |
500 | } | |
cded2ebf | 501 | |
94178a89 | 502 | if ($component === 'membership') { |
6a488035 TO |
503 | $sql = " |
504 | SELECT cr.payment_processor_id as ppID1, cp.payment_processor as ppID2, con.is_test | |
505 | FROM civicrm_membership mem | |
506 | INNER JOIN civicrm_membership_payment mp ON ( mem.id = mp.membership_id ) | |
507 | INNER JOIN civicrm_contribution con ON ( mp.contribution_id = con.id ) | |
508 | LEFT JOIN civicrm_contribution_recur cr ON ( mem.contribution_recur_id = cr.id ) | |
509 | LEFT JOIN civicrm_contribution_page cp ON ( con.contribution_page_id = cp.id ) | |
510 | WHERE mp.membership_id = %1"; | |
511 | } | |
94178a89 | 512 | elseif ($component === 'contribute') { |
6a488035 TO |
513 | $sql = " |
514 | SELECT cr.payment_processor_id as ppID1, cp.payment_processor as ppID2, con.is_test | |
515 | FROM civicrm_contribution con | |
516 | LEFT JOIN civicrm_contribution_recur cr ON ( con.contribution_recur_id = cr.id ) | |
517 | LEFT JOIN civicrm_contribution_page cp ON ( con.contribution_page_id = cp.id ) | |
518 | WHERE con.id = %1"; | |
519 | } | |
94178a89 | 520 | elseif ($component === 'recur') { |
b3e340d9 | 521 | // @deprecated - use getPaymentProcessorForRecurringContribution. |
6a488035 TO |
522 | $sql = " |
523 | SELECT cr.payment_processor_id as ppID1, NULL as ppID2, cr.is_test | |
524 | FROM civicrm_contribution_recur cr | |
525 | WHERE cr.id = %1"; | |
526 | } | |
527 | ||
cded2ebf | 528 | // We are interested in a single record. |
6a488035 TO |
529 | $sql .= ' LIMIT 1'; |
530 | ||
be2fb01f | 531 | $params = [1 => [$entityID, 'Integer']]; |
6a488035 TO |
532 | $dao = CRM_Core_DAO::executeQuery($sql, $params); |
533 | ||
534 | if (!$dao->fetch()) { | |
535 | ||
536 | return $result; | |
537 | ||
538 | } | |
539 | ||
2e1f50d6 | 540 | $ppID = (isset($dao->ppID1) && $dao->ppID1) ? $dao->ppID1 : ($dao->ppID2 ?? NULL); |
6a488035 | 541 | $mode = (isset($dao->is_test) && $dao->is_test) ? 'test' : 'live'; |
94178a89 | 542 | if (!$ppID || $type === 'id') { |
6a488035 TO |
543 | $result = $ppID; |
544 | } | |
94178a89 | 545 | elseif ($type === 'info') { |
6a488035 TO |
546 | $result = self::getPayment($ppID, $mode); |
547 | } | |
94178a89 | 548 | elseif ($type === 'obj' && is_numeric($ppID)) { |
0bd096e8 | 549 | try { |
be2fb01f | 550 | $paymentProcessor = civicrm_api3('PaymentProcessor', 'getsingle', ['id' => $ppID]); |
0bd096e8 | 551 | } |
552 | catch (API_Exception $e) { | |
553 | // Unable to load the processor because this function uses an unreliable method to derive it. | |
554 | // The function looks to load the payment processor ID from the contribution page, which | |
555 | // can support multiple processors. | |
556 | } | |
742c1119 MW |
557 | |
558 | $paymentProcessor['payment_processor_type'] = CRM_Core_PseudoConstant::getName('CRM_Financial_BAO_PaymentProcessor', 'payment_processor_type_id', $paymentProcessor['payment_processor_type_id']); | |
0bd096e8 | 559 | $result = Civi\Payment\System::singleton()->getByProcessor($paymentProcessor); |
6a488035 | 560 | } |
6a488035 TO |
561 | return $result; |
562 | } | |
96025800 | 563 | |
b3e340d9 | 564 | /** |
565 | * Get the payment processor associated with a recurring contribution series. | |
566 | * | |
567 | * @param int $contributionRecurID | |
568 | * | |
569 | * @return \CRM_Core_Payment | |
570 | */ | |
571 | public static function getPaymentProcessorForRecurringContribution($contributionRecurID) { | |
be2fb01f | 572 | $paymentProcessorId = civicrm_api3('ContributionRecur', 'getvalue', [ |
b3e340d9 | 573 | 'id' => $contributionRecurID, |
574 | 'return' => 'payment_processor_id', | |
be2fb01f | 575 | ]); |
b3e340d9 | 576 | return Civi\Payment\System::singleton()->getById($paymentProcessorId); |
577 | } | |
578 | ||
46097c9c MW |
579 | /** |
580 | * Get the name of the payment processor | |
581 | * | |
582 | * @param $paymentProcessorId | |
583 | * | |
584 | * @return null|string | |
585 | */ | |
586 | public static function getPaymentProcessorName($paymentProcessorId) { | |
587 | try { | |
be2fb01f CW |
588 | $paymentProcessor = civicrm_api3('PaymentProcessor', 'getsingle', [ |
589 | 'return' => ['name'], | |
46097c9c | 590 | 'id' => $paymentProcessorId, |
be2fb01f | 591 | ]); |
46097c9c MW |
592 | return $paymentProcessor['name']; |
593 | } | |
594 | catch (Exception $e) { | |
595 | return ts('Unknown') . ' (' . $paymentProcessorId . ')'; | |
596 | } | |
597 | } | |
598 | ||
84df6a33 | 599 | /** |
600 | * Generate and assign an arbitrary value to a field of a test object. | |
601 | * | |
602 | * @param string $fieldName | |
603 | * @param array $fieldDef | |
604 | * @param int $counter | |
605 | * The globally-unique ID of the test object. | |
606 | */ | |
607 | protected function assignTestValue($fieldName, &$fieldDef, $counter) { | |
608 | if ($fieldName === 'class_name') { | |
609 | $this->class_name = 'Payment_Dummy'; | |
610 | } | |
611 | else { | |
612 | parent::assignTestValue($fieldName, $fieldDef, $counter); | |
613 | } | |
614 | } | |
615 | ||
8563c1ce | 616 | /** |
617 | * Get the default financial account id for payment processor accounts. | |
618 | * | |
619 | * Note that there is only a 'name' field & no label field. If people customise | |
620 | * name then this won't work. This is new best-effort functionality so that's non-regressive. | |
621 | * | |
622 | * The fix for that is to add a label value to the financial account table. | |
623 | */ | |
624 | public static function getDefaultFinancialAccountID() { | |
625 | return CRM_Core_PseudoConstant::getKey('CRM_Financial_DAO_EntityFinancialAccount', 'financial_account_id', 'Payment Processor Account'); | |
626 | } | |
627 | ||
6a488035 | 628 | } |