=head1 NAME WebService::HMRC::VAT - Interact with the UK HMRC VAT API =head1 VERSION Version 0.02 =cut =head1 SYNOPSIS use WebService::HMRC::VAT; my $vat = WebService::HMRC::VAT->new({ vrn => '123456789' }); $vat->auth->access_token->('MY-ACCESS-TOKEN'); # Display outstanding VAT returns my $result = $vat->obligations({ from => '2018-01-01', to => '2018-12-31', state => 'O', }); if($result->is_success) { foreach my $o (@{$result->data->{obligations}) { print "VAT return " . $o->{periodKey}; print " due " . $o->{due} . "\n"; } } # Submit a VAT return $result = $vat->submit_return({ periodKey => "#001", # from ->obligations() vatDueSales => 100.00, # Box 1 on paper form vatDueAcquisitions => 100.00, # Box 2 on paper form totalVatDue => 200.00, # Box 3 on paper form vatReclaimedCurrPeriod => 100.00, # Box 4 on paper form netVatDue => 100.00, # Box 5 on paper form totalValueSalesExVAT => 500, # Box 6 on paper form totalValuePurchasesExVAT => 500, # Box 7 on paper form totalValueGoodsSuppliedExVAT => 500, # Box 8 on paper form totalAcquisitionsExVAT => 500, # Box 9 on paper form finalised => 1, # Boolean user declaration }); if($result->is_success) { print "VAT Return submitted:\n" printf "Receipt ID: %s\n", $result->header('Receipt-ID'); printf "Form Bundle: %s\n", $result->data->{formBundleNumber}; } =head1 DESCRIPTION Perl module to interact with the UK's HMRC Making Tax Digital `VAT` API. This allows VAT returns to be submitted or viewed, and obligations, payments and liabilities to be viewed. For more information, see: L =head1 REQUIRES =over =item * L =item * L =item * L =item * L =back =head1 EXPORTS Nothing =head1 PROPERTIES Inherits from L. =head2 vrn VAT registration number for which records are being queries or submitted. Required parameter for initialisation. The VAT registration number must be purely numeric, without any spaces or GB prefix. =cut =head1 METHODS Inherits from L. =head2 obligations({ from => 'YYYY-MM-DD', to => 'YYYY-MM-DD', [status => $status, ] [test_mode => $test_mode] }) Retrieve a set of VAT filing obligations for the specified date range. Returns a WebService::HMRC::Response object reference. Requires permission for the C service scope. =head3 Parameters =over =item from Return obligations from this date, specified as YYYY-MM-DD. Required parameter. =item to Return obligations up to this date, specified as YYYY-MM-DD. Required parameter. =item status Optional parameter to filter the obligations returned. May be set to 'O' to return only 'open' obligations, or 'F' to return only 'fulfilled' obligations. Default is to return all obligations, both fulfilled and open. =item test_mode Optional parameter used only for testing against the HMRC sandbox api. This parameter should not be used in production systems - it causes dummy test data to be returned. By default, when testing against the sandbox with no C specified, the test api simulates the scenario where the client has quarterly obligations and one is fulfilled Other test scenarios are available by setting the C parameter as detailed below: C simulates the scenario where the client has quarterly obligations and none are fulfilled. C simulates the scenario where the client has quarterly obligations and one is fulfilled. C simulates the scenario where the client has quarterly obligations and two are fulfilled. C simulates the scenario where the client has quarterly obligations and three are fulfilled. C simulates the scenario where the client has quarterly obligations and four are fulfilled. C simulates the scenario where the client has monthly obligations and none are fulfilled. C simulates the scenario where the client has monthly obligations and one month is fulfilled. C simulates the scenario where the client has monthly obligations and two months are fulfilled. C simulates the scenario where the client has monthly obligations and three months are fulfilled. C simulates the scenario where no data is found. =back =head3 Response Data For full details of the response data, see the HMRC API specification. In summary, the data contains a single element `obligations` pointing to an array of VAT return obligations: { obligations => [ { periodKey => "#001" start => "2017-04-06", end => "2017-07-05", due => "2017-08-12", status => "F", received => "2017-08-05", # only present if 'Fulfilled' }, { periodKey => "#004" start => "2018-01-06", end => "2018-04-05", due" => "2018-05-12", status => "O", }, ] } =head3 Example usage my $result = $vat->obligations({ from => '2018-01-01', to => '2018-12-31', }); foreach my $obligation( @{$result->data->{obligations}} ) { print "-- VAT Return Obligation --\n" print " ID: $obligation->{periodKey}\n"; print " Period Start: $obligation->{start}\n"; print " Period End: $obligation->{end}\n"; print " Due Date: $obligation->{due}\n"; print "Received Date: "; if ($obligation->{status} eq 'F') { print "$obligation->{received}\n"; } else { print "Still Outstanding\n"; } } =cut =head2 liabilities({ from => 'YYYY-MM-DD', to => 'YYYY-MM-DD', [test_mode => $test_mode] }) Retrieve a set of VAT payment liabilities. Returns a WebService::HMRC::Response object reference. Requires permission for the C service scope. =head3 Parameters =over =item from Return liabilities from this date, specified as YYYY-MM-DD. Required parameter. The date must be before today's date, otherwise the api will return an error. =item to Return liabilities up to this date, specified as YYYY-MM-DD. Required parameter. =item test_mode Optional parameter used only for testing against the HMRC sandbox api. If set to C, returns a single valid liability when used with dates from 2017-01-02 and to 2017-02-02. If set to C, returns multiple valid liabilities when used with dates from 2017-04-05 and to 2017-12-21. This parameter should not be used in production systems - it causes dummy test data to be returned. =back =head3 Response Data For full details of the response data, see the HMRC API specification. In summary, the data contains a single element `liabilities` pointing to an array of VAT payment liabilities: { liabilities => [ { taxPeriod => { from => "2017-04-06", to => "2017-07-06" }, type => "VAT ...", originalAmount => 6000.00, outstandingAmount => 100.00, due => "2017-07-06" }, ] } =head3 Example usage my $result = $vat->liabilities({ from => '2018-01-01', to => '2018-03-31', }); foreach my $liability( @{$result->data->{liabilities}} ) { print "-- VAT Payment Liability --\n" print " Type: $liability->{type}\n"; print " Period Start: $liability->{taxPeriod}->{from}\n"; print " Period End: $liability->{taxPeriod}->{to}\n"; print "Original Amount: $liability->{originalAmount}\n"; print " Due Amount: $liability->{outstandingAmount}\n"; print " Due Date: $liability->{due}\n"; } =cut =head2 payments({ from => 'YYYY-MM-DD', to => 'YYYY-MM-DD', [test_mode => $test_mode] }) Retrieve a set of payments received by HMRC in respect of VAT over the specified date range. Returns a WebService::HMRC::Response object reference. Requires permission for the C service scope. =head3 Parameters =over =item from Return payments from this date, specified as YYYY-MM-DD. Required parameter. =item to Return payments up to this date, specified as YYYY-MM-DD. Required parameter. =item test_mode Optional parameter used only for testing against the HMRC sandbox api. If set to C, returns a single valid payment when used with dates from 2017-01-02 and to 2017-02-02. If set to C, returns multiple valid payments when used with dates from 2017-02-27 and to 2017-12-21. This parameter should not be used in production systems - it causes dummy test data to be returned. =back =head3 Response Data For full details of the response data, see the HMRC API specification. In summary, the data contains a single element `payments` pointing to an array of payments received by HMRC: { payments => [ { amount => 100.00, received => "2017-04-06" }, ] } =head3 Example usage my $result = $vat->payments( from => '2018-01-01', to => '2018-03-31', ); foreach my $payment( @{$result->data->{payments}} ) { print "-- VAT Payments Received by HMRC --\n" print "Date Received: $payment->{received}\n"; print " Amount: $payment->{amount}\n"; } =cut =head2 get_return({ period_key => $period_key }) Retrieve a previously submitted VAT return corresponding to the supplied period_key. Returns a WebService::HMRC::Response object reference. Requires permission for the C service scope. =head3 Parameters =over =item period_key The ID code for the period that uniquely identifies a submitted VAT return, as contained within the response from an obligations() method call. =back =head3 Response Data For full details of the response data, see the HMRC API specification. In summary, the data is a hashref comprising the following elements which correspond to fields on the traditional paper VAT100 form: { periodKey => "#001", vatDueSales => 100.00, vatDueAcquisitions => 100.00, totalVatDue => 200, vatReclaimedCurrPeriod => 100.00, netVatDue => 100, totalValueSalesExVAT => 500, totalValuePurchasesExVAT => 500, totalValueGoodsSuppliedExVAT => 500, totalAcquisitionsExVAT => 500 } Note that some fields are returned as integers where only whole pounds are required to be submitted by HMRC. =cut =head2 submit_return($hashref) Retrieve a previously submitted VAT return corresponding to the supplied period_key. Returns a WebService::HMRC::Response object reference. Requires permission for the C service scope. =head3 Parameters For full details of the required parameters and the rules for calculating each value, see the HMRC API specification and VAT documentation. The brief descriptions here are intended as a simplified overview to help understand the code and are not a comprehensive or necessarily accurate representation of VAT law. In summary, the data is a hashref comprising the following elements which correspond to fields on the traditional paper VAT100 form. All parameters are required. =over =item period_key The ID code for the period that uniquely identifies a submitted VAT return, as contained within the response from an obligations() method call. =item vatDueSales VAT due on sales and other outputs. Corresponds to box 1 on the traditional VAT100 paper form. =item vatDueAcquisitions VAT due on acquisitions from other EC member states as part of the reverse- charge scheme. Corresponds to box 2 on the traditional VAT100 paper form. =item totalVatDue The sum of vatDueSales and vatDueAcquisitions. Corresponds to box 3 on the traditional VAT100 paper form. =item vatReclaimedCurrPeriod VAT reclaimed on purchases and other inputs, including acquisitions from other EC member states. This corresponds to box 4 on the traditional VAT100 paper form. =item netVatDue The absolute (unsigned, always positive) difference between totalVatDue and vatReclaimedCurrPeriod. This corresponds to box 5 on the traditional VAT100 paper form. =item totalValueSalesExVAT Total value of sales and all other outputs, excluding any VAT, rounded to an integer value. This corresponds to box 6 on the traditional VAT100 paper form. =item totalValuePurchasesExVAT Total value of purchases and all other inputs, excluding any VAT and including any exempt purchases. This corresponds to box 7 on the traditional VAT100 paper form. =item totalValueGoodsSuppliedExVAT Total value of all supplies of goods (but not services) to other EC member states and costs directly related to that supply (such as freight or insurance), excluding any VAT. This corresponds to box 8 on the traditional VAT100 paper form. =item totalAcquisitionsExVAT Total value of acquisitions of goods from other EC member states and directly related costs (such as freight or insurance), excluding any VAT. This corresponds to box 9 on the traditional VAT100 paper form. =item finalised Boolean declaration that the data being submitted has been finalised and approved by the user. Must be true for successful submission. This parameter is converted to a JSON()->true or JSON()->false boolean value before encoding to json for submission. Defaults to false. =back =head3 Response Headers For full details of the response headers, see the HMRC API specification. In summary the headers confirm receipt of the submission, comprising: =over =item Receipt ID Unique reference number returned for a submission. =item Receipt-Timestamp ISO8601 format timestamp of the form '2018-02-14T09:32:15Z'. =item X-CorrelationId Unique ID for this operation. =back =head3 Response Data For full details of the response data, see the HMRC API specification. In summary, the response data is a hashref with keys: =over =item processingDate ISO8601 timestamp indicating the time that the submission was processed. =item formBundleNumber Unique number representing the "Form Bundle" in which the submitted data has been stored by HMRC. =item paymentIndicator Set to 'DD' if payment is due to HMRC and they hold a Direct Debit instruction for the client, 'BANK' if a repayment is due from HMRC and they hold bank details to make the repayment, otherwise this element is not present in the returned data. =item chargeRefNumber Present only is payment is due to HMRC. =back =head3 Example my $result = $vat->submit_return({ periodKey => "#001", vatDueSales => 100.00, vatDueAcquisitions => 0.00, totalVatDue => 100.00, vatReclaimedCurrPeriod => 50.00, netVatDue => 50.00, totalValueSalesExVAT => 500, totalValuePurchasesExVAT => 250, totalValueGoodsSuppliedExVAT => 0, totalAcquisitionsExVAT => 0, finalised => 1, }) if($result->is_success) { print "==== VAT Return Submitted ====\n"; printf " Receipt ID: %s\n", $result->header('Receipt-ID'); printf " Receipt Timestamp: %s\n", $result->header('Receipt-Timestamp'); printf " Tracking ID: %s\n", $result->header('X-CorrelationId'); printf " Processing Date: %s\n", $result->data->{processingDate}; printf " Form Bundle: %s\n", $result->data->{formBundleNumber}; if($result->data->{paymentIndicator}) { printf " Payment Indicator: %s\n", $result->data->{paymentIndicator}; } if($result->data->{paymentIndicator}) { printf " Charge Reference: %s\n", $result->data->{chargeRefNumber}; } } =cut =head1 AUTHORISATION Access to the HMRC Making Tax Digital VAT APIs requires that an application be registered with HMRC and enabled for this service. Additionally permission must be granted by a registered user for the application to access the C or C service scope, as noted for each method. Authorisation is provided by means of an C. For more details on obtaining and using access tokens, See L. Further information, application credentials and documentation may be obtained from the L. =head1 TESTING The basic tests are run as part of the installation instructions shown above use an invalid uri as an endpoint. This tests basic interaction with the module's method and does not require an internet connection. Developer pre-release tests may be run with the following command: prove -l xt/ With a working internet connection, HMRC application credentials and an access token granted by a test user enrolled for the Making Tax Digital for Business VAT service, interaction with the real HMRC sandbox api can be tested. The test user's VAT registration number must also be provided. The credentials are specified as environment variables when running the tests: HMRC_ACCESS_TOKEN=[MY-ACCESS-TOKEN] \ HMRC_VRN=[USER-VAT-REGISTRATION-NUMBER] \ make test TEST_VERBOSE=1 =head1 AUTHOR Nick Prater, =head1 BUGS Please report any bugs or feature requests to C, or through the web interface at L. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. =head1 SUPPORT AND DOCUMENTATION You can find documentation for this module with the perldoc command. perldoc WebService::HMRC::VAT The C file supplied with this distribution is generated from the L module's pod by running the following command from the distribution root: perldoc -u lib/WebService/HMRC/VAT.pm > README.pod You can also look for information at: =over 4 =item * RT: CPAN's request tracker (report bugs here) L =item * CPAN Ratings L =item * Search CPAN L =item * Github L =back =head1 ACKNOWLEDGEMENTS This module was originally developed for use as part of the L open source accounting software. =head1 LICENSE AND COPYRIGHT Copyright 2018 Nick Prater. This program is free software; you can redistribute it and/or modify it under the terms of the the Artistic License (2.0). You may obtain a copy of the full license at: L Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License. By using, modifying or distributing the Package, you accept this license. Do not use, modify, or distribute the Package, if you do not accept this license. If your Modified Version has been derived from a Modified Version made by someone other than you, you are nevertheless required to ensure that your Modified Version complies with the requirements of this license. This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder. This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent claims licensable by the Copyright Holder that are necessarily infringed by the Package. If you institute patent litigation (including a cross-claim or counterclaim) against any party alleging that the Package constitutes direct or contributory patent infringement, then this Artistic License to you shall terminate on the date that such litigation is filed. Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =cut