# ================================================================== # Gossamer Links - enhanced directory management system # # Website : http://gossamer-threads.com/ # Support : http://gossamer-threads.com/scripts/support/ # CVS Info : 087,071,086,086,085 # Revision : $Id: Moneris.pm,v 1.2 2005/03/05 01:29:09 brewt Exp $ # # Copyright (c) 2003 Gossamer Threads Inc. All Rights Reserved. # Redistribution in part or in whole strictly prohibited. Please # see LICENSE file for full details. # ================================================================== # # Glue between Gossamer Links and Moneris payment interface package Links::Payment::Direct::Moneris; use strict; # Make sure the payment module is available use GT::Payment::Direct::Moneris 1.007; # CVS Versions < 1.7 were for the old, defunct Moneris payment system use Links qw/$IN $CFG $DB/; use vars qw/%INVALID %EMPTY/; my @FIELDS = ( keys %GT::Payment::Direct::Moneris::NAME_MAP, qw/ credit_card_number credit_card_expiry_month credit_card_expiry_year billing_country billing_email charge_total/ ); sub required { # ----------------------------------------------------------------------------- # Returns a list of required field names. Each field name will be looked for # in the language file, prefixed with 'PAYMENT_DIRECT_Moneris_', for the title # of the field, and 'PAYMENT_DIRECT_DESC_Moneris_' for a description of the # field's contents. # Note that these are just required SETUP fields, so things like credit card # number, billing name, etc. are NOT included. return account_token => { type => 'TEXT', valid => '^\w+$' }, account_token2 => { type => 'TEXT', valid => '^\w+$' }; } sub optional { return test_mode => { type => 'YESNO' } } sub payment_info { # ----------------------------------------------------------------------------- # Returns a hash of various parameters used to figure out how to display the # payment form for this payment method. return { fields => [ grep ! /^(?:account|capture|currency|test)/, @FIELDS ], no_cc_brand => 1 }; } sub verify { # ----------------------------------------------------------------------------- # Checks that $IN, combined with the saved admin settings, makes up all of the # required information. Returns 1 on success, or an array ref of invalid and # empty keys array references (i.e. [\@invalid, \@empty]) on failure. _collect_data(); if (keys %INVALID or keys %EMPTY) { my ($i, %order); for (@{$GT::Payment::Direct::Moneris::REQUIRED{AUTHORIZE}}) { $order{$_} = $i++ } return [ # Error [sort { ($order{$a} || 0x7fff_ffff) <=> ($order{$b} || 0x7fff_ffff) } keys %INVALID], [sort { ($order{$a} || 0x7fff_ffff) <=> ($order{$b} || 0x7fff_ffff) } keys %EMPTY] ]; } else { return 1; # Success } } sub complete { # ----------------------------------------------------------------------------- # Checks that $IN, combined with the saved admin settings, makes up all of the # required information. Returns (1, $message) on success, (0, $reason) on # declined, or (-1, $errormsg) on error. my $pay = _collect_data() or return; # Set the admin-specified fields while (my ($k, $v) = each %{$CFG->{payment}->{direct}->{used}->{Moneris}}) { $pay->$k($v) or return (-1, "Payment configuration error (Invalid $k)"); } $pay->check('sale') or return (-1, $pay->error); my $ret = $pay->sale; if (not defined $ret) { # An error occured in the module return (-1, $pay->error); } else { # The request at least got through to Moneris if ($ret == 1) { # Approved! my $resp_text; my @receipt = $pay->receipt(); my $receipt = "Transaction approved\n\n"; while (@receipt) { my ($k, $v) = splice @receipt, 0, 2; $receipt .= "$k: $v\n"; $resp_text = $v if $k eq 'Status'; } return (1, $resp_text, $receipt); } elsif ($ret == 0) { # Declined return (0, $pay->error); } else { # An error was generated by Moneris return (-1, $pay->error); } } } sub _collect_data { # ----------------------------------------------------------------------------- # Collect data from the payment data saved in the admin, and any valid columns # in $IN. Anything from $IN is checked for validity, and $INVALID{column} is # set if invalid. %INVALID = %EMPTY = (); return unless $CFG->{payment}->{direct}->{used}->{Moneris}; my %data = %{$CFG->{payment}->{direct}->{used}->{Moneris}}; return unless keys %data; my $pay = GT::Payment::Direct::Moneris->new(debug_level => $CFG->{debug}); my %required = map { $_ => 1 } @{$GT::Payment::Direct::Moneris::REQUIRED{AUTHORIZE}}; for my $field (@FIELDS) { # The account_*, capture_*, currency_*, etc. fields should not be user-settable. next if exists $data{$field} or $field =~ /^(?:account|capture|currency|test)/; if (my $value = $IN->param($field)) { if ($pay->$field($value)) { $data{$field} = $value; } else { $INVALID{$field}++; $data{$field} = undef; } } elsif ($required{$field}) { $EMPTY{$field}++; $data{$field} = undef; } } return if keys %INVALID or keys %EMPTY; return $pay; } 1;