Business-GoCardless

 view release on metacpan or  search on metacpan

t/business/gocardless/pro.t  view on Meta::CPAN

use utf8;
use feature qw/ postderef /;

use Test::Most;
no warnings qw/ experimental::postderef /;
use Test::MockObject;
use Test::Exception;
use JSON;

# soft requirements of Business::GoCardless::Client
# "soft" in that they're not required => 1 but must
# be set in the ENV var if not passed to constructor
$ENV{GOCARDLESS_APP_ID}         = 'foo';
$ENV{GOCARDLESS_WEBHOOK_SECRET} = 'bar';
$ENV{GOCARDLESS_MERCHANT_ID}    = 'baz';

# this makes Business::GoCardless::Exception show a stack
# trace when any error is thrown so i don't have to keep
# wrapping stuff in this test in evals to debug
$ENV{GOCARDLESS_DEV_TESTING} = 1;

use_ok( 'Business::GoCardless::Pro' );
isa_ok(
    my $GoCardless = Business::GoCardless::Pro->new(
        token       => 'MvYX0i6snRh/1PXfPoc6',
    ),
    'Business::GoCardless::Pro'
);

can_ok(
    $GoCardless,
    qw/
        token
        client_details
        client
        bill

        payment
        payments
        subscription
        pre_authorizations
        customer
        customers
        new_bill_url
        new_pre_authorization_url
        new_subscription_url
        confirm_resource
        users
        webhooks
    /,
);

cmp_deeply(
    $GoCardless->client_details,
    { api_version => 2 },
    'client_details'
);
isa_ok( $GoCardless->client,'Business::GoCardless::Client' );

# monkey patching LWP here to make this test work without
# having to actually hit the endpoints or use credentials
no warnings 'redefine';
no warnings 'once';
my $mock = Test::MockObject->new;
$mock->mock( 'is_success',sub { 1 } );
$mock->mock( 'header',sub {} );
*LWP::UserAgent::request = sub { $mock };

test_payment( $GoCardless,$mock );
test_payout( $GoCardless,$mock );
test_pre_authorization( $GoCardless,$mock );
test_subscription( $GoCardless,$mock );
test_user( $GoCardless,$mock );
test_webhook( $GoCardless,$mock );
test_webhooks( $GoCardless,$mock );

done_testing();

sub test_payment {

    my ( $GoCardless,$mock ) = @_;

    $mock->mock(
        'content',
        sub { '{"payments":{' . _payment_json_internal() . '}}' }
    );

    isa_ok(
        my $Payment = $GoCardless->create_payment,
        'Business::GoCardless::Payment',
        '->create_payment',
    );

    $mock->mock( 'content',sub { _redirect_flow_json() } );

    note( "Bill" );
    like(
        my $new_bill_url = $GoCardless->new_bill_url(
            session_token        => 'foo',
            description          => "Test Bill",
            success_redirect_url => "http://localhost:3000/rflow/confirm/bill/100/EUR",
        ),
        qr!http://pay\.gocardless\.dev/flow/RE123!,
        '->new_bill_url returns a url'
    );

    $ENV{GOCARDLESS_DEV_TESTING} = 1;

    my $i = 0;

    $mock->mock(
        'content',
        sub {
            $i++ < 2
                ? _redirect_flow_json()
                : _payment_json()
        }
    );

    cmp_deeply(
        my $Bill = $GoCardless->confirm_resource(

t/business/gocardless/pro.t  view on Meta::CPAN

    $ENV{GOCARDLESS_DEV_TESTING} = 0;

    note( "Webhooks" );

    $mock->mock( 'content',sub { _webhooks_payload() } );

    foreach my $Webhook ( $GoCardless->webhooks ) {
        isa_ok( $Webhook,'Business::GoCardless::Webhook::V2' );
        foreach my $Event ( $Webhook->events->@* ) {
            isa_ok( $Event,'Business::GoCardless::Webhook::Event' );
            foreach my $Resource ( $Event->resources ) {
                isa_ok( $Resource,'Business::GoCardless::Resource' );
                ok( keys $Resource->links->%*,'resource has ->links' );
            }
        }
    }
}

sub _user_json {

    return qq{
  {
"id": "CU123",
    "created_at": "2014-05-08T17:01:06.000Z",
    "email": "user\@example.com",
    "given_name": "Frañk",
    "family_name": "Osbörne",
    "address_line1": "27 Acer Road",
    "address_line2": "Apt 2",
    "address_line3": null,
    "city": "London",
    "region": null,
    "postal_code": "E8 3GX",
    "country_code": "GB",
    "language": "en",
    "swedish_identity_number": null,
    "metadata": {
      "salesforce_id": "ABCD1234"
    }
  } }

}

sub _user_obj {

    return bless( {
  'address_line1' => '27 Acer Road',
  'address_line2' => 'Apt 2',
  'address_line3' => undef,
  'city' => 'London',
  'client' => bless( {
    'api_path' => '',
    'api_version' => 2,
    'base_url' => 'https://api.gocardless.com',
    'token' => 'MvYX0i6snRh/1PXfPoc6',
    'user_agent' => ignore(),
  }, 'Business::GoCardless::Client' ),
  'country_code' => 'GB',
  'created_at' => '2014-05-08T17:01:06.000Z',
  'email' => 'user@example.com',
  'endpoint' => '/customers/%s',
  'family_name' => 'Osbörne',
  'given_name' => 'Frañk',
  'id' => 'CU123',
  'language' => 'en',
  'metadata' => {
    'salesforce_id' => 'ABCD1234'
  },
  'postal_code' => 'E8 3GX',
  'region' => undef,
  'swedish_identity_number' => undef
}, 'Business::GoCardless::Customer' );

}

sub _subscription_json {

    my ( $status ) = @_;

    my $internal = _subscription_json_internal( $status );

    return qq!{
  "subscriptions": {
    $internal
  }
}!;

}

sub _subscription_json_internal {
    my ( $status ) = @_;

    $status //= 'active';

    return qq!
    "id": "SB123",
    "created_at": "2014-10-20T17:01:06.000Z",
    "amount": 2500,
    "currency": "GBP",
    "status": "$status",
    "name": "Monthly Magaziné",
    "start_date": "2014-11-03",
    "end_date": null,
    "interval": 1,
    "interval_unit": "monthly",
    "day_of_month": 1,
    "month": null,
    "payment_reference": null,
    "upcoming_payments": [
      { "charge_date": "2014-11-03", "amount": 2500 },
      { "charge_date": "2014-12-01", "amount": 2500 },
      { "charge_date": "2015-01-02", "amount": 2500 },
      { "charge_date": "2015-02-02", "amount": 2500 },
      { "charge_date": "2015-03-02", "amount": 2500 },
      { "charge_date": "2015-04-01", "amount": 2500 },
      { "charge_date": "2015-05-01", "amount": 2500 },
      { "charge_date": "2015-06-01", "amount": 2500 },
      { "charge_date": "2015-07-01", "amount": 2500 },
      { "charge_date": "2015-08-03", "amount": 2500 }
    ],
    "metadata": {
      "order_no": "ABCD1234"
    },
    "links": {
      "mandate": "MA123"
    }
!;

}

sub _subscription_obj {

    my ( $status ) = @_;

    $status //= 'active';

return bless( {
  'amount' => 2500,
  'client' => bless( {
    'api_path' => '',
    'api_version' => 2,
    'base_url' => 'https://api.gocardless.com',
    'token' => 'MvYX0i6snRh/1PXfPoc6',
    'user_agent' => ignore(),
  }, 'Business::GoCardless::Client' ),
  'created_at' => '2014-10-20T17:01:06.000Z',
  'currency' => 'GBP',
  'day_of_month' => 1,
  'end_date' => undef,
  'endpoint' => '/subscriptions/%s',
  'id' => 'SB123',
  'interval' => 1,
  'interval_unit' => 'monthly',
  'links' => {
    'mandate' => 'MA123'
  },
  'metadata' => {
    'order_no' => 'ABCD1234'
  },
  'month' => undef,
  'name' => 'Monthly Magaziné',
  'payment_reference' => undef,
  'start_date' => '2014-11-03',
  'status' => $status,
  'upcoming_payments' => [
    {
      'amount' => 2500,
      'charge_date' => '2014-11-03'
    },
    {
      'amount' => 2500,
      'charge_date' => '2014-12-01'
    },
    {
      'amount' => 2500,
      'charge_date' => '2015-01-02'
    },
    {
      'amount' => 2500,
      'charge_date' => '2015-02-02'
    },
    {
      'amount' => 2500,
      'charge_date' => '2015-03-02'
    },
    {
      'amount' => 2500,
      'charge_date' => '2015-04-01'
    },
    {
      'amount' => 2500,
      'charge_date' => '2015-05-01'
    },
    {
      'amount' => 2500,
      'charge_date' => '2015-06-01'
    },
    {
      'amount' => 2500,
      'charge_date' => '2015-07-01'
    },
    {
      'amount' => 2500,
      'charge_date' => '2015-08-03'
    }
  ]
}, 'Business::GoCardless::Subscription' );

}

sub _redirect_flow_obj {

    my ( $status ) = @_;

    $status //= 'active';

    return 
bless( {
  'client' => bless( {
    'api_path' => '',
    'api_version' => 2,
    'base_url' => 'https://api.gocardless.com',
    'token' => 'MvYX0i6snRh/1PXfPoc6',
    'user_agent' => ignore(),
  }, 'Business::GoCardless::Client' ),
  'created_at' => '2014-10-22T13:10:06.000Z',
  'description' => 'Winé boxes',
  'endpoint' => '/redirect_flows/%s',
  'id' => 'RE123',
  'links' => {
    'creditor' => 'CR123',
    'mandate' => 'MD123'
  },
  'redirect_url' => 'http://pay.gocardless.dev/flow/RE123',
  'scheme' => undef,
  'session_token' => 'SESS_wSs0uGYMISxzqOBq',
  'success_redirect_url' => 'https://example.com/pay/confirm'
}, 'Business::GoCardless::RedirectFlow' );

}

sub _mandate_obj {

    my ( $status ) = @_;

    $status //= 'active';

    return 
bless( {
  'client' => bless( {
    'api_path' => '',
    'api_version' => 2,
    'base_url' => 'https://api.gocardless.com',
    'token' => 'MvYX0i6snRh/1PXfPoc6',
    'user_agent' => ignore(),
  }, 'Business::GoCardless::Client' ),
  'endpoint' => '/mandates/%s',
    "id" => "MD000660000000",
    "created_at" => "2017-09-12T20:37:07.787Z",
    "reference" => "MAND-RZ000S",
    "status" => "active",
    "scheme" => "bacs",
    "next_possible_charge_date" => "2017-09-27",
    "payments_require_approval" => JSON::false,
    "metadata" => {},
    "links" => {
        "customer_bank_account" => "BA00060000000W",
        "creditor" => "CR000020000008",
        "customer" => "CU0006J00000TV"
    }
}, 'Business::GoCardless::Mandate' );

}

sub _pre_auth_json {

    my ( $status ) = @_;

    $status //= 'active';

    return qq{
{
  "currency": "GBP",
  "created_at": "2014-08-20T21:41:25Z",
  "expires_at": "2016-08-20T21:41:25Z",
  "id": "1234ABCD",
  "name": "Computer support invoicés",
  "description": "GoCardless magaziné",
  "max_amount": "750.00",
  "setup_fee": "10.00",
  "remaining_amount": "750.00",
  "interval_unit": "month",
  "interval_length": "1",
  "status": "$status",
  "sub_resource_uris": {
    "bills": "https://sandbox.gocardless.com/api/v1/merchants/0HMARBD8H1/bills?source_id=0PWCDRPCWN"
  },
  "next_interval_start": "2014-09-20T00:00:00Z",
  "merchant_id": "06Z06JWQW1",
  "user_id": "FIVWCCVEST6S4D",
  "uri": "https://gocardless.com/api/v1/pre-authorisations/1234ABCD"
} }

}

sub _payout_json {

    return qq!
{
    "id": "PO123",
    "amount": 1000,
    "arrival_date": "2014-06-27",
    "deducted_fees": 10,
    "currency": "GBP",
    "created_at": "2014-06-20T13:23:34.000Z",
    "payout_type": "merchant",
    "reference": "ref-1",
    "status": "pending",
    "fx": {
      "fx_currency": "EUR",
      "fx_amount": null,
      "exchange_rate": null,
      "estimated_exchange_rate": "1.11667"
    },
    "tax_currency": "GBP",
    "metadata":{ "key": "value" },
    "links": {
      "creditor_bank_account": "BA123",
      "creditor": "CR123"
    }
}
!;

}

sub _payouts_json {

    my $payout = _payout_json();
    return qq!{ "payouts": [ $payout ] }!;
}

sub _payout_obj {

    return bless( {
  'amount' => 1000,
  'arrival_date' => '2014-06-27',
  'client' => bless( {
    'api_path' => '',
    'api_version' => 2,
    'base_url' => 'https://api.gocardless.com',
    'token' => 'MvYX0i6snRh/1PXfPoc6',
    'user_agent' => ignore(),
  }, 'Business::GoCardless::Client' ),
  'created_at' => '2014-06-20T13:23:34.000Z',
  'currency' => 'GBP',
  'deducted_fees' => 10,
  'endpoint' => '/payouts/%s',
  'fx' => {
    'estimated_exchange_rate' => '1.11667',
    'exchange_rate' => undef,
    'fx_amount' => undef,
    'fx_currency' => 'EUR'
  },
  'id' => 'PO123',
  'links' => {
    'creditor' => 'CR123',
    'creditor_bank_account' => 'BA123'
  },
  'metadata' => {
    'key' => 'value'
  },
  'payout_type' => 'merchant',
  'reference' => 'ref-1',
  'status' => 'pending',
  'tax_currency' => 'GBP'

   }, 'Business::GoCardless::Payout' );
}

sub _merchant_json {

    return qq!{
  "id":"06Z06JWQW1",
  "name":"Company Ltd",
  "description":"Wé do stuff.",
  "created_at":"2014-01-22T10:27:42Z",
  "first_name":"Lee",
  "last_name":"Johnson",
  "email":"lee\@foo.com",
  "uri":"https://sandbox.gocardless.com/api/v1/merchants/06Z06JWQW1",
  "balance":"0.0",
  "pending_balance":"0.0",
  "next_payout_date":null,
  "next_payout_amount":null,
  "hide_variable_amount":false,
  "sub_resource_uris":{
    "users":"https://sandbox.gocardless.com/api/v1/merchants/06Z06JWQW1/users",
    "bills":"https://sandbox.gocardless.com/api/v1/merchants/06Z06JWQW1/bills",
    "pre_authorizations":"https://sandbox.gocardless.com/api/v1/merchants/06Z06JWQW1/pre_authorizations",
    "subscriptions":"https://sandbox.gocardless.com/api/v1/merchants/06Z06JWQW1/subscriptions",
    "payouts":"https://sandbox.gocardless.com/api/v1/merchants/06Z06JWQW1/payouts"
  },
  "gbp_balance":"0.0",
  "eur_balance":"0.0",
  "gbp_pending_balance":"0.0",
  "eur_pending_balance":"0.0"
 }!;
}

sub _merchant_obj {

    return bless(
        {
            'balance' => '0.0',
            'client' => ignore(),
            'created_at'           => '2014-01-22T10:27:42Z',
            'description'          => 'Wé do stuff.',
            'email'                => 'lee@foo.com',
            'endpoint'             => '/merchants/%s',
            'eur_balance'          => '0.0',
            'eur_pending_balance'  => '0.0',
            'first_name'           => 'Lee',
            'gbp_balance'          => '0.0',
            'gbp_pending_balance'  => '0.0',
            'hide_variable_amount' => JSON::false,
            'id'                   => '06Z06JWQW1',
            'last_name'            => 'Johnson',
            'name'                 => 'Company Ltd',
            'next_payout_amount'   => undef,
            'next_payout_date'     => undef,
            'pending_balance'      => '0.0',
            'sub_resource_uris'    => {
                'bills'   => 'https://sandbox.gocardless.com/api/v1/merchants/06Z06JWQW1/bills',
                'payouts' => 'https://sandbox.gocardless.com/api/v1/merchants/06Z06JWQW1/payouts',
                'pre_authorizations' =>
                    'https://sandbox.gocardless.com/api/v1/merchants/06Z06JWQW1/pre_authorizations',
                'subscriptions' =>
                    'https://sandbox.gocardless.com/api/v1/merchants/06Z06JWQW1/subscriptions',
                'users' => 'https://sandbox.gocardless.com/api/v1/merchants/06Z06JWQW1/users'
            },
            'uri' => 'https://sandbox.gocardless.com/api/v1/merchants/06Z06JWQW1'
        },
        'Business::GoCardless::Merchant'
        );
}

sub _payment_json {

    my ( $status,$amount ) = @_;

    my $internal = _payment_json_internal( $status,$amount );

return qq!{
  "payments": {
    $internal
  }
  }!;
}

sub _payment_json_internal {

    my ( $status,$amount ) = @_;

    $status //= 'pending_submission';
    $amount //= '44.0';

return qq!
    "id": "PM123",
    "created_at": "2014-05-08T17:01:06.000Z",
    "charge_date": "2014-05-15",
    "amount": $amount,
    "description": "Stuff and Thiñgs",
    "currency": "GBP",
    "status": "$status",
    "reference": "WINEBOX001",
    "metadata": {
      "order_dispatch_date": "2014-05-22"
    },
    "amount_refunded": 0,
    "links": {
      "mandate": "MD123",
      "creditor": "CR123"
    }
!;

}

sub _payment_obj {

    my ( $status ) = @_;

    $status //= 'pending_submission';

    return bless({
        'client'          => ignore(),
        "id"              => "PM123",
        "created_at"      => "2014-05-08T17:01:06.000Z",
        "charge_date"     => "2014-05-15",
        "amount"          => 44.0,
        "amount_refunded" => 0,
        "description"     => "Stuff and Thiñgs",
        "currency"        => "GBP",
        "status"          => $status,
        "reference"       => "WINEBOX001",
        "metadata"        => {
          "order_dispatch_date" => "2014-05-22"
        },
        "links" => {
          "mandate"  => "MD123",
          "creditor" => "CR123",
        },
        'endpoint' => '/payments/%s',
    },'Business::GoCardless::Payment'
    );
}

sub _webhook_payload {

    my ( $signature ) = @_;

    $signature //= '07525beb4617490b433bd9036b97e856cefb041a6401e4f18b228345d34f5fc5';

    return qq!{
  "events": [
    {
      "id": "EV123",
      "created_at": "2014-08-04T12:00:00.000Z",
      "action": "paid",
      "resource_type": "payouts",
      "links": {
        "payout": "PO123"
      }
    }
  ]
}!;
}

sub _redirect_flow_json {

    return qq!{
          "redirect_flows": {
            "id": "RE123",
            "description": "Winé boxes",
            "session_token": "SESS_wSs0uGYMISxzqOBq",
            "scheme": null,
            "success_redirect_url": "https://example.com/pay/confirm",
            "redirect_url": "http://pay.gocardless.dev/flow/RE123",
            "created_at": "2014-10-22T13:10:06.000Z",
            "links": {
              "mandate": "MD123",
              "creditor": "CR123"
            }
          }
        }!;
}

sub _mandate_json {
    return qq!{
        "mandates":{
            "id":"MD000660000000",
            "created_at":"2017-09-12T20:37:07.787Z",
            "reference":"MAND-RZ000S",
            "status":"active",
            "scheme":"bacs",
            "next_possible_charge_date":"2017-09-27",
            "payments_require_approval":false,
            "metadata":{},
            "links":{
                "customer_bank_account":"BA00060000000W",
                "creditor":"CR000020000008",
                "customer":"CU0006J00000TV"
            }



( run in 1.110 second using v1.01-cache-2.11-cpan-a49fcb8fa48 )