# ==================================================================
# 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: WorldPay.pm,v 1.13 2006/08/22 23:05:13 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 Links and WorldPay payment interface

package Links::Payment::Remote::WorldPay;
use strict;

# Make sure the payment module is available
use GT::Payment::Remote::WorldPay;
use Links qw/:objects/;
use Links::Payment qw/:status :log/;
use Links::SiteHTML;
use vars qw/%INVALID %EMPTY/;

sub required {
# -----------------------------------------------------------------------------
# Returns a list of required field names.  Each field name will be looked for
# in the language file, prefixed with 'PAYMENT_REMOTE_WorldPay_', for the title
# of the field, and 'PAYMENT_REMOTE_DESC_WorldPay_' 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.
    my @currencies;
    for (qw/USD CAD EUR GBP AFA ALL DZD AON ARS AWG AUD BSD BHD BDT BBD BZD BMD BOB BAD BWP BRL BND BGL XOF BIF KHR
        XAF CVE KYD CLP CNY COP KMF CRC HRK CUP CYP CZK DKK DJF XCD DOP TPE ECS EGP SVC EEK ETB FKP FJD XPF GMD GHC
        GIP GTQ GNF GWP GYD HTG HNL HKD HUF ISK INR IDR IRR IQD ILS JMD JPY JOD KZT KES KRW KPW KWD KGS LAK LVL LBP
        LSL LRD LYD LTL MOP MKD MGF MWK MYR MVR MTL MRO MUR MXN MNT MAD MZM MMK NAD NPR ANG NZD NIO NGN NOK OMR PKR
        PAB PGK PYG PEN PHP PLN QAR ROL RUR RWF WST STD SAR SCR SLL SGD SKK SIT SBD SOS ZAR LKR SHP SDP SRG SZL SEK
        CHF SYP TWD TJR TZS THB TOP TTD TND TRL UGX UAH AED UYU VUV VEB VND YER YUM ZRN ZMK ZWD/) {
        push @currencies, $_ => Links::language('PAYMENT_CURRENCY_' . $_);
    }

    return
        installation_id => { type => 'TEXT', valid => '^\d{1,16}$' },
        callback_password => { type => 'TEXT' },
        md5_password => { type => 'TEXT' },
        currency => {
            type => 'SELECT',
            options => \@currencies
        }
}

sub optional {
# -----------------------------------------------------------------------------
    return
        test_mode => { type => 'SELECT', options => [100 => 'Test mode: Always approved', 101 => 'Test mode: Always declined'] }
}

sub payment_info {
# -----------------------------------------------------------------------------
# Returns a hashref of payment hints
#
    my @fields = qw/currency installation_id md5_password test_mode/;
    my $ret = {
        fields => \@fields
    };
    if (my $pp = $CFG->{payment}->{remote}->{used}->{WorldPay}) {
        for (@fields) {
            $ret->{$_ eq 'image_url' ? 'pp_image_url' : $_} = $pp->{$_};
        }
    }
    return $ret;
}

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 keys
# on failure.  For Remote payment methods, this has no real effect.
    return 1;
}

sub postback {
# -----------------------------------------------------------------------------

    my $pay = $DB->table('Payments');
    my $log = $DB->table('PaymentLogs');

    my $unique = $IN->param('cartId');
    my $payment = $pay->select({ payments_id => $unique })->fetchrow_hashref
        or return; # Whatever it is, we didn't create it.

    my $end = 1; # Returned after processing - if true, a blank page will be displayed,
                 # if false, a worldpay receipt page.

    GT::Payment::Remote::WorldPay::process(
        param => $IN,
        password => $CFG->{payment}->{remote}->{used}->{WorldPay}->{callback_password},
        test_mode => $CFG->{payment}->{remote}->{used}->{WorldPay}->{test_mode},
        on_valid => sub {
            # A one-time payment (or the initial payment, in the case of recurring payments)
            return unless $IN->param('amount') >= $payment->{payments_amount};

            return if $payment->{payments_status} == COMPLETED;

            $pay->update(
                { payments_status => COMPLETED, payments_last => time },
                { payments_id => $payment->{payments_id} }
            );

            $log->insert({
                paylogs_payments_id => $payment->{payments_id},
                paylogs_type => LOG_ACCEPTED,
                paylogs_time => time,
                paylogs_text => (
                    sprintf(Links::language('PAYMENT_REMOTE_APPROVED') => 'WorldPay') . "\n" .
                    "Transaction ID: " . $IN->param('transId') . "\n" .
                    "Amount: " . $IN->param('amountString') . " (" . $IN->param('authAmountString') . ")\n" .
                    ($IN->param('futurePayId') ? "FuturePay ID: " . $IN->param('futurePayId') . "\n" : '') .
                    "Authorization Message: " . $IN->param('rawAuthMessage') . "\n"
                )
            });

            Links::Payment::process_payment($payment->{payments_linkid}, $payment->{payments_term});

            $end = 0;
        },
        on_cancel => sub {
            # The user clicked "cancel payment"
            $pay->update(
                { payments_status => DECLINED, payments_last => time },
                { payments_id => $payment->{payments_id} }
            );

            $log->insert({
                paylogs_payments_id => $payment->{payments_id},
                paylogs_type => LOG_DECLINED,
                paylogs_time => time,
                paylogs_text => (
                    sprintf(Links::language('PAYMENT_REMOTE_CANCELLED') => 'WorldPay') . "\n" .
                    "Amount: " . $IN->param('amountString') . " (" . $IN->param('authAmountString') . ")\n"
                )
            });
        },
        on_invalid_password => sub {
            $pay->update(
                { payments_status => ERROR, payments_last => time },
                { payments_id => $payment->{payments_id} }
            );

            $log->insert({
                paylogs_payments_id => $payment->{payments_id},
                paylogs_type => LOG_ERROR,
                paylogs_time => time,
                paylogs_text => sprintf(Links::language('PAYMENT_REMOTE_INVALIDPW') => 'WorldPay') . "\n"
            });
        },
        on_recurring => sub {
            # A recurring payment, NOT counting the original payment
            $pay->update(
                { payments_status => COMPLETED, payments_last => time },
                { payments_id => $payment->{payments_id} }
            );

            $log->insert({
                paylogs_payments_id => $payment->{payments_id},
                paylogs_type => LOG_ACCEPTED,
                paylogs_time => time,
                paylogs_text => (
                    sprintf(Links::language('PAYMENT_REMOTE_RECURRING_ACCEPTED') => 'WorldPay') . "\n" .
                    "Transaction ID: " . $IN->param('transId') . "\n" .
                    "Amount: " . $IN->param('amountString') . " (" . $IN->param('authAmountString') . ")\n" .
                    "FuturePay ID: " . $IN->param('futurePayId') . "\n" .
                    "Authorization Message: " . $IN->param('rawAuthMessage') . "\n"
                )
            });

            # The "1" gives them an extra day for recurring payments.
            Links::Payment::process_payment($payment->{payments_linkid}, $payment->{payments_term}, 1);
        },
        on_recurring_failed => sub {
            $pay->update(
                { payments_status => DECLINED, payments_last => time },
                { payments_id => $payment->{payments_id} }
            );

            $log->insert({
                paylogs_payments_id => $payment->{payments_id},
                paylogs_type => LOG_DECLINED,
                paylogs_time => time,
                paylogs_text => (
                    sprintf(Links::language('PAYMENT_REMOTE_RECURRING_DECLINED') => 'WorldPay') . "\n" .
                    "Amount: " . $IN->param('amountString') . " (" . $IN->param('authAmountString') . ")\n"
                )
            });
        }
    );

    print $IN->header;
    unless ($end) {
        print Links::SiteHTML::display('payment_success');
    }
    1;
}

1;
