Vandar Cashier is a Laravel package that allows you to seamlessly implement IPG and Direct Debit on your application

Overview

Vandar Cashier is a Laravel package that provides you with a seamless integration with Vandar services. Take a look at Vandar Documentation for more information on the services we provide.

Setup

To use Vandar Cashier, you need to install it through Composer first:

composer require vandarpay/cashier

Then, you will need to publish the package's assets and migrate your project's database to add Vandar Cashier's tables:

php artisan vendor:publish --provider="Vandar\\Cashier\\VandarCashierServiceProvider"
php artisan migrate

After that, open your User model (located in app/User.php or app/Models/User.php in most projects) and add the Billable trait:

use Vandar\Cashier\Traits\Billable;
// ...
class User extends Authenticatable
{
    use Billable;
// ...

You will need to add the necessary configuration to your .env file:

VANDAR_MOBILE=
VANDAR_PASSWORD=
VANDAR_BUSINESS_SLUG=
VANDAR_API_KEY=

VANDAR_MOBILE and VANDAR_PASSWORD are your login credentials to Vandar dashboard, the VANDAR_BUSINESS_SLUG is set by you when you add a business in Vandar and VANDAR_API_KEY is obtained through your business dashboard.

Usage

Currently, Vandar Cashier supports three of Vandar services: IPG, Direct Debit, and Settlement. IPG is the more common method used which provides you with a link that the user can use to pay for a service. The direct debit service works by requesting access from a user's bank account and withdrawing from their accounts periodically without a need for user interaction.

IPG

Independent

if you're creating a donation form, or you don't really need a logged-in user to make payments, you will need two paths. The first path is going to be initiating the payment and sending it to payment gateway. The second path (also known as callback url) will verify the transaction once your user has returned.

use Vandar\Cashier\Models\Payment;
Route::get('/initiate-payment', function(Request $request) {
    // Amounts are in IRR
    // For more values, see Payment or https://vandarpay.github.io/docs/ipg/#step-1
    $payment = Payment::create(['amount' => 10000]);
    return redirect($payment->url);
});

User-Dependent

In a user-dependant scenario, we are assuming that anyone making a payment is already logged-in to your system, therefore, you can create a payment link for them to redirect them to through their user model:

Route::get('/initiate-payment', function(Request $request){
    $user = auth()->user(); // Added as a separate variable for clarity
    // Amounts are in IRR
    // For more values, see Payment or https://vandarpay.github.io/docs/ipg/#step-1
    $payment = $user->payments()->create(['amount' => 10000]);
    return redirect($payment->url); // See documentation for info on payload and callback
});

Callback URL

Once the transaction finishes (successfully or not), they will be redirect back to the path you defined in callback, you may define a controller or a route to verify the payment using the Payment::verify($request) method:

use Vandar\Cashier\Models\Payment;
Route::get('/callback', function(Request $request){
    if(Payment::verifyFromRequest($request)){
        return 'Success!';
    } 
    else {
        return 'Failed!';
    }
});

The verify method automatically updates the transaction status in your database.

Also, for IPG, you're going to need to define a callback url for when users are returning from Vandar to your application, you can either set the VANDAR_CALLBACK_URL environment variable or modify config/vandar.php. You will also need to add the callback URL in your Business Dashboard in Vandar or otherwise it will lead into an error.

Direct-Debit

When setting up direct-debit, you have two main steps to take.

  1. Get user to allow for access to their account (also known as a Mandate)
  2. Request a withdrawal from a user's account

Mandate

A mandate is basically a permission that a customer gives us to access their accounts. in Vandar, a customer is defined by their phone number and that's considered the primary key when it comes to customers. if you're planning to use subscription services in your project, you will need a mobile_number column in your users table. This code can be used as a migration that will add such a column:

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class AddMobileNumbersColumnToUsersTable extends Migration
{
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('mobile_number')->nullable();
        });
    }
    
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
           $table->dropColumn('mobile_number');
        });
    }
}

You may also pass the mobile_number key in the array passed to authorizeMandate manually.

You can then create a mandate and redirect the user to the bank for authorizing the mandate:

Route::get('/initiate-mandate', function(){
    $user = auth()->user();
    if(! $user->hasValidMandate()){ // You may use the hasValidMandate method if your design requires each user to have only one active mandate
    return redirect($user->authorizeMandate(['bank_code' => '062', 'count' => 3, 'limit' => '10000', 'expiration_date' => '2021-01-01']));
    }
})

You are also going to need a callback url for the user to return to after they're finished with the mandate process, this path should be set as an absolute url through VANDAR_MANDATE_CALLBACK_URL or editing the config file.

You can verify whether the mandate was successfully made and update the mandate accordingly using the Mandate::verifyFromRequest method:

use Vandar\Cashier\Models\Mandate;
Route::get('/mandate-callback', function(Request $request){
    if(Mandate::verifyFromRequest($request)){
        return 'Success!';
    } else {
        return 'Failed!';
    }
})

You can also revoke any mandates through the Mandate model's revoke function:

use Vandar\Cashier\Models\Mandate

$mandate = Mandate::find(1);
$mandate->revoke(); // true if mandate was revoked successfully

Since the only way for a user to cancel a mandate is through your platform, it is standard to provide a way for users to do so in a convenient way.

Withdrawal

Once the mandate has been created successfully, you may create a withdrawal through the mandate:

$user->mandates()->active()->first()->createWithdrawal(['amount' => 10000, 'is_instant' => true, 'description' => 'Subscription renewal', 'max_retry_count' => 16]);

Please note that you may use any method you like to find your current mandate, for example if you have more than one mandate per user, you may use different queries to find that particular mandate.

When creating a new withdrawal, passing authorization_id and notify_url is not necessary as Cashier automatically sets these values.

Note: if not provided, Vandar Cashier automatically sets withdrawal_date to now. (date('Y-m-d'))

if you're not creating an instant withdrawal (is_instant = false) you can also cancel the withdrawal before it is run:

$status = $withdrawal->cancel(); // Returns 'CANCELED' on success, any other status (DONE, PENDING, INIT, FAILED) on failure.

Settlement

Vandar Cashier provides the ability to make requests for settlements:

$settlement = Settlement::create(['amount' => 5000, 'iban' => 'IR000000000000000000000000']) // amount is in Toman

Once a settlement is created successfully, Vandar will queue the settlement and send it to bank. When the settlement is finalized, a notification will be sent to the URL specified in settlement_notify_url in vandar config.

Vandar Cashier provides a route that automatically handles settlement updates and updates your databases accordingly, so you don't need to update the settlement_notify_url unless you need to implement your own solution.

You may also cancel a settlement through the cancel method before it is done, if successful, CANCELED will be returned. if the cancel attempt fails, the last known settlement status is returned from the database:

$settlement->cancel(); // Returns `CANCELED` on success.

Utilities

You may use the Vandar::getBanksHealth() method to get an array containing a list of all banks and whether they're healthy.

Error Handling

When making contact with Vandar APIs, a series of exceptions may be raised due to errors while processing your requests in the APIs. All of these errors can be caught and processed through Vandar\Exceptions\ResponseException exception. This means that all exceptions raised by Cashier have the following methods:

try {
    ...
} catch (\Vandar\Cashier\Exceptions\ResponseException $exception) {
    dump($exception->context()) // Dumps all the information passed into Guzzle, including headers and configuration
    dump($exception->getUrl()) // Dumps the url the request was sent to
    dump($exception->getPayload()) // Dumps the payload that was sent to Vandar APIs
    dump($exception->getResponse()) // Dumps the response object returned by Guzzle
    dump($exception->getResponse()->json()) // Returns an associative array of json response.
    dump($exception->errors()) // Useful especially in InvalidPayloadException, returns the "errors" key in the json response
}

You may also attempt to differentiate between the errors based on the exception that was raised:

  • ExternalAPIException is raised when any 5xx error occurs
  • AuthenticationException is raised when there's an HTTP 401 error, this may only happen if you forgot to set your env or if your information is invalid, if this occurs in any other case, do let us know!
  • DeprecatedAPIException is raised when there's either an HTTP 404, 405 or 410 error, this probably means that the version of Vandar Cashier (and the APIs behind it) used is no longer supported by Vandar, run composer update!
  • InvalidPayloadException is raised when the attempted action was in any way invalid on Vandar's side raising an HTTP 422. (e.g. you're authorized to withdraw 1000 Toman and you attempt to withdraw more), We aim to break this down into more specific exceptions in the future.
  • TooManyRequestsException is raised if you attempt to send a very large sum of requests to Vandar in a short period of time, causing an HTTP 429 error.
  • UnexpectedAPIErrorException is raised when any other 4xx series error not in the scope of Vandar Cashier is returned. if this happens, consider updating Cashier or filing a bug with the full context of the exception you got.

License

All material in this project (unless otherwise noted) are available under the MIT License. See LICENSE for more information.

You might also like...
A Laravel package that allows you to validate your config values and environment.
A Laravel package that allows you to validate your config values and environment.

Table of Contents Overview Installation Requirements Install the Package Publishing the Default Rulesets Usage Creating a Validation Ruleset Using the

This package allows you to easily track your laravel jobs!
This package allows you to easily track your laravel jobs!

Trackable Jobs For Laravel This package allows you to track your laravel jobs! Using this package, you can easily persist the output and the status of

This package provides a Logs page that allows you to view your Laravel log files in a simple UI
This package provides a Logs page that allows you to view your Laravel log files in a simple UI

A simplistics log viewer for your Filament apps. This package provides a Logs page that allows you to view your Laravel log files in a simple UI. Inst

This package allows you to easily work with NanoID in your Laravel models.
This package allows you to easily work with NanoID in your Laravel models.

Laravel Model UUIDs Introduction Huge thanks to Micheal Dyrynda, whose work inspired me to create this package based on laravel-model-nanoid but uses

Filament Plugin to help implement Cloudflare turnstile into your forms.
Filament Plugin to help implement Cloudflare turnstile into your forms.

Filament Turnstile Filament Turnstile, is a plugin to help you implement the Cloudflare turnstile. This plugin uses Laravel Turnstile Behind the scene

This Laravel Nova package allows you to manage media and media fields
This Laravel Nova package allows you to manage media and media fields

Nova Media Hub This Laravel Nova package allows you to manage media and media fields. Requirements php: =8.0 laravel/nova: ^4.0 Features Media Hub UI

Laminas\Console is a component to design and implement console applications in PHP.

laminas-console This package is abandoned and will receive no further development! We recommend using laminas/laminas-cli. Laminas\Console is a compon

A Laravel chat package. You can use this package to create a chat/messaging Laravel application.
A Laravel chat package. You can use this package to create a chat/messaging Laravel application.

Chat Create a Chat application for your multiple Models Table of Contents Click to expand Introduction Installation Usage Adding the ability to partic

Save Model is a Laravel package that allows you to save data in the database in a new way.

Save Model is a Laravel package that allows you to save data in the database in a new way. No need to worry about $guarded and $fillable properties in the model anymore. Just relax an use Save Model package.

Comments
  • v1.0.4

    v1.0.4

    • [FIX] datetimes are now correctly sent on expiration_date and withdrawal_date in Direct Debit services
    • [CHORE] internal direct debit APIs have been upgraded to version 3 as according to Vandar's latest updates
    opened by WiGeeky 0
  • IPG Event Listener

    IPG Event Listener

    The following changes have been made:

    1. Add events and stub listeners for Payment, Mandate and Withdrawal
    2. Migrate the IPG initialization step from VandarIPGController to SendPaymentCreateRequest listener
    3. Fix PaymentFactory issue not generating the correct data
    4. Fix EventListenerProvider not booting properly issue
    5. Make user_id optional in all Vandar tables (further refactor coming soon)
    opened by WiGeeky 0
  • Investiage removal of `is_active` in vandar_mandates

    Investiage removal of `is_active` in vandar_mandates

    Since we have different status fields in the process of creating, activating, and deleting mandates, along with an "active" scope that runs a query on the database, the use of "is_active" in Cashier seems unnecessary.

    • [ ] Investigate the usage of the is_active field
    • [ ] Make sure there's a solid scenario for deletion of Mandates
    opened by WiGeeky 0
  • Mandate Active Scope Needs To Avoid Withdrawal Limit

    Mandate Active Scope Needs To Avoid Withdrawal Limit

    When a mandate reaches the maximum amount or frequency of withdrawal, the mandate should automatically stop showing as active when using the active scope. (e.g a mandate with only 1 withdrawal per month shouldn't be found in Mandate::active() after its first pending or successful withdrawal)

    opened by WiGeeky 0
Releases(v1.0.5)
  • v1.0.5(Dec 10, 2022)

  • v1.0.4(Nov 14, 2021)

    In the latest release of Vandar Cashier, we have fixed our previous bugs and upgraded the internal API for direct debit to version 3.

    What's Changed

    • [FIX] datetimes are now parsed and sent correctly to Vandar APIs
    • [CHORE] Internal Direct Debit APIs have been upgraded to version 3

    Full Changelog: https://github.com/vandarpay/cashier/compare/v1.0.3...v1.0.4

    Source code(tar.gz)
    Source code(zip)
  • v1.0.3(Nov 8, 2021)

  • v1.0.2(Oct 31, 2021)

    What's Changed

    • documentation: added documentation for error handling
    • fix: updating non-init mandate is no longer allowed
    • fix: initialized-only mandates can now be revoked without any interactions with Vandar
    • fix: attempting to revoke an inactive mandate doesn't cause an error anymore
    • refactor: legacy controller classes have been removed

    Full Changelog: https://github.com/vandarpay/cashier/compare/v1.0.1...v1.0.2

    Source code(tar.gz)
    Source code(zip)
  • v1.0.1(Oct 31, 2021)

    What's Changed

    • fix: add ability to revoke initialized-only mandate by @WiGeeky in https://github.com/vandarpay/cashier/pull/16

    Full Changelog: https://github.com/vandarpay/cashier/compare/v1.0.0...v1.0.1

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0(Oct 31, 2021)

    This is Vandar Cashier's first stable release. All documentation has been tested several times and is known to work quite well. Further technical and more user-friendly documentation will be coming soon!

    • Added ability to create user dependant and independent IPG
    • Added full implementation of Vandar Direct Debit services
    • Added basic technical documentation on README

    The project has been thoroughly tested and is known to work correctly, further found bugs will be fixed in minor revisions, for best results, set your requirement on composer.json to ^1.0.

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0-beta.6(Oct 27, 2021)

  • v1.0.0-beta.5(Oct 19, 2021)

  • v1.0.0-beta.4(Oct 19, 2021)

  • v1.0.0-beta.3(Oct 19, 2021)

  • v1.0.0-beta.2(Oct 19, 2021)

    What's Changed

    • Documentation update & fixes for reported issues by @WiGeeky in https://github.com/vandarpay/cashier/pull/15

    Full Changelog: https://github.com/vandarpay/cashier/compare/v1.0.0-beta.1...v1.0.0-beta.2

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0-beta.1(Oct 16, 2021)

  • v1.0.0-beta(Oct 16, 2021)

List of 77 languages for Laravel Framework 4, 5, 6, 7 and 8, Laravel Jetstream , Laravel Fortify, Laravel Breeze, Laravel Cashier, Laravel Nova and Laravel Spark.

Laravel Lang In this repository, you can find the lang files for the Laravel Framework 4/5/6/7/8, Laravel Jetstream , Laravel Fortify, Laravel Cashier

Laravel Lang 6.9k Jan 2, 2023
laravel package help you to implement geographical calculation, with several algorithms that help you deal with coordinates and distances.

Geographical Calculator Geographical Calculator was developed for laravel 5.8+ to help you to implement geographical calculation, with With several al

karam mustafa 342 Dec 31, 2022
Laravel Cashier provides an expressive, fluent interface to Stripe's subscription billing services.

Introduction Laravel Cashier provides an expressive, fluent interface to Stripe's subscription billing services. It handles almost all of the boilerpl

The Laravel Framework 2.2k Jan 4, 2023
Laravel Cashier Paddle provides an expressive, fluent interface to Paddle's subscription billing services.

Introduction Laravel Cashier Paddle provides an expressive, fluent interface to Paddle's subscription billing services. It handles almost all of the b

The Laravel Framework 189 Jan 5, 2023
Thunder is an advanced Laravel tool to track user consumption using Cashier's Metered Billing for Stripe. ⚡

⚡ Thunder Thunder is an advanced Laravel tool to track user consumption using Cashier's Metered Billing for Stripe. ⚡ ?? Supporting If you are using o

Renoki Co. 10 Nov 21, 2022
Official Mollie integration for Laravel Cashier

Subscription billing with Laravel Cashier for Mollie Laravel Cashier provides an expressive, fluent interface to subscriptions using Mollie's billing

Mollie 80 Dec 31, 2022
Driver for managing cash payments in the Cashier Provider ecosystem

Cash Driver Provider Installation To get the latest version of Cash Driver Provider, simply require the project using Composer: $ composer require cas

Cashier Provider 4 Aug 30, 2022
A Laravel 8 Project Implement with GraphQL With Sanctum APIs Authentications Which utilized in Any Frontend or Any Mobile Application Programs.

A Laravel 8 Project Implement with GraphQL With Sanctum APIs Authentications Which utilized in Any Frontend or Any Mobile Application Programs.

Vikas Ukani 3 Jan 6, 2022
Your users do not always report errors, LaraBug does. LaraBug is a simple to use and implement error tracker built for the Laravel framework.

Your users do not always report errors, LaraBug does. LaraBug is a simple to use and implement error tracker built for the Laravel framework. This rep

LaraBug 197 Dec 9, 2022
A package to implement repository pattern for laravel models

Laravel Model UUID A simple package to use Repository Pattern approach for laravel models . Repository pattern Repositories are classes or components

null 26 Dec 21, 2022