3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
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 |
9 +--------------------------------------------------------------------+
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
19 * This class generates form components for Payment Processor.
21 class CRM_Admin_Form_PaymentProcessor
extends CRM_Admin_Form
{
22 use CRM_Core_Form_EntityFormTrait
;
26 * Test Payment Processor ID
31 * @var \CRM_Financial_DAO_PaymentProcessorType
32 * Payment Processor DAO Object
34 protected $_paymentProcessorDAO;
38 * Payment processor Type ID
40 protected $_paymentProcessorType;
43 * Fields for the entity to be assigned to the template.
45 * Fields may have keys
46 * - name (required to show in tpl from the array)
47 * - description (optional, will appear below the field)
48 * Auto-added by setEntityFieldsMetadata unless specified here (use description => '' to hide)
49 * - not-auto-addable - this class will not attempt to add the field using addField.
50 * (this will be automatically set if the field does not have html in it's metadata
51 * or is not a core field on the form's entity).
52 * - help (option) add help to the field - e.g ['id' => 'id-source', 'file' => 'CRM/Contact/Form/Contact']]
53 * - template - use a field specific template to render this field
55 * - is_freeze (field should be frozen).
59 protected $entityFields = [];
62 * Set entity fields to be assigned to the form.
64 protected function setEntityFields() {
65 $this->entityFields
= [
66 'payment_processor_type_id' => [
67 'name' => 'payment_processor_type_id',
78 'name' => 'description',
82 $this->setEntityFieldsMetadata();
86 * Get the name of the base entity being edited.
90 public function getDefaultEntity() {
91 return 'PaymentProcessor';
95 * Set the delete message.
97 * We do this from the constructor in order to do a translation.
99 public function setDeleteMessage() {
100 $this->deleteMessage
= ts('Deleting this Payment Processor may result in some transaction pages being rendered inactive.') . ' ' . ts('Do you want to continue?');
104 * Preprocess the form.
106 * @throws \CRM_Core_Exception
108 public function preProcess() {
109 parent
::preProcess();
111 $this->setPaymentProcessorTypeID();
112 $this->setPaymentProcessor();
113 $this->assign('ppType', $this->_paymentProcessorType
);
114 $this->assign('ppTypeName', $this->_paymentProcessorDAO
->name
);
117 $refreshURL = CRM_Utils_System
::url('civicrm/admin/paymentProcessor',
118 "reset=1&action=update&id={$this->_id}",
123 $refreshURL = CRM_Utils_System
::url('civicrm/admin/paymentProcessor',
124 "reset=1&action=add",
130 $destination = CRM_Utils_Request
::retrieve('civicrmDestination', 'String', $this);
132 $destination = urlencode($destination);
133 $refreshURL .= "&civicrmDestination=$destination";
136 $this->refreshURL
= $refreshURL;
137 $this->assign('refreshURL', $refreshURL);
139 $this->assign('is_recur', $this->_paymentProcessorDAO
->is_recur
);
143 'name' => 'user_name',
144 'label' => $this->_paymentProcessorDAO
->user_name_label
,
147 'name' => 'password',
148 'label' => $this->_paymentProcessorDAO
->password_label
,
151 'name' => 'signature',
152 'label' => $this->_paymentProcessorDAO
->signature_label
,
156 'label' => $this->_paymentProcessorDAO
->subject_label
,
159 'name' => 'url_site',
160 'label' => ts('Site URL'),
162 'msg' => ts('Enter a valid URL'),
166 if ($this->_paymentProcessorDAO
->is_recur
) {
168 'name' => 'url_recur',
169 'label' => ts('Recurring Payments URL'),
171 'msg' => ts('Enter a valid URL'),
175 if (!empty($this->_paymentProcessorDAO
->url_button_default
)) {
177 'name' => 'url_button',
178 'label' => ts('Button URL'),
180 'msg' => ts('Enter a valid URL'),
184 if (!empty($this->_paymentProcessorDAO
->url_api_default
)) {
187 'label' => ts('API URL'),
189 'msg' => ts('Enter a valid URL'),
195 * Build the form object.
199 public function buildQuickForm($check = FALSE) {
200 $this->buildQuickEntityForm();
202 if ($this->isDeleteContext()) {
206 $attributes = CRM_Core_DAO
::getAttribute('CRM_Financial_DAO_PaymentProcessor');
208 $this->addRule('name', ts('Name already exists in Database.'), 'objectExists', [
209 'CRM_Financial_DAO_PaymentProcessor',
212 CRM_Core_Config
::domainID(),
215 // @todo - remove this & let the entityForm do it - need to make sure we are handling the js though.
217 'payment_processor_type_id',
218 ts('Payment Processor Type'),
219 CRM_Financial_BAO_PaymentProcessor
::buildOptions('payment_processor_type_id'),
221 ['onchange' => "reload(true)"]
224 // Financial Account of account type asset CRM-11515
225 $accountType = CRM_Core_PseudoConstant
::accountOptionValues('financial_account_type', NULL, " AND v.name = 'Asset' ");
226 $financialAccount = CRM_Contribute_PseudoConstant
::financialAccount(NULL, key($accountType));
227 if ($fcount = count($financialAccount)) {
228 $this->assign('financialAccount', $fcount);
230 $this->add('select', 'financial_account_id', ts('Financial Account'),
231 ['' => ts('- select -')] +
$financialAccount,
234 $this->addSelect('payment_instrument_id',
236 'entity' => 'contribution',
237 'label' => ts('Payment Method'),
238 'placeholder' => NULL,
242 // is this processor active ?
243 $this->add('checkbox', 'is_active', ts('Is this Payment Processor active?'));
244 $this->add('checkbox', 'is_default', ts('Is this Payment Processor the default?'));
245 $creditCardTypes = CRM_Contribute_PseudoConstant
::creditCard();
246 $this->addCheckBox('accept_credit_cards', ts('Accepted Credit Card Type(s)'),
247 $creditCardTypes, NULL, NULL, NULL, NULL, ' ');
248 foreach ($this->_fields
as $field) {
249 if (empty($field['label'])) {
253 $this->addField($field['name'], ['label' => $field['label']]);
255 $fieldSpec = civicrm_api3($this->getDefaultEntity(), 'getfield', [
256 'name' => $field['name'],
257 'action' => 'create',
259 $this->add($fieldSpec['values']['html']['type'], "test_{$field['name']}",
260 $field['label'], $attributes[$field['name']]
262 if (!empty($field['rule'])) {
263 $this->addRule($field['name'], $field['msg'], $field['rule']);
264 $this->addRule("test_{$field['name']}", $field['msg'], $field['rule']);
268 $this->addFormRule(['CRM_Admin_Form_PaymentProcessor', 'formRule']);
276 public static function formRule($fields) {
278 // make sure that at least one of live or test is present
279 // and we have at least name and url_site
280 // would be good to make this processor specific
283 if (!(self
::checkSection($fields, $errors) ||
284 self
::checkSection($fields, $errors, 'test')
287 $errors['_qf_default'] = ts('You must have at least the test or live section filled');
290 if (!empty($errors)) {
294 return empty($errors) ?
TRUE : $errors;
300 * @param null $section
304 public static function checkSection(&$fields, &$errors, $section = NULL): bool {
305 $names = ['user_name'];
309 foreach ($names as $name) {
311 $name = "{$section}_$name";
313 if (!empty($fields[$name])) {
323 $errors['_qf_default'] = ts('You must have at least the user_name specified');
332 public function setDefaultValues() {
336 $defaults['is_active'] = $defaults['is_default'] = 1;
337 $defaults['url_site'] = $this->_paymentProcessorDAO
->url_site_default
;
338 $defaults['url_api'] = $this->_paymentProcessorDAO
->url_api_default
;
339 $defaults['url_recur'] = $this->_paymentProcessorDAO
->url_recur_default
;
340 $defaults['url_button'] = $this->_paymentProcessorDAO
->url_button_default
;
341 $defaults['test_url_site'] = $this->_paymentProcessorDAO
->url_site_test_default
;
342 $defaults['test_url_api'] = $this->_paymentProcessorDAO
->url_api_test_default
;
343 $defaults['test_url_recur'] = $this->_paymentProcessorDAO
->url_recur_test_default
;
344 $defaults['test_url_button'] = $this->_paymentProcessorDAO
->url_button_test_default
;
345 $defaults['payment_instrument_id'] = $this->_paymentProcessorDAO
->payment_instrument_id
;
346 // When user changes payment processor type, it is passed in via $this->_ppType so update defaults array.
347 if ($this->_paymentProcessorType
) {
348 $defaults['payment_processor_type_id'] = $this->_paymentProcessorType
;
350 $defaults['financial_account_id'] = CRM_Financial_BAO_PaymentProcessor
::getDefaultFinancialAccountID();
353 $domainID = CRM_Core_Config
::domainID();
355 $dao = new CRM_Financial_DAO_PaymentProcessor();
356 $dao->id
= $this->_id
;
357 $dao->domain_id
= $domainID;
358 if (!$dao->find(TRUE)) {
362 CRM_Core_DAO
::storeValues($dao, $defaults);
363 // If payment processor ID does not exist, $paymentProcessorName will be FALSE
364 $paymentProcessorName = CRM_Core_PseudoConstant
::getName('CRM_Financial_BAO_PaymentProcessor', 'payment_processor_type_id', $this->_paymentProcessorType
);
365 if ($this->_paymentProcessorType
&& $paymentProcessorName) {
366 // When user changes payment processor type, it is passed in via $this->_ppType so update defaults array.
367 $defaults['payment_processor_type_id'] = $this->_paymentProcessorType
;
370 CRM_Core_Session
::setStatus(ts('Payment Processor Type (ID=%1) not found. Did you disable the payment processor extension?', [1 => $this->_paymentProcessorType
]), ts('Missing Payment Processor'), 'alert');
373 $cards = json_decode(CRM_Core_DAO
::getFieldValue('CRM_Financial_DAO_PaymentProcessor',
375 'accepted_credit_cards'
378 if (!empty($cards)) {
379 foreach ($cards as $card => $val) {
380 $acceptedCards[$card] = 1;
383 $defaults['accept_credit_cards'] = $acceptedCards;
384 unset($defaults['accepted_credit_cards']);
386 $testDAO = new CRM_Financial_DAO_PaymentProcessor();
387 $testDAO->name
= $dao->name
;
388 $testDAO->is_test
= 1;
389 $testDAO->domain_id
= $domainID;
390 if ($testDAO->find(TRUE)) {
391 $this->_testID
= $testDAO->id
;
393 foreach ($this->_fields
as $field) {
394 $testName = "test_{$field['name']}";
395 $defaults[$testName] = $testDAO->{$field['name']};
398 $defaults['financial_account_id'] = CRM_Contribute_PseudoConstant
::getRelationalFinancialAccount($dao->id
, NULL, 'civicrm_payment_processor');
404 * Process the form submission.
406 * @throws \CiviCRM_API3_Exception
407 * @throws \CRM_Core_Exception
409 public function postProcess() {
411 if ($this->_action
& CRM_Core_Action
::DELETE
) {
412 CRM_Financial_BAO_PaymentProcessor
::del($this->_id
);
413 CRM_Core_Session
::setStatus("", ts('Payment Processor Deleted.'), "success");
417 $values = $this->controller
->exportValues($this->_name
);
418 $domainID = CRM_Core_Config
::domainID();
420 if (!empty($values['is_default'])) {
421 $query = "UPDATE civicrm_payment_processor SET is_default = 0 WHERE domain_id = $domainID";
422 CRM_Core_DAO
::executeQuery($query);
425 if ($this->_paymentProcessorType
!== $values['payment_processor_type_id']) {
426 // If we changed the payment processor type, need to update the object as well
427 $this->_paymentProcessorType
= $values['payment_processor_type_id'];
428 $this->_paymentProcessorDAO
= new CRM_Financial_DAO_PaymentProcessorType();
429 $this->_paymentProcessorDAO
->id
= $values['payment_processor_type_id'];
430 $this->_paymentProcessorDAO
->find(TRUE);
432 $this->updatePaymentProcessor($values, $domainID, FALSE);
433 $this->updatePaymentProcessor($values, $domainID, TRUE);
435 $processor = civicrm_api3('payment_processor', 'getsingle', ['name' => $values['name'], 'is_test' => 0]);
436 $errors = Civi\Payment\System
::singleton()->checkProcessorConfig($processor);
438 CRM_Core_Session
::setStatus($errors, ts('Payment processor configuration invalid'), 'error');
439 Civi
::log()->error('Payment processor configuration invalid: ' . $errors);
440 CRM_Core_Session
::singleton()->pushUserContext($this->refreshURL
);
443 CRM_Core_Session
::setStatus(ts('Payment processor %1 has been saved.', [1 => "<em>{$values['name']}</em>"]), ts('Saved'), 'success');
448 * Save a payment processor.
450 * @param array $values
451 * @param int $domainID
454 * @throws \CiviCRM_API3_Exception
456 public function updatePaymentProcessor(&$values, $domainID, $test) {
458 foreach (['user_name', 'password', 'signature', 'url_site', 'url_recur', 'url_api', 'url_button', 'subject'] as $field) {
459 $values[$field] = empty($values["test_{$field}"]) ? CRM_Utils_Array
::value($field, $values) : $values["test_{$field}"];
462 if (!empty($values['accept_credit_cards'])) {
464 $accptedCards = array_keys($values['accept_credit_cards']);
465 $creditCardTypes = CRM_Contribute_PseudoConstant
::creditCard();
466 foreach ($creditCardTypes as $type => $val) {
467 if (in_array($type, $accptedCards)) {
468 $creditCards[$type] = $creditCardTypes[$type];
471 $creditCards = json_encode($creditCards);
474 $creditCards = "NULL";
476 $params = array_merge([
477 'id' => $test ?
$this->_testID
: $this->_id
,
478 'domain_id' => $domainID,
482 'is_recur' => $this->_paymentProcessorDAO
->is_recur
,
483 'billing_mode' => $this->_paymentProcessorDAO
->billing_mode
,
484 'class_name' => $this->_paymentProcessorDAO
->class_name
,
485 'payment_type' => $this->_paymentProcessorDAO
->payment_type
,
486 'payment_instrument_id' => $this->_paymentProcessorDAO
->payment_instrument_id
,
487 'financial_account_id' => $values['financial_account_id'],
488 'accepted_credit_cards' => $creditCards,
491 civicrm_api3('PaymentProcessor', 'create', $params);
495 * Set the payment processor type id as a form property
497 * @throws \CRM_Core_Exception
499 protected function setPaymentProcessorTypeID(): void
{
501 $this->_paymentProcessorType
= CRM_Utils_Request
::retrieve('pp', 'String', $this, FALSE, NULL);
502 if (!$this->_paymentProcessorType
) {
503 $this->_paymentProcessorType
= CRM_Core_DAO
::getFieldValue('CRM_Financial_DAO_PaymentProcessor',
505 'payment_processor_type_id'
508 $this->set('pp', $this->_paymentProcessorType
);
511 $this->_paymentProcessorType
= CRM_Utils_Request
::retrieve('pp', 'String', $this, TRUE, NULL);
516 * Get the relevant payment processor type id.
520 protected function getPaymentProcessorTypeID(): int {
521 return (int) $this->_paymentProcessorType
;
525 * Set the payment processor as a form property.
527 protected function setPaymentProcessor(): void
{
528 $this->_paymentProcessorDAO
= new CRM_Financial_DAO_PaymentProcessorType();
529 $this->_paymentProcessorDAO
->id
= $this->getPaymentProcessorTypeID();
530 $this->_paymentProcessorDAO
->find(TRUE);