No description
- Perl 90.1%
- Raku 9.9%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| lib/Mojolicious/Plugin | ||
| t | ||
| .gitignore | ||
| .ship.conf | ||
| Changes | ||
| cpanfile | ||
| MANIFEST.SKIP | ||
| README.pod | ||
package Mojolicious::Plugin::StripePayment;
=head1 NAME
Mojolicious::Plugin::StripePayment - Make payments using Stripe
=head1 VERSION
0.01
=head1 DESCRIPTION
L<Mojolicious::Plugin::StripePayment> is a plugin for the L<Mojolicious> web
framework which allow you to do payments using L<https://stripe.com|Stripe>.
This module is EXPERIMENTAL. The API can change at any time. Let me know
if you are using it.
=head1 SYNOPSIS
use Mojolicious::Lite;
plugin StripePayment => {
api_key => 'sk_test_xyDZFd5OeA8ioFQ8HbBlJQaz',
pub_key => '...',
};
# make a payment
post '/checkout' => sub {
my $self = shift->render_later;
my %payment = (
amount => scalar $self->param('amount'),
card => scalar $self->param('stripeToken'),
description => 'Cool item',
metadata => {},
receipt_email => '...',
);
Mojo::IOLoop->delay(
sub {
my ($delay) = @_;
$self->stripe->charge(\%payment, $delay->begin);
},
sub {
my ($delay, $res) = @_;
return $self->redirect_to('receipt') if $res->code == 200;
return $self->render(error => $res->json->{failure_message});
},
);
};
=head2 Self contained
use Mojolicious::Lite;
plugin StripePayment => {
pub_key => '...',
api_key => \ "dummy",
};
Setting C<api_key> to a reference will enable this plugin to work without
a working Stripe backend. This is done by replicating the behavior of Stripe. This
is especially useful when writing unit tests.
The following routes will be added to your application to mimic Stripe:
=over 4
=item * TODO
TODO
=back
=cut
use Mojo::Base 'Mojolicious::Plugin';
use Mojo::UserAgent;
use constant DEBUG => $ENV{MOJO_STRIPE_DEBUG} || 0;
our $VERSION = '0.01';
=head1 ATTRIBUTES
=head2 api_key
$str = $self->api_key;
The value for the private API key, can be found in the Stripe admin gui.
=head2 base_url
$str = $self->base_url;
This is the location to Stripe payment solution. Will be set to
L<https://api.stripe.com/v1>.
=head2 currency_code
$str = $self->currency_code;
The currency code, following ISO 4217. Default is "USD".
=head2 pub_key
$str = $self->pub_key;
The value for the public key, can be found in the Stripe admin gui.
=cut
has api_key => 'sk_test_BQokikJOvBiI2HlWgH4olfQ2';
has base_url => 'https://api.stripe.com/v1';
has currency_code => 'USD';
has pub_key => 'dummy_pub_key';
has _ua => sub { Mojo::UserAgent->new; };
=head1 HELPERS
=head2 stripe->charge
$c->stripe->charge(\%args, sub { my ($c, $res) = @_; });
C<$res> is a L<Mojo::Message::Response> object, where you can get the
L<charge object|https://stripe.com/docs/api/curl#charge_object> or test
the status code:
$data = $res->json;
$code = $res->code;
=head1 METHODS
=head2 register
$app->plugin(StripePayment => \%config);
Called when registering this plugin in the main L<Mojolicious> application.
=cut
sub register {
my ($self, $app, $config) = @_;
# self contained
if (ref $config->{api_key}) {
$self->_add_routes($app);
$self->_ua->server->app($app);
$config->{api_key} = ${$config->{api_key}};
}
# copy config to this object
for (grep { $self->$_ } keys %$config) {
$self->{$_} = $config->{$_};
}
$app->helper('stripe.charge' => sub { $self->_stripe_charge(@_); });
$app->helper('stripe.token' => sub { $self->_stripe_token(@_); });
$app->helper('stripe.pub_key' => sub { shift; $self->pub_key(@_); });
}
sub _add_routes {
my ($self, $app) = @_;
my $r = $app->routes;
$self->base_url('/stripe-payment');
push @{$app->renderer->classes}, __PACKAGE__;
}
sub _error {
my ($self, $err) = @_;
my $res = Mojo::Message::Response->new;
$res->code(400);
$res->param(message => $err);
$res->param(source => __PACKAGE__);
$res;
}
sub _expand {
my ($self, $ns, $args) = @_;
my $data = delete $args->{$ns} or return;
while (my ($k, $v) = each %$data) {
$args->{"$ns\[$k\]"} = $v;
}
}
sub _extract_error {
my ($self, $tx, $e) = @_;
my $res = $tx->res;
my $err;
local $@;
$err = eval { $_[0]->res->dom->Exception->Error->Message->text };
$res->code(500);
$res->param(code => '') unless $res->param('code');
$res->param(message => $err // $e);
$res->param(source => $err ? $self->base_url : __PACKAGE__);
}
sub _stripe_charge {
my ($self, $c, $args, $cb) = @_;
my $url = Mojo::URL->new($self->base_url);
$self->_expand(metadata => $args);
$args->{currency} ||= $self->currency_code;
$url->userinfo($self->api_key . ':');
push @{$url->path->parts}, 'charges';
Mojo::IOLoop->delay(
sub {
my ($delay) = @_;
$self->_ua->post($url, form => $args, $delay->begin);
},
sub {
my ($delay, $tx) = @_;
$c->$cb($tx->res);
},
);
return $c;
}
sub _stripe_token {
my ($self, $c, $args, $cb) = @_;
my $url = Mojo::URL->new($self->base_url);
$self->_expand(card => $args);
$url->userinfo($self->api_key . ':');
push @{$url->path->parts}, 'tokens';
Mojo::IOLoop->delay(
sub {
my ($delay) = @_;
$self->_ua->post($url, form => $args, $delay->begin);
},
sub {
my ($delay, $tx) = @_;
$c->$cb($tx->res);
},
);
return $c;
}
sub _url {
my $url = Mojo::URL->new($_[0]->base_url . $_[1]);
warn "[MOJO_NETS] URL $url\n" if DEBUG;
$url;
}
=head1 ERROR HANDLING
There are some generic error handling in this module: The C<$res> object
passed on to the callbacks will have "source" and "message" set. These can
be retrived using the code below:
$int = $res->code; # will be 500 on exception
$str = $res->param("source");
$str = $res->param("message");
The "source" might have to special values:
=over 4
=item * Same as L</base_url>.
If the "source" is set to the value of L</base_url> then the "message"
will contain an exception from Stripe.
=item * "Mojolicious::Plugin::StripePayment"
If the "source" is set to this package name, then the "message" will be an
exception from parse error.
=back
=head1 SEE ALSO
=over 4
=item * Overview
L<https://stripe.com/docs>
=item * API
L<https://stripe.com/docs/api>
=back
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2014, Jan Henning Thorsen
This program is free software, you can redistribute it and/or modify it under
the terms of the Artistic License version 2.0.
=head1 AUTHOR
Jan Henning Thorsen - C<jhthorsen@cpan.org>
=cut
1;
__DATA__
@@ stripe-payment/TODO.html.ep