File Coverage

blib/lib/Catalyst/Model/CPI.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package Catalyst::Model::CPI;
2             # ABSTRACT: Business::CPI models for Catalyst
3 1     1   1716 use Moose;
  0            
  0            
4             use Module::Pluggable (
5             search_path => [ 'Business::CPI::Gateway' ],
6             except => [
7             'Business::CPI::Gateway::Base',
8             'Business::CPI::Gateway::Test',
9             ],
10             sub_name => 'available_gateways',
11             require => 1,
12             );
13             use Moo::Role ();
14              
15             extends 'Catalyst::Model';
16              
17             our $VERSION = '0.03'; # VERSION
18              
19             has _config_for_gateway => (
20             isa => 'HashRef',
21             is => 'ro',
22             default => sub { +{} },
23             traits => ['Hash'],
24             handles => {
25             _get_config_for_gateway => 'get',
26             },
27             );
28              
29             has _req => ( is => 'rw' );
30             has _log => ( is => 'rw' );
31              
32             around BUILDARGS => sub {
33             my $orig = shift;
34             my $self = shift;
35              
36             my $args = $self->$orig(@_);
37              
38             $args->{_config_for_gateway} = delete $args->{gateway};
39              
40             return $args;
41             };
42              
43             before COMPONENT => sub {
44             my ($self, $ctx) = @_;
45              
46             for ($self->available_gateways) {
47             if ($_->isa('Business::CPI::Gateway::Base') && $_->can('notify')) {
48             Moo::Role->apply_roles_to_package(
49             $_, 'Business::CPI::Role::Request'
50             );
51             }
52             }
53             };
54              
55             sub ACCEPT_CONTEXT {
56             my ($self, $ctx) = @_;
57              
58             $self->_req($ctx->req);
59             $self->_log($ctx->log);
60              
61             return $self;
62             }
63              
64             sub get {
65             my ($self, $name) = @_;
66              
67             if (!$self->exists($name)) {
68             local $" = ", ";
69             my @plugins = $self->available_gateways;
70             die "Can't get gateway $name. Available gateways are @plugins";
71             }
72              
73             my $fullname = "Business::CPI::Gateway::$name";
74              
75             my %args = %{ $self->_get_config_for_gateway($name) };
76             $args{req} = $self->_req;
77             $args{log} = $self->_log;
78              
79             return $fullname->new(%args);
80             }
81              
82             sub exists {
83             my ($self, $name) = @_;
84              
85             my $fullname = "Business::CPI::Gateway::$name";
86              
87             for ($self->available_gateways) {
88             return 1 if $_ eq $fullname;
89             }
90              
91             return 0;
92             }
93              
94              
95             package # hide from PAUSE
96             Business::CPI::Role::Request;
97             use Moo::Role;
98              
99             has req => ( is => 'ro' );
100              
101             around notify => sub {
102             my $orig = shift;
103             my $self = shift;
104              
105             if (scalar @_) {
106             die "You are using Business::CPI from Catalyst.\n" .
107             "You don't have to pass the request!\n";
108             }
109              
110             return $self->$orig($self->req);
111             };
112              
113             1;
114              
115             __END__
116              
117             =pod
118              
119             =encoding utf-8
120              
121             =head1 NAME
122              
123             Catalyst::Model::CPI - Business::CPI models for Catalyst
124              
125             =head1 VERSION
126              
127             version 0.03
128              
129             =head1 SYNOPSIS
130              
131             In the config:
132              
133             <model Payments>
134             <gateway PayPal>
135             api_username ...
136             api_password ...
137             signature ...
138             receiver_email seller@test.com
139             sandbox 1
140             </gateway>
141              
142             <gateway X> ... </gateway>
143              
144             <gateway Y> ... </gateway>
145             </model>
146              
147             In the controller:
148              
149             # It should be configured in PayPal's IPN, for example, the notify_url as:
150             # http://myserver/api/store/notification/PayPal
151             # Other gateways are similar.
152             sub gtw_notification : Chained('/api/store') PathPart('notification') Args(1) {
153             my ($self, $ctx, $gateway_name) = @_;
154              
155             my $model = $ctx->model('Payments');
156              
157             if ( !$model->exists($gateway_name) ) {
158             my $gtw_list = join ", ", $model->available_gateways;
159             die "$gateway_name is not available.\n"
160             . "Available gateways are: $gtw_list.";
161             }
162              
163             my $notification = $model->get($gateway_name)->notify;
164              
165             my $purchase = $ctx->model('DB::Purchase')->find( $notification->{payment_id} );
166             $purchase->update({ payment_status => $notification->{status} });
167              
168             ...
169             }
170              
171             sub checkout : Chained('/website/cart') PathPart Args(0) {
172             my ($self, $ctx) = @_;
173              
174             my $model = $ctx->model('Payments');
175             my $cart = $ctx->session->{cart};
176              
177             # create a form for each available gateway
178             my @forms = map {
179             $model->get($_)->new_cart($cart)->get_form_to_pay("${_}_form")
180             } $model->available_gateways;
181              
182             $ctx->stash->{checkout_forms} = \@forms;
183             }
184              
185             =head1 DESCRIPTION
186              
187             This module connects CPI gateways to a Catalyst application. It automatically
188             loads the configuration from Catalyst and uses it to instantiate the gateways
189             when requested through this model.
190              
191             =head1 METHODS
192              
193             =head2 available_gateways
194              
195             List all the class names for the installed CPI gateways.
196              
197             my @gateways = $ctx->model('Payments')->available_gateways;
198              
199             =head2 get
200              
201             Returns a new instance of the gateway, with all the configuration passed as
202             arguments to the constructor.
203              
204             my $cart = $ctx->model('Payments')->get('PayPal')->new_cart(...);
205              
206             =head2 exists
207              
208             Check whether the provided gateway is really installed.
209              
210             if ($model->exists($gateway)) {
211             ...
212             }
213              
214             =head2 ACCEPT_CONTEXT
215              
216             Saves the request, so that C<< $gateway->notify >> can receive it
217             automatically. See the L<Catalyst docs|Catalyst::Component/ACCEPT_CONTEXT> for
218             details.
219              
220             =head1 CONFIGURATION
221              
222             <model Payments>
223             <gateway PayPal>
224             api_username ...
225             api_password ...
226             signature ...
227             receiver_email seller@test.com
228             sandbox 1
229             </gateway>
230              
231             <gateway PagSeguro>
232             receiver_email seller@test.com
233             ...
234             </gateway>
235              
236             <gateway Custom>
237             foo bar
238             </gateway>
239             </model>
240              
241             =head1 AUTHOR
242              
243             André Walker <andre@andrewalker.net>
244              
245             =head1 COPYRIGHT AND LICENSE
246              
247             This software is copyright (c) 2013 by André Walker.
248              
249             This is free software; you can redistribute it and/or modify it under
250             the same terms as the Perl 5 programming language system itself.
251              
252             =cut