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

Change subject: Back-end logic for Amazon recurring donations
......................................................................


Back-end logic for Amazon recurring donations

Creates the billing agreement that lets us charge monthly and makes
an initial charge against it.

Adds optional subscr_id to queue messages sent from payments frontend,
since you can't derive the billing agreement ID from the capture ID
we record as gateway_txn_id.

Bug: T111430
Change-Id: I41001359e413839cde6e0dcec84900c848d37b29
---
M amazon_gateway/amazon.adapter.php
M amazon_gateway/amazon.api.php
M gateway_common/DonationData.php
M gateway_common/DonationQueue.php
M tests/Adapter/Amazon/AmazonTest.php
M tests/includes/MockAmazonClient.php
A tests/includes/Responses/amazon/authorizeOnBillingAgreement.json
A tests/includes/Responses/amazon/confirmBillingAgreement.json
A tests/includes/Responses/amazon/getBillingAgreementDetails.json
A tests/includes/Responses/amazon/setBillingAgreementDetails.json
10 files changed, 310 insertions(+), 79 deletions(-)

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



diff --git a/amazon_gateway/amazon.adapter.php 
b/amazon_gateway/amazon.adapter.php
index 775fac0..1742d4b 100644
--- a/amazon_gateway/amazon.adapter.php
+++ b/amazon_gateway/amazon.adapter.php
@@ -156,8 +156,13 @@
                }
 
                try {
-                       $this->confirmOrderReference();
-                       $this->authorizeAndCapturePayment();
+                       if ( $this->getData_Unstaged_Escaped( 'recurring' ) === 
'1' ) {
+                               $this->confirmBillingAgreement();
+                               $this->authorizeAndCapturePayment( true );
+                       } else {
+                               $this->confirmOrderReference();
+                               $this->authorizeAndCapturePayment( false );
+                       }
                } catch ( ResponseProcessingException $ex ) {
                        $this->handleErrors( $ex, $this->transaction_response );
                }
@@ -213,34 +218,9 @@
                return $result;
        }
 
-       /**
-        * Amazon's widget has made calls to create an order reference object 
and
-        * has provided us the ID.  We make one API call to set amount, 
currency,
-        * and our note and local reference ID.  A second call confirms that the
-        * details are valid and moves it out of draft state.  Once it is out of
-        * draft state, we can retrieve the donor's name and email address with 
a
-        * third API call.
-        */
-       protected function confirmOrderReference() {
-               $orderReferenceId = $this->getData_Staged( 'order_reference_id' 
);
-
-               $this->setOrderReferenceDetailsIfUnset( $orderReferenceId );
-
-               $this->logger->info( "Confirming order $orderReferenceId" );
-               $this->callPwaClient( 'confirmOrderReference', array(
-                       'amazon_order_reference_id' => $orderReferenceId,
-               ) );
-
-               // TODO: either check the status, or skip this call when we 
already have
-               // donor details
-               $this->logger->info( "Getting details of order 
$orderReferenceId" );
-               $getDetailsResult = $this->callPwaClient( 
'getOrderReferenceDetails', array(
-                       'amazon_order_reference_id' => $orderReferenceId,
-               ) );
-
-               $buyerDetails = 
$getDetailsResult['GetOrderReferenceDetailsResult']['OrderReferenceDetails']['Buyer'];
-               $email = $buyerDetails['Email'];
-               $name = $buyerDetails['Name'];
+       protected function addDonorDetails( $donorDetails ) {
+               $email = $donorDetails['Email'];
+               $name = $donorDetails['Name'];
                $nameParts = preg_split( '/\s+/', $name, 2 ); // 
janky_split_name
                $fname = $nameParts[0];
                $lname = isset( $nameParts[1] ) ? $nameParts[1] : '';
@@ -257,53 +237,20 @@
        }
 
        /**
-        * Set the order reference details if they haven't been set yet.  Track
-        * which ones have been set in session.
-        * @param string $orderReferenceId
-        */
-       protected function setOrderReferenceDetailsIfUnset( $orderReferenceId ) 
{
-               if ( $this->session_getData( 'order_refs', $orderReferenceId ) 
) {
-                       return;
-               }
-               $this->logger->info( "Setting details for order 
$orderReferenceId" );
-               $this->callPwaClient( 'setOrderReferenceDetails', array(
-                       'amazon_order_reference_id' => $orderReferenceId,
-                       'amount' => $this->getData_Staged( 'amount' ),
-                       'currency_code' => $this->getData_Staged( 
'currency_code' ),
-                       'seller_note' => WmfFramework::formatMessage( 
'donate_interface-donation-description' ),
-                       'seller_order_reference_id' => $this->getData_Staged( 
'order_id' ),
-               ) );
-               // TODO: session_setData wrapper?
-               $_SESSION['order_refs'][$orderReferenceId] = true;
-       }
-
-       /**
-        * Once the order reference is finalized, we can authorize a payment 
against
-        * it and capture the funds.  We combine both steps in a single 
authorize
-        * call.  If the authorization is successful, we can check on the 
capture
-        * status and close the order reference.  TODO: determine if capture 
status
+        * Once the order reference or billing agreement is finalized, we can
+        * authorize a payment against it and capture the funds.  We combine 
both
+        * steps in a single authorize call.  If the authorization is 
successful,
+        * we can check on the capture status.  TODO: determine if capture 
status
         * check is really needed.  According to our tech contact, Amazon 
guarantees
         * that the capture will eventually succeed if the authorization 
succeeds.
         */
-       protected function authorizeAndCapturePayment() {
-               $orderReferenceId = $this->getData_Staged( 'order_reference_id' 
);
+       protected function authorizeAndCapturePayment( $recurring = false ) {
+               if ( $recurring ) {
+                       $authDetails = $this->authorizeOnBillingAgreement();
+               } else {
+                       $authDetails = $this->authorizeOnOrderReference();
+               }
 
-               $this->logger->info( "Authorizing and capturing payment on 
order $orderReferenceId" );
-               $authResponse = $this->callPwaClient( 'authorize', array(
-                       'amazon_order_reference_id' => $orderReferenceId,
-                       'authorization_amount' => $this->getData_Staged( 
'amount' ),
-                       'currency_code' => $this->getData_Staged( 
'currency_code' ),
-                       'capture_now' => true, // combine authorize and capture 
steps
-                       'authorization_reference_id' => $this->getData_Staged( 
'order_id' ),
-                       'transaction_timeout' => 0, // authorize synchronously
-                       // Could set 'SoftDescriptor' to control what appears 
on CC statement (16 char max, prepended with AMZ*)
-                       // Use the seller_authorization_note to simulate an 
error in the sandbox
-                       // See 
https://payments.amazon.com/documentation/lpwa/201749840#201750790
-                       // 'seller_authorization_note' => 
'{"SandboxSimulation": {"State":"Declined", 
"ReasonCode":"TransactionTimedOut"}}',
-                       // 'seller_authorization_note' => 
'{"SandboxSimulation": {"State":"Declined", 
"ReasonCode":"InvalidPaymentMethod"}}',
-               ) );
-
-               $authDetails = 
$authResponse['AuthorizeResult']['AuthorizationDetails'];
                if ( $authDetails['AuthorizationStatus']['State'] === 
'Declined' ) {
                        throw new ResponseProcessingException(
                                WmfFramework::formatMessage( 
'php-response-declined' ), // php- ??
@@ -335,6 +282,127 @@
        }
 
        /**
+        * Amazon's widget has made calls to create an order reference object 
and
+        * has provided us the ID.  We make one API call to set amount, 
currency,
+        * and our note and local reference ID.  A second call confirms that the
+        * details are valid and moves it out of draft state.  Once it is out of
+        * draft state, we can retrieve the donor's name and email address with 
a
+        * third API call.
+        */
+       protected function confirmOrderReference() {
+               $orderReferenceId = $this->getData_Staged( 'order_reference_id' 
);
+
+               $this->setOrderReferenceDetailsIfUnset( $orderReferenceId );
+
+               $this->logger->info( "Confirming order $orderReferenceId" );
+               $this->callPwaClient( 'confirmOrderReference', array(
+                       'amazon_order_reference_id' => $orderReferenceId,
+               ) );
+
+               // TODO: either check the status, or skip this call when we 
already have
+               // donor details
+               $this->logger->info( "Getting details of order 
$orderReferenceId" );
+               $getDetailsResult = $this->callPwaClient( 
'getOrderReferenceDetails', array(
+                       'amazon_order_reference_id' => $orderReferenceId,
+               ) );
+
+               $this->addDonorDetails(
+                       
$getDetailsResult['GetOrderReferenceDetailsResult']['OrderReferenceDetails']['Buyer']
+               );
+       }
+
+       /**
+        * Set the order reference details if they haven't been set yet.  Track
+        * which ones have been set in session.
+        * @param string $orderReferenceId
+        */
+       protected function setOrderReferenceDetailsIfUnset( $orderReferenceId ) 
{
+               if ( $this->session_getData( 'order_refs', $orderReferenceId ) 
) {
+                       return;
+               }
+               $this->logger->info( "Setting details for order 
$orderReferenceId" );
+               $this->callPwaClient( 'setOrderReferenceDetails', array(
+                       'amazon_order_reference_id' => $orderReferenceId,
+                       'amount' => $this->getData_Staged( 'amount' ),
+                       'currency_code' => $this->getData_Staged( 
'currency_code' ),
+                       'seller_note' => WmfFramework::formatMessage( 
'donate_interface-donation-description' ),
+                       'seller_order_reference_id' => $this->getData_Staged( 
'order_id' ),
+               ) );
+               // TODO: session_setData wrapper?
+               $_SESSION['order_refs'][$orderReferenceId] = true;
+       }
+
+       protected function authorizeOnOrderReference() {
+               $orderReferenceId = $this->getData_Staged( 'order_reference_id' 
);
+
+               $this->logger->info( "Authorizing and capturing payment on 
order $orderReferenceId" );
+               $authResponse = $this->callPwaClient( 'authorize', array(
+                       'amazon_order_reference_id' => $orderReferenceId,
+                       'authorization_amount' => $this->getData_Staged( 
'amount' ),
+                       'currency_code' => $this->getData_Staged( 
'currency_code' ),
+                       'capture_now' => true, // combine authorize and capture 
steps
+                       'authorization_reference_id' => $this->getData_Staged( 
'order_id' ),
+                       'transaction_timeout' => 0, // authorize synchronously
+                       // Could set 'SoftDescriptor' to control what appears 
on CC statement (16 char max, prepended with AMZ*)
+                       // Use the seller_authorization_note to simulate an 
error in the sandbox
+                       // See 
https://payments.amazon.com/documentation/lpwa/201749840#201750790
+                       // 'seller_authorization_note' => 
'{"SandboxSimulation": {"State":"Declined", 
"ReasonCode":"TransactionTimedOut"}}',
+                       // 'seller_authorization_note' => 
'{"SandboxSimulation": {"State":"Declined", 
"ReasonCode":"InvalidPaymentMethod"}}',
+               ) );
+               return $authResponse['AuthorizeResult']['AuthorizationDetails'];
+       }
+
+       protected function confirmBillingAgreement() {
+               $billingAgreementId = $this->getData_Staged( 'subscr_id' );
+               $this->setBillingAgreementDetailsIfUnset( $billingAgreementId );
+
+               $this->logger->info( "Confirming billing agreement 
$billingAgreementId" );
+               $this->callPwaClient( 'confirmBillingAgreement', array(
+                       'amazon_billing_agreement_id' => $billingAgreementId,
+               ) );
+
+               $this->logger->info( "Getting details of billing agreement 
$billingAgreementId" );
+               $getDetailsResult = $this->callPwaClient( 
'getBillingAgreementDetails', array(
+                       'amazon_billing_agreement_id' => $billingAgreementId,
+               ) );
+
+               $this->addDonorDetails(
+                       
$getDetailsResult['GetBillingAgreementDetailsResult']['BillingAgreementDetails']['Buyer']
+               );
+       }
+
+       protected function setBillingAgreementDetailsIfUnset( 
$billingAgreementId ) {
+               if ( $this->session_getData( 'billing_agreements', 
$billingAgreementId ) ) {
+                       return;
+               }
+               $this->logger->info( "Setting details for billing agreement 
$billingAgreementId" );
+               $this->callPwaClient( 'setBillingAgreementDetails', array(
+                       'amazon_billing_agreement_id' => $billingAgreementId,
+                       'seller_note' => WmfFramework::formatMessage( 
'donate_interface-monthly-donation-description' ),
+                       'seller_billing_agreement_id' => $this->getData_Staged( 
'order_id' ),
+               ) );
+               $_SESSION['billing_agreements'][$billingAgreementId] = true;
+       }
+
+       protected function authorizeOnBillingAgreement() {
+               $billingAgreementId = $this->getData_Staged( 'subscr_id' );
+
+               $this->logger->info( "Authorizing and capturing payment on 
billing agreement $billingAgreementId" );
+               $authResponse = $this->callPwaClient( 
'authorizeOnBillingAgreement', array(
+                       'amazon_billing_agreement_id' => $billingAgreementId,
+                       'authorization_amount' => $this->getData_Staged( 
'amount' ),
+                       'currency_code' => $this->getData_Staged( 
'currency_code' ),
+                       'capture_now' => true, // combine authorize and capture 
steps
+                       'authorization_reference_id' => $this->getData_Staged( 
'order_id' ),
+                       'seller_order_id' => $this->getData_Staged( 'order_id' 
),
+                       'seller_note' => WmfFramework::formatMessage( 
'donate_interface-monthly-donation-description' ),
+                       'transaction_timeout' => 0, // authorize synchronously
+                       // 'seller_authorization_note' => 
'{"SandboxSimulation": {"State":"Declined", 
"ReasonCode":"InvalidPaymentMethod"}}',
+               ) );
+               return 
$authResponse['AuthorizeOnBillingAgreementResult']['AuthorizationDetails'];
+       }
+
+       /**
         * Replace decimal point with a dash to comply with Amazon's 
restrictions on
         * seller reference ID format.
         */
diff --git a/amazon_gateway/amazon.api.php b/amazon_gateway/amazon.api.php
index 73cdc2d..f0eb4aa 100644
--- a/amazon_gateway/amazon.api.php
+++ b/amazon_gateway/amazon.api.php
@@ -3,19 +3,22 @@
 class AmazonBillingApi extends ApiBase {
        protected $allowedParams = array(
                'amount',
+               'billingAgreementId',
                'currency_code',
                'orderReferenceId',
+               'recurring',
                'token',
        );
 
        public function execute() {
                $output = $this->getResult();
-               $orderReferenceId = $this->getParameter( 'orderReferenceId' );
+               $recurring = $this->getParameter( 'recurring');
                $adapterParams = array(
                        'api_request' => true,
                        'external_data' => array(
                                'amount' => $this->getParameter( 'amount' ),
                                'currency_code' => $this->getParameter( 
'currency_code' ),
+                               'recurring' => $this->getParameter( 'recurring' 
),
                        ),
                );
 
@@ -28,9 +31,15 @@
                                $adapter->getValidationErrors()
                        );
                } else if ( $adapter->checkTokens() ) {
-                       $adapter->addRequestData( array(
-                               'order_reference_id' => $orderReferenceId,
-                       ) );
+                       if ( $recurring ) {
+                               $adapter->addRequestData( array(
+                                       'subscr_id' => $this->getParameter( 
'billingAgreementId' ),
+                               ) );
+                       } else {
+                               $adapter->addRequestData( array(
+                                       'order_reference_id' => 
$this->getParameter( 'orderReferenceId' ),
+                               ) );
+                       }
                        $result = $adapter->doPayment();
                        if ( $result->isFailed() ) {
                                $output->addvalue(
diff --git a/gateway_common/DonationData.php b/gateway_common/DonationData.php
index 6657922..5a9d943 100644
--- a/gateway_common/DonationData.php
+++ b/gateway_common/DonationData.php
@@ -95,6 +95,7 @@
                                'submethod', //same as above. Ideally, the 
newer banners would stop using these vars and go back to the old ones...
                                'issuer_id',
                                'order_id',
+                               'subscr_id',
                                'referrer',
                                'utm_source',
                                'utm_source_id',
@@ -915,6 +916,7 @@
                        'gateway',
                        'gateway_account',
                        'gateway_txn_id',
+                       'subscr_id',
                        'recurring',
                        'payment_method',
                        'payment_submethod',
diff --git a/gateway_common/DonationQueue.php b/gateway_common/DonationQueue.php
index f47edb1..cdb203a 100644
--- a/gateway_common/DonationQueue.php
+++ b/gateway_common/DonationQueue.php
@@ -229,6 +229,7 @@
                        'state_province' => 'state',
                        'street_address' => 'street',
                        'supplemental_address_1' => 'street_supplemental',
+                       'subscr_id' => 'subscr_id',
                        'utm_campaign' => 'utm_campaign',
                        'utm_medium' => 'utm_medium',
                        'postal_code' => 'zip',
diff --git a/tests/Adapter/Amazon/AmazonTest.php 
b/tests/Adapter/Amazon/AmazonTest.php
index 1e47950..3e439a0 100644
--- a/tests/Adapter/Amazon/AmazonTest.php
+++ b/tests/Adapter/Amazon/AmazonTest.php
@@ -256,4 +256,38 @@
                $errors = $result->getErrors();
                $this->assertTrue( isset( $errors[ResponseCodes::NO_RESPONSE] 
), 'NO_RESPONSE error should be set' );
        }
+
+       /**
+        * Check the adapter makes the correct calls for successful monthly 
donations
+        */
+       function testDoRecurringPaymentSuccess() {
+               $init = $this->getDonorTestData( 'US' );
+               $init['amount'] = '10.00';
+               $init['recurring'] = '1';
+               $init['subscr_id'] = 'C01-9650293-7351908';
+               // We don't get any profile data up front
+               unset( $init['email'] );
+               unset( $init['fname'] );
+               unset( $init['lname'] );
+
+               $gateway = $this->getFreshGatewayObject( $init );
+               $result = $gateway->doPayment();
+               // FIXME: PaymentResult->isFailed returns null for false
+               $this->assertTrue( !( $result->isFailed() ), 'Result should not 
be failed when responses are good' );
+               $this->assertEquals( 'Testy', 
$gateway->getData_Unstaged_Escaped( 'fname' ), 'Did not populate first name 
from Amazon data' );
+               $this->assertEquals( 'Test', 
$gateway->getData_Unstaged_Escaped( 'lname' ), 'Did not populate last name from 
Amazon data' );
+               $this->assertEquals( '[email protected]', 
$gateway->getData_Unstaged_Escaped( 'email' ), 'Did not populate email from 
Amazon data' );
+               $mockClient = TestingAmazonAdapter::$mockClient;
+               $setBillingAgreementDetailsArgs = 
$mockClient->calls['setBillingAgreementDetails'][0];
+               $oid = $gateway->getData_Unstaged_Escaped( 'order_id' );
+               $this->assertEquals( $oid, 
$setBillingAgreementDetailsArgs['seller_billing_agreement_id'], 'Did not set 
order id on billing agreement' );
+               $authorizeOnBillingAgreementDetailsArgs = 
$mockClient->calls['authorizeOnBillingAgreement'][0];
+               $this->assertEquals( $init['amount'], 
$authorizeOnBillingAgreementDetailsArgs['authorization_amount'], 'Did not 
authorize correct amount' );
+               $this->assertEquals( $init['currency_code'], 
$authorizeOnBillingAgreementDetailsArgs['currency_code'], 'Did not authorize 
correct currency code' );
+               $queued = $gateway->queue_messages;
+               $this->assertNotEmpty( $queued['complete'], 'Not sending a 
message to the complete queue' );
+               $message = $queued['complete'][0];
+               $this->assertEquals( 'S01-5318994-6362993-C004044', 
$message['gateway_txn_id'], 'Queue message has wrong txn ID' );
+               $this->assertEquals( $init['subscr_id'], $message['subscr_id'], 
'Queue message has wrong subscription ID' );
+       }
 }
diff --git a/tests/includes/MockAmazonClient.php 
b/tests/includes/MockAmazonClient.php
index cdeec61..6915609 100644
--- a/tests/includes/MockAmazonClient.php
+++ b/tests/includes/MockAmazonClient.php
@@ -49,7 +49,7 @@
        }
 
        public function authorizeOnBillingAgreement( $requestParameters = 
array() ) {
-
+               return $this->fakeCall( 'authorizeOnBillingAgreement', 
$requestParameters );
        }
 
        public function cancelOrderReference( $requestParameters = array() ) {
@@ -77,7 +77,7 @@
        }
 
        public function confirmBillingAgreement( $requestParameters = array() ) 
{
-
+               return $this->fakeCall( 'confirmBillingAgreement', 
$requestParameters );
        }
 
        public function confirmOrderReference( $requestParameters = array() ) {
@@ -137,6 +137,7 @@
        }
 
        public function setBillingAgreementDetails( $requestParameters = 
array() ) {
+               return $this->fakeCall( 'setBillingAgreementDetails', 
$requestParameters );
 
        }
 
diff --git a/tests/includes/Responses/amazon/authorizeOnBillingAgreement.json 
b/tests/includes/Responses/amazon/authorizeOnBillingAgreement.json
new file mode 100644
index 0000000..0163e64
--- /dev/null
+++ b/tests/includes/Responses/amazon/authorizeOnBillingAgreement.json
@@ -0,0 +1,38 @@
+{
+    "AuthorizeOnBillingAgreementResult": {
+        "AuthorizationDetails": {
+            "AuthorizationAmount": {
+                "CurrencyCode": "USD",
+                "Amount": "10.00"
+            },
+            "CapturedAmount": {
+                "CurrencyCode": "USD",
+                "Amount": "0"
+            },
+            "SoftDescriptor": "AMZ*Wikimedia Founda",
+            "ExpirationTimestamp": "2015-11-04T18:06:49.965Z",
+            "IdList": {
+                "member": "S01-5318994-6362993-C004044"
+            },
+            "AuthorizationStatus": {
+                "LastUpdateTimestamp": "2015-10-05T18:06:49.965Z",
+                "State": "Closed",
+                "ReasonCode": "MaxCapturesProcessed"
+            },
+            "AuthorizationFee": {
+                "CurrencyCode": "USD",
+                "Amount": "0.00"
+            },
+            "CaptureNow": "true",
+            "CreationTimestamp": "2015-10-05T18:06:49.965Z",
+            "SellerAuthorizationNote": [],
+            "AmazonAuthorizationId": "S01-5318994-6362993-A004044",
+            "AuthorizationReferenceId": "36834-0"
+        },
+        "AmazonOrderReferenceId": "S01-5318994-6362993"
+    },
+    "ResponseMetadata": {
+        "RequestId": "8c8f4d79-06d5-4de5-ae34-d3fdc73aa343"
+    },
+    "ResponseStatus": "200"
+}
\ No newline at end of file
diff --git a/tests/includes/Responses/amazon/confirmBillingAgreement.json 
b/tests/includes/Responses/amazon/confirmBillingAgreement.json
new file mode 100644
index 0000000..266dad3
--- /dev/null
+++ b/tests/includes/Responses/amazon/confirmBillingAgreement.json
@@ -0,0 +1,7 @@
+{
+    "ConfirmBillingAgreementResult": [],
+    "ResponseMetadata": {
+        "RequestId": "61e7b7c9-ed72-4a27-b18f-6ec37ac031c5"
+    },
+    "ResponseStatus": "200"
+}
\ No newline at end of file
diff --git a/tests/includes/Responses/amazon/getBillingAgreementDetails.json 
b/tests/includes/Responses/amazon/getBillingAgreementDetails.json
new file mode 100644
index 0000000..0caa393
--- /dev/null
+++ b/tests/includes/Responses/amazon/getBillingAgreementDetails.json
@@ -0,0 +1,38 @@
+{
+    "GetBillingAgreementDetailsResult": {
+        "BillingAgreementDetails": {
+            "BillingAgreementStatus": {
+                "LastUpdatedTimestamp": "2015-10-05T18:06:48.288Z",
+                "State": "Open"
+            },
+            "AmazonBillingAgreementId": "C01-9650293-7351908",
+            "BillingAgreementConsent": "true",
+            "SellerBillingAgreementAttributes": {
+                "SellerBillingAgreementId": "36834-0"
+            },
+            "Buyer": {
+                "Name": "Testy Test",
+                "Email": "[email protected]"
+            },
+            "ReleaseEnvironment": "Sandbox",
+            "SellerNote": "Monthly donation to the Wikimedia Foundation",
+            "CreationTimestamp": "2015-10-05T18:06:38.940Z",
+            "BillingAgreementLimits": {
+                "TimePeriodStartDate": "2015-10-01T00:00:00Z",
+                "CurrentRemainingBalance": {
+                    "CurrencyCode": "USD",
+                    "Amount": "500.00"
+                },
+                "AmountLimitPerTimePeriod": {
+                    "CurrencyCode": "USD",
+                    "Amount": "500"
+                },
+                "TimePeriodEndDate": "2015-11-01T00:00:00Z"
+            }
+        }
+    },
+    "ResponseMetadata": {
+        "RequestId": "547cb94e-690e-47e9-99cd-aef79622a451"
+    },
+    "ResponseStatus": "200"
+}
\ No newline at end of file
diff --git a/tests/includes/Responses/amazon/setBillingAgreementDetails.json 
b/tests/includes/Responses/amazon/setBillingAgreementDetails.json
new file mode 100644
index 0000000..85aac83
--- /dev/null
+++ b/tests/includes/Responses/amazon/setBillingAgreementDetails.json
@@ -0,0 +1,33 @@
+{
+    "SetBillingAgreementDetailsResult": {
+        "BillingAgreementDetails": {
+            "AmazonBillingAgreementId": "C01-9650293-7351908",
+            "BillingAgreementStatus": {
+                "State": "Draft"
+            },
+            "BillingAgreementConsent": "true",
+            "SellerBillingAgreementAttributes": {
+                "SellerBillingAgreementId": "36834-0"
+            },
+            "ReleaseEnvironment": "Sandbox",
+            "SellerNote": "Monthly donation to the Wikimedia Foundation",
+            "CreationTimestamp": "2015-10-05T18:06:38.940Z",
+            "BillingAgreementLimits": {
+                "TimePeriodStartDate": "2015-10-01T00:00:00Z",
+                "CurrentRemainingBalance": {
+                    "CurrencyCode": "USD",
+                    "Amount": "500.00"
+                },
+                "AmountLimitPerTimePeriod": {
+                    "CurrencyCode": "USD",
+                    "Amount": "500"
+                },
+                "TimePeriodEndDate": "2015-11-01T00:00:00Z"
+            }
+        }
+    },
+    "ResponseMetadata": {
+        "RequestId": "9a92b3f8-d8d2-46bf-b998-e3332c71df61"
+    },
+    "ResponseStatus": "200"
+}
\ No newline at end of file

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

Gerrit-MessageType: merged
Gerrit-Change-Id: I41001359e413839cde6e0dcec84900c848d37b29
Gerrit-PatchSet: 4
Gerrit-Project: mediawiki/extensions/DonationInterface
Gerrit-Branch: master
Gerrit-Owner: Ejegg <[email protected]>
Gerrit-Reviewer: AndyRussG <[email protected]>
Gerrit-Reviewer: Awight <[email protected]>
Gerrit-Reviewer: Cdentinger <[email protected]>
Gerrit-Reviewer: Ssmith <[email protected]>
Gerrit-Reviewer: XenoRyet <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to