File Coverage

blib/lib/WebService/Dwolla.pm
Criterion Covered Total %
statement 36 575 6.2
branch 0 160 0.0
condition 0 190 0.0
subroutine 12 60 20.0
pod 0 42 0.0
total 48 1027 4.6


line stmt bran cond sub pod time code
1             # package: WebService::Dwolla
2             # Perl module to interact with Dwolla's OAuth+REST API
3             package WebService::Dwolla;
4              
5 1     1   23843 use 5.010001;
  1         4  
  1         37  
6 1     1   6 use strict;
  1         2  
  1         32  
7 1     1   6 use warnings;
  1         6  
  1         53  
8              
9             our $VERSION = '0.05';
10              
11 1     1   2703 use LWP::UserAgent;
  1         91770  
  1         43  
12 1     1   1293 use JSON;
  1         17242  
  1         7  
13 1     1   348 use URI::Escape;
  1         5  
  1         106  
14 1     1   1148 use Digest::HMAC;
  1         649  
  1         52  
15 1     1   1369 use IO::File;
  1         11167  
  1         169  
16              
17             use constant {
18 1         5123 API_SERVER => 'https://www.dwolla.com/oauth/rest',
19             AUTH_URL => 'https://www.dwolla.com/oauth/v2/authenticate',
20             TOKEN_URL => 'https://www.dwolla.com/oauth/v2/token',
21             GATEWAY_URL => 'https://www.dwolla.com/payment/request',
22             CHECKOUT_URL => 'https://www.dwolla.com/payment/checkout',
23             MASSPAY_URL => 'https://masspay.dwollalabs.com/api'
24 1     1   9 };
  1         2  
25              
26             # Function: new
27             #
28             # Constructor.
29             #
30             # Parameters:
31             # self - Object instance.
32             # key - API key
33             # secret - API secret
34             # redirect_uri - OAuth redirect URL
35             # permissions - Application permissions
36             # mode - Mode. Default: 'live'
37             # debug_mode - Debug mode. Default: 0 (Off)
38             #
39             # Returns:
40             # Object instance.
41             sub new
42             {
43 0     0 0   my $class = shift;
44 0   0       my $key = shift || undef;
45 0   0       my $secret = shift || undef;
46 0   0       my $redirect_uri = shift || undef;
47 0   0       my $permissions = shift || ['send','transactions','balance','request','contacts','accountinfofull','funding'];
48 0   0       my $mode = shift || 'live';
49 0   0       my $debug_mode = shift || 0;
50              
51 0           my $self = {};
52              
53 0           $self->{'api_key'} = $key;
54 0           $self->{'api_secret'} = $secret;
55 0           $self->{'permissions'} = $permissions;
56 0           $self->{'mode'} = $mode;
57 0           $self->{'errors'} = [];
58 0           $self->{'redirect_uri'} = $redirect_uri;
59 0           $self->{'debug_mode'} = $debug_mode;
60              
61 0           bless($self,$class);
62              
63 0           return $self;
64             }
65              
66             # Function: set_api_config_from_file
67             #
68             # Sets required API information from configuration file.
69             # key=APIKEY
70             # secret=APISECRET
71             # token=OAUTHTOKEN
72             #
73             # Parameters:
74             # self - Object instance.
75             # file - Filename of configuaretion.
76             #
77             # Returns:
78             # true (1) on success and false (0) on failure.
79             sub set_api_config_from_file
80             {
81 0     0 0   my $self = shift;
82 0           my $file = shift;
83              
84 0           my $config = IO::File->new($file,'r');
85              
86 0 0         if (!defined($config)) {
87 0           return 0;
88             }
89              
90 0           while(!$config->eof()) {
91 0           my $line = $config->getline();
92 0           $line =~ s/\n//g;
93              
94 0           my ($key,$value) = split(/\=/,$line);
95              
96 0 0         if ($key eq 'key') {
97 0           $self->{'api_key'} = $value;
98             }
99              
100 0 0         if ($key eq 'secret') {
101 0           $self->{'api_secret'} = $value;
102             }
103              
104 0 0         if ($key eq 'token') {
105 0           $self->{'oauth_token'} = $value;
106             }
107             }
108              
109 0           $config->close();
110             }
111              
112             # Function: get_auth_url
113             #
114             # Gets OAuth URL
115             #
116             # Parameters:
117             # self - Object instance.
118             #
119             # Returns:
120             # OAuth URL
121             sub get_auth_url
122             {
123 0     0 0   my $self = shift;
124              
125 0           my $params = {
126             'client_id' => $self->{'api_key'},
127             'response_type' => 'code',
128 0           'scope' => join('|',@{$self->{'permissions'}})
129             };
130              
131 0 0         if (defined($self->{'redirect_uri'})) {
132 0           $params->{'redirect_uri'} = $self->{'redirect_uri'};
133             }
134              
135 0           my $url = AUTH_URL . '/?' . $self->_http_build_query($params);
136              
137 0           return $url;
138             }
139              
140             # Function: request_token
141             #
142             # Request OAuth token from Dwolla.
143             #
144             # Parameters:
145             # self - Object instance.
146             # code - Temporary code from Dwolla.
147             #
148             # Returns:
149             # OAuth token.
150             sub request_token
151             {
152 0     0 0   my $self = shift;
153 0           my $code = shift;
154              
155 0 0         if (!defined($code)) {
156 0           $self->set_error('Please pass a valid OAuth code.');
157 0           return 0;
158             }
159              
160 0           my $params = {
161             'client_id' => $self->{'api_key'},
162             'client_secret' => $self->{'api_secret'},
163             'redirect_uri' => $self->{'redirect_uri'},
164             'grant_type' => 'authorization_code',
165             'code' => $code
166             };
167              
168 0           my $url = TOKEN_URL . '?' . $self->_http_build_query($params);
169              
170 0           my $response = $self->_api_request($url,'GET');
171              
172 0 0         if ($response->{'error'}) {
173 0           $self->set_error($response->{'error_description'});
174 0           return 0;
175             }
176              
177 0           return $response->{'access_token'};
178             }
179              
180             # Function: set_token
181             #
182             # Manually set OAuth token.
183             #
184             # Parameters:
185             # self - Object instance.
186             # token - Existing OAuth token.
187             #
188             # Returns:
189             # Void
190             sub set_token
191             {
192 0     0 0   my $self = shift;
193 0           my $token = shift;
194              
195 0           $self->{'oauth_token'} = $token;
196             }
197              
198             # Function: set_mode
199             #
200             # Set mode.
201             #
202             # Parameters:
203             # self - Object instance.
204             # mode - Mode ('test' / 'live').
205             #
206             # Returns:
207             # Void or false (0) on error.
208             sub set_mode
209             {
210 0     0 0   my $self = shift;
211 0           my $mode = shift;
212              
213 0 0 0       if ($mode ne 'test' && $mode ne 'live') {
214 0           $self->set_error("Invalid mode. Please use 'test' / 'live'.");
215 0           return 0;
216             }
217              
218 0           $self->{'mode'} = $mode;
219             }
220              
221             # Function: get_mode
222             #
223             # Get mode.
224             #
225             # Parameters:
226             # self - Object instance.
227             #
228             # Returns:
229             # Mode
230             sub get_mode
231             {
232 0     0 0   my $self = shift;
233              
234 0           return $self->{'mode'};
235             }
236              
237             # Function: get_token
238             #
239             # Get current OAuth token.
240             #
241             # Parameters:
242             # self - Object instance.
243             # token - Existing OAuth token.
244             #
245             # Returns:
246             # OAuth token
247             sub get_token
248             {
249 0     0 0   my $self = shift;
250              
251 0           return $self->{'oauth_token'};
252             }
253              
254             # Function: me
255             #
256             # Gets information about user with token.
257             #
258             # Parameters:
259             # self - Object instance.
260             #
261             # Returns:
262             # Anonymous hash of user info.
263             sub me
264             {
265 0     0 0   my $self = shift;
266              
267 0           my $response = $self->_get("users");
268            
269 0           return $response;
270             }
271              
272             # Function: get_user
273             #
274             # Gets information about user specified by id.
275             #
276             # Parameters:
277             # self - object instance.
278             # id - user id.
279             #
280             # Returns:
281             # Anonymous hash of user info.
282             sub get_user
283             {
284 0     0 0   my $self = shift;
285 0           my $id = shift;
286              
287 0 0         if (!$self->is_id_valid($id)) {
288             #$self->set_error("Please enter a valid Dwolla Id.");
289             #return 0;
290             }
291              
292 0           my $params = {
293             'client_id' => $self->{'api_key'},
294             'client_secret' => $self->{'api_secret'},
295             };
296              
297 0           my $response = $self->_get("users/$id",$params);
298            
299 0           return $response;
300             }
301              
302             # Function: users_nearby
303             #
304             # Gets list of users given geo-coordinates.
305             #
306             # Parameters:
307             # self - Object instance.
308             # lat - Latitude.
309             # long - Longitude.
310             #
311             # Returns:
312             # An array of anonymous hashes containing user info.
313             sub users_nearby
314             {
315 0     0 0   my $self = shift;
316 0           my $lat = shift;
317 0           my $long = shift;
318              
319 0           my $params = {
320             'client_id' => $self->{'api_key'},
321             'client_secret' => $self->{'api_secret'},
322             'latitude' => $lat,
323             'longitude' => $long
324             };
325              
326 0           my $response = $self->_get("users/nearby",$params);
327            
328 0           return $response;
329             }
330              
331             # Function: register
332             #
333             # Register a new Dwolla account.
334             #
335             # Parameters:
336             # self - Object instance.
337             # email - Email address.
338             # password - Password.
339             # pin - 4-digit Dwolla pin.
340             # first_name - First name.
341             # last_name - Last name.
342             # address - Address line 1.
343             # address2 - Address line 2 (Optional)
344             # city - City.
345             # state - State.
346             # zip - Zipcode.
347             # phone - Phone number.
348             # date_of_birth - Date of birth.
349             # accept_terms - Has the new user accepted the terms?
350             # type - User type ('Personal',Commercial','NonProfit)
351             # organization - Organization.
352             # ein - Employee Identifer Number
353             #
354             # Returns:
355             # Registration response or false (0) for error.
356             sub register
357             {
358 0     0 0   my $self = shift;
359 0           my $email = shift;
360 0           my $password = shift;
361 0           my $pin = shift;
362 0           my $first_name = shift;
363 0           my $last_name = shift;
364 0           my $address = shift;
365 0   0       my $address2 = shift || '';
366 0           my $city = shift;
367 0           my $state = shift;
368 0           my $zip = shift;
369 0           my $phone = shift;
370 0           my $date_of_birth = shift;
371 0   0       my $accept_terms = shift || 0;
372 0   0       my $type = shift || 'Personal';
373 0   0       my $organization = shift || '';
374 0   0       my $ein = shift || undef;
375            
376 0           my $errors = 0;
377              
378 0 0 0       if ($type ne 'Personal' && $type ne 'Commercial' && $type ne 'NonProfit') {
      0        
379 0           $self->set_error("Please enter a valid account type.");
380 0           $errors++;
381             }
382              
383 0 0 0       if (!defined($date_of_birth) || $date_of_birth !~ /^\d{2}\-\d{2}\-\d{4}$/) {
384 0           $self->set_error("Please enter a valid date of birth.");
385 0           $errors++;
386             }
387              
388 0 0         if ($errors) {
389 0           return 0;
390             }
391              
392 0           my $params = {
393             'client_id' => $self->{'api_key'},
394             'client_secret' => $self->{'api_secret'},
395             'email' => $email,
396             'password' => $password,
397             'pin' => $pin,
398             'firstName' => $first_name,
399             'lastName' => $last_name,
400             'address' => $address,
401             'address2' => $address2,
402             'city' => $city,
403             'state' => $state,
404             'zip' => $zip,
405             'phone' => $phone,
406             'dateOfBirth' => $date_of_birth,
407             'type' => $type,
408             'organization' => $organization,
409             'ein' => $ein,
410             'acceptTerms' => $accept_terms
411             };
412              
413 0           my $response = $self->_post("register/",$params,0);
414            
415 0           return $response;
416             }
417              
418             # Function: contacts
419             #
420             # Get a list of contacts.
421             #
422             # Parameters:
423             # self - Object instance.
424             # search - Search term.
425             # types - Account types (e.g Dwolla, Facebook) Default: 'Dwolla'.
426             # limit - Limit results. Default: 10.
427             #
428             # Returns:
429             # Array of contact information.
430             sub contacts
431             {
432 0     0 0   my $self = shift;
433 0           my $search = shift;
434 0   0       my $types = shift || ['Dwolla'];
435 0   0       my $limit = shift || 10;
436              
437 0           my $params = {
438             'search' => $self->{'api_key'},
439 0           'types' => join(',',@{$types}),
440             'limit' => $limit
441             };
442              
443 0           my $response = $self->_get("contacts",$params);
444            
445 0           return $response;
446             }
447              
448             # Function: nearby_contacts
449             #
450             # Gets list of nearby Dwolla spots withing the range of the provided
451             # latitude and longitude.
452             #
453             # Half of the limit are returned as spots with closest proximity. The other
454             # half of the spots are returned as random spots within the range.
455             # This call can return nearby venues on Foursquare but not Dwolla, they will
456             # have an Id of "null"
457             #
458             # Parameters:
459             # self - object instance.
460             # lat - Latitude.
461             # long - Longitude.
462             # range - Range to search (miles).
463             # limit - Limit results to this number.
464             #
465             # Returns:
466             # Array of anonymous hashes containing contacts.
467             sub nearby_contacts
468             {
469 0     0 0   my $self = shift;
470 0           my $lat = shift;
471 0           my $long = shift;
472 0   0       my $range = shift || 10;
473 0   0       my $limit = shift || 10;
474              
475 0           my $params = {
476             'client_id' => $self->{'api_key'},
477             'client_secret' => $self->{'api_secret'},
478             'latitude' => $lat,
479             'longitude' => $long,
480             'range' => $range,
481             'limit' => $limit
482             };
483              
484 0           my $response = $self->_get("contacts/nearby",$params);
485            
486 0           return $response;
487             }
488              
489             # Function: funding_sources
490             #
491             # Retrieve a list of verified funding sources for the user associated
492             # with the authorized access token.
493             #
494             # Paramters:
495             # self - Object instance.
496             #
497             # Returns:
498             # Array of anonymous hashes containg funding sources.
499             sub funding_sources
500             {
501 0     0 0   my $self = shift;
502              
503 0           my $response = $self->_get("fundingsources");
504            
505 0           return $response;
506             }
507              
508             # Function: funding_source
509             #
510             # Retrieve a funding source given its id.
511             #
512             # Paramters:
513             # self - Object instance.
514             # sourceid - Fund source id.
515             #
516             # Returns:
517             # Anonymous hash containg funding sources.
518             sub funding_source
519             {
520 0     0 0   my $self = shift;
521 0           my $sourceid = shift;
522              
523 0           my $response = $self->_get("fundingsources/$sourceid");
524            
525 0           return $response;
526             }
527              
528             # Function: add_funding_source
529             #
530             # Add a new funding source for the user associated with the
531             # authorized access token.
532             #
533             # Parameters:
534             # self - Object instance.
535             # acctnum - Financial institution account number.
536             # trnnum - Routing number.
537             # accttype - Account type ('checking','savings')
538             # acctname - Name to give account.
539             #
540             # Returns:
541             # Funding sources.
542             sub add_funding_source
543             {
544 0     0 0   my $self = shift;
545 0   0       my $acctnum = shift || undef;
546 0   0       my $trnnum = shift || undef;
547 0   0       my $accttype = shift || undef;
548 0   0       my $acctname = shift || undef;
549              
550 0           my $errors = 0;
551              
552 0 0         if (!defined($acctnum)) {
553 0           $self->set_error('Please supply a valid account number.');
554 0           $errors++;
555             }
556 0 0 0       if (!defined($trnnum) || $trnnum !~ /^[0-9]{9}$/) {
557 0           $self->set_error('Please supply a valid routing number.');
558 0           $errors++;
559             }
560              
561 0 0 0       if (!defined($accttype) || ($accttype ne 'Checking' && $accttype ne 'Savings')) {
      0        
562 0           $self->set_error('Please supply a valid account type.');
563 0           $errors++;
564             }
565              
566 0 0         if (!defined($acctname)) {
567 0           $self->set_error('Please supply a valid account name.');
568 0           $errors++;
569             }
570              
571 0 0         if ($errors) {
572 0           return 0;
573             }
574              
575 0           my $params = {
576             'account_number' => $acctnum,
577             'routing_number' => $trnnum,
578             'account_type' => $accttype,
579             'name' => $acctname
580             };
581              
582 0           my $response = $self->_post("fundingsources/",$params);
583              
584 0           return $response;
585             }
586              
587             # Function: verify_funding_source
588             #
589             # Verify a funding source.
590             #
591             # Parameters:
592             # self - Object instance.
593             # sourceid - Fund source Id.
594             # deposit1 - Verification deposit amount 1.
595             # deposit2 - Verification deposit amount 2.
596             #
597             # Returns:
598             # Request Id or array or false (0) on error.
599             sub verify_funding_source
600             {
601 0     0 0   my $self = shift;
602 0   0       my $sourceid = shift || undef;
603 0   0       my $deposit1 = shift || undef;
604 0   0       my $deposit2 = shift || undef;
605              
606 0           my $errors = 0;
607              
608 0 0         if (!defined($sourceid)) {
609 0           $self->set_error("Please provide a valid funding source.");
610 0           $errors++;
611             }
612              
613 0 0         if (!defined($deposit1)) {
614 0           $self->set_error("Please provide deposit #1.");
615 0           $errors++;
616             }
617              
618 0 0         if (!defined($deposit2)) {
619 0           $self->set_error("Please provide deposit #2.");
620 0           $errors++;
621             }
622              
623 0 0         if ($errors) {
624 0           return 0;
625             }
626              
627 0           my $params = {
628             'deposit1' => $deposit1,
629             'deposit2' => $deposit2
630             };
631              
632 0           my $response = $self->_post("fundingsources/$sourceid/verify",$params);
633              
634 0           return $response;
635             }
636              
637             # Function: withdraw
638             #
639             # Withdraw money from a funding source.
640             #
641             # Parameters:
642             # self - Object instance.
643             # sourceid - Fund source Id.
644             # pin - Dwolla pin.
645             # amount - Deposit amount.
646             #
647             # Returns:
648             # Response or 0 on error.
649             sub withdraw
650             {
651 0     0 0   my $self = shift;
652 0   0       my $sourceid = shift || undef;
653 0   0       my $pin = shift || undef;
654 0   0       my $amount = shift || undef;
655              
656 0           my $errors = 0;
657              
658 0 0 0       if (!defined($pin) || $pin !~ /^[0-9]{4}$/) {
659 0           $self->set_error('Please supply a valid pin.');
660 0           $errors++;
661             }
662            
663 0 0         if (!defined($sourceid)) {
664 0           $self->set_error('Please supply a fund source.');
665 0           $errors++;
666             }
667            
668 0 0         if (!defined($amount)) {
669 0           $self->set_error('Please supply an amount.');
670 0           $errors++;
671             }
672              
673 0 0         if ($errors) {
674 0           return 0;
675             }
676              
677 0           my $params = {
678             'pin' => $pin,
679             'amount' => $amount
680             };
681              
682 0           my $response = $self->_post("fundingsources/$sourceid/withdraw",$params);
683              
684 0           return $response;
685             }
686              
687             # Function: deposit
688             #
689             # Deposit money into a funding source.
690             #
691             # Parameters:
692             # sourceid - Fund source Id.
693             # pin - Dwolla pin.
694             # amount - Deposit amount.
695             #
696             # Returns:
697             # Response or 0 on error.
698             sub deposit
699             {
700 0     0 0   my $self = shift;
701 0   0       my $sourceid = shift || undef;
702 0   0       my $pin = shift || undef;
703 0   0       my $amount = shift || undef;
704              
705 0           my $errors = 0;
706              
707 0 0 0       if (!defined($pin) || $pin !~ /^[0-9]{4}$/) {
708 0           $self->set_error('Please supply a valid pin.');
709 0           $errors++;
710             }
711            
712 0 0         if (!defined($sourceid)) {
713 0           $self->set_error('Please supply a fund source.');
714 0           $errors++;
715             }
716            
717 0 0         if (!defined($amount)) {
718 0           $self->set_error('Please supply an amount');
719 0           $errors++;
720             }
721              
722 0 0         if ($errors) {
723 0           return 0;
724             }
725              
726 0           my $params = {
727             'pin' => $pin,
728             'amount' => $amount
729             };
730              
731 0           my $response = $self->_post("fundingsources/$sourceid/deposit",$params);
732              
733 0           return $response;
734             }
735              
736             # Function: balance
737             #
738             # Retrieve the account balance for the user with the given authorized
739             # access token.
740             #
741             # Parameters:
742             # self - Object instance.
743             #
744             # Returns:
745             # Balance
746             sub balance
747             {
748 0     0 0   my $self = shift;
749              
750 0           my $response = $self->_get("balance");
751            
752 0           return $response;
753             }
754              
755             # Function: send
756             #
757             # Send funds to a user, originating from the user associated
758             # with the authorized access token.
759             #
760             # Parameters:
761             # self - Object instance.
762             # pin - Dwolla pin.
763             # destid - Destination Id.
764             # amount - Transaction amount.
765             # dtype - Destination type.
766             # notes - Transaction notes..
767             # facilitator_amount - Faciltitator amount.
768             # assume_costs - Assume Dwolla costs?
769             # fund_source - Fund source. Default: 'balance'
770             #
771             # Returns:
772             # Request Id or array or false on error.
773             sub send
774             {
775 0     0 0   my $self = shift;
776 0   0       my $pin = shift || undef;
777 0   0       my $destid = shift || undef;
778 0   0       my $amount = shift || undef;
779 0   0       my $dtype = shift || 'Dwolla';
780 0   0       my $notes = shift || '';
781 0   0       my $facilitator_amount = shift || 0;
782 0   0       my $assume_costs = shift || 0;
783 0   0       my $fund_source = shift || 'balance';
784              
785 0           my $errors = 0;
786              
787 0 0 0       if (!defined($pin) || $pin !~ /^[0-9]+$/) {
788 0           $self->set_error('Please supply a valid pin.');
789 0           $errors++;
790             }
791              
792 0 0         if (!defined($destid)) {
793 0           $self->set_error('Please supply a valid destination.');
794 0           $errors++;
795             }
796              
797 0 0         if (!defined($amount)) {
798 0           $self->set_error('Please supply a valid amount.');
799 0           $errors++;
800             }
801              
802 0 0         if ($errors) {
803 0           return 0;
804             }
805              
806 0           my $params = {
807             'pin' => $pin,
808             'destinationId' => $destid,
809             'destinationType' => $dtype,
810             'amount' => $amount,
811             'facilitatorAmount' => $facilitator_amount,
812             'assumeCosts' => $assume_costs,
813             'notes' => $notes,
814             'fundsSource' => $fund_source
815             };
816              
817 0           my $response = $self->_post("transactions/send",$params);
818              
819 0           return $response;
820             }
821              
822             # Function: guest_send
823             #
824             # Send funds to a destination user, from a non-Dwolla user's bank account.
825             #
826             # Parameters:
827             # self - Object instance.
828             # destid - Destination Id.
829             # amount - Transaction amount.
830             # first_name - First Name.
831             # last_name - Last name.
832             # email - Email address.
833             # trnnum - Transit routing number.
834             # acctnum - Account number.
835             # accttype - Account type ('Checking','Savings')
836             # assume_costs - Assume Dwolla costs?
837             # dtype - Destination type.
838             # notes - Transaction Id.
839             # group_id - ID specified by the client application.
840             # addtl_fees - Additional faciliator fees (Array of anonymous hashes)
841             #
842             # Returns:
843             # Transaction info or false (0) on error
844             sub guest_send
845             {
846 0     0 0   my $self = shift;
847 0           my $destid = shift;
848 0           my $amount = shift;
849 0           my $first_name = shift;
850 0           my $last_name = shift;
851 0           my $email = shift;
852 0           my $trnnum = shift;
853 0           my $acctnum = shift;
854 0           my $accttype = shift;
855 0   0       my $assume_costs = shift || 0;
856 0   0       my $dtype = shift || 'Dwolla';
857 0   0       my $notes = shift || '';
858 0   0       my $group_id = shift || undef;
859 0   0       my $addtl_fees = shift || undef;
860              
861 0           my $errors = 0;
862              
863 0 0         if (!defined($destid)) {
864 0           $self->set_error('Please supply a valid destination.');
865 0           $errors++;
866             }
867              
868 0 0         if (!defined($amount)) {
869 0           $self->set_error('Please supply a valid amount.');
870 0           $errors++;
871             }
872              
873 0 0         if ($errors) {
874 0           return 0;
875             }
876              
877 0           my $params = {
878             'client_id' => $self->{'api_key'},
879             'client_secret' => $self->{'api_secret'},
880             'destinationId' => $destid,
881             'destinationType' => $dtype,
882             'amount' => $amount,
883             'emailAddress' => $email,
884             'accountNumber' => $acctnum,
885             'routingNumber' => $trnnum,
886             'accountType' => $accttype,
887             'firstName' => $first_name,
888             'lastName' => $last_name,
889             'assumeCosts' => $assume_costs,
890             'notes' => $notes,
891             'groupId' => $group_id,
892             'additionalFees' => $addtl_fees
893             };
894              
895 0           my $response = $self->_post("transactions/guestsend",$params);
896              
897 0           return $response;
898             }
899              
900             # Function: request
901             #
902             # Request funds from a source user, originating from the user associated
903             # with the authorized access token.
904             #
905             # Parameters:
906             # self - Object instance.
907             # sourceid - Fund source Id.
908             # amount - Transaction amount.
909             # stype - Source type.
910             # notes - Transaction Id.
911             # facilitator_amount - Faciltitator amount.
912             #
913             # Returns:
914             # Request Id or array or false on error.
915             sub request
916             {
917 0     0 0   my $self = shift;
918 0   0       my $sourceid = shift || undef;
919 0   0       my $amount = shift || undef;
920 0   0       my $stype = shift || 'Dwolla';
921 0   0       my $notes = shift || '';
922 0   0       my $facilitator_amount = shift || 0;
923              
924 0           my $errors = 0;
925            
926 0 0         if (!defined($sourceid)) {
927 0           $self->set_error('Please supply a fund source.');
928 0           $errors++;
929             }
930              
931 0 0         if (!defined($amount)) {
932 0           $self->set_error('Please supply a valid amount.');
933 0           $errors++;
934             }
935              
936 0 0         if ($errors) {
937 0           return 0;
938             }
939              
940 0           my $params = {
941             'sourceId' => $sourceid,
942             'sourceType' => $stype,
943             'amount' => $amount,
944             'facilitatorAmount' => $facilitator_amount,
945             'notes' => $notes
946             };
947              
948 0           my $response = $self->_post("requests/",$params);
949              
950 0           return $response;
951             }
952              
953             # Function: request_by_id
954             #
955             # Get a request by its id.
956             #
957             # Parameters:
958             # self - Object instance.
959             # id - Request Id.
960             #
961             # Returns:
962             # Request information.
963             sub request_by_id
964             {
965 0     0 0   my $self = shift;
966 0           my $id = shift;
967              
968 0           my $response = $self->_get("requests/$id");
969            
970 0           return $response;
971             }
972              
973             # Function: fulfill_request
974             #
975             # Fulfill a pending money request.
976             #
977             # Parameters:
978             #
979             # self - Object instance.
980             # id - Request Id.
981             # pin - Dwolla pin.
982             # amount - Amount of transaction.
983             # notes - Notes about transaction.
984             # fund_source - Fund source. Default: 'balance'
985             # assume_costs - Assume transation cost?
986             #
987             # Returns:
988             # Transaction information.
989             sub fulfill_request
990             {
991 0     0 0   my $self = shift;
992 0   0       my $id = shift || undef;
993 0   0       my $pin = shift || undef;
994 0   0       my $amount = shift || undef;
995 0   0       my $notes = shift || '';
996 0   0       my $fund_source = shift || 'balance';
997 0           my $assume_costs = shift;
998              
999 0           my $params = {
1000             'pin' => $pin
1001             };
1002              
1003 0 0         if (defined($amount)) {
1004 0           $params->{'amount'} = $amount;
1005             }
1006              
1007 0 0         if (defined($notes)) {
1008 0           $params->{'notes'} = $notes;
1009             }
1010              
1011 0 0         if (defined($fund_source)) {
1012 0           $params->{'fundsSource'} = $fund_source;
1013             }
1014            
1015 0 0         if (!defined($assume_costs)) {
1016 0           $assume_costs = 0;
1017             }
1018 0           $params->{'assumeCosts'} = $assume_costs;
1019              
1020 0           my $response = $self->_post("requests/$id/fulfill",$params);
1021              
1022 0           return $response;
1023             }
1024              
1025             # Function: cancel
1026             #
1027             # Cancels a pending mooney request.
1028             #
1029             # Parameters:
1030             #
1031             # self - Object instance.
1032             # id - Request Id.
1033             #
1034             # Returns:
1035             # Array of requests.
1036             sub cancel_request
1037             {
1038 0     0 0   my $self = shift;
1039 0   0       my $id = shift || undef;
1040              
1041 0 0         if (!defined($id)) {
1042 0           $self->set_error('Must supply request id.');
1043 0           return 0;
1044             }
1045              
1046 0           my $response = $self->_post("requests/$id/cancel",{});
1047            
1048 0           return $response;
1049             }
1050              
1051             # Function: requests
1052             #
1053             # Get a list of pending money requests.
1054             #
1055             # Parameters:
1056             #
1057             # self - Object instance.
1058             #
1059             # Returns:
1060             # Array of requests.
1061             sub requests
1062             {
1063 0     0 0   my $self = shift;
1064              
1065 0           my $response = $self->_get("requests");
1066            
1067 0           return $response;
1068             }
1069              
1070             # Function: transaction
1071             #
1072             # Grab information for the given transaction ID with
1073             # app credentials (instead of oauth token)
1074             #
1075             # Parameters:
1076             #
1077             # self - Object instance.
1078             # transaction - Transaction ID.
1079             #
1080             # Returns:
1081             # Transaction information.
1082             sub transaction
1083             {
1084 0     0 0   my $self = shift;
1085 0   0       my $transaction = shift || undef;
1086              
1087 0 0         if (!defined($transaction)) {
1088 0           $self->set_error('Must supply transaction id.');
1089 0           return 0;
1090             }
1091              
1092 0           my $params = {
1093             'client_id' => $self->{'api_key'},
1094             'client_secret' => $self->{'api_secret'},
1095             };
1096              
1097 0           my $response = $self->_get("transactions/$transaction",$params);
1098            
1099 0           return $response;
1100             }
1101              
1102             # Function: listings
1103             #
1104             # Retrieve a list of transactions for the user associated with the
1105             # authorized access token.
1106             #
1107             # Parameters:
1108             #
1109             # self - Object instance.
1110             # since - Earliest date and time for which to retrieve transactions.
1111             # Default: 7 days prior to current date / time in UTC. (DD-MM-YYYY)
1112             # types - Types of transactions to retrieve. Options are money_sent,
1113             # money_received, deposit, withdrawal, and fee.
1114             # limit - Number of transactions to retrieve between 1 and 200, Default: 10.
1115             # skip - Number of transactions to skip. Default: 0.
1116             # groupid - ID specified by the client application. If specified, this call
1117             # will only return transactions with IDs matching the given groupId.
1118             #
1119             # Returns:
1120             # Array of transactions / false (0) on error.
1121             sub listings
1122             {
1123 0   0 0 0   my $self = shift || undef;
1124 0   0       my $since = shift || undef;
1125 0   0       my $types = shift || undef;
1126 0   0       my $limit = shift || 10;
1127 0   0       my $skip = shift || 0;
1128 0   0       my $groupid = shift || undef;
1129              
1130 0           my $params = {
1131             'client_id' => $self->{'api_key'},
1132             'client_secret' => $self->{'api_secret'},
1133             'limit' => $limit,
1134             'skip' => $skip,
1135             'groupId' => $groupid
1136             };
1137              
1138 0 0         if (defined($since)) {
1139 0 0         if ($since =~ /^\d{2}\-\d{2}\-\d{4}$/) {
1140 0           $params->{'sinceDate'} = $since;
1141             } else {
1142 0           $self->set_error("Please supply a date in 'MM-DD-YYYY' format.");
1143 0           return 0;
1144             }
1145             }
1146              
1147 0 0         if (defined($types)) {
1148 0           $params->{'types'} = join(',',@{$types});
  0            
1149             }
1150              
1151 0           my $response = $self->_get("transactions/",$params);
1152              
1153 0           return $response;
1154             }
1155              
1156             # Function: stats
1157             #
1158             # Retrieve transactions stats for the user associated with the authorized
1159             # access token.
1160             #
1161             # Parameters:
1162             # self - Object instance.
1163             # types - Options. Default: 'TransactionsCount', 'TransactionsTotal'
1164             # start_date - Search start date. Default: 0300 of the current day in UTC.
1165             # end_date - Search end date. Default: 0300 of the current day in UTC.
1166             #
1167             # Returns:
1168             # void
1169             sub stats
1170             {
1171 0     0 0   my $self = shift;
1172 0   0       my $types = shift || ['TransactionsCount', 'TransactionsTotal'];
1173 0   0       my $start_date = shift || undef;
1174 0   0       my $end_date = shift || undef;
1175              
1176 0           my $params = {
1177 0           'types' => join(',',@{$types}),
1178             'startDate' => $start_date,
1179             'endDate' => $end_date
1180             };
1181              
1182 0           my $response = $self->_get("transactions/stats",$params);
1183              
1184 0           return $response;
1185             }
1186              
1187             # Function: start_gateway_session
1188             #
1189             # Starts a new gateway session.
1190             #
1191             # Parameters:
1192             # self - Object instance.
1193             #
1194             # Returns:
1195             # Void
1196             sub start_gateway_session
1197             {
1198 0     0 0   my $self = shift;
1199              
1200 0           $self->{'gateway_session'} = [];
1201             }
1202              
1203             # Function: add_gateway_product
1204             #
1205             # Adds a product to the gateway session.
1206             #
1207             # Parameters:
1208             # self - Object instance.
1209             # name - Product name.
1210             # price - Product price.
1211             # quantity - Product quantity.
1212             # description - Product description.
1213             #
1214             # Returns:
1215             # void
1216             sub add_gateway_product
1217             {
1218 0     0 0   my $self = shift;
1219 0           my $name = shift;
1220 0           my $price = shift;
1221 0   0       my $quantity = shift || undef;
1222 0   0       my $description = shift || '';
1223            
1224 0 0         if (!defined($quantity)) {
1225 0           $quantity = 1;
1226             }
1227              
1228 0           my $product = {
1229             'Name' => $name,
1230             'Price' => $price,
1231             'Description' => $description,
1232             'Quantity' => $quantity
1233             };
1234              
1235 0           push(@{$self->{'gateway_session'}},$product);
  0            
1236             }
1237              
1238             # Function: get_gateway_url
1239             #
1240             # Creates and executes Server-to-Server checkout request.
1241             #
1242             # Parameters:
1243             # self - Object instance.
1244             # orderid - Order Id.
1245             # discount - Discount amount.
1246             # shipping - Shipping amount.
1247             # tax - Tax ammount.
1248             # notes - Transaction notes.
1249             # callback - Callback URL
1250             # allow_funding_sources - Allow funding sources? (1 - yes; 0 - no)
1251             #
1252             # Returns:
1253             # Gateway URL
1254             sub get_gateway_url
1255             {
1256 0     0 0   my $self = shift;
1257 0           my $destid = shift;
1258 0           my $orderid = shift;
1259 0   0       my $discount = shift || 0;
1260 0   0       my $shipping = shift || 0;
1261 0   0       my $tax = shift || 0;
1262 0   0       my $notes = shift || '';
1263 0   0       my $callback = shift || undef;
1264 0           my $allow_funding_sources = shift;
1265              
1266 0 0         if (!$self->is_id_valid($destid)) {
1267 0           $self->set_error("Please supply a valid Dwolla Id.");
1268 0           return 0;
1269             }
1270              
1271 0 0         if (!defined($allow_funding_sources)) {
1272 0           $allow_funding_sources = 1;
1273             }
1274              
1275 0           my $subtotal = 0;
1276              
1277 0           foreach my $product (@{$self->{'gateway_session'}}) {
  0            
1278 0           $subtotal += $product->{'Price'} * $product->{'Quantity'};
1279             }
1280              
1281 0           my $total = sprintf("%.2f",($subtotal - abs($discount) + $shipping + $tax));
1282              
1283 0 0         my $request = {
    0          
1284             'Key' => $self->{'api_key'},
1285             'Secret' => $self->{'api_secret'},
1286             'Test' => ($self->{'mode'} eq 'test') ? 1 : 0,
1287             'AllowFundingSources' => ($allow_funding_sources) ? 'true' : 'false',
1288             'PurchaseOrder' => {
1289             'DestinationId' => $destid,
1290             'OrderItems' => $self->{'gateway_session'},
1291             'Discount' => (abs($discount) * -1),
1292             'Shipping' => $shipping,
1293             'Tax' => $tax,
1294             'Total' => $total,
1295             'Notes' => $notes,
1296             }
1297             };
1298            
1299 0 0         if (defined($self->{'redirect_uri'})) {
1300 0           $request->{'Redirect'} = $self->{'redirect_uri'};
1301             }
1302            
1303 0 0         if (defined($callback)) {
1304 0           $request->{'Callback'} = $callback;
1305             }
1306            
1307 0 0         if (defined($orderid)) {
1308 0           $request->{'OrderId'} = $orderid;
1309             }
1310            
1311 0           my $response = $self->_api_request(GATEWAY_URL,'POST',$request);
1312              
1313 0 0         if ($response != 0) {
1314 0 0         if ($response->{'Result'} ne 'Success') {
1315 0           $self->set_error($response->{'Message'});
1316 0           return 0;
1317             }
1318             } else {
1319 0           return $response;
1320             }
1321              
1322 0           return CHECKOUT_URL . '/' . $response->{'CheckoutId'};
1323             }
1324              
1325             # Function: verify_gateway_signature
1326             #
1327             # Verify a signature that came back with an offsite gateway redirect.
1328             #
1329             # Parameters:
1330             # self - Object instance.
1331             # signature - HMAC signature.
1332             # checkout_id - Checkout Id.
1333             # amount - Transaction amount.
1334             #
1335             # Returns:
1336             # 1 - valid; 0 invalid
1337             sub verify_gateway_signature
1338             {
1339 0     0 0   my $self = shift;
1340 0   0       my $signature = shift || undef;
1341 0   0       my $checkout_id = shift || undef;
1342 0   0       my $amount = shift || undef;
1343              
1344 0           my $errors = 0;
1345              
1346 0 0         if (!defined($signature)) {
1347 0           $self->set_error("Please pass a proposed signature.");
1348 0           $errors++;
1349             }
1350              
1351 0 0         if (!defined($checkout_id)) {
1352 0           $self->set_error("Please pass a checkout id.");
1353 0           $errors++;
1354             }
1355              
1356 0 0         if (!defined($amount)) {
1357 0           $self->set_error("Please pass an amount.");
1358 0           $errors++;
1359             }
1360              
1361 0 0         if ($errors) {
1362 0           return 0;
1363             }
1364              
1365 0           my $hmac = Digest::HMAC_SHA1->new($checkout_id . '&' . $amount,$self->{'api_secret'});
1366 0           my $hash = $hmac->hexdigest;
1367              
1368 0 0         if ($hash ne $signature) {
1369 0           $self->set_error('Dwolla signature verification failed.');
1370 0           return 0;
1371             }
1372              
1373 0           return 1;
1374             }
1375              
1376             # Function: verify_webhook_signature
1377             #
1378             # Verify the signature from Webhook notifications.
1379             #
1380             # Parameters:
1381             # self - Object instance.
1382             # sheader - Signature header.
1383             # body - Request body.
1384             #
1385             # Returns:
1386             # 1 - valid; 0 - invalid;
1387             sub verify_webhook_signature
1388             {
1389 0     0 0   my $self = shift;
1390 0           my $sheader = shift;
1391 0           my $body = shift;
1392              
1393 0           my $hmac = Digest::HMAC_SHA1->new($body,$self->{'api_secret'});
1394 0           my $hash = $hmac->hexdigest;
1395              
1396 0 0         if ($hash ne $sheader) {
1397 0           $self->set_error('Dwolla signature verification failed.');
1398 0           return 0;
1399             }
1400              
1401 0           return 1;
1402             }
1403              
1404             # Function: masspay_create_job
1405             #
1406             # Send payments in bulk from the user with the given authorized access token.
1407             #
1408             # Parameters:
1409             # pin - Dwolla pin number.
1410             # email - Email address to send reports.
1411             # user_job_id - A user assigned job ID for the MassPay job.
1412             # assume_costs - Should the sending user pay any associated fees?
1413             # 1 - Yes; 0 - No;
1414             # source - Desired funding source from which to send money.
1415             # Defaults to Dwolla 'balance'.
1416             # filedata - The bulk payments data. Must be an array reference of
1417             # anonymous hashes.
1418             #
1419             # Returns:
1420             # MassPay reeponse or false (0) on error.
1421             sub masspay_create_job
1422             {
1423 0     0 0   my $self = shift;
1424 0           my $pin = shift;
1425 0           my $email = shift;
1426 0           my $user_job_id = shift;
1427 0           my $assume_costs = shift;
1428 0   0       my $source = shift || 'balance';
1429 0   0       my $filedata = shift || undef;
1430              
1431 0 0         my $test_string = ($self->{'mode'} eq 'test') ? 'true' : 'false';
1432              
1433 0           my $params = {
1434             'pin' => $pin,
1435             'email' => $email,
1436             'source' => $source,
1437             'user_job_id' => $user_job_id,
1438             'test' => $test_string,
1439             'filedata' => $filedata,
1440             'assumeCosts' => $assume_costs,
1441             'token' => $self->{'oauth_token'}
1442             };
1443              
1444 0           my $response = $self->_parse_masspay(
1445             $self->_api_request(
1446             MASSPAY_URL . '/create',
1447             'POST',
1448             $params
1449             )
1450             );
1451              
1452 0           return $response;
1453             }
1454              
1455             # Function: masspay_job_details
1456             #
1457             # Parameters:
1458             # self - Object instance.
1459             # uid - Dwolla Id
1460             # job_id - MassPay job id
1461             # user_job_id - User-assigned job id.
1462             #
1463             # Returns:
1464             # Job details or false (0) on set error.
1465             sub masspay_job_details
1466             {
1467 0     0 0   my $self = shift;
1468 0           my $uid = shift;
1469 0           my $job_id = shift;
1470 0   0       my $user_job_id = shift || undef;
1471              
1472 0           my $params = {
1473             'uid' => $uid,
1474             'job_id' => $job_id,
1475             'user_job_id' => $user_job_id
1476             };
1477              
1478 0           my $response = $self->_parse_masspay(
1479             $self->_api_request(
1480             MASSPAY_URL . '/status',
1481             'POST',
1482             $params
1483             )
1484             );
1485              
1486 0           return $response;
1487             }
1488              
1489             # Function: is_id_valid
1490             #
1491             # Determines if provided Dwolla Id is valid.
1492             #
1493             # Parameters:
1494             # self - Object instance.
1495             # id - Dwolla Id
1496             #
1497             # Returns:
1498             # 1 for valid; 0 for invalid
1499             sub is_id_valid
1500             {
1501 0     0 0   my $self = shift;
1502 0           my $id = shift;
1503              
1504 0           my $valid = 0;
1505              
1506 0 0 0       if (defined($id) && $id =~ /([0-9]{3})\-*([0-9]{3})\-*([0-9]{4})/) {
1507 0           $valid = 1;
1508             }
1509              
1510 0           return $valid;
1511             }
1512              
1513             # Function: set_error
1514             #
1515             # Add error to error array.
1516             #
1517             # Parameters:
1518             # self - Object instances.
1519             # error - Error string.
1520             #
1521             # Returns:
1522             # void
1523             sub set_error
1524             {
1525 0     0 0   my $self = shift;
1526 0           my $error = shift;
1527              
1528 0           push(@{$self->{'errors'}},$error);
  0            
1529             }
1530              
1531             # Function: get_errors
1532             #
1533             # Returnserror array.
1534             #
1535             # Parameters:
1536             # self - Object instances.
1537             #
1538             # Returns:
1539             # Error array
1540             sub get_errors
1541             {
1542 0     0 0   my $self = shift;
1543              
1544 0           my @err = ();
1545 0           @err = @{$self->{'errors'}};
  0            
1546              
1547 0           $self->{'errors'} = [];
1548              
1549 0           return \@err;
1550             }
1551              
1552             # Function: set_debug_mode
1553             #
1554             # Toggle debug mode on / off.
1555             # NOTE: Turning this on could potentially write sensitive information to
1556             # the screen / command-line. So, using this in production is not
1557             # advisable.
1558             #
1559             # Parameters:
1560             # self - Object instance.
1561             # mode - Debug mode. 1 = on; 0 = off
1562             #
1563             # Returns:
1564             # void
1565             sub set_debug_mode
1566             {
1567 0     0 0   my $self = shift;
1568 0   0       my $debug_mode = shift || 0;
1569              
1570 0           $self->{'debug_mode'} = $debug_mode;
1571             }
1572              
1573             # Function: _http_build_query
1574             #
1575             # Build HTTP query string similar to PHP's http_build_query()
1576             #
1577             # Parameters:
1578             # self - Object instance.
1579             # params - Request query parameters.
1580             #
1581             # Returns:
1582             # Query string
1583             sub _http_build_query
1584             {
1585 0     0     my $self = shift;
1586 0           my $params = shift;
1587              
1588 0           my @tmp = ();
1589 0           my $str;
1590              
1591 0           foreach my $key (keys %{$params}) {
  0            
1592 0 0         if (defined($params->{$key})) {
1593 0           $str = uri_escape($key) . '=' . uri_escape($params->{$key});
1594 0           push(@tmp,$str);
1595             }
1596             }
1597              
1598 0           return join(q{&},@tmp);
1599             }
1600              
1601             # Function: _get
1602             #
1603             # Wrapper for _api_request (GET)
1604             #
1605             # Parameters:
1606             # self - Object instance.
1607             # url - Request URL.
1608             # params - Request query parameters.
1609             #
1610             # Returns:
1611             # JSON object or false (0) on failure
1612             sub _get
1613             {
1614 0     0     my $self = shift;
1615 0           my $url = shift;
1616 0           my $params = shift;
1617              
1618 0           $params->{'oauth_token'} = $self->{'oauth_token'};
1619              
1620 0           my $rurl = API_SERVER . '/' . $url . '?' . $self->_http_build_query($params);
1621              
1622 0           my $response = $self->_parse($self->_api_request($rurl,'GET'));
1623              
1624 0           return $response;
1625             }
1626              
1627             # Function: _post
1628             #
1629             # Wrapper for _api_request (POST)
1630             #
1631             # Parameters:
1632             # self - Object instance.
1633             # url - Request URL.
1634             # params - Request query parameters.
1635             # include_token - Whether or not to include OAuth token.
1636             #
1637             # Returns:
1638             # JSON object or false (0) on failure
1639             sub _post
1640             {
1641 0     0     my $self = shift;
1642 0           my $url = shift;
1643 0           my $params = shift;
1644 0           my $include_token = shift;
1645              
1646 0           my $rurl = API_SERVER . '/' . $url;
1647 0 0 0       if (!defined($include_token) || $include_token != 0) {
1648 0           $rurl .= '?' .
1649             $self->_http_build_query({
1650             'oauth_token' => $self->{'oauth_token'}
1651             });
1652             }
1653              
1654 0           my $response = $self->_parse($self->_api_request($rurl,'POST',$params));
1655              
1656 0           return $response;
1657             }
1658              
1659             # Function: _api_request
1660             #
1661             # Make the API HTTP request.
1662             #
1663             # Parameters:
1664             # self - Object instance.
1665             # url - Request URL.
1666             # method - HTTP method. (GET,POST)
1667             #
1668             # Returns:
1669             # JSON object or false (0) on failure
1670             sub _api_request
1671             {
1672 0     0     my $self = shift;
1673 0           my $url = shift;
1674 0           my $method = shift;
1675 0   0       my $params = shift || undef;
1676              
1677 0           my $content_type = 'application/json;charset=UTF-8';
1678              
1679 0           my $ua = LWP::UserAgent->new;
1680 0           $ua->agent('Dwolla Perl API V' . $VERSION);
1681            
1682 0 0         if ($self->{'debug_mode'}) {
1683 0           print "Making '$method' request to '$url'\n";
1684             }
1685              
1686 0           my $request;
1687 0 0         if ($method eq 'GET') {
    0          
1688 0           $request = HTTP::Request->new(GET => $url);
1689             } elsif ($method eq 'POST') {
1690 0           my $data = JSON->new->utf8->encode($params);
1691 0 0         if ($self->{'debug_mode'}) {
1692 0           print "POST DATA: $data\n";
1693             }
1694 0           $request = HTTP::Request->new(POST => $url);
1695 0           $request->content_length(length($data));
1696 0           $request->content($data);
1697             }
1698              
1699 0           $request->content_type($content_type);
1700              
1701 0           my $response = $ua->request($request);
1702 0 0         if ($response->code() ne '200') {
1703 0 0         if ($self->{'debug_mode'}) {
1704 1     1   2489 use Data::Dumper;
  1         11781  
  1         190  
1705 0           print Data::Dumper->Dump([$response],'response');
1706             }
1707 0           $self->set_error("Request failed. HTTP status code: " . $response->code());
1708 0           return 0;
1709             }
1710              
1711 0           my $obj = JSON->new->utf8->decode($response->content);
1712              
1713 0           return $obj;
1714             }
1715              
1716             # Function: _parse
1717             #
1718             # Parse the JSON response from API request for errors.
1719             #
1720             # Parameters:
1721             # self - Object instance.
1722             # response - JSON response data.
1723             #
1724             # Returns:
1725             # JSON response or zero (0) on failure.
1726             sub _parse
1727             {
1728 0     0     my $self = shift;
1729 0           my $response = shift;
1730              
1731 0 0         if ($self->{'debug_mode'}) {
1732 1     1   8 use Data::Dumper;
  1         2  
  1         198  
1733 0           print Data::Dumper->Dump([$response],'response');
1734             }
1735              
1736 0           my $errstring = '';
1737 0           my $errors = 0;
1738              
1739 0 0         if ($response->{'Success'} == 0) {
1740 0           $errstring = $response->{'Message'};
1741 0           $errors++;
1742              
1743 0 0         if ($response->{'Response'}) {
1744 0           $errstring .= ' :: ' . join(',',@{$response->{'Response'}});
  0            
1745             }
1746             }
1747              
1748 0 0         if ($errors) {
1749 0           $self->set_error($errstring);
1750 0           return 0;
1751             }
1752            
1753 0           return $response->{'Response'};
1754             }
1755              
1756             # Function: _parse_masspay
1757             #
1758             # Parse the JSON response from MassPay API request for errors.
1759             #
1760             # Parameters:
1761             # self - Object instance.
1762             # response - JSON response data.
1763             #
1764             # Returns:
1765             # JSON response or zero (0) on failure.
1766             sub _parse_masspay
1767             {
1768 0     0     my $self = shift;
1769 0           my $response = shift;
1770              
1771 0 0         if ($self->{'debug_mode'}) {
1772 1     1   6 use Data::Dumper;
  1         2  
  1         115  
1773 0           print Data::Dumper->Dump([$response],'response');
1774             }
1775              
1776 0 0         if (!$response->{'success'}) {
1777 0           $self->set_error($response->{'message'});
1778 0           return 0;
1779             }
1780              
1781 0           return $response->{'job'};
1782             }
1783              
1784             1;
1785             __END__