=cut
-enum 'Action' => qw(payment credit);
+enum 'Action' => [qw(payment credit)];
coerce 'Action', from 'Str', via { lc $_ };
has action => (
is => 'rw',
=cut
# are we okay with these names?
-enum 'PaymentType' => qw( CC ECHECK );
+enum 'PaymentType' => [qw( CC ECHECK )];
has payment_type => ( is => 'rw', isa => 'PaymentType' );
=item amount
Billing address fields. Credit card processors may use these (especially
zip) for authentication.
+ =item phone
+
+ Customer phone number.
+
=cut
has [ qw(
state
country
zip
+ phone
) ] => ( is => 'rw', isa => 'Str', default => '' );
=back
=item process_date
- The date requested for processing.
+ The date requested for processing. This is meaningful only if the
+ processor allows different processing dates for items in the same
+ batch.
=item invoice_number
=cut
has card_number => ( is => 'rw', isa => 'Str' );
- has expiration => ( is => 'rw', isa => 'Str' );
+ has ['expiration_month', 'expiration_year'] => ( is => 'rw', isa => 'Int' );
+
+ sub expiration {
+ # gets/sets expiration_month and _year in MMYY format
+ my $self = shift;
+ my $arg = shift;
+ if ( $arg ) {
+ # well, we said it's in MMYY format
+ my ($m, $y) = _parse_expiration($arg);
+ $self->expiration_month($m);
+ $self->expiration_year($y);
+ }
+ return sprintf('%02d/%02d',
+ $self->expiration_month,
+ $self->expiration_year % 2000);
+ }
+
+ sub _parse_expiration {
+ my $arg = shift;
+ if ( $arg =~ /^(\d\d)(\d\d)$/ ) {
+ return ($1, 2000 + $2);
+ } elsif ( $arg =~ /^(\d\d?)\W(\d\d)$/ ) {
+ return ($1, 2000 + $2);
+ } elsif ( $arg =~ /^(\d\d?)\W(\d\d\d\d)$/ ) {
+ return ($1, $2);
+ } elsif ( $arg =~ /^(\d\d?)\W\d\d?\W(\d\d\d\d)$/) {
+ return ($1, $3);
+ } else {
+ die "can't parse expiration date '$arg'";
+ }
+ }
+
+ sub payinfo {
+ # gets/sets either the card number, or the account number + routing code
+ # depending on the payment type
+ my $self = shift;
+ if ( $self->payment_type eq 'CC' ) {
+ $self->card_number(@_);
+ } elsif ( $self->payment_type eq 'ECHECK' ) {
+ my $arg = shift;
+ if ( $arg ) {
+ $arg =~ /^(\d+)@(\d+)$/ or die "Validation failed for payinfo";
+ $self->account_number($1);
+ $self->routing_code($2);
+ }
+ return ($self->account_number . '@' . $self->routing_code);
+ }
+ }
=back
The message returned by the gateway. This may contain a value even
if the payment was successful (use C<approved> to determine that.)
+ =item failure_status
+
+ A normalized failure status, from the following list:
+
+ =over 4
+
+ =item expired
+
+ =item nsf (non-sufficient funds / credit limit)
+
+ =item stolen
+
+ =item pickup
+
+ =item blacklisted
+
+ =item inactive
+
+ =item decline (other card/transaction declines)
+
+ =back
+
=back
=cut
assigned_token
)] => ( is => 'rw', isa => 'Str');
+ enum FailureStatus => qw(
+ expired
+ nsf
+ stolen
+ pickup
+ blacklisted
+ inactive
+ decline
+ );
+ has failure_status => ( is => 'rw', isa => 'Maybe[FailureStatus]' );
+
has check_number => ( is => 'rw', isa => 'Int' );
+ around 'BUILDARGS' => sub {
+ my ($orig, $self, %args) = @_;
+ if ( $args{expiration} ) {
+ @args{'expiration_month', 'expiration_year'} =
+ _parse_expiration($args{expiration});
+ }
+ $self->$orig(%args);
+ };
+
__PACKAGE__->meta->make_immutable;
1;