#################### main pod documentation begin ###################
=head1 NAME
Zymonic::Action::PaymentGateway -s Zymonic Workflow System Action module
=head1 SYNOPSIS
use Zymonic::Action::PaymentGateway;
Performs a PaymentGateway authroisation using the Decryptor.
=head1 DESCRIPTION
Performs a PaymentGateway authroisation using the Decryptor.
=head1 USAGE
The following ClassOption Schema should be used:
Token should be a valid PTE token. Will be passed to decryptor as:
card_number => ENCRYPTEDtokenENCRYPTED
so when it reaches decrytpor it will have been decrytped.
Extras is used to pass extra values through to the PaymentGateway, e.g.
card_number, epiry_date, etc... or anything needed for a specific
PaymentGateway.
=head1 BUGS
NONE
=head1 SUPPORT
As in the license, Zymonic is provided without warranty or support
unless purchased separately, however... If you email
zymonic-support@zednax.com your issue will be noted and may
receive a response.
For security issues, please contact zymonic-security@zednax.com and
someone will respond within 8 working hours.
=head1 AUTHOR
Alex Masidlover et al.
CPAN ID: MODAUTHOR
Zednax Limited
alex.masidlover@zednax.com
http://www.zednax.com
=head1 COPYRIGHT
This program is free software licensed under the...
Alfresco Public License 1.0
The full text of the license can be found in the
LICENSE file included with this module.
Other licenses may be acceptable if including
parts of Zymonic in larger projects, please
contact Zednax for details.
=head1 SEE ALSO
Zymonic
perl(1).
=cut
#################### main pod documentation end ###################
package Zymonic::Action::PaymentGateway;
use strict;
BEGIN
{
use Exporter ();
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
$VERSION = 'D1-r7186';
@ISA = qw(Exporter);
#Give a hoot don't pollute, do not export more than needed by default
@EXPORT = qw();
@EXPORT_OK = qw();
%EXPORT_TAGS = ();
}
use base "Zymonic::Action";
use Zymonic::Decryptor::Client;
use Zymonic::Table;
use Zymonic::Utils qw(get_array debug deep_replace_card_numbers);
use Data::Dumper;
#################### subroutine header begin ####################
=head2 init
Usage : N/A
Purpose : The init method is called by the object constructor
to initialise the object fields. In this case it retrieves the
form definition from the config module and then loads all the
fields as objects.
Returns : nothing
Argument : nothing
Throws : nothing
Comment : Suggested that the Transition and all the mechanisms
called by Action to have permission checks that there is no need for
action to have permissions on it at this stage.
See Also :
=cut
#################### subroutine header end ####################
sub init
{
my $self = shift;
$self->{other_fields} = {};
if ( $self->{state} && $self->{state}->{form} )
{
$self->{other_fields} = $self->{state}->{form}->{records}->[0]->{fields};
}
}
################# subroutine header begin ####################
=head2 timeout
Usage : $action->timeout
Purpose : Gets the timeout value from class options
Returns : a scalar timeout value
Argument : nothing
Throws : nothing
Comment :
See Also :
=cut
#################### subroutine header end ####################
sub timeout
{
my $self = shift;
return $self->static_or_field_value( 'Timeout', $self->{other_fields}, 'optional' );
}
################# subroutine header begin ####################
=head2 payment_gateway
Usage : $action->payment_gateway
Purpose : Gets the payment_gateway value from the transaction settings.
Returns : a scalar payment_gateway value
Argument : nothing
Throws : nothing
Comment : Looks up transaciton, gets merchant id, then finds payment
gateway from that.
See Also :
=cut
#################### subroutine header end ####################
sub payment_gateway
{
my $self = shift;
return $self->static_or_field_value( 'PaymentGatway', $self->{other_fields}, 'optional' );
}
################# subroutine header begin ####################
=head2 token
Usage : $action->token
Purpose : Gets the token value from class option defined field
Returns : a scalar token value
Argument : nothing
Throws : nothing
Comment :
See Also :
=cut
#################### subroutine header end ####################
sub token
{
my $self = shift;
return $self->{token_field}->value if $self->{token_field};
my $tf_ref = $self->{other_fields}->{ $self->{xmldef}->{ClassOptions}->{Token}->{Field}->{ZName}->{content} };
Zymonic::Exception::Action->throw(
error => "Unable to find Token field: "
. $self->{xmldef}->{ClassOptions}->{TokenID}->{Field}->{ZName}->{content},
zname => $self->{zname},
catchable => 'false'
) unless $tf_ref;
$self->{token_field} = $tf_ref->{parent}->get_object($tf_ref);
$self->{token_field}->value( $self->{token_field}->raw_value, $self->{token_field}->{fromdb} )
unless defined $self->{token_field}->value;
return $self->{token_field}->value;
}
################# subroutine header begin ####################
=head2 transaction_id
Usage : $action->transaction_id
Purpose : Gets the transaction_id value from class option defined field
Returns : a scalar transaction_id value
Argument : nothing
Throws : nothing
Comment :
See Also :
=cut
#################### subroutine header end ####################
sub transaction_id
{
my $self = shift;
return $self->{transaction_id_field}->value if $self->{transaction_id_field};
my $ti_ref =
$self->{other_fields}->{ $self->{xmldef}->{ClassOptions}->{TransactionID}->{Field}->{ZName}->{content} };
Zymonic::Exception::Action->throw(
error => "Unable to find TransactionID field: "
. $self->{xmldef}->{ClassOptions}->{TransactionID}->{Field}->{ZName}->{content} . ' in ('
. join( ', ', map { $_->{zname} } get_array( $self->{other_fields} ) ) . ')',
zname => $self->{zname},
catchable => 'false'
) unless $ti_ref;
$self->{transaction_id_field} = $ti_ref->{parent}->get_object($ti_ref);
$self->{transaction_id_field}
->value( $self->{transaction_id_field}->raw_value, $self->{transaction_id_field}->{fromdb} )
unless defined $self->{transaction_id_field}->value;
return $self->{transaction_id_field}->value;
}
################# subroutine header begin ####################
=head2 extras
Usage : $action->extras
Purpose : Gets the extras value from class options
Returns : A hashref of key/value options as retrieved from ClassOptions.
Argument : nothing
Throws : nothing
Comment :
See Also :
=cut
#################### subroutine header end ####################
sub extras
{
my $self = shift;
my $extras = {};
foreach my $extra ( get_array( $self->{ClassOptions}->{Extras} ) )
{
if ( $extra->{Key} && $extra->{Value} )
{
$extras->{ $extra->{Key}->{content} } =
$self->static_or_field_value( 'Value', $self->{other_fields}, '', '', $extra );
}
}
return $extras;
}
#################### subroutine header begin ####################
=head2 do
Usage : $action->do
Purpose : Performs the action, i.e. generates the report
Returns : nothing
Argument : nothing
Throws : TODO
Comment : nothing
=cut
#################### subroutine header end ####################
sub do
{
my $self = shift;
my $fake = shift || '';
my $no_display_attributes = shift || 0;
my $conditions = $self->conditions($fake);
$self->{condition_passed} = 'false';
$self->{success} = 'false';
if ( $conditions->{condition_passed} )
{
$self->{condition_passed} = 'true';
my $token = $self->token();
my $transaction_id = $self->transaction_id();
my $payment_gateway = $self->payment_gateway();
my $request = {
messagetype => 'PaymentGateway',
payment_gateway_type => $payment_gateway,
%{ $self->payment_gateway_details($payment_gateway) },
%{ $self->transaction_details($transaction_id) },
%{ $self->payment_data_details($token) },
token => $token,
card_number => 'ENCRYPTED' . $token . 'ENCRYPTED',
timeout => $self->timeout || '',
%{ $self->extras }
};
debug( 'Payment Gateway request: ' . Dumper( deep_replace_card_numbers($request) ) );
# call the decryptor to process the transactions through the gateway
$self->{response} = $self->decryptor_client()->call_decryptor($request);
debug( 'Payment Gateway response: ' . Dumper( deep_replace_card_numbers( $self->{response} ) ) );
Zymonic::Exception::Action->throw(
error => 'No response received from decryptor',
zname => $self->{zname},
catchable => 'false'
) unless ref( $self->{response} ) && keys %{ $self->{response} } > 0;
if ( $self->{response}->{error} )
{
Zymonic::Exception::Action->throw(
error => 'Error from decryptor: ' . $self->{response}->{error},
zname => $self->{zname},
catchable => 'false'
);
}
else
{
$self->{success} = 'true';
}
}
}
#################### subroutine header begin ####################
=head2 decyptor_client
Usage : $form->decryptor_client;
Purpose : TODO
Returns : nothing
Argument : nothing
Throws : TODO
Comment :
See Also :
=cut
#################### subroutine header end ####################
sub decryptor_client
{
my $self = shift;
$self->{decryptor_client} =
Zymonic::Decryptor::Client->new( parent => $self, config => $self->{config}, db => $self->{DB} )
unless ( defined( $self->{decryptor_client} ) );
return $self->{decryptor_client};
}
#################### subroutine header begin ####################
=head2 value
Usage : $action->value($name)
Purpose : Returns a 'value' from an Action.
Returns : a scalar value
Argument : the name of the value to get
Throws :
Comment :
See Also :
=cut
#################### subroutine header end ####################
sub value
{
my $self = shift;
my $name = shift || '';
# get any values from response
return $self->{response}->{$name} if defined $self->{response}->{$name};
return $self->SUPER::value($name);
}
#################### subroutine header begin ####################
=head2 payment_gateway_details
Usage : $self->payment_gateway_details($pg)
Purpose : Returns the settings from DB for the given payment gateway.
Returns : A hashref of settings for the specified payment gateway.
Argument : A payment gateway name.
Throws : Zymonic::Exception::Action
Comment :
See Also :
=cut
#################### subroutine header end ####################
sub payment_gateway_details
{
my $self = shift;
my $pg = shift;
Zymonic::Exception::Action->throw(
zname => $self->{zname},
error => 'Need Payment Gateway to look it up',
catchable => 'true'
) unless $pg;
# check in cache
return $self->{payment_gateway_details}->{$pg} if $self->{payment_gateway_details}->{$pg};
# load payment gateway table
my $payment_gateway_table = Zymonic::Table->new(
parent => $self,
zname => 'pte_payment_gateways',
config => $self->{config},
auth => $self->{auth},
DB => $self->{DB},
filter => { where => 'pg_name = ?', params => [$pg] }
);
$payment_gateway_table->get_all_records();
# map into simple hash and add to cache
$self->{payment_gateway_details}->{$pg} = {
map {
$_->value( $_->raw_value, $_->{fromdb} ) unless defined $_->value;
$_->{field} => $_->value
}
map { $payment_gateway_table->get_object($_) } values( %{ $payment_gateway_table->{records}->[0]->{fields} } )
};
# set payment_gateway_id
$self->{payment_gateway_details}->{$pg}->{payment_gateway_id} = $self->{payment_gateway_details}->{$pg}->{id};
return $self->{payment_gateway_details}->{$pg};
}
#################### subroutine header begin ####################
=head2 transaction_details
Usage : $self->transaction_details($id)
Purpose : Returns the settings from DB for the given transaction id.
Returns : A hashref of settings for the specified transaction.
Argument : A transaction id
Throws : nothing
Comment :
See Also :
=cut
#################### subroutine header end ####################
sub transaction_details
{
my $self = shift;
my $id = shift;
Zymonic::Exception::Action->throw(
zname => $self->{zname},
error => 'Need Transaction ID to lookup transaction',
catchable => 'true'
) unless $id;
# check in cache
return $self->{transaction_details}->{$id} if $self->{transaction_details}->{$id};
# load transactions table
my $transaction_table = Zymonic::Table->new(
parent => $self,
zname => 'pte_tns',
config => $self->{config},
auth => $self->{auth},
DB => $self->{DB},
);
$transaction_table->get_all_records(
{
where_clause => $transaction_table->{tableasname} . '.id = ?',
where_params => [$id]
}
);
# map into simple hash and add to cache
$self->{transaction_details}->{$id} = {
map {
$_->value( $_->raw_value, $_->{fromdb} ) unless defined $_->value;
$_->{field} => $_->value
}
map { $transaction_table->get_object($_) } values( %{ $transaction_table->{records}->[0]->{fields} } )
};
# grab csc from form (not in table)
my $csc_ref = $self->{other_fields}->{CSC_tef};
my $csc_field = $csc_ref->{parent}->get_object($csc_ref) if $csc_ref;
if ($csc_field)
{
$csc_field->value( $csc_field->raw_value, $csc_field->{fromdb} ) unless defined $csc_field->value;
$self->{transaction_details}->{$id}->{csc} = $csc_field->value;
}
# get country from MID
my $mid_table = Zymonic::Table->new(
parent => $self,
zname => 'pte_mids',
config => $self->{config},
auth => $self->{auth},
DB => $self->{DB},
);
$mid_table->get_all_records(
{
where_clause => $mid_table->{tableasname} . '.mid = ?',
where_params => [ $self->{transaction_details}->{$id}->{mid} ]
}
);
my $cnf_ref = $mid_table->{records}->[0]->{fields}->{pte_mids_country};
my $cnf_field = $mid_table->get_object($cnf_ref) if $cnf_ref;
if ($cnf_field)
{
$cnf_field->value( $cnf_field->raw_value, $cnf_field->{fromdb} ) unless defined $cnf_field->value;
$self->{transaction_details}->{$id}->{country} = $cnf_field->value;
}
# if currency not set on transaction get it from MID
unless ( $self->{transaction_details}->{$id}->{currency} )
{
my $crf_ref = $mid_table->{records}->[0]->{fields}->{pte_mids_currency};
my $crf_field = $mid_table->get_object($crf_ref) if $crf_ref;
if ($crf_field)
{
$crf_field->value( $crf_field->raw_value, $crf_field->{fromdb} ) unless defined $crf_field->value;
$self->{transaction_details}->{$id}->{currency} = $crf_field->value;
}
}
# set transaction_id
$self->{transaction_details}->{$id}->{transaction_id} = $id;
return $self->{transaction_details}->{$id};
}
#################### subroutine header begin ####################
=head2 payment_data_details
Usage : $self->payment_data_details($token)
Purpose : Returns the settings from DB for the given payment_data token.
Returns : A hashref of settings for the specified payment_data.
Argument : A payment_data token
Throws : nothing
Comment :
See Also :
=cut
#################### subroutine header end ####################
sub payment_data_details
{
my $self = shift;
my $token = shift;
Zymonic::Exception::Action->throw(
zname => $self->{zname},
error => 'Need token to lookup Payment Data',
catchable => 'true'
) unless $token;
# check in cache
return $self->{payment_data_details}->{$token} if $self->{payment_data_details}->{$token};
# load payment data table
my $payment_data_table = Zymonic::Table->new(
parent => $self,
zname => 'pte_cards',
config => $self->{config},
auth => $self->{auth},
DB => $self->{DB},
filter => { where => 'token = ?', params => [$token] }
);
$payment_data_table->get_all_records();
# map into simple hash and add to cache
$self->{payment_data_details}->{$token} = {
map {
$_->value( $_->raw_value, $_->{fromdb} ) unless defined $_->value;
$_->{field} => $_->value
}
map { $payment_data_table->get_object($_) } values( %{ $payment_data_table->{records}->[0]->{fields} } )
};
# set payment_data_id
$self->{payment_data_details}->{$token}->{payment_data_id} = $self->{payment_data_details}->{$token}->{id};
return $self->{payment_data_details}->{$token};
}
1;