The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

WebService::HMRC::VAT - Interact with the UK HMRC VAT API

VERSION

Version 0.04

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};
}

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: https://developer.service.hmrc.gov.uk/api-documentation/docs/api/service/vat-api/1.0

REQUIRES

EXPORTS

Nothing

PROPERTIES

Inherits from WebService::HMRC::Request.

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.

METHODS

Inherits from WebService::HMRC::Request.

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 read:vat service scope.

Parameters

from

Return obligations from this date, specified as YYYY-MM-DD. Required parameter.

to

Return obligations up to this date, specified as YYYY-MM-DD. Required parameter.

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.

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 test_mode 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 test_mode parameter as detailed below:

QUARTERLY_NONE_MET simulates the scenario where the client has quarterly obligations and none are fulfilled.

QUARTERLY_ONE_MET simulates the scenario where the client has quarterly obligations and one is fulfilled.

QUARTERLY_TWO_MET simulates the scenario where the client has quarterly obligations and two are fulfilled.

QUARTERLY_THREE_MET simulates the scenario where the client has quarterly obligations and three are fulfilled.

QUARTERLY_FOUR_MET simulates the scenario where the client has quarterly obligations and four are fulfilled.

MONTHLY_NONE_MET simulates the scenario where the client has monthly obligations and none are fulfilled.

MONTHLY_ONE_MET simulates the scenario where the client has monthly obligations and one month is fulfilled.

MONTHLY_TWO_MET simulates the scenario where the client has monthly obligations and two months are fulfilled.

MONTHLY_THREE_MET simulates the scenario where the client has monthly obligations and three months are fulfilled.

NOT_FOUND simulates the scenario where no data is found.

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",
    },
  ]
}

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";
    }
}

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 read:vat service scope.

Parameters

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.

to

Return liabilities up to this date, specified as YYYY-MM-DD. Required parameter.

test_mode

Optional parameter used only for testing against the HMRC sandbox api.

If set to SINGLE_LIABILITY, returns a single valid liability when used with dates from 2017-01-02 and to 2017-02-02.

If set to MULTIPLE_LIABILITIES, 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.

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"
    },
  ]
}

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";
}

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 read:vat service scope.

Parameters

from

Return payments from this date, specified as YYYY-MM-DD. Required parameter.

to

Return payments up to this date, specified as YYYY-MM-DD. Required parameter.

test_mode

Optional parameter used only for testing against the HMRC sandbox api.

If set to SINGLE_PAYMENT, returns a single valid payment when used with dates from 2017-01-02 and to 2017-02-02.

If set to MULTIPLE_PAYMENTS, 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.

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"
    },
  ]
}

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";
}

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 read:vat service scope.

Parameters

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.

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.

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 write:vat service scope.

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.

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.

vatDueSales

VAT due on sales and other outputs. Corresponds to box 1 on the traditional VAT100 paper form.

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.

totalVatDue

The sum of vatDueSales and vatDueAcquisitions. Corresponds to box 3 on the traditional VAT100 paper form.

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.

netVatDue

The absolute (unsigned, always positive) difference between totalVatDue and vatReclaimedCurrPeriod. This corresponds to box 5 on the traditional VAT100 paper form.

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.

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.

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.

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.

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.

Response Headers

For full details of the response headers, see the HMRC API specification. In summary the headers confirm receipt of the submission, comprising:

Receipt ID

Unique reference number returned for a submission.

Receipt-Timestamp

ISO8601 format timestamp of the form '2018-02-14T09:32:15Z'.

X-CorrelationId

Unique ID for this operation.

Response Data

For full details of the response data, see the HMRC API specification. In summary, the response data is a hashref with keys:

processingDate

ISO8601 timestamp indicating the time that the submission was processed.

formBundleNumber

Unique number representing the "Form Bundle" in which the submitted data has been stored by HMRC.

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.

chargeRefNumber

Present only is payment is due to HMRC.

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};
    }
}

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 read:vat or write:vat service scope, as noted for each method.

Authorisation is provided by means of an access token.

For more details on obtaining and using access tokens, See WebService::HMRC::Authenticate.

Further information, application credentials and documentation may be obtained from the HMRC Developer Hub.

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

AUTHOR

Nick Prater, <nick@npbroadcast.com>

BUGS

Please report any bugs or feature requests to bug-webservice-hmrc-vat at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=WebService-HMRC-VAT. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT AND DOCUMENTATION

You can find documentation for this module with the perldoc command.

perldoc WebService::HMRC::VAT

The README.pod file supplied with this distribution is generated from the WebService::HMRC::VAT 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:

ACKNOWLEDGEMENTS

This module was originally developed for use as part of the LedgerSMB open source accounting software.

LICENSE AND COPYRIGHT

Copyright 2018-2019 Nick Prater, NP Broadcast Limited.

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:

http://www.perlfoundation.org/artistic_license_2_0

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.