Skip to content

#219 support rest jsv4 implementation #221

New issue

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

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

Already on GitHub? Sign in to your account

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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"require-dev": {
"omnipay/tests": "^3",
"squizlabs/php_codesniffer": "^3",
"phpro/grumphp": "^0.14"
"phpro/grumphp": "1.3.0"
},
"extra": {
"branch-alias": {
Expand Down
2 changes: 1 addition & 1 deletion grumphp.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
parameters:
grumphp:
git_dir: .
bin_dir: vendor/bin
tasks:
Expand Down
46 changes: 43 additions & 3 deletions src/Message/RestAuthorizeRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

namespace Omnipay\PayPal\Message;

use Omnipay\Common\Exception\InvalidCreditCardException;

/**
* PayPal REST Authorize Request
*
Expand Down Expand Up @@ -251,17 +253,29 @@ public function getData()
$data['transactions'][0]['item_list']["items"] = $itemList;
}

if ($this->getCardReference()) {
if ($this->getCardReference() && substr($this->getCardReference(), 0, 2) === 'B-') {
// Card references can be for a billing agreement (format B-....) or a stored card format CARD-...
// here billing agreement
// https://developer.paypal.com/docs/limited-release/reference-transactions/#use-a-reference-transaction-to-make-a-payment
$this->validate('amount');
$data['payer']['funding_instruments'][] = array(
'billing' => array(
'billing_agreement_id' => $this->getCardReference(),
),
);
$data['payer']['payment_method'] = 'paypal';
} elseif ($this->getCardReference()) {
// stored card
//https://developer.paypal.com/docs/integration/direct/vault/#pay-with-vaulted-card
$this->validate('amount');

$data['payer']['funding_instruments'][] = array(
'credit_card_token' => array(
'credit_card_id' => $this->getCardReference(),
),
);
} elseif ($this->getCard()) {
} elseif ($this->validCardPresent()) {
$this->validate('amount', 'card');
$this->getCard()->validate();

$data['payer']['funding_instruments'][] = array(
'credit_card' => array(
Expand Down Expand Up @@ -304,6 +318,32 @@ public function getData()
return $data;
}

/**
* Has a valid card been passed in the Omnipay parameters.
*
* Omnipay supports details other than card details in the card parameter (e.g.
* billing address) so a generic omnipay integration might set the 'card' when
* there is no number present. In which case the Rest integration should fall
* back to the next method.
*/
public function validCardPresent()
{
$card = $this->getCard();
if (!$card) {
return false;
}
try {
$card->validate();
} catch (InvalidCreditCardException $e) {
if (stristr($e->getMessage(), 'is required')) {
return false;
} else {
throw $e;
}
}
return true;
}

/**
* Get the experience profile id
*
Expand Down
8 changes: 7 additions & 1 deletion src/Message/RestAuthorizeResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,11 @@ public function getTransactionReference()
// The transaction reference for a paypal purchase request or for a
// paypal create subscription request ends up in the execute URL
// in the links section of the response.
$completeUrl = $this->getCompleteUrl();
// this has been HACKED. Paypal changed it's product offering & introduced
// smart buttons instead of checkout.js and it needs something different returned.
// notes here https://github.com/thephpleague/omnipay-paypal/issues/228 but I couldn't see a
// good answer here so I just hacked.
$completeUrl = $this->getRedirectUrl();
if (empty($completeUrl)) {
return parent::getTransactionReference();
}
Expand All @@ -70,6 +74,8 @@ public function getTransactionReference()

// The last element of the URL should be "execute"
$execute = end($urlParts);
// part of hack above.
return (str_replace('webscr?cmd=_express-checkout&token=', '', $execute));
if (!in_array($execute, array('execute', 'agreement-execute'))) {
return parent::getTransactionReference();
}
Expand Down
117 changes: 117 additions & 0 deletions src/Message/RestCompleteCreateCardRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<?php
/**
* PayPal REST Complete Subscription Request
*/

namespace Omnipay\PayPal\Message;

/**
* PayPal REST Complete Create Card Request
*
* Use this call to create a billing agreement after the buyer approves it.
*
* Note: This request is only necessary for PayPal payments.
* https://developer.paypal.com/docs/limited-release/reference-transactions/#create-billing-agreement-token
*
* ### Request Data
*
* Pass the token in the URI of a POST call to execute the subscription
* agreement after buyer approval. You can find the token in the execute
* link returned by the request to create a billing agreement.
*
* No other data is required.
*
* ### Example
*
* To create the agreement, see the code example in RestCreateCardRequest.
*
* At the completion of a CreateCard call, the customer should be
* redirected to the redirect URL contained in $response->getRedirectUrl(). Once
* the customer has approved the agreement and be returned to the returnUrl
* in the call. The returnUrl can contain the following code to complete
* the agreement:
*
* <code>
* // Create a gateway for the PayPal REST Gateway
* // (routes to GatewayFactory::create)
* $gateway = Omnipay::create('PayPal_Rest');
*
* // Initialise the gateway
* $gateway->initialize(array(
* 'clientId' => 'MyPayPalClientId',
* 'secret' => 'MyPayPalSecret',
* 'testMode' => true, // Or false when you are ready for live transactions
* ));
*
* // Crate a card
* $transaction = $gateway->completeCreateCard(array(
* 'transactionReference' => $subscription_id,
* ));
* $response = $transaction->send();
* if ($response->isSuccessful()) {
* echo "Complete Subscription transaction was successful!\n";
* $subscription_id = $response->getTransactionReference();
* echo "Subscription reference = " . $subscription_id;
* }
* </code>
*
* Note that the subscription_id that you get from calling the response's
* getTransactionReference() method at the end of the completeSubscription
* call will be different to the one that you got after calling the response's
* getTransactionReference() method at the end of the createSubscription
* call. The one that you get from completeSubscription is the correct
* one to use going forwards (e.g. for cancelling or updating the subscription).
*
* ### Request Sample
*
* This is from the PayPal web site:
*
* <code>
* curl -v POST https://api.sandbox.paypal.com/v1/payments/billing-agreements/EC-0JP008296V451950C/agreement-execute \
* -H 'Content-Type:application/json' \
* -H 'Authorization: Bearer <Access-Token>' \
* -d '{}'
* </code>
*
* ### Response Sample
*
* This is from the PayPal web site:
*
* <code>
* {
* "id": "I-0LN988D3JACS",
* "links": [
* {
* "href": "https://api.sandbox.paypal.com/v1/payments/billing-agreements/I-0LN988D3JACS",
* "rel": "self",
* "method": "GET"
* }
* ]
* }
* </code>
*
* @link https://developer.paypal.com/docs/api/#execute-an-agreement
* @see RestCreateSubscriptionRequest
* @see Omnipay\PayPal\RestGateway
*/
class RestCompleteCreateCardRequest extends AbstractRestRequest
{
public function getData()
{
$this->validate('transactionReference');

return ['token_id' => $this->getTransactionReference()];
}

/**
* Get transaction endpoint.
*
* Subscriptions are executed using the /billing-agreements resource.
*
* @return string
*/
protected function getEndpoint()
{
return parent::getEndpoint() . '/billing-agreements/agreements';
}
}
86 changes: 60 additions & 26 deletions src/Message/RestCreateCardRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,39 +72,73 @@ class RestCreateCardRequest extends AbstractRestRequest
{
public function getData()
{
$this->validate('card');
$this->getCard()->validate();
if ($this->isCardPresent()) {
$this->validate('card');
$this->getCard()->validate();

$data = array(
'number' => $this->getCard()->getNumber(),
'type' => $this->getCard()->getBrand(),
'expire_month' => $this->getCard()->getExpiryMonth(),
'expire_year' => $this->getCard()->getExpiryYear(),
'cvv2' => $this->getCard()->getCvv(),
'first_name' => $this->getCard()->getFirstName(),
'last_name' => $this->getCard()->getLastName(),
'billing_address' => array(
'line1' => $this->getCard()->getAddress1(),
//'line2' => $this->getCard()->getAddress2(),
'city' => $this->getCard()->getCity(),
'state' => $this->getCard()->getState(),
'postal_code' => $this->getCard()->getPostcode(),
'country_code' => strtoupper($this->getCard()->getCountry()),
)
);
$data = array(
'number' => $this->getCard()->getNumber(),
'type' => $this->getCard()->getBrand(),
'expire_month' => $this->getCard()->getExpiryMonth(),
'expire_year' => $this->getCard()->getExpiryYear(),
'cvv2' => $this->getCard()->getCvv(),
'first_name' => $this->getCard()->getFirstName(),
'last_name' => $this->getCard()->getLastName(),
'billing_address' => array(
'line1' => $this->getCard()->getAddress1(),
//'line2' => $this->getCard()->getAddress2(),
'city' => $this->getCard()->getCity(),
'state' => $this->getCard()->getState(),
'postal_code' => $this->getCard()->getPostcode(),
'country_code' => strtoupper($this->getCard()->getCountry()),
)
);

// There's currently a quirk with the REST API that requires line2 to be
// non-empty if it's present. Jul 14, 2014
$line2 = $this->getCard()->getAddress2();
if (!empty($line2)) {
$data['billing_address']['line2'] = $line2;
// There's currently a quirk with the REST API that requires line2 to be
// non-empty if it's present. Jul 14, 2014
$line2 = $this->getCard()->getAddress2();
if (!empty($line2)) {
$data['billing_address']['line2'] = $line2;
}
} else {
// We are creating a token to rebill a paypal account.
// this equates to the meaning of 'createCard' in other processors
// such as Stripe.
// https://developer.paypal.com/docs/limited-release/reference-transactions/#create-billing-agreement
$data = ["description" => $this->getDescription(),
"payer" => ["payment_method" => "PAYPAL"],
"plan" =>
[
"type" => "MERCHANT_INITIATED_BILLING",
"merchant_preferences" =>
[
"return_url" => $this->getReturnUrl(),
"cancel_url" => $this->getCancelUrl(),
"notify_url" => $this->getNotifyUrl(),
"accepted_pymt_type" => "INSTANT",
"skip_shipping_address" => true,
"immutable_shipping_address" => false,
]
]
];
}

return $data;
}

protected function getEndpoint()
{
return parent::getEndpoint() . '/vault/credit-cards';
if ($this->isCardPresent()) {
return parent::getEndpoint() . '/vault/credit-cards';
} else {
return parent::getEndpoint() . '/billing-agreements/agreement-tokens';
}
}

/**
* Is the card present (or are we dealing with a paypal account transaction)
*/
protected function isCardPresent()
{
return $this->getCard()->getNumber();
}
}
Loading