├── .gitignore
├── tests
├── Mock
│ ├── ExpressVoidFailure.txt
│ ├── ExpressVoidSuccess.txt
│ ├── ExpressOrderSuccess.txt
│ ├── ExpressPurchaseSuccess.txt
│ ├── ProPurchaseSuccess.txt
│ ├── ExpressCompletePurchaseFailure.txt
│ ├── RestGenericSubscriptionSuccess.txt
│ ├── ExpressOrderFailure.txt
│ ├── ExpressPurchaseFailure.txt
│ ├── ProPurchaseFailure.txt
│ ├── ExpressFetchCheckoutFailure.txt
│ ├── RestTokenFailure.txt
│ ├── ExpressCompletePurchaseFailureRedirect.txt
│ ├── RestExecuteSubscriptionSuccess.txt
│ ├── RestCompletePurchaseFailure.txt
│ ├── RestTokenSuccess.txt
│ ├── ExpressFetchCheckoutSuccess.txt
│ ├── RestPurchaseFailure.txt
│ ├── ExpressCompletePurchaseSuccess.txt
│ ├── RestRefundSuccess.txt
│ ├── RestCreateCardSuccess.txt
│ ├── RestCaptureSuccess.txt
│ ├── RestPurchaseWithoutCardSuccess.txt
│ ├── RestPurchaseSuccess.txt
│ ├── RestAuthorizationSuccess.txt
│ ├── RestFetchPurchaseSuccess.txt
│ └── RestCompletePurchaseSuccess.txt
├── Message
│ ├── RestFetchPurchaseRequestTest.php
│ ├── RestListWebhooksRequestTest.php
│ ├── RestCompleteSubscriptionRequestTest.php
│ ├── ExpressVoidRequestTest.php
│ ├── RestCompletePurchaseRequestTest.php
│ ├── RestCancelSubscriptionRequestTest.php
│ ├── RestUpdatePlanRequestTest.php
│ ├── RestSuspendSubscriptionRequestTest.php
│ ├── RestFetchTransactionRequestTest.php
│ ├── RestReactivateSubscriptionRequestTest.php
│ ├── RestDeleteCardRequestTest.php
│ ├── RestListPlanRequestTest.php
│ ├── RestAuthorizeResponseTest.php
│ ├── RestSearchTransactionRequestTest.php
│ ├── FetchTransactionRequestTest.php
│ ├── RestCreateSubscriptionRequestTest.php
│ ├── ResponseTest.php
│ ├── RestVerifyWebhookSignatureResponseTest.php
│ ├── CaptureRequestTest.php
│ ├── RestCreateWebhookRequestTest.php
│ ├── ExpressTransactionSearchResponseTest.php
│ ├── RestCreateCardRequestTest.php
│ ├── RestCreatePlanRequestTest.php
│ ├── RefundRequestTest.php
│ ├── ExpressAuthorizeResponseTest.php
│ ├── ExpressInContextAuthorizeResponseTest.php
│ ├── RestVerifyWebhookSignatureRequestTest.php
│ ├── ExpressFetchCheckoutRequestTest.php
│ ├── ProPurchaseRequestTest.php
│ ├── ProAuthorizeRequestTest.php
│ ├── ExpressTransactionSearchRequestTest.php
│ ├── RestResponseTest.php
│ ├── RestPurchaseRequestTest.php
│ ├── ExpressCompletePurchaseRequestTest.php
│ ├── ExpressCompleteAuthorizeRequestTest.php
│ └── RestAuthorizeRequestTest.php
├── ProGatewayTest.php
└── ExpressInContextGatewayTest.php
├── src
├── Message
│ ├── ProPurchaseRequest.php
│ ├── ExpressOrderRequest.php
│ ├── ExpressInContextAuthorizeRequest.php
│ ├── ExpressCompleteOrderRequest.php
│ ├── ExpressInContextOrderRequest.php
│ ├── ExpressVoidRequest.php
│ ├── FetchTransactionRequest.php
│ ├── ExpressCompletePurchaseRequest.php
│ ├── ExpressInContextAuthorizeResponse.php
│ ├── CaptureRequest.php
│ ├── ExpressFetchCheckoutRequest.php
│ ├── RefundRequest.php
│ ├── RestVoidRequest.php
│ ├── RestListWebhooksRequest.php
│ ├── RestVerifyWebhookSignatureResponse.php
│ ├── ExpressTransactionSearchResponse.php
│ ├── RestRefundCaptureRequest.php
│ ├── Response.php
│ ├── ExpressCompletePurchaseResponse.php
│ ├── RestCreateWebhookRequest.php
│ ├── RestFetchPurchaseRequest.php
│ ├── ExpressAuthorizeResponse.php
│ ├── RestTokenRequest.php
│ ├── ProAuthorizeRequest.php
│ ├── ExpressCompleteAuthorizeRequest.php
│ ├── RestFetchTransactionRequest.php
│ ├── RestDeleteCardRequest.php
│ ├── RestResponse.php
│ ├── RestCaptureRequest.php
│ ├── RestCompletePurchaseRequest.php
│ ├── RestRefundRequest.php
│ ├── RestAuthorizeResponse.php
│ ├── RestSuspendSubscriptionRequest.php
│ ├── RestCancelSubscriptionRequest.php
│ ├── RestReactivateSubscriptionRequest.php
│ ├── RestUpdatePlanRequest.php
│ ├── RestCreateCardRequest.php
│ ├── RestCompleteSubscriptionRequest.php
│ ├── RestVerifyWebhookSignatureRequest.php
│ ├── RestSearchTransactionRequest.php
│ ├── RestListPlanRequest.php
│ └── AbstractRestRequest.php
├── PayPalItem.php
├── ExpressInContextGateway.php
├── PayPalItemBag.php
├── Support
│ └── InstantUpdateApi
│ │ ├── ShippingOption.php
│ │ └── BillingAgreement.php
├── ProGateway.php
└── ExpressGateway.php
├── grumphp.yml
├── CONTRIBUTING.md
├── phpunit.xml.dist
├── phpunit.xml.dist~
├── LICENSE
├── .github
└── workflows
│ └── run-tests.yml
├── composer.json
├── README.md
└── makedoc.sh
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor
2 | composer.lock
3 | composer.phar
4 | phpunit.xml
5 | .idea/
6 |
7 | .directory
8 | dirlist.app
9 | dirlist.vendor
10 | dirlist.cache
11 | documents/
12 |
--------------------------------------------------------------------------------
/tests/Mock/ExpressVoidFailure.txt:
--------------------------------------------------------------------------------
1 | HTTP/1.1 200 OK
2 | Date: Fri, 15 Feb 2013 19:19:21 GMT
3 | Server: Apache
4 | Content-Length: 136
5 | Connection: close
6 | Content-Type: text/plain; charset=utf-8
7 |
8 | AUTHORIZATIONID=ASDFASDFASDF&TIMESTAMP=2013%2d02%2d15T19%3a19%3a21Z&CORRELATIONID=37b8b9915987c&ACK=Failure&VERSION=85%2e0&BUILD=5060305
--------------------------------------------------------------------------------
/tests/Mock/ExpressVoidSuccess.txt:
--------------------------------------------------------------------------------
1 | HTTP/1.1 200 OK
2 | Date: Fri, 15 Feb 2013 19:19:21 GMT
3 | Server: Apache
4 | Content-Length: 136
5 | Connection: close
6 | Content-Type: text/plain; charset=utf-8
7 |
8 | AUTHORIZATIONID=ASDFASDFASDF&TIMESTAMP=2013%2d02%2d15T19%3a19%3a21Z&CORRELATIONID=37b8b9915987c&ACK=Success&VERSION=85%2e0&BUILD=5060305
--------------------------------------------------------------------------------
/tests/Mock/ExpressOrderSuccess.txt:
--------------------------------------------------------------------------------
1 | HTTP/1.1 200 OK
2 | Date: Fri, 15 Feb 2013 19:19:21 GMT
3 | Server: Apache
4 | Content-Length: 136
5 | Connection: close
6 | Content-Type: text/plain; charset=utf-8
7 |
8 | TOKEN=EC%2d42721413K79637829&TIMESTAMP=2013%2d02%2d15T19%3a19%3a21Z&CORRELATIONID=37b8b9915987c&ACK=Success&VERSION=85%2e0&BUILD=5060305
--------------------------------------------------------------------------------
/tests/Mock/ExpressPurchaseSuccess.txt:
--------------------------------------------------------------------------------
1 | HTTP/1.1 200 OK
2 | Date: Fri, 15 Feb 2013 19:19:21 GMT
3 | Server: Apache
4 | Content-Length: 136
5 | Connection: close
6 | Content-Type: text/plain; charset=utf-8
7 |
8 | TOKEN=EC%2d42721413K79637829&TIMESTAMP=2013%2d02%2d15T19%3a19%3a21Z&CORRELATIONID=37b8b9915987c&ACK=Success&VERSION=85%2e0&BUILD=5060305
--------------------------------------------------------------------------------
/tests/Mock/ProPurchaseSuccess.txt:
--------------------------------------------------------------------------------
1 | HTTP/1.1 200 OK
2 | Date: Fri, 15 Feb 2013 18:38:31 GMT
3 | Server: Apache
4 | Content-Length: 190
5 | Connection: close
6 | Content-Type: text/plain; charset=utf-8
7 |
8 | TIMESTAMP=2013%2d02%2d15T18%3a38%3a36Z&CORRELATIONID=541737dc565cb&ACK=Success&VERSION=85%2e0&BUILD=5060305&AMT=10%2e00&CURRENCYCODE=USD&AVSCODE=X&CVV2MATCH=M&TRANSACTIONID=96U93778BD657313D
--------------------------------------------------------------------------------
/src/Message/ProPurchaseRequest.php:
--------------------------------------------------------------------------------
1 | response = new ExpressInContextAuthorizeResponse($this, $data);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/tests/Mock/RestGenericSubscriptionSuccess.txt:
--------------------------------------------------------------------------------
1 | HTTP/1.1 204 OK
2 | Server: Apache-Coyote/1.1
3 | PROXY_SERVER_INFO: host=slcsbjava3.slc.paypal.com;threadId=3205
4 | Paypal-Debug-Id: 217a9ddefd384
5 | SERVER_INFO: identitysecuretokenserv:v1.oauth2.token&CalThreadId=91&TopLevelTxnStartTime=146fbfe679a&Host=slcsbidensectoken502.slc.paypal.com&pid=29059
6 | CORRELATION-ID: 217a9ddefd384
7 | Date: Thu, 03 Jul 2014 11:31:32 GMT
8 |
9 | {}
10 |
--------------------------------------------------------------------------------
/src/Message/ExpressCompleteOrderRequest.php:
--------------------------------------------------------------------------------
1 | validate('transactionReference');
13 | $data = $this->getBaseData();
14 | $data['METHOD'] = 'DoVoid';
15 | $data['AUTHORIZATIONID'] = $this->getTransactionReference();
16 | return $data;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/tests/Mock/ProPurchaseFailure.txt:
--------------------------------------------------------------------------------
1 | HTTP/1.1 200 OK
2 | Date: Fri, 15 Feb 2013 18:49:26 GMT
3 | Server: Apache
4 | Content-Length: 340
5 | Connection: close
6 | Content-Type: text/plain; charset=utf-8
7 |
8 | TIMESTAMP=2013%2d02%2d15T18%3a49%3a27Z&CORRELATIONID=ec641b50c33b0&ACK=Failure&VERSION=85%2e0&BUILD=5060305&L_ERRORCODE0=10562&L_SHORTMESSAGE0=Invalid%20Data&L_LONGMESSAGE0=This%20transaction%20cannot%20be%20processed%2e%20Please%20enter%20a%20valid%20credit%20card%20expiration%20year%2e&L_SEVERITYCODE0=Error&AMT=150%2e04&CURRENCYCODE=USD
--------------------------------------------------------------------------------
/src/Message/FetchTransactionRequest.php:
--------------------------------------------------------------------------------
1 | validate('transactionReference');
13 |
14 | $data = $this->getBaseData();
15 | $data['METHOD'] = 'GetTransactionDetails';
16 | $data['TRANSACTIONID'] = $this->getTransactionReference();
17 |
18 | return $data;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/tests/Mock/ExpressFetchCheckoutFailure.txt:
--------------------------------------------------------------------------------
1 | HTTP/1.1 200 OK
2 | Date: 05 Apr 2007 23:44:11 GMT
3 | Server: Apache
4 | Connection: close
5 | Content-Type: text/plain; charset=utf-8
6 |
7 | TIMESTAMP=2007%2d04%2d05T23%3a44%3a11Z&CORRELATIONID=6b174e9bac3b3&ACK=Failure&VERSION=85.0&BUILD=11235635&L_ERRORCODE0=10414&L_SHORTMESSAGE0=Transaction%20refused%20because%20of%20an%20invalid%20argument.%20See%20additional%20error%20messages%20for%20details.&L_LONGMESSAGE0=The%20amount%20exceeds%20the%20maximum%20amount%20for%20a%20single%20transaction.&L_SEVERITYCODE0=Error
--------------------------------------------------------------------------------
/tests/Mock/RestTokenFailure.txt:
--------------------------------------------------------------------------------
1 | HTTP/1.1 401 Unauthorized
2 | Server: Apache-Coyote/1.1
3 | PROXY_SERVER_INFO: host=slcsbjava2.slc.paypal.com;threadId=3683
4 | Paypal-Debug-Id: f115dd7f08d14
5 | SERVER_INFO: identitysecuretokenserv:v1.oauth2.token&CalThreadId=126527&TopLevelTxnStartTime=146fc214a29&Host=slcsbidensectoken502.slc.paypal.com&pid=29059
6 | CORRELATION-ID: f115dd7f08d14
7 | Date: Thu, 03 Jul 2014 12:09:38 GMT
8 | Content-Type: application/json
9 | Content-Length: 93
10 |
11 | {"error":"invalid_client","error_description":"Client secret does not match for this client"}
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing Guidelines
2 |
3 | * Fork the project.
4 | * Make your feature addition or bug fix.
5 | * Add tests for it. This is important so I don't break it in a future version unintentionally.
6 | * Commit just the modifications, do not mess with the composer.json or CHANGELOG.md files.
7 | * Ensure your code is nicely formatted in the [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)
8 | style and that all tests pass.
9 | * Send the pull request.
10 | * Check that the Travis CI build passed. If not, rinse and repeat.
11 |
--------------------------------------------------------------------------------
/src/PayPalItem.php:
--------------------------------------------------------------------------------
1 | getParameter('code');
23 | }
24 |
25 | /**
26 | * Set the item code
27 | */
28 | public function setCode($value)
29 | {
30 | return $this->setParameter('code', $value);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/tests/Mock/ExpressCompletePurchaseFailureRedirect.txt:
--------------------------------------------------------------------------------
1 | HTTP/1.1 200 OK
2 | Date: Wed, 20 Feb 2013 13:55:50 GMT
3 | Server: Apache
4 | Content-Length: 214
5 | Connection: close
6 | Content-Type: text/plain; charset=utf-8
7 |
8 | TOKEN=ASDFASDFASDF&SUCCESSPAGEREDIRECTREQUESTED=false&TIMESTAMP=2016%2d09%2d12T14%3a06%3a12Z&CORRELATIONID=31e509fc8f6a8&ACK=Failure&VERSION=119%2e0&BUILD=25037053&L_ERRORCODE0=10486&L_SHORTMESSAGE0=This%20transaction%20couldn%27t%20be%20completed%2e&L_LONGMESSAGE0=This%20transaction%20couldn%27t%20be%20completed%2e%20Please%20redirect%20your%20customer%20to%20PayPal%2e&L_SEVERITYCODE0=Error
--------------------------------------------------------------------------------
/src/Message/ExpressCompletePurchaseRequest.php:
--------------------------------------------------------------------------------
1 | response = new ExpressCompletePurchaseResponse($this, $data);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Message/ExpressInContextAuthorizeResponse.php:
--------------------------------------------------------------------------------
1 | 'commit',
17 | 'token' => $this->getTransactionReference(),
18 | );
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Message/CaptureRequest.php:
--------------------------------------------------------------------------------
1 | validate('transactionReference', 'amount');
13 |
14 | $data = $this->getBaseData();
15 | $data['METHOD'] = 'DoCapture';
16 | $data['AMT'] = $this->getAmount();
17 | $data['CURRENCYCODE'] = $this->getCurrency();
18 | $data['AUTHORIZATIONID'] = $this->getTransactionReference();
19 | $data['COMPLETETYPE'] = 'Complete';
20 |
21 | return $data;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/ExpressInContextGateway.php:
--------------------------------------------------------------------------------
1 | createRequest('\Omnipay\PayPal\Message\ExpressInContextAuthorizeRequest', $parameters);
18 | }
19 |
20 | public function order(array $parameters = array())
21 | {
22 | return $this->createRequest('\Omnipay\PayPal\Message\ExpressInContextOrderRequest', $parameters);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/tests/Mock/RestExecuteSubscriptionSuccess.txt:
--------------------------------------------------------------------------------
1 | HTTP/1.1 200 OK
2 | Server: Apache-Coyote/1.1
3 | PROXY_SERVER_INFO: host=slcsbjava2.slc.paypal.com;threadId=76018
4 | Paypal-Debug-Id: 965491cb1a1e5
5 | SERVER_INFO: paymentsplatformserv:v1.payments.sale&CalThreadId=129&TopLevelTxnStartTime=14701c36ef9&Host=slcsbjm3.slc.paypal.com&pid=15797
6 | CORRELATION-ID: 965491cb1a1e5
7 | Content-Language: *
8 | Date: Fri, 04 Jul 2014 14:24:52 GMT
9 | Content-Type: application/json
10 |
11 | {
12 | "id": "I-0LN988D3JACS",
13 | "links": [
14 | {
15 | "href": "https://api.sandbox.paypal.com/v1/payments/billing-agreements/I-0LN988D3JACS",
16 | "rel": "self",
17 | "method": "GET"
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/src/Message/ExpressFetchCheckoutRequest.php:
--------------------------------------------------------------------------------
1 | validate();
13 |
14 | $data = $this->getBaseData();
15 | $data['METHOD'] = 'GetExpressCheckoutDetails';
16 |
17 | // token can either be specified directly, or inferred from the GET parameters
18 | if ($this->getToken()) {
19 | $data['TOKEN'] = $this->getToken();
20 | } else {
21 | $data['TOKEN'] = $this->httpRequest->query->get('token');
22 | }
23 |
24 | return $data;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Message/RefundRequest.php:
--------------------------------------------------------------------------------
1 | validate('transactionReference');
13 |
14 | $data = $this->getBaseData();
15 | $data['METHOD'] = 'RefundTransaction';
16 | $data['TRANSACTIONID'] = $this->getTransactionReference();
17 | $data['REFUNDTYPE'] = 'Full';
18 | if ($this->getAmount() > 0) {
19 | $data['REFUNDTYPE'] = 'Partial';
20 | $data['AMT'] = $this->getAmount();
21 | $data['CURRENCYCODE'] = $this->getCurrency();
22 | }
23 |
24 | return $data;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tests/Mock/RestCompletePurchaseFailure.txt:
--------------------------------------------------------------------------------
1 | HTTP/1.1 400 Bad Request
2 | Server: Apache-Coyote/1.1
3 | PROXY_SERVER_INFO: host=slcsbplatformapiserv3002.slc.paypal.com;threadId=533
4 | Paypal-Debug-Id: 65f24674659dc
5 | SERVER_INFO: paymentsplatformserv:v1.payments.payment&CalThreadId=166&TopLevelTxnStartTime=14b8c851ff1&Host=slcsbpaymentsplatformserv3001.slc.paypal.com&pid=12653
6 | Content-Language: *
7 | Date: Sun, 15 Feb 2015 09:15:09 GMT
8 | Connection: close, close
9 | Content-Type: application/json
10 | Content-Length: 235
11 |
12 | {"name":"PAYMENT_STATE_INVALID","message":"This request is invalid due to the current state of the payment","information_link":"https://developer.paypal.com/webapps/developer/docs/api/#PAYMENT_STATE_INVALID","debug_id":"65f24674659dc"}
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 | ./tests/
15 |
16 |
17 |
18 |
19 | ./src
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/PayPalItemBag.php:
--------------------------------------------------------------------------------
1 | items[] = $item;
29 | } else {
30 | $this->items[] = new PayPalItem($item);
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/tests/Message/RestFetchPurchaseRequestTest.php:
--------------------------------------------------------------------------------
1 | getHttpClient();
15 | $request = $this->getHttpRequest();
16 | $this->request = new RestFetchPurchaseRequest($client, $request);
17 | }
18 |
19 | public function testEndpoint()
20 | {
21 | $this->request->setTransactionReference('ABC-123');
22 | $this->assertStringEndsWith('/payments/payment/ABC-123', $this->request->getEndpoint());
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/tests/Mock/RestTokenSuccess.txt:
--------------------------------------------------------------------------------
1 | HTTP/1.1 200 OK
2 | Server: Apache-Coyote/1.1
3 | PROXY_SERVER_INFO: host=slcsbjava3.slc.paypal.com;threadId=3205
4 | Paypal-Debug-Id: 217a9ddefd384
5 | SERVER_INFO: identitysecuretokenserv:v1.oauth2.token&CalThreadId=91&TopLevelTxnStartTime=146fbfe679a&Host=slcsbidensectoken502.slc.paypal.com&pid=29059
6 | CORRELATION-ID: 217a9ddefd384
7 | Date: Thu, 03 Jul 2014 11:31:32 GMT
8 | Content-Type: application/json
9 | Content-Length: 328
10 |
11 | {"scope":"openid https://uri.paypal.com/services/invoicing https://api.paypal.com/v1/payments/.* https://api.paypal.com/v1/vault/credit-card/.* https://api.paypal.com/v1/vault/credit-card","access_token":"A015GQlKQ6uCRzLHSGRliANi59BHw6egNVKEWRnxvTwvLr0","token_type":"Bearer","app_id":"APP-80W284485P519543T","expires_in":28800}
--------------------------------------------------------------------------------
/src/Message/RestVoidRequest.php:
--------------------------------------------------------------------------------
1 | validate('transactionReference');
22 | }
23 |
24 | public function getEndpoint()
25 | {
26 | return parent::getEndpoint() . '/payments/authorization/' . $this->getTransactionReference() . '/void';
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Message/RestListWebhooksRequest.php:
--------------------------------------------------------------------------------
1 | getHttpClient();
17 | $request = $this->getHttpRequest();
18 | $this->request = new RestListWebhooksRequest($client, $request);
19 | }
20 |
21 | public function testEndpoint()
22 | {
23 | $this->assertStringEndsWith('/notifications/webhooks', $this->request->getEndpoint());
24 | }
25 |
26 | public function testGetData()
27 | {
28 | $this->assertEmpty($this->request->getData());
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Message/RestVerifyWebhookSignatureResponse.php:
--------------------------------------------------------------------------------
1 | getVerificationStatus();
20 | }
21 |
22 | /**
23 | * The status of the signature verification. Value is `SUCCESS` or `FAILURE`.
24 | *
25 | * @return string
26 | */
27 | public function getVerificationStatus()
28 | {
29 | return $this->data['verification_status'];
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/tests/Message/RestCompleteSubscriptionRequestTest.php:
--------------------------------------------------------------------------------
1 | getHttpClient();
16 | $request = $this->getHttpRequest();
17 | $this->request = new RestCompleteSubscriptionRequest($client, $request);
18 |
19 | $this->request->initialize(array(
20 | 'transactionReference' => 'ABC-123',
21 | ));
22 | }
23 |
24 | public function testGetData()
25 | {
26 | $data = $this->request->getData();
27 | $this->assertEquals(array(), $data);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/tests/Message/ExpressVoidRequestTest.php:
--------------------------------------------------------------------------------
1 | request = new ExpressVoidRequest($this->getHttpClient(), $this->getHttpRequest());
20 | $this->request->initialize(
21 | array(
22 | 'transactionReference' => 'ASDFASDFASDF',
23 | )
24 | );
25 | }
26 |
27 | public function testGetData()
28 | {
29 | $data = $this->request->getData();
30 |
31 | $this->assertSame('ASDFASDFASDF', $data['AUTHORIZATIONID']);
32 | $this->assertSame('DoVoid', $data['METHOD']);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/phpunit.xml.dist~:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 | ./tests/
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | ./src
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/tests/Message/RestCompletePurchaseRequestTest.php:
--------------------------------------------------------------------------------
1 | getHttpClient();
22 |
23 | $request = $this->getHttpRequest();
24 | $this->request = new RestCompletePurchaseRequest($client, $request);
25 | $this->request->initialize(array());
26 | }
27 |
28 | public function testGetData()
29 | {
30 | $this->request->setTransactionReference('abc123');
31 | $this->request->setPayerId('Payer12345');
32 |
33 | $data = $this->request->getData();
34 |
35 | $this->assertSame('Payer12345', $data['payer_id']);
36 | }
37 | }
--------------------------------------------------------------------------------
/tests/Message/RestCancelSubscriptionRequestTest.php:
--------------------------------------------------------------------------------
1 | getHttpClient();
16 | $request = $this->getHttpRequest();
17 | $this->request = new RestCancelSubscriptionRequest($client, $request);
18 |
19 | $this->request->initialize(array(
20 | 'transactionReference' => 'ABC-123',
21 | 'description' => 'Cancel this subscription',
22 | ));
23 | }
24 |
25 | public function testGetData()
26 | {
27 | $data = $this->request->getData();
28 | $this->assertEquals('Cancel this subscription', $data['note']);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/tests/Message/RestUpdatePlanRequestTest.php:
--------------------------------------------------------------------------------
1 | getHttpClient();
16 | $request = $this->getHttpRequest();
17 | $this->request = new RestUpdatePlanRequest($client, $request);
18 |
19 | $this->request->initialize(array(
20 | 'transactionReference' => 'ABC-123',
21 | 'state' => 'ACTIVE',
22 | ));
23 | }
24 |
25 | public function testGetData()
26 | {
27 | $data = $this->request->getData();
28 | $this->assertEquals('/', $data[0]['path']);
29 | $this->assertEquals('ACTIVE', $data[0]['value']['state']);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/tests/Message/RestSuspendSubscriptionRequestTest.php:
--------------------------------------------------------------------------------
1 | getHttpClient();
16 | $request = $this->getHttpRequest();
17 | $this->request = new RestSuspendSubscriptionRequest($client, $request);
18 |
19 | $this->request->initialize(array(
20 | 'transactionReference' => 'ABC-123',
21 | 'description' => 'Suspend this subscription',
22 | ));
23 | }
24 |
25 | public function testGetData()
26 | {
27 | $data = $this->request->getData();
28 | $this->assertEquals('Suspend this subscription', $data['note']);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Message/ExpressTransactionSearchResponse.php:
--------------------------------------------------------------------------------
1 | data as $key => $value) {
19 | if ($this->isSuccessful()
20 | && preg_match('/(L_)?(?[A-Za-z]+)(?[0-9]+)/', $key, $matches)
21 | ) {
22 | $payments[$matches['n']][$matches['key']] = $value;
23 | unset($this->data[$key]);
24 | }
25 | }
26 |
27 | $this->data['payments'] = $payments;
28 | }
29 |
30 | public function getPayments()
31 | {
32 | return $this->data['payments'];
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/tests/Message/RestFetchTransactionRequestTest.php:
--------------------------------------------------------------------------------
1 | getHttpClient();
15 | $request = $this->getHttpRequest();
16 | $this->request = new RestFetchTransactionRequest($client, $request);
17 | }
18 |
19 | public function testGetData()
20 | {
21 | $this->request->setTransactionReference('ABC-123');
22 | $data = $this->request->getData();
23 | $this->assertEquals(array(), $data);
24 | }
25 |
26 | public function testEndpoint()
27 | {
28 | $this->request->setTransactionReference('ABC-123');
29 | $this->assertStringEndsWith('/payments/sale/ABC-123', $this->request->getEndpoint());
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/tests/Message/RestReactivateSubscriptionRequestTest.php:
--------------------------------------------------------------------------------
1 | getHttpClient();
16 | $request = $this->getHttpRequest();
17 | $this->request = new RestReactivateSubscriptionRequest($client, $request);
18 |
19 | $this->request->initialize(array(
20 | 'transactionReference' => 'ABC-123',
21 | 'description' => 'Reactivate this subscription',
22 | ));
23 | }
24 |
25 | public function testGetData()
26 | {
27 | $data = $this->request->getData();
28 | $this->assertEquals('Reactivate this subscription', $data['note']);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/tests/Message/RestDeleteCardRequestTest.php:
--------------------------------------------------------------------------------
1 | request = new RestDeleteCardRequest($this->getHttpClient(), $this->getHttpRequest());
21 | $this->request->initialize(array('cardReference' => 'CARD-TEST123'));
22 | }
23 |
24 | public function testGetData()
25 | {
26 | $data = $this->request->getData();
27 | $this->assertTrue(is_array($data));
28 | $this->assertEmpty($data);
29 | }
30 |
31 | public function testEndpoint()
32 | {
33 | $this->assertStringEndsWith('/vault/credit-cards/CARD-TEST123', $this->request->getEndpoint());
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/tests/Message/RestListPlanRequestTest.php:
--------------------------------------------------------------------------------
1 | getHttpClient();
15 | $request = $this->getHttpRequest();
16 | $this->request = new RestListPlanRequest($client, $request);
17 | }
18 |
19 | public function testGetData()
20 | {
21 | $data = $this->request->getData();
22 | $this->assertArrayHasKey('page',$data);
23 | $this->assertArrayHasKey('status',$data);
24 | $this->assertArrayHasKey('page_size',$data);
25 | $this->assertArrayHasKey('total_required',$data);
26 | }
27 |
28 | public function testEndpoint()
29 | {
30 | $this->assertStringEndsWith('/payments/billing-plans', $this->request->getEndpoint());
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/tests/Mock/ExpressCompletePurchaseSuccess.txt:
--------------------------------------------------------------------------------
1 | HTTP/1.1 200 OK
2 | Date: Wed, 20 Feb 2013 13:54:27 GMT
3 | Server: Apache
4 | Content-Length: 869
5 | Connection: close
6 | Content-Type: text/plain; charset=utf-8
7 |
8 | TOKEN=EC%2d96V667110D1727015&SUCCESSPAGEREDIRECTREQUESTED=true&TIMESTAMP=2013%2d02%2d20T13%3a54%3a28Z&CORRELATIONID=f78b888897f8a&ACK=Success&VERSION=85%2e0&BUILD=5060305&INSURANCEOPTIONSELECTED=false&SHIPPINGOPTIONISDEFAULT=false&PAYMENTINFO_0_TRANSACTIONID=8RM57414KW761861W&PAYMENTINFO_0_RECEIPTID=0368%2d2088%2d8643%2d7560&PAYMENTINFO_0_TRANSACTIONTYPE=expresscheckout&PAYMENTINFO_0_PAYMENTTYPE=instant&PAYMENTINFO_0_ORDERTIME=2013%2d02%2d20T13%3a54%3a03Z&PAYMENTINFO_0_AMT=10%2e00&PAYMENTINFO_0_FEEAMT=0%2e59&PAYMENTINFO_0_TAXAMT=0%2e00&PAYMENTINFO_0_CURRENCYCODE=USD&PAYMENTINFO_0_PAYMENTSTATUS=Completed&PAYMENTINFO_0_PENDINGREASON=None&PAYMENTINFO_0_REASONCODE=None&PAYMENTINFO_0_PROTECTIONELIGIBILITY=Ineligible&PAYMENTINFO_0_PROTECTIONELIGIBILITYTYPE=None&PAYMENTINFO_0_SECUREMERCHANTACCOUNTID=VZTRGMSKHHAEW&PAYMENTINFO_0_ERRORCODE=0&PAYMENTINFO_0_ACK=Success
--------------------------------------------------------------------------------
/src/Message/RestRefundCaptureRequest.php:
--------------------------------------------------------------------------------
1 | validate('transactionReference');
22 |
23 | return array(
24 | 'amount' => array(
25 | 'currency' => $this->getCurrency(),
26 | 'total' => $this->getAmount(),
27 | ),
28 | 'description' => $this->getDescription(),
29 | );
30 | }
31 |
32 | public function getEndpoint()
33 | {
34 | return parent::getEndpoint() . '/payments/capture/' . $this->getTransactionReference() . '/refund';
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/tests/Mock/RestRefundSuccess.txt:
--------------------------------------------------------------------------------
1 | HTTP/1.1 201 Created
2 | Server: Apache-Coyote/1.1
3 | PROXY_SERVER_INFO: host=slcsbjava2.slc.paypal.com;threadId=76018
4 | Paypal-Debug-Id: 965491cb1a1e5
5 | SERVER_INFO: paymentsplatformserv:v1.payments.sale&CalThreadId=129&TopLevelTxnStartTime=14701c36ef9&Host=slcsbjm3.slc.paypal.com&pid=15797
6 | CORRELATION-ID: 965491cb1a1e5
7 | Content-Language: *
8 | Date: Fri, 04 Jul 2014 14:24:52 GMT
9 | Content-Type: application/json
10 | Content-Length: 592
11 |
12 | {"id":"7G199247NK652674M","create_time":"2014-07-04T14:24:52Z","update_time":"2014-07-04T14:24:52Z","state":"completed","amount":{"total":"2.34","currency":"USD"},"sale_id":"44E89981F8714392Y","parent_payment":"PAY-6RT04683U7444573DKO2WI6A","links":[{"href":"https://api.sandbox.paypal.com/v1/payments/refund/7G199247NK652674M","rel":"self","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/payments/payment/PAY-6RT04683U7444573DKO2WI6A","rel":"parent_payment","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/payments/sale/44E89981F8714392Y","rel":"sale","method":"GET"}]}
--------------------------------------------------------------------------------
/tests/Message/RestAuthorizeResponseTest.php:
--------------------------------------------------------------------------------
1 | getMockHttpResponse('RestPurchaseWithoutCardSuccess.txt');
14 | $data = json_decode($httpResponse->getBody()->getContents(), true);
15 |
16 | $response = new RestAuthorizeResponse($this->getMockRequest(), $data, $httpResponse->getStatusCode());
17 |
18 | $this->assertTrue($response->isSuccessful());
19 | $this->assertSame('PAY-3TJ47806DA028052TKTQGVYI', $response->getTransactionReference());
20 | $this->assertNull($response->getMessage());
21 |
22 | $this->assertNull($response->getRedirectData());
23 | $this->assertSame('GET', $response->getRedirectMethod());
24 | $this->assertSame('https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=EC-5KV58254GL528393N', $response->getRedirectUrl());
25 | }
26 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2012-2013 Adrian Macneil
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/tests/Mock/RestCreateCardSuccess.txt:
--------------------------------------------------------------------------------
1 | HTTP/1.1 201 Created
2 | Server: Apache-Coyote/1.1
3 | PROXY_SERVER_INFO: host=slcsbjava3.slc.paypal.com;threadId=39734
4 | Paypal-Debug-Id: 17a8320884bba
5 | Content-Language: *
6 | CORRELATION-ID: 17a8320884bba
7 | Date: Fri, 04 Jul 2014 14:50:33 GMT
8 | SERVER_INFO: vaultplatformserv:v1.vault.credit-card&CalThreadId=76352&TopLevelTxnStartTime=14701dafae7&Host=slcsbvaultplatformserv501.slc.paypal.com&pid=19516
9 | Content-Type: application/json
10 | Content-Length: 690
11 |
12 | {"id":"CARD-70E78145XN686604FKO3L6OQ","state":"ok","payer_id":"user12345","type":"visa","number":"xxxxxxxxxxxx0331","expire_month":"11","expire_year":"2018","first_name":"Betsy","last_name":"Buyer","valid_until":"2017-07-03T00:00:00Z","create_time":"2014-07-04T14:50:34Z","update_time":"2014-07-04T14:50:34Z","links":[{"href":"https://api.sandbox.paypal.com/v1/vault/credit-card/CARD-70E78145XN686604FKO3L6OQ","rel":"self","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/vault/credit-card/CARD-70E78145XN686604FKO3L6OQ","rel":"delete","method":"DELETE"},{"href":"https://api.sandbox.paypal.com/v1/vault/credit-card/CARD-70E78145XN686604FKO3L6OQ","rel":"patch","method":"PATCH"}]}
--------------------------------------------------------------------------------
/tests/Mock/RestCaptureSuccess.txt:
--------------------------------------------------------------------------------
1 | HTTP/1.1 200 OK
2 | Server: Apache-Coyote/1.1
3 | PROXY_SERVER_INFO: host=slcsbjava2.slc.paypal.com;threadId=127
4 | Paypal-Debug-Id: 030d6a098c7c5
5 | SERVER_INFO: paymentsplatformserv:v1.payments.authorization&CalThreadId=15946&TopLevelTxnStartTime=14701ba0b41&Host=slcsbjm3.slc.paypal.com&pid=15797
6 | CORRELATION-ID: 030d6a098c7c5
7 | Content-Language: *
8 | Date: Fri, 04 Jul 2014 14:14:42 GMT
9 | Content-Type: application/json
10 | Content-Length: 724
11 |
12 | {"id":"9EP22596VU4085001","create_time":"2014-07-04T14:14:35Z","update_time":"2014-07-04T14:14:42Z","amount":{"total":"7.47","currency":"USD"},"is_final_capture":false,"state":"completed","parent_payment":"PAY-66G66446716792522KO3LK4Y","links":[{"href":"https://api.sandbox.paypal.com/v1/payments/capture/9EP22596VU4085001","rel":"self","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/payments/capture/9EP22596VU4085001/refund","rel":"refund","method":"POST"},{"href":"https://api.sandbox.paypal.com/v1/payments/authorization/58N7596879166930B","rel":"authorization","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/payments/payment/PAY-66G66446716792522KO3LK4Y","rel":"parent_payment","method":"GET"}]}
--------------------------------------------------------------------------------
/.github/workflows/run-tests.yml:
--------------------------------------------------------------------------------
1 | name: Unit Tests
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | pull_request:
8 | branches:
9 | - "*"
10 | schedule:
11 | - cron: '0 0 * * *'
12 |
13 | jobs:
14 | php-tests:
15 | runs-on: ubuntu-latest
16 | timeout-minutes: 15
17 | env:
18 | COMPOSER_NO_INTERACTION: 1
19 |
20 | strategy:
21 | matrix:
22 | php: [8.1, 8.0, 7.4, 7.3, 7.2]
23 | dependency-version: [prefer-lowest, prefer-stable]
24 |
25 | name: P${{ matrix.php }} - ${{ matrix.dependency-version }}
26 |
27 | steps:
28 | - name: Checkout code
29 | uses: actions/checkout@v2
30 |
31 | - name: Setup PHP
32 | uses: shivammathur/setup-php@v2
33 | with:
34 | php-version: ${{ matrix.php }}
35 | coverage: none
36 | tools: composer:v2
37 |
38 | - name: Install dependencies
39 | run: |
40 | composer update --${{ matrix.dependency-version }} --prefer-dist --no-progress
41 |
42 | - name: Execute Unit Tests
43 | run: composer test
44 |
45 | - name: Check Code Style
46 | run: composer check-style
47 | if: ${{ matrix.dependency-version == 'prefer-stable' }}
48 |
--------------------------------------------------------------------------------
/tests/Message/RestSearchTransactionRequestTest.php:
--------------------------------------------------------------------------------
1 | getHttpClient();
16 | $request = $this->getHttpRequest();
17 | $this->request = new RestSearchTransactionRequest($client, $request);
18 |
19 | $this->request->initialize(array(
20 | 'agreementId' => 'ABC-123',
21 | 'startDate' => '2015-09-01',
22 | 'endDate' => '2015-09-30',
23 | ));
24 | }
25 |
26 | public function testGetData()
27 | {
28 | $data = $this->request->getData();
29 | $this->assertEquals('2015-09-01', $data['start_date']);
30 | $this->assertEquals('2015-09-30', $data['end_date']);
31 | }
32 |
33 | public function testEndpoint()
34 | {
35 | $this->assertStringEndsWith('/payments/billing-agreements/ABC-123/transactions', $this->request->getEndpoint());
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/tests/Mock/RestPurchaseWithoutCardSuccess.txt:
--------------------------------------------------------------------------------
1 | HTTP/1.1 201 Created
2 | Server: Apache-Coyote/1.1
3 | PROXY_SERVER_INFO: host=slcsbplatformapiserv3001.slc.paypal.com;threadId=383
4 | Paypal-Debug-Id: b4dc1c6623f68
5 | SERVER_INFO: paymentsplatformserv:v1.payments.payment&CalThreadId=166&TopLevelTxnStartTime=14b8ca1806f&Host=slcsbpaymentsplatformserv3001.slc.paypal.com&pid=12653
6 | Content-Language: *
7 | Date: Sun, 15 Feb 2015 09:46:09 GMT
8 | Content-Type: application/json
9 | Content-Length: 894
10 |
11 | {"id":"PAY-3TJ47806DA028052TKTQGVYI","create_time":"2015-02-15T09:46:09Z","update_time":"2015-02-15T09:46:09Z","state":"created","intent":"sale","payer":{"payment_method":"paypal","payer_info":{"shipping_address":{}}},"transactions":[{"amount":{"total":"199.00","currency":"USD","details":{"subtotal":"199.00"}},"description":"Product 1","item_list":{"items":[{"name":"Item 1","price":"199.00","currency":"USD","quantity":"1","description":"Item Description"}]},"related_resources":[]}],"links":[{"href":"https://api.sandbox.paypal.com/v1/payments/payment/PAY-3TJ47806DA028052TKTQGVYI","rel":"self","method":"GET"},{"href":"https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=EC-5KV58254GL528393N","rel":"approval_url","method":"REDIRECT"},{"href":"https://api.sandbox.paypal.com/v1/payments/payment/PAY-3TJ47806DA028052TKTQGVYI/execute","rel":"execute","method":"POST"}]}
--------------------------------------------------------------------------------
/src/Message/Response.php:
--------------------------------------------------------------------------------
1 | request = $request;
16 | parse_str($data, $this->data);
17 | }
18 |
19 | public function isPending()
20 | {
21 | return isset($this->data['PAYMENTINFO_0_PAYMENTSTATUS'])
22 | && $this->data['PAYMENTINFO_0_PAYMENTSTATUS'] == 'Pending';
23 | }
24 |
25 | public function isSuccessful()
26 | {
27 | return isset($this->data['ACK']) && in_array($this->data['ACK'], array('Success', 'SuccessWithWarning'));
28 | }
29 |
30 | public function getTransactionReference()
31 | {
32 | foreach (array('REFUNDTRANSACTIONID',
33 | 'TRANSACTIONID',
34 | 'PAYMENTINFO_0_TRANSACTIONID',
35 | 'AUTHORIZATIONID') as $key) {
36 | if (isset($this->data[$key])) {
37 | return $this->data[$key];
38 | }
39 | }
40 | }
41 |
42 | public function getMessage()
43 | {
44 | return isset($this->data['L_LONGMESSAGE0']) ? $this->data['L_LONGMESSAGE0'] : null;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "omnipay/paypal",
3 | "type": "library",
4 | "description": "PayPal gateway for Omnipay payment processing library",
5 | "keywords": [
6 | "gateway",
7 | "merchant",
8 | "omnipay",
9 | "pay",
10 | "payment",
11 | "paypal",
12 | "purchase"
13 | ],
14 | "homepage": "https://github.com/thephpleague/omnipay-paypal",
15 | "license": "MIT",
16 | "authors": [
17 | {
18 | "name": "Adrian Macneil",
19 | "email": "adrian@adrianmacneil.com"
20 | },
21 | {
22 | "name": "Omnipay Contributors",
23 | "homepage": "https://github.com/thephpleague/omnipay-paypal/contributors"
24 | }
25 | ],
26 | "autoload": {
27 | "psr-4": { "Omnipay\\PayPal\\" : "src/" }
28 | },
29 | "require": {
30 | "php": "^7.2|^8.0",
31 | "omnipay/common": "^3"
32 | },
33 | "require-dev": {
34 | "omnipay/tests": "^4.1.2",
35 | "squizlabs/php_codesniffer": "^3"
36 | },
37 | "extra": {
38 | "branch-alias": {
39 | "dev-master": "3.0.x-dev"
40 | }
41 | },
42 | "scripts": {
43 | "test": "phpunit",
44 | "check-style": "phpcs -p --standard=PSR2 src/",
45 | "fix-style": "phpcbf -p --standard=PSR2 src/"
46 | },
47 | "prefer-stable": true
48 | }
49 |
--------------------------------------------------------------------------------
/tests/Message/FetchTransactionRequestTest.php:
--------------------------------------------------------------------------------
1 | getHttpClient();
18 |
19 | $request = $this->getHttpRequest();
20 |
21 | $this->request = new FetchTransactionRequest($client, $request);
22 | }
23 |
24 | public function testGetData()
25 | {
26 | $this->request->setTransactionReference('ABC-123');
27 | $this->request->setUsername('testuser');
28 | $this->request->setPassword('testpass');
29 | $this->request->setSignature('SIG');
30 | $this->request->setSubject('SUB');
31 |
32 | $expected = array();
33 | $expected['METHOD'] = 'GetTransactionDetails';
34 | $expected['TRANSACTIONID'] = 'ABC-123';
35 | $expected['USER'] = 'testuser';
36 | $expected['PWD'] = 'testpass';
37 | $expected['SIGNATURE'] = 'SIG';
38 | $expected['SUBJECT'] = 'SUB';
39 | $expected['VERSION'] = RefundRequest::API_VERSION;
40 |
41 | $this->assertEquals($expected, $this->request->getData());
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/tests/Message/RestCreateSubscriptionRequestTest.php:
--------------------------------------------------------------------------------
1 | getHttpClient();
16 | $request = $this->getHttpRequest();
17 | $this->request = new RestCreateSubscriptionRequest($client, $request);
18 |
19 | $this->request->initialize(array(
20 | 'name' => 'Test Subscription',
21 | 'description' => 'Test Billing Subscription',
22 | 'startDate' => new \DateTime('now', new \DateTimeZone('UTC')),
23 | 'planId' => 'ABC-123',
24 | 'payerDetails' => array(
25 | 'payment_method' => 'paypal',
26 | ),
27 | ));
28 | }
29 |
30 | public function testGetData()
31 | {
32 | $data = $this->request->getData();
33 | $this->assertEquals('Test Subscription', $data['name']);
34 | $this->assertEquals('Test Billing Subscription', $data['description']);
35 | $this->assertEquals('ABC-123', $data['plan']['id']);
36 | $this->assertEquals('paypal', $data['payer']['payment_method']);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Message/ExpressCompletePurchaseResponse.php:
--------------------------------------------------------------------------------
1 | data['ACK']) && in_array($this->data['ACK'], array('Success', 'SuccessWithWarning'));
18 | return !$this->isRedirect() && $success;
19 | }
20 |
21 | /**
22 | * The complete purchase response can be in error where it wants to have your customer return to paypal.
23 | *
24 | * @return bool
25 | */
26 | public function isRedirect()
27 | {
28 | return isset($this->data['L_ERRORCODE0']) && in_array($this->data['L_ERRORCODE0'], array('10486'));
29 | }
30 |
31 | /**
32 | * The transaction reference obtained from the purchase() call can't be used to refund a purchase.
33 | *
34 | * @return string
35 | */
36 | public function getTransactionReference()
37 | {
38 | if ($this->isSuccessful() && isset($this->data['PAYMENTINFO_0_TRANSACTIONID'])) {
39 | return $this->data['PAYMENTINFO_0_TRANSACTIONID'];
40 | }
41 |
42 | return parent::getTransactionReference();
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/tests/Message/ResponseTest.php:
--------------------------------------------------------------------------------
1 | getMockRequest(), 'example=value&foo=bar');
13 | $this->assertEquals(array('example' => 'value', 'foo' => 'bar'), $response->getData());
14 | }
15 |
16 | public function testProPurchaseSuccess()
17 | {
18 | $httpResponse = $this->getMockHttpResponse('ProPurchaseSuccess.txt');
19 | $response = new Response($this->getMockRequest(), $httpResponse->getBody());
20 |
21 | $this->assertFalse($response->isPending());
22 | $this->assertTrue($response->isSuccessful());
23 | $this->assertSame('96U93778BD657313D', $response->getTransactionReference());
24 | $this->assertNull($response->getMessage());
25 | }
26 |
27 | public function testProPurchaseFailure()
28 | {
29 | $httpResponse = $this->getMockHttpResponse('ProPurchaseFailure.txt');
30 | $response = new Response($this->getMockRequest(), $httpResponse->getBody());
31 |
32 | $this->assertFalse($response->isPending());
33 | $this->assertFalse($response->isSuccessful());
34 | $this->assertNull($response->getTransactionReference());
35 | $this->assertSame('This transaction cannot be processed. Please enter a valid credit card expiration year.', $response->getMessage());
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/Message/RestCreateWebhookRequest.php:
--------------------------------------------------------------------------------
1 | \array_map(
14 | function ($value) {
15 | return ['name' => $value];
16 | },
17 | $this->getEventTypes()
18 | ),
19 | 'url' => $this->getUrl(),
20 | ];
21 | }
22 |
23 | /**
24 | * @return array
25 | */
26 | public function getEventTypes()
27 | {
28 | return $this->getParameter('event_types') ?: [];
29 | }
30 |
31 | /**
32 | * @inheritDoc
33 | */
34 | public function getEndpoint()
35 | {
36 | return parent::getEndpoint().'/notifications/webhooks';
37 | }
38 |
39 | /**
40 | * @return string|null
41 | */
42 | public function getUrl()
43 | {
44 | return $this->getParameter('webhook_url');
45 | }
46 |
47 | /**
48 | * @param array $eventTypes
49 | *
50 | * @return $this
51 | */
52 | public function setEventTypes(array $eventTypes)
53 | {
54 | return $this->setParameter('event_types', $eventTypes);
55 | }
56 |
57 | /**
58 | * @param string $url
59 | *
60 | * @return $this
61 | */
62 | public function setUrl($url)
63 | {
64 | return $this->setParameter('webhook_url', $url);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/tests/Message/RestVerifyWebhookSignatureResponseTest.php:
--------------------------------------------------------------------------------
1 | getMockRequest(),
13 | ['verification_status' => 'SUCCESS']
14 | );
15 |
16 | $this->assertSame('SUCCESS', $response->getVerificationStatus());
17 | }
18 |
19 | public function testIsSuccessfulWillReturnFalseIfParentCheckIsSuccesfullButVerificationFailed()
20 | {
21 | $response = new RestVerifyWebhookSignatureResponse(
22 | $this->getMockRequest(),
23 | ['verification_status' => 'FAILED']
24 | );
25 |
26 | $this->assertFalse($response->isSuccessful());
27 | }
28 |
29 | public function testIsSuccessfulWillReturnFalseIfParentCheckIsUnsuccesfull()
30 | {
31 | $response = new RestVerifyWebhookSignatureResponse(
32 | $this->getMockRequest(),
33 | ['verification_status' => 'foobar'],
34 | 400
35 | );
36 |
37 | $this->assertFalse($response->isSuccessful());
38 | }
39 |
40 | public function testIsSuccessfulWillReturnTrueIfEverythingIsOk()
41 | {
42 | $response = new RestVerifyWebhookSignatureResponse(
43 | $this->getMockRequest(),
44 | ['verification_status' => 'SUCCESS']
45 | );
46 |
47 | $this->assertTrue($response->isSuccessful());
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Support/InstantUpdateApi/ShippingOption.php:
--------------------------------------------------------------------------------
1 | name = $name;
28 | $this->amount = $amount;
29 | $this->isDefault = $isDefault;
30 | $this->label = $label;
31 | }
32 |
33 | /**
34 | * @return bool
35 | */
36 | public function hasLabel()
37 | {
38 | return !is_null($this->label);
39 | }
40 |
41 | /**
42 | * @return string
43 | */
44 | public function getName()
45 | {
46 | return $this->name;
47 | }
48 |
49 | /**
50 | * @return float
51 | */
52 | public function getAmount()
53 | {
54 | return $this->amount;
55 | }
56 |
57 | /**
58 | * @return boolean
59 | */
60 | public function isDefault()
61 | {
62 | return $this->isDefault;
63 | }
64 |
65 | /**
66 | * @return string
67 | */
68 | public function getLabel()
69 | {
70 | return $this->label;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/tests/Message/CaptureRequestTest.php:
--------------------------------------------------------------------------------
1 | getHttpClient();
18 | $request = $this->getHttpRequest();
19 | $this->request = new CaptureRequest($client, $request);
20 | }
21 |
22 | public function testGetData()
23 | {
24 | $this->request->setTransactionReference('ABC-123');
25 | $this->request->setAmount('1.23');
26 | $this->request->setCurrency('USD');
27 | $this->request->setUsername('testuser');
28 | $this->request->setPassword('testpass');
29 | $this->request->setSignature('SIG');
30 | $this->request->setSubject('SUB');
31 | $this->request->setButtonSource('BNCode_PP');
32 |
33 | $expected = array();
34 | $expected['METHOD'] = 'DoCapture';
35 | $expected['AUTHORIZATIONID'] = 'ABC-123';
36 | $expected['AMT'] = '1.23';
37 | $expected['CURRENCYCODE'] = 'USD';
38 | $expected['COMPLETETYPE'] = 'Complete';
39 | $expected['USER'] = 'testuser';
40 | $expected['PWD'] = 'testpass';
41 | $expected['SIGNATURE'] = 'SIG';
42 | $expected['SUBJECT'] = 'SUB';
43 | $expected['BUTTONSOURCE'] = 'BNCode_PP';
44 | $expected['VERSION'] = CaptureRequest::API_VERSION;
45 |
46 | $this->assertEquals($expected, $this->request->getData());
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/Message/RestFetchPurchaseRequest.php:
--------------------------------------------------------------------------------
1 |
19 | * // Fetch the transaction so that details can be found for refund, etc.
20 | * $transaction = $gateway->fetchPurchase();
21 | * $transaction->setTransactionReference($sale_id);
22 | * $response = $transaction->send();
23 | * $data = $response->getData();
24 | * echo "Gateway fetchTransaction response data == " . print_r($data, true) . "\n";
25 | *
26 | *
27 | * @see RestPurchaseRequest
28 | * @link https://developer.paypal.com/docs/api/#look-up-a-payment-resource
29 | */
30 | class RestFetchPurchaseRequest extends AbstractRestRequest
31 | {
32 | public function getData()
33 | {
34 | $this->validate('transactionReference');
35 | return array();
36 | }
37 |
38 | /**
39 | * Get HTTP Method.
40 | *
41 | * The HTTP method for fetchTransaction requests must be GET.
42 | * Using POST results in an error 500 from PayPal.
43 | *
44 | * @return string
45 | */
46 | protected function getHttpMethod()
47 | {
48 | return 'GET';
49 | }
50 |
51 | public function getEndpoint()
52 | {
53 | return parent::getEndpoint() . '/payments/payment/' . $this->getTransactionReference();
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/tests/Mock/RestPurchaseSuccess.txt:
--------------------------------------------------------------------------------
1 | HTTP/1.1 201 Created
2 | Server: Apache-Coyote/1.1
3 | PROXY_SERVER_INFO: host=slcsbjava2.slc.paypal.com;threadId=1534
4 | Paypal-Debug-Id: 98cbd3ab19dfe
5 | SERVER_INFO: paymentsplatformserv:v1.payments.payment&CalThreadId=129&TopLevelTxnStartTime=146fc9074ec&Host=slcsbjm3.slc.paypal.com&pid=15797
6 | CORRELATION-ID: 98cbd3ab19dfe
7 | Content-Language: *
8 | Date: Thu, 03 Jul 2014 14:11:10 GMT
9 | Content-Type: application/json
10 | Content-Length: 1243
11 |
12 | {"id":"PAY-6RT04683U7444573DKO2WI6A","create_time":"2014-07-03T14:11:04Z","update_time":"2014-07-03T14:11:10Z","state":"approved","intent":"sale","payer":{"payment_method":"credit_card","funding_instruments":[{"credit_card":{"type":"mastercard","number":"xxxxxxxxxxxx5559","expire_month":"12","expire_year":"2018","first_name":"Betsy","last_name":"Buyer"}}]},"transactions":[{"amount":{"total":"7.47","currency":"USD","details":{"subtotal":"7.47"}},"description":"This is the payment transaction description.","related_resources":[{"sale":{"id":"44E89981F8714392Y","create_time":"2014-07-03T14:11:04Z","update_time":"2014-07-03T14:11:10Z","state":"completed","amount":{"total":"7.47","currency":"USD"},"parent_payment":"PAY-6RT04683U7444573DKO2WI6A","links":[{"href":"https://api.sandbox.paypal.com/v1/payments/sale/44E89981F8714392Y","rel":"self","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/payments/sale/44E89981F8714392Y/refund","rel":"refund","method":"POST"},{"href":"https://api.sandbox.paypal.com/v1/payments/payment/PAY-6RT04683U7444573DKO2WI6A","rel":"parent_payment","method":"GET"}]}}]}],"links":[{"href":"https://api.sandbox.paypal.com/v1/payments/payment/PAY-6RT04683U7444573DKO2WI6A","rel":"self","method":"GET"}]}
13 |
--------------------------------------------------------------------------------
/src/Message/ExpressAuthorizeResponse.php:
--------------------------------------------------------------------------------
1 | data['ACK']) && in_array($this->data['ACK'], array('Success', 'SuccessWithWarning'));
23 | }
24 |
25 | public function getRedirectUrl()
26 | {
27 | return $this->getCheckoutEndpoint().'?'.http_build_query($this->getRedirectQueryParameters(), '', '&');
28 | }
29 |
30 | public function getTransactionReference()
31 | {
32 | return isset($this->data['TOKEN']) ? $this->data['TOKEN'] : null;
33 | }
34 |
35 | public function getRedirectMethod()
36 | {
37 | return 'GET';
38 | }
39 |
40 | public function getRedirectData()
41 | {
42 | return null;
43 | }
44 |
45 | protected function getRedirectQueryParameters()
46 | {
47 | return array(
48 | 'cmd' => '_express-checkout',
49 | 'useraction' => 'commit',
50 | 'token' => $this->getTransactionReference(),
51 | );
52 | }
53 |
54 | protected function getCheckoutEndpoint()
55 | {
56 | return $this->getRequest()->getTestMode() ? $this->testCheckoutEndpoint : $this->liveCheckoutEndpoint;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/Message/RestTokenRequest.php:
--------------------------------------------------------------------------------
1 | 'client_credentials');
24 | }
25 |
26 | protected function getEndpoint()
27 | {
28 | return parent::getEndpoint() . '/oauth2/token';
29 | }
30 |
31 | public function sendData($data)
32 | {
33 | $body = $data ? http_build_query($data, '', '&') : null;
34 | $httpResponse = $this->httpClient->request(
35 | $this->getHttpMethod(),
36 | $this->getEndpoint(),
37 | array(
38 | 'Accept' => 'application/json',
39 | 'Authorization' => 'Basic ' . base64_encode("{$this->getClientId()}:{$this->getSecret()}"),
40 | ),
41 | $body
42 | );
43 | // Empty response body should be parsed also as and empty array
44 | $body = (string) $httpResponse->getBody()->getContents();
45 | $jsonToArrayResponse = !empty($body) ? json_decode($body, true) : array();
46 | return $this->response = new RestResponse($this, $jsonToArrayResponse, $httpResponse->getStatusCode());
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/Message/ProAuthorizeRequest.php:
--------------------------------------------------------------------------------
1 | validate('amount', 'card');
13 | $this->getCard()->validate();
14 |
15 | $data = $this->getBaseData();
16 | $data['METHOD'] = 'DoDirectPayment';
17 | $data['PAYMENTACTION'] = 'Authorization';
18 | $data['AMT'] = $this->getAmount();
19 | $data['CURRENCYCODE'] = $this->getCurrency();
20 | $data['INVNUM'] = $this->getTransactionId();
21 | $data['DESC'] = $this->getDescription();
22 |
23 | // add credit card details
24 | $data['ACCT'] = $this->getCard()->getNumber();
25 | $data['CREDITCARDTYPE'] = $this->getCard()->getBrand();
26 | $data['EXPDATE'] = $this->getCard()->getExpiryDate('mY');
27 | $data['STARTDATE'] = $this->getCard()->getStartDate('mY');
28 | $data['CVV2'] = $this->getCard()->getCvv();
29 | $data['ISSUENUMBER'] = $this->getCard()->getIssueNumber();
30 | $data['IPADDRESS'] = $this->getClientIp();
31 | $data['FIRSTNAME'] = $this->getCard()->getFirstName();
32 | $data['LASTNAME'] = $this->getCard()->getLastName();
33 | $data['EMAIL'] = $this->getCard()->getEmail();
34 | $data['STREET'] = $this->getCard()->getAddress1();
35 | $data['STREET2'] = $this->getCard()->getAddress2();
36 | $data['CITY'] = $this->getCard()->getCity();
37 | $data['STATE'] = $this->getCard()->getState();
38 | $data['ZIP'] = $this->getCard()->getPostcode();
39 | $data['COUNTRYCODE'] = strtoupper($this->getCard()->getCountry());
40 |
41 | return $data;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/tests/Message/RestCreateWebhookRequestTest.php:
--------------------------------------------------------------------------------
1 | getHttpClient();
17 | $request = $this->getHttpRequest();
18 | $this->request = new RestCreateWebhookRequest($client, $request);
19 | }
20 |
21 | public function testGetData()
22 | {
23 | $event1 = 'PAYMENT.AUTHORIZATION.CREATED';
24 | $event2 = 'PAYMENT.AUTHORIZATION.VOIDED';
25 | $url = 'https://foo.bar/baz';
26 | $this->request->initialize(
27 | [
28 | 'event_types' => [$event1, $event2],
29 | 'url' => $url,
30 | ]
31 | );
32 |
33 | $this->assertEquals(
34 | [
35 | 'event_types' => [['name' => $event1], ['name' => $event2]],
36 | 'url' => $url,
37 | ],
38 | $this->request->getData()
39 | );
40 | }
41 |
42 | public function testGetEndpoint()
43 | {
44 | $this->assertStringEndsWith('/notifications/webhooks', $this->request->getEndpoint());
45 | }
46 |
47 | public function testGetEventTypes()
48 | {
49 | $value = ['PAYMENT.AUTHORIZATION.CREATED'];
50 | $this->request->setEventTypes($value);
51 | self::assertSame($value, $this->request->getEventTypes());
52 | }
53 |
54 | public function testGetUrl()
55 | {
56 | $value = 'https://foo.bar/baz';
57 | $this->request->setUrl($value);
58 | self::assertSame($value, $this->request->getUrl());
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/tests/Message/ExpressTransactionSearchResponseTest.php:
--------------------------------------------------------------------------------
1 | getMockRequest(), 'ACK=Success&BUILD=18308778');
13 |
14 | $this->assertEquals(
15 | array('ACK' => 'Success', 'BUILD' => '18308778', 'payments' => array()),
16 | $response->getData()
17 | );
18 | }
19 |
20 | public function testExpressTransactionSearch()
21 | {
22 | $httpResponse = $this->getMockHttpResponse('ExpressTransactionSearchResponse.txt');
23 |
24 | $response = new ExpressTransactionSearchResponse($this->getMockRequest(), $httpResponse->getBody());
25 |
26 | $this->assertTrue($response->isSuccessful());
27 | $this->assertNull($response->getMessage());
28 | $this->assertArrayHasKey('payments', $response->getData());
29 |
30 | foreach ($response->getPayments() as $payment) {
31 | $this->assertArrayHasKey('TIMESTAMP', $payment);
32 | $this->assertArrayHasKey('TIMEZONE', $payment);
33 | $this->assertArrayHasKey('TYPE', $payment);
34 | $this->assertArrayHasKey('EMAIL', $payment);
35 | $this->assertArrayHasKey('NAME', $payment);
36 | $this->assertArrayHasKey('TRANSACTIONID', $payment);
37 | $this->assertArrayHasKey('STATUS', $payment);
38 | $this->assertArrayHasKey('AMT', $payment);
39 | $this->assertArrayHasKey('CURRENCYCODE', $payment);
40 | $this->assertArrayHasKey('FEEAMT', $payment);
41 | $this->assertArrayHasKey('NETAMT', $payment);
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/src/Message/ExpressCompleteAuthorizeRequest.php:
--------------------------------------------------------------------------------
1 | validate('amount');
13 |
14 | $data = $this->getBaseData();
15 | $data['METHOD'] = 'DoExpressCheckoutPayment';
16 | $data['PAYMENTREQUEST_0_PAYMENTACTION'] = 'Authorization';
17 | $data['PAYMENTREQUEST_0_AMT'] = $this->getAmount();
18 | $data['PAYMENTREQUEST_0_CURRENCYCODE'] = $this->getCurrency();
19 | $data['PAYMENTREQUEST_0_INVNUM'] = $this->getTransactionId();
20 | $data['PAYMENTREQUEST_0_DESC'] = $this->getDescription();
21 | $data['PAYMENTREQUEST_0_NOTIFYURL'] = $this->getNotifyUrl();
22 |
23 | $data['MAXAMT'] = $this->getMaxAmount();
24 | $data['PAYMENTREQUEST_0_TAXAMT'] = $this->getTaxAmount();
25 | $data['PAYMENTREQUEST_0_SHIPPINGAMT'] = $this->getShippingAmount();
26 | $data['PAYMENTREQUEST_0_HANDLINGAMT'] = $this->getHandlingAmount();
27 | $data['PAYMENTREQUEST_0_SHIPDISCAMT'] = $this->getShippingDiscount();
28 | $data['PAYMENTREQUEST_0_INSURANCEAMT'] = $this->getInsuranceAmount();
29 |
30 | $data['TOKEN'] = $this->getToken() ? $this->getToken() : $this->httpRequest->query->get('token');
31 | $data['PAYERID'] = $this->getPayerID() ? $this->getPayerID() : $this->httpRequest->query->get('PayerID');
32 |
33 | $data = array_merge($data, $this->getItemData());
34 |
35 | return $data;
36 | }
37 |
38 | public function getPayerID()
39 | {
40 | return $this->getParameter('payerID');
41 | }
42 |
43 | public function setPayerID($value)
44 | {
45 | return $this->setParameter('payerID', $value);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/tests/Mock/RestAuthorizationSuccess.txt:
--------------------------------------------------------------------------------
1 | HTTP/1.1 201 Created
2 | Server: Apache-Coyote/1.1
3 | PROXY_SERVER_INFO: host=slcsbjava3.slc.paypal.com;threadId=3224
4 | Paypal-Debug-Id: 2a1b9202663bc
5 | SERVER_INFO: paymentsplatformserv:v1.payments.payment&CalThreadId=206&TopLevelTxnStartTime=14701b4cb42&Host=slcsbjm1.slc.paypal.com&pid=20119
6 | CORRELATION-ID: 2a1b9202663bc
7 | Content-Language: *
8 | Date: Fri, 04 Jul 2014 14:09:00 GMT
9 | Content-Type: application/json
10 | Content-Length: 1435
11 |
12 | {"id":"PAY-66G66446716792522KO3LK4Y","create_time":"2014-07-04T14:08:51Z","update_time":"2014-07-04T14:09:01Z","state":"approved","intent":"authorize","payer":{"payment_method":"credit_card","funding_instruments":[{"credit_card":{"type":"mastercard","number":"xxxxxxxxxxxx5559","expire_month":"12","expire_year":"2018","first_name":"Betsy","last_name":"Buyer"}}]},"transactions":[{"amount":{"total":"7.47","currency":"USD","details":{"subtotal":"7.47"}},"description":"This is the payment transaction description.","related_resources":[{"authorization":{"id":"58N7596879166930B","create_time":"2014-07-04T14:08:51Z","update_time":"2014-07-04T14:09:01Z","state":"authorized","amount":{"total":"7.47","currency":"USD"},"parent_payment":"PAY-66G66446716792522KO3LK4Y","valid_until":"2014-08-02T14:08:51Z","links":[{"href":"https://api.sandbox.paypal.com/v1/payments/authorization/58N7596879166930B","rel":"self","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/payments/authorization/58N7596879166930B/capture","rel":"capture","method":"POST"},{"href":"https://api.sandbox.paypal.com/v1/payments/authorization/58N7596879166930B/void","rel":"void","method":"POST"},{"href":"https://api.sandbox.paypal.com/v1/payments/payment/PAY-66G66446716792522KO3LK4Y","rel":"parent_payment","method":"GET"}]}}]}],"links":[{"href":"https://api.sandbox.paypal.com/v1/payments/payment/PAY-66G66446716792522KO3LK4Y","rel":"self","method":"GET"}]}
--------------------------------------------------------------------------------
/src/Message/RestFetchTransactionRequest.php:
--------------------------------------------------------------------------------
1 |
20 | * // Fetch the transaction so that details can be found for refund, etc.
21 | * $transaction = $gateway->fetchTransaction();
22 | * $transaction->setTransactionReference($sale_id);
23 | * $response = $transaction->send();
24 | * $data = $response->getData();
25 | * echo "Gateway fetchTransaction response data == " . print_r($data, true) . "\n";
26 | *
27 | *
28 | * @see RestPurchaseRequest
29 | * @link https://developer.paypal.com/docs/api/#sale-transactions
30 | */
31 | class RestFetchTransactionRequest extends AbstractRestRequest
32 | {
33 | public function getData()
34 | {
35 | $this->validate('transactionReference');
36 | return array();
37 | }
38 |
39 | /**
40 | * Get HTTP Method.
41 | *
42 | * The HTTP method for fetchTransaction requests must be GET.
43 | * Using POST results in an error 500 from PayPal.
44 | *
45 | * @return string
46 | */
47 | protected function getHttpMethod()
48 | {
49 | return 'GET';
50 | }
51 |
52 | public function getEndpoint()
53 | {
54 | return parent::getEndpoint() . '/payments/sale/' . $this->getTransactionReference();
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/tests/Message/RestCreateCardRequestTest.php:
--------------------------------------------------------------------------------
1 | request = new RestCreateCardRequest($this->getHttpClient(), $this->getHttpRequest());
21 |
22 | $card = $this->getValidCard();
23 | $this->card = new CreditCard($card);
24 |
25 | $this->request->initialize(array('card' => $card));
26 | }
27 |
28 | public function testGetData()
29 | {
30 | $card = $this->card;
31 | $data = $this->request->getData();
32 |
33 | $this->assertSame($card->getNumber(), $data['number']);
34 | $this->assertSame($card->getBrand(), $data['type']);
35 | $this->assertSame($card->getExpiryMonth(), $data['expire_month']);
36 | $this->assertSame($card->getExpiryYear(), $data['expire_year']);
37 | $this->assertSame($card->getCvv(), $data['cvv2']);
38 | $this->assertSame($card->getFirstName(), $data['first_name']);
39 | $this->assertSame($card->getLastName(), $data['last_name']);
40 | $this->assertSame($card->getAddress1(), $data['billing_address']['line1']);
41 | $this->assertSame($card->getAddress2(), $data['billing_address']['line2']);
42 | $this->assertSame($card->getCity(), $data['billing_address']['city']);
43 | $this->assertSame($card->getState(), $data['billing_address']['state']);
44 | $this->assertSame($card->getPostcode(), $data['billing_address']['postal_code']);
45 | $this->assertSame($card->getCountry(), $data['billing_address']['country_code']);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/tests/Mock/RestFetchPurchaseSuccess.txt:
--------------------------------------------------------------------------------
1 | HTTP/1.1 201 Created
2 | Server: Apache-Coyote/1.1
3 | PROXY_SERVER_INFO: host=slcsbjava2.slc.paypal.com;threadId=1534
4 | Paypal-Debug-Id: 98cbd3ab19dfe
5 | SERVER_INFO: paymentsplatformserv:v1.payments.payment&CalThreadId=129&TopLevelTxnStartTime=146fc9074ec&Host=slcsbjm3.slc.paypal.com&pid=15797
6 | CORRELATION-ID: 98cbd3ab19dfe
7 | Content-Language: *
8 | Date: Thu, 03 Jul 2014 14:11:10 GMT
9 | Content-Type: application/json
10 |
11 | {
12 | "id": "PAY-0WB587530N302915SKXWVCSQ",
13 | "create_time": "2015-09-07T08:56:42Z",
14 | "update_time": "2015-09-07T08:56:42Z",
15 | "state": "created",
16 | "intent": "sale",
17 | "payer": {
18 | "payment_method": "paypal",
19 | "payer_info": {
20 | "shipping_address": []
21 | }
22 | },
23 | "transactions": [
24 | {
25 | "amount": {
26 | "total": "10.00",
27 | "currency": "AUD",
28 | "details": {
29 | "subtotal": "10.00"
30 | }
31 | },
32 | "description": "This is a test purchase transaction.",
33 | "related_resources": []
34 | }
35 | ],
36 | "links": [
37 | {
38 | "href": "https:\/\/api.sandbox.paypal.com\/v1\/payments\/payment\/PAY-0WB587530N302915SKXWVCSQ",
39 | "rel": "self",
40 | "method": "GET"
41 | },
42 | {
43 | "href": "https:\/\/www.sandbox.paypal.com\/cgi-bin\/webscr?cmd=_express-checkout&token=EC-3DR71034MD528800J",
44 | "rel": "approval_url",
45 | "method": "REDIRECT"
46 | },
47 | {
48 | "href": "https:\/\/api.sandbox.paypal.com\/v1\/payments\/payment\/PAY-0WB587530N302915SKXWVCSQ\/execute",
49 | "rel": "execute",
50 | "method": "POST"
51 | }
52 | ]
53 | }
54 |
--------------------------------------------------------------------------------
/tests/Message/RestCreatePlanRequestTest.php:
--------------------------------------------------------------------------------
1 | getHttpClient();
16 | $request = $this->getHttpRequest();
17 | $this->request = new RestCreatePlanRequest($client, $request);
18 |
19 | $this->request->initialize(array(
20 | 'name' => 'Super Duper Billing Plan',
21 | 'description' => 'Test Billing Plan',
22 | 'type' => RestGateway::BILLING_PLAN_TYPE_FIXED,
23 | 'paymentDefinitions' => array(
24 | array(
25 | 'name' => 'Monthly Payments',
26 | 'type' => RestGateway::PAYMENT_REGULAR,
27 | 'frequency' => RestGateway::BILLING_PLAN_FREQUENCY_MONTH,
28 | 'frequency_interval' => 1,
29 | 'cycles' => 12,
30 | 'amount' => array(
31 | 'value' => 10.00,
32 | 'currency' => 'USD',
33 | )
34 | )
35 | ),
36 | 'merchantPreferences' => array(
37 | 'name' => 'asdf',
38 | ),
39 | ));
40 | }
41 |
42 | public function testGetData()
43 | {
44 | $data = $this->request->getData();
45 | $this->assertEquals('Super Duper Billing Plan', $data['name']);
46 | $this->assertEquals(RestGateway::BILLING_PLAN_TYPE_FIXED, $data['type']);
47 | $this->assertEquals('Monthly Payments', $data['payment_definitions'][0]['name']);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/tests/ProGatewayTest.php:
--------------------------------------------------------------------------------
1 | gateway = new ProGateway($this->getHttpClient(), $this->getHttpRequest());
15 |
16 | $this->options = array(
17 | 'amount' => '10.00',
18 | 'card' => new CreditCard(array(
19 | 'firstName' => 'Example',
20 | 'lastName' => 'User',
21 | 'number' => '4111111111111111',
22 | 'expiryMonth' => '12',
23 | 'expiryYear' => date('Y'),
24 | 'cvv' => '123',
25 | )),
26 | );
27 | }
28 |
29 | public function testAuthorize()
30 | {
31 | $this->setMockHttpResponse('ProPurchaseSuccess.txt');
32 |
33 | $response = $this->gateway->authorize($this->options)->send();
34 |
35 | $this->assertTrue($response->isSuccessful());
36 | $this->assertEquals('96U93778BD657313D', $response->getTransactionReference());
37 | $this->assertNull($response->getMessage());
38 | }
39 |
40 | public function testPurchase()
41 | {
42 | $this->setMockHttpResponse('ProPurchaseSuccess.txt');
43 |
44 | $response = $this->gateway->purchase($this->options)->send();
45 |
46 | $this->assertTrue($response->isSuccessful());
47 | $this->assertEquals('96U93778BD657313D', $response->getTransactionReference());
48 | $this->assertNull($response->getMessage());
49 | }
50 |
51 | public function testFetchTransaction()
52 | {
53 | $request = $this->gateway->fetchTransaction(array('transactionReference' => 'abc123'));
54 |
55 | $this->assertInstanceOf('\Omnipay\PayPal\Message\FetchTransactionRequest', $request);
56 | $this->assertSame('abc123', $request->getTransactionReference());
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/tests/Mock/RestCompletePurchaseSuccess.txt:
--------------------------------------------------------------------------------
1 | HTTP/1.1 200 OK
2 | Server: Apache-Coyote/1.1
3 | PROXY_SERVER_INFO: host=slcsbplatformapiserv3001.slc.paypal.com;threadId=216
4 | Paypal-Debug-Id: 539b1c0678b08
5 | SERVER_INFO: paymentsplatformserv:v1.payments.payment&CalThreadId=4342&TopLevelTxnStartTime=14b8c84b1f3&Host=slcsbpaymentsplatformserv3002.slc.paypal.com&pid=8929
6 | Content-Language: *
7 | Date: Sun, 15 Feb 2015 09:14:43 GMT
8 | Content-Type: application/json
9 | Content-Length: 1632
10 |
11 | {"id":"PAY-4BF374015W374910XKTQGGBZ","create_time":"2015-02-15T09:12:36Z","update_time":"2015-02-15T09:14:43Z","state":"approved","intent":"sale","payer":{"payment_method":"paypal","payer_info":{"email":"test.buyer@example.com","first_name":"Betsy","last_name":"Buyer","payer_id":"Payer12345","shipping_address":{"line1":"test","city":"","state":"","postal_code":"123456","country_code":"US","recipient_name":"Buyer Betsy"}}},"transactions":[{"amount":{"total":"100.00","currency":"USD","details":{"subtotal":"100.00","fee":"3.90"}},"description":"The product description","item_list":{"items":[{"name":"Item 1","price":"100.00","currency":"USD","quantity":"1","description":"Standard Item"}],"shipping_address":{"recipient_name":"Buyer Betsy","line1":"test","city":"","state":"","postal_code":"123456","country_code":"US"}},"related_resources":[{"sale":{"id":"9EA05739TH369572R","create_time":"2015-02-15T09:12:36Z","update_time":"2015-02-15T09:14:43Z","amount":{"total":"100.00","currency":"USD"},"payment_mode":"INSTANT_TRANSFER","state":"completed","protection_eligibility":"INELIGIBLE","parent_payment":"PAY-4BF374015W374910XKTQGGBZ","links":[{"href":"https://api.sandbox.paypal.com/v1/payments/sale/9EA05739TH369572R","rel":"self","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/payments/sale/9EA05739TH369572R/refund","rel":"refund","method":"POST"},{"href":"https://api.sandbox.paypal.com/v1/payments/payment/PAY-4BF374015W374910XKTQGGBZ","rel":"parent_payment","method":"GET"}]}}]}],"links":[{"href":"https://api.sandbox.paypal.com/v1/payments/payment/PAY-4BF374015W374910XKTQGGBZ","rel":"self","method":"GET"}]}
--------------------------------------------------------------------------------
/src/Message/RestDeleteCardRequest.php:
--------------------------------------------------------------------------------
1 |
30 | * $transaction = $gateway->deleteCard();
31 | * $transaction->setCardReference($card_id);
32 | * $response = $transaction->send();
33 | * if ($response->isSuccessful()) {
34 | * echo "Gateway deleteCard was successful.\n";
35 | * } else {
36 | * echo "Gateway deleteCard failed.\n";
37 | * }
38 | *
39 | *
40 | * @link https://developer.paypal.com/docs/api/#vault
41 | * @link https://developer.paypal.com/docs/api/#delete-a-stored-credit-card
42 | * @link http://bit.ly/1wUQ33R
43 | * @see RestCreateCardRequest
44 | */
45 | class RestDeleteCardRequest extends AbstractRestRequest
46 | {
47 | public function getHttpMethod()
48 | {
49 | return 'DELETE';
50 | }
51 |
52 | public function getData()
53 | {
54 | $this->validate('cardReference');
55 | return array();
56 | }
57 |
58 | public function getEndpoint()
59 | {
60 | return parent::getEndpoint() . '/vault/credit-cards/' . $this->getCardReference();
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/tests/Message/RefundRequestTest.php:
--------------------------------------------------------------------------------
1 | getHttpClient();
18 |
19 | $request = $this->getHttpRequest();
20 |
21 | $this->request = new RefundRequest($client, $request);
22 | }
23 |
24 | /**
25 | * @dataProvider provideRefundTypes
26 | */
27 | public function testGetData($type, $amount)
28 | {
29 | $this->request->setAmount($amount);
30 | $this->request->setCurrency('USD');
31 | $this->request->setTransactionReference('ABC-123');
32 | $this->request->setUsername('testuser');
33 | $this->request->setPassword('testpass');
34 | $this->request->setSignature('SIG');
35 | $this->request->setSubject('SUB');
36 |
37 | $expected = array();
38 | $expected['REFUNDTYPE'] = $type;
39 | $expected['METHOD'] = 'RefundTransaction';
40 | $expected['TRANSACTIONID'] = 'ABC-123';
41 | $expected['USER'] = 'testuser';
42 | $expected['PWD'] = 'testpass';
43 | $expected['SIGNATURE'] = 'SIG';
44 | $expected['SUBJECT'] = 'SUB';
45 | $expected['VERSION'] = RefundRequest::API_VERSION;
46 | // $amount will be a formatted string, and '0.00' evaluates to true
47 | if ((float)$amount) {
48 | $expected['AMT'] = $amount;
49 | $expected['CURRENCYCODE'] = 'USD';
50 | }
51 |
52 | $this->assertEquals($expected, $this->request->getData());
53 | }
54 |
55 | public function provideRefundTypes()
56 | {
57 | return array(
58 | 'Partial' => array('Partial', '1.23'),
59 | // All amounts must include decimals or be a float if the currency supports decimals.
60 | 'Full' => array('Full', '0.00'),
61 | );
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/Message/RestResponse.php:
--------------------------------------------------------------------------------
1 | statusCode = $statusCode;
22 | }
23 |
24 | public function isSuccessful()
25 | {
26 | return empty($this->data['error']) && $this->getCode() < 400;
27 | }
28 |
29 | public function getTransactionReference()
30 | {
31 | // This is usually correct for payments, authorizations, etc
32 | if (!empty($this->data['transactions']) && !empty($this->data['transactions'][0]['related_resources'])) {
33 | foreach (array('sale', 'authorization') as $type) {
34 | if (!empty($this->data['transactions'][0]['related_resources'][0][$type])) {
35 | return $this->data['transactions'][0]['related_resources'][0][$type]['id'];
36 | }
37 | }
38 | }
39 |
40 | // This is a fallback, but is correct for fetch transaction and possibly others
41 | if (!empty($this->data['id'])) {
42 | return $this->data['id'];
43 | }
44 |
45 | return null;
46 | }
47 |
48 | public function getMessage()
49 | {
50 | if (isset($this->data['error_description'])) {
51 | return $this->data['error_description'];
52 | }
53 |
54 | if (isset($this->data['message'])) {
55 | return $this->data['message'];
56 | }
57 |
58 | return null;
59 | }
60 |
61 | public function getCode()
62 | {
63 | return $this->statusCode;
64 | }
65 |
66 | public function getCardReference()
67 | {
68 | if (isset($this->data['id'])) {
69 | return $this->data['id'];
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/Message/RestCaptureRequest.php:
--------------------------------------------------------------------------------
1 |
28 | * // Once the transaction has been authorized, we can capture it for final payment.
29 | * $transaction = $gateway->capture(array(
30 | * 'amount' => '10.00',
31 | * 'currency' => 'AUD',
32 | * ));
33 | * $transaction->setTransactionReference($auth_id);
34 | * $response = $transaction->send();
35 | *
36 | *
37 | * @see RestAuthorizeRequest
38 | * @link https://developer.paypal.com/docs/api/#capture-an-authorization
39 | */
40 | class RestCaptureRequest extends AbstractRestRequest
41 | {
42 | public function getData()
43 | {
44 | $this->validate('transactionReference', 'amount');
45 |
46 | return array(
47 | 'amount' => array(
48 | 'currency' => $this->getCurrency(),
49 | 'total' => $this->getAmount(),
50 | ),
51 | 'is_final_capture' => true,
52 | );
53 | }
54 |
55 | public function getEndpoint()
56 | {
57 | return parent::getEndpoint() . '/payments/authorization/' . $this->getTransactionReference() . '/capture';
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/tests/Message/ExpressAuthorizeResponseTest.php:
--------------------------------------------------------------------------------
1 | getMockRequest(), 'example=value&foo=bar');
14 |
15 | $this->assertEquals(array('example' => 'value', 'foo' => 'bar'), $response->getData());
16 | }
17 |
18 | public function testExpressPurchaseSuccess()
19 | {
20 | $httpResponse = $this->getMockHttpResponse('ExpressPurchaseSuccess.txt');
21 | $request = $this->getMockRequest();
22 | $request->shouldReceive('getTestMode')->once()->andReturn(true);
23 | $response = new ExpressAuthorizeResponse($request, $httpResponse->getBody());
24 |
25 | $this->assertFalse($response->isPending());
26 | $this->assertFalse($response->isSuccessful());
27 | $this->assertSame('EC-42721413K79637829', $response->getTransactionReference());
28 | $this->assertNull($response->getMessage());
29 | $this->assertNull($response->getRedirectData());
30 | $this->assertSame('https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&useraction=commit&token=EC-42721413K79637829', $response->getRedirectUrl());
31 | $this->assertSame('GET', $response->getRedirectMethod());
32 | }
33 |
34 | public function testExpressPurchaseFailure()
35 | {
36 | $httpResponse = $this->getMockHttpResponse('ExpressPurchaseFailure.txt');
37 | $response = new ExpressAuthorizeResponse($this->getMockRequest(), $httpResponse->getBody());
38 |
39 | $this->assertFalse($response->isPending());
40 | $this->assertFalse($response->isSuccessful());
41 | $this->assertNull($response->getTransactionReference());
42 | $this->assertNull($response->getTransactionReference());
43 | $this->assertSame('This transaction cannot be processed. The amount to be charged is zero.', $response->getMessage());
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/tests/Message/ExpressInContextAuthorizeResponseTest.php:
--------------------------------------------------------------------------------
1 | getMockRequest(), 'example=value&foo=bar');
14 |
15 | $this->assertEquals(array('example' => 'value', 'foo' => 'bar'), $response->getData());
16 | }
17 |
18 | public function testExpressPurchaseSuccess()
19 | {
20 | $httpResponse = $this->getMockHttpResponse('ExpressPurchaseSuccess.txt');
21 | $request = $this->getMockRequest();
22 | $request->shouldReceive('getTestMode')->once()->andReturn(true);
23 | $response = new ExpressInContextAuthorizeResponse($request, $httpResponse->getBody());
24 |
25 | $this->assertFalse($response->isPending());
26 | $this->assertFalse($response->isSuccessful());
27 | $this->assertSame('EC-42721413K79637829', $response->getTransactionReference());
28 | $this->assertNull($response->getMessage());
29 | $this->assertNull($response->getRedirectData());
30 | $this->assertSame('https://www.sandbox.paypal.com/checkoutnow?useraction=commit&token=EC-42721413K79637829', $response->getRedirectUrl());
31 | $this->assertSame('GET', $response->getRedirectMethod());
32 | }
33 |
34 | public function testExpressPurchaseFailure()
35 | {
36 | $httpResponse = $this->getMockHttpResponse('ExpressPurchaseFailure.txt');
37 | $response = new ExpressInContextAuthorizeResponse($this->getMockRequest(), $httpResponse->getBody());
38 |
39 | $this->assertFalse($response->isPending());
40 | $this->assertFalse($response->isSuccessful());
41 | $this->assertNull($response->getTransactionReference());
42 | $this->assertNull($response->getTransactionReference());
43 | $this->assertSame('This transaction cannot be processed. The amount to be charged is zero.', $response->getMessage());
44 | }
45 | }
--------------------------------------------------------------------------------
/src/ProGateway.php:
--------------------------------------------------------------------------------
1 | '',
21 | 'password' => '',
22 | 'signature' => '',
23 | 'testMode' => false,
24 | );
25 | }
26 |
27 | public function getUsername()
28 | {
29 | return $this->getParameter('username');
30 | }
31 |
32 | public function setUsername($value)
33 | {
34 | return $this->setParameter('username', $value);
35 | }
36 |
37 | public function getPassword()
38 | {
39 | return $this->getParameter('password');
40 | }
41 |
42 | public function setPassword($value)
43 | {
44 | return $this->setParameter('password', $value);
45 | }
46 |
47 | public function getSignature()
48 | {
49 | return $this->getParameter('signature');
50 | }
51 |
52 | public function setSignature($value)
53 | {
54 | return $this->setParameter('signature', $value);
55 | }
56 |
57 | public function authorize(array $parameters = array())
58 | {
59 | return $this->createRequest('\Omnipay\PayPal\Message\ProAuthorizeRequest', $parameters);
60 | }
61 |
62 | public function purchase(array $parameters = array())
63 | {
64 | return $this->createRequest('\Omnipay\PayPal\Message\ProPurchaseRequest', $parameters);
65 | }
66 |
67 | public function capture(array $parameters = array())
68 | {
69 | return $this->createRequest('\Omnipay\PayPal\Message\CaptureRequest', $parameters);
70 | }
71 |
72 | public function refund(array $parameters = array())
73 | {
74 | return $this->createRequest('\Omnipay\PayPal\Message\RefundRequest', $parameters);
75 | }
76 |
77 | public function fetchTransaction(array $parameters = array())
78 | {
79 | return $this->createRequest('\Omnipay\PayPal\Message\FetchTransactionRequest', $parameters);
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/tests/Message/RestVerifyWebhookSignatureRequestTest.php:
--------------------------------------------------------------------------------
1 | getHttpClient();
17 | $request = $this->getHttpRequest();
18 | $this->request = new RestVerifyWebhookSignatureRequest($client, $request);
19 | }
20 |
21 | public function testGetData()
22 | {
23 | $data = [
24 | 'transmission_id' => 'foo',
25 | 'auth_algo' => 'bar',
26 | 'cert_url' => 'baz',
27 | 'transmission_sig' => 'qux',
28 | 'transmission_time' => 'foobar',
29 | 'webhook_event' => ['bar' => 'baz'],
30 | 'webhook_id' => 'barbaz',
31 | ];
32 |
33 | $this->request->initialize($data);
34 |
35 | $this->assertEquals($data, $this->request->getData());
36 | }
37 |
38 | public function testGettersAndSetters() {
39 | $authAlgo = 'foo';
40 | $certUrl = 'bar';
41 | $transmissionId = 'baz';
42 | $transmissionTime = 'qux';
43 | $transmissionSig = 'foobar';
44 | $webhookEvent = ['bar' => 'baz'];
45 | $webhookId = 'barfoo';
46 |
47 | $this->request->setAuthAlgo($authAlgo);
48 | $this->request->setCertUrl($certUrl);
49 | $this->request->setTransmissionId($transmissionId);
50 | $this->request->setTransmissionTime($transmissionTime);
51 | $this->request->setTransmissionSig($transmissionSig);
52 | $this->request->setWebhookEvent($webhookEvent);
53 | $this->request->setWebhookId($webhookId);
54 |
55 | $this->assertEquals($authAlgo, $this->request->getAuthAlgo());
56 | $this->assertEquals($certUrl,$this->request->getCertUrl());
57 | $this->assertEquals($transmissionId, $this->request->getTransmissionId());
58 | $this->assertEquals($transmissionTime, $this->request->getTransmissionTime());
59 | $this->assertEquals($transmissionSig, $this->request->getTransmissionSig());
60 | $this->assertEquals($webhookEvent, $this->request->getWebhookEvent());
61 | $this->assertEquals($webhookId, $this->request->getWebhookId());
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/tests/Message/ExpressFetchCheckoutRequestTest.php:
--------------------------------------------------------------------------------
1 | getHttpClient();
18 |
19 | $request = $this->getHttpRequest();
20 | $request->query->set('token', 'TOKEN1234');
21 |
22 | $this->request = new ExpressFetchCheckoutRequest($client, $request);
23 | }
24 |
25 | public function testGetData()
26 | {
27 | $this->request->setUsername('testuser');
28 | $this->request->setPassword('testpass');
29 | $this->request->setSignature('SIG');
30 |
31 | $expected = array();
32 | $expected['METHOD'] = 'GetExpressCheckoutDetails';
33 | $expected['USER'] = 'testuser';
34 | $expected['PWD'] = 'testpass';
35 | $expected['SIGNATURE'] = 'SIG';
36 | $expected['SUBJECT'] = null;
37 | $expected['VERSION'] = ExpressCompletePurchaseRequest::API_VERSION;
38 | $expected['TOKEN'] = 'TOKEN1234';
39 |
40 | $this->assertEquals($expected, $this->request->getData());
41 | }
42 |
43 | public function testGetDataTokenOverride()
44 | {
45 | $this->request->setToken('TOKEN2000');
46 |
47 | $data = $this->request->getData();
48 |
49 | $this->assertSame('TOKEN2000', $data['TOKEN']);
50 | }
51 |
52 | public function testSendSuccess()
53 | {
54 | $this->setMockHttpResponse('ExpressFetchCheckoutSuccess.txt');
55 |
56 | $response = $this->request->send();
57 | $this->assertFalse($response->isPending());
58 | $this->assertTrue($response->isSuccessful());
59 | $this->assertFalse($response->isRedirect());
60 | }
61 |
62 | public function testSendFailure()
63 | {
64 | $this->setMockHttpResponse('ExpressFetchCheckoutFailure.txt');
65 |
66 | $response = $this->request->send();
67 | $this->assertFalse($response->isPending());
68 | $this->assertFalse($response->isSuccessful());
69 | $this->assertFalse($response->isRedirect());
70 | $this->assertSame('The amount exceeds the maximum amount for a single transaction.', $response->getMessage());
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/Message/RestCompletePurchaseRequest.php:
--------------------------------------------------------------------------------
1 |
27 | * $paymentId = $_GET['paymentId'];
28 | * $payerId = $_GET['payerId'];
29 | *
30 | * // Once the transaction has been approved, we need to complete it.
31 | * $transaction = $gateway->completePurchase(array(
32 | * 'payer_id' => $payerId,
33 | * 'transactionReference' => $paymentId,
34 | * ));
35 | * $response = $transaction->send();
36 | * if ($response->isSuccessful()) {
37 | * // The customer has successfully paid.
38 | * } else {
39 | * // There was an error returned by completePurchase(). You should
40 | * // check the error code and message from PayPal, which may be something
41 | * // like "card declined", etc.
42 | * }
43 | *
44 | *
45 | * @see RestPurchaseRequest
46 | * @link https://developer.paypal.com/docs/api/#execute-an-approved-paypal-payment
47 | */
48 | class RestCompletePurchaseRequest extends AbstractRestRequest
49 | {
50 | /**
51 | * Get the raw data array for this message. The format of this varies from gateway to
52 | * gateway, but will usually be either an associative array, or a SimpleXMLElement.
53 | *
54 | * @return mixed
55 | */
56 | public function getData()
57 | {
58 | $this->validate('transactionReference', 'payerId');
59 |
60 | $data = array(
61 | 'payer_id' => $this->getPayerId()
62 | );
63 |
64 | return $data;
65 | }
66 |
67 | public function getEndpoint()
68 | {
69 | return parent::getEndpoint() . '/payments/payment/' . $this->getTransactionReference() . '/execute';
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Omnipay: PayPal
2 |
3 | **PayPal driver for the Omnipay PHP payment processing library**
4 |
5 | [](https://github.com/thephpleague/omnipay-paypal/actions/workflows/run-tests.yml)
6 | [](https://packagist.org/packages/omnipay/paypal)
7 | [](https://packagist.org/packages/omnipay/paypal)
8 |
9 | [Omnipay](https://github.com/thephpleague/omnipay) is a framework agnostic, multi-gateway payment
10 | processing library for PHP. This package implements PayPal support for Omnipay.
11 |
12 | ## Installation
13 |
14 | Omnipay is installed via [Composer](http://getcomposer.org/). To install, simply require `league/omnipay` and `omnipay/paypal` with Composer:
15 |
16 | ```
17 | composer require league/omnipay omnipay/paypal
18 | ```
19 |
20 |
21 | ## Basic Usage
22 |
23 | The following gateways are provided by this package:
24 |
25 | * PayPal_Express (PayPal Express Checkout)
26 | * PayPal_ExpressInContext (PayPal Express In-Context Checkout)
27 | * PayPal_Pro (PayPal Website Payments Pro)
28 | * PayPal_Rest (Paypal Rest API)
29 |
30 | For general usage instructions, please see the main [Omnipay](https://github.com/thephpleague/omnipay)
31 | repository.
32 |
33 | ## Quirks
34 |
35 | The transaction reference obtained from the purchase() response can't be used to refund a purchase. The transaction reference from the completePurchase() response is the one that should be used.
36 |
37 | ## Out Of Scope
38 |
39 | Omnipay does not cover recurring payments or billing agreements, and so those features are not included in this package. Extensions to this gateway are always welcome.
40 |
41 | ## Support
42 |
43 | If you are having general issues with Omnipay, we suggest posting on
44 | [Stack Overflow](http://stackoverflow.com/). Be sure to add the
45 | [omnipay tag](http://stackoverflow.com/questions/tagged/omnipay) so it can be easily found.
46 |
47 | If you want to keep up to date with release anouncements, discuss ideas for the project,
48 | or ask more detailed questions, there is also a [mailing list](https://groups.google.com/forum/#!forum/omnipay) which
49 | you can subscribe to.
50 |
51 | If you believe you have found a bug, please report it using the [GitHub issue tracker](https://github.com/thephpleague/omnipay-paypal/issues),
52 | or better yet, fork the library and submit a pull request.
53 |
--------------------------------------------------------------------------------
/src/Support/InstantUpdateApi/BillingAgreement.php:
--------------------------------------------------------------------------------
1 | 'MerchantInitiatedBillingSingleAgreement',
16 | 'recurring' => 'MerchantInitiatedBilling',
17 | );
18 |
19 | /** @var string */
20 | private $type;
21 |
22 | /** @var string */
23 | private $description;
24 |
25 | /** @var string */
26 | private $paymentType;
27 |
28 | /** @var string */
29 | private $customAnnotation;
30 |
31 | /**
32 | * @param bool $recurring L_BILLINGTYPE0
33 | * @param string $description L_BILLINGAGREEMENTDESCRIPTION0
34 | * @param null|string $paymentType L_PAYMENTTYPE0
35 | * @param null|string $customAnnotation L_BILLINGAGREEMENTCUSTOM0
36 | * @throws \Exception
37 | */
38 | public function __construct($recurring, $description, $paymentType = null, $customAnnotation = null)
39 | {
40 | if (!$recurring && !is_null($paymentType) && !in_array($paymentType, array('Any', 'InstantOnly'))) {
41 | throw new InvalidRequestException("The 'paymentType' parameter can be only 'Any' or 'InstantOnly'");
42 | }
43 |
44 | $this->type = $recurring ? $this->types['recurring'] : $this->types['single'];
45 | $this->description = $description;
46 | $this->customAnnotation = $customAnnotation;
47 | $this->paymentType = $paymentType;
48 | }
49 |
50 | /**
51 | * @return string
52 | */
53 | public function getType()
54 | {
55 | return $this->type;
56 | }
57 |
58 | /**
59 | * @return string
60 | */
61 | public function getDescription()
62 | {
63 | return $this->description;
64 | }
65 |
66 | /**
67 | * @return bool
68 | */
69 | public function hasPaymentType()
70 | {
71 | return !is_null($this->paymentType);
72 | }
73 |
74 | /**
75 | * @return string
76 | */
77 | public function getPaymentType()
78 | {
79 | return $this->paymentType;
80 | }
81 |
82 | /**
83 | * @return bool
84 | */
85 | public function hasCustomAnnotation()
86 | {
87 | return !is_null($this->customAnnotation);
88 | }
89 |
90 | /**
91 | * @return string
92 | */
93 | public function getCustomAnnotation()
94 | {
95 | return $this->customAnnotation;
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/tests/Message/ProPurchaseRequestTest.php:
--------------------------------------------------------------------------------
1 | request = new ProPurchaseRequest($this->getHttpClient(), $this->getHttpRequest());
20 | $this->request->initialize(
21 | array(
22 | 'amount' => '10.00',
23 | 'currency' => 'USD',
24 | 'card' => $this->getValidCard(),
25 | )
26 | );
27 | }
28 |
29 | public function testGetData()
30 | {
31 | $card = new CreditCard($this->getValidCard());
32 | $card->setStartMonth(1);
33 | $card->setStartYear(2000);
34 |
35 | $this->request->setCard($card);
36 | $this->request->setTransactionId('abc123');
37 | $this->request->setDescription('Sheep');
38 | $this->request->setClientIp('127.0.0.1');
39 |
40 | $data = $this->request->getData();
41 |
42 | $this->assertSame('DoDirectPayment', $data['METHOD']);
43 | $this->assertSame('Sale', $data['PAYMENTACTION']);
44 | $this->assertSame('10.00', $data['AMT']);
45 | $this->assertSame('USD', $data['CURRENCYCODE']);
46 | $this->assertSame('abc123', $data['INVNUM']);
47 | $this->assertSame('Sheep', $data['DESC']);
48 | $this->assertSame('127.0.0.1', $data['IPADDRESS']);
49 |
50 | $this->assertSame($card->getNumber(), $data['ACCT']);
51 | $this->assertSame($card->getBrand(), $data['CREDITCARDTYPE']);
52 | $this->assertSame($card->getExpiryDate('mY'), $data['EXPDATE']);
53 | $this->assertSame('012000', $data['STARTDATE']);
54 | $this->assertSame($card->getCvv(), $data['CVV2']);
55 | $this->assertSame($card->getIssueNumber(), $data['ISSUENUMBER']);
56 |
57 | $this->assertSame($card->getFirstName(), $data['FIRSTNAME']);
58 | $this->assertSame($card->getLastName(), $data['LASTNAME']);
59 | $this->assertSame($card->getEmail(), $data['EMAIL']);
60 | $this->assertSame($card->getAddress1(), $data['STREET']);
61 | $this->assertSame($card->getAddress2(), $data['STREET2']);
62 | $this->assertSame($card->getCity(), $data['CITY']);
63 | $this->assertSame($card->getState(), $data['STATE']);
64 | $this->assertSame($card->getPostcode(), $data['ZIP']);
65 | $this->assertSame($card->getCountry(), $data['COUNTRYCODE']);
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/tests/Message/ProAuthorizeRequestTest.php:
--------------------------------------------------------------------------------
1 | request = new ProAuthorizeRequest($this->getHttpClient(), $this->getHttpRequest());
20 | $this->request->initialize(
21 | array(
22 | 'amount' => '10.00',
23 | 'currency' => 'USD',
24 | 'card' => $this->getValidCard(),
25 | )
26 | );
27 | }
28 |
29 | public function testGetData()
30 | {
31 | $card = new CreditCard($this->getValidCard());
32 | $card->setStartMonth(1);
33 | $card->setStartYear(2000);
34 |
35 | $this->request->setCard($card);
36 | $this->request->setTransactionId('abc123');
37 | $this->request->setDescription('Sheep');
38 | $this->request->setClientIp('127.0.0.1');
39 |
40 | $data = $this->request->getData();
41 |
42 | $this->assertSame('DoDirectPayment', $data['METHOD']);
43 | $this->assertSame('Authorization', $data['PAYMENTACTION']);
44 | $this->assertSame('10.00', $data['AMT']);
45 | $this->assertSame('USD', $data['CURRENCYCODE']);
46 | $this->assertSame('abc123', $data['INVNUM']);
47 | $this->assertSame('Sheep', $data['DESC']);
48 | $this->assertSame('127.0.0.1', $data['IPADDRESS']);
49 |
50 | $this->assertSame($card->getNumber(), $data['ACCT']);
51 | $this->assertSame($card->getBrand(), $data['CREDITCARDTYPE']);
52 | $this->assertSame($card->getExpiryDate('mY'), $data['EXPDATE']);
53 | $this->assertSame('012000', $data['STARTDATE']);
54 | $this->assertSame($card->getCvv(), $data['CVV2']);
55 | $this->assertSame($card->getIssueNumber(), $data['ISSUENUMBER']);
56 |
57 | $this->assertSame($card->getFirstName(), $data['FIRSTNAME']);
58 | $this->assertSame($card->getLastName(), $data['LASTNAME']);
59 | $this->assertSame($card->getEmail(), $data['EMAIL']);
60 | $this->assertSame($card->getAddress1(), $data['STREET']);
61 | $this->assertSame($card->getAddress2(), $data['STREET2']);
62 | $this->assertSame($card->getCity(), $data['CITY']);
63 | $this->assertSame($card->getState(), $data['STATE']);
64 | $this->assertSame($card->getPostcode(), $data['ZIP']);
65 | $this->assertSame($card->getCountry(), $data['COUNTRYCODE']);
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/Message/RestRefundRequest.php:
--------------------------------------------------------------------------------
1 |
29 | * $transaction = $gateway->refund(array(
30 | * 'amount' => '10.00',
31 | * 'currency' => 'AUD',
32 | * ));
33 | * $transaction->setTransactionReference($sale_id);
34 | * $response = $transaction->send();
35 | * if ($response->isSuccessful()) {
36 | * echo "Refund transaction was successful!\n";
37 | * $data = $response->getData();
38 | * echo "Gateway refund response data == " . print_r($data, true) . "\n";
39 | * }
40 | *
41 | *
42 | * ### Known Issues
43 | *
44 | * PayPal subscription payments cannot be refunded. PayPal is working on this functionality
45 | * for their future API release. In order to refund a PayPal subscription payment, you will
46 | * need to use the PayPal web interface to refund it manually.
47 | *
48 | * @see RestPurchaseRequest
49 | */
50 | class RestRefundRequest extends AbstractRestRequest
51 | {
52 | public function getData()
53 | {
54 | $this->validate('transactionReference');
55 |
56 | if ($this->getAmount() > 0) {
57 | return array(
58 | 'amount' => array(
59 | 'currency' => $this->getCurrency(),
60 | 'total' => $this->getAmount(),
61 | ),
62 | 'description' => $this->getDescription(),
63 | );
64 | } else {
65 | return new \stdClass();
66 | }
67 | }
68 |
69 | public function getEndpoint()
70 | {
71 | return parent::getEndpoint() . '/payments/sale/' . $this->getTransactionReference() . '/refund';
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/tests/ExpressInContextGatewayTest.php:
--------------------------------------------------------------------------------
1 | gateway = new ExpressInContextGateway($this->getHttpClient(), $this->getHttpRequest());
29 |
30 | $this->options = array(
31 | 'amount' => '10.00',
32 | 'returnUrl' => 'https://www.example.com/return',
33 | 'cancelUrl' => 'https://www.example.com/cancel',
34 | );
35 | $this->voidOptions = array(
36 | 'transactionReference' => 'ASDFASDFASDF',
37 | );
38 | }
39 |
40 | public function testAuthorizeSuccess()
41 | {
42 | $this->setMockHttpResponse('ExpressPurchaseSuccess.txt');
43 |
44 | $response = $this->gateway->authorize($this->options)->send();
45 |
46 | $this->assertInstanceOf('\Omnipay\PayPal\Message\ExpressInContextAuthorizeResponse', $response);
47 | $this->assertFalse($response->isPending());
48 | $this->assertFalse($response->isSuccessful());
49 | $this->assertTrue($response->isRedirect());
50 | $this->assertEquals('https://www.paypal.com/checkoutnow?useraction=commit&token=EC-42721413K79637829', $response->getRedirectUrl());
51 | }
52 |
53 | public function testPurchaseSuccess()
54 | {
55 | $this->setMockHttpResponse('ExpressPurchaseSuccess.txt');
56 |
57 | $response = $this->gateway->purchase($this->options)->send();
58 |
59 | $this->assertInstanceOf('\Omnipay\PayPal\Message\ExpressInContextAuthorizeResponse', $response);
60 | $this->assertFalse($response->isPending());
61 | $this->assertFalse($response->isSuccessful());
62 | $this->assertTrue($response->isRedirect());
63 | $this->assertEquals('https://www.paypal.com/checkoutnow?useraction=commit&token=EC-42721413K79637829', $response->getRedirectUrl());
64 | }
65 |
66 | public function testOrderSuccess()
67 | {
68 | $this->setMockHttpResponse('ExpressOrderSuccess.txt');
69 |
70 | $response = $this->gateway->order($this->options)->send();
71 |
72 | $this->assertInstanceOf('\Omnipay\PayPal\Message\ExpressInContextAuthorizeResponse', $response);
73 | $this->assertFalse($response->isPending());
74 | $this->assertFalse($response->isSuccessful());
75 | $this->assertTrue($response->isRedirect());
76 | $this->assertEquals('https://www.paypal.com/checkoutnow?useraction=commit&token=EC-42721413K79637829', $response->getRedirectUrl());
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/Message/RestAuthorizeResponse.php:
--------------------------------------------------------------------------------
1 | data['error']) && $this->getCode() == 201;
18 | }
19 |
20 | public function isRedirect()
21 | {
22 | return $this->getRedirectUrl() !== null;
23 | }
24 |
25 | public function getRedirectUrl()
26 | {
27 | if (isset($this->data['links']) && is_array($this->data['links'])) {
28 | foreach ($this->data['links'] as $key => $value) {
29 | if ($value['rel'] == 'approval_url') {
30 | return $value['href'];
31 | }
32 | }
33 | }
34 |
35 | return null;
36 | }
37 |
38 | /**
39 | * Get the URL to complete (execute) the purchase or agreement.
40 | *
41 | * The URL is embedded in the links section of the purchase or create
42 | * subscription request response.
43 | *
44 | * @return string
45 | */
46 | public function getCompleteUrl()
47 | {
48 | if (isset($this->data['links']) && is_array($this->data['links'])) {
49 | foreach ($this->data['links'] as $key => $value) {
50 | if ($value['rel'] == 'execute') {
51 | return $value['href'];
52 | }
53 | }
54 | }
55 |
56 | return null;
57 | }
58 |
59 | public function getTransactionReference()
60 | {
61 | // The transaction reference for a paypal purchase request or for a
62 | // paypal create subscription request ends up in the execute URL
63 | // in the links section of the response.
64 | $completeUrl = $this->getCompleteUrl();
65 | if (empty($completeUrl)) {
66 | return parent::getTransactionReference();
67 | }
68 |
69 | $urlParts = explode('/', $completeUrl);
70 |
71 | // The last element of the URL should be "execute"
72 | $execute = end($urlParts);
73 | if (!in_array($execute, array('execute', 'agreement-execute'))) {
74 | return parent::getTransactionReference();
75 | }
76 |
77 | // The penultimate element should be the transaction reference
78 | return prev($urlParts);
79 | }
80 |
81 | /**
82 | * Get the required redirect method (either GET or POST).
83 | *
84 | * @return string
85 | */
86 | public function getRedirectMethod()
87 | {
88 | return 'GET';
89 | }
90 |
91 | /**
92 | * Gets the redirect form data array, if the redirect method is POST.
93 | *
94 | * @return null
95 | */
96 | public function getRedirectData()
97 | {
98 | return null;
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/src/Message/RestSuspendSubscriptionRequest.php:
--------------------------------------------------------------------------------
1 |
23 | * // Create a gateway for the PayPal REST Gateway
24 | * // (routes to GatewayFactory::create)
25 | * $gateway = Omnipay::create('PayPal_Rest');
26 | *
27 | * // Initialise the gateway
28 | * $gateway->initialize(array(
29 | * 'clientId' => 'MyPayPalClientId',
30 | * 'secret' => 'MyPayPalSecret',
31 | * 'testMode' => true, // Or false when you are ready for live transactions
32 | * ));
33 | *
34 | * // Do a suspend subscription transaction on the gateway
35 | * $transaction = $gateway->suspendSubscription(array(
36 | * 'transactionReference' => $subscription_id,
37 | * 'description' => "Suspending the agreement.",
38 | * ));
39 | * $response = $transaction->send();
40 | * if ($response->isSuccessful()) {
41 | * echo "Suspend Subscription transaction was successful!\n";
42 | * }
43 | *
44 | *
45 | * Note that the subscription_id that you get from calling the response's
46 | * getTransactionReference() method at the end of the completeSubscription
47 | * call will be different to the one that you got after calling the response's
48 | * getTransactionReference() method at the end of the createSubscription
49 | * call. The one that you get from completeSubscription is the correct
50 | * one to use going forwards (e.g. for cancelling or updating the subscription).
51 | *
52 | * ### Request Sample
53 | *
54 | * This is from the PayPal web site:
55 | *
56 | *
57 | * curl -v POST https://api.sandbox.paypal.com/v1/payments/billing-agreements/I-0LN988D3JACS/suspend \
58 | * -H 'Content-Type:application/json' \
59 | * -H 'Authorization: Bearer ' \
60 | * -d '{
61 | * "note": "Suspending the agreement."
62 | * }'
63 | *
64 | *
65 | * @link https://developer.paypal.com/docs/api/#suspend-an-agreement
66 | * @see RestCreateSubscriptionRequest
67 | * @see Omnipay\PayPal\RestGateway
68 | */
69 | class RestSuspendSubscriptionRequest extends AbstractRestRequest
70 | {
71 | public function getData()
72 | {
73 | $this->validate('transactionReference', 'description');
74 | $data = array(
75 | 'note' => $this->getDescription(),
76 | );
77 |
78 | return $data;
79 | }
80 |
81 | /**
82 | * Get transaction endpoint.
83 | *
84 | * Subscriptions are executed using the /billing-agreements resource.
85 | *
86 | * @return string
87 | */
88 | protected function getEndpoint()
89 | {
90 | return parent::getEndpoint() . '/payments/billing-agreements/' .
91 | $this->getTransactionReference() . '/suspend';
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/Message/RestCancelSubscriptionRequest.php:
--------------------------------------------------------------------------------
1 |
23 | * // Create a gateway for the PayPal REST Gateway
24 | * // (routes to GatewayFactory::create)
25 | * $gateway = Omnipay::create('PayPal_Rest');
26 | *
27 | * // Initialise the gateway
28 | * $gateway->initialize(array(
29 | * 'clientId' => 'MyPayPalClientId',
30 | * 'secret' => 'MyPayPalSecret',
31 | * 'testMode' => true, // Or false when you are ready for live transactions
32 | * ));
33 | *
34 | * // Do a cancel subscription transaction on the gateway
35 | * $transaction = $gateway->cancelSubscription(array(
36 | * 'transactionReference' => $subscription_id,
37 | * 'description' => "Cancelling the agreement.",
38 | * ));
39 | * $response = $transaction->send();
40 | * if ($response->isSuccessful()) {
41 | * echo "Cancel Subscription transaction was successful!\n";
42 | * }
43 | *
44 | *
45 | * Note that the subscription_id that you get from calling the response's
46 | * getTransactionReference() method at the end of the completeSubscription
47 | * call will be different to the one that you got after calling the response's
48 | * getTransactionReference() method at the end of the createSubscription
49 | * call. The one that you get from completeSubscription is the correct
50 | * one to use going forwards (e.g. for cancelling or updating the subscription).
51 | *
52 | * ### Request Sample
53 | *
54 | * This is from the PayPal web site:
55 | *
56 | *
57 | * curl -v POST https://api.sandbox.paypal.com/v1/payments/billing-agreements/I-0LN988D3JACS/cancel \
58 | * -H 'Content-Type:application/json' \
59 | * -H 'Authorization: Bearer ' \
60 | * -d '{
61 | * "note": "Canceling the agreement."
62 | * }'
63 | *
64 | *
65 | * @link https://developer.paypal.com/docs/api/#cancel-an-agreement
66 | * @see RestCreateSubscriptionRequest
67 | * @see Omnipay\PayPal\RestGateway
68 | */
69 | class RestCancelSubscriptionRequest extends AbstractRestRequest
70 | {
71 | public function getData()
72 | {
73 | $this->validate('transactionReference', 'description');
74 | $data = array(
75 | 'note' => $this->getDescription(),
76 | );
77 |
78 | return $data;
79 | }
80 |
81 | /**
82 | * Get transaction endpoint.
83 | *
84 | * Subscriptions are executed using the /billing-agreements resource.
85 | *
86 | * @return string
87 | */
88 | protected function getEndpoint()
89 | {
90 | return parent::getEndpoint() . '/payments/billing-agreements/' .
91 | $this->getTransactionReference() . '/cancel';
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/Message/RestReactivateSubscriptionRequest.php:
--------------------------------------------------------------------------------
1 |
23 | * // Create a gateway for the PayPal REST Gateway
24 | * // (routes to GatewayFactory::create)
25 | * $gateway = Omnipay::create('PayPal_Rest');
26 | *
27 | * // Initialise the gateway
28 | * $gateway->initialize(array(
29 | * 'clientId' => 'MyPayPalClientId',
30 | * 'secret' => 'MyPayPalSecret',
31 | * 'testMode' => true, // Or false when you are ready for live transactions
32 | * ));
33 | *
34 | * // Do a reactivate subscription transaction on the gateway
35 | * $transaction = $gateway->reactivateSubscription(array(
36 | * 'transactionReference' => $subscription_id,
37 | * 'description' => "Reactivating the agreement.",
38 | * ));
39 | * $response = $transaction->send();
40 | * if ($response->isSuccessful()) {
41 | * echo "Reactivate Subscription transaction was successful!\n";
42 | * }
43 | *
44 | *
45 | * Note that the subscription_id that you get from calling the response's
46 | * getTransactionReference() method at the end of the completeSubscription
47 | * call will be different to the one that you got after calling the response's
48 | * getTransactionReference() method at the end of the createSubscription
49 | * call. The one that you get from completeSubscription is the correct
50 | * one to use going forwards (e.g. for cancelling or updating the subscription).
51 | *
52 | * ### Request Sample
53 | *
54 | * This is from the PayPal web site:
55 | *
56 | *
57 | * curl -v POST https://api.sandbox.paypal.com/v1/payments/billing-agreements/I-0LN988D3JACS/re-activate \
58 | * -H 'Content-Type:application/json' \
59 | * -H 'Authorization: Bearer ' \
60 | * -d '{
61 | * "note": "Reactivating the agreement."
62 | * }'
63 | *
64 | *
65 | * @link https://developer.paypal.com/docs/api/#reactivate-an-agreement
66 | * @see RestCreateSubscriptionRequest
67 | * @see Omnipay\PayPal\RestGateway
68 | */
69 | class RestReactivateSubscriptionRequest extends AbstractRestRequest
70 | {
71 | public function getData()
72 | {
73 | $this->validate('transactionReference', 'description');
74 | $data = array(
75 | 'note' => $this->getDescription(),
76 | );
77 |
78 | return $data;
79 | }
80 |
81 | /**
82 | * Get transaction endpoint.
83 | *
84 | * Subscriptions are executed using the /billing-agreements resource.
85 | *
86 | * @return string
87 | */
88 | protected function getEndpoint()
89 | {
90 | return parent::getEndpoint() . '/payments/billing-agreements/' .
91 | $this->getTransactionReference() . '/re-activate';
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/tests/Message/ExpressTransactionSearchRequestTest.php:
--------------------------------------------------------------------------------
1 | request = new ExpressTransactionSearchRequest($this->getHttpClient(), $this->getHttpRequest());
20 | }
21 |
22 | public function testGetData()
23 | {
24 | $startDate = '2015-01-01';
25 | $endDate = '2016-01-01';
26 |
27 | $this->request->initialize(array(
28 | 'amount' => '10.00',
29 | 'currency' => 'USD',
30 | 'startDate' => $startDate,
31 | 'endDate' => $endDate,
32 | 'salutation' => 'Mr.',
33 | 'firstName' => 'Jhon',
34 | 'middleName' => 'Carter',
35 | 'lastName' => 'Macgiver',
36 | 'suffix' => 'Jh',
37 | 'email' => 'test@email.com',
38 | 'receiver' => 'Patt Doret',
39 | 'receiptId' => '1111',
40 | 'transactionId' => 'XKCD',
41 | 'invoiceNumber' => '123456789',
42 | 'card' => array('number' => '376449047333005'),
43 | 'auctionItemNumber' => '321564',
44 | 'transactionClass' => 'Received',
45 | 'status' => 'Success',
46 | 'profileId' => '00000000000'
47 | ));
48 |
49 | $data = $this->request->getData();
50 |
51 | $startDate = new \DateTime($startDate);
52 | $endDate = new \DateTime($endDate);
53 |
54 | $this->assertSame('10.00', $data['AMT']);
55 | $this->assertSame('USD', $data['CURRENCYCODE']);
56 | $this->assertSame($startDate->format(\DateTime::ISO8601), $data['STARTDATE']);
57 | $this->assertSame($endDate->format(\DateTime::ISO8601), $data['ENDDATE']);
58 | $this->assertSame('Mr.', $data['SALUTATION']);
59 | $this->assertSame('Jhon', $data['FIRSTNAME']);
60 | $this->assertSame('Carter', $data['MIDDLENAME']);
61 | $this->assertSame('Macgiver', $data['LASTNAME']);
62 | $this->assertSame('Jh', $data['SUFFIX']);
63 | $this->assertSame('test@email.com', $data['EMAIL']);
64 | $this->assertSame('XKCD', $data['TRANSACTIONID']);
65 | $this->assertSame('123456789', $data['INVNUM']);
66 | $this->assertSame('376449047333005', $data['ACCT']);
67 | $this->assertSame('321564', $data['AUCTIONITEMNUMBER']);
68 | $this->assertSame('Received', $data['TRANSACTIONCLASS']);
69 | $this->assertSame('Success', $data['STATUS']);
70 | $this->assertSame('00000000000', $data['PROFILEID']);
71 | }
72 |
73 | public function testWithoutStartDate()
74 | {
75 | $this->request->initialize(array());
76 |
77 | $this->expectException(InvalidRequestException::class);
78 | $this->expectExceptionMessage('The startDate parameter is required');
79 |
80 | $this->request->getData();
81 | }
82 |
83 | public function testAmountWithoutCurrency()
84 | {
85 | $this->request->setStartDate('2015-01-01');
86 | $this->request->setAmount(150.00);
87 |
88 | $this->expectException(InvalidRequestException::class);
89 | $this->expectExceptionMessage('The currency parameter is required');
90 |
91 | $this->request->getData();
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/Message/RestUpdatePlanRequest.php:
--------------------------------------------------------------------------------
1 |
25 | * // Create a gateway for the PayPal REST Gateway
26 | * // (routes to GatewayFactory::create)
27 | * $gateway = Omnipay::create('PayPal_Rest');
28 | *
29 | * // Initialise the gateway
30 | * $gateway->initialize(array(
31 | * 'clientId' => 'MyPayPalClientId',
32 | * 'secret' => 'MyPayPalSecret',
33 | * 'testMode' => true, // Or false when you are ready for live transactions
34 | * ));
35 | *
36 | * // Update the billing plan
37 | * $transaction = $gateway->updatePlan(array(
38 | * 'transactionReference' => $plan_id,
39 | * 'state' => $gateway::BILLING_PLAN_STATE_ACTIVE,
40 | * ));
41 | * $response = $transaction->send();
42 | * if ($response->isSuccessful()) {
43 | * echo "Update Plan transaction was successful!\n";
44 | * }
45 | *
46 | *
47 | * ### Request Sample
48 | *
49 | * This is from the PayPal web site:
50 | *
51 | *
52 | * curl -v -k -X PATCH 'https://api.sandbox.paypal.com/v1/payments/billing-plans/P-94458432VR012762KRWBZEUA' \
53 | * -H "Content-Type: application/json" \
54 | * -H "Authorization: Bearer " \
55 | * -d '[
56 | * {
57 | * "path": "/",
58 | * "value": {
59 | * "state": "ACTIVE"
60 | * },
61 | * "op": "replace"
62 | * }
63 | * ]'
64 | *
65 | *
66 | * ### Response
67 | *
68 | * Returns the HTTP status of 200 if the call is successful.
69 | *
70 | * @link https://developer.paypal.com/docs/api/#update-a-plan
71 | * @see RestCreateSubscriptionRequest
72 | * @see Omnipay\PayPal\RestGateway
73 | */
74 | class RestUpdatePlanRequest extends AbstractRestRequest
75 | {
76 | /**
77 | * Get the plan state
78 | *
79 | * @return string
80 | */
81 | public function getState()
82 | {
83 | return $this->getParameter('state');
84 | }
85 |
86 | /**
87 | * Set the plan state
88 | *
89 | * @param string $value
90 | * @return RestUpdatePlanRequest provides a fluent interface.
91 | */
92 | public function setState($value)
93 | {
94 | return $this->setParameter('state', $value);
95 | }
96 |
97 | public function getData()
98 | {
99 | $this->validate('transactionReference', 'state');
100 | $data = array(array(
101 | 'path' => '/',
102 | 'value' => array(
103 | 'state' => $this->getState(),
104 | ),
105 | 'op' => 'replace'
106 | ));
107 |
108 | return $data;
109 | }
110 |
111 | /**
112 | * Get transaction endpoint.
113 | *
114 | * Billing plans are managed using the /billing-plans resource.
115 | *
116 | * @return string
117 | */
118 | protected function getEndpoint()
119 | {
120 | return parent::getEndpoint() . '/payments/billing-plans/' . $this->getTransactionReference();
121 | }
122 |
123 | protected function getHttpMethod()
124 | {
125 | return 'PATCH';
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/tests/Message/RestResponseTest.php:
--------------------------------------------------------------------------------
1 | getMockHttpResponse('RestPurchaseSuccess.txt');
12 | $data = json_decode($httpResponse->getBody()->getContents(), true);
13 | $response = new RestResponse($this->getMockRequest(), $data, $httpResponse->getStatusCode());
14 |
15 | $this->assertTrue($response->isSuccessful());
16 | $this->assertSame('44E89981F8714392Y', $response->getTransactionReference());
17 | $this->assertNull($response->getMessage());
18 | }
19 |
20 | public function testPurchaseFailure()
21 | {
22 | $httpResponse = $this->getMockHttpResponse('RestPurchaseFailure.txt');
23 | $data = json_decode($httpResponse->getBody()->getContents(), true);
24 | $response = new RestResponse($this->getMockRequest(), $data, $httpResponse->getStatusCode());
25 |
26 | $this->assertFalse($response->isSuccessful());
27 | $this->assertNull($response->getTransactionReference());
28 | $this->assertSame('Invalid request - see details', $response->getMessage());
29 | }
30 |
31 | public function testCompletePurchaseSuccess()
32 | {
33 | $httpResponse = $this->getMockHttpResponse('RestCompletePurchaseSuccess.txt');
34 | $data = json_decode($httpResponse->getBody()->getContents(), true);
35 |
36 | $response = new RestResponse($this->getMockRequest(), $data, $httpResponse->getStatusCode());
37 |
38 | $this->assertTrue($response->isSuccessful());
39 | $this->assertSame('9EA05739TH369572R', $response->getTransactionReference());
40 | $this->assertNull($response->getMessage());
41 | }
42 |
43 | public function testCompletePurchaseFailure()
44 | {
45 | $httpResponse = $this->getMockHttpResponse('RestCompletePurchaseFailure.txt');
46 | $data = json_decode($httpResponse->getBody()->getContents(), true);
47 |
48 | $response = new RestResponse($this->getMockRequest(), $data, $httpResponse->getStatusCode());
49 |
50 | $this->assertFalse($response->isSuccessful());
51 | $this->assertNull($response->getTransactionReference());
52 | $this->assertSame('This request is invalid due to the current state of the payment', $response->getMessage());
53 | }
54 |
55 | public function testTokenFailure()
56 | {
57 | $httpResponse = $this->getMockHttpResponse('RestTokenFailure.txt');
58 | $data = json_decode($httpResponse->getBody()->getContents(), true);
59 |
60 | $response = new RestResponse($this->getMockRequest(), $data, $httpResponse->getStatusCode());
61 |
62 | $this->assertFalse($response->isSuccessful());
63 | $this->assertSame('Client secret does not match for this client', $response->getMessage());
64 | }
65 |
66 | public function testAuthorizeSuccess()
67 | {
68 | $httpResponse = $this->getMockHttpResponse('RestAuthorizationSuccess.txt');
69 | $data = json_decode($httpResponse->getBody()->getContents(), true);
70 |
71 | $response = new RestResponse($this->getMockRequest(), $data, $httpResponse->getStatusCode());
72 |
73 | $this->assertTrue($response->isSuccessful());
74 | $this->assertSame('58N7596879166930B', $response->getTransactionReference());
75 | $this->assertNull($response->getMessage());
76 | }
77 |
78 | public function testCreateCardSuccess()
79 | {
80 | $httpResponse = $this->getMockHttpResponse('RestCreateCardSuccess.txt');
81 | $data = json_decode($httpResponse->getBody()->getContents(), true);
82 |
83 | $response = new RestResponse($this->getMockRequest(), $data, $httpResponse->getStatusCode());
84 |
85 | $this->assertTrue($response->isSuccessful());
86 | $this->assertSame('CARD-70E78145XN686604FKO3L6OQ', $response->getCardReference());
87 | $this->assertNull($response->getMessage());
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/tests/Message/RestPurchaseRequestTest.php:
--------------------------------------------------------------------------------
1 | getValidCard());
16 | $card->setStartMonth(1);
17 | $card->setStartYear(2000);
18 |
19 | $this->request = new RestPurchaseRequest($this->getHttpClient(), $this->getHttpRequest());
20 | $this->request->initialize(array(
21 | 'amount' => '10.00',
22 | 'currency' => 'USD',
23 | 'card' => $card
24 | ));
25 |
26 | $this->request->setTransactionId('abc123');
27 | $this->request->setDescription('Sheep');
28 | $this->request->setClientIp('127.0.0.1');
29 |
30 | $data = $this->request->getData();
31 |
32 | $this->assertSame('sale', $data['intent']);
33 | $this->assertSame('credit_card', $data['payer']['payment_method']);
34 | $this->assertSame('10.00', $data['transactions'][0]['amount']['total']);
35 | $this->assertSame('USD', $data['transactions'][0]['amount']['currency']);
36 | $this->assertSame('abc123 : Sheep', $data['transactions'][0]['description']);
37 |
38 | $this->assertSame($card->getNumber(), $data['payer']['funding_instruments'][0]['credit_card']['number']);
39 | $this->assertSame($card->getBrand(), $data['payer']['funding_instruments'][0]['credit_card']['type']);
40 | $this->assertSame($card->getExpiryMonth(), $data['payer']['funding_instruments'][0]['credit_card']['expire_month']);
41 | $this->assertSame($card->getExpiryYear(), $data['payer']['funding_instruments'][0]['credit_card']['expire_year']);
42 | $this->assertSame($card->getCvv(), $data['payer']['funding_instruments'][0]['credit_card']['cvv2']);
43 |
44 | $this->assertSame($card->getFirstName(), $data['payer']['funding_instruments'][0]['credit_card']['first_name']);
45 | $this->assertSame($card->getLastName(), $data['payer']['funding_instruments'][0]['credit_card']['last_name']);
46 | $this->assertSame($card->getAddress1(), $data['payer']['funding_instruments'][0]['credit_card']['billing_address']['line1']);
47 | $this->assertSame($card->getAddress2(), $data['payer']['funding_instruments'][0]['credit_card']['billing_address']['line2']);
48 | $this->assertSame($card->getCity(), $data['payer']['funding_instruments'][0]['credit_card']['billing_address']['city']);
49 | $this->assertSame($card->getState(), $data['payer']['funding_instruments'][0]['credit_card']['billing_address']['state']);
50 | $this->assertSame($card->getPostcode(), $data['payer']['funding_instruments'][0]['credit_card']['billing_address']['postal_code']);
51 | $this->assertSame($card->getCountry(), $data['payer']['funding_instruments'][0]['credit_card']['billing_address']['country_code']);
52 | }
53 |
54 | public function testGetDataWithCardRef()
55 | {
56 | $this->request = new RestPurchaseRequest($this->getHttpClient(), $this->getHttpRequest());
57 | $this->request->initialize(array(
58 | 'amount' => '10.00',
59 | 'currency' => 'USD',
60 | 'cardReference' => 'CARD-123',
61 | ));
62 |
63 | $this->request->setTransactionId('abc123');
64 | $this->request->setDescription('Sheep');
65 | $this->request->setClientIp('127.0.0.1');
66 |
67 | $data = $this->request->getData();
68 |
69 | $this->assertSame('sale', $data['intent']);
70 | $this->assertSame('credit_card', $data['payer']['payment_method']);
71 | $this->assertSame('10.00', $data['transactions'][0]['amount']['total']);
72 | $this->assertSame('USD', $data['transactions'][0]['amount']['currency']);
73 | $this->assertSame('abc123 : Sheep', $data['transactions'][0]['description']);
74 | $this->assertSame('CARD-123', $data['payer']['funding_instruments'][0]['credit_card_token']['credit_card_id']);
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/tests/Message/ExpressCompletePurchaseRequestTest.php:
--------------------------------------------------------------------------------
1 | getHttpClient();
18 |
19 | $request = $this->getHttpRequest();
20 | $request->query->set('PayerID', 'Payer-1234');
21 | $request->query->set('token', 'TOKEN1234');
22 |
23 | $this->request = new ExpressCompletePurchaseRequest($client, $request);
24 | }
25 |
26 | public function testGetData()
27 | {
28 | $this->request->setAmount('1.23');
29 | $this->request->setCurrency('USD');
30 | $this->request->setTransactionId('ABC-123');
31 | $this->request->setUsername('testuser');
32 | $this->request->setPassword('testpass');
33 | $this->request->setSignature('SIG');
34 | $this->request->setSubject('SUB');
35 | $this->request->setDescription('DESC');
36 | $this->request->setNotifyUrl('https://www.example.com/notify');
37 | $this->request->setMaxAmount('0.00');
38 | $this->request->setTaxAmount('0.00');
39 | $this->request->setShippingAmount('0.00');
40 | $this->request->setHandlingAmount('0.00');
41 | $this->request->setShippingDiscount('0.00');
42 | $this->request->setInsuranceAmount('0.00');
43 |
44 | $expected = array();
45 | $expected['METHOD'] = 'DoExpressCheckoutPayment';
46 | $expected['PAYMENTREQUEST_0_PAYMENTACTION'] = 'Sale';
47 | $expected['PAYMENTREQUEST_0_AMT'] = '1.23';
48 | $expected['PAYMENTREQUEST_0_CURRENCYCODE'] = 'USD';
49 | $expected['PAYMENTREQUEST_0_INVNUM'] = 'ABC-123';
50 | $expected['PAYMENTREQUEST_0_DESC'] = 'DESC';
51 | $expected['PAYMENTREQUEST_0_NOTIFYURL'] = 'https://www.example.com/notify';
52 | $expected['USER'] = 'testuser';
53 | $expected['PWD'] = 'testpass';
54 | $expected['SIGNATURE'] = 'SIG';
55 | $expected['SUBJECT'] = 'SUB';
56 | $expected['VERSION'] = ExpressCompletePurchaseRequest::API_VERSION;
57 | $expected['TOKEN'] = 'TOKEN1234';
58 | $expected['PAYERID'] = 'Payer-1234';
59 | $expected['MAXAMT'] = '0.00';
60 | $expected['PAYMENTREQUEST_0_TAXAMT'] = '0.00';
61 | $expected['PAYMENTREQUEST_0_SHIPPINGAMT'] = '0.00';
62 | $expected['PAYMENTREQUEST_0_HANDLINGAMT'] = '0.00';
63 | $expected['PAYMENTREQUEST_0_SHIPDISCAMT'] = '0.00';
64 | $expected['PAYMENTREQUEST_0_INSURANCEAMT'] = '0.00';
65 |
66 | $this->assertEquals($expected, $this->request->getData());
67 | }
68 |
69 | public function testGetDataWithItems()
70 | {
71 | $this->request->setAmount('50.00');
72 | $this->request->setCurrency('USD');
73 | $this->request->setTransactionId('ABC-123');
74 | $this->request->setUsername('testuser');
75 | $this->request->setPassword('testpass');
76 | $this->request->setSignature('SIG');
77 | $this->request->setSubject('SUB');
78 | $this->request->setDescription('DESC');
79 |
80 | $this->request->setItems(array(
81 | array('name' => 'Floppy Disk', 'description' => 'MS-DOS', 'quantity' => 2, 'price' => 10),
82 | array('name' => 'CD-ROM', 'description' => 'Windows 95', 'quantity' => 1, 'price' => 40),
83 | ));
84 |
85 | $data = $this->request->getData();
86 | $this->assertSame('Floppy Disk', $data['L_PAYMENTREQUEST_0_NAME0']);
87 | $this->assertSame('MS-DOS', $data['L_PAYMENTREQUEST_0_DESC0']);
88 | $this->assertSame(2, $data['L_PAYMENTREQUEST_0_QTY0']);
89 | $this->assertSame('10.00', $data['L_PAYMENTREQUEST_0_AMT0']);
90 |
91 | $this->assertSame('CD-ROM', $data['L_PAYMENTREQUEST_0_NAME1']);
92 | $this->assertSame('Windows 95', $data['L_PAYMENTREQUEST_0_DESC1']);
93 | $this->assertSame(1, $data['L_PAYMENTREQUEST_0_QTY1']);
94 | $this->assertSame('40.00', $data['L_PAYMENTREQUEST_0_AMT1']);
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/tests/Message/ExpressCompleteAuthorizeRequestTest.php:
--------------------------------------------------------------------------------
1 | getHttpClient();
18 |
19 | $request = $this->getHttpRequest();
20 | $request->query->set('PayerID', 'Payer-1234');
21 | $request->query->set('token', 'TOKEN1234');
22 |
23 | $this->request = new ExpressCompleteAuthorizeRequest($client, $request);
24 | }
25 |
26 | public function testGetData()
27 | {
28 | $this->request->setAmount('1.23');
29 | $this->request->setCurrency('USD');
30 | $this->request->setTransactionId('ABC-123');
31 | $this->request->setUsername('testuser');
32 | $this->request->setPassword('testpass');
33 | $this->request->setSignature('SIG');
34 | $this->request->setSubject('SUB');
35 | $this->request->setDescription('DESC');
36 | $this->request->setNotifyUrl('https://www.example.com/notify');
37 | $this->request->setMaxAmount('0.00');
38 | $this->request->setTaxAmount('0.00');
39 | $this->request->setShippingAmount('0.00');
40 | $this->request->setHandlingAmount('0.00');
41 | $this->request->setShippingDiscount('0.00');
42 | $this->request->setInsuranceAmount('0.00');
43 |
44 | $expected = array();
45 | $expected['METHOD'] = 'DoExpressCheckoutPayment';
46 | $expected['PAYMENTREQUEST_0_PAYMENTACTION'] = 'Authorization';
47 | $expected['PAYMENTREQUEST_0_AMT'] = '1.23';
48 | $expected['PAYMENTREQUEST_0_CURRENCYCODE'] = 'USD';
49 | $expected['PAYMENTREQUEST_0_INVNUM'] = 'ABC-123';
50 | $expected['PAYMENTREQUEST_0_DESC'] = 'DESC';
51 | $expected['PAYMENTREQUEST_0_NOTIFYURL'] = 'https://www.example.com/notify';
52 | $expected['USER'] = 'testuser';
53 | $expected['PWD'] = 'testpass';
54 | $expected['SIGNATURE'] = 'SIG';
55 | $expected['SUBJECT'] = 'SUB';
56 | $expected['VERSION'] = ExpressCompleteAuthorizeRequest::API_VERSION;
57 | $expected['TOKEN'] = 'TOKEN1234';
58 | $expected['PAYERID'] = 'Payer-1234';
59 | $expected['MAXAMT'] = '0.00';
60 | $expected['PAYMENTREQUEST_0_TAXAMT'] = '0.00';
61 | $expected['PAYMENTREQUEST_0_SHIPPINGAMT'] = '0.00';
62 | $expected['PAYMENTREQUEST_0_HANDLINGAMT'] = '0.00';
63 | $expected['PAYMENTREQUEST_0_SHIPDISCAMT'] = '0.00';
64 | $expected['PAYMENTREQUEST_0_INSURANCEAMT'] = '0.00';
65 |
66 | $this->assertEquals($expected, $this->request->getData());
67 | }
68 |
69 | public function testGetDataWithItems()
70 | {
71 | $this->request->setAmount('50.00');
72 | $this->request->setCurrency('USD');
73 | $this->request->setTransactionId('ABC-123');
74 | $this->request->setUsername('testuser');
75 | $this->request->setPassword('testpass');
76 | $this->request->setSignature('SIG');
77 | $this->request->setSubject('SUB');
78 | $this->request->setDescription('DESC');
79 |
80 | $this->request->setItems(array(
81 | array('name' => 'Floppy Disk', 'description' => 'MS-DOS', 'quantity' => 2, 'price' => 10),
82 | array('name' => 'CD-ROM', 'description' => 'Windows 95', 'quantity' => 1, 'price' => 40),
83 | ));
84 |
85 | $data = $this->request->getData();
86 | $this->assertSame('Floppy Disk', $data['L_PAYMENTREQUEST_0_NAME0']);
87 | $this->assertSame('MS-DOS', $data['L_PAYMENTREQUEST_0_DESC0']);
88 | $this->assertSame(2, $data['L_PAYMENTREQUEST_0_QTY0']);
89 | $this->assertSame('10.00', $data['L_PAYMENTREQUEST_0_AMT0']);
90 |
91 | $this->assertSame('CD-ROM', $data['L_PAYMENTREQUEST_0_NAME1']);
92 | $this->assertSame('Windows 95', $data['L_PAYMENTREQUEST_0_DESC1']);
93 | $this->assertSame(1, $data['L_PAYMENTREQUEST_0_QTY1']);
94 | $this->assertSame('40.00', $data['L_PAYMENTREQUEST_0_AMT1']);
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/Message/RestCreateCardRequest.php:
--------------------------------------------------------------------------------
1 |
27 | * // Create a gateway for the PayPal RestGateway
28 | * // (routes to GatewayFactory::create)
29 | * $gateway = Omnipay::create('PayPal_Rest');
30 | *
31 | * // Initialise the gateway
32 | * $gateway->initialize(array(
33 | * 'clientId' => 'MyPayPalClientId',
34 | * 'secret' => 'MyPayPalSecret',
35 | * 'testMode' => true, // Or false when you are ready for live transactions
36 | * ));
37 | *
38 | * // Create a credit card object
39 | * // DO NOT USE THESE CARD VALUES -- substitute your own
40 | * // see the documentation in the class header.
41 | * $card = new CreditCard(array(
42 | * 'firstName' => 'Example',
43 | * 'lastName' => 'User',
44 | * 'number' => '4111111111111111',
45 | * 'expiryMonth' => '01',
46 | * 'expiryYear' => '2020',
47 | * 'cvv' => '123',
48 | * 'billingAddress1' => '1 Scrubby Creek Road',
49 | * 'billingCountry' => 'AU',
50 | * 'billingCity' => 'Scrubby Creek',
51 | * 'billingPostcode' => '4999',
52 | * 'billingState' => 'QLD',
53 | * ));
54 | *
55 | * // Do a create card transaction on the gateway
56 | * $transaction = $gateway->createCard(array(
57 | * 'card' => $card,
58 | * ));
59 | * $response = $transaction->send();
60 | * if ($response->isSuccessful()) {
61 | * echo "Create card transaction was successful!\n";
62 | * // Find the card ID
63 | * $card_id = $response->getTransactionReference();
64 | * }
65 | *
66 | *
67 | * @link https://developer.paypal.com/docs/api/#vault
68 | * @link https://developer.paypal.com/docs/api/#store-a-credit-card
69 | * @link http://bit.ly/1wUQ33R
70 | */
71 | class RestCreateCardRequest extends AbstractRestRequest
72 | {
73 | public function getData()
74 | {
75 | $this->validate('card');
76 | $this->getCard()->validate();
77 |
78 | $data = array(
79 | 'number' => $this->getCard()->getNumber(),
80 | 'type' => $this->getCard()->getBrand(),
81 | 'expire_month' => $this->getCard()->getExpiryMonth(),
82 | 'expire_year' => $this->getCard()->getExpiryYear(),
83 | 'cvv2' => $this->getCard()->getCvv(),
84 | 'first_name' => $this->getCard()->getFirstName(),
85 | 'last_name' => $this->getCard()->getLastName(),
86 | 'billing_address' => array(
87 | 'line1' => $this->getCard()->getAddress1(),
88 | //'line2' => $this->getCard()->getAddress2(),
89 | 'city' => $this->getCard()->getCity(),
90 | 'state' => $this->getCard()->getState(),
91 | 'postal_code' => $this->getCard()->getPostcode(),
92 | 'country_code' => strtoupper($this->getCard()->getCountry()),
93 | )
94 | );
95 |
96 | // There's currently a quirk with the REST API that requires line2 to be
97 | // non-empty if it's present. Jul 14, 2014
98 | $line2 = $this->getCard()->getAddress2();
99 | if (!empty($line2)) {
100 | $data['billing_address']['line2'] = $line2;
101 | }
102 |
103 | return $data;
104 | }
105 |
106 | protected function getEndpoint()
107 | {
108 | return parent::getEndpoint() . '/vault/credit-cards';
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/src/Message/RestCompleteSubscriptionRequest.php:
--------------------------------------------------------------------------------
1 | getRedirectUrl(). Once
31 | * the customer has approved the agreement and be returned to the returnUrl
32 | * in the call. The returnUrl can contain the following code to complete
33 | * the agreement:
34 | *
35 | *
36 | * // Create a gateway for the PayPal REST Gateway
37 | * // (routes to GatewayFactory::create)
38 | * $gateway = Omnipay::create('PayPal_Rest');
39 | *
40 | * // Initialise the gateway
41 | * $gateway->initialize(array(
42 | * 'clientId' => 'MyPayPalClientId',
43 | * 'secret' => 'MyPayPalSecret',
44 | * 'testMode' => true, // Or false when you are ready for live transactions
45 | * ));
46 | *
47 | * // Do a complete subscription transaction on the gateway
48 | * $transaction = $gateway->completeSubscription(array(
49 | * 'transactionReference' => $subscription_id,
50 | * ));
51 | * $response = $transaction->send();
52 | * if ($response->isSuccessful()) {
53 | * echo "Complete Subscription transaction was successful!\n";
54 | * $subscription_id = $response->getTransactionReference();
55 | * echo "Subscription reference = " . $subscription_id;
56 | * }
57 | *
58 | *
59 | * Note that the subscription_id that you get from calling the response's
60 | * getTransactionReference() method at the end of the completeSubscription
61 | * call will be different to the one that you got after calling the response's
62 | * getTransactionReference() method at the end of the createSubscription
63 | * call. The one that you get from completeSubscription is the correct
64 | * one to use going forwards (e.g. for cancelling or updating the subscription).
65 | *
66 | * ### Request Sample
67 | *
68 | * This is from the PayPal web site:
69 | *
70 | *
71 | * curl -v POST https://api.sandbox.paypal.com/v1/payments/billing-agreements/EC-0JP008296V451950C/agreement-execute \
72 | * -H 'Content-Type:application/json' \
73 | * -H 'Authorization: Bearer ' \
74 | * -d '{}'
75 | *
76 | *
77 | * ### Response Sample
78 | *
79 | * This is from the PayPal web site:
80 | *
81 | *
82 | * {
83 | * "id": "I-0LN988D3JACS",
84 | * "links": [
85 | * {
86 | * "href": "https://api.sandbox.paypal.com/v1/payments/billing-agreements/I-0LN988D3JACS",
87 | * "rel": "self",
88 | * "method": "GET"
89 | * }
90 | * ]
91 | * }
92 | *
93 | *
94 | * @link https://developer.paypal.com/docs/api/#execute-an-agreement
95 | * @see RestCreateSubscriptionRequest
96 | * @see Omnipay\PayPal\RestGateway
97 | */
98 | class RestCompleteSubscriptionRequest extends AbstractRestRequest
99 | {
100 | public function getData()
101 | {
102 | $this->validate('transactionReference');
103 | $data = array();
104 |
105 | return $data;
106 | }
107 |
108 | /**
109 | * Get transaction endpoint.
110 | *
111 | * Subscriptions are executed using the /billing-agreements resource.
112 | *
113 | * @return string
114 | */
115 | protected function getEndpoint()
116 | {
117 | return parent::getEndpoint() . '/payments/billing-agreements/' .
118 | $this->getTransactionReference() . '/agreement-execute';
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/src/Message/RestVerifyWebhookSignatureRequest.php:
--------------------------------------------------------------------------------
1 | getParameter('auth_algo');
16 | }
17 |
18 | /**
19 | * @return string
20 | */
21 | public function getCertUrl()
22 | {
23 | return $this->getParameter('cert_url');
24 | }
25 |
26 | /**
27 | * @inheritDoc
28 | */
29 | public function getData()
30 | {
31 | return [
32 | 'transmission_id' => $this->getTransmissionId(),
33 | 'auth_algo' => $this->getAuthAlgo(),
34 | 'cert_url' => $this->getCertUrl(),
35 | 'transmission_sig' => $this->getTransmissionSig(),
36 | 'transmission_time' => $this->getTransmissionTime(),
37 | 'webhook_event' => $this->getWebhookEvent(),
38 | 'webhook_id' => $this->getWebhookId(),
39 | ];
40 | }
41 |
42 | /**
43 | * @inheritDoc
44 | */
45 | public function getEndpoint()
46 | {
47 | return parent::getEndpoint().'/notifications/verify-webhook-signature';
48 | }
49 |
50 | /**
51 | * @return string
52 | */
53 | public function getTransmissionId()
54 | {
55 | return $this->getParameter('transmission_id');
56 | }
57 |
58 | /**
59 | * @return string
60 | */
61 | public function getTransmissionSig()
62 | {
63 | return $this->getParameter('transmission_sig');
64 | }
65 |
66 | /**
67 | * @return string
68 | */
69 | public function getTransmissionTime()
70 | {
71 | return $this->getParameter('transmission_time');
72 | }
73 |
74 | /**
75 | * @return string
76 | */
77 | public function getWebhookEvent()
78 | {
79 | return $this->getParameter('webhook_event');
80 | }
81 |
82 | /**
83 | * @return string
84 | */
85 | public function getWebhookId()
86 | {
87 | return $this->getParameter('webhook_id');
88 | }
89 |
90 | /**
91 | * @param string $authAlgo
92 | *
93 | * @return $this
94 | */
95 | public function setAuthAlgo($authAlgo)
96 | {
97 | return $this->setParameter('auth_algo', $authAlgo);
98 | }
99 |
100 | /**
101 | * @param string $certUrl
102 | *
103 | * @return $this
104 | */
105 | public function setCertUrl($certUrl)
106 | {
107 | return $this->setParameter('cert_url', $certUrl);
108 | }
109 |
110 | /**
111 | * @param string $transmissionId
112 | *
113 | * @return $this
114 | */
115 | public function setTransmissionId($transmissionId)
116 | {
117 | return $this->setParameter('transmission_id', $transmissionId);
118 | }
119 |
120 | /**
121 | * @param string $transmissionSig
122 | *
123 | * @return $this
124 | */
125 | public function setTransmissionSig($transmissionSig)
126 | {
127 | return $this->setParameter('transmission_sig', $transmissionSig);
128 | }
129 |
130 | /**
131 | * @param string $transmissionTime
132 | *
133 | * @return $this
134 | */
135 | public function setTransmissionTime($transmissionTime)
136 | {
137 | return $this->setParameter('transmission_time', $transmissionTime);
138 | }
139 |
140 | /**
141 | * @param array $webhookEvent
142 | *
143 | * @return $this
144 | */
145 | public function setWebhookEvent(array $webhookEvent)
146 | {
147 | return $this->setParameter('webhook_event', $webhookEvent);
148 | }
149 |
150 | /**
151 | * @param string $webhookId
152 | *
153 | * @return $this
154 | */
155 | public function setWebhookId($webhookId)
156 | {
157 | return $this->setParameter('webhook_id', $webhookId);
158 | }
159 |
160 | /**
161 | * @param $data
162 | * @param $statusCode
163 | *
164 | * @return RestVerifyWebhookSignatureResponse
165 | */
166 | protected function createResponse($data, $statusCode)
167 | {
168 | return $this->response = new RestVerifyWebhookSignatureResponse($this, $data, $statusCode);
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/makedoc.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Smart little documentation generator.
5 | # GPL/LGPL
6 | # (c) Del 2015 http://www.babel.com.au/
7 | #
8 |
9 | APPNAME='Omnipay PayPal Gateway Module'
10 | CMDFILE=apigen.cmd.$$
11 | DESTDIR=./documents
12 |
13 | #
14 | # Find apigen, either in the path or as a local phar file
15 | #
16 | if [ -f apigen.phar ]; then
17 | APIGEN="php apigen.phar"
18 |
19 | else
20 | APIGEN=`which apigen`
21 | if [ ! -f "$APIGEN" ]; then
22 |
23 | # Search for phpdoc if apigen is not found.
24 | if [ -f phpDocumentor.phar ]; then
25 | PHPDOC="php phpDocumentor.phar"
26 |
27 | else
28 | PHPDOC=`which phpdoc`
29 | if [ ! -f "$PHPDOC" ]; then
30 | echo "Neither apigen nor phpdoc is installed in the path or locally, please install one of them"
31 | echo "see http://www.apigen.org/ or http://www.phpdoc.org/"
32 | exit 1
33 | fi
34 | fi
35 | fi
36 | fi
37 |
38 | #
39 | # As of version 4 of apigen need to use the generate subcommand
40 | #
41 | if [ ! -z "$APIGEN" ]; then
42 | APIGEN="$APIGEN generate"
43 | fi
44 |
45 | #
46 | # Without any arguments this builds the entire system documentation,
47 | # making the cache file first if required.
48 | #
49 | if [ -z "$1" ]; then
50 | #
51 | # Check to see that the cache has been made.
52 | #
53 | if [ ! -f dirlist.cache ]; then
54 | echo "Making dirlist.cache file"
55 | $0 makecache
56 | fi
57 |
58 | #
59 | # Build the apigen/phpdoc command in a file.
60 | #
61 | if [ ! -z "$APIGEN" ]; then
62 | echo "$APIGEN --php --tree --title '$APPNAME API Documentation' --destination $DESTDIR/main \\" > $CMDFILE
63 | cat dirlist.cache | while read dir; do
64 | echo "--source $dir \\" >> $CMDFILE
65 | done
66 | echo "" >> $CMDFILE
67 |
68 | elif [ ! -z "$PHPDOC" ]; then
69 | echo "$PHPDOC --sourcecode --title '$APPNAME API Documentation' --target $DESTDIR/main --directory \\" > $CMDFILE
70 | cat dirlist.cache | while read dir; do
71 | echo "${dir},\\" >> $CMDFILE
72 | done
73 | echo "" >> $CMDFILE
74 |
75 | else
76 | "Neither apigen nor phpdoc are found, how did I get here?"
77 | exit 1
78 | fi
79 |
80 | #
81 | # Run the apigen command
82 | #
83 | rm -rf $DESTDIR/main
84 | mkdir -p $DESTDIR/main
85 | . ./$CMDFILE
86 |
87 | /bin/rm -f ./$CMDFILE
88 |
89 | #
90 | # The "makecache" argument causes the script to just make the cache file
91 | #
92 | elif [ "$1" = "makecache" ]; then
93 | echo "Find application source directories"
94 | find src -name \*.php -print | \
95 | (
96 | while read file; do
97 | grep -q 'class' $file && dirname $file
98 | done
99 | ) | sort -u | \
100 | grep -v -E 'config|docs|migrations|phpunit|test|Test|views|web' > dirlist.app
101 |
102 | echo "Find vendor source directories"
103 | find vendor -name \*.php -print | \
104 | (
105 | while read file; do
106 | grep -q 'class' $file && dirname $file
107 | done
108 | ) | sort -u | \
109 | grep -v -E 'config|docs|migrations|phpunit|codesniffer|test|Test|views' > dirlist.vendor
110 |
111 | #
112 | # Filter out any vendor directories for which apigen fails
113 | #
114 | echo "Filter source directories"
115 | mkdir -p $DESTDIR/tmp
116 | cat dirlist.app dirlist.vendor | while read dir; do
117 | if [ ! -z "$APIGEN" ]; then
118 | $APIGEN --quiet --title "Test please ignore" \
119 | --source $dir \
120 | --destination $DESTDIR/tmp && (
121 | echo "Including $dir"
122 | echo $dir >> dirlist.cache
123 | ) || (
124 | echo "Excluding $dir"
125 | )
126 |
127 | elif [ ! -z "$PHPDOC" ]; then
128 | $PHPDOC --quiet --title "Test please ignore" \
129 | --directory $dir \
130 | --target $DESTDIR/tmp && (
131 | echo "Including $dir"
132 | echo $dir >> dirlist.cache
133 | ) || (
134 | echo "Excluding $dir"
135 | )
136 |
137 | fi
138 | done
139 | echo "Documentation cache dirlist.cache built OK"
140 |
141 | #
142 | # Clean up
143 | #
144 | /bin/rm -rf $DESTDIR/tmp
145 |
146 | fi
147 |
--------------------------------------------------------------------------------
/src/ExpressGateway.php:
--------------------------------------------------------------------------------
1 | getParameter('solutionType');
31 | }
32 |
33 | public function setSolutionType($value)
34 | {
35 | return $this->setParameter('solutionType', $value);
36 | }
37 |
38 | public function getLandingPage()
39 | {
40 | return $this->getParameter('landingPage');
41 | }
42 |
43 | public function setLandingPage($value)
44 | {
45 | return $this->setParameter('landingPage', $value);
46 | }
47 |
48 | public function getBrandName()
49 | {
50 | return $this->getParameter('brandName');
51 | }
52 |
53 | public function setBrandName($value)
54 | {
55 | return $this->setParameter('brandName', $value);
56 | }
57 |
58 | public function getHeaderImageUrl()
59 | {
60 | return $this->getParameter('headerImageUrl');
61 | }
62 |
63 | public function getLogoImageUrl()
64 | {
65 | return $this->getParameter('logoImageUrl');
66 | }
67 |
68 | public function getBorderColor()
69 | {
70 | return $this->getParameter('borderColor');
71 | }
72 |
73 | /**
74 | * Header Image URL (Optional)
75 | *
76 | * URL for the image you want to appear at the top left of the payment page.
77 | * The image has a maximum size of 750 pixels wide by 90 pixels high.
78 | * PayPal recommends that you provide an image that is stored on a secure
79 | * (HTTPS) server.
80 | * If you do not specify an image, the business name displays.
81 | * Character length and limitations: 127 single-byte alphanumeric characters
82 | */
83 | public function setHeaderImageUrl($value)
84 | {
85 | return $this->setParameter('headerImageUrl', $value);
86 | }
87 |
88 | /**
89 | * Logo Image URL (Optional)
90 | *
91 | * URL for the image to appear above the order summary, in place of the
92 | * brand name.
93 | * The recommended size is 190 pixels wide and 60 pixels high.
94 | */
95 | public function setLogoImageUrl($value)
96 | {
97 | return $this->setParameter('logoImageUrl', $value);
98 | }
99 |
100 | /**
101 | * Border Color (Optional)
102 | *
103 | * The color of the border gradient on payment pages.
104 | * Should be a six character hexadecimal code (i.e. C0C0C0).
105 | */
106 | public function setBorderColor($value)
107 | {
108 | return $this->setParameter('borderColor', $value);
109 | }
110 |
111 | public function setSellerPaypalAccountId($value)
112 | {
113 | return $this->setParameter('sellerPaypalAccountId', $value);
114 | }
115 |
116 | public function getSellerPaypalAccountId()
117 | {
118 | return $this->getParameter('sellerPaypalAccountId');
119 | }
120 |
121 | public function authorize(array $parameters = array())
122 | {
123 | return $this->createRequest('\Omnipay\PayPal\Message\ExpressAuthorizeRequest', $parameters);
124 | }
125 |
126 | public function completeAuthorize(array $parameters = array())
127 | {
128 | return $this->createRequest('\Omnipay\PayPal\Message\ExpressCompleteAuthorizeRequest', $parameters);
129 | }
130 |
131 | public function purchase(array $parameters = array())
132 | {
133 | return $this->authorize($parameters);
134 | }
135 |
136 | public function completePurchase(array $parameters = array())
137 | {
138 | return $this->createRequest('\Omnipay\PayPal\Message\ExpressCompletePurchaseRequest', $parameters);
139 | }
140 |
141 | public function void(array $parameters = array())
142 | {
143 | return $this->createRequest('\Omnipay\PayPal\Message\ExpressVoidRequest', $parameters);
144 | }
145 |
146 | public function fetchCheckout(array $parameters = array())
147 | {
148 | return $this->createRequest('\Omnipay\PayPal\Message\ExpressFetchCheckoutRequest', $parameters);
149 | }
150 |
151 | /**
152 | * @return Message\ExpressTransactionSearchRequest
153 | */
154 | public function transactionSearch(array $parameters = array())
155 | {
156 | return $this->createRequest('\Omnipay\PayPal\Message\ExpressTransactionSearchRequest', $parameters);
157 | }
158 |
159 | public function order(array $parameters = array())
160 | {
161 | return $this->createRequest('\Omnipay\PayPal\Message\ExpressOrderRequest', $parameters);
162 | }
163 |
164 | public function completeOrder(array $parameters = array())
165 | {
166 | return $this->createRequest('\Omnipay\PayPal\Message\ExpressCompleteOrderRequest', $parameters);
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/src/Message/RestSearchTransactionRequest.php:
--------------------------------------------------------------------------------
1 |
22 | * // List the transactions for a billing agreement.
23 | * $transaction = $gateway->listPurchase();
24 | * $response = $transaction->send();
25 | * $data = $response->getData();
26 | * echo "Gateway listPurchase response data == " . print_r($data, true) . "\n";
27 | *
28 | *
29 | * ### Request Sample
30 | *
31 | * This is from the PayPal web site:
32 | *
33 | *
34 | * curl -v GET https://api.sandbox.paypal.com/v1/payments/billing-agreements/I-0LN988D3JACS/transactions \
35 | * -H 'Content-Type:application/json' \
36 | * -H 'Authorization: Bearer '
37 | *
38 | *
39 | * ### Response Sample
40 | *
41 | * This is from the PayPal web site:
42 | *
43 | *
44 | * {
45 | * "agreement_transaction_list": [
46 | * {
47 | * "transaction_id": "I-0LN988D3JACS",
48 | * "status": "Created",
49 | * "transaction_type": "Recurring Payment",
50 | * "payer_email": "bbuyer@example.com",
51 | * "payer_name": "Betsy Buyer",
52 | * "time_stamp": "2014-06-09T09:29:36Z",
53 | * "time_zone": "GMT"
54 | * },
55 | * {
56 | * "transaction_id": "928415314Y5640008",
57 | * "status": "Completed",
58 | * "transaction_type": "Recurring Payment",
59 | * "amount": {
60 | * "currency": "USD",
61 | * "value": "1.00"
62 | * },
63 | * "fee_amount": {
64 | * "currency": "USD",
65 | * "value": "-0.33"
66 | * },
67 | * "net_amount": {
68 | * "currency": "USD",
69 | * "value": "0.67"
70 | * },
71 | * "payer_email": "bbuyer@example.com",
72 | * "payer_name": "Betsy Buyer",
73 | * "time_stamp": "2014-06-09T09:42:47Z",
74 | * "time_zone": "GMT"
75 | * },
76 | * {
77 | * "transaction_id": "I-0LN988D3JACS",
78 | * "status": "Suspended",
79 | * "transaction_type": "Recurring Payment",
80 | * "payer_email": "bbuyer@example.com",
81 | * "payer_name": "Betsy Buyer",
82 | * "time_stamp": "2014-06-09T11:18:34Z",
83 | * "time_zone": "GMT"
84 | * },
85 | * {
86 | * "transaction_id": "I-0LN988D3JACS",
87 | * "status": "Reactivated",
88 | * "transaction_type": "Recurring Payment",
89 | * "payer_email": "bbuyer@example.com",
90 | * "payer_name": "Betsy Buyer",
91 | * "time_stamp": "2014-06-09T11:18:48Z",
92 | * "time_zone": "GMT"
93 | * }
94 | * ]
95 | * }
96 | *
97 | *
98 | * ### Known Issues
99 | *
100 | * PayPal subscription payments cannot be refunded. PayPal is working on this functionality
101 | * for their future API release. In order to refund a PayPal subscription payment, you will
102 | * need to use the PayPal web interface to refund it manually.
103 | *
104 | * @see RestCreateSubscriptionRequest
105 | * @link https://developer.paypal.com/docs/api/#search-for-transactions
106 | */
107 | class RestSearchTransactionRequest extends AbstractRestRequest
108 | {
109 | /**
110 | * Get the agreement ID
111 | *
112 | * @return string
113 | */
114 | public function getAgreementId()
115 | {
116 | return $this->getParameter('agreementId');
117 | }
118 |
119 | /**
120 | * Set the agreement ID
121 | *
122 | * @param string $value
123 | * @return RestSearchTransactionRequest provides a fluent interface.
124 | */
125 | public function setAgreementId($value)
126 | {
127 | return $this->setParameter('agreementId', $value);
128 | }
129 |
130 | /**
131 | * Get the request startDate
132 | *
133 | * @return string
134 | */
135 | public function getStartDate()
136 | {
137 | return $this->getParameter('startDate');
138 | }
139 |
140 | /**
141 | * Set the request startDate
142 | *
143 | * @param string|DateTime $value
144 | * @return RestSearchTransactionRequest provides a fluent interface.
145 | */
146 | public function setStartDate($value)
147 | {
148 | return $this->setParameter('startDate', is_string($value) ? new \DateTime($value) : $value);
149 | }
150 |
151 | /**
152 | * Get the request endDate
153 | *
154 | * @return string
155 | */
156 | public function getEndDate()
157 | {
158 | return $this->getParameter('endDate');
159 | }
160 |
161 | /**
162 | * Set the request endDate
163 | *
164 | * @param string|DateTime $value
165 | * @return RestSearchTransactionRequest provides a fluent interface.
166 | */
167 | public function setEndDate($value)
168 | {
169 | return $this->setParameter('endDate', is_string($value) ? new \DateTime($value) : $value);
170 | }
171 |
172 | public function getData()
173 | {
174 | $this->validate('agreementId', 'startDate', 'endDate');
175 | return array(
176 | 'start_date' => $this->getStartDate()->format('Y-m-d'),
177 | 'end_date' => $this->getEndDate()->format('Y-m-d'),
178 | );
179 | }
180 |
181 | /**
182 | * Get HTTP Method.
183 | *
184 | * The HTTP method for searchTransaction requests must be GET.
185 | *
186 | * @return string
187 | */
188 | protected function getHttpMethod()
189 | {
190 | return 'GET';
191 | }
192 |
193 | public function getEndpoint()
194 | {
195 | return parent::getEndpoint() . '/payments/billing-agreements/' .
196 | $this->getAgreementId() . '/transactions';
197 | }
198 | }
199 |
--------------------------------------------------------------------------------
/tests/Message/RestAuthorizeRequestTest.php:
--------------------------------------------------------------------------------
1 | request = new RestAuthorizeRequest($this->getHttpClient(), $this->getHttpRequest());
20 | $this->request->initialize(
21 | array(
22 | 'amount' => '10.00',
23 | 'currency' => 'USD',
24 | 'returnUrl' => 'https://www.example.com/return',
25 | 'cancelUrl' => 'https://www.example.com/cancel',
26 | )
27 | );
28 | }
29 |
30 | public function testGetDataWithoutCard()
31 | {
32 | $this->request->setTransactionId('abc123');
33 | $this->request->setDescription('Sheep');
34 |
35 | $data = $this->request->getData();
36 |
37 | $this->assertSame('authorize', $data['intent']);
38 | $this->assertSame('paypal', $data['payer']['payment_method']);
39 | $this->assertSame('10.00', $data['transactions'][0]['amount']['total']);
40 | $this->assertSame('USD', $data['transactions'][0]['amount']['currency']);
41 | $this->assertSame('abc123 : Sheep', $data['transactions'][0]['description']);
42 |
43 | // Funding instruments must not be set, otherwise paypal API will give error 500.
44 | $this->assertArrayNotHasKey('funding_instruments', $data['payer']);
45 |
46 | $this->assertSame('https://www.example.com/return', $data['redirect_urls']['return_url']);
47 | $this->assertSame('https://www.example.com/cancel', $data['redirect_urls']['cancel_url']);
48 | }
49 |
50 | public function testGetDataWithCard()
51 | {
52 | $card = new CreditCard($this->getValidCard());
53 | $card->setStartMonth(1);
54 | $card->setStartYear(2000);
55 |
56 | $this->request->setCard($card);
57 | $this->request->setTransactionId('abc123');
58 | $this->request->setDescription('Sheep');
59 | $this->request->setClientIp('127.0.0.1');
60 |
61 | $data = $this->request->getData();
62 |
63 | $this->assertSame('authorize', $data['intent']);
64 | $this->assertSame('credit_card', $data['payer']['payment_method']);
65 | $this->assertSame('10.00', $data['transactions'][0]['amount']['total']);
66 | $this->assertSame('USD', $data['transactions'][0]['amount']['currency']);
67 | $this->assertSame('abc123 : Sheep', $data['transactions'][0]['description']);
68 |
69 | $this->assertSame($card->getNumber(), $data['payer']['funding_instruments'][0]['credit_card']['number']);
70 | $this->assertSame($card->getBrand(), $data['payer']['funding_instruments'][0]['credit_card']['type']);
71 | $this->assertSame($card->getExpiryMonth(), $data['payer']['funding_instruments'][0]['credit_card']['expire_month']);
72 | $this->assertSame($card->getExpiryYear(), $data['payer']['funding_instruments'][0]['credit_card']['expire_year']);
73 | $this->assertSame($card->getCvv(), $data['payer']['funding_instruments'][0]['credit_card']['cvv2']);
74 |
75 | $this->assertSame($card->getFirstName(), $data['payer']['funding_instruments'][0]['credit_card']['first_name']);
76 | $this->assertSame($card->getLastName(), $data['payer']['funding_instruments'][0]['credit_card']['last_name']);
77 | $this->assertSame($card->getAddress1(), $data['payer']['funding_instruments'][0]['credit_card']['billing_address']['line1']);
78 | $this->assertSame($card->getAddress2(), $data['payer']['funding_instruments'][0]['credit_card']['billing_address']['line2']);
79 | $this->assertSame($card->getCity(), $data['payer']['funding_instruments'][0]['credit_card']['billing_address']['city']);
80 | $this->assertSame($card->getState(), $data['payer']['funding_instruments'][0]['credit_card']['billing_address']['state']);
81 | $this->assertSame($card->getPostcode(), $data['payer']['funding_instruments'][0]['credit_card']['billing_address']['postal_code']);
82 | $this->assertSame($card->getCountry(), $data['payer']['funding_instruments'][0]['credit_card']['billing_address']['country_code']);
83 | }
84 |
85 | public function testGetDataWithItems()
86 | {
87 | $this->request->setAmount('50.00');
88 | $this->request->setCurrency('USD');
89 | $this->request->setItems(array(
90 | array('name' => 'Floppy Disk', 'description' => 'MS-DOS', 'quantity' => 2, 'price' => 10),
91 | array('name' => 'CD-ROM', 'description' => 'Windows 95', 'quantity' => 1, 'price' => 40),
92 | ));
93 |
94 | $data = $this->request->getData();
95 | $transactionData = $data['transactions'][0];
96 |
97 | $this->assertSame('Floppy Disk', $transactionData['item_list']['items'][0]['name']);
98 | $this->assertSame('MS-DOS', $transactionData['item_list']['items'][0]['description']);
99 | $this->assertSame(2, $transactionData['item_list']['items'][0]['quantity']);
100 | $this->assertSame('10.00', $transactionData['item_list']['items'][0]['price']);
101 |
102 | $this->assertSame('CD-ROM', $transactionData['item_list']['items'][1]['name']);
103 | $this->assertSame('Windows 95', $transactionData['item_list']['items'][1]['description']);
104 | $this->assertSame(1, $transactionData['item_list']['items'][1]['quantity']);
105 | $this->assertSame('40.00', $transactionData['item_list']['items'][1]['price']);
106 |
107 | $this->assertSame('50.00', $transactionData['amount']['total']);
108 | $this->assertSame('USD', $transactionData['amount']['currency']);
109 | }
110 |
111 | public function testDescription()
112 | {
113 | $this->request->setTransactionId('');
114 | $this->request->setDescription('');
115 | $this->assertEmpty($this->request->getDescription());
116 |
117 | $this->request->setTransactionId('');
118 | $this->request->setDescription('Sheep');
119 | $this->assertEquals('Sheep', $this->request->getDescription());
120 |
121 | $this->request->setTransactionId('abc123');
122 | $this->request->setDescription('');
123 | $this->assertEquals('abc123', $this->request->getDescription());
124 |
125 | $this->request->setTransactionId('abc123');
126 | $this->request->setDescription('Sheep');
127 | $this->assertEquals('abc123 : Sheep', $this->request->getDescription());
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/src/Message/RestListPlanRequest.php:
--------------------------------------------------------------------------------
1 |
20 | * // Create a gateway for the PayPal RestGateway
21 | * // (routes to GatewayFactory::create)
22 | * $gateway = Omnipay::create('PayPal_Rest');
23 | *
24 | * // Initialise the gateway
25 | * $gateway->initialize(array(
26 | * 'clientId' => 'MyPayPalClientId',
27 | * 'secret' => 'MyPayPalSecret',
28 | * 'testMode' => true, // Or false when you are ready for live transactions
29 | * ));
30 | *
31 | *
32 | * #### List all plans that have state CREATED
33 | *
34 | *
35 | * // List all billing plans
36 | * $transaction = $gateway->listPlan([
37 | * 'state' => CREATED,
38 | * ]);
39 | * $response = $transaction->send();
40 | * $data = $response->getData();
41 | * echo "Gateway listPlan response data == " . print_r($data, true) . "\n";
42 | *
43 | *
44 | * ### Request Sample
45 | *
46 | * This is from the PayPal web site:
47 | *
48 | *
49 | * curl -v -X GET https://api.sandbox.paypal.com/v1/payments/billing-plans?page_size=3&status=ACTIVE&page=1\
50 | * -H "Content-Type:application/json" \
51 | * -H "Authorization: Bearer Access-Token"
52 | *
53 | *
54 | * ### Response Sample
55 | *
56 | * This is from the PayPal web site:
57 | *
58 | *
59 | * {
60 | * "total_items": "166",
61 | * "total_pages": "83",
62 | * "plans": [
63 | * {
64 | * "id": "P-7DC96732KA7763723UOPKETA",
65 | * "state": "ACTIVE",
66 | * "name": "Plan with Regular and Trial Payment Definitions",
67 | * "description": "Plan with regular and trial billing payment definitions.",
68 | * "type": "FIXED",
69 | * "create_time": "2017-08-22T04:41:52.836Z",
70 | * "update_time": "2017-08-22T04:41:53.169Z",
71 | * "links": [
72 | * {
73 | * "href": "https://api.sandbox.paypal.com//v1/payments/billing-plans/P-7DC96732KA7763723UOPKETA",
74 | * "rel": "self",
75 | * "method": "GET"
76 | * }
77 | * ]
78 | * },
79 | * {
80 | * "id": "P-1TV69435N82273154UPWDU4I",
81 | * "state": "ACTIVE",
82 | * "name": "Plan with Regular Payment Definition",
83 | * "description": "Plan with one regular payment definition, minimal merchant preferences, and no shipping fee",
84 | * "type": "INFINITE",
85 | * "create_time": "2017-08-22T04:41:55.623Z",
86 | * "update_time": "2017-08-22T04:41:56.055Z",
87 | * "links": [
88 | * {
89 | * "href": "https://api.sandbox.paypal.com//v1/payments/billing-plans/P-1TV69435N82273154UPWDU4I",
90 | * "rel": "self",
91 | * "method": "GET"
92 | * }
93 | * ]
94 | * }
95 | * ],
96 | * "links": [
97 | * {
98 | * "href": "https://api.sandbox.paypal.com/v1/payments/billing-plans?page_size=2&page=1&start=3&status=active",
99 | * "rel": "start",
100 | * "method": "GET"
101 | * },
102 | * {
103 | * "href": "https://api.sandbox.paypal.com/v1/payments/billing-plans?page_size=2&page=0&status=active",
104 | * "rel": "previous_page",
105 | * "method": "GET"
106 | * },
107 | * {
108 | * "href": "https://api.sandbox.paypal.com/v1/payments/billing-plans?page_size=2&page=2&status=active",
109 | * "rel": "next_page",
110 | * "method": "GET"
111 | * },
112 | * {
113 | * "href": "https://api.sandbox.paypal.com/v1/payments/billing-plans?page_size=2&page=82&status=active",
114 | * "rel": "last",
115 | * "method": "GET"
116 | * }
117 | * ]
118 | * }
119 | *
120 | *
121 | *
122 | * @link https://developer.paypal.com/docs/api/payments.billing-plans#plan_list
123 | */
124 | class RestListPlanRequest extends AbstractRestRequest
125 | {
126 | /**
127 | *
128 | * Get the request page
129 | *
130 | * @return integer
131 | */
132 |
133 | public function getPage()
134 | {
135 | return $this->getParameter('page');
136 | }
137 |
138 |
139 | /**
140 | * Set the request page
141 | *
142 | * @param integer $value
143 | * @return AbstractRestRequest provides a fluent interface.
144 | */
145 | public function setPage($value)
146 | {
147 | return $this->setParameter('page', $value);
148 | }
149 |
150 | /**
151 | * Get the request status
152 | *
153 | * @return string
154 | */
155 | public function getStatus()
156 | {
157 | return $this->getParameter('status');
158 | }
159 |
160 | /**
161 | * Set the request status
162 | *
163 | * @param string $value
164 | * @return AbstractRestRequest provides a fluent interface.
165 | */
166 | public function setStatus($value)
167 | {
168 | return $this->setParameter('status', $value);
169 | }
170 |
171 | /**
172 | * Get the request page size
173 | *
174 | * @return string
175 | */
176 | public function getPageSize()
177 | {
178 | return $this->getParameter('pageSize');
179 | }
180 |
181 | /**
182 | * Set the request page size
183 | *
184 | * @param string $value
185 | * @return AbstractRestRequest provides a fluent interface.
186 | */
187 | public function setPageSize($value)
188 | {
189 | return $this->setParameter('pageSize', $value);
190 | }
191 |
192 | /**
193 | * Get the request total required
194 | *
195 | * @return string
196 | */
197 | public function getTotalRequired()
198 | {
199 | return $this->getParameter('totalRequired');
200 | }
201 |
202 | /**
203 | * Set the request total required
204 | *
205 | * @param string $value
206 | * @return AbstractRestRequest provides a fluent interface.
207 | */
208 | public function setTotalRequired($value)
209 | {
210 | return $this->setParameter('totalRequired', $value);
211 | }
212 |
213 |
214 |
215 |
216 | public function getData()
217 | {
218 | return array(
219 | 'page' => $this->getPage(),
220 | 'status' => $this->getStatus(),
221 | 'page_size' => $this->getPageSize(),
222 | 'total_required' => $this->getTotalRequired()
223 | );
224 | }
225 |
226 | /**
227 | * Get HTTP Method.
228 | *
229 | * The HTTP method for list plans requests must be GET.
230 | *
231 | * @return string
232 | */
233 | protected function getHttpMethod()
234 | {
235 | return 'GET';
236 | }
237 |
238 | public function getEndpoint()
239 | {
240 | return parent::getEndpoint() . '/payments/billing-plans';
241 | }
242 | }
243 |
--------------------------------------------------------------------------------
/src/Message/AbstractRestRequest.php:
--------------------------------------------------------------------------------
1 |
20 | * POST https://api.paypal.com/v1/payments/payment
21 | *
22 | *
23 | * To create a complete request, combine the operation with the appropriate HTTP headers
24 | * and any required JSON payload.
25 | *
26 | * @link https://developer.paypal.com/docs/api/
27 | * @link https://devtools-paypal.com/integrationwizard/
28 | * @link http://paypal.github.io/sdk/
29 | * @see Omnipay\PayPal\RestGateway
30 | */
31 | abstract class AbstractRestRequest extends \Omnipay\Common\Message\AbstractRequest
32 | {
33 | const API_VERSION = 'v1';
34 |
35 | /**
36 | * Sandbox Endpoint URL
37 | *
38 | * The PayPal REST APIs are supported in two environments. Use the Sandbox environment
39 | * for testing purposes, then move to the live environment for production processing.
40 | * When testing, generate an access token with your test credentials to make calls to
41 | * the Sandbox URIs. When you’re set to go live, use the live credentials assigned to
42 | * your app to generate a new access token to be used with the live URIs.
43 | *
44 | * @var string URL
45 | */
46 | protected $testEndpoint = 'https://api.sandbox.paypal.com';
47 |
48 | /**
49 | * Live Endpoint URL
50 | *
51 | * When you’re set to go live, use the live credentials assigned to
52 | * your app to generate a new access token to be used with the live URIs.
53 | *
54 | * @var string URL
55 | */
56 | protected $liveEndpoint = 'https://api.paypal.com';
57 |
58 | /**
59 | * PayPal Payer ID
60 | *
61 | * @var string PayerID
62 | */
63 | protected $payerId = null;
64 |
65 | protected $referrerCode;
66 |
67 | /**
68 | * @var bool
69 | */
70 | protected $negativeAmountAllowed = true;
71 |
72 | /**
73 | * @return string
74 | */
75 | public function getReferrerCode()
76 | {
77 | return $this->referrerCode;
78 | }
79 |
80 | /**
81 | * @param string $referrerCode
82 | */
83 | public function setReferrerCode($referrerCode)
84 | {
85 | $this->referrerCode = $referrerCode;
86 | }
87 |
88 | public function getClientId()
89 | {
90 | return $this->getParameter('clientId');
91 | }
92 |
93 | public function setClientId($value)
94 | {
95 | return $this->setParameter('clientId', $value);
96 | }
97 |
98 | public function getSecret()
99 | {
100 | return $this->getParameter('secret');
101 | }
102 |
103 | public function setSecret($value)
104 | {
105 | return $this->setParameter('secret', $value);
106 | }
107 |
108 | public function getToken()
109 | {
110 | return $this->getParameter('token');
111 | }
112 |
113 | public function setToken($value)
114 | {
115 | return $this->setParameter('token', $value);
116 | }
117 |
118 | public function getPayerId()
119 | {
120 | return $this->getParameter('payerId');
121 | }
122 |
123 | public function setPayerId($value)
124 | {
125 | return $this->setParameter('payerId', $value);
126 | }
127 |
128 | /**
129 | * Get HTTP Method.
130 | *
131 | * This is nearly always POST but can be over-ridden in sub classes.
132 | *
133 | * @return string
134 | */
135 | protected function getHttpMethod()
136 | {
137 | return 'POST';
138 | }
139 |
140 | protected function getEndpoint()
141 | {
142 | $base = $this->getTestMode() ? $this->testEndpoint : $this->liveEndpoint;
143 | return $base . '/' . self::API_VERSION;
144 | }
145 |
146 | public function sendData($data)
147 | {
148 |
149 | // Guzzle HTTP Client createRequest does funny things when a GET request
150 | // has attached data, so don't send the data if the method is GET.
151 | if ($this->getHttpMethod() == 'GET') {
152 | $requestUrl = $this->getEndpoint() . '?' . http_build_query($data);
153 | $body = null;
154 | } else {
155 | $body = $this->toJSON($data);
156 | $requestUrl = $this->getEndpoint();
157 | }
158 |
159 | // Might be useful to have some debug code here, PayPal especially can be
160 | // a bit fussy about data formats and ordering. Perhaps hook to whatever
161 | // logging engine is being used.
162 | // echo "Data == " . json_encode($data) . "\n";
163 |
164 | try {
165 | $httpResponse = $this->httpClient->request(
166 | $this->getHttpMethod(),
167 | $this->getEndpoint(),
168 | array(
169 | 'Accept' => 'application/json',
170 | 'Authorization' => 'Bearer ' . $this->getToken(),
171 | 'Content-type' => 'application/json',
172 | 'PayPal-Partner-Attribution-Id' => $this->getReferrerCode(),
173 | ),
174 | $body
175 | );
176 | // Empty response body should be parsed also as and empty array
177 | $body = (string) $httpResponse->getBody()->getContents();
178 | $jsonToArrayResponse = !empty($body) ? json_decode($body, true) : array();
179 | return $this->response = $this->createResponse($jsonToArrayResponse, $httpResponse->getStatusCode());
180 | } catch (\Exception $e) {
181 | throw new InvalidResponseException(
182 | 'Error communicating with payment gateway: ' . $e->getMessage(),
183 | $e->getCode()
184 | );
185 | }
186 | }
187 |
188 | /**
189 | * Returns object JSON representation required by PayPal.
190 | * The PayPal REST API requires the use of JSON_UNESCAPED_SLASHES.
191 | *
192 | * Adapted from the official PayPal REST API PHP SDK.
193 | * (https://github.com/paypal/PayPal-PHP-SDK/blob/master/lib/PayPal/Common/PayPalModel.php)
194 | *
195 | * @param int $options http://php.net/manual/en/json.constants.php
196 | * @return string
197 | */
198 | public function toJSON($data, $options = 0)
199 | {
200 | // Because of PHP Version 5.3, we cannot use JSON_UNESCAPED_SLASHES option
201 | // Instead we would use the str_replace command for now.
202 | // TODO: Replace this code with return json_encode($this->toArray(), $options | 64); once we support PHP >= 5.4
203 | if (version_compare(phpversion(), '5.4.0', '>=') === true) {
204 | return json_encode($data, $options | 64);
205 | }
206 | return str_replace('\\/', '/', json_encode($data, $options));
207 | }
208 |
209 | protected function createResponse($data, $statusCode)
210 | {
211 | return $this->response = new RestResponse($this, $data, $statusCode);
212 | }
213 | }
214 |
--------------------------------------------------------------------------------