File Coverage

blib/lib/Business/OnlinePayment/IPayment/Response.pm
Criterion Covered Total %
statement 73 81 90.1
branch 28 38 73.6
condition 5 8 62.5
subroutine 12 12 100.0
pod 6 6 100.0
total 124 145 85.5


line stmt bran cond sub pod time code
1             package Business::OnlinePayment::IPayment::Response;
2 8     8   80676 use strict;
  8         26  
  8         201  
3 8     8   44 use warnings;
  8         17  
  8         169  
4 8     8   557 use utf8;
  8         25  
  8         63  
5 8     8   184 use Digest::MD5 qw/md5_hex/;
  8         16  
  8         344  
6 8     8   3629 use Moo;
  8         57556  
  8         36  
7              
8             =encoding utf8
9              
10             =head1 NAME
11              
12             Business::OnlinePayment::IPayment::Response - Helper class for Ipayment responses
13              
14             =head1 SYNOPSIS
15              
16             # where %params are the GET parameters
17             $ipayres = Business::OnlinePayment::IPayment::Response->new(%params);
18              
19             $ipayres->set_credentials(
20             my_amount => "5000",
21             my_currency => "EUR",
22             my_userid => "99999",
23             my_security_key => "testtest",
24             );
25             ok($ipayres->is_success && $ipayres->is_valid, "Payment looks ok");
26              
27             =head1 DESCRIPTION
28              
29             =head2 ACCESSORS
30              
31             =over 4
32              
33             =item ret_transtime
34              
35             Time of transaction.
36              
37             =cut
38              
39             has ret_transtime => (is => 'ro',
40             default => sub { return "" });
41              
42             =item ret_transdate
43              
44             Date of the transaction.
45              
46             =cut
47              
48             has ret_transdate => (is => 'ro',
49             default => sub { return "" });
50              
51             =item ret_errorcode
52              
53             The error code of 0 means that the transaction was successful. When in
54             a CGI integration mode parameter redirect_needed returned with the
55             value 1 is the only means that all data is correct and a redirect must
56             be running. The return value is meaningful only after a second call.
57              
58             =cut
59              
60             has ret_errorcode => (is => 'ro',
61             default => sub { return "" });
62              
63             =item redirect_needed
64              
65             This parameter is set if the payment could not be completed because of
66             a redirect necessary.
67              
68             =cut
69              
70              
71             =item ret_errormsg
72              
73             Error message (in German). This is important to propagate to the web
74             interface.
75              
76             =cut
77              
78             has ret_errormsg => (is => 'ro',
79             default => sub { return "" });
80              
81              
82             =item ret_additionalmsg
83              
84             Additional Error message, sometimes in English, sometimes inexistent.
85              
86             =cut
87              
88             has ret_additionalmsg => (is => 'ro',
89             default => sub { return "" });
90              
91             =item ret_fatalerror
92              
93             This value is returned only if an error has occurred.
94              
95             Based on this value, your shop offer the buyer the option of payment
96             data correct as long as there is no fatal error. Fatal errors are
97             usually disruptions in Bank network or other problems where a new
98             trial is expected no Improvement brings. Your customers, you can in
99             this case, a specific error message
100              
101             =cut
102              
103             has ret_fatalerror => (is => 'ro',
104             default => sub { return "" });
105              
106              
107             has redirect_needed => (is => 'ro',
108             default => sub { return "" });
109              
110             =item addr_name
111              
112             Data type: string, maximum 100 characters
113             Name of the buyer. This parameter is required for all payments.
114              
115             =cut
116              
117             has addr_name => (is => 'ro',
118             default => sub { return "" });
119              
120              
121             =item addr_email
122              
123             Data type: string, B
124              
125             E-mail address of the buyer. If this field is filled in, the e-mail
126             address is checked for plausibility.
127              
128             =cut
129              
130             has addr_email => (is => 'ro',
131             default => sub { return "" });
132              
133             =item addr_street
134              
135             =cut
136              
137             has addr_street => (is => 'ro',
138             default => sub { return "" });
139              
140             =item addr_city
141              
142             City
143              
144             =cut
145              
146             has addr_city => (is => 'ro',
147             default => sub { return "" });
148              
149             =item addr_zip
150              
151             ZIP code
152              
153             =cut
154              
155             has addr_zip => (is => 'ro',
156             default => sub { return "" });
157              
158             =item addr_country
159              
160             ISO country code (2 chars, not 3 as the documentation says)
161              
162             =back
163              
164             =cut
165              
166             has addr_country => (is => 'ro',
167             default => sub { return "" });
168              
169             =head3 Optional contact details
170              
171             =over 4
172              
173             =item addr_street2
174              
175             Second street.
176              
177             =cut
178              
179             has addr_street2 => (is => 'ro',
180             default => sub { return "" });
181              
182             =item addr_state
183              
184             (USA only), two chars.
185              
186             =cut
187              
188             has addr_state => (is => 'ro',
189             default => sub { return "" });
190              
191             =item addr_telefon
192              
193             Telephone, max 30 chars
194              
195             =cut
196              
197             has addr_telefon => (is => 'ro',
198             default => sub { return "" });
199              
200             =item addr_telefax
201              
202             Telefax, max 30 chars
203              
204             =back
205              
206             =cut
207              
208             has addr_telefax => (is => 'ro',
209             default => sub { return "" });
210              
211             =head3 Payment details
212              
213             =over 4
214              
215             =item trx_paymentmethod
216              
217             In this parameter the name of the medium used, payment will be
218             returned. the For example, a credit card type (such as Visa or
219             MasterCard) or ELV.
220              
221             =cut
222              
223             has trx_paymentmethod => (is => 'ro',
224             default => sub { return "" });
225              
226             =item ret_authcode
227              
228             Authorization number of third party payment for this transaction or
229             other unique Identification of the payment the payment provider. The
230             parameters may in certain cases be empty.
231              
232             =cut
233              
234             has ret_authcode => (is => 'ro',
235             default => sub { return ""});
236              
237              
238             =item trx_currency
239              
240             Currency in which the payment is processed. There are all known
241             three-letter ISO Currency codes allowed. A list of known currency
242             codes, see L under B.
243              
244             Note that the processing of payments in the currency must be agreed
245             with your payment provider.
246              
247              
248             =cut
249              
250             has trx_currency => (is => 'ro',
251             default => sub { return "" });
252              
253              
254             =item ret_url_checksum
255              
256             =cut
257              
258             has ret_url_checksum => (is => 'ro',
259             default => sub { return "" });
260              
261              
262             =item ret_param_checksum
263              
264             =cut
265              
266             has ret_param_checksum => (is => 'ro',
267             default => sub { return "" });
268              
269              
270             =item ret_ip
271              
272             IP of the client who did the transaction
273              
274             =cut
275              
276             has ret_ip => (is => 'ro',
277             default => sub { return "" });
278              
279              
280             =item trx_typ
281              
282             See C in L
283              
284             =cut
285              
286             has trx_typ => (is => 'ro',
287             default => sub { return "" });
288              
289              
290             =item ret_trx_number
291              
292             If the status is C, here we have the Unique transaction
293             number (reservation number) of ipayment system. this number is
294             returned in the form of "x-xxxxxxx", where x is a single digit. with
295             this Transaction number, you can perform other actions such as
296             charging or cancellations.
297              
298             =cut
299              
300             has ret_trx_number => (is => 'ro',
301             default => sub { return "" });
302              
303              
304             =item ret_status
305              
306             The possible values ​​are:
307              
308             C: The transaction has been successfully completed.
309              
310             C: In transaction processing, an error occurred.
311              
312             C: To further processing must be performed a redirect (3-D
313             secure, verification needed)
314              
315             =cut
316              
317             has ret_status => (is => 'ro',
318             default => sub { return "" });
319              
320              
321             =item trx_paymenttyp
322              
323             Values: C (Credit card), C (ELV), C (Prepaid payment)
324              
325             =cut
326              
327             has trx_paymenttyp => (is => 'ro',
328             default => sub { return "" });
329              
330              
331             =item trx_paymentdata_country
332              
333             In this parameter, if possible, the ISO code of the country returned
334             to the the payment data belongs. The field contains, for example, for
335             credit card payments, the country the card-issuing bank and ELV
336             payments the bank country.
337              
338             =cut
339              
340             has trx_paymentdata_country => (is => 'ro',
341             default => sub { return "" });
342              
343              
344             =item trx_amount
345              
346             Amount to be debited. Enter the value in the B
347             unit>, for Example cents. B or other characters except
348             numbers are B.
349              
350             For example, the amount of EUR 10.00 is given as 1000 cents.
351              
352             =cut
353              
354             has trx_amount => (is => 'ro',
355             default => sub { return "" });
356              
357              
358             =item ret_booknr
359              
360             Used for the checksum and apparently not documented.
361              
362             =cut
363              
364             has ret_booknr => (is => 'ro',
365             default => sub { return "" });
366              
367              
368             =item trxuser_id
369              
370             See C in Business::OnlinePayment::IPayment
371              
372             =cut
373              
374             has trxuser_id => (is => 'ro',
375             default => sub { return "" });
376              
377              
378             =item trx_remoteip_country
379              
380             Iso code of the IP which does the transaction
381              
382             =back
383              
384             =cut
385              
386             has trx_remoteip_country => (is => 'ro',
387             default => sub { return "" });
388              
389             =head2 Payment data
390              
391             Optional data returned by the Ipayment server if the cgi parameter
392             C is set to 1 (no SOAP for this, you have
393             to add an hidded input field in the form).
394              
395             The credit card number is returned masked with the last 4 digits
396             visible.
397              
398             =over 4
399              
400             =item paydata_cc_cardowner
401              
402             =cut
403              
404             has paydata_cc_cardowner => (is => 'ro',
405             default => sub { return "" });
406              
407              
408             =item paydata_cc_number
409              
410             =cut
411              
412             has paydata_cc_number => (is => 'ro',
413             default => sub { return "" });
414              
415              
416             =item paydata_cc_typ
417              
418             =cut
419              
420             has paydata_cc_typ => (is => 'ro',
421             default => sub { return "" });
422              
423              
424              
425             =item paydata_cc_expdate
426              
427             =cut
428              
429             has paydata_cc_expdate => (is => 'ro',
430             default => sub { return "" });
431              
432             =back
433              
434             =cut
435              
436              
437             =head2 Setters needed for the hash checking
438              
439             =head3 my_amount
440              
441             You need to set the C attribute if you want to check
442             the hash.
443              
444             =cut
445              
446             has my_amount => (is => 'rw');
447              
448             =head3 my_userid
449              
450             Our trxuser_id
451              
452             =cut
453              
454             has my_userid => (is => 'rw');
455              
456             =head3 my_currency
457              
458             Our currency
459              
460             =cut
461              
462             has my_currency => (is => 'rw');
463              
464             =head3 my_security_key
465              
466             The security key
467              
468             =cut
469              
470             has my_security_key => (is => 'rw');
471              
472             =head3 shopper_id
473              
474             The cart->id of the transaction
475              
476             =cut
477              
478             has shopper_id => (is => 'rw');
479              
480              
481             =head3 invoice_text
482              
483             In payment processing with the below payment provider you can use a
484             Specify text that is sent to the payment provider. This text if the
485             debiting more precisely describe. Depending on the payment providers
486             and credit cards out bender site This text is printed on the card
487             account of the customer and / or dealer. If this parameter is not set,
488             ipayment automatically uses the company name merchant that you
489             specified in the configuration menu ipayment under General Data
490              
491             This can be sent into the options as C{invoiceText}>
492              
493             =cut
494              
495             has invoice_text => (is => 'ro',
496             default => sub { return "" });
497              
498             =head3 trx_user_comment
499              
500             Comment that is stored in the transaction in ipayment system. this
501             comment is not sent to the bank or payment processor.
502              
503             This can be sent into the options as C{trxUserComment}>
504              
505             =cut
506              
507             has trx_user_comment => (is => 'ro',
508             default => sub { return "" });
509              
510              
511             =head2 Storage accessors
512              
513             =head3 datastorage_expirydate
514              
515             The date as returned by the ipayment server (like: 2008/09/15)
516              
517             =cut
518              
519             has datastorage_expirydate => (is => 'ro',
520             default => sub { return "" });
521              
522             =head3 storage_id
523              
524             The storage id for the current transaction.
525              
526             =cut
527              
528             has storage_id => (is => 'ro',
529             default => sub { return "" });
530              
531              
532             =head3 trx_issuer_avs_response
533              
534             AVS related response.p. 62 of the doc
535              
536             =cut
537              
538             has trx_issuer_avs_response => (is => 'ro',
539             default => sub { return "" });
540              
541             =head3 trx_payauth_status
542              
543             3D-related response, p. 62 of the doc
544              
545             =cut
546              
547             has trx_payauth_status => (is => 'ro',
548             default => sub { return "" });
549              
550              
551              
552             =head2 METHODS
553              
554             =head3 set_credentials(%hash)
555              
556             As a shortcut, you can set the above attribute using this method
557              
558             =cut
559              
560             sub set_credentials {
561 1     1 1 29 my ($self, %args) = @_;
562 1 50       6 if (defined $args{my_userid}) {
563 0         0 $self->my_userid($args{my_userid});
564             }
565 1 50       5 if (defined $args{my_security_key}) {
566 0         0 $self->my_security_key($args{my_security_key});
567             }
568 1 50       4 if (defined $args{my_amount}) {
569             $self->my_amount($args{my_amount})
570 1         5 }
571 1 50       3 if (defined $args{my_currency}) {
572 1         6 $self->my_currency($args{my_currency});
573             }
574             }
575              
576              
577             =head3 is_success
578              
579             Return true if the transaction was successful, undef otherwise
580              
581             =cut
582              
583             sub is_success {
584 12     12 1 5240 my $self = shift;
585 12 100 66     109 if ($self->ret_status eq 'SUCCESS' and !$self->ret_errorcode) {
586 11         45 return 1;
587             }
588             else {
589 1         5 return undef;
590             }
591             }
592              
593             =head3 is_error
594              
595             Return true if the transaction raised an error, undef otherwise.
596             You can access the German error message with the accessor
597             C
598              
599             =cut
600              
601             sub is_error {
602 1     1 1 3 my $self = shift;
603 1 50       6 if ($self->ret_status eq 'ERROR') {
604 0         0 return 1;
605             }
606             else {
607 1         4 return undef;
608             }
609             }
610              
611              
612             =head3 is_valid
613              
614             Return true if the servers return a checksum (for this you have to
615             build a session with C for this to work, and you
616             should use the app_security_key).
617              
618             CGI Name: C
619             Data type: String
620              
621             The hash is the md5sum of the concatenation of C
622             C, C, C, C and
623             I.
624              
625             If one of the fields is empty or not returned, use the empty string.
626              
627              
628             The checksum is only in case of success of a transaction
629             (ret_errorcode = 0 and redirect_ needed = 0) are available.
630              
631             perl -e 'use Digest::MD5 qw/md5_hex/;
632             print md5_hex("99998" . 5000 . "EUR" . "" . "1-83400472" . "testtest");'
633              
634             # => 6bff5d51a44f048e887d1ab7677c4798 and it matches
635              
636             =head3 validation_errors
637              
638             With this accessor you are able to lookup the validation errors found
639              
640             =cut
641              
642             has validation_errors => (is => 'rwp');
643              
644             sub _add_valid_error {
645 26     26   44 my $self = shift;
646 26         44 my $error = shift;
647 26   100     114 my $olderr = $self->validation_errors || "";
648 26         98 $self->_set_validation_errors($olderr . " " . $error);
649             }
650              
651             sub is_valid {
652 15     15 1 343 my $self = shift;
653             # clear the error stack
654 15         68 $self->_set_validation_errors("");
655 15 50       68 unless ($self->ret_param_checksum) {
656 0         0 $self->_set_validation_errors("No checksum provided!");
657 0         0 return 0;
658             }
659              
660 15 100       246 die "Validation asked, but you didn't provide the security key!\n"
661             unless $self->my_security_key;
662            
663            
664 14 100       50 unless ($self->my_amount) {
665 11         49 $self->_add_valid_error("Using the data passed by the server!");
666 11         49 $self->my_amount($self->trx_amount);
667             }
668 14 100       48 unless ($self->my_currency) {
669 11         34 $self->_add_valid_error("Using the currency passed by the server!");
670 11         43 $self->my_currency($self->trx_currency);
671             }
672 14 100       47 unless ($self->my_userid) {
673 1         3 $self->_add_valid_error("Using the userid passed by the server!");
674 1         3 $self->my_userid($self->trxuser_id);
675             }
676            
677 14         155 my $expectedhash = md5_hex($self->my_userid .
678             $self->my_amount .
679             $self->my_currency .
680             $self->ret_authcode .
681             $self->ret_booknr .
682             $self->my_security_key);
683 14 100       60 if ($expectedhash eq $self->ret_param_checksum) {
684 12         74 return "OK"
685             }
686             else {
687 2         12 $self->_add_valid_error("Expected hash $expectedhash isn't " . $self->ret_param_checksum);
688 2         8 return 0;
689             }
690             }
691              
692              
693             =head3 raw_url
694              
695             Accessor for the raw, undecoded url (used for the checksum).
696              
697             =cut
698              
699              
700             has raw_url => (is => 'rw');
701              
702              
703              
704             =head3 url_is_valid($raw_undecoded_url)
705              
706             You may ask for the validation of the url, which comes with a checksum
707             attached. For this you should have already provided the security key
708             and you should pass the raw undecoded url as argument.
709              
710             Alternatively, if you set the attribute C in the constructor
711             or with the accessor, you can call url_is_valid without arguments.
712              
713             Return false on failure, true on success
714              
715             Original German doc (left in place because the translation was drunk).
716              
717             CGI-Name: ret_url_checksum
718             Webservice-Name: - (nicht benötigt)
719             Datentyp: String
720              
721             Wenn Sie für eine Transaktion eine Anwendung mit einem Security-Key
722             verwendet haben, wird dieser Parameter mit einem MD5-Hash an die
723             Rücksprungs-URL angehängt.
724              
725             Für die Bildung des Hash wird an die Rücksprungs-URL ein & und der
726             Transaktions-Security- Key der Anwendung angehängt. Für diese
727             Zeichenkette wird die MD5-Prüfsumme generiert. Der ermittelte Hash
728             wird als Parameter ret_url_checksum an die Rücksprungs-URL hinter alle
729             anderen Parameter an das Ende angehängt.
730              
731             Um die Prüfsumme zu überprüfen müssen Sie den Parameter
732             ret_url_checksum von der vollständigen URL des aufgerufenen Scriptes
733             abschneiden, den Transaktions-Security-Key anhängen und dann die
734             MD5-Prüfsumme ermitteln. Wenn die Prüfsumme nicht mit dem Wert des
735             Parameters ret_url_checksum übereinstimmt, liegt vermutlich eine
736             Manipulation der URL vor.
737              
738             =cut
739              
740             sub url_is_valid {
741 5     5 1 93 my ($self, $url) = @_;
742 5 100       15 unless ($url) {
743 2         10 $url = $self->raw_url;
744             }
745             # clear the error stack;
746 5         19 $self->_set_validation_errors("");
747 5 50       14 $self->_set_validation_errors("Missing url for url validation")
748             unless $url;
749 5 50       19 $self->_add_valid_error("Missing secret key for url validation")
750             unless $self->my_security_key;
751 5 50 33     32 unless ($url and $self->my_security_key) {
752 0         0 return 0
753             }
754              
755 5         10 my $checksum;
756             # warn $url;
757             # unclear if the & should be removed
758 5 50       34 if ($url =~ m/&ret_url_checksum=([A-Za-z0-9]+)$/) {
759 5         12 $checksum = $1;
760             # it looks like the trailing & should be left in place
761 5         29 $url =~ s/ret_url_checksum=([A-Za-z0-9]+)$//
762             } else {
763 0         0 $self->_add_valid_error("checksum not found\n");
764 0         0 return 0
765             }
766 5         43 my $ourchecksum = md5_hex($url . $self->my_security_key);
767 5 100       17 if ($ourchecksum eq $checksum) {
768 4         24 return "OK";
769             } else {
770 1         5 $self->_add_valid_error("Url checksums don't match");
771 1         4 return 0;
772             }
773             }
774              
775             =head3 address_info
776              
777             Shortcut that combines the cardholder details, separated by a whitespace
778              
779             =cut
780              
781             sub address_info {
782 3     3 1 1287 my $self = shift;
783 3         5 my @details;
784 3         8 foreach my $method (qw/addr_name addr_street addr_street2
785             addr_zip addr_city
786             addr_state addr_country addr_email
787             addr_telefon
788             addr_telefax/) {
789 30 100       72 if (my $det = $self->$method) {
790 14         23 push @details, $det
791             }
792             }
793 3         17 return join(" ", @details);
794             }
795              
796              
797              
798             ### HERE WE CAN ADD SOME SHORTCUTS FOR THE SHOP, so we can extract the
799             ### interesting parameters
800              
801             1;
802              
803              
804              
805