File Coverage

lib/Net/API/Stripe/List.pm
Criterion Covered Total %
statement 19 136 13.9
branch 0 70 0.0
condition 0 56 0.0
subroutine 7 28 25.0
pod 10 15 66.6
total 36 305 11.8


line stmt bran cond sub pod time code
1             ##----------------------------------------------------------------------------
2             ## Stripe API - ~/lib/Net/API/Stripe/List.pm
3             ## Version v0.200.3
4             ## Copyright(c) 2020 DEGUEST Pte. Ltd.
5             ## Author: Jacques Deguest <jack@deguest.jp>
6             ## Created 2019/11/02
7             ## Modified 2022/10/25
8             ## All rights reserved.
9             ##
10             ##
11             ## This program is free software; you can redistribute it and/or modify it
12             ## under the same terms as Perl itself.
13             ##----------------------------------------------------------------------------
14             # To be inherited
15             BEGIN
16             {
17             use strict;
18 1     1   420 use warnings;
  1         2  
  1         31  
19 1     1   6 use parent qw( Net::API::Stripe::Generic );
  1         2  
  1         27  
20 1     1   5 use vars qw( $VERSION );
  1         1  
  1         6  
21 1     1   64 # use B;
  1         2  
  1         47  
22             # use B::Deparse;
23             our( $VERSION ) = 'v0.200.3';
24 1     1   19 };
25              
26             use strict;
27 1     1   5 use warnings;
  1         2  
  1         19  
28 1     1   4  
  1         2  
  1         1504  
29             # Provide our own version of as_hash to avoid our helper methods from being called by Module::Generic::as_hash
30             {
31             my $self = CORE::shift( @_ );
32             my $p = {};
33 0     0 1   $p = CORE::shift( @_ ) if( scalar( @_ ) == 1 && ref( $_[0] ) eq 'HASH' );
34 0           my $data = $self->_data;
35 0 0 0       my $res = [];
36 0           foreach my $this ( @$data )
37 0           {
38 0           if( $self->_is_object( $this ) && $this->can( 'as_hash' ) )
39             {
40 0 0 0       my $v = $this->as_hash( $p );
41             CORE::push( @$res, $v );
42 0           }
43 0           }
44             return( { data => $res } );
45             }
46 0            
47              
48              
49 0     0 1    
50              
51 0     0 0    
52             {
53 0     0 1   my $self = CORE::shift( @_ );
54             if( @_ )
55 0     0 1   {
56             $self->_set_get_scalar( 'total_count', @_ );
57 0     0 1   }
58             my $total = $self->_set_get_scalar( 'total_count' );
59             if( !defined( $total ) || !CORE::length( $total ) )
60             {
61 0     0 1   return( $self->_data->size );
62 0 0         }
63             else
64 0           {
65             return( $total );
66 0           }
67 0 0 0       }
68              
69 0           # Additional methods for navigation to be used like $list->next or $list->prev
70             {
71             my $self = CORE::shift( @_ );
72             my $pos = @_ ? int( CORE::shift( @_ ) ) : ( $self->{_pos} || 0 );
73 0           my $data = $self->_data;
74             return( $data->[ $pos ] );
75             }
76              
77             {
78             my $self = CORE::shift( @_ );
79             my $data = $self->_data;
80 0     0 1   return( scalar( @$data ) );
81 0 0 0       }
82 0            
83 0           {
84             my $self = CORE::shift( @_ );
85             $self->{_pos} = -1 if( !exists( $self->{_pos} ) );
86             my $data = $self->_data;
87             if( $self->{_pos} + 1 < scalar( @$data ) )
88 0     0 1   {
89 0           return( $data->[ ++$self->{_pos} ] );
90 0           }
91             elsif( $self->has_more && scalar( @$data ) && $self->_is_object( $data->[-1] ) )
92             {
93             my $last_id = $data->[-1]->id;
94             $self->{_limit} = scalar( @$data ) if( !$self->{_limit} );
95 0     0 1   my $opts =
96 0 0         {
97 0           starting_after => $last_id,
98 0 0 0       limit => ( $self->{_limit} || 10 ),
    0 0        
99             };
100 0           my $hash = $self->parent->get( $self->url, $opts ) || return;
101             return( $self->error( "Cannot find property 'object' in this hash reference: ", sub{ $self->dumper( $hash ) } ) ) if( !CORE::exists( $hash->{object} ) );
102             my $class = $self->_object_type_to_class( $hash->{object} ) || return;
103             my $list = $self->parent->_response_to_object( $class, $hash ) || return;
104 0           $data = $list->_data;
105 0 0         $self->{data} = $data;
106             $self->{_pos} = 0;
107             return( '' ) if( !scalar( @$data ) );
108             return( $data->[ $self->{_pos} ] );
109 0   0       }
110             else
111 0   0       {
112 0 0   0     # We do not return undef(), which we use to signal errors
  0            
113 0   0       return( '' );
114 0   0       }
115 0           }
116 0            
117 0           {
118 0 0         my $self = CORE::shift( @_ );
119 0           $self->{_pos} = -1 if( !exists( $self->{_pos} ) );
120             my $data = $self->_data;
121             if( $self->{_pos} - 1 >= 0 )
122             {
123             return( $data->[ --$self->{_pos} ] );
124 0           }
125             elsif( scalar( @$data ) && $self->_is_object( $data->[0] ) )
126             {
127             my $first_id = $data->[0]->id;
128             $self->{_limit} = scalar( @$data ) if( !$self->{_limit} );
129             my $opts =
130 0     0 1   {
131 0 0         ending_before => $first_id,
132 0           limit => ( $self->{_limit} || 10 ),
133 0 0 0       };
    0          
134             my $hash = $self->parent->get( $self->url, $opts ) || return;
135 0           return( $self->error( "Cannot find property 'object' in this hash reference: ", sub{ $self->dumper( $hash ) } ) ) if( !CORE::exists( $hash->{object} ) );
136             my $class = $self->_object_type_to_class( $hash->{object} ) || return;
137             my $list = $self->parent->_response_to_object( $class, $hash ) || return;
138             $data = $list->_data;
139 0           $self->{data} = $data;
140 0 0         # $self->_data( $data );
141             $self->{_pos} = $#$data;
142             return( '' ) if( !scalar( @$data ) );
143             return( $data->[ $self->{_pos} ] );
144 0   0       }
145             else
146 0   0       {
147 0 0   0     # We do not return undef(), which we use to signal errors
  0            
148 0   0       return( '' );
149 0   0       }
150 0           }
151 0            
152             {
153 0           my $self = CORE::shift( @_ );
154 0 0         return( $self->_data->pop );
155 0           }
156              
157             {
158             my $self = CORE::shift( @_ );
159             my $this = CORE::shift( @_ ) || return( $self->error( "Nothing was provided to add to the list of object." ) );
160 0           $self->_check( $this ) || return;
161             $self->_data->push( $this );
162             return( $self );
163             }
164              
165             {
166 0     0 0   my $self = CORE::shift( @_ );
167 0           return( $self->_data->shift );
168             }
169              
170             {
171             my $self = CORE::shift( @_ );
172 0     0 0   my $this = CORE::shift( @_ ) || return( $self->error( "Nothing was provided to add to the list of object." ) );
173 0   0       $self->_check( $this ) || return;
174 0 0         $self->_data->unshift( $this );
175 0           return( $self );
176 0           }
177              
178             {
179             my $self = CORE::shift( @_ );
180             my $this = CORE::shift( @_ ) || return( $self->error( "No data was provided to check." ) );
181 0     0 0   return( $self->error( "Data provided is not an object." ) ) if( !$self->_is_object( $this ) );
182 0           # Check if there is any data and if there is find out what kind of object we are holding so we can maintain consistency
183             my $data = $self->_data;
184             my $obj_name;
185             if( scalar( @$data ) && $self->_is_object( $data->[0] ) )
186             {
187 0     0 0   $obj_name = $data->[0]->object if( $data->[0]->can( 'object' ) );
188 0   0       }
189 0 0         if( $this->can( 'object' ) )
190 0           {
191 0           return( $self->error( "Object provided ($this) has an object type (", $this->object, ") different from the ones currently in our stack ($obj_name)." ) ) if( $this->object ne $obj_name );
192             }
193             return( $this );
194             }
195              
196 0     0     {
197 0   0       my $self = CORE::shift( @_ );
198 0 0         my $field = 'data';
199             if( @_ )
200 0           {
201 0           my $ref = CORE::shift( @_ );
202 0 0 0       return( $self->error( "I was expecting an array ref, but instead got '$ref'. _is_array returned: '", $self->_is_array( $ref ), "'" ) ) if( !$self->_is_array( $ref ) );
203             my $arr = [];
204 0 0         # Are we provided with an array of existing objects? No need to do anything then
205             if( $self->_is_object( $ref->[0] ) )
206 0 0         {
207             # Unless it is already an array object, we make it one
208 0 0         $arr = $self->_is_object( $ref ) ? $ref : $self->new_array( $ref );
209             }
210 0           else
211             {
212             if( scalar( @$ref ) )
213             {
214             my $type;
215 0     0     if( $self->_is_object( $ref->[0] ) )
216 0           {
217 0 0         return( $self->error( "I found an array of objects, but they do not have the method \"object\"." ) ) if( !$ref->[0]->can( 'object' ) );
218             $type = $ref->[0]->object || return( $self->error( "Somehow, the object property for this object (", $ref->[0], ") is empty." ) );
219 0           }
220 0 0         else
221 0           {
222             return( $self->error( "I was expecting an array of hash reference, but instead of hash I found $ref->[0]" ) ) if( ref( $ref->[0] ) ne 'HASH' );
223 0 0         return( $self->error( "Found an hash reference in this array, but it is empty: ", sub{ $self->dumper( $ref ) } ) ) if( !scalar( keys( %{$ref->[0]} ) ) );
224             $type = $ref->[0]->{object} || return( $self->error( "I was expecting a string in property 'object', but found nothing: ", sub{ $self->dumper( $ref ) } ) );
225             }
226 0 0         my $class = $self->_object_type_to_class( $type ) || return( $self->error( "Could not find corresponding class for ojbect type \"$type\"." ) );
227             $arr = $self->_set_get_object_array_object( $field, $class, $ref );
228             # Store this value used by next() and prev() to replicate the query with the right limit
229             # If initial query made by the user was 10 this array would be 10 or less if there is no more data
230 0 0         }
231             }
232 0           $self->{ $field } = $arr;
233 0 0         }
234             if( !$self->{ $field } || !$self->_is_object( $self->{ $field } ) )
235 0 0         {
236 0   0       my $o = $self->new_array( ( defined( $self->{ $field } ) && CORE::length( $self->{ $field } ) ) ? $self->{ $field } : [] );
237             $self->{ $field } = $o;
238             }
239             return( $self->{ $field } );
240 0 0         }
241 0 0   0      
  0            
  0            
242 0   0 0     1;
  0            
243             # NOTE: POD
244 0   0        
245 0           =encoding utf8
246              
247             =head1 NAME
248              
249             Net::API::Stripe::List - Stripe List Object
250 0            
251             =head1 SYNOPSIS
252 0 0 0        
253             my $stripe = Net::API::Stripe->new( conf_file => 'settings.json' ) || die( Net::API::Stripe->error );
254 0 0 0       my $list = $stripe->customers( 'list' ) || die( $stripe->error );
255 0           printf( "%d total customer(s) found\n", $list->count );
256             while( my $cust = $list->next )
257 0           {
258             printf( "Customer %s with e-mail has a balance of %s\n", $cust->name, $cust->email, $cust->balance->format_money( 0, '¥' ) );
259             }
260              
261             =head1 VERSION
262              
263             v0.200.3
264              
265             =head1 DESCRIPTION
266              
267             This is a package with a set of useful methods to be inherited by various Stripe package, such as bellow packages. It can also be used directly in a generic way and this will find out which list of objects this is. This is the case for example when getting the list of customer tax ids in B<Net::API::Stripe::tax_id_list>().
268              
269             =over 4
270              
271             =item L<Net::API::Stripe::Billing::Invoice::Lines>
272              
273             =item L<Net::API::Stripe::Billing::Subscription::Items>
274              
275             =item L<Net::API::Stripe::Charge::Refunds>
276              
277             =item L<Net::API::Stripe::Connect::Account::ExternalAccounts>
278              
279             =item L<Net::API::Stripe::Connect::ApplicationFee::Refunds>
280              
281             =item L<Net::API::Stripe::Connect::Transfer::Reversals>
282              
283             =item L<Net::API::Stripe::Customer::List>
284              
285             =item L<Net::API::Stripe::Customer::Sources>
286              
287             =item L<Net::API::Stripe::Customer::Subscription>
288              
289             =item L<Net::API::Stripe::Customer::TaxIds>
290              
291             =item L<Net::API::Stripe::File::Links>
292              
293             =item L<Net::API::Stripe::Order::Return>
294              
295             =item L<Net::API::Stripe::Payment::Intent::Charges>
296              
297             =item L<Net::API::Stripe::Sigma::ScheduledQueryRun::File::Links>
298              
299             =back
300              
301             =head1 CONSTRUCTOR
302              
303             =head2 new( %ARG )
304              
305             Creates a new L<Net::API::Stripe::List> object.
306             It may also take an hash like arguments, that also are method of the same name.
307              
308             =head1 METHODS
309              
310             =head2 object string
311              
312             This is the string identifier of the type of data. Usually it is "list"
313              
314             =head2 data array
315              
316             This is an array of data, usually objects, but it could vary, which is why this method should be overriden by package inheriting from this one.
317              
318             =head2 has_more boolean
319              
320             This is a boolean value to indicate whether the data is buffered
321              
322             =head2 url URI
323              
324             This is uri to be used to access the next or previous set of data
325              
326             =head2 total_count integer
327              
328             Total size of the array i.e. number of elements
329              
330             =head2 get offset
331              
332             Retrieves the data at the offset specified
333              
334             =head2 length integer
335              
336             The size of the array
337              
338             =head2 next
339              
340             Moves to the next entry in the array
341              
342             =head2 prev
343              
344             Moves to the previous entry in the array
345              
346             =head1 API SAMPLE
347              
348             {
349             "object": "list",
350             "url": "/v1/refunds",
351             "has_more": false,
352             "data": [
353             {
354             "id": "re_fake123456789",
355             "object": "refund",
356             "amount": 30200,
357             "balance_transaction": "txn_fake123456789",
358             "charge": "ch_fake123456789",
359             "created": 1540736617,
360             "currency": "jpy",
361             "metadata": {},
362             "reason": null,
363             "receipt_number": null,
364             "source_transfer_reversal": null,
365             "status": "succeeded",
366             "transfer_reversal": null
367             },
368             {...},
369             {...}
370             ]
371             }
372              
373             =head1 HISTORY
374              
375             =head2 v0.1
376              
377             Initial version
378              
379             =head2 v0.200
380              
381             Change in version numbering
382              
383             =head1 AUTHOR
384              
385             Jacques Deguest E<lt>F<jack@deguest.jp>E<gt>
386              
387             =head1 SEE ALSO
388              
389             Stripe API documentation:
390              
391             L<https://stripe.com/docs/api>
392              
393             =head1 COPYRIGHT & LICENSE
394              
395             Copyright (c) 2020-2020 DEGUEST Pte. Ltd.
396              
397             You can use, copy, modify and redistribute this package and associated
398             files under the same terms as Perl itself.
399              
400             =cut