diff --git a/wwwroot/sites/all/modules/commerce_paypal/commerce_paypal.module b/wwwroot/sites/all/modules/commerce_paypal/commerce_paypal.module index 5917f90..0907c5b 100644 --- a/wwwroot/sites/all/modules/commerce_paypal/commerce_paypal.module +++ b/wwwroot/sites/all/modules/commerce_paypal/commerce_paypal.module @@ -320,7 +320,7 @@ function commerce_paypal_api_request($payment_method, $nvp = array(), $order = N drupal_alter('commerce_paypal_api_request', $nvp, $order, $payment_method); // Log the request if specified. - if ($payment_method['settings']['log']['request'] == 'request') { + if ($payment_method['settings']['log']['request'] === 'request') { // Mask the credit card number and CVV. $log_nvp = $nvp; $log_nvp['PWD'] = str_repeat('X', strlen($log_nvp['PWD'])); @@ -385,7 +385,7 @@ function commerce_paypal_api_request($payment_method, $nvp = array(), $order = N } // Log the response if specified. - if ($payment_method['settings']['log']['response'] == 'response') { + if ($payment_method['settings']['log']['response'] === 'response') { watchdog('commerce_paypal', 'PayPal server response: !param', array('!param' => '
' . check_plain(print_r($response, TRUE)) . '', WATCHDOG_DEBUG)); } @@ -445,7 +445,7 @@ function commerce_paypal_rest_api_request($payment_method, $rest = array(), $par drupal_alter('commerce_paypal_rest_api_request', $params, $order, $payment_method); // Log the request if specified. - if ($payment_method['settings']['log']['request'] == 'request') { + if ($payment_method['settings']['log']['request'] === 'request') { // Sanitize the request to mask CC number, CVV, and account info. // This has been turned into a separate function for potential re-use and @@ -461,7 +461,7 @@ function commerce_paypal_rest_api_request($payment_method, $rest = array(), $par $json_error = json_last_error(); // Make sure someone didn't pass us a bogus array to json_encode(). if (!$rest_json && $json_error !== JSON_ERROR_NONE) { - $log_params = commerce_paypal_sanitize_api_params($params); + $log_params = commerce_paypal_sanitize_rest_api_params($params); watchdog('commerce_paypal', 'PayPal REST API request failed to json_encode(): !param', array('!param' => '
' . check_plain(print_r(array('Rest API' => $rest,'Params' => $log_params), TRUE)) . ''), WATCHDOG_ERROR);
return FALSE;
}
@@ -522,7 +522,7 @@ function commerce_paypal_rest_api_request($payment_method, $rest = array(), $par
$response->data = json_decode($response_body);
// Log the response if specified.
- if ($payment_method['settings']['log']['response'] == 'response') {
+ if ($payment_method['settings']['log']['response'] === 'response') {
watchdog('commerce_paypal', 'PayPal server response: !param', array('!param' => '' . check_plain(print_r($response, TRUE)) . '', WATCHDOG_DEBUG)); } @@ -561,7 +561,8 @@ function commerce_paypal_rest_api_token_fetch($payment_method, $params) { curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_NOPROGRESS, 1); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0); - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1); + curl_setopt($ch, CURLOPT_FAILONERROR, TRUE); if (variable_get('commerce_paypal_cacert', FALSE)) { curl_setopt($ch, CURLOPT_CAINFO, variable_get('commerce_paypal_cacert', '')); @@ -585,11 +586,11 @@ function commerce_paypal_rest_api_token_fetch($payment_method, $params) { function commerce_paypal_sanitize_param(&$param, $key) { switch ($key) { case 'number': - $value = str_repeat('X', strlen($value) - 4) . substr($value, -4); + $param = str_repeat('X', strlen($param) - 4) . substr($param, -4); break; case 'cvv2': case 'cvv': - $value = str_repeat('X', strlen($value)); + $param = str_repeat('X', strlen($param)); break; } } diff --git a/wwwroot/sites/all/modules/commerce_paypal/modules/vault/commerce_paypal_vault.module b/wwwroot/sites/all/modules/commerce_paypal/modules/vault/commerce_paypal_vault.module index f8a3b5a..b06dc28 100644 --- a/wwwroot/sites/all/modules/commerce_paypal/modules/vault/commerce_paypal_vault.module +++ b/wwwroot/sites/all/modules/commerce_paypal/modules/vault/commerce_paypal_vault.module @@ -18,9 +18,6 @@ function commerce_paypal_vault_commerce_payment_method_info_alter(&$methods) { if (module_exists('commerce_paypal_wpp') && isset($methods['paypal_wpp'])) { $methods['paypal_wpp']['cardonfile'] = array( 'create callback' => 'commerce_paypal_vault_cardonfile_create', - // @todo: This callback is implemented but it doesn't work because there - // is no documentation on the PATCH method via the PayPal REST API. - // Argh. 'update callback' => 'commerce_paypal_vault_cardonfile_update', 'delete callback' => 'commerce_paypal_vault_cardonfile_delete', 'charge callback' => 'commerce_paypal_vault_cardonfile_charge', @@ -35,8 +32,6 @@ function commerce_paypal_vault_cardonfile_create($form, $form_state, $payment_me $card_number = $form_state['values']['credit_card']['number']; $card_expire_month = $form_state['values']['credit_card']['exp_month']; $card_expire_year = $form_state['values']['credit_card']['exp_year']; - $card_expire = $card_expire_year . '-' . $card_expire_month; - $card_code = $form_state['values']['credit_card']['code']; $card_type = $form_state['values']['credit_card']['type']; $card_owner = $form_state['values']['credit_card']['owner']; $name_fragments = explode(' ', $card_owner); @@ -54,7 +49,7 @@ function commerce_paypal_vault_cardonfile_create($form, $form_state, $payment_me 'last_name' => $last_name, ); $rest = array( - 'endpoint' => 'vault/credit-card', + 'endpoint' => 'vault/credit-cards', 'method' => 'POST', 'version' => 'v1', ); @@ -62,17 +57,17 @@ function commerce_paypal_vault_cardonfile_create($form, $form_state, $payment_me $response = commerce_paypal_rest_api_request($payment_method, $rest, $params); // @todo: This needs much better error handling based on the PayPal response. - if (!$response || $response->code != '201') { - // Our request failed. Whoops. - return FALSE; - drupal_set_message(t('This card was not able to be added. Please contact the site administrator for additional information.'), 'error'); - } - else { + if ($response && $response->code == '201') { // Op success! $card->remote_id = $response->data->id; $card->card_name = $card_owner; return $card; } + else { + // Our request failed. Whoops. + watchdog('commerce_paypal', 'PayPal Vault card on file creation failed: !param', array('!param' => '
' . check_plain(print_r($response, TRUE)) . ''), WATCHDOG_ERROR); + return FALSE; + } } @@ -84,13 +79,14 @@ function commerce_paypal_vault_cardonfile_delete($form, &$form_state, $payment_m // None of the rigmarole from the various CC gateways. $rest = array( 'method' => 'DELETE', - 'endpoint' => 'vault/credit-card/' . $card->remote_id, + 'endpoint' => 'vault/credit-cards/' . $card->remote_id, 'version' => 'v1', ); $response = commerce_paypal_rest_api_request($payment_method, $rest); + // PayPal Vault returns a 204 on a successful deletion. - if ($response->code == 204) { + if ($response && $response->code == 204) { return TRUE; } else { @@ -101,45 +97,57 @@ function commerce_paypal_vault_cardonfile_delete($form, &$form_state, $payment_m } /** - * Delete callback for PayPal Vault stored cards. + * Update callback for PayPal Vault stored cards. * https://developer.paypal.com/docs/api/#update-a-stored-credit-card * * Doesn't work yet -- waiting on feedback from PayPal Developer Support. */ function commerce_paypal_vault_cardonfile_update($form, &$form_state, $payment_method, $card) { - $card_number = $form_state['values']['credit_card']['number']; $card_expire_month = $form_state['values']['credit_card']['exp_month']; $card_expire_year = $form_state['values']['credit_card']['exp_year']; - //$card_expire = $card_expire_year . '-' . $card_expire_month; - //$card_code = $form_state['values']['credit_card']['code']; - $card_type = $form_state['values']['credit_card']['type']; - // $billing_address = $form_state['values']['commerce_customer_address'][LANGUAGE_NONE][0]; + $card_owner = $form_state['values']['credit_card']['owner']; + $name_fragments = explode(' ', $card_owner); + $last_name = array_pop($name_fragments); + $first_name = implode(' ', $name_fragments); $params = array( - 'op' => 'replace', - 'path' => '/', //to be set - 'value' => array( - 'payer_id' => 'user_' . $card->uid, - 'type' => $card_type, - // 'number' => $card_number, - 'expire_month' => $card_expire_month, - 'expire_year' => $card_expire_year, - // 'first_name' => $billing_address['first_name'], - // 'last_name' => $billing_address['last_name'], - ) + array( + 'op' => 'replace', + 'path' => '/first_name', + 'value' => $first_name, + ), + array( + 'op' => 'replace', + 'path' => '/last_name', + 'value' => $last_name, + ), + array( + 'op' => 'replace', + 'path' => '/expire_month', + 'value' => $card_expire_month, + ), + array( + 'op' => 'replace', + 'path' => '/expire_year', + 'value' => $card_expire_year, + ), ); $rest = array( 'method' => 'PATCH', - 'endpoint' => 'vault/credit-card/' . $card->remote_id, + 'endpoint' => 'vault/credit-cards/' . $card->remote_id, 'version' => 'v1', ); - + $response = commerce_paypal_rest_api_request($payment_method, $rest, $params); - - // @todo: What do we do here? Who knows! There is no documentation and all I get are 401s! - // Even the official SDKs don't implement this even though there is a HATEOAS link provided! - // Argh. - - return FALSE; + + // PayPal Vault returns a 200 on a successful update. + if ($response && $response->code == 200) { + return TRUE; + } + else { + // Something screwed up here. Watchdog the response. + watchdog('commerce_paypal', 'PayPal Vault card on file update failed: !param', array('!param' => '
' . check_plain(print_r($response, TRUE)) . ''), WATCHDOG_ERROR); + return FALSE; + } } /** @@ -165,7 +173,6 @@ function commerce_paypal_vault_cardonfile_charge($payment_method, $card, $order, if (!isset($charge)) { $wrapper = entity_metadata_wrapper('commerce_order', $order); $charge = commerce_line_items_total($wrapper->commerce_line_items); - } $amount = commerce_currency_amount_to_decimal($charge['amount'], $charge['currency_code']); @@ -175,7 +182,7 @@ function commerce_paypal_vault_cardonfile_charge($payment_method, $card, $order, 'endpoint' => 'payments/payment', ); $params = array( - 'intent' => ($payment_method['settings']['txn_type'] == 'auth_capture' ? 'sale' : 'authorization'), + 'intent' => ($payment_method['settings']['txn_type'] == 'auth_capture' ? 'sale' : 'authorize'), 'payer' => array( 'payment_method' => 'credit_card', 'funding_instruments' => array( @@ -200,13 +207,14 @@ function commerce_paypal_vault_cardonfile_charge($payment_method, $card, $order, $response = commerce_paypal_rest_api_request($payment_method, $rest, $params, $order); + // @todo: needs better error checking? $txn = commerce_payment_transaction_new($payment_method['method_id'], $order->order_id); $txn->instance_id = $payment_method['instance_id']; - $txn->remote_id = $response->data->id; - $txn->amount = $amount; + $txn->remote_id = isset($response->data->id) ? $response->data->id : ''; + $txn->amount = $charge['amount']; $txn->currency_code = $charge['currency_code']; $txn->payload[REQUEST_TIME] = $response; - $txn->remote_status = $response->data->state; + $txn->remote_status = isset($response->data->state) ? $response->data->state : 'failed'; if ($response && in_array($txn->remote_status, array('approved', 'created'))) { switch ($payment_method['settings']['txn_type']) { case COMMERCE_CREDIT_AUTH_ONLY: @@ -217,18 +225,24 @@ function commerce_paypal_vault_cardonfile_charge($payment_method, $card, $order, break; case COMMERCE_CREDIT_CAPTURE_ONLY: $txn->status = COMMERCE_PAYMENT_STATUS_SUCCESS; - break; + break; } } else { $txn->status = COMMERCE_PAYMENT_STATUS_FAILURE; } + $txn->message = 'Name: @name. Transaction status: !status.'; + $txn->message_variables = array( + '@name' => 'Commerce Card on File Paypal', + '!status' => $txn->status, + ); commerce_payment_transaction_save($txn); // @todo: Check for other error types and do deactivation of expired/messed-up cards here. if (!in_array($txn->remote_status, array('approved', 'created'))) { if ($response && isset($response->data->details)) { + $messages = array(); foreach ($response->data->details as $detail) { $messages[] = $detail->field . ' -- ' . $detail->issue; }