jenkins-bot has submitted this change and it was merged.

Change subject: PayPal Express Checkout: recurring
......................................................................


PayPal Express Checkout: recurring

TODO:
* Transaction is finalized twice, which is a big no-no.
* Put controller code somewhere sane, should help with the above.
* Hasn't been tested with the newer express checkout flow, so far I've only
gotten the old flow will appear in the sandbox, but PP dev says the same
parameters give him the new flow, so perhaps we'll have to test on production.

Bug: T134446
Change-Id: I8761b077cdccfc693176f15d3efeca83904cb5ff
---
M gateway_common/gateway.adapter.php
M paypal_gateway/express_checkout/config/transformers.yaml
M paypal_gateway/express_checkout/config/var_map.yaml
M paypal_gateway/express_checkout/paypal_express.adapter.php
4 files changed, 287 insertions(+), 87 deletions(-)

Approvals:
  Ejegg: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/gateway_common/gateway.adapter.php 
b/gateway_common/gateway.adapter.php
index 04d729d..67860d6 100644
--- a/gateway_common/gateway.adapter.php
+++ b/gateway_common/gateway.adapter.php
@@ -1068,7 +1068,7 @@
                        $formatted = $this->getFormattedResponse( 
$this->transaction_response->getRawResponse() );
 
                        // Process the formatted response. This will then drive 
the result action
-                       try{
+                       try {
                                $this->processResponse( $formatted );
                        } catch ( ResponseProcessingException $ex ) {
                                $errCode = $ex->getErrorCode();
diff --git a/paypal_gateway/express_checkout/config/transformers.yaml 
b/paypal_gateway/express_checkout/config/transformers.yaml
index cdaea4f..e55037c 100644
--- a/paypal_gateway/express_checkout/config/transformers.yaml
+++ b/paypal_gateway/express_checkout/config/transformers.yaml
@@ -1,3 +1,4 @@
 - IsoDate
 - DonorLocale
 - PaypalExpressReturnUrl
+- IsoDate
diff --git a/paypal_gateway/express_checkout/config/var_map.yaml 
b/paypal_gateway/express_checkout/config/var_map.yaml
index 5e5a3bb..9bac3f2 100644
--- a/paypal_gateway/express_checkout/config/var_map.yaml
+++ b/paypal_gateway/express_checkout/config/var_map.yaml
@@ -1,9 +1,14 @@
+AMT: amount
 COUNTRYCODE: country
+CURRENCYCODE: currency_code
 EMAIL: email
 FIRSTNAME: fname
+# FIXME: This might already come through the Invoice Number field.
+L_BILLINGAGREEMENTCUSTOM0: order_id
 L_PAYMENTREQUEST_0_AMT0: amount
 LASTNAME: lname
 LOCALECODE: language
+MAXAMT: amount
 PAYERID: donor_id
 # Example: 2016%2d05%2d03T21%3a25%3a22Z&
 PAYMENTINFO_0_ORDERTIME: date
@@ -16,6 +21,9 @@
 # FIXME: Update the audit and IPN listener to read from this field.
 PAYMENTREQUEST_0_INVNUM: order_id
 PAYMENTREQUEST_0_ITEMAMT: amount
+PROFILEID: subscr_id
+PROFILEREFERENCE: contribution_tracking_id
+PROFILESTARTDATE: date
 # TODO: discuss whether to capture
 #PHONENUM: phone
 RETURNURL: returnto
diff --git a/paypal_gateway/express_checkout/paypal_express.adapter.php 
b/paypal_gateway/express_checkout/paypal_express.adapter.php
index 32e54fe..dda2c80 100644
--- a/paypal_gateway/express_checkout/paypal_express.adapter.php
+++ b/paypal_gateway/express_checkout/paypal_express.adapter.php
@@ -8,7 +8,11 @@
  * https://developer.paypal.com/docs/classic/express-checkout/overview-ec/
  * https://developer.paypal.com/docs/classic/products/
  * 
https://developer.paypal.com/docs/classic/express-checkout/ht_ec-singleItemPayment-curl-etc/
+ * 
https://developer.paypal.com/docs/classic/express-checkout/ht_ec-recurringPaymentProfile-curl-etc/
+ * TODO: We would need reference transactions to do recurring in Germany or 
China.
+ * 
https://developer.paypal.com/docs/classic/express-checkout/integration-guide/ECReferenceTxns/#id094UM0C03Y4
  * https://developer.paypal.com/docs/classic/api/gs_PayPalAPIs/
+ * 
https://developer.paypal.com/docs/classic/express-checkout/integration-guide/ECCustomizing/
  */
 class PaypalExpressAdapter extends GatewayAdapter {
        const GATEWAY_NAME = 'Paypal Express Checkout';
@@ -45,19 +49,6 @@
        }
 
        /**
-        * Shared snippet to parse and the ACK response field and store it as
-        * communication status.
-        */
-       protected function processAckResponse( $response ) {
-               if ( isset( $response['ACK'] ) && $response['ACK'] === 
'Success' ) {
-                       $this->transaction_response->setCommunicationStatus( 
true );
-                       return true;
-               } else {
-                       return false;
-               }
-       }
-
-       /**
         * Use our own Order ID sequence.
         */
        function defineOrderIDMeta() {
@@ -68,6 +59,7 @@
        }
        function setGatewayDefaults() {}
 
+       // TODO: Support "response" specification.
        function defineTransactions() {
                $this->transactions = array();
 
@@ -88,6 +80,8 @@
                                'EMAIL',
                                'L_PAYMENTREQUEST_0_AMT0',
                                'L_PAYMENTREQUEST_0_DESC0',
+                               // FIXME: Investigate rate discount for Digital
+                               //'L_PAYMENTREQUEST_0_ITEMCATEGORY0',
                                'PAYMENTREQUEST_0_AMT',
                                'PAYMENTREQUEST_0_CURRENCYCODE',
                                // FIXME: This should be deprecated, and is 
only for back-compat.
@@ -99,6 +93,7 @@
                                'PAYMENTREQUEST_0_PAYMENTREASON',
                                // TODO: Investigate why can we give this as an 
input:
                                // PAYMENTREQUEST_n_TRANSACTIONID
+                               // TODO: BUYEREMAILOPTINENABLE=1
                        ),
                        'values' => array(
                                'USER' => $this->account_config['User'],
@@ -110,9 +105,79 @@
                                'REQCONFIRMSHIPPING' => 0,
                                'NOSHIPPING' => 1,
                                'L_PAYMENTREQUEST_0_DESC0' => 
WmfFramework::formatMessage( 'donate_interface-donation-description' ),
+                               'L_PAYMENTREQUEST_0_ITEMCATEGORY0' => 'Digital',
                                'PAYMENTREQUEST_0_DESC' => 
WmfFramework::formatMessage( 'donate_interface-donation-description' ),
                                'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale',
                                'PAYMENTREQUEST_0_PAYMENTREASON' => 'None',
+                       ),
+                       'response' => array(
+                               'TOKEN',
+                       ),
+               );
+
+               // 
https://developer.paypal.com/docs/classic/api/merchant/SetExpressCheckout_API_Operation_NVP/
+               $this->transactions['SetExpressCheckout_recurring'] = array(
+                       'request' => array(
+                               'USER',
+                               'PWD',
+                               'SIGNATURE',
+                               'VERSION',
+                               'METHOD',
+                               'RETURNURL',
+                               'CANCELURL',
+                               'REQCONFIRMSHIPPING',
+                               'NOSHIPPING',
+                               'LOCALECODE',
+                               // TODO: PAGESTYLE, HDRIMG, LOGOIMG
+                               'EMAIL',
+                               'L_BILLINGTYPE0',
+                               'L_BILLINGAGREEMENTDESCRIPTION0',
+                               'L_BILLINGAGREEMENTCUSTOM0',
+                               'L_PAYMENTREQUEST_0_AMT0',
+                               // // Note that the DESC fields can be tweaked 
to get different
+                               // // effects in the PayPal layout.
+                               //'L_PAYMENTREQUEST_0_DESC0',
+                               'L_PAYMENTREQUEST_0_ITEMCATEGORY0',
+                               'L_PAYMENTREQUEST_0_NAME0',
+                               'L_PAYMENTREQUEST_0_QTY0',
+                               'MAXAMT',
+                               'PAYMENTREQUEST_0_AMT',
+                               'PAYMENTREQUEST_0_CURRENCYCODE',
+                               // // FIXME: This should be deprecated, and is 
only for back-compat.
+                               // 'PAYMENTREQUEST_0_CUSTOM',
+                               //'PAYMENTREQUEST_0_DESC',
+                               //'PAYMENTREQUEST_0_INVNUM',
+                               'PAYMENTREQUEST_0_ITEMAMT',
+                               //'PAYMENTREQUEST_0_PAYMENTACTION',
+                               //'PAYMENTREQUEST_0_PAYMENTREASON',
+                               // // TODO: Investigate why would give this as 
an input:
+                               // // PAYMENTREQUEST_n_TRANSACTIONID
+                       ),
+                       'values' => array(
+                               'USER' => $this->account_config['User'],
+                               'PWD' => $this->account_config['Password'],
+                               'SIGNATURE' => 
$this->account_config['Signature'],
+                               'VERSION' => self::API_VERSION,
+                               'METHOD' => 'SetExpressCheckout',
+                               'CANCELURL' => ResultPages::getCancelPage( 
$this ),
+                               'REQCONFIRMSHIPPING' => 0,
+                               'NOSHIPPING' => 1,
+                               'L_BILLINGTYPE0' => 'RecurringPayments',
+                               // FIXME: Sad!  The thank-you message would be 
perfect here,
+                               // but it seems the exlamation mark is not 
supported, even when
+                               // urlencoded properly.
+                               //'L_BILLINGAGREEMENTDESCRIPTION0' => 
WmfFramework::formatMessage( 
'donate_interface-donate-error-thank-you-for-your-support' ),
+                               'L_BILLINGAGREEMENTDESCRIPTION0' => 
WmfFramework::formatMessage( 'donate_interface-monthly-donation-description' ),
+                               'L_PAYMENTREQUEST_0_DESC0' => 
WmfFramework::formatMessage( 'donate_interface-monthly-donation-description' ),
+                               'L_PAYMENTREQUEST_0_ITEMCATEGORY0' => 'Digital',
+                               'L_PAYMENTREQUEST_0_NAME0' => 
WmfFramework::formatMessage( 'donate_interface-monthly-donation-description' ),
+                               'L_PAYMENTREQUEST_0_QTY0' => 1,
+                               'PAYMENTREQUEST_0_DESC' => 
WmfFramework::formatMessage( 'donate_interface-monthly-donation-description' ),
+                               'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale',
+                               'PAYMENTREQUEST_0_PAYMENTREASON' => 'None',
+                       ),
+                       'response' => array(
+                               'TOKEN',
                        ),
                );
 
@@ -140,6 +205,32 @@
                                'SIGNATURE' => 
$this->account_config['Signature'],
                                'VERSION' => self::API_VERSION,
                                'METHOD' => 'GetExpressCheckoutDetails',
+                       ),
+                       'response' => array(
+                               'ACK',
+                               'TOKEN',
+                               'CORRELATIONID',
+                               'TIMESTAMP',
+                               'CUSTOM',
+                               'INVNUM',
+                               'BILLINGAGREEMENTACCEPTEDSTATUS',
+                               'REDIRECTREQUIRED',
+                               'CHECKOUTSTATUS',
+                               'EMAIL',
+                               'PAYERID',
+                               'COUNTRYCODE',
+                               'FIRSTNAME',
+                               'MIDDLENAME',
+                               'LASTNAME',
+                               'SUFFIX',
+                               // TODO: Don't know if this is the one? 
'PAYMENTINFO_0_CURRENCYCODE',
+                               'PAYMENTREQUEST_0_AMT',
+                               'PAYMENTREQUEST_0_CURRENCYCODE',
+                               // Or this one? 'PAYMENTREQUEST_n_ITEMAMT'
+                               // FIXME: Are we able to override 
contribution_tracking_id like this?
+                               'PAYMENTREQUEST_0_INVNUM',
+                               'PAYMENTREQUEST_0_TRANSACTIONID',
+                               // Or, the L_ item?
                        ),
                );
 
@@ -176,6 +267,56 @@
                                'PAYMENTREQUEST_0_PAYMENTREASON' => 'None',
                        ),
                );
+
+               // 
https://developer.paypal.com/docs/classic/api/merchant/CreateRecurringPaymentsProfile_API_Operation_NVP/
+               $this->transactions['CreateRecurringPaymentsProfile'] = array(
+                       'request' => array(
+                               'USER',
+                               'PWD',
+                               'SIGNATURE',
+                               'VERSION',
+                               'METHOD',
+                               'TOKEN',
+                               'DESC',
+                               //'L_PAYMENTREQUEST_0_AMT0',
+                               //'L_PAYMENTREQUEST_0_DESC0',
+                               //'L_PAYMENTREQUEST_n_NAME0',
+                               //'L_PAYMENTREQUEST_0_ITEMCATEGORY0',
+                               'PROFILESTARTDATE',
+                               'PROFILEREFERENCE',
+                               'AUTOBILLOUTAMT',
+                               'BILLINGPERIOD',
+                               'BILLINGFREQUENCY',
+                               'TOTALBILLINGCYCLES',
+                               'MAXFAILEDPAYMENTS',
+                               'AMT',
+                               'CURRENCYCODE',
+                               'EMAIL',
+                       ),
+                       'values' => array(
+                               'USER' => $this->account_config['User'],
+                               'PWD' => $this->account_config['Password'],
+                               'SIGNATURE' => 
$this->account_config['Signature'],
+                               'VERSION' => self::API_VERSION,
+                               'METHOD' => 'CreateRecurringPaymentsProfile',
+                               'DESC' => WmfFramework::formatMessage( 
'donate_interface-monthly-donation-description' ),
+                               //'L_PAYMENTREQUEST_0_DESC0' => 
WmfFramework::formatMessage( 'donate_interface-monthly-donation-description' ),
+                               //'L_PAYMENTREQUEST_0_ITEMCATEGORY0' => 
'Digital',
+                               //'L_PAYMENTREQUEST_n_NAME0' => 
WmfFramework::formatMessage( 'donate_interface-monthly-donation-description' ),
+                               // Do not charge for the balance if payments 
fail.
+                               'AUTOBILLOUTAMT' => 'NoAutoBill',
+                               'BILLINGPERIOD' => 'Month',
+                               'BILLINGFREQUENCY' => 1,
+                               'TOTALBILLINGCYCLES' => 0, // Forever.
+                               'MAXFAILEDPAYMENTS' => 3,
+                       ),
+                       'response' => array(
+                               # FIXME: Make sure this gets passed as 
subscription_id in the message
+                               'PROFILEID',
+                               'PROFILESTATUS',
+                               'TRANSACTIONID',
+                       ),
+               );
        }
 
        function getBasedir() {
@@ -184,8 +325,8 @@
 
        public function doPayment() {
                if ( $this->getData_Unstaged_Escaped( 'recurring' ) ) {
-                       // TODO: implement
-                       throw new Exception( "Recurring not implemented yet." );
+                       // Build the billing agreement and get a token to 
redirect.
+                       $resultData = $this->do_transaction( 
'SetExpressCheckout_recurring' );
                } else {
                        // Returns a token which we use to build a redirect URL 
into the
                        // PayPal flow.
@@ -200,7 +341,7 @@
                if ( $resultAction->getRedirect() ) {
                        // FIXME: This stuff should be base behavior for 
handling redirect responses.
                        $this->logPaymentDetails();
-                       $this->setLimboMessage( 'pending' );
+                       // Don't worry about saving a limbo message, we know 
next to nothing yet.
                        // TODO: need ffname hack?
                }
 
@@ -217,83 +358,133 @@
                        $this->transaction_response = new 
PaymentTransactionResponse();
                }
                $this->transaction_response->setData( $response );
-               if ( !$response ) {
-                       throw new ResponseProcessingException(
-                               'Missing or badly formatted response',
-                               ResponseCodes::NO_RESPONSE
-                       );
-               }
+               // FIXME: I'm not sure why we're responsible for failing the
+               // transaction.  If not, we can omit the try/catch here.
+               try {
+                       if ( !$response ) {
+                               throw new ResponseProcessingException(
+                                       'Missing or badly formatted response',
+                                       ResponseCodes::NO_RESPONSE
+                               );
+                       }
 
-               switch ( $this->getCurrentTransaction() ) {
-               case 'SetExpressCheckout':
-                       if ( !$this->processAckResponse( $response ) ) {
-                               // TODO: Here and below, parse the API error 
fields and log.
-                               $this->logger->error( "Failed to set up 
payment, " . json_encode( $response ) );
-                               $this->finalizeInternalStatus( 
FinalStatus::FAILED );
+                       switch ( $this->getCurrentTransaction() ) {
+                       case 'CreateRecurringPaymentsProfile':
+                               $this->checkResponseAck( $response );
+
+                               // Grab the subscription ID.
+                               $this->addResponseData( $this->unstageKeys( 
$response ) );
+
+                               // FIXME: Not a satisfying ending.  Parse the 
PROFILESTATUS
+                               // response and sort it into complete or 
pending.
+                               $this->finalizeInternalStatus( 
FinalStatus::COMPLETE );
+                               $this->runPostProcessHooks();
+                               // FIXME: deprecated
+                               $this->deleteLimboMessage( 'pending' );
                                break;
-                       }
-                       $this->transaction_response->setRedirect( 
$this->account_config['RedirectURL'] . $response['TOKEN'] );
-                       break;
-               case 'ProcessReturn':
-                       // FIXME: Silly that we have to wedge the response 
controller in here with tail recursion.
-                       $this->addRequestData( array(
-                               'ec_token' => $response['token'],
-                               'donor_id' => $response['PayerID'],
-                       ) );
-                       $resultData = $this->do_transaction( 
'GetExpressCheckoutDetails' );
-                       if ( $resultData->getCommunicationStatus() ) {
-                               $this->do_transaction( 
'DoExpressCheckoutPayment' );
-                       }
-                       break;
-               case 'GetExpressCheckoutDetails':
-                       if ( !$this->processAckResponse( $response ) ) {
-                               $this->logger->error( "Failed to get details, " 
. json_encode( $response ) );
-                               $this->finalizeInternalStatus( 
FinalStatus::FAILED );
+                       case 'SetExpressCheckout':
+                       case 'SetExpressCheckout_recurring':
+                               $this->checkResponseAck( $response );
+                               $this->transaction_response->setRedirect(
+                                       $this->account_config['RedirectURL'] . 
$response['TOKEN'] );
+                               break;
+                       case 'ProcessReturn':
+                               // FIXME: Silly that we have to wedge the 
response controller in
+                               // here with tail recursion.  And fragile, 
because we have to
+                               // remember about reentry.
+                               $this->addRequestData( array(
+                                       'ec_token' => $response['token'],
+                                       'payer_id' => $response['PayerID'],
+                               ) );
+                               $resultData = $this->do_transaction( 
'GetExpressCheckoutDetails' );
+                               if ( !$resultData->getCommunicationStatus() ) {
+                                       throw new ResponseProcessingException( 
'Failed to get customer details',
+                                               ResponseCodes::UNKNOWN );
+                               }
+
+                               // One-time payment, or initial payment in a 
subscription.
+                               // XXX: This shouldn't finalize the transaction.
+                               $resultData = $this->do_transaction( 
'DoExpressCheckoutPayment' );
+                               if ( !$resultData->getCommunicationStatus() ) {
+                                       $this->finalizeInternalStatus( 
FinalStatus::FAILED );
+                                       break;
+                               }
+
+                               if ( $this->getData_Unstaged_Escaped( 
'recurring' ) ) {
+                                       // Set up recurring billing agreement.
+                                       $this->addRequestData( array(
+                                               // Start in a month; we're 
making today's payment as an one-time charge.
+                                               'date' => time() + 30 * 24 * 
3600, // FIXME: calendar month
+                                       ) );
+                                       $resultData = $this->do_transaction( 
'CreateRecurringPaymentsProfile' );
+                                       if ( 
!$resultData->getCommunicationStatus() ) {
+                                               throw new 
ResponseProcessingException(
+                                                       'Failed to create a 
recurring profile', ResponseCodes::UNKNOWN );
+                                       }
+                               }
+                               break;
+                       case 'GetExpressCheckoutDetails':
+                               $this->checkResponseAck( $response );
+
+                               // Merge response into our transaction data.
+                               // TODO: Use getFormattedData instead.
+                               // FIXME: We don't want to allow overwriting of 
ctid, need a
+                               // blacklist of protected fields.
+                               $this->addResponseData( $this->unstageKeys( 
$response ) );
+
+                               $this->runAntifraudHooks();
+                               if ( $this->getValidationAction() !== 'process' 
) {
+                                       $this->finalizeInternalStatus( 
FinalStatus::FAILED );
+                               }
+                               break;
+                       case 'DoExpressCheckoutPayment':
+                               $this->checkResponseAck( $response );
+
+                               $this->addResponseData( $this->unstageKeys( 
$response ) );
+                               // FIXME: Silly.
+                               
$this->transaction_response->setGatewayTransactionId(
+                                       $this->getData_Unstaged_Escaped( 
'gateway_txn_id' ) );
+                               $status = $this->findCodeAction( 
'DoExpressCheckoutPayment',
+                                       'PAYMENTINFO_0_ERRORCODE', 
$response['PAYMENTINFO_0_ERRORCODE'] );
+                               // TODO: Can we do this from do_transaction 
instead, or at least protect with !recurring...
+                               $this->finalizeInternalStatus( $status );
+                               $this->runPostProcessHooks();
+                               // FIXME: deprecated
+                               $this->deleteLimboMessage( 'pending' );
                                break;
                        }
 
-                       // Merge response into our transaction data.
-                       // TODO: Use getFormattedData instead.
-                       // FIXME: We don't want to allow overwriting of ctid, 
need a
-                       // blacklist of protected fields.
-                       $this->addResponseData( $this->unstageKeys( $response ) 
);
-
-                       $this->runAntifraudHooks();
-                       if ( $this->getValidationAction() !== 'process' ) {
-                               $this->finalizeInternalStatus( 
FinalStatus::FAILED );
+                       if ( 
!$this->transaction_response->getCommunicationStatus() ) {
+                               // TODO: so much boilerplate...  Just throw an 
exception subclass.
+                               $logme = 'Failed response for Order ID ' . 
$this->getData_Unstaged_Escaped( 'order_id' );
+                               $this->logger->error( $logme );
+                               $this->transaction_response->setErrors( array(
+                                       'internal-0000' => array (
+                                               'message' => 
$this->getErrorMapByCodeAndTranslate( 'internal-0000' ),
+                                               'debugInfo' => $logme,
+                                               'logLevel' => LogLevel::ERROR
+                                       )
+                               ) );
                        }
-                       break;
-               case 'DoExpressCheckoutPayment':
-                       if ( !$this->processAckResponse( $response ) ) {
-                               // FIXME: is response already logged?
-                               $this->logger->error( "Failed to complete 
payment, " . json_encode( $response ) );
-                               $this->finalizeInternalStatus( 
FinalStatus::FAILED );
-                               break;
-                       }
-                       $this->addResponseData( $this->unstageKeys( $response ) 
);
-                       // FIXME: Silly.
-                       $this->transaction_response->setGatewayTransactionId( 
$this->getData_Unstaged_Escaped( 'gateway_txn_id' ) );
-                       $status = $this->findCodeAction( 
'DoExpressCheckoutPayment',
-                               'PAYMENTINFO_0_ERRORCODE', 
$response['PAYMENTINFO_0_ERRORCODE'] );
-                       $this->finalizeInternalStatus( $status );
-                       $this->runPostProcessHooks();
-                       // FIXME: deprecated
-                       $this->deleteLimboMessage( 'pending' );
-                       break;
-               }
-
-               if ( !$this->transaction_response->getCommunicationStatus() ) {
-                       // TODO: so much boilerplate...  Just throw an 
exception subclass.
-                       $logme = 'Failed response for Order ID ' .  
$this->getData_Unstaged_Escaped( 'order_id' );
-                       $this->logger->error( $logme );
-                       $this->transaction_response->setErrors( array(
-                               'internal-0000' => array (
-                                       'message' => 
$this->getErrorMapByCodeAndTranslate( 'internal-0000' ),
-                                       'debugInfo' => $logme,
-                                       'logLevel' => LogLevel::ERROR
-                               )
-                       ) );
+               } catch ( Exception $ex ) {
+                       // TODO: Parse the API error fields and log them.
+                       $this->logger->error( "Failure detected in " . 
json_encode( $response ) );
+                       $this->finalizeInternalStatus( FinalStatus::FAILED );
+                       throw $ex;
                }
        }
 
+       /**
+        * Shared snippet to parse the ACK response field and store it as
+        * communication status.
+        *
+        * @throws ResponseProcessingException
+        */
+       protected function checkResponseAck( $response ) {
+               if ( isset( $response['ACK'] ) && $response['ACK'] === 
'Success' ) {
+                       $this->transaction_response->setCommunicationStatus( 
true );
+               } else {
+                       throw new ResponseProcessingException( "Failure 
response", $response['ACK'] );
+               }
+       }
 }

-- 
To view, visit https://gerrit.wikimedia.org/r/287036
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I8761b077cdccfc693176f15d3efeca83904cb5ff
Gerrit-PatchSet: 12
Gerrit-Project: mediawiki/extensions/DonationInterface
Gerrit-Branch: master
Gerrit-Owner: Awight <awi...@wikimedia.org>
Gerrit-Reviewer: Awight <awi...@wikimedia.org>
Gerrit-Reviewer: Ejegg <eeggles...@wikimedia.org>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to