epic-s6ts
[kivitendo-erp.git] / SL / VATIDNr.pm
1 package SL::VATIDNr;
2
3 use strict;
4 use warnings;
5
6 use Algorithm::CheckDigits;
7
8 sub clean {
9   my ($class, $ustid) = @_;
10
11   $ustid //= '';
12   $ustid   =~ s{[[:space:].-]+}{}g;
13
14   return $ustid;
15 }
16
17 sub normalize {
18   my ($class, $ustid) = @_;
19
20   $ustid = $class->clean($ustid);
21
22   if ($ustid =~ m{^CHE(\d{3})(\d{3})(\d{3})$}) {
23     return sprintf('CHE-%s.%s.%s', $1, $2, $3);
24   }
25
26   return $ustid;
27 }
28
29 sub _validate_switzerland {
30   my ($ustid) = @_;
31
32   return $ustid =~ m{^CHE\d{9}$} ? 1 : 0;
33 }
34
35 sub _validate_european_union {
36   my ($ustid) = @_;
37
38   # 1. Two upper-case letters with the ISO 3166-1 Alpha-2 country code (exception: Greece uses EL instead of GR)
39   # 2. Up to twelve alphanumeric characters
40
41   return 0 unless $ustid =~ m{^(?:AT|BE|BG|CY|CZ|DE|DK|EE|EL|ES|FI|FR|GB|HR|HU|IE|IT|LT|LU|LV|MT|NL|PL|PT|RO|SE|SI|SK|SM)[[:alnum:]]{1,12}$};
42
43   my $algo_name = "ustid_" . lc(substr($ustid, 0, 2));
44   my $checker   = eval { CheckDigits($algo_name) };
45
46   return $checker->is_valid(substr($ustid, 2)) if $checker;
47   return 1;
48 }
49
50 sub validate {
51   my ($class, $ustid) = @_;
52
53   $ustid = $class->clean($ustid);
54
55   return _validate_switzerland($ustid) if $ustid =~ m{^CHE};
56   return _validate_european_union($ustid);
57 }
58
59 1;
60 __END__
61
62 =pod
63
64 =encoding utf8
65
66 =head1 NAME
67
68 SL::VATIDNr - Helper routines for dealing with VAT ID numbers
69 ("Umsatzsteuer-Identifikationsnummern", "UStID-Nr" in German) and
70 Switzerland's enterprise identification numbers (UIDs)
71
72 =head1 SYNOPSIS
73
74     my $is_valid = SL::VATIDNr->validate($ustid);
75
76 =head1 FUNCTIONS
77
78 =over 4
79
80 =item C<clean> C<$ustid>
81
82 Returns the number with all spaces, dashes & points removed.
83
84 =item C<normalize> C<$ustid>
85
86 Normalizes the given number to the format usually used in the country
87 given by the country code at the start of the number
88 (e.g. C<CHE-123.456.789> for a Swiss UID or DE123456789 for a German
89 VATIDNr).
90
91 =item C<validate> C<$ustid>
92
93 Returns whether or not a number is valid. Depending on the country
94 code at the start several tests are done including check digit
95 validation.
96
97 The number in question is first run through the L</clean> function and
98 may therefore contain certain ignored characters.
99
100 =back
101
102 =head1 BUGS
103
104 Nothing here yet.
105
106 =head1 AUTHOR
107
108 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
109
110 =cut