The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.
Build.PL 1232
Changes 05
LICENSE 11
MANIFEST 11
META.json 3332
Makefile.PL 2252
README 11
dist.ini 49
examples/OAuthDemo.pm 11
lib/Net/FreshBooks/API/Base.pm 97
lib/Net/FreshBooks/API/Client/Contact.pm 106
lib/Net/FreshBooks/API/Client.pm 86
lib/Net/FreshBooks/API/Estimate.pm 75
lib/Net/FreshBooks/API/Gateway.pm 75
lib/Net/FreshBooks/API/Invoice.pm 912
lib/Net/FreshBooks/API/InvoiceLine.pm 65
lib/Net/FreshBooks/API/Iterator.pm 129
lib/Net/FreshBooks/API/Language.pm 75
lib/Net/FreshBooks/API/Links.pm 75
lib/Net/FreshBooks/API/OAuth.pm 5666
lib/Net/FreshBooks/API/Payment.pm 75
lib/Net/FreshBooks/API/Recurring/AutoBill/Card/Expiration.pm 65
lib/Net/FreshBooks/API/Recurring/AutoBill/Card.pm 108
lib/Net/FreshBooks/API/Recurring/AutoBill.pm 97
lib/Net/FreshBooks/API/Recurring.pm 912
lib/Net/FreshBooks/API/Role/CRUD.pm 86
lib/Net/FreshBooks/API/Role/Common.pm 87
lib/Net/FreshBooks/API/Role/Iterator.pm 86
lib/Net/FreshBooks/API/Role/LineItem.pm 86
lib/Net/FreshBooks/API/Role/SendBy.pm 75
lib/Net/FreshBooks/API.pm 1412
t/001_api.t 27
t/002_base-parameters_to_request_xml.t 44
t/003-client_create.t 66
t/004-client_list.t 23
t/005-invoice_create.t 44
t/006_live_connect.t 118
t/007_live_test.t 1519
t/008-recurring.t 68
t/009-estimate.t 911
t/010-invoice_line.t 33
t/011_error.t 22
t/012_oauth.t 1518
t/013_gateway.t 79
t/014_language.t 1212
t/015_autobill.t 1924
t/config.pl 23
t/release-pod-coverage.t 210
48 files changed (This is a version diff) 447485
@@ -1,4 +1,5 @@
 
+# This file was automatically generated by Dist::Zilla::Plugin::ModuleBuild v5.015.
 use strict;
 use warnings;
 
@@ -7,16 +8,7 @@ use Module::Build 0.3601;
 
 my %module_build_args = (
   "build_requires" => {
-    "DateTime" => 0,
-    "English" => 0,
-    "File::Slurp" => 0,
-    "Module::Build" => "0.3601",
-    "Sub::Override" => 0,
-    "Test::Exception" => 0,
-    "Test::More" => 0,
-    "Test::Simple" => "0.98",
-    "Test::WWW::Mechanize" => 0,
-    "Test::XML" => 0
+    "Module::Build" => "0.3601"
   },
   "configure_requires" => {
     "ExtUtils::MakeMaker" => "6.30",
@@ -28,7 +20,7 @@ my %module_build_args = (
     "Olaf Alders <olaf\@wundercounter.com>"
   ],
   "dist_name" => "Net-FreshBooks-API",
-  "dist_version" => "0.23",
+  "dist_version" => "0.24",
   "license" => "perl",
   "module_name" => "Net::FreshBooks::API",
   "recommends" => {},
@@ -57,10 +49,38 @@ my %module_build_args = (
     "strict" => 0,
     "warnings" => 0
   },
-  "script_files" => []
+  "script_files" => [],
+  "test_requires" => {
+    "DateTime" => 0,
+    "File::Slurp" => 0,
+    "Sub::Override" => 0,
+    "Test::Exception" => 0,
+    "Test::More" => 0,
+    "Test::Simple" => "0.98",
+    "Test::WWW::Mechanize" => 0,
+    "Test::XML" => 0
+  }
 );
 
 
+my %fallback_build_requires = (
+  "DateTime" => 0,
+  "File::Slurp" => 0,
+  "Module::Build" => "0.3601",
+  "Sub::Override" => 0,
+  "Test::Exception" => 0,
+  "Test::More" => 0,
+  "Test::Simple" => "0.98",
+  "Test::WWW::Mechanize" => 0,
+  "Test::XML" => 0
+);
+
+
+unless ( eval { Module::Build->VERSION(0.4004) } ) {
+  delete $module_build_args{test_requires};
+  $module_build_args{build_requires} = \%fallback_build_requires;
+}
+
 my $build = Module::Build->new(%module_build_args);
 
 $build->create_build_script;
@@ -1,5 +1,10 @@
 Revision history for Perl module Net::FreshBooks::API
 
+{{$NEXT}}
+    - Change the no_index rule in order to get PAUSE to remove OAuthDemo from
+      02packages
+    - Disable all live tests by default
+
 0.23 2011-10-20
     - Silences warning which emitted a lot of XML outside of verbose mode
     - Adds docs on how to paginate using an iterator
@@ -22,7 +22,7 @@ This is free software, licensed under:
                      Version 1, February 1989
 
  Copyright (C) 1989 Free Software Foundation, Inc.
-                    51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
  Everyone is permitted to copy and distribute verbatim copies
  of this license document, but changing it is not allowed.
@@ -1,3 +1,4 @@
+# This file was automatically generated by Dist::Zilla::Plugin::Manifest v5.015.
 Build.PL
 Changes
 INSTALL
@@ -53,7 +54,6 @@ t/author-critic.t
 t/config.pl
 t/config_sample.pl
 t/perlcriticrc
-t/release-pod-coverage.t
 t/test_data/client.create.req.xml
 t/test_data/client.create.res.xml
 t/test_data/client.get.req.xml
@@ -5,7 +5,7 @@
       "Olaf Alders <olaf@wundercounter.com>"
    ],
    "dynamic_config" : 0,
-   "generated_by" : "Dist::Zilla version 4.300000, CPAN::Meta::Converter version 2.110930",
+   "generated_by" : "Dist::Zilla version 5.015, CPAN::Meta::Converter version 2.140640",
    "license" : [
       "perl_5"
    ],
@@ -15,8 +15,8 @@
    },
    "name" : "Net-FreshBooks-API",
    "no_index" : {
-      "file" : [
-         "examples/OAuthDemo.pm"
+      "directory" : [
+         "examples"
       ]
    },
    "prereqs" : {
@@ -34,40 +34,39 @@
       "runtime" : {
          "requires" : {
             "B::Hooks::EndOfScope" : "0.09",
-            "Carp" : 0,
-            "Clone" : 0,
-            "Data::Dump" : 0,
-            "LWP::Protocol::https" : 0,
-            "LWP::UserAgent" : 0,
-            "Lingua::EN::Inflect" : 0,
-            "Moose" : 0,
-            "Moose::Role" : 0,
-            "Net::OAuth::Simple" : 0,
-            "Params::Validate" : 0,
-            "Path::Class" : 0,
-            "Scalar::Util" : 0,
-            "URI" : 0,
-            "WWW::Mechanize" : 0,
-            "XML::LibXML" : 0,
-            "XML::Simple" : 0,
-            "base" : 0,
+            "Carp" : "0",
+            "Clone" : "0",
+            "Data::Dump" : "0",
+            "LWP::Protocol::https" : "0",
+            "LWP::UserAgent" : "0",
+            "Lingua::EN::Inflect" : "0",
+            "Moose" : "0",
+            "Moose::Role" : "0",
+            "Net::OAuth::Simple" : "0",
+            "Params::Validate" : "0",
+            "Path::Class" : "0",
+            "Scalar::Util" : "0",
+            "URI" : "0",
+            "WWW::Mechanize" : "0",
+            "XML::LibXML" : "0",
+            "XML::Simple" : "0",
+            "base" : "0",
             "namespace::autoclean" : "0.11",
             "parent" : "0.224",
-            "strict" : 0,
-            "warnings" : 0
+            "strict" : "0",
+            "warnings" : "0"
          }
       },
       "test" : {
          "requires" : {
-            "DateTime" : 0,
-            "English" : 0,
-            "File::Slurp" : 0,
-            "Sub::Override" : 0,
-            "Test::Exception" : 0,
-            "Test::More" : 0,
+            "DateTime" : "0",
+            "File::Slurp" : "0",
+            "Sub::Override" : "0",
+            "Test::Exception" : "0",
+            "Test::More" : "0",
             "Test::Simple" : "0.98",
-            "Test::WWW::Mechanize" : 0,
-            "Test::XML" : 0
+            "Test::WWW::Mechanize" : "0",
+            "Test::XML" : "0"
          }
       }
    },
@@ -79,10 +78,10 @@
       "homepage" : "https://metacpan.org/release/Net-FreshBooks-API",
       "repository" : {
          "type" : "git",
-         "url" : "http://github.com/oalders/net-freshbooks-api",
-         "web" : "http://github.com/oalders/net-freshbooks-api"
+         "url" : "https://github.com/oalders/net-freshbooks-api.git",
+         "web" : "https://github.com/oalders/net-freshbooks-api"
       }
    },
-   "version" : "0.23"
+   "version" : "0.24"
 }
 
@@ -1,4 +1,5 @@
 
+# This file was automatically generated by Dist::Zilla::Plugin::MakeMaker v5.015.
 use strict;
 use warnings;
 
@@ -12,16 +13,7 @@ my %WriteMakefileArgs = (
   "ABSTRACT" => "Easy OO access to the FreshBooks.com API",
   "AUTHOR" => "Edmund von der Burg <evdb\@ecclestoad.co.uk>, Olaf Alders <olaf\@wundercounter.com>",
   "BUILD_REQUIRES" => {
-    "DateTime" => 0,
-    "English" => 0,
-    "File::Slurp" => 0,
-    "Module::Build" => "0.3601",
-    "Sub::Override" => 0,
-    "Test::Exception" => 0,
-    "Test::More" => 0,
-    "Test::Simple" => "0.98",
-    "Test::WWW::Mechanize" => 0,
-    "Test::XML" => 0
+    "Module::Build" => "0.3601"
   },
   "CONFIGURE_REQUIRES" => {
     "ExtUtils::MakeMaker" => "6.30",
@@ -55,24 +47,62 @@ my %WriteMakefileArgs = (
     "strict" => 0,
     "warnings" => 0
   },
-  "VERSION" => "0.23",
+  "TEST_REQUIRES" => {
+    "DateTime" => 0,
+    "File::Slurp" => 0,
+    "Sub::Override" => 0,
+    "Test::Exception" => 0,
+    "Test::More" => 0,
+    "Test::Simple" => "0.98",
+    "Test::WWW::Mechanize" => 0,
+    "Test::XML" => 0
+  },
+  "VERSION" => "0.24",
   "test" => {
     "TESTS" => "t/*.t"
   }
 );
 
 
-unless ( eval { ExtUtils::MakeMaker->VERSION(6.56) } ) {
-  my $br = delete $WriteMakefileArgs{BUILD_REQUIRES};
-  my $pp = $WriteMakefileArgs{PREREQ_PM};
-  for my $mod ( keys %$br ) {
-    if ( exists $pp->{$mod} ) {
-      $pp->{$mod} = $br->{$mod} if $br->{$mod} > $pp->{$mod};
-    }
-    else {
-      $pp->{$mod} = $br->{$mod};
-    }
-  }
+my %FallbackPrereqs = (
+  "B::Hooks::EndOfScope" => "0.09",
+  "Carp" => 0,
+  "Clone" => 0,
+  "Data::Dump" => 0,
+  "DateTime" => 0,
+  "File::Slurp" => 0,
+  "LWP::Protocol::https" => 0,
+  "LWP::UserAgent" => 0,
+  "Lingua::EN::Inflect" => 0,
+  "Module::Build" => "0.3601",
+  "Moose" => 0,
+  "Moose::Role" => 0,
+  "Net::OAuth::Simple" => 0,
+  "Params::Validate" => 0,
+  "Path::Class" => 0,
+  "Scalar::Util" => 0,
+  "Sub::Override" => 0,
+  "Test::Exception" => 0,
+  "Test::More" => 0,
+  "Test::Simple" => "0.98",
+  "Test::WWW::Mechanize" => 0,
+  "Test::XML" => 0,
+  "URI" => 0,
+  "WWW::Mechanize" => 0,
+  "XML::LibXML" => 0,
+  "XML::Simple" => 0,
+  "base" => 0,
+  "namespace::autoclean" => "0.11",
+  "parent" => "0.224",
+  "strict" => 0,
+  "warnings" => 0
+);
+
+
+unless ( eval { ExtUtils::MakeMaker->VERSION(6.63_03) } ) {
+  delete $WriteMakefileArgs{TEST_REQUIRES};
+  delete $WriteMakefileArgs{BUILD_REQUIRES};
+  $WriteMakefileArgs{PREREQ_PM} = \%FallbackPrereqs;
 }
 
 delete $WriteMakefileArgs{CONFIGURE_REQUIRES}
@@ -2,7 +2,7 @@ NAME
     Net::FreshBooks::API - Easy OO access to the FreshBooks.com API
 
 VERSION
-    version 0.23
+    version 0.24
 
 SYNOPSIS
         use Net::FreshBooks::API;
@@ -4,18 +4,18 @@ author  = Olaf Alders <olaf@wundercounter.com>
 license = Perl_5
 copyright_holder = Edmund von der Burg & Olaf Alders
 copyright_year   = 2011
-version = 0.23
+version = 0.24
 main_module = lib/Net/FreshBooks/API.pm
 
 [MetaNoIndex]
-  file = examples/OAuthDemo.pm
+directory = examples
 
 [GatherDir]
 [PruneCruft]
 [ManifestSkip]
 [MetaJSON]
 [License]
-[PodCoverageTests]
+;[PodCoverageTests]
 [ExtraTests]
 [ExecDir]
 [ShareDir]
@@ -45,9 +45,14 @@ LWP::Protocol::https = 0
 Test::Simple = 0.98
 DateTime  = 0
 
-[CriticTests]
+[Test::Perl::Critic]
 [ReadmeFromPod]
 [InstallGuide]
 [ModuleBuild]
 [PodWeaver]
 [CopyReadmeFromBuild]
+
+;[ContributorsFromGit]
+;[ContributorsFile]
+
+[@Git]
@@ -48,7 +48,7 @@ sub run {
         consumer_key    => $self->consumer_key,
         consumer_secret => $self->consumer_secret,
     );
-    
+
     my $app = Net::FreshBooks::API::OAuth->new( %tokens );
 
     # Check to see we have a consumer key and secret
@@ -2,10 +2,7 @@ use strict;
 use warnings;
 
 package Net::FreshBooks::API::Base;
-{
-  $Net::FreshBooks::API::Base::VERSION = '0.23';
-}
-
+$Net::FreshBooks::API::Base::VERSION = '0.24';
 use Moose;
 
 with 'Net::FreshBooks::API::Role::Common';
@@ -14,7 +11,7 @@ use Carp qw( carp croak );
 use Clone qw(clone);
 use Data::Dump qw( dump );
 use Scalar::Util qw( blessed reftype );
-use XML::LibXML ':libxml';
+use XML::LibXML qw( XML_ELEMENT_NODE );
 use XML::Simple;
 use LWP::UserAgent;
 
@@ -232,7 +229,7 @@ sub construct_element {
 
         # scalar values are text nodes
         elsif ( ref $val eq '' ) {
-            $element->appendTextChild( $key, $val );
+            $element->appendTextChild( $key, $val || '' );
         }
 
         # arrayrefs are groups of nested values
@@ -372,17 +369,19 @@ __PACKAGE__->meta->make_immutable( inline_constructor => 1 );
 
 # ABSTRACT: Base class
 
-
 __END__
+
 =pod
 
+=encoding UTF-8
+
 =head1 NAME
 
 Net::FreshBooks::API::Base - Base class
 
 =head1 VERSION
 
-version 0.23
+version 0.24
 
 =head2 new_from_node
 
@@ -526,4 +525,3 @@ This is free software; you can redistribute it and/or modify it under
 the same terms as the Perl 5 programming language system itself.
 
 =cut
-
@@ -2,16 +2,13 @@ use strict;
 use warnings;
 
 package Net::FreshBooks::API::Client::Contact;
-{
-  $Net::FreshBooks::API::Client::Contact::VERSION = '0.23';
-}
-
+$Net::FreshBooks::API::Client::Contact::VERSION = '0.24';
 use Moose;
 extends 'Net::FreshBooks::API::Base';
 
 has $_ => ( is => _fields()->{$_}->{is} ) for sort keys %{ _fields() };
 
-sub node_name { return 'contact' };
+sub node_name { return 'contact' }
 
 sub _fields {
     return {
@@ -25,25 +22,25 @@ sub _fields {
     };
 }
 
-
-
 __PACKAGE__->meta->make_immutable();
 
 1;
 
 # ABSTRACT: Provides FreshBooks Contact objects to Clients and Invoices
 
-
 __END__
+
 =pod
 
+=encoding UTF-8
+
 =head1 NAME
 
 Net::FreshBooks::API::Client::Contact - Provides FreshBooks Contact objects to Clients and Invoices
 
 =head1 VERSION
 
-version 0.23
+version 0.24
 
 =head1 SYNOPSIS
 
@@ -81,4 +78,3 @@ This is free software; you can redistribute it and/or modify it under
 the same terms as the Perl 5 programming language system itself.
 
 =cut
-
@@ -2,10 +2,7 @@ use strict;
 use warnings;
 
 package Net::FreshBooks::API::Client;
-{
-  $Net::FreshBooks::API::Client::VERSION = '0.23';
-}
-
+$Net::FreshBooks::API::Client::VERSION = '0.24';
 use Moose;
 extends 'Net::FreshBooks::API::Base';
 with 'Net::FreshBooks::API::Role::CRUD';
@@ -67,7 +64,7 @@ sub add_contact {
     my $self = shift;
     my $args = shift;
     push @{ $self->{contacts} ||= [] },
-        Net::FreshBooks::API::Client::Contact->new($args);
+        Net::FreshBooks::API::Client::Contact->new( $args );
 }
 
 __PACKAGE__->meta->make_immutable();
@@ -76,17 +73,19 @@ __PACKAGE__->meta->make_immutable();
 
 # ABSTRACT: FreshBooks Client access
 
-
 __END__
+
 =pod
 
+=encoding UTF-8
+
 =head1 NAME
 
 Net::FreshBooks::API::Client - FreshBooks Client access
 
 =head1 VERSION
 
-version 0.23
+version 0.24
 
 =head1 SYNOPSIS
 
@@ -210,4 +209,3 @@ This is free software; you can redistribute it and/or modify it under
 the same terms as the Perl 5 programming language system itself.
 
 =cut
-
@@ -2,10 +2,7 @@ use strict;
 use warnings;
 
 package Net::FreshBooks::API::Estimate;
-{
-  $Net::FreshBooks::API::Estimate::VERSION = '0.23';
-}
-
+$Net::FreshBooks::API::Estimate::VERSION = '0.24';
 use Moose;
 extends 'Net::FreshBooks::API::Base';
 with 'Net::FreshBooks::API::Role::CRUD';
@@ -63,17 +60,19 @@ __PACKAGE__->meta->make_immutable();
 
 # ABSTRACT: FreshBooks Estimate access
 
-
 __END__
+
 =pod
 
+=encoding UTF-8
+
 =head1 NAME
 
 Net::FreshBooks::API::Estimate - FreshBooks Estimate access
 
 =head1 VERSION
 
-version 0.23
+version 0.24
 
 =head1 SYNOPSIS
 
@@ -207,4 +206,3 @@ This is free software; you can redistribute it and/or modify it under
 the same terms as the Perl 5 programming language system itself.
 
 =cut
-
@@ -2,10 +2,7 @@ use strict;
 use warnings;
 
 package Net::FreshBooks::API::Gateway;
-{
-  $Net::FreshBooks::API::Gateway::VERSION = '0.23';
-}
-
+$Net::FreshBooks::API::Gateway::VERSION = '0.24';
 use Moose;
 extends 'Net::FreshBooks::API::Base';
 
@@ -27,17 +24,19 @@ __PACKAGE__->meta->make_immutable();
 
 # ABSTRACT: List gateways available in your FreshBooks account
 
-
 __END__
+
 =pod
 
+=encoding UTF-8
+
 =head1 NAME
 
 Net::FreshBooks::API::Gateway - List gateways available in your FreshBooks account
 
 =head1 VERSION
 
-version 0.23
+version 0.24
 
 =head1 SYNOPSIS
 
@@ -98,4 +97,3 @@ This is free software; you can redistribute it and/or modify it under
 the same terms as the Perl 5 programming language system itself.
 
 =cut
-
@@ -2,10 +2,7 @@ use strict;
 use warnings;
 
 package Net::FreshBooks::API::Invoice;
-{
-  $Net::FreshBooks::API::Invoice::VERSION = '0.23';
-}
-
+$Net::FreshBooks::API::Invoice::VERSION = '0.24';
 use Moose;
 extends 'Net::FreshBooks::API::Base';
 with 'Net::FreshBooks::API::Role::CRUD';
@@ -17,8 +14,13 @@ has $_ => ( is => _fields()->{$_}->{is} ) for sort keys %{ _fields() };
 sub _fields {
     return {
 
-        amount        => { is => 'ro' },
-        client_id     => { is => 'rw' },
+        amount    => { is => 'ro' },
+        client_id => { is => 'rw' },
+        contacts  => {
+            is           => 'rw',
+            made_of      => 'Net::FreshBooks::API::Client::Contact',
+            presented_as => 'array',
+        },
         currency_code => { is => 'rw' },
         date          => { is => 'rw' },
         discount      => { is => 'rw' },
@@ -67,17 +69,19 @@ __PACKAGE__->meta->make_immutable();
 
 # ABSTRACT: FreshBooks Invoice access
 
-
 __END__
+
 =pod
 
+=encoding UTF-8
+
 =head1 NAME
 
 Net::FreshBooks::API::Invoice - FreshBooks Invoice access
 
 =head1 VERSION
 
-version 0.23
+version 0.24
 
 =head1 SYNOPSIS
 
@@ -190,4 +194,3 @@ This is free software; you can redistribute it and/or modify it under
 the same terms as the Perl 5 programming language system itself.
 
 =cut
-
@@ -2,10 +2,7 @@ use strict;
 use warnings;
 
 package Net::FreshBooks::API::InvoiceLine;
-{
-  $Net::FreshBooks::API::InvoiceLine::VERSION = '0.23';
-}
-
+$Net::FreshBooks::API::InvoiceLine::VERSION = '0.24';
 use Moose;
 extends 'Net::FreshBooks::API::Base';
 
@@ -36,15 +33,18 @@ __PACKAGE__->meta->make_immutable();
 # ABSTRACT: Adds Line Item support to FreshBooks Invoices
 
 __END__
+
 =pod
 
+=encoding UTF-8
+
 =head1 NAME
 
 Net::FreshBooks::API::InvoiceLine - Adds Line Item support to FreshBooks Invoices
 
 =head1 VERSION
 
-version 0.23
+version 0.24
 
 =head1 AUTHORS
 
@@ -68,4 +68,3 @@ This is free software; you can redistribute it and/or modify it under
 the same terms as the Perl 5 programming language system itself.
 
 =cut
-
@@ -2,15 +2,11 @@ use strict;
 use warnings;
 
 package Net::FreshBooks::API::Iterator;
-{
-  $Net::FreshBooks::API::Iterator::VERSION = '0.23';
-}
-
+$Net::FreshBooks::API::Iterator::VERSION = '0.24';
 use Moose;
 
-use Data::Dump qw( dump );
 use Lingua::EN::Inflect qw( PL );
-use XML::LibXML ':libxml';
+use XML::LibXML qw( XML_ELEMENT_NODE );
 
 has 'parent_object' => ( is => 'rw' );    # The object we are iterating for
 has 'args'          => ( is => 'rw' );    # args used in the search
@@ -44,8 +40,8 @@ sub new {
     my $parser = XML::LibXML->new();
 
     my @item_nodes =    #
-        map { $parser->parse_string( $_->toString ) }    # recreate
-        grep { $_->nodeType eq XML_ELEMENT_NODE }        # filter
+        map  { $parser->parse_string( $_->toString ) }    # recreate
+        grep { $_->nodeType eq XML_ELEMENT_NODE }         # filter
         $list->childNodes;
 
     $self->item_nodes( \@item_nodes );
@@ -53,7 +49,7 @@ sub new {
     return $self;
 }
 
-sub next {                                               ## no critic
+sub next {                                                ## no critic
     ## use critic
     my $self = shift;
 
@@ -79,17 +75,19 @@ __PACKAGE__->meta->make_immutable( inline_constructor => 0 );
 
 # ABSTRACT: FreshBooks Iterator objects
 
-
 __END__
+
 =pod
 
+=encoding UTF-8
+
 =head1 NAME
 
 Net::FreshBooks::API::Iterator - FreshBooks Iterator objects
 
 =head1 VERSION
 
-version 0.23
+version 0.24
 
 =head1 SYNOPSIS
 
@@ -162,4 +160,3 @@ This is free software; you can redistribute it and/or modify it under
 the same terms as the Perl 5 programming language system itself.
 
 =cut
-
@@ -2,10 +2,7 @@ use strict;
 use warnings;
 
 package Net::FreshBooks::API::Language;
-{
-  $Net::FreshBooks::API::Language::VERSION = '0.23';
-}
-
+$Net::FreshBooks::API::Language::VERSION = '0.24';
 use Moose;
 extends 'Net::FreshBooks::API::Base';
 
@@ -27,17 +24,19 @@ __PACKAGE__->meta->make_immutable();
 
 # ABSTRACT: List the languages your FreshBooks account supports
 
-
 __END__
+
 =pod
 
+=encoding UTF-8
+
 =head1 NAME
 
 Net::FreshBooks::API::Language - List the languages your FreshBooks account supports
 
 =head1 VERSION
 
-version 0.23
+version 0.24
 
 =head1 SYNOPSIS
 
@@ -93,4 +92,3 @@ This is free software; you can redistribute it and/or modify it under
 the same terms as the Perl 5 programming language system itself.
 
 =cut
-
@@ -2,10 +2,7 @@ use strict;
 use warnings;
 
 package Net::FreshBooks::API::Links;
-{
-  $Net::FreshBooks::API::Links::VERSION = '0.23';
-}
-
+$Net::FreshBooks::API::Links::VERSION = '0.24';
 use Moose;
 extends 'Net::FreshBooks::API::Base';
 
@@ -26,17 +23,19 @@ __PACKAGE__->meta->make_immutable();
 
 # ABSTRACT: Provides FreshBooks Link objects to Clients and Invoices
 
-
 __END__
+
 =pod
 
+=encoding UTF-8
+
 =head1 NAME
 
 Net::FreshBooks::API::Links - Provides FreshBooks Link objects to Clients and Invoices
 
 =head1 VERSION
 
-version 0.23
+version 0.24
 
 =head1 SYNOPSIS
 
@@ -91,4 +90,3 @@ This is free software; you can redistribute it and/or modify it under
 the same terms as the Perl 5 programming language system itself.
 
 =cut
-
@@ -2,10 +2,7 @@ use strict;
 use warnings;
 
 package Net::FreshBooks::API::OAuth;
-{
-  $Net::FreshBooks::API::OAuth::VERSION = '0.23';
-}
-
+$Net::FreshBooks::API::OAuth::VERSION = '0.24';
 use base qw(Net::OAuth::Simple);
 
 use Carp qw( croak );
@@ -22,9 +19,9 @@ sub new {
             croak( "$key required as an argument to new()" );
         }
     }
-    
+
     my $account_name = delete $tokens{account_name};
-    
+
     my $url = 'https://' . $account_name . '.freshbooks.com/oauth';
 
     my %create = (
@@ -112,23 +109,23 @@ sub request_access_token {
     my %params = @_;
     my $url    = $self->access_token_url;
 
-    $params{token}        = $self->request_token        unless defined $params{token};
-    $params{token_secret} = $self->request_token_secret unless defined $params{token_secret};
+    $params{token} = $self->request_token unless defined $params{token};
+    $params{token_secret} = $self->request_token_secret
+        unless defined $params{token_secret};
 
-    if ($self->oauth_1_0a) {
-        $params{verifier} = $self->verifier                             unless defined $params{verifier};
-        return $self->_error("You must pass a verified parameter when using OAuth v1.0a") unless defined $params{verifier};
+    if ( $self->oauth_1_0a ) {
+        $params{verifier} = $self->verifier unless defined $params{verifier};
+        return $self->_error(
+            "You must pass a verified parameter when using OAuth v1.0a" )
+            unless defined $params{verifier};
 
     }
 
+    my $access_token_response
+        = $self->_make_request( 'Net::OAuth::AccessTokenRequest',
+        $url, 'POST', %params, );
 
-    my $access_token_response = $self->_make_request(
-        'Net::OAuth::AccessTokenRequest',
-        $url, 'POST',
-        %params,
-    );
-
-    return $self->_decode_tokens($url, $access_token_response);
+    return $self->_decode_tokens( $url, $access_token_response );
 }
 
 sub request_request_token {
@@ -136,44 +133,49 @@ sub request_request_token {
     my %params = @_;
     my $url    = $self->request_token_url;
 
-    if ($self->oauth_1_0a) {
-        $params{callback} = $self->callback                             unless defined $params{callback};
-        return $self->_error("You must pass a callback parameter when using OAuth v1.0a") unless defined $params{callback};
+    if ( $self->oauth_1_0a ) {
+        $params{callback} = $self->callback unless defined $params{callback};
+        return $self->_error(
+            "You must pass a callback parameter when using OAuth v1.0a" )
+            unless defined $params{callback};
     }
 
-    my $request_token_response = $self->_make_request(
-        'Net::OAuth::RequestTokenRequest',
-        $url, 'POST',
-        %params);
+    my $request_token_response
+        = $self->_make_request( 'Net::OAuth::RequestTokenRequest',
+        $url, 'POST', %params );
 
-    return $self->_error("GET for $url failed: ".$request_token_response->status_line)
-      unless ( $request_token_response->is_success );
+    return $self->_error(
+        "GET for $url failed: " . $request_token_response->status_line )
+        unless ( $request_token_response->is_success );
 
     # Cast response into CGI query for EZ parameter decoding
-    my $request_token_response_query =
-      new CGI( $request_token_response->content );
+    my $request_token_response_query
+        = new CGI( $request_token_response->content );
 
     # Split out token and secret parameters from the request token response
-    $self->request_token($request_token_response_query->param('oauth_token'));
-    $self->request_token_secret($request_token_response_query->param('oauth_token_secret'));
-    $self->callback_confirmed($request_token_response_query->param('oauth_callback_confirmed'));
+    $self->request_token(
+        $request_token_response_query->param( 'oauth_token' ) );
+    $self->request_token_secret(
+        $request_token_response_query->param( 'oauth_token_secret' ) );
+    $self->callback_confirmed(
+        $request_token_response_query->param( 'oauth_callback_confirmed' ) );
 
-    return $self->_error("Response does not confirm to OAuth1.0a. oauth_callback_confirmed not received")
-     if $self->oauth_1_0a && !$self->callback_confirmed;
+    return $self->_error(
+        "Response does not confirm to OAuth1.0a. oauth_callback_confirmed not received"
+    ) if $self->oauth_1_0a && !$self->callback_confirmed;
 
 }
 
-
 sub _make_request {
-    my $self    = shift;
-    my $class   = shift;
-    my $url     = shift;
-    my $method  = uc(shift);
-    my @extra   = @_;
+    my $self   = shift;
+    my $class  = shift;
+    my $url    = shift;
+    my $method = uc( shift );
+    my @extra  = @_;
 
-    my $uri   = URI->new($url);
+    my $uri   = URI->new( $url );
     my %query = $uri->query_form;
-    $uri->query_form({});
+    $uri->query_form( {} );
 
     my $request = $class->new(
         consumer_key     => $self->consumer_key,
@@ -181,22 +183,28 @@ sub _make_request {
         request_url      => $uri,
         request_method   => $method,
         signature_method => $self->signature_method,
-        protocol_version => $self->oauth_1_0a ? Net::OAuth::PROTOCOL_VERSION_1_0A : Net::OAuth::PROTOCOL_VERSION_1_0,
-        timestamp        => time,
-        nonce            => $self->_nonce,
-        extra_params     => \%query,
+        protocol_version => $self->oauth_1_0a
+        ? Net::OAuth::PROTOCOL_VERSION_1_0A
+        : Net::OAuth::PROTOCOL_VERSION_1_0,
+        timestamp    => time,
+        nonce        => $self->_nonce,
+        extra_params => \%query,
         @extra,
     );
     $request->sign;
-    return $self->_error("Couldn't verify request! Check OAuth parameters.")
-      unless $request->verify;
+    return $self->_error( "Couldn't verify request! Check OAuth parameters." )
+        unless $request->verify;
 
-    my $params  = $request->to_hash;
-    $uri->query_form(%$params);
-    my $req      = HTTP::Request->new( $method => "$uri");
-    my $response = $self->{browser}->request($req);
-    return $self->_error("$method on ".$request->normalized_request_url." failed: ".$response->status_line." - ".$response->content)
-      unless ( $response->is_success );
+    my $params = $request->to_hash;
+    $uri->query_form( %$params );
+    my $req = HTTP::Request->new( $method => "$uri" );
+    my $response = $self->{browser}->request( $req );
+    return $self->_error( "$method on "
+            . $request->normalized_request_url
+            . " failed: "
+            . $response->status_line . " - "
+            . $response->content )
+        unless ( $response->is_success );
 
     return $response;
 }
@@ -207,15 +215,18 @@ sub _make_request {
 1;
 
 __END__
+
 =pod
 
+=encoding UTF-8
+
 =head1 NAME
 
 Net::FreshBooks::API::OAuth - FreshBooks OAuth implementation
 
 =head1 VERSION
 
-version 0.23
+version 0.24
 
 =head2 DESCRIPTION
 
@@ -295,4 +306,3 @@ This is free software; you can redistribute it and/or modify it under
 the same terms as the Perl 5 programming language system itself.
 
 =cut
-
@@ -2,10 +2,7 @@ use strict;
 use warnings;
 
 package Net::FreshBooks::API::Payment;
-{
-  $Net::FreshBooks::API::Payment::VERSION = '0.23';
-}
-
+$Net::FreshBooks::API::Payment::VERSION = '0.24';
 use Moose;
 extends 'Net::FreshBooks::API::Base';
 with 'Net::FreshBooks::API::Role::CRUD';
@@ -34,17 +31,19 @@ __PACKAGE__->meta->make_immutable();
 
 # ABSTRACT: FreshBooks Payment access
 
-
 __END__
+
 =pod
 
+=encoding UTF-8
+
 =head1 NAME
 
 Net::FreshBooks::API::Payment - FreshBooks Payment access
 
 =head1 VERSION
 
-version 0.23
+version 0.24
 
 =head1 SYNOPSIS
 
@@ -110,4 +109,3 @@ This is free software; you can redistribute it and/or modify it under
 the same terms as the Perl 5 programming language system itself.
 
 =cut
-
@@ -2,10 +2,7 @@ use strict;
 use warnings;
 
 package Net::FreshBooks::API::Recurring::AutoBill::Card::Expiration;
-{
-  $Net::FreshBooks::API::Recurring::AutoBill::Card::Expiration::VERSION = '0.23';
-}
-
+$Net::FreshBooks::API::Recurring::AutoBill::Card::Expiration::VERSION = '0.24';
 use Moose;
 extends 'Net::FreshBooks::API::Base';
 
@@ -36,15 +33,18 @@ __PACKAGE__->meta->make_immutable();
 # ABSTRACT: FreshBooks Autobill Credit Card Expiration access
 
 __END__
+
 =pod
 
+=encoding UTF-8
+
 =head1 NAME
 
 Net::FreshBooks::API::Recurring::AutoBill::Card::Expiration - FreshBooks Autobill Credit Card Expiration access
 
 =head1 VERSION
 
-version 0.23
+version 0.24
 
 =head1 AUTHORS
 
@@ -68,4 +68,3 @@ This is free software; you can redistribute it and/or modify it under
 the same terms as the Perl 5 programming language system itself.
 
 =cut
-
@@ -2,19 +2,16 @@ use strict;
 use warnings;
 
 package Net::FreshBooks::API::Recurring::AutoBill::Card;
-{
-  $Net::FreshBooks::API::Recurring::AutoBill::Card::VERSION = '0.23';
-}
-
+$Net::FreshBooks::API::Recurring::AutoBill::Card::VERSION = '0.24';
 use Moose;
 extends 'Net::FreshBooks::API::Base';
 
 use Net::FreshBooks::API::Recurring::AutoBill::Card::Expiration;
 
 has 'expiration' => (
-    is      => 'rw',
+    is         => 'rw',
     lazy_build => 1,
-    handles => [ 'month', 'year' ],
+    handles    => [ 'month', 'year' ],
 );
 
 has 'name' => ( is => 'rw', );
@@ -46,7 +43,7 @@ sub _validates {
 }
 
 sub _build_expiration {
-    
+
     my $self = shift;
     return Net::FreshBooks::API::Recurring::AutoBill::Card::Expiration->new;
 }
@@ -57,17 +54,19 @@ __PACKAGE__->meta->make_immutable();
 
 # ABSTRACT: FreshBooks Autobill Credit Card access
 
-
 __END__
+
 =pod
 
+=encoding UTF-8
+
 =head1 NAME
 
 Net::FreshBooks::API::Recurring::AutoBill::Card - FreshBooks Autobill Credit Card access
 
 =head1 VERSION
 
-version 0.23
+version 0.24
 
 =head2 expiration
 
@@ -132,4 +131,3 @@ This is free software; you can redistribute it and/or modify it under
 the same terms as the Perl 5 programming language system itself.
 
 =cut
-
@@ -2,10 +2,7 @@ use strict;
 use warnings;
 
 package Net::FreshBooks::API::Recurring::AutoBill;
-{
-  $Net::FreshBooks::API::Recurring::AutoBill::VERSION = '0.23';
-}
-
+$Net::FreshBooks::API::Recurring::AutoBill::VERSION = '0.24';
 use Net::FreshBooks::API::Recurring::AutoBill::Card;
 
 use Moose;
@@ -47,8 +44,8 @@ sub _validates {
 
     return 0 if $self->card->number && $self->card->number =~ m{\*};
 
-    return 1 if 
-        ( $self->gateway_name
+    return 1
+        if ( $self->gateway_name
         || $self->card->name
         || $self->card->month
         || $self->card->year );
@@ -72,17 +69,19 @@ __PACKAGE__->meta->make_immutable();
 
 # ABSTRACT: Adds AutoBill support to FreshBooks Recurring Items
 
-
 __END__
+
 =pod
 
+=encoding UTF-8
+
 =head1 NAME
 
 Net::FreshBooks::API::Recurring::AutoBill - Adds AutoBill support to FreshBooks Recurring Items
 
 =head1 VERSION
 
-version 0.23
+version 0.24
 
 =head1 SYNOPSIS
 
@@ -180,4 +179,3 @@ This is free software; you can redistribute it and/or modify it under
 the same terms as the Perl 5 programming language system itself.
 
 =cut
-
@@ -2,10 +2,7 @@ use strict;
 use warnings;
 
 package Net::FreshBooks::API::Recurring;
-{
-  $Net::FreshBooks::API::Recurring::VERSION = '0.23';
-}
-
+$Net::FreshBooks::API::Recurring::VERSION = '0.24';
 use Moose;
 extends 'Net::FreshBooks::API::Base';
 with 'Net::FreshBooks::API::Role::CRUD';
@@ -32,8 +29,13 @@ sub _fields {
 
     return {
 
-        amount        => { is => 'ro' },
-        client_id     => { is => 'rw' },
+        amount    => { is => 'ro' },
+        client_id => { is => 'rw' },
+        contacts  => {
+            is           => 'rw',
+            made_of      => 'Net::FreshBooks::API::Client::Contact',
+            presented_as => 'array',
+        },
         currency_code => { is => 'rw' },
         date          => { is => 'rw' },
         discount      => { is => 'rw' },
@@ -82,17 +84,19 @@ __PACKAGE__->meta->make_immutable();
 
 # ABSTRACT: FreshBooks Recurring Item access
 
-
 __END__
+
 =pod
 
+=encoding UTF-8
+
 =head1 NAME
 
 Net::FreshBooks::API::Recurring - FreshBooks Recurring Item access
 
 =head1 VERSION
 
-version 0.23
+version 0.24
 
 =head1 SYNOPSIS
 
@@ -250,4 +254,3 @@ This is free software; you can redistribute it and/or modify it under
 the same terms as the Perl 5 programming language system itself.
 
 =cut
-
@@ -2,10 +2,7 @@ use strict;
 use warnings;
 
 package Net::FreshBooks::API::Role::CRUD;
-{
-  $Net::FreshBooks::API::Role::CRUD::VERSION = '0.23';
-}
-
+$Net::FreshBooks::API::Role::CRUD::VERSION = '0.24';
 use Moose::Role;
 use Data::Dump qw( dump );
 use Scalar::Util qw( blessed );
@@ -65,7 +62,7 @@ sub update {
 
     my %args = ();
     for my $field ( $self->field_names_rw, $self->id_field ) {
-        
+
         # we're not forcing fields to be objects.  for example, setting a
         # field to undef will send an empty element, which is how autobill,
         # for example, can be deleted
@@ -109,17 +106,19 @@ sub delete {    ## no critic
 
 # ABSTRACT: Create, Read and Update roles
 
-
 __END__
+
 =pod
 
+=encoding UTF-8
+
 =head1 NAME
 
 Net::FreshBooks::API::Role::CRUD - Create, Read and Update roles
 
 =head1 VERSION
 
-version 0.23
+version 0.24
 
 =head1 SYNOPSIS
 
@@ -158,4 +157,3 @@ This is free software; you can redistribute it and/or modify it under
 the same terms as the Perl 5 programming language system itself.
 
 =cut
-
@@ -2,10 +2,7 @@ use strict;
 use warnings;
 
 package Net::FreshBooks::API::Role::Common;
-{
-  $Net::FreshBooks::API::Role::Common::VERSION = '0.23';
-}
-
+$Net::FreshBooks::API::Role::Common::VERSION = '0.24';
 use Moose::Role;
 use Carp qw( carp croak );
 use Data::Dump qw( dump );
@@ -18,7 +15,8 @@ has '_return_xml'  => ( is => 'rw', isa => 'Str' );
 has '_request_xml' => ( is => 'rw', isa => 'Str' );
 
 sub _build_die_on_server_error { return 1; }
-sub _build_verbose             {
+
+sub _build_verbose {
     return 1 if $ENV{VERBOSE} || $ENV{DEBUG};
     return 0;
 }
@@ -55,17 +53,19 @@ sub _log {    ## no critic
 
 # ABSTRACT: Roles common to both Base.pm and API.pm
 
-
 __END__
+
 =pod
 
+=encoding UTF-8
+
 =head1 NAME
 
 Net::FreshBooks::API::Role::Common - Roles common to both Base.pm and API.pm
 
 =head1 VERSION
 
-version 0.23
+version 0.24
 
 =head1 SYNOPSIS
 
@@ -97,4 +97,3 @@ This is free software; you can redistribute it and/or modify it under
 the same terms as the Perl 5 programming language system itself.
 
 =cut
-
@@ -2,10 +2,7 @@ use strict;
 use warnings;
 
 package Net::FreshBooks::API::Role::Iterator;
-{
-  $Net::FreshBooks::API::Role::Iterator::VERSION = '0.23';
-}
-
+$Net::FreshBooks::API::Role::Iterator::VERSION = '0.24';
 use Moose::Role;
 use Data::Dump qw( dump );
 
@@ -31,7 +28,7 @@ sub get_all {
     # override any pagination
     $args->{per_page} = 100;
 
-    my @all     = ();
+    my @all      = ();
     my $per_page = 100;
     my $page     = 1;
 
@@ -70,17 +67,19 @@ sub list {
 
 # ABSTRACT: Read-only roles
 
-
 __END__
+
 =pod
 
+=encoding UTF-8
+
 =head1 NAME
 
 Net::FreshBooks::API::Role::Iterator - Read-only roles
 
 =head1 VERSION
 
-version 0.23
+version 0.24
 
 =head1 SYNOPSIS
 
@@ -122,4 +121,3 @@ This is free software; you can redistribute it and/or modify it under
 the same terms as the Perl 5 programming language system itself.
 
 =cut
-
@@ -2,10 +2,7 @@ use strict;
 use warnings;
 
 package Net::FreshBooks::API::Role::LineItem;
-{
-  $Net::FreshBooks::API::Role::LineItem::VERSION = '0.23';
-}
-
+$Net::FreshBooks::API::Role::LineItem::VERSION = '0.24';
 use Moose::Role;
 use Net::FreshBooks::API::InvoiceLine;
 use Data::Dump qw( dump );
@@ -15,7 +12,7 @@ sub add_line {
     my $line_args = shift;
 
     push @{ $self->{lines} ||= [] },
-        Net::FreshBooks::API::InvoiceLine->new($line_args);
+        Net::FreshBooks::API::InvoiceLine->new( $line_args );
 
     return 1;
 }
@@ -24,17 +21,19 @@ sub add_line {
 
 # ABSTRACT: Line Item roles
 
-
 __END__
+
 =pod
 
+=encoding UTF-8
+
 =head1 NAME
 
 Net::FreshBooks::API::Role::LineItem - Line Item roles
 
 =head1 VERSION
 
-version 0.23
+version 0.24
 
 =head1 SYNOPSIS
 
@@ -65,4 +64,3 @@ This is free software; you can redistribute it and/or modify it under
 the same terms as the Perl 5 programming language system itself.
 
 =cut
-
@@ -2,10 +2,7 @@ use strict;
 use warnings;
 
 package Net::FreshBooks::API::Role::SendBy;
-{
-  $Net::FreshBooks::API::Role::SendBy::VERSION = '0.23';
-}
-
+$Net::FreshBooks::API::Role::SendBy::VERSION = '0.24';
 use Moose::Role;
 use Data::Dump qw( dump );
 
@@ -42,17 +39,19 @@ sub _send_using {
 
 # ABSTRACT: Send by email and snail mail roles
 
-
 __END__
+
 =pod
 
+=encoding UTF-8
+
 =head1 NAME
 
 Net::FreshBooks::API::Role::SendBy - Send by email and snail mail roles
 
 =head1 VERSION
 
-version 0.23
+version 0.24
 
 =head1 SYNOPSIS
 
@@ -86,4 +85,3 @@ This is free software; you can redistribute it and/or modify it under
 the same terms as the Perl 5 programming language system itself.
 
 =cut
-
@@ -2,9 +2,7 @@ use strict;
 use warnings;
 
 package Net::FreshBooks::API;
-{
-  $Net::FreshBooks::API::VERSION = '0.23';
-}
+$Net::FreshBooks::API::VERSION = '0.24';
 use Moose;
 
 with 'Net::FreshBooks::API::Role::Common';
@@ -28,12 +26,12 @@ use Path::Class;
 use WWW::Mechanize;
 use URI;
 
-has 'account_name'        => ( is => 'rw' );
-has 'auth_token'          => ( is => 'rw' );
-has 'api_version'         => ( is => 'rw', default => 2.1 );
-has 'auth_realm'          => ( is => 'rw', default => 'FreshBooks' );
-has 'ua'                  => ( is => 'rw', lazy_build => 1 );
-has 'ua_name'             => ( is => 'rw', lazy_build => 1 );
+has 'account_name' => ( is => 'rw' );
+has 'auth_token'   => ( is => 'rw' );
+has 'api_version'  => ( is => 'rw', default => 2.1 );
+has 'auth_realm'   => ( is => 'rw', default => 'FreshBooks' );
+has 'ua'           => ( is => 'rw', lazy_build => 1 );
+has 'ua_name'      => ( is => 'rw', lazy_build => 1 );
 
 # oauth methods
 has 'access_token'        => ( is => 'rw' );
@@ -134,7 +132,7 @@ sub _build_ua {
         $self->auth_token,                # username
         ''                                # password (none - all in username)
     );
-    
+
     $ua->credentials(                     #
         $self->service_url->host_port,    # net loc
         '',                               # realm (none)
@@ -145,7 +143,6 @@ sub _build_ua {
     return $ua;
 }
 
-
 sub delete_everything_from_this_test_account {
 
     my $self = shift;
@@ -217,17 +214,19 @@ __PACKAGE__->meta->make_immutable();
 
 # ABSTRACT: Easy OO access to the FreshBooks.com API
 
-
 __END__
+
 =pod
 
+=encoding UTF-8
+
 =head1 NAME
 
 Net::FreshBooks::API - Easy OO access to the FreshBooks.com API
 
 =head1 VERSION
 
-version 0.23
+version 0.24
 
 =head1 SYNOPSIS
 
@@ -553,4 +552,3 @@ This is free software; you can redistribute it and/or modify it under
 the same terms as the Perl 5 programming language system itself.
 
 =cut
-
@@ -1,7 +1,8 @@
 #!/usr/bin/env perl
 
 use strict;
-use Data::Dump qw( dump );
+use warnings;
+
 use Test::More tests => 8;
 
 use Net::FreshBooks::API;
@@ -44,4 +45,8 @@ ok( !$bad_name->account_name_ok, "invalid service url is not found" );
 
 my $good_name
     = Net::FreshBooks::API->new( account_name => 'netfreshbooksapi' );
-ok( $good_name->account_name_ok, "valid service url is found" );
+
+SKIP: {
+    skip 'live tests not enabled', 1, unless $ENV{FB_LIVE_TESTS};
+    ok( $good_name->account_name_ok, "valid service url is found" );
+}
@@ -15,7 +15,7 @@ my @tests = (
             page     => 1,
             per_page => 15,
         },
-        out => read_file('t/test_data/client.list.req.xml') . '',
+        out => read_file( 't/test_data/client.list.req.xml' ) . '',
     },
 
     {   name => 'nested request',
@@ -27,7 +27,7 @@ my @tests = (
                 { baz => 'bundy2' },
             ],
         },
-        out => read_file('t/test_data/nested.req.xml') . '',
+        out => read_file( 't/test_data/nested.req.xml' ) . '',
     },
 
     {   name => 'client.create request',
@@ -50,7 +50,7 @@ my @tests = (
                 p_code       => '553132',
             }
         },
-        out => read_file('t/test_data/client.create.req.xml') . '',
+        out => read_file( 't/test_data/client.create.req.xml' ) . '',
     },
 
 );
@@ -60,7 +60,7 @@ plan tests => 1 + @tests;
 my $class = 'Net::FreshBooks::API::Client';
 use_ok $class;
 
-foreach my $test (@tests) {
+foreach my $test ( @tests ) {
     my $xml = $class->parameters_to_request_xml( $test->{in} );
     is_xml( $xml, $test->{out}, $test->{name} )
         || die;
@@ -36,7 +36,7 @@ my $client_create_args = {
 };
 
 my @caught_out_xml = ();
-my @fake_return_xml = map { read_file($_) . '' }
+my @fake_return_xml = map { read_file( $_ ) . '' }
     ( 't/test_data/client.create.res.xml', 't/test_data/client.get.res.xml' );
 
 # Intercept the call to freshbooks with our own data
@@ -57,23 +57,23 @@ my $fb = Net::FreshBooks::API->new(
 );
 ok $fb, "created the FB object";
 
-foreach my $method ( sort keys %{$fb->client->_fields() } ) {
-    can_ok( $fb->client, $method );    
+foreach my $method ( sort keys %{ $fb->client->_fields() } ) {
+    can_ok( $fb->client, $method );
 }
 
-my $client = $fb->client->create($client_create_args);
+my $client = $fb->client->create( $client_create_args );
 ok $client,     "Got a client back";
 isa_ok $client, 'Net::FreshBooks::API::Client';
 
 # Check that the xml sent was correct.
 is_xml(
     $caught_out_xml[0],
-    read_file('t/test_data/client.create.req.xml') . '',
+    read_file( 't/test_data/client.create.req.xml' ) . '',
     "xml sent was correct for create"
 );
 is_xml(
     $caught_out_xml[1],
-    read_file('t/test_data/client.get.req.xml') . '',
+    read_file( 't/test_data/client.get.req.xml' ) . '',
     "xml sent was correct for get"
 );
 
@@ -9,7 +9,7 @@ use Test::XML;
 use_ok 'Net::FreshBooks::API';
 
 my @caught_out_xml = ();
-my @fake_return_xml = map { read_file($_) . '' } (
+my @fake_return_xml = map { read_file( $_ ) . '' } (
     't/test_data/client.list.res.xml',    #
     't/test_data/client.get.res.xml',
 );
@@ -44,7 +44,7 @@ isa_ok $list, 'Net::FreshBooks::API::Iterator';
 # check that the correct xml was sent out.
 is_xml(
     $caught_out_xml[0],
-    read_file('t/test_data/client.list.req.xml') . '',
+    read_file( 't/test_data/client.list.req.xml' ) . '',
     "xml sent was correct for list"
 );
 
@@ -55,4 +55,5 @@ is $list->pages, 1, "only one page of results";
 # Get the first entry
 my $client = $list->next;
 ok $client, "got a client";
+
 #is $client->credit, 123.45, "got correct credit";
@@ -79,10 +79,10 @@ is $invoice->status, 'draft', 'status is correct';
 is $invoice->links->client_view,
     'https://hinuhinutest.freshbooks.com/inv/106252-2-80cad',
     "client_view correct";
-    
-ok( $invoice->die_on_server_error, "invoice will die");
 
-$invoice->die_on_server_error(0);
-ok (!$invoice->die_on_server_error, "die on error turned off");
+ok( $invoice->die_on_server_error, "invoice will die" );
+
+$invoice->die_on_server_error( 0 );
+ok( !$invoice->die_on_server_error, "die on error turned off" );
 
 done_testing();
@@ -3,24 +3,21 @@
 use strict;
 use Test::More;
 
-#BEGIN {
-#    use Log::Log4perl;
-#    Log::Log4perl::init('t/log4perl.conf');
-#}
-
 use Net::FreshBooks::API;
 
-plan -r 't/config.pl' && require('t/config.pl')
+plan -r 't/config.pl'
+    && require( 't/config.pl' )
+    && $ENV{FB_LIVE_TESTS}
     ? ( tests => 3 )
-    : ( skip_all => "Need test connection details in t/config.pl"
-        . " - see t/config_sample.pl for details" );
+    : (
+    skip_all => 'Set FB_LIVE_TESTS to true in your %ENV to run live tests' );
 
-ok FBTest->get('auth_token') && FBTest->get('account_name'),
+ok FBTest->get( 'auth_token' ) && FBTest->get( 'account_name' ),
     "Could get auth_token and account_name";
 
 my $fb = Net::FreshBooks::API->new(
-    {   auth_token   => FBTest->get('auth_token'),
-        account_name => FBTest->get('account_name'),
+    {   auth_token   => FBTest->get( 'auth_token' ),
+        account_name => FBTest->get( 'account_name' ),
         verbose      => 0,
     }
 );
@@ -12,22 +12,23 @@ use Net::FreshBooks::API;
 use Net::FreshBooks::API::Client::Contact;
 use Test::WWW::Mechanize;
 
-plan -r 't/config.pl' && require('t/config.pl')
+plan -r 't/config.pl'
+    && require( 't/config.pl' )
+    && $ENV{FB_LIVE_TESTS}
     ? ( tests => 28 )
-    : ( skip_all => "Need test connection details in t/config.pl"
-        . " - see t/config_sample.pl for details" );
+    : (
+    skip_all => 'Set FB_LIVE_TESTS to true in your %ENV to run live tests' );
 
-my $test_email = FBTest->get('test_email') || die;
+my $test_email = FBTest->get( 'test_email' ) || die;
 
 # create the FB object
 my $fb = Net::FreshBooks::API->new(
-    {   auth_token   => FBTest->get('auth_token'),
-        account_name => FBTest->get('account_name'),
+    {   auth_token   => FBTest->get( 'auth_token' ),
+        account_name => FBTest->get( 'account_name' ),
     }
 );
 ok $fb, "created the FB object";
 
-
 $fb->delete_everything_from_this_test_account();
 
 # create a new client
@@ -50,7 +51,7 @@ ok $client, "Created a new client";
 
 # update the client - check that the changes stick
 isnt $client->organization, 'foobar', 'organization is not foobar';
-$client->organization('foobar');
+$client->organization( 'foobar' );
 is $client->organization, 'foobar', 'organization is foobar';
 ok $client->update, "update the client";
 {
@@ -60,7 +61,7 @@ ok $client->update, "update the client";
         "Client has been updated on FB";
 }
 
-foreach my $alpha ('a'..'e') {
+foreach my $alpha ( 'a' .. 'e' ) {
 
     ok( $client->add_contact(
             {   username   => 'net' . time() . $alpha,
@@ -76,17 +77,20 @@ foreach my $alpha ('a'..'e') {
 }
 my $dt = DateTime->now();
 $client->organization( $dt->ymd . '-' . $dt->hms );
-#$client->verbose(1);
 
 ok( $client->update, "can update client" );
 
-my $updated = $fb->client->get({ client_id => $client->client_id });
+my $updated = $fb->client->get( { client_id => $client->client_id } );
 
-foreach my $contact (@{$client->contacts}) {
-    diag( $contact->last_name );
+foreach my $contact ( @{ $updated->contacts } ) {
+    diag(
+        sprintf(
+            "contact: %s (%s)",
+            $contact->last_name, $contact->contact_id
+        )
+    );
 }
-
-cmp_ok( scalar @{$client->contacts}, '==', 5, "5 contacts created");
+cmp_ok( scalar @{ $client->contacts }, '==', 5, "5 contacts created" );
 
 # create an invoice for this client
 my $return_uri = 'http://www.google.com';
@@ -7,10 +7,12 @@ use Data::Dump qw( dump );
 use DateTime;
 use Test::More;
 
-plan -r 't/config.pl' && require( 't/config.pl' )
+plan -r 't/config.pl'
+    && require( 't/config.pl' )
+    && $ENV{FB_LIVE_TESTS}
     ? ( tests => 102 )
-    : ( skip_all => "Need test connection details in t/config.pl"
-        . " - see t/config_sample.pl for details" );
+    : (
+    skip_all => 'Set FB_LIVE_TESTS to true in your %ENV to run live tests' );
 
 use_ok 'Net::FreshBooks::API';
 
@@ -18,7 +20,7 @@ use_ok 'Net::FreshBooks::API';
 my $fb = Net::FreshBooks::API->new(
     {   auth_token   => FBTest->get( 'auth_token' ),
         account_name => FBTest->get( 'account_name' ),
-        verbose     => $ENV{'FB_VERBOSE'} || 0,
+        verbose      => $ENV{'FB_VERBOSE'} || 0,
     }
 );
 
@@ -29,8 +31,8 @@ diag( "verbose: " . $fb->verbose );
 
 my $recurring = $fb->recurring;
 
-foreach my $method ( sort keys %{$recurring->_fields() } ) {
-    can_ok( $recurring, $method );    
+foreach my $method ( sort keys %{ $recurring->_fields() } ) {
+    can_ok( $recurring, $method );
 }
 
 isa_ok( $recurring, "Net::FreshBooks::API::Recurring" );
@@ -7,10 +7,12 @@ use Data::Dump qw( dump );
 use DateTime;
 use Test::More;
 
-plan -r 't/config.pl' && require( 't/config.pl' )
+plan -r 't/config.pl'
+    && require( 't/config.pl' )
+    && $ENV{FB_LIVE_TESTS}
     ? ( tests => 34 )
-    : ( skip_all => "Need test connection details in t/config.pl"
-        . " - see t/config_sample.pl for details" );
+    : (
+    skip_all => 'Set FB_LIVE_TESTS to true in your %ENV to run live tests' );
 
 use_ok 'Net::FreshBooks::API';
 
@@ -18,7 +20,7 @@ use_ok 'Net::FreshBooks::API';
 my $fb = Net::FreshBooks::API->new(
     {   auth_token   => FBTest->get( 'auth_token' ),
         account_name => FBTest->get( 'account_name' ),
-        verbose     => $ENV{'FB_VERBOSE'} || 0,
+        verbose      => $ENV{'FB_VERBOSE'} || 0,
     }
 );
 
@@ -26,14 +28,14 @@ ok $fb, "created the FB object";
 
 my $estimate = $fb->estimate;
 
-foreach my $method ( sort keys %{$fb->estimate->_fields() } ) {
+foreach my $method ( sort keys %{ $fb->estimate->_fields() } ) {
     can_ok( $estimate, $method );
 }
 
 isa_ok( $estimate, 'Net::FreshBooks::API::Estimate', );
 
 my $client = $fb->client->list->next;
-ok( $client->client_id, "got a client id");
+ok( $client->client_id, "got a client id" );
 
 $estimate->client_id( $client->client_id );
 ok $estimate->add_line(
@@ -53,11 +55,11 @@ ok $estimate->add_line(
     "Add second line to the estimate";
 
 ok $estimate->create, "create the estimate";
-is ( $estimate->status, "draft", 'flagged as draft');
+is( $estimate->status, "draft", 'flagged as draft' );
 
 #$estimate->status('sent');
-$estimate->update({ status => 'sent' });
+$estimate->update( { status => 'sent' } );
 
-is ( $estimate->status, "sent", 'flagged as sent');
+is( $estimate->status, "sent", 'flagged as sent' );
 
 #ok ( $estimate->send_by_email, "sent by email" );
@@ -5,12 +5,12 @@ use warnings;
 
 use Data::Dump qw( dump );
 use Test::More qw( no_plan );
-require_ok('Net::FreshBooks::API::InvoiceLine');
+require_ok( 'Net::FreshBooks::API::InvoiceLine' );
 
 my $line = Net::FreshBooks::API::InvoiceLine->new;
 
-foreach my $method ( sort keys %{$line->_fields() } ) {
-    can_ok( $line, $method );    
+foreach my $method ( sort keys %{ $line->_fields() } ) {
+    can_ok( $line, $method );
 }
 
 isa_ok( $line, 'Net::FreshBooks::API::InvoiceLine', );
@@ -6,6 +6,6 @@ use Test::More tests => 2;
 require_ok( 'Net::FreshBooks::API' );
 my $error = Net::FreshBooks::API->new;
 
-can_ok( $error, 'die_on_server_error', '_handle_server_error', 'last_server_error' ); 
-
+can_ok( $error, 'die_on_server_error', '_handle_server_error',
+    'last_server_error' );
 
@@ -16,38 +16,41 @@ if ( $key && $secret ) {
 
 SKIP: {
     skip "tokens required", 1 if !$tokens_ok;
-    
+
     my %tokens = (
         consumer_key    => $key,
-        consumer_secret => $secret,        
+        consumer_secret => $secret,
     );
 
     my $oauth = Net::FreshBooks::API::OAuth->new( %tokens );
     isa_ok( $oauth, 'Net::FreshBooks::API::OAuth' );
-    
-    my $api = Net::FreshBooks::API->new( %tokens, verbose => $ENV{'FB_VERBOSE'} );
+
+    my $api
+        = Net::FreshBooks::API->new( %tokens, verbose => $ENV{'FB_VERBOSE'} );
     isa_ok( $api, 'Net::FreshBooks::API' );
-    
+
     can_ok( $api, 'oauth' );
-    
-    isa_ok( $api->oauth, 'Net::FreshBooks::API::OAuth');
+
+    isa_ok( $api->oauth, 'Net::FreshBooks::API::OAuth' );
     ok( !$api->oauth->authorized, "should not be authorized" );
-    
-    if ( exists $ENV{'FB_ACCESS_TOKEN'} && exists $ENV{'FB_ACCESS_TOKEN_SECRET'} ) {
+
+    if (   exists $ENV{'FB_ACCESS_TOKEN'}
+        && exists $ENV{'FB_ACCESS_TOKEN_SECRET'} )
+    {
         $api->oauth->access_token( $ENV{'FB_ACCESS_TOKEN'} );
         $api->oauth->access_token_secret( $ENV{'FB_ACCESS_TOKEN_SECRET'} );
     }
-    
+
     ok( $api->oauth->authorized, "is now authorized" );
-    
+
     my $client = $api->client;
-    isa_ok( $client, 'Net::FreshBooks::API::Client');
+    isa_ok( $client, 'Net::FreshBooks::API::Client' );
     my $iterator = $client->list;
-    ok( $iterator, "got an iterator");
+    ok( $iterator, "got an iterator" );
     while ( my $cl = $iterator->next ) {
         diag( "Client: " . $cl->first_name . ' ' . $cl->last_name );
     }
-    
+
     ok( $api->ping, "can ping the server" );
-    
+
 }
@@ -9,18 +9,20 @@ use Test::Exception;
 use Net::FreshBooks::API;
 use Test::WWW::Mechanize;
 
-plan -r 't/config.pl' && require('t/config.pl')
+plan -r 't/config.pl'
+    && require( 't/config.pl' )
+    && $ENV{FB_LIVE_TESTS}
     ? ( tests => 6 )
-    : ( skip_all => "Need test connection details in t/config.pl"
-        . " - see t/config_sample.pl for details" );
+    : (
+    skip_all => 'Set FB_LIVE_TESTS to true in your %ENV to run live tests' );
 
-my $test_email = FBTest->get('test_email') || die;
+my $test_email = FBTest->get( 'test_email' ) || die;
 
 # create the FB object
 my $fb = Net::FreshBooks::API->new(
-    {   auth_token   => FBTest->get('auth_token'),
-        account_name => FBTest->get('account_name'),
-        verbose => 0,
+    {   auth_token   => FBTest->get( 'auth_token' ),
+        account_name => FBTest->get( 'account_name' ),
+        verbose      => 0,
     }
 );
 ok $fb, "created the FB object";
@@ -5,36 +5,36 @@ use warnings;
 
 use Test::More;
 use Test::Exception;
+use Test::WWW::Mechanize;
 
 use Net::FreshBooks::API;
-use Test::WWW::Mechanize;
 
-plan -r 't/config.pl' && require('t/config.pl')
+plan -r 't/config.pl'
+    && require( 't/config.pl' )
+    && $ENV{FB_LIVE_TESTS}
     ? ( tests => 7 )
-    : ( skip_all => "Need test connection details in t/config.pl"
-        . " - see t/config_sample.pl for details" );
+    : (
+    skip_all => 'Set FB_LIVE_TESTS to true in your %ENV to run live tests' );
 
-# create the FB object
 my $fb = Net::FreshBooks::API->new(
-    {   auth_token   => FBTest->get('auth_token'),
-        account_name => FBTest->get('account_name'),
-        verbose => 0,
+    {   auth_token   => FBTest->get( 'auth_token' ),
+        account_name => FBTest->get( 'account_name' ),
+        verbose      => 0,
     }
 );
 
 ok $fb, "created the FB object";
 
-
 isa_ok( $fb->language, "Net::FreshBooks::API::Language" );
 my $langs = $fb->language->get_all();
 ok( $langs, "got languages" );
 
-foreach my $lang ( @{$fb->language->get_all()} ) {
+foreach my $lang ( @{ $fb->language->get_all() } ) {
     diag $lang->code . ": " . $lang->name;
 }
 
-#diag explain $langs;
-ok( ( scalar @{$langs} != 0 ), "languages in test account: " . scalar @{$langs} );
+ok( ( scalar @{$langs} != 0 ),
+    "languages in test account: " . scalar @{$langs} );
 dies_ok( sub { $fb->language->get }, "get not implemented" );
 my $list = $fb->language->list;
 
@@ -12,31 +12,36 @@ use Net::FreshBooks::API::Recurring::AutoBill;
 new_ok( 'Net::FreshBooks::API::Recurring::AutoBill' );
 my $autobill = Net::FreshBooks::API::Recurring::AutoBill->new;
 
-$autobill->gateway_name('PayPal Payflow Pro');
-$autobill->card->name('Tim Toady');
-$autobill->card->number('4111 1111 1111 1111');
-$autobill->card->expiration->month(12);
-$autobill->card->expiration->year(2015);
-
-isa_ok( $autobill, 'Net::FreshBooks::API::Recurring::AutoBill');
-isa_ok( $autobill->card, 'Net::FreshBooks::API::Recurring::AutoBill::Card');
-isa_ok( $autobill->card->expiration, 'Net::FreshBooks::API::Recurring::AutoBill::Card::Expiration');
-
-ok( $autobill->gateway_name, "gateway name: " . $autobill->gateway_name );
+$autobill->gateway_name( 'PayPal Payflow Pro' );
+$autobill->card->name( 'Tim Toady' );
+$autobill->card->number( '4111 1111 1111 1111' );
+$autobill->card->expiration->month( 12 );
+$autobill->card->expiration->year( 2015 );
+
+isa_ok( $autobill,       'Net::FreshBooks::API::Recurring::AutoBill' );
+isa_ok( $autobill->card, 'Net::FreshBooks::API::Recurring::AutoBill::Card' );
+isa_ok( $autobill->card->expiration,
+    'Net::FreshBooks::API::Recurring::AutoBill::Card::Expiration' );
+
+ok( $autobill->gateway_name,     "gateway name: " . $autobill->gateway_name );
 ok( $autobill->card->expiration, "card expiration" );
-ok( $autobill->card->expiration->month, "card expiration month: " . $autobill->card->expiration->month );
-ok( $autobill->card->expiration->year, "card expiration year: " . $autobill->card->expiration->year );
+ok( $autobill->card->expiration->month,
+    "card expiration month: " . $autobill->card->expiration->month );
+ok( $autobill->card->expiration->year,
+    "card expiration year: " . $autobill->card->expiration->year );
 
-ok( $autobill->card->name, "card name: " . $autobill->card->name );
+ok( $autobill->card->name,   "card name: " . $autobill->card->name );
 ok( $autobill->card->number, "card number: " . $autobill->card->number );
 
-diag("alternate syntax");
-ok( $autobill->card->month, "card expiration month: " . $autobill->card->expiration->month );
-ok( $autobill->card->year, "card expiration year: " . $autobill->card->expiration->year );
+diag( "alternate syntax" );
+ok( $autobill->card->month,
+    "card expiration month: " . $autobill->card->expiration->month );
+ok( $autobill->card->year,
+    "card expiration year: " . $autobill->card->expiration->year );
 
-ok( $autobill->_validates, "all required fields have been filled");
+ok( $autobill->_validates, "all required fields have been filled" );
 
 my $empty = Net::FreshBooks::API::Recurring::AutoBill->new;
-ok( !$empty->_validates, "NOT all required fields have been filled");
+ok( !$empty->_validates, "NOT all required fields have been filled" );
 
 done_testing();
@@ -4,9 +4,10 @@ use strict;
 use warnings;
 
 my %CONFIG = (
-    test_email   => $ENV{FRESHBOOKS_EMAIL} || 'olaf@raybec.com',
+    test_email   => $ENV{FRESHBOOKS_EMAIL}        || 'olaf@raybec.com',
     account_name => $ENV{FRESHBOOKS_ACCOUNT_NAME} || 'netfreshbooksapi',
-    auth_token   => $ENV{FRESHBOOKS_AUTH_TOKEN} || 'd2d6c5a50b023d95e1c804416d1ec15d',
+    auth_token   => $ENV{FRESHBOOKS_AUTH_TOKEN}
+        || 'd2d6c5a50b023d95e1c804416d1ec15d',
 );
 
 sub get {
@@ -1,21 +0,0 @@
-#!perl
-
-BEGIN {
-  unless ($ENV{RELEASE_TESTING}) {
-    require Test::More;
-    Test::More::plan(skip_all => 'these tests are for release candidate testing');
-  }
-}
-
-
-use Test::More;
-
-eval "use Test::Pod::Coverage 1.08";
-plan skip_all => "Test::Pod::Coverage 1.08 required for testing POD coverage"
-  if $@;
-
-eval "use Pod::Coverage::TrustPod";
-plan skip_all => "Pod::Coverage::TrustPod required for testing POD coverage"
-  if $@;
-
-all_pod_coverage_ok({ coverage_class => 'Pod::Coverage::TrustPod' });