package WWW::YNAB; use Moose; # ABSTRACT: Wrapper for the YNAB API use WWW::YNAB::Account; use WWW::YNAB::Budget; use WWW::YNAB::CategoryGroup; use WWW::YNAB::Category; use WWW::YNAB::Month; use WWW::YNAB::Payee; use WWW::YNAB::ScheduledSubTransaction; use WWW::YNAB::ScheduledTransaction; use WWW::YNAB::SubTransaction; use WWW::YNAB::Transaction; use WWW::YNAB::UA; use WWW::YNAB::User; with 'WWW::YNAB::ModelHelpers'; =head1 SYNOPSIS use WWW::YNAB; my $ynab = WWW::YNAB->new(access_token => 'SECRET'); my @budgets = $ynab->budgets; =head1 DESCRIPTION This module is a wrapper around the V1 YNAB API. It follows the API structure quite closely, so the API documentation should be used for information about the data that this module returns. You can find the API documentation at L. =cut =attr access_token Your personal access token. Information about generating a personal access token can be found at L. Required. =cut has access_token => ( is => 'ro', isa => 'Str', required => 1, ); =attr base_uri The base uri for all API requests. Defaults to C. It's unlikely you'll need to change this. =cut has base_uri => ( is => 'ro', isa => 'Str', default => 'https://api.youneedabudget.com/v1/', ); =attr ua The HTTP user agent to use. Must be compatible with L. =cut has ua => ( is => 'ro', isa => 'HTTP::Tiny', lazy => 1, default => sub { HTTP::Tiny->new }, ); has _ua => ( is => 'ro', isa => 'WWW::YNAB::UA', lazy => 1, default => sub { my $self = shift; WWW::YNAB::UA->new( access_token => $self->access_token, base_uri => $self->base_uri, ua => $self->ua, ) }, ); =method user =cut sub user { my $self = shift; my $data = $self->_ua->get('/user'); my $user = $data->{data}{user}; $self->model_from_data('WWW::YNAB::User', $user); } =method budgets =cut sub budgets { my $self = shift; my $data = $self->_ua->get('/budgets'); map { $self->model_from_data('WWW::YNAB::Budget', $_) } @{ $data->{data}{budgets} }; } =method budget($id, $server_knowledge=undef) Returns the budget with id C<$id>. The returned budget object will have a C method which represents the state of the server when that object was returned. If the C<$server_knowledge> parameter is passed here with a value that came from an object previously returned by this method, this method will only return sub-objects (transactions, accounts, etc.) which have changed since that previous object was generated. =cut sub budget { my $self = shift; my ($id, $server_knowledge) = @_; my $params; if (defined $server_knowledge) { $params = { last_knowledge_of_server => $server_knowledge, } } my $data = $self->_ua->get("/budgets/$id", $params); my $budget = $data->{data}{budget}; my %budget = %$budget; my @accounts = map { $self->model_from_data('WWW::YNAB::Account', $_) } @{ $budget{accounts} }; $budget{accounts} = \@accounts; my @payees = map { $self->model_from_data('WWW::YNAB::Payee', $_) } @{ $budget{payees} }; $budget{payees} = \@payees; my @category_groups = map { my %category_group = %$_; $category_group{categories} = [ map { $self->model_from_data('WWW::YNAB::Category', $_) } grep { $_->{category_group_id} eq $category_group{id} } @{ $budget{categories} } ]; $self->model_from_data('WWW::YNAB::CategoryGroup', \%category_group) } @{ $budget{category_groups} }; $budget{category_groups} = \@category_groups; my @months = map { my %month = %$_; $month{categories} = [ map { $self->model_from_data('WWW::YNAB::Category', $_) } @{ $month{categories} } ]; $self->model_from_data('WWW::YNAB::Month', \%month) } @{ $budget{months} }; $budget{months} = \@months; my @transactions = map { my %transaction = %$_; if ($transaction{account_id}) { ($transaction{account_name}) = map { $_->{name} } grep { $_->{id} eq $transaction{account_id} } @{ $budget{accounts} }; } if ($transaction{payee_id}) { ($transaction{payee_name}) = map { $_->{name} } grep { $_->{id} eq $transaction{payee_id} } @{ $budget{payees} }; } if ($transaction{category_id}) { ($transaction{category_name}) = map { $_->{name} } grep { $_->{id} eq $transaction{category_id} } @{ $budget{categories} }; } $transaction{subtransactions} = [ map { $self->model_from_data('WWW::YNAB::SubTransaction', $_) } grep { $_->{transaction_id} eq $transaction{id} } @{ $budget{subtransactions} } ]; $self->model_from_data('WWW::YNAB::Transaction', \%transaction) } @{ $budget{transactions} }; $budget{transactions} = \@transactions; my @scheduled_transactions = map { my %transaction = %$_; if ($transaction{account_id}) { ($transaction{account_name}) = map { $_->{name} } grep { $_->{id} eq $transaction{account_id} } @{ $budget{accounts} }; } if ($transaction{payee_id}) { ($transaction{payee_name}) = map { $_->{name} } grep { $_->{id} eq $transaction{payee_id} } @{ $budget{payees} }; } if ($transaction{category_id}) { ($transaction{category_name}) = map { $_->{name} } grep { $_->{id} eq $transaction{category_id} } @{ $budget{categories} }; } $transaction{subtransactions} = [ map { $self->model_from_data('WWW::YNAB::ScheduledSubTransaction', $_) } grep { $_->{scheduled_transaction_id} eq $transaction{id} } @{ $budget{scheduled_subtransactions} } ]; $self->model_from_data('WWW::YNAB::ScheduledTransaction', \%transaction) } @{ $budget{scheduled_transactions} }; $budget{scheduled_transactions} = \@scheduled_transactions; $self->model_from_data( 'WWW::YNAB::Budget', \%budget, $data->{data}{server_knowledge}, ); } =method rate_limit Returns the number of requests in the current rate limit bucket. =cut sub rate_limit { my $self = shift; $self->_ua->rate_limit } =method knows_rate_limit Returns true if the current rate limit is known. This will only be true after a request has already been made (since the API currently doesn't provide a way to just request the current rate limit). =cut sub knows_rate_limit { my $self = shift; $self->_ua->knows_rate_limit } =method total_rate_limit Returns the total number of requests that will be allowed in the current rate limit bucket. =cut sub total_rate_limit { my $self = shift; $self->_ua->total_rate_limit } =method knows_total_rate_limit Returns true if the current total rate limit is known. This will only be true after a request has already been made (since the API currently doesn't provide a way to just request the current rate limit). =cut sub knows_total_rate_limit { my $self = shift; $self->_ua->knows_total_rate_limit } __PACKAGE__->meta->make_immutable; no Moose; =head1 BUGS/LIMITATIONS No known bugs. Please report any bugs to GitHub Issues at L. Not all of the API is exposed by this wrapper yet. In particular, these things are missing: =over 4 =item All modification endpoints (this module currently only exposes read-only operations) =item The payee location API =item OAuth authentication =back Patches are greatly appreciated if you are interested in this functionality. =head1 SEE ALSO L =head1 SUPPORT You can find this documentation for this module with the perldoc command. perldoc WWW::YNAB You can also look for information at: =over 4 =item * MetaCPAN L =item * Github L =item * RT: CPAN's request tracker L =item * CPAN Ratings L =back =cut 1;