Giter VIP home page Giter VIP logo

spreedly's Introduction

changelog !! As of the 2.0 release the amount must be an integer as required by Spreedly. E.g., 1098 for $10.98 !!

Getting Started

Setup/Install

Install through Composer.

composer require tuurbo/spreedly

Laravel 4 or 5 Setup

Next, update app/config/app.php to include a reference to this package's service provider in the providers array and the facade in the aliases array.

'providers' => [
    ...
   'Tuurbo\Spreedly\SpreedlyServiceProvider'
]

'aliases' => [
    ...
    'Spreedly' => 'Tuurbo\Spreedly\SpreedlyFacade'
]

Login to your Spreedly account to retrieve your api credentials. You can set your default gateway once you've created your first gateway.

Add to app/config/services.php config file.

return [

    ...

    'spreedly' => [
        'key' => '', // (required) Environment key
        'secret' => '', // (required) Signing Secret
        'gateway' => '', // (required) Default gateway
        'timeout' => '', // (optional) Default 64 seconds (recommended by Spreedly)
        'connect_timeout' => '', // (optional) Default 10 seconds
    ]

];

Default Setup (Non Laravel)

$config = [
    'key' => '', // (required) Environment key
    'secret' => '', // (required) Signing Secret
    'gateway' => '', // (required) Default gateway
    'timeout' => '', // (optional) Default 64 seconds (recommended by Spreedly)
    'connect_timeout' => '', // (optional) Default 10 seconds
];

$spreedly = new Tuurbo\Spreedly\Spreedly($config);

// The amount must be an integer as per required by Spreedly. E.g., 1098 for $10.98.
$resp = $spreedly->payment($paymentToken)->purchase(1098);

Example response handling

// If the call to Spreedly is successful
if ($resp->success()) {
    return $resp->response();
    // $resp->transactionToken();
    // $resp->paymentToken();
    // $resp->message();
}

// If the call to Spreedly fails or payment declines
if ($resp->fails()) {

    // returns array
    return $resp->errors();

    // returns list of errors as a string
    return $resp->errors(true);
}

More Docs

Quick list of all methods

NOTE: Many of the methods below return multiple tokens. Be sure when storing tokens, you store the correct ones for later use.

// Gateway calls.
Spreedly::gateway()->setup();
Spreedly::gateway()->all();
Spreedly::gateway()->show();
Spreedly::gateway()->create();
Spreedly::gateway()->disable();
Spreedly::gateway()->update();
Spreedly::gateway()->transactions();

// If using multiple gateways, you can set the gateway token before the payment call.
Spreedly::gateway()->payment()->purchase();
Spreedly::gateway()->payment()->authorize();

// Uses default gateway.
Spreedly::payment()->all();
Spreedly::payment()->create();
Spreedly::payment()->update();
Spreedly::payment()->disable();
Spreedly::payment()->retain();
Spreedly::payment()->recache();
Spreedly::payment()->store();
Spreedly::payment()->get();
Spreedly::payment()->transactions();
Spreedly::payment()->purchase();
Spreedly::payment()->authorize();
Spreedly::payment()->verify();
Spreedly::payment()->generalCredit();

// Transaction calls
Spreedly::transaction()->all();
Spreedly::transaction()->get();
Spreedly::transaction()->referencing();
Spreedly::transaction()->transcript();
Spreedly::transaction()->purchase();
Spreedly::transaction()->void();
Spreedly::transaction()->credit();
Spreedly::transaction()->capture();
Spreedly::transaction()->complete();

Development

Clone the repo and run npm install. This will composer install.

Testing

Tests are in the spec directory. They are written with phpspec.

To run your tests, simply do npm test. If you don't want to use npm, that's fine, simply run vendor/bin/phpspec run

Please ensure you have added proper test coverage for each Pull Request.

Changelog

2.4+

See releases page https://github.com/tuurbo/spreedly/releases

2.3

  • added support for laravel 5.4

2.2

  • added ability to merge configs.

2.1

  • changed default timeout from 15 seconds to 64 seconds as recommended by Spreedly.
  • added timeout method to change timeout per api call. E.g., Spreedly::timeout(25)->payment()->purchase().
  • added new Tuurbo\Spreedly\Exceptions\TimeoutException for catching timeouts.

2.0

  • amount is no longer converted to cents.
    • the amount must be an integer as required by Spreedly. E.g., 1098 for $10.98
  • switched from Spreedly xml api to json api.
  • renamed ->declined() method to ->message().

spreedly's People

Contributors

adridev avatar andyfleming avatar danielfosbery avatar jcherniak avatar lasergoat avatar oradwell avatar tuurbo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

spreedly's Issues

Response wrapper methods throw exceptions inappropriately

In Client model.

For instance, if $this->response['payment_method'] is not set, then paymentToken() throws an exception, but response('payment_method.token') correctly returns null.

Is this expected behaviour? Should paymentToken not be wrapping a call to response(), rather than accessing the attribute directly?

setResponse doesn't set response status

I am trying to create a Spreedly client using:

// Retrieve transaction from POST data
$xmlText = file_get_contents('php://input', 'r');
$xml = new SimpleXMLElement($xmlText, LIBXML_NONET | LIBXML_NOCDATA);
// We expect only one transaction
$transactionXml = $xml->children()[0];

$client = new \Tuurbo\Spreedly\Client(new \GuzzleHttp\Client, []);
$client->setResponse($transactionXml);

Problem I have is that when response is set that way, status of the response does not get set on the client. Therefore the result of $client->success() and $client->fails() is always false.

I think it would be better if the code that sets the status:

if (isset($this->response['error']) || (isset($this->response['succeeded']) && $this->response['succeeded'] == 'false'))
{
    $this->status = 'error';

    return $this;
}

$this->status = 'success';

was inside setResponse method.

--- vendor/tuurbo/spreedly/src/Client.php    Tue Oct 20 17:53:03 2015
+++ vendor/tuurbo/spreedly/src/Client.php    Tue Oct 20 17:53:06 2015
@@ -58,15 +58,6 @@

        $this->setResponse($response);

-       if (isset($this->response['error']) || (isset($this->response['succeeded']) && $this->response['succeeded'] == 'false'))
-       {
-           $this->status = 'error';
-
-           return $this;
-       }
-
-       $this->status = 'success';
-
        return $this;
    }

@@ -93,6 +84,15 @@
        $response = json_decode(json_encode((array) $response), true);

        $this->response = $this->cleanArray($response);
+
+       if (isset($this->response['error']) || (isset($this->response['succeeded']) && $this->response['succeeded'] == 'false'))
+       {
+           $this->status = 'error';
+
+           return $this;
+       }
+
+       $this->status = 'success';
    }

    /**

Allow to post data on complete 3DS 2 calls

According to Spreedly guide:

Note: Worldpay uses postMessages to notify when authentication needs to progress to the next step. We pass these parameters in event.context.

{"MessageType": "profile.completed", "SessionId": "d3197c02-6f63-4ab2-801c-83633d097e32","Status": true)

These parameters should be included in the complete call using the key context.

{context: {"MessageType": "profile.completed", "SessionId": "d3197c02-6f63-4ab2-801c-83633d097e32", "Status": true}}

These parameters will only be sent during trigger-completion events

Would it be possible to allow to pass an array $data in the complete() call (it could be empty by default)?

    /**
     * Can be used to Completes a 3DS 2 transaction in the device fingerprint stage
     * See docs for more information.
     *
     * <code>
     *		// Completes a 3DS 2 transaction in the device fingerprint stage.
     *		Spreedly::transaction($transactionToken)->complete($data);
     * </code>
     *
     *
     * @return mixed
     *
     * @throws Exceptions\MissingTransactionTokenException
     */
    public function complete(array $data = [])
    {
        if (!$this->transactionToken) {
            throw new Exceptions\MissingTransactionTokenException();
        }

        return $this->client->post('v1/transactions/'.$this->transactionToken.'/complete.json', $data);
    }

Failed requests don't always throw exception

In the Client::request() method you are checking for certain error codes and throwing exceptions when they occur, but if it's not one you check for, you just set $this->status = 'error' so that user's of the library must check for this variable every single time we make a request.

Code: https://github.com/tuurbo/spreedly/blob/master/src/Client.php#L82

Are you opposed to always throwing an exception on line 82? If you are, would you be opposed to adding a configuration variable we could set to throw exceptions (that's disabled by default)? I can write the code if you like.

We've seen Spreedly APIs returning HTTP 504 and other error response codes that aren't currently throwing an exception so our code just keeps chugging along.

Issue with required version of Guzzle (4.0)

I'm excited to use this library. However when doing composer update I get this error:

Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - tuurbo/spreedly 0.9.2 requires guzzlehttp/guzzle ~4.0 -> no matching package found.
    - tuurbo/spreedly 0.9.1 requires guzzlehttp/guzzle ~4.0 -> no matching package found.
    - tuurbo/spreedly 0.9.0 requires guzzlehttp/guzzle ~4.0 -> no matching package found.
    - Installation request for tuurbo/spreedly ~0.9 -> satisfiable by tuurbo/spreedly[0.9.0, 0.9.1, 0.9.2].

Before finding this library I was hitting spreedly with guzzle directly, and using Guzzle 5.2. Is there a way I can overwrite your requirement of an old version of Guzzle? Or, is that even the problem.

Add support to complete 3DS 2 transactions

A new endpoint transactions/{token}/complete has been added to be able to complete a
3DS 2 transaction (https://docs.spreedly.com/reference/api/v1/transactions/). The SDK cannot reach that endpoint right now so a new method like the one below should be added to src/Transaction.php

    /**
     * Can be used to Completes a 3DS 2 transaction in the device fingerprint stage
     * See docs for more information.
     *
     * <code>
     *		// Completes a 3DS 2 transaction in the device fingerprint stage.
     *		Spreedly::transaction($transactionToken)->complete();
     * </code>
     *
     *
     * @return mixed
     *
     * @throws Exceptions\MissingTransactionTokenException
     */
    public function complete()
    {
        if (!$this->transactionToken) {
            throw new Exceptions\MissingTransactionTokenException();
        }

        return $this->client->post('v1/transactions/'.$this->transactionToken.'/complete.json');
    }

Dont times * 100 on amount

You should not be doing times on the amount. Because the currency cannot always be split into 100.

For example YPN (japanese) will not be multiplied with 100.

Checkout form cannot be retrieved for 3D Secure transactions

From https://docs.spreedly.com/guides/3dsecure/

<transaction>
  <on_test_gateway type="boolean">false</on_test_gateway>
  <created_at type="dateTime">2015-01-08T21:04:22Z</created_at>
  <updated_at type="dateTime">2015-01-08T21:04:22Z</updated_at>
  <succeeded type="boolean">false</succeeded>
  <state>pending</state>
  <token>AYNT7hwbLm2eAN2LYnCxanVlHVv</token>
  <transaction_type>Purchase</transaction_type>
  <order_id nil="true"/>
  <ip nil="true"/>
  <description nil="true"/>
  <email nil="true"/>
  <merchant_name_descriptor nil="true"/>
  <merchant_location_descriptor nil="true"/>
  <gateway_specific_fields nil="true"/>
  <gateway_specific_response_fields nil="true"/>
  <gateway_transaction_id nil="true"/>
  <amount type="integer">100</amount>
  <currency_code>USD</currency_code>
  <retain_on_success type="boolean">false</retain_on_success>
  <payment_method_added type="boolean">false</payment_method_added>
  <message key="messages.transaction_pending">Pending</message>
  <gateway_token>8XJtbE1p4NTZ6fFqwwn0GrkjEmW</gateway_token>
  <api_urls>
    <callback_conversations>https://core.spreedly.com/v1/callbacks/XjCHPJad2pDbIKKq2fOJezXmxiM/conversations.xml</callback_conversations>
  </api_urls>
  <payment_method>
    <token>XTpo2jo5q3mXi9uXsrDNyzeRkK9</token>
    <created_at type="dateTime">2015-01-08T16:04:22-05:00</created_at>
    <updated_at type="dateTime">2015-01-08T16:04:22-05:00</updated_at>
    <email nil="true"/>
    <data nil="true"/>
    <storage_state>cached</storage_state>
    <test type="boolean">true</test>
    <last_four_digits>3886</last_four_digits>
    <first_six_digits>455676</first_six_digits>
    <card_type>visa</card_type>
    <first_name>Bob</first_name>
    <last_name>Smith</last_name>
    <month type="integer">2</month>
    <year type="integer">2020</year>
    <address1 nil="true"/>
    <address2 nil="true"/>
    <city nil="true"/>
    <state nil="true"/>
    <zip nil="true"/>
    <country nil="true"/>
    <phone_number nil="true"/>
    <full_name>Bob Smith</full_name>
    <eligible_for_card_updater type="boolean">true</eligible_for_card_updater>
    <shipping_address1 nil="true"/>
    <shipping_address2 nil="true"/>
    <shipping_city nil="true"/>
    <shipping_state nil="true"/>
    <shipping_zip nil="true"/>
    <shipping_country nil="true"/>
    <shipping_phone_number nil="true"/>
    <payment_method_type>credit_card</payment_method_type>
    <errors>
    </errors>
    <verification_value>XXX</verification_value>
    <number>XXXX-XXXX-XXXX-3886</number>
  </payment_method>
  <callback_url>http://127.0.0.1:3044</callback_url>
  <redirect_url>http://example.com/handle_redirect</redirect_url>
  <checkout_url nil="true"/>
  <checkout_form>
    <![CDATA[
<form action="https://core.spreedly.com/test/8XJtbE1p4NTZ6fFqwwn0GrkjEmW/auth/AYNT7hwbLm2eAN2LYnCxanVlHVv" method="POST">
  <div>
    <input name="PaReq" value="" type="hidden"/>
    <input name="MD" value="" type="hidden"/>
    <input name="TermUrl" value="https://core.spreedly.com/transaction/AYNT7hwbLm2eAN2LYnCxanVlHVv/redirect" type="hidden"/>
    <input name="Complete" value="Authorize Transaction" type="submit"/>
  </div>
</form>
]]>
  </checkout_form>
  <setup_response>
    <success type="boolean">true</success>
    <message>Checked enrollment status</message>
    <error_code></error_code>
    <checkout_url nil="true"/>
    <created_at type="dateTime">2015-01-08T21:04:22Z</created_at>
    <updated_at type="dateTime">2015-01-08T21:04:22Z</updated_at>
  </setup_response>
</transaction>
$client = new \Tuurbo\Spreedly\Client(new \GuzzleHttp\Client, []);

checkout_form is a CDATA field and $client->response('checkout_form') returns empty string.

This is because default Guzzle config doesn't set LIBXML_NOCDATA flag for SimpleXMLElement. See: http://php.net/manual/en/libxml.constants.php#constant.libxml-nocdata

Fix:

--- vendor/tuurbo/spreedly/src/Client.php    Tue Oct 20 17:53:03 2015
+++ vendor/tuurbo/spreedly/src/Client.php    Tue Oct 20 18:05:33 2015
@@ -82,7 +82,13 @@
        {
            if ($response->getHeader('Content-Type') === 'application/xml; charset=utf-8')
            {
-               $response = $response->xml();
+               // We overwrite Guzzle libxml options
+               // as by default it doesn't show CDATA fields
+               $xmlConfig = [
+                   'libxml_options' => (LIBXML_NONET | LIBXML_NOCDATA),
+               ];
+
+               $response = $response->xml($xmlConfig);
            }
            else
            {

¿Work on Laravel 5.1?

I am thinking use tuurbo/spreedly in laravel 5.1 but i don't know if is compatible, is it?

credit expects cents not dollars.cents

For the new general credit method, the error is this:

Amount should be specified as an integer value corresponding to the number of cents. Example: $42.34 is 4234 cents.

I assume that the other methods are doing this for me, but not general_credit

Question about Base Url

We need the ability to change the base URL with a config. This is because we need to route our spreedly calls through another service first then do some mappings and let that other service then forward to spreedly.

If I submit a PR which would allow overriding the Base spreedly URL (but still defaulting to the correct url) would that be something you would approve or is this something you'd rather me maintain in a separate fork?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.