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
;
24 protected $_paymentProcessorDAO;
28 * Payment processor Type ID
30 protected $_paymentProcessorType;
33 * Fields for the entity to be assigned to the template.
35 * Fields may have keys
36 * - name (required to show in tpl from the array)
37 * - description (optional, will appear below the field)
38 * Auto-added by setEntityFieldsMetadata unless specified here (use description => '' to hide)
39 * - not-auto-addable - this class will not attempt to add the field using addField.
40 * (this will be automatically set if the field does not have html in it's metadata
41 * or is not a core field on the form's entity).
42 * - help (option) add help to the field - e.g ['id' => 'id-source', 'file' => 'CRM/Contact/Form/Contact']]
43 * - template - use a field specific template to render this field
45 * - is_freeze (field should be frozen).
49 protected $entityFields = [];
52 * Set entity fields to be assigned to the form.
54 protected function setEntityFields() {
55 $this->entityFields
= [
56 'payment_processor_type_id' => [
57 'name' => 'payment_processor_type_id',
68 'name' => 'description',
72 $this->setEntityFieldsMetadata();
76 * Get the name of the base entity being edited.
80 public function getDefaultEntity() {
81 return 'PaymentProcessor';
85 * Set the delete message.
87 * We do this from the constructor in order to do a translation.
89 public function setDeleteMessage() {
90 $this->deleteMessage
= ts('Deleting this Payment Processor may result in some transaction pages being rendered inactive.') . ' ' . ts('Do you want to continue?');
93 public function preProcess() {
97 $this->_paymentProcessorType
= CRM_Utils_Request
::retrieve('pp', 'String', $this, FALSE, NULL);
98 if (!$this->_paymentProcessorType
) {
99 $this->_paymentProcessorType
= CRM_Core_DAO
::getFieldValue('CRM_Financial_DAO_PaymentProcessor',
101 'payment_processor_type_id'
104 $this->set('pp', $this->_paymentProcessorType
);
107 $this->_paymentProcessorType
= CRM_Utils_Request
::retrieve('pp', 'String', $this, TRUE, NULL);
110 $this->assign('ppType', $this->_paymentProcessorType
);
111 $ppTypeName = CRM_Core_DAO
::getFieldValue('CRM_Financial_DAO_PaymentProcessorType',
112 $this->_paymentProcessorType
,
115 $this->assign('ppTypeName', $ppTypeName);
117 $this->_paymentProcessorDAO
= new CRM_Financial_DAO_PaymentProcessorType();
118 $this->_paymentProcessorDAO
->id
= $this->_paymentProcessorType
;
120 $this->_paymentProcessorDAO
->find(TRUE);
123 $refreshURL = CRM_Utils_System
::url('civicrm/admin/paymentProcessor',
124 "reset=1&action=update&id={$this->_id}",
129 $refreshURL = CRM_Utils_System
::url('civicrm/admin/paymentProcessor',
130 "reset=1&action=add",
136 $destination = CRM_Utils_Request
::retrieve('civicrmDestination', 'String', $this);
138 $destination = urlencode($destination);
139 $refreshURL .= "&civicrmDestination=$destination";
142 $this->refreshURL
= $refreshURL;
143 $this->assign('refreshURL', $refreshURL);
145 $this->assign('is_recur', $this->_paymentProcessorDAO
->is_recur
);
149 'name' => 'user_name',
150 'label' => $this->_paymentProcessorDAO
->user_name_label
,
153 'name' => 'password',
154 'label' => $this->_paymentProcessorDAO
->password_label
,
157 'name' => 'signature',
158 'label' => $this->_paymentProcessorDAO
->signature_label
,
162 'label' => $this->_paymentProcessorDAO
->subject_label
,
165 'name' => 'url_site',
166 'label' => ts('Site URL'),
168 'msg' => ts('Enter a valid URL'),
172 if ($this->_paymentProcessorDAO
->is_recur
) {
174 'name' => 'url_recur',
175 'label' => ts('Recurring Payments URL'),
177 'msg' => ts('Enter a valid URL'),
181 if (!empty($this->_paymentProcessorDAO
->url_button_default
)) {
183 'name' => 'url_button',
184 'label' => ts('Button URL'),
186 'msg' => ts('Enter a valid URL'),
190 if (!empty($this->_paymentProcessorDAO
->url_api_default
)) {
193 'label' => ts('API URL'),
195 'msg' => ts('Enter a valid URL'),
201 * Build the form object.
205 public function buildQuickForm($check = FALSE) {
206 $this->buildQuickEntityForm();
208 if ($this->isDeleteContext()) {
212 $attributes = CRM_Core_DAO
::getAttribute('CRM_Financial_DAO_PaymentProcessor');
214 $this->addRule('name', ts('Name already exists in Database.'), 'objectExists', [
215 'CRM_Financial_DAO_PaymentProcessor',
218 CRM_Core_Config
::domainID(),
221 // @todo - remove this & let the entityForm do it - need to make sure we are handling the js though.
223 'payment_processor_type_id',
224 ts('Payment Processor Type'),
225 CRM_Financial_BAO_PaymentProcessor
::buildOptions('payment_processor_type_id'),
227 ['onchange' => "reload(true)"]
230 // Financial Account of account type asset CRM-11515
231 $accountType = CRM_Core_PseudoConstant
::accountOptionValues('financial_account_type', NULL, " AND v.name = 'Asset' ");
232 $financialAccount = CRM_Contribute_PseudoConstant
::financialAccount(NULL, key($accountType));
233 if ($fcount = count($financialAccount)) {
234 $this->assign('financialAccount', $fcount);
236 $this->add('select', 'financial_account_id', ts('Financial Account'),
237 ['' => ts('- select -')] +
$financialAccount,
240 $this->addSelect('payment_instrument_id',
242 'entity' => 'contribution',
243 'label' => ts('Payment Method'),
244 'placeholder' => NULL,
248 // is this processor active ?
249 $this->add('checkbox', 'is_active', ts('Is this Payment Processor active?'));
250 $this->add('checkbox', 'is_default', ts('Is this Payment Processor the default?'));
251 $creditCardTypes = CRM_Contribute_PseudoConstant
::creditCard();
252 $this->addCheckBox('accept_credit_cards', ts('Accepted Credit Card Type(s)'),
253 $creditCardTypes, NULL, NULL, NULL, NULL, ' ');
254 foreach ($this->_fields
as $field) {
255 if (empty($field['label'])) {
259 $this->addField($field['name'], ['label' => $field['label']]);
261 $fieldSpec = civicrm_api3($this->getDefaultEntity(), 'getfield', [
262 'name' => $field['name'],
263 'action' => 'create',
265 $this->add($fieldSpec['values']['html']['type'], "test_{$field['name']}",
266 $field['label'], $attributes[$field['name']]
268 if (!empty($field['rule'])) {
269 $this->addRule($field['name'], $field['msg'], $field['rule']);
270 $this->addRule("test_{$field['name']}", $field['msg'], $field['rule']);
274 $this->addFormRule(['CRM_Admin_Form_PaymentProcessor', 'formRule']);
282 public static function formRule($fields) {
284 // make sure that at least one of live or test is present
285 // and we have at least name and url_site
286 // would be good to make this processor specific
289 if (!(self
::checkSection($fields, $errors) ||
290 self
::checkSection($fields, $errors, 'test')
293 $errors['_qf_default'] = ts('You must have at least the test or live section filled');
296 if (!empty($errors)) {
300 return empty($errors) ?
TRUE : $errors;
306 * @param null $section
310 public static function checkSection(&$fields, &$errors, $section = NULL) {
311 $names = ['user_name'];
315 foreach ($names as $name) {
317 $name = "{$section}_$name";
319 if (!empty($fields[$name])) {
329 $errors['_qf_default'] = ts('You must have at least the user_name specified');
338 public function setDefaultValues() {
342 $defaults['is_active'] = $defaults['is_default'] = 1;
343 $defaults['url_site'] = $this->_paymentProcessorDAO
->url_site_default
;
344 $defaults['url_api'] = $this->_paymentProcessorDAO
->url_api_default
;
345 $defaults['url_recur'] = $this->_paymentProcessorDAO
->url_recur_default
;
346 $defaults['url_button'] = $this->_paymentProcessorDAO
->url_button_default
;
347 $defaults['test_url_site'] = $this->_paymentProcessorDAO
->url_site_test_default
;
348 $defaults['test_url_api'] = $this->_paymentProcessorDAO
->url_api_test_default
;
349 $defaults['test_url_recur'] = $this->_paymentProcessorDAO
->url_recur_test_default
;
350 $defaults['test_url_button'] = $this->_paymentProcessorDAO
->url_button_test_default
;
351 $defaults['payment_instrument_id'] = $this->_paymentProcessorDAO
->payment_instrument_id
;
352 // When user changes payment processor type, it is passed in via $this->_ppType so update defaults array.
353 if ($this->_paymentProcessorType
) {
354 $defaults['payment_processor_type_id'] = $this->_paymentProcessorType
;
356 $defaults['financial_account_id'] = CRM_Financial_BAO_PaymentProcessor
::getDefaultFinancialAccountID();
359 $domainID = CRM_Core_Config
::domainID();
361 $dao = new CRM_Financial_DAO_PaymentProcessor();
362 $dao->id
= $this->_id
;
363 $dao->domain_id
= $domainID;
364 if (!$dao->find(TRUE)) {
368 CRM_Core_DAO
::storeValues($dao, $defaults);
369 // If payment processor ID does not exist, $paymentProcessorName will be FALSE
370 $paymentProcessorName = CRM_Core_PseudoConstant
::getName('CRM_Financial_BAO_PaymentProcessor', 'payment_processor_type_id', $this->_paymentProcessorType
);
371 if ($this->_paymentProcessorType
&& $paymentProcessorName) {
372 // When user changes payment processor type, it is passed in via $this->_ppType so update defaults array.
373 $defaults['payment_processor_type_id'] = $this->_paymentProcessorType
;
376 CRM_Core_Session
::setStatus('Payment Processor Type (ID=' . $this->_paymentProcessorType
. ') not found. Did you disable the payment processor extension?', 'Missing Payment Processor', 'alert');
379 $cards = json_decode(CRM_Core_DAO
::getFieldValue('CRM_Financial_DAO_PaymentProcessor',
381 'accepted_credit_cards'
384 if (!empty($cards)) {
385 foreach ($cards as $card => $val) {
386 $acceptedCards[$card] = 1;
389 $defaults['accept_credit_cards'] = $acceptedCards;
390 unset($defaults['accepted_credit_cards']);
392 $testDAO = new CRM_Financial_DAO_PaymentProcessor();
393 $testDAO->name
= $dao->name
;
394 $testDAO->is_test
= 1;
395 $testDAO->domain_id
= $domainID;
396 if ($testDAO->find(TRUE)) {
397 $this->_testID
= $testDAO->id
;
399 foreach ($this->_fields
as $field) {
400 $testName = "test_{$field['name']}";
401 $defaults[$testName] = $testDAO->{$field['name']};
404 $defaults['financial_account_id'] = CRM_Contribute_PseudoConstant
::getRelationalFinancialAccount($dao->id
, NULL, 'civicrm_payment_processor');
410 * Process the form submission.
412 * @throws \CiviCRM_API3_Exception
413 * @throws \CRM_Core_Exception
415 public function postProcess() {
417 if ($this->_action
& CRM_Core_Action
::DELETE
) {
418 CRM_Financial_BAO_PaymentProcessor
::del($this->_id
);
419 CRM_Core_Session
::setStatus("", ts('Payment Processor Deleted.'), "success");
423 $values = $this->controller
->exportValues($this->_name
);
424 $domainID = CRM_Core_Config
::domainID();
426 if (!empty($values['is_default'])) {
427 $query = "UPDATE civicrm_payment_processor SET is_default = 0 WHERE domain_id = $domainID";
428 CRM_Core_DAO
::executeQuery($query);
431 if ($this->_paymentProcessorType
!== $values['payment_processor_type_id']) {
432 // If we changed the payment processor type, need to update the object as well
433 $this->_paymentProcessorType
= $values['payment_processor_type_id'];
434 $this->_paymentProcessorDAO
= new CRM_Financial_DAO_PaymentProcessorType();
435 $this->_paymentProcessorDAO
->id
= $values['payment_processor_type_id'];
436 $this->_paymentProcessorDAO
->find(TRUE);
438 $this->updatePaymentProcessor($values, $domainID, FALSE);
439 $this->updatePaymentProcessor($values, $domainID, TRUE);
441 $processor = civicrm_api3('payment_processor', 'getsingle', ['name' => $values['name'], 'is_test' => 0]);
442 $errors = Civi\Payment\System
::singleton()->checkProcessorConfig($processor);
444 CRM_Core_Session
::setStatus($errors, 'Payment processor configuration invalid', 'error');
445 Civi
::log()->error('Payment processor configuration invalid: ' . $errors);
446 CRM_Core_Session
::singleton()->pushUserContext($this->refreshURL
);
449 CRM_Core_Session
::setStatus(ts('Payment processor %1 has been saved.', [1 => "<em>{$values['name']}</em>"]), ts('Saved'), 'success');
454 * Save a payment processor.
456 * @param array $values
457 * @param int $domainID
460 * @throws \CiviCRM_API3_Exception
462 public function updatePaymentProcessor(&$values, $domainID, $test) {
464 foreach (['user_name', 'password', 'signature', 'url_site', 'url_recur', 'url_api', 'url_button', 'subject'] as $field) {
465 $values[$field] = empty($values["test_{$field}"]) ? CRM_Utils_Array
::value($field, $values) : $values["test_{$field}"];
468 if (!empty($values['accept_credit_cards'])) {
470 $accptedCards = array_keys($values['accept_credit_cards']);
471 $creditCardTypes = CRM_Contribute_PseudoConstant
::creditCard();
472 foreach ($creditCardTypes as $type => $val) {
473 if (in_array($type, $accptedCards)) {
474 $creditCards[$type] = $creditCardTypes[$type];
477 $creditCards = json_encode($creditCards);
480 $creditCards = "NULL";
482 $params = array_merge([
483 'id' => $test ?
$this->_testID
: $this->_id
,
484 'domain_id' => $domainID,
488 'is_recur' => $this->_paymentProcessorDAO
->is_recur
,
489 'billing_mode' => $this->_paymentProcessorDAO
->billing_mode
,
490 'class_name' => $this->_paymentProcessorDAO
->class_name
,
491 'payment_type' => $this->_paymentProcessorDAO
->payment_type
,
492 'payment_instrument_id' => $this->_paymentProcessorDAO
->payment_instrument_id
,
493 'financial_account_id' => $values['financial_account_id'],
494 'accepted_credit_cards' => $creditCards,
497 civicrm_api3('PaymentProcessor', 'create', $params);