File Coverage

lib/Business/Payment/SwissESR/V11Parser.pm
Criterion Covered Total %
statement 76 76 100.0
branch 10 12 83.3
condition 13 28 46.4
subroutine 24 24 100.0
pod 1 2 50.0
total 124 142 87.3


line stmt bran cond sub pod time code
1             package Business::Payment::SwissESR::V11Parser;
2              
3             =head1 NAME
4              
5             Business::Payment::SwissESR::V11Parser - Class for parsing v11 records
6              
7             =head1 SYNOPSYS
8              
9             use Business::Payment::SwissESR::V11Parser;
10             my $parser = Business::Payment::SwissESR::V11Parser->new();
11             my $records = $parser->parse($data);
12             for my $rec (@$records){
13             warn Dumper $rec;
14             }
15              
16             =head1 DESCRIPTION
17              
18             When issuing ESR payment slips to your customers, you can get payment data from swisspost in
19             the form of so called v11 files. They contain information about the paiments received. This
20             class transforms this information into easily accessible data.
21              
22             See records L
23             for details (2.1 Gutschriftrecord Typ 3 and 2.3 Gutschriftrecord Typ 4).
24              
25             =head1 METHODS
26              
27             =head2 $p->parse($string)
28              
29             parses v11 encoded data and returns an array of hashes where each hash represents a payment.
30              
31             typ3
32              
33             [ ...
34             {
35             'status' => 'reject',
36             'microfilmReference' => '000010086',
37             'transferDate' => '2012-09-26',
38             'payDate' => '2012-09-25',
39             'paymentLocation' => 'postoffice counter',
40             'creditDate' => '2012-09-27',
41             'submissionReference' => '5100 0100',
42             'paymentType' => 'payment',
43             'transactionCost' => '0.9',
44             'paymentSlip' => 'ESR+',
45             'amount' => '20',
46             'referenceNumber' => '326015262012',
47             'reseved' => '000000000',
48             'accontNumber' => '01-17546-3'
49             },
50             {
51             'status' => 'ok',
52             'microfilmReference' => '004570001',
53             'transferDate' => '2012-09-26',
54             'payDate' => '2012-09-26',
55             'paymentLocation' => 'online',
56             'creditDate' => '2012-09-27',
57             'submissionReference' => '0040 0400',
58             'paymentType' => 'payment',
59             'transactionCost' => '0',
60             'paymentSlip' => 'ESR',
61             'amount' => '40',
62             'referenceNumber' => '326015852012',
63             'reseved' => '000000000',
64             'accontNumber' => '01-17546-3'
65             },
66             ... ]
67              
68             typ4
69             [ ...
70             {
71             'paymentType' => 'payment',
72             'currency2' => 'CHF',
73             'payDate' => '2016-02-25',
74             'amount' => '64',
75             'paymentSlip' => 'ESR CHF',
76             'microfilmReference' => '-',
77             'currency' => 'CHF',
78             'status' => 'ok',
79             'accontNumber' => '01-89079-7',
80             'transferDate' => '2016-02-25',
81             'deliveryType' => 'original',
82             'paymentLocation' => 'eurosic',
83             'paymentSource' => 'normal',
84             'creditDate' => '2016-02-26',
85             'submissionReference' => '00020160225007602125808164000000012',
86             'transactionCost' => '0',
87             'referenceNumber' => '9320'
88             }
89             ]
90              
91             =cut
92              
93 1     1   1423 use Mojo::Base -base;
  1         2  
  1         7  
94              
95 1     1   171 use vars qw($VERSION);
  1         5  
  1         1237  
96 1     1 0 2 our $VERSION = '0.13.3';
97              
98             # all the magic of this parser is in setting up the right infrastructure
99             # so that we can blaze through the file with just a few lines of code
100             # later on.
101              
102             my $date = {
103             w => 6,
104             rx => qr/(..)(..)(..)/,
105             su => sub {
106 465     465   1690 return ((2000+$_[0])."-$_[1]-$_[2]");
107             }
108 1         9 };
109             my $date4 = {
110             w => 8,
111             rx => qr/(....)(..)(..)/,
112             su => sub {
113 3     3   10 return "$_[0]-$_[1]-$_[2]";
114             }
115 1         4 };
116              
117 1         5 my %src = (
118             '0' => 'online',
119             '1' => 'postoffice counter',
120             '2' => 'cash on delivery'
121             );
122              
123 1         3 my %type = (
124             '2' => 'payment',
125             '5' => 'refund',
126             '8' => 'correction'
127             );
128              
129             # the v11 format is a fixed with data format. in the format structure
130             # we have the width (w) of each column as well as an optional regular expression
131             my $GSR = {
132             typ3 => [
133             paymentSlip => {
134             w => 1,
135             su => sub {
136 155 100   155   434 return $_[0] ? 'ESR+' : 'ESR';
137             }
138             },
139             paymentLocation => {
140             w => 1,
141             su => sub {
142 155   33 155   523 return $src{$_[0]} || $_[0];
143             }
144             },
145             paymentType => {
146             w => 1,
147             su => sub {
148 155   33 155   556 return $type{$_[0]} || $_[0];
149             }
150             },
151             accontNumber => {
152             w => 9,
153             rx => qr/(..)0*(.+)(.)/,
154             su => sub {
155 155     155   473 return "$_[0]-$_[1]-$_[2]";
156             }
157             },
158             referenceNumber => {
159             w => 27,
160             rx => qr/(.+)./,
161             su => sub {
162 155     155   303 my $ret = shift;
163 155         480 $ret =~ s/^0+//;
164 155         421 return $ret;
165             }
166             },
167             amount => {
168             w => 10,
169             su => sub {
170 155     155   530 return int($_[0]) / 100;
171             }
172             },
173             submissionReference => 10,
174             payDate => $date,
175             transferDate => $date,
176             creditDate => $date,
177             microfilmReference => 9,
178             status => {
179             w => 1,
180             su => sub {
181 155 100   155   518 return $_[0] ? "reject" : "ok"
182             }
183             },
184             reseved => 9,
185             transactionCost => {
186             w => 4,
187             su => sub {
188 155     155   455 return int($_[0]) / 100;
189             }
190             }
191             ],
192             typ4 => [
193             paymentSlip => {
194             w => 1,
195             su => sub {
196             return [
197 1     1   5 'ESR CHF',
198             'ESR+ CHF',
199             'ESR EUR',
200             'ESR+ EUR'
201             ]->[$_[0]];
202             }
203             },
204             paymentSource => {
205             w => 1,
206             su => sub {
207 1   33 1   9 return [ undef,'normal','nachnahme','ownaccount']->[$_[0]] // 'Unknown Source '.$_[0];
208             }
209             },
210             paymentType => {
211             w => 1,
212             su => sub {
213 1   33 1   7 return [undef,'payment','refund','correction']->[$_[0]] // 'Unknown Type '.$_[0];
214             }
215             },
216             paymentLocation => {
217             w => 2,
218             su => sub {
219             return {
220             '01' => 'postoffice counter',
221             '02' => 'zag/dag',
222             '03' => 'online',
223             '04' => 'eurosic'
224 1   33 1   8 }->{$_[0]} // 'Unknown Location '.$_[0];
225             }
226             },
227             deliveryType => {
228             w => 1,
229             su => sub {
230 1   33 1   6 return [undef,'original','reko','test']->[$_[0]] // 'Unkown Delivery '.$_[0];
231             }
232             },
233             accontNumber => {
234             w => 9,
235             rx => qr/(..)0*(.+)(.)/,
236             su => sub {
237 1     1   4 return "$_[0]-$_[1]-$_[2]";
238             }
239             },
240             referenceNumber => {
241             w => 27,
242             rx => qr/^0+(.+)./,
243             },
244             currency => 3,
245             amount => {
246             w => 12,
247             su => sub {
248 1     1   4 return int($_[0]) / 100;
249             }
250             },
251             submissionReference => 35,
252             payDate => $date4,
253             transferDate => $date4,
254             creditDate => $date4,
255             status => {
256             w => 1,
257             su => sub {
258 1 50   1   6 return $_[0] ? "reject" : "ok"
259             }
260             },
261             currency2 => 3,
262             transactionCost => {
263             w => 6,
264             su => sub {
265 1     1   6 return int($_[0]) / 100;
266             }
267             }
268 1         38 ]
269             };
270 1         5 my %parser;
271              
272 1         6 for my $type (keys %$GSR){
273 2         6 my @keys;
274 2         12 my $parser = '^';
275 2         5 my %proc;
276              
277 2         3 while (my $key = shift @{$GSR->{$type}}){
  32         94  
278 30         54 my $val = shift @{$GSR->{$type}};
  30         55  
279 30         53 my $w = $val;
280 30         77 my $rx = qr/(.*)/;
281 30     469   77 my $su = sub { return shift };
  469         1155  
282 30 100       70 if (ref $val){
283 24   50     58 $w = $val->{w} || die "$key -> w - width property is mandatory";
284 24   66     56 $su = $val->{su} // $su;
285 24   66     85 $rx = $val->{rx} // $rx;
286             }
287 30         60 push @keys, $key;
288 30         62 $parser .= "(.{$w})";
289 30         100 $proc{$key} = {
290             rx => $rx,
291             su => $su
292             }
293             }
294 2         3 $parser .= '$';
295 2         8 $parser{$type} = {
296             rx => $parser,
297             proc => \%proc,
298             keys => \@keys
299             };
300             }
301              
302             sub parse {
303 2     2 1 3362 my $self = shift;
304 2         160 my @data = split /[\r?\n]/, shift;
305 2         4 my @all;
306 2         6 for my $line (@data){
307 314         1127 $line =~ s/\s+$//;
308 314         755 for my $type (keys %parser){
309 627         993 my %d;
310 627         1123 my $parse = $parser{$type}{rx};
311 627         946 my @keys = @{$parser{$type}{keys}};
  627         2006  
312 627         11473 @d{@keys} = $line =~ /$parse/;
313 627   100     3020 $d{microfilmReference} //= '-';
314 627 100       2164 next if not defined $d{transactionCost};
315 156         258 for my $key (keys %{$parser{$type}{proc}}){
  156         570  
316 2186 50       5568 if (my $su = $parser{$type}{proc}{$key}{su} ){
317 2186         8054 $d{$key} = $su->( $d{$key} =~ $parser{$type}{proc}{$key}{rx} );
318             }
319             }
320 156         415 push @all,\%d;
321 156         444 last;
322             }
323             }
324 2         37 return \@all;
325             }
326              
327              
328 1         57 1;
329              
330             __END__