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   1401 use Mojo::Base -base;
  1         1  
  1         8  
94              
95 1     1   156 use vars qw($VERSION);
  1         1  
  1         1186  
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   1054 return ((2000+$_[0])."-$_[1]-$_[2]");
107             }
108 1         7 };
109             my $date4 = {
110             w => 8,
111             rx => qr/(....)(..)(..)/,
112             su => sub {
113 3     3   6 return "$_[0]-$_[1]-$_[2]";
114             }
115 1         4 };
116              
117 1         4 my %src = (
118             '0' => 'online',
119             '1' => 'postoffice counter',
120             '2' => 'cash on delivery'
121             );
122              
123 1         2 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   272 return $_[0] ? 'ESR+' : 'ESR';
137             }
138             },
139             paymentLocation => {
140             w => 1,
141             su => sub {
142 155   33 155   320 return $src{$_[0]} || $_[0];
143             }
144             },
145             paymentType => {
146             w => 1,
147             su => sub {
148 155   33 155   344 return $type{$_[0]} || $_[0];
149             }
150             },
151             accontNumber => {
152             w => 9,
153             rx => qr/(..)0*(.+)(.)/,
154             su => sub {
155 155     155   308 return "$_[0]-$_[1]-$_[2]";
156             }
157             },
158             referenceNumber => {
159             w => 27,
160             rx => qr/(.+)./,
161             su => sub {
162 155     155   127 my $ret = shift;
163 155         291 $ret =~ s/^0+//;
164 155         223 return $ret;
165             }
166             },
167             amount => {
168             w => 10,
169             su => sub {
170 155     155   272 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   286 return $_[0] ? "reject" : "ok"
182             }
183             },
184             reseved => 9,
185             transactionCost => {
186             w => 4,
187             su => sub {
188 155     155   322 return int($_[0]) / 100;
189             }
190             }
191             ],
192             typ4 => [
193             paymentSlip => {
194             w => 1,
195             su => sub {
196             return [
197 1     1   4 '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   6 return [ undef,'normal','nachnahme','ownaccount']->[$_[0]] // 'Unknown Source '.$_[0];
208             }
209             },
210             paymentType => {
211             w => 1,
212             su => sub {
213 1   33 1   6 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   9 }->{$_[0]} // 'Unknown Location '.$_[0];
225             }
226             },
227             deliveryType => {
228             w => 1,
229             su => sub {
230 1   33 1   5 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   3 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   3 return $_[0] ? "reject" : "ok"
259             }
260             },
261             currency2 => 3,
262             transactionCost => {
263             w => 6,
264             su => sub {
265 1     1   3 return int($_[0]) / 100;
266             }
267             }
268 1         25 ]
269             };
270 1         2 my %parser;
271              
272 1         2 for my $type (keys %$GSR){
273 2         2 my @keys;
274 2         3 my $parser = '^';
275 2         2 my %proc;
276              
277 2         0 while (my $key = shift @{$GSR->{$type}}){
  32         50  
278 30         16 my $val = shift @{$GSR->{$type}};
  30         24  
279 30         21 my $w = $val;
280 30         35 my $rx = qr/(.*)/;
281 30     469   43 my $su = sub { return shift };
  469         733  
282 30 100       38 if (ref $val){
283 24   50     33 $w = $val->{w} || die "$key -> w - width property is mandatory";
284 24   66     29 $su = $val->{su} // $su;
285 24   66     70 $rx = $val->{rx} // $rx;
286             }
287 30         58 push @keys, $key;
288 30         27 $parser .= "(.{$w})";
289 30         71 $proc{$key} = {
290             rx => $rx,
291             su => $su
292             }
293             }
294 2         2 $parser .= '$';
295 2         7 $parser{$type} = {
296             rx => $parser,
297             proc => \%proc,
298             keys => \@keys
299             };
300             }
301              
302             sub parse {
303 2     2 1 2838 my $self = shift;
304 2         151 my @data = split /[\r?\n]/, shift;
305 2         2 my @all;
306 2         4 for my $line (@data){
307 314         611 $line =~ s/\s+$//;
308 314         412 for my $type (keys %parser){
309 473         270 my %d;
310 473         407 my $parse = $parser{$type}{rx};
311 473         301 my @keys = @{$parser{$type}{keys}};
  473         887  
312 473         5862 @d{@keys} = $line =~ /$parse/;
313 473   100     1103 $d{microfilmReference} //= '-';
314 473 100       1030 next if not defined $d{transactionCost};
315 156         112 for my $key (keys %{$parser{$type}{proc}}){
  156         367  
316 2186 50       2952 if (my $su = $parser{$type}{proc}{$key}{su} ){
317 2186         5787 $d{$key} = $su->( $d{$key} =~ $parser{$type}{proc}{$key}{rx} );
318             }
319             }
320 156         224 push @all,\%d;
321 156         277 last;
322             }
323             }
324 2         34 return \@all;
325             }
326              
327              
328 1         12 1;
329              
330             __END__