Skip to content

Multiple fixes for PaypalRest #166

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion CRM/Core/Payment/OmnipayMultiProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,12 @@ public function doPayment(&$params, $component = 'contribute') {
$this->initialize($params);
$this->saveBillingAddressIfRequired($params);

// "token" only gets set when coming in via a contribution page.
// Otherwise we need to set it from the actual parameter that's set on the form
if (!empty($params['paymentToken']) && empty($params['token'])) {
$params['token'] = $params['paymentToken'];
}

try {
if (!empty($params['token'])) {
$response = $this->doTokenPayment($params);
Expand Down Expand Up @@ -325,7 +331,13 @@ public function buildForm(&$form) {
$jsVariables[$clientSideKey] = $this->_paymentProcessor[$key];
}
}
CRM_Core_Resources::singleton()->addVars('omnipay', $jsVariables);

\Civi::resources()->addVars('omnipay', $jsVariables);
// Assign to smarty so we can add via tpl for drupal webform / default processor on contribution page because addVars doesn't work in that context
// until https://github.com/civicrm/civicrm-core/pull/18141 is merged
// Then we can set 'billing-block' above and remove the assign/tpl
$form->assign('omnipayJSVars', $jsVariables);

if (is_array($regions)) {
foreach ($regions as $region => $additions) {
foreach ($additions as $addition) {
Expand Down
124 changes: 124 additions & 0 deletions CRM/Omnipaymultiprocessor/Check.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
<?php
/*
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC. All rights reserved. |
| |
| This work is published under the GNU AGPLv3 license with some |
| permitted exceptions and without any warranty. For full license |
| and copyright information, see https://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/

use CRM_Omnipaymultiprocessor_ExtensionUtil as E;

/**
* Class CRM_Omnipaymultiprocessor_Check
*/
class CRM_Omnipaymultiprocessor_Check {

/**
* @var string
*/
const MIN_VERSION_MJWSHARED = '1.2.9';

/**
* @var array
*/
private $messages;

/**
* constructor.
*
* @param $messages
*/
public function __construct($messages) {
$this->messages = $messages;
}

public function checkRequirements() {
$this->checkExtensionMjwshared();
return $this->messages;
}

/**
* @param string $extensionName
* @param string $minVersion
* @param string $actualVersion
*/
private function requireExtensionMinVersion($extensionName, $minVersion, $actualVersion) {
$actualVersionModified = $actualVersion;
if (substr($actualVersion, -4) === '-dev') {
$message = new CRM_Utils_Check_Message(
__FUNCTION__ . $extensionName . E::SHORT_NAME . '_requirements_dev',
E::ts('You are using a development version of %1 extension.',
[1 => $extensionName]),
E::ts('%1: Development version', [1 => $extensionName]),
\Psr\Log\LogLevel::WARNING,
'fa-code'
);
$this->messages[] = $message;
$actualVersionModified = substr($actualVersion, 0, -4);
}

if (version_compare($actualVersionModified, $minVersion) === -1) {
$message = new CRM_Utils_Check_Message(
__FUNCTION__ . $extensionName . E::SHORT_NAME . '_requirements',
E::ts('The %1 extension requires the %2 extension version %3 or greater but your system has version %4.',
[
1 => ucfirst(E::SHORT_NAME),
2 => $extensionName,
3 => $minVersion,
4 => $actualVersion
]),
E::ts('%1: Missing Requirements', [1 => ucfirst(E::SHORT_NAME)]),
\Psr\Log\LogLevel::ERROR,
'fa-exclamation-triangle'
);
$message->addAction(
E::ts('Upgrade now'),
NULL,
'href',
['path' => 'civicrm/admin/extensions', 'query' => ['action' => 'update', 'id' => $extensionName, 'key' => $extensionName]]
);
$this->messages[] = $message;
}
}

/**
* @throws \CiviCRM_API3_Exception
*/
private function checkExtensionMjwshared() {
// mjwshared: required. Requires min version
$extensionName = 'mjwshared';
$extensions = civicrm_api3('Extension', 'get', [
'full_name' => $extensionName,
]);

if (empty($extensions['count']) || ($extensions['values'][$extensions['id']]['status'] !== 'installed')) {
$message = new CRM_Utils_Check_Message(
__FUNCTION__ . E::SHORT_NAME . '_requirements',
E::ts('The <em>%1</em> extension requires the <em>Payment Shared</em> extension which is not installed. See <a href="%2" target="_blank">details</a> for more information.',
[
1 => ucfirst(E::SHORT_NAME),
2 => 'https://civicrm.org/extensions/mjwshared',
]
),
E::ts('%1: Missing Requirements', [1 => ucfirst(E::SHORT_NAME)]),
\Psr\Log\LogLevel::ERROR,
'fa-money'
);
$message->addAction(
E::ts('Install now'),
NULL,
'href',
['path' => 'civicrm/admin/extensions', 'query' => ['action' => 'update', 'id' => $extensionName, 'key' => $extensionName]]
);
$this->messages[] = $message;
return;
}
if (isset($extensions['id']) && $extensions['values'][$extensions['id']]['status'] === 'installed') {
$this->requireExtensionMinVersion($extensionName, self::MIN_VERSION_MJWSHARED, $extensions['values'][$extensions['id']]['version']);
}
}

}
94 changes: 77 additions & 17 deletions Metadata/js/omnipay_PaypalRest.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,62 @@
// @see https://developer.paypal.com/docs/checkout/integrate/
(function($) {
var form = $('#billing-payment-block').closest('form');
var qfKey = $('[name=qfKey]', form).val();
var scriptName = 'omnipayPaypal';

if (typeof CRM.vars.omnipay === 'undefined') {
CRM.payment.debugging(scriptName, 'CRM.vars.omnipay not defined! Not a Omnipay processor?');
return;
}

function renderPaypal() {
paypal.Buttons({


onInit: function(data, actions) {

// On webform, hide the submit button as it's triggered automatically
if (CRM.$('[type="submit"].webform-submit').length !== 0) {
$('[type="submit"].webform-submit').hide();
}

$('[type="submit"][formnovalidate="1"]',
'[type="submit"][formnovalidate="formnovalidate"]',
'[type="submit"].cancel',
'[type="submit"].webform-previous'
).on('click', function() {
CRM.payment.debugging(scriptName, 'adding submitdontprocess: ' + this.id);
CRM.payment.form.dataset.submitdontprocess = 'true';
});

$(CRM.payment.getBillingSubmit()).on('click', function() {
CRM.payment.debugging(scriptName, 'clearing submitdontprocess');
CRM.payment.form.dataset.submitdontprocess = 'false';
});

$(CRM.payment.form).on('submit', function(event) {
if (CRM.payment.form.dataset.submitdontprocess === 'true') {
CRM.payment.debugging(scriptName, 'non-payment submit detected - not submitting payment');
event.preventDefault();
return true;
}
if (document.getElementById('payment_token') && (document.getElementById('payment_token').value !== 'Authorisation token') &&
document.getElementById('PayerID') && (document.getElementById('PayerID').value !== 'Payer ID')) {
return true;
}
CRM.payment.debugging(scriptName, 'Unable to submit - paypal not executed');
event.preventDefault();
return true;
});

// Set up the buttons.
if (form.valid()) {
actions.enable()
if ($(CRM.payment.form).valid()) {
actions.enable();
}
else {
actions.disable();
}

form.on('blur keyup change', 'input', function (event) {
if (form.valid()) {
actions.enable()
$(CRM.payment.form).on('blur keyup change', 'input', function (event) {
if ($(CRM.payment.form).valid()) {
actions.enable();
}
else {
actions.disable();
Expand All @@ -28,23 +66,41 @@

createBillingAgreement: function (data, actions) {

// CRM.payment.getTotalAmount is implemented by webform_civicrm and mjwshared. The plan is to
// add CRM.payment.getTotalAmount() into CiviCRM core. This code allows it to work under any of
// these circumstances as well as if CRM.payment does not exist.
var totalAmount = 0.0;
if ((typeof CRM.payment !== 'undefined') && (CRM.payment.hasOwnProperty('getTotalAmount'))) {
totalAmount = CRM.payment.getTotalAmount();
}
else if (typeof calculateTotalFee == 'function') {
// This is ONLY triggered in the following circumstances on a CiviCRM contribution page:
// - With a priceset that allows a 0 amount to be selected.
// - When we are the ONLY payment processor configured on the page.
totalAmount = parseFloat(calculateTotalFee());
}
else if (document.getElementById('total_amount')) {
// The input#total_amount field exists on backend contribution forms
totalAmount = parseFloat(document.getElementById('total_amount').value);
}

var frequencyInterval = $('#frequency_interval').val() || 1;
var frequencyUnit = $('#frequency_unit').val() ? $('#frequency_interval').val() : CRM.vars.omnipay.frequency_unit;
var paymentAmount = calculateTotalFee();
var isRecur = $('#is_recur').is(":checked");
var recurText = isRecur ? ' recurring' : '';
var qfKey = $('[name=qfKey]', $(CRM.payment.form)).val();

return new Promise(function (resolve, reject) {
CRM.api3('PaymentProcessor', 'preapprove', {
'payment_processor_id': CRM.vars.omnipay.paymentProcessorId,
'amount': paymentAmount,
'amount': totalAmount,
'currencyID' : CRM.vars.omnipay.currency,
'qf_key': qfKey,
'is_recur' : isRecur,
'installments' : $('#installments').val(),
'frequency_unit' : frequencyUnit,
'frequency_interval' : frequencyInterval,
'description' : CRM.vars.omnipay.title + ' ' + CRM.formatMoney(paymentAmount) + recurText,
'description' : CRM.vars.omnipay.title + ' ' + CRM.formatMoney(totalAmount) + recurText,
}
).then(function (result) {
if (result['is_error'] === 1) {
Expand All @@ -63,21 +119,25 @@

onApprove: function (data, actions) {
var isRecur = 1;
var paymentToken = data['billingToken'];
var paymentToken = data.billingToken;
if (!paymentToken) {
paymentToken = data['paymentID'];
paymentToken = data.paymentID;
isRecur = 0;
}

document.getElementById('paypal-button-container').style.visibility = "hidden";
document.getElementById('crm-submit-buttons').style.display = 'block';
document.getElementById('PayerID').value = data['payerID'];
var crmSubmitButtons = document.getElementById('crm-submit-buttons');
if (crmSubmitButtons) {
crmSubmitButtons.style.display = 'block';
}
document.getElementById('PayerID').value = data.payerID;
document.getElementById('payment_token').value = paymentToken;
form.submit();

CRM.$(CRM.payment.getBillingSubmit()).click();
},

onError: function(err) {
console.log(err);
CRM.payment.debugging(scriptName, err);
alert('Site is not correctly configured to process payments');
}

Expand Down
19 changes: 8 additions & 11 deletions Metadata/omnipay_PaypalRest.mgd.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@
* database as appropriate. For more details, see "hook_civicrm_managed" at:
* http://wiki.civicrm.org/confluence/display/CRMDOC/Hook+Reference
*/

use CRM_Omnipaymultiprocessor_ExtensionUtil as E;

return [
[
'name' => 'PayPal Checkout',
Expand All @@ -71,13 +74,14 @@
'url_site_test_default' => 'http://unused.com',
'url_recur_test_default' => 'http://unused.com',
'url_api_test_default' => 'http://unused.com',
'billing_mode' => 4,
'billing_mode' => 1,
'payment_type' => 1,
'is_recur' => 1,
],
'metadata' => [
'suppress_submit_button' => 1,
'supports_preapproval' => 1,
'fields' => ['billing_fields' => []],
'payment_fields' => ['payment_token', 'PayerID', 'post_authorize'],
'pass_through_fields' => [
'referrerCode' => 'CiviCRM_SP',
Expand Down Expand Up @@ -114,16 +118,9 @@
'regions' => [
//'billing-block-post' => [],
'billing-block' => [
[
'markup' => '<div id="paypal-button-container" class="crm-paypal-buttons"></div>',
'name' => 'paypal_button',
'weight' => 400,
],
[
'name' => 'paypal_script',
'weight' => 500,
'script' => file_get_contents(__DIR__ . '/js/omnipay_PaypalRest.js'),
],
['markup' => '<div id="paypal-button-container" class="crm-paypal-buttons"></div>', 'name' => 'paypal_button', 'weight' => 400],
['template' => E::path('templates/CRM/Omnipaymultiprocessor/Form/OmnipayResource.tpl'), 'region' => 'billing-block', 'weight' => -1],
['name' => 'paypal_script', 'weight' => 500, 'scriptUrl' => \Civi::resources()->addCacheCode(E::url('Metadata/js/omnipay_PaypalRest.js'))]
],
],
],
Expand Down
15 changes: 12 additions & 3 deletions omnipaymultiprocessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,18 +104,27 @@ function omnipaymultiprocessor_civicrm_preProcess($formName, &$form) {
$form->assign('isJsValidate', TRUE);
if (!empty($form->_values['is_recur'])) {
$recurOptions = [
'is_recur_interval' => $form->_values['is_recur_interval'],
'is_recur_interval' => $form->_values['is_recur_interval'],
'frequency_unit' => $form->_values['recur_frequency_unit'],
'is_recur_installments' => $form->_values['is_recur_installments'],
];

if (!$recurOptions['is_recur_interval']) {
$recurOptions['frequency_interval'] = 1;
}
CRM_Core_Resources::singleton()->addVars(
CRM_Core_Resources::singleton()->addVars(
'omnipay', $recurOptions
);
);
}
}
}

/**
* Implements hook_civicrm_check().
*
* @throws \CiviCRM_API3_Exception
*/
function omnipaymultiprocessor_civicrm_check(&$messages) {
$checks = new CRM_Omnipaymultiprocessor_Check($messages);
$messages = $checks->checkRequirements();
}
Loading