<?php
/* $Id$ */
// {{{ license
/**
 * Implementation of the Authorize.Net AIM payment gateway processor.
 * Copyright 2006-2011, SyberIsle Productions, <http://www.syberisle.net>
 *
 * Licensed under The MIT License
 * Redistributions of files must retain the above copyright notice.
 *
 * @copyright     Copyright 2011, SyberIsle Productions, http://www.syberisle.net>
 * @package       SyberIsle_Wifi_Administration
 * @version       $Revision$
 * @modifiedby    $LastChangedBy$
 * @lastmodified  $Date$
 * @createdOn     20061101
 * @license       MIT License (http://www.opensource.org/licenses/mit-license.php)
 */
// }}}
// {{{ defines

// Error on the socket... 

define('SIP_AUTHORIZE_NET_TRANSACTION_ACCEPTED'0);
define('SIP_AUTHORIZE_NET_TRANSACTION_DECLINED'1);
define('SIP_AUTHORIZE_NET_TRANSACTION_ERROR',    2);

// XXX: We should be using a standard no socket on this
define('SIP_AUTHORIZE_NET_ERROR_NO_SOCKET',    100);

define('SIP_AUTHORIZE_NET_TWO_STEP',           true);
define('SIP_AUTHORIZE_NET_DEBUG',             false);

define('SIP_AUTHROIZE_NET_TYPE_AUTH_CAPTURE',       1);
define('SIP_AUTHROIZE_NET_TYPE_AUTH_ONLY',          2);
define('SIP_AUTHROIZE_NET_TYPE_CAPTURE_ONLY',       3);
define('SIP_AUTHROIZE_NET_TYPE_CREDIT',             4);
define('SIP_AUTHROIZE_NET_TYPE_PRIOR_AUTH_CAPTURE'5);
define('SIP_AUTHROIZE_NET_TYPE_VOID',               6);

// }}}
// {{{ SIP AuthorizeNet Component class
class SipAuthorizeNetComponent extends Object
{
    
// {{{ properties
    
private $country_codes = array(
        
'AF' => 'Afghanistan',
        
'AL' => 'Albania',
        
'DZ' => 'Algeria',
        
'AS' => 'American Samoa',
        
'AD' => 'Andorra',
        
'AO' => 'Angola',
        
'AI' => 'Anguilla',
        
'AQ' => 'Antarctica',
        
'AG' => 'Antigua and Barbuda',
        
'AR' => 'Argentina',
        
'AM' => 'Armenia',
        
'AW' => 'Aruba',
        
'AU' => 'Australia',
        
'AT' => 'Austria',
        
'AZ' => 'Azerbaijan',
        
'BS' => 'Bahamas',
        
'BH' => 'Bahrain',
        
'BD' => 'Bangladesh',
        
'BB' => 'Barbados',
        
'BY' => 'Belarus',
        
'BE' => 'Belgium',
        
'BZ' => 'Belize',
        
'BJ' => 'Benin',
        
'BM' => 'Bermuda',
        
'BT' => 'Bhutan',
        
'BO' => 'Bolivia',
        
'BA' => 'Bosnia and Herzegovina',
        
'BW' => 'Botswana',
        
'BV' => 'Bouvet Island',
        
'BR' => 'Brazil',
        
'IO' => 'British Indian Ocean Territory',
        
'BN' => 'Brunei Darussalam',
        
'BG' => 'Bulgaria',
        
'BF' => 'Burkina Faso',
        
'BI' => 'Burundi',
        
'KH' => 'Cambodia',
        
'CM' => 'Cameroon',
        
'CA' => 'Canada',
        
'CV' => 'Cape Verde',
        
'KY' => 'Cayman Islands',
        
'CF' => 'Central African Republic',
        
'TD' => 'Chad',
        
'CL' => 'Chile',
        
'CN' => 'China',
        
'CX' => 'Christmas Island',
        
'CC' => 'Cocos (Keeling) Islands',
        
'CO' => 'Colombia',
        
'KM' => 'Comoros',
        
'CG' => 'Congo',
        
'CD' => 'Congo, the Democratic Republic of the',
        
'CK' => 'Cook Islands',
        
'CR' => 'Costa Rica',
        
'CI' => 'Cote D\'Ivoire',
        
'HR' => 'Croatia',
        
'CU' => 'Cuba',
        
'CY' => 'Cyprus',
        
'CZ' => 'Czech Republic',
        
'DK' => 'Denmark',
        
'DJ' => 'Djibouti',
        
'DM' => 'Dominica',
        
'DO' => 'Dominican Republic',
        
'EC' => 'Ecuador',
        
'EG' => 'Egypt',
        
'SV' => 'El Salvador',
        
'GQ' => 'Equatorial Guinea',
        
'ER' => 'Eritrea',
        
'EE' => 'Estonia',
        
'ET' => 'Ethiopia',
        
'FK' => 'Falkland Islands (Malvinas)',
        
'FO' => 'Faroe Islands',
        
'FJ' => 'Fiji',
        
'FI' => 'Finland',
        
'FR' => 'France',
        
'GF' => 'French Guiana',
        
'PF' => 'French Polynesia',
        
'TF' => 'French Southern Territories',
        
'GA' => 'Gabon',
        
'GM' => 'Gambia',
        
'GE' => 'Georgia',
        
'DE' => 'Germany',
        
'GH' => 'Ghana',
        
'GI' => 'Gibraltar',
        
'GR' => 'Greece',
        
'GL' => 'Greenland',
        
'GD' => 'Grenada',
        
'GP' => 'Guadeloupe',
        
'GU' => 'Guam',
        
'GT' => 'Guatemala',
        
'GN' => 'Guinea',
        
'GW' => 'Guinea-Bissau',
        
'GY' => 'Guyana',
        
'HT' => 'Haiti',
        
'HM' => 'Heard Island and Mcdonald Islands',
        
'VA' => 'Holy See (Vatican City State)',
        
'HN' => 'Honduras',
        
'HK' => 'Hong Kong',
        
'HU' => 'Hungary',
        
'IS' => 'Iceland',
        
'IN' => 'India',
        
'ID' => 'Indonesia',
        
'IR' => 'Iran, Islamic Republic of',
        
'IQ' => 'Iraq',
        
'IE' => 'Ireland',
        
'IL' => 'Israel',
        
'IT' => 'Italy',
        
'JM' => 'Jamaica',
        
'JP' => 'Japan',
        
'JO' => 'Jordan',
        
'KZ' => 'Kazakhstan',
        
'KE' => 'Kenya',
        
'KI' => 'Kiribati',
        
'KP' => 'Korea, Democratic People\'s Republic of',
        
'KR' => 'Korea, Republic of',
        
'KW' => 'Kuwait',
        
'KG' => 'Kyrgyzstan',
        
'LA' => 'Lao People\'s Democratic Republic',
        
'LV' => 'Latvia',
        
'LB' => 'Lebanon',
        
'LS' => 'Lesotho',
        
'LR' => 'Liberia',
        
'LY' => 'Libyan Arab Jamahiriya',
        
'LI' => 'Liechtenstein',
        
'LT' => 'Lithuania',
        
'LU' => 'Luxembourg',
        
'MO' => 'Macao',
        
'MK' => 'Macedonia, the Former Yugoslav Republic of',
        
'MG' => 'Madagascar',
        
'MW' => 'Malawi',
        
'MY' => 'Malaysia',
        
'MV' => 'Maldives',
        
'ML' => 'Mali',
        
'MT' => 'Malta',
        
'MH' => 'Marshall Islands',
        
'MQ' => 'Martinique',
        
'MR' => 'Mauritania',
        
'MU' => 'Mauritius',
        
'YT' => 'Mayotte',
        
'MX' => 'Mexico',
        
'FM' => 'Micronesia, Federated States of',
        
'MD' => 'Moldova, Republic of',
        
'MC' => 'Monaco',
        
'MN' => 'Mongolia',
        
'MS' => 'Montserrat',
        
'MA' => 'Morocco',
        
'MZ' => 'Mozambique',
        
'MM' => 'Myanmar',
        
'NA' => 'Namibia',
        
'NR' => 'Nauru',
        
'NP' => 'Nepal',
        
'NL' => 'Netherlands',
        
'AN' => 'Netherlands Antilles',
        
'NC' => 'New Caledonia',
        
'NZ' => 'New Zealand',
        
'NI' => 'Nicaragua',
        
'NE' => 'Niger',
        
'NG' => 'Nigeria',
        
'NU' => 'Niue',
        
'NF' => 'Norfolk Island',
        
'MP' => 'Northern Mariana Islands',
        
'NO' => 'Norway',
        
'OM' => 'Oman',
        
'PK' => 'Pakistan',
        
'PW' => 'Palau',
        
'PS' => 'Palestinian Territory, Occupied',
        
'PA' => 'Panama',
        
'PG' => 'Papua New Guinea',
        
'PY' => 'Paraguay',
        
'PE' => 'Peru',
        
'PH' => 'Philippines',
        
'PN' => 'Pitcairn',
        
'PL' => 'Poland',
        
'PT' => 'Portugal',
        
'PR' => 'Puerto Rico',
        
'QA' => 'Qatar',
        
'RE' => 'Reunion',
        
'RO' => 'Romania',
        
'RU' => 'Russian Federation',
        
'RW' => 'Rwanda',
        
'SH' => 'Saint Helena',
        
'KN' => 'Saint Kitts and Nevis',
        
'LC' => 'Saint Lucia',
        
'PM' => 'Saint Pierre and Miquelon',
        
'VC' => 'Saint Vincent and the Grenadines',
        
'WS' => 'Samoa',
        
'SM' => 'San Marino',
        
'ST' => 'Sao Tome and Principe',
        
'SA' => 'Saudi Arabia',
        
'SN' => 'Senegal',
        
'CS' => 'Serbia and Montenegro',
        
'SC' => 'Seychelles',
        
'SL' => 'Sierra Leone',
        
'SG' => 'Singapore',
        
'SK' => 'Slovakia',
        
'SI' => 'Slovenia',
        
'SB' => 'Solomon Islands',
        
'SO' => 'Somalia',
        
'ZA' => 'South Africa',
        
'GS' => 'South Georgia and the South Sandwich Islands',
        
'ES' => 'Spain',
        
'LK' => 'Sri Lanka',
        
'SD' => 'Sudan',
        
'SR' => 'Suriname',
        
'SJ' => 'Svalbard and Jan Mayen',
        
'SZ' => 'Swaziland',
        
'SE' => 'Sweden',
        
'CH' => 'Switzerland',
        
'SY' => 'Syrian Arab Republic',
        
'TW' => 'Taiwan, Province of China',
        
'TJ' => 'Tajikistan',
        
'TZ' => 'Tanzania, United Republic of',
        
'TH' => 'Thailand',
        
'TL' => 'Timor-Leste',
        
'TG' => 'Togo',
        
'TK' => 'Tokelau',
        
'TO' => 'Tonga',
        
'TT' => 'Trinidad and Tobago',
        
'TN' => 'Tunisia',
        
'TR' => 'Turkey',
        
'TM' => 'Turkmenistan',
        
'TC' => 'Turks and Caicos Islands',
        
'TV' => 'Tuvalu',
        
'UG' => 'Uganda',
        
'UA' => 'Ukraine',
        
'AE' => 'United Arab Emirates',
        
'GB' => 'United Kingdom',
        
'US' => 'United States',
        
'UM' => 'United States Minor Outlying Islands',
        
'UY' => 'Uruguay',
        
'UZ' => 'Uzbekistan',
        
'VU' => 'Vanuatu',
        
'VE' => 'Venezuela',
        
'VN' => 'Viet Nam',
        
'VG' => 'Virgin Islands, British',
        
'VI' => 'Virgin Islands, U.s.',
        
'WF' => 'Wallis and Futuna',
        
'EH' => 'Western Sahara',
        
'YE' => 'Yemen',
        
'ZM' => 'Zambia',
        
'ZW' => 'Zimbabwe',
    );
    
    
/**
     * A list of the API fields that authorize.net uses.
     * NOTE: AIM implementation (http://developer.authorize.net/guides/AIM/)
     * FORMAT:
     *   'field' => array(
     *       'api_name' => 'x_field',
     *       'validation' => <SEE Cake's Core Validation rules)
     *       ),
     *   ),
     *
     */
    
private $api_fields = array(
        
// Merchant information
        
'login' => array(
            
'api_field'  => 'x_login',
            
'required'   => true,
            
'validation' => array(
                array(
'rule' => 'alphaNumeric'),
                array(
'rule' => array('between'020)),
            ),
        ),
        
'login_id' => 'login',
        
        
'tran_key' => array(
            
'api_field'  => 'x_tran_key',
            
'required'   => true,
            
'validation' => array(
                array(
'rule' => 'alphaNumeric'),
                array(
'rule' => array('between'1616)),
            ),
        ),
        
'transaction_key' => 'tran_key',
        
'allow_partial_auth' => array(
            
'validation' => array('boolean')
        ),

        
// Transaction Information
        
'version' => array(
            
'required' => true,
            
'validation' => array('values', array('3.1''3.0')),
        ),
        
'type' => array(
            
'validation' => array(
                
'values',
                array(
SIP_AUTHROIZE_NET_TYPE_AUTH_CAPTURE,
                      
SIP_AUTHROIZE_NET_TYPE_AUTH_ONLY,
                      
SIP_AUTHROIZE_NET_TYPE_CAPTURE_ONLY,
                      
SIP_AUTHROIZE_NET_TYPE_CREDIT,
                      
SIP_AUTHROIZE_NET_TYPE_PRIOR_AUTH_CAPTURE,
                      
SIP_AUTHROIZE_NET_TYPE_VOID))
        ),
        
'method' => array(
            
'validation' => array('values', array('CC''ECHECK')),
        ),
        
'recurring_billing' => array(
            
'validation' => 'validateBoolean',
        ),
        
'amount' => array(
            
'required' => true,
            
'validation' => array('float''15'),
        ),
        
'card_num' => array(
            
'required' => true,
            
'validation' => 'validateCreditCard',
        ),
        
'card_number' => 'card_num',
        
'exp_date' => array(
            
'required' => true,
            
'validation' => 'validateCreditCardExpiration'
        
),
        
'card_expiration' => 'exp_date',
        
'card_expiration_date' => 'exp_date',
        
'card_code' => array(
            
'validation' => 'numeric',
        ),
        
'cvv' => 'card_code',
        
'trans_id' => array(
            
// CONDITIONAL
            // Used for CREDIT, PRIOR_AUTH_CAPTURE, or VOID transactions
        
),
        
'transaction_id' => 'trans_id',
        
'split_tender_id' => array(
            
// conditional for split tender orders
            // XXX: we currently don't deal with these.
        
),
        
'auth_code' => array(
            
// CONDITIONAL: required for CAPTURE_ONLY
            
'validate' => array(
                array(
'rule' => 'alphaNumeric'),
                array(
'rule' => array('between'66)),
            ),
        ),
        
'test_request' => array(
            
'validate' => 'validateBoolean',
        ),
        
'duplicate_window' => array(
            
'validate' => array('range'028800)
        ),
        
'merchant_descriptor' => array(
            
'validate' => array('between'0255)
        ),

        
// Order Information
        
'invoice_num' => array(
            
'validate' => array('validateBetween'020)
        ),
        
'invoice_number' => 'invoice_num',
        
'description' => array(
            
'validate' => array('validateBetween'0255)
        ),
        
'line_item' => array(
            
'api_field' => 'x_line_item',
            
'required'  => false,
            
'multiples' => 30,
            
'validation' => 'validateLineItem',
        ),

        
// Customer information
        
'first_name' => array(),
        
'last_name' => array(),
        
'company' => array(),
        
'address' => array(),
        
'city' => array(),
        
'state' => array(),
        
'zip' => array(),
        
'country' => array(),
        
'phone' => array(),
        
'fax' => array(),
        
'email' => array(),
        
'cust_id' => array(),
        
'customer_ip' => array(),

        
// Shipping information
        
'ship_to_first_name' => array(),
        
'ship_to_last_name' => array(),
        
'ship_to_company' => array(),
        
'ship_to_address' => array(),
        
'ship_to_city' => array(),
        
'ship_to_state' => array(),
        
'ship_to_zip' => array(),
        
'ship_to_country' => array(),

        
// Additional Shipping Information (Level 2 data)
        
'tax' => array(),
        
'freight' => array(),
        
'duty' => array(),
        
'tax_exempt' => array(),
        
'po_num' => array(),

        
// Cardholder authentication
        
'authentication_indicator' => array(),
        
'cardhold_authentication_value' => array(),

        
// Merchant Defined fields
        
'a' => array(),
    );
    private 
$raw_data;

    
/**
     * Whether or not merchant defined fields cause an error
     * @var boolean
     */
    
private $allow_merchant_fields false;


    
/**
     * Authorize.Net secure url for transactions.
     *
     * @var string
     */
    
private $post_url;
    
    
/**
     * Information about the transaction to send to Authorize.Net.
     *
     * @var array
     */
    
private $transaction_data;

    
/**
     * Information returned by Authorize.Net on the transaction.
     *
     * @var array
     */
    
private $response_data;

    
// {{{ functions: private
    /**
     * Checks with the Authorize.net service about whether or not the
     * credit card is valid. Returns an array of the data from the server.
     *
     * @param   string $in_body The body of the message to send to the server as
     *                          a POST request.
     * @returns array  Response from the server
     */
    
private function _authorize($in_body)
    {
        
// determine the host and uri
        
$s_url    preg_replace('#^https?://#i'''$this->post_url);
        
$s_host   substr($s_url0strpos($s_url"/"));
        
$s_uri    strstr($s_url"/");
        
$s_length strlen($in_body);

        
// make sure that we have an ip address
        
if (preg_match('#([0-9]{1,3}\.){3}[0-9]{1,3}#'$s_host)) {
            
$s_host gethostbyname($s_host);
        }
        
// There is no such thing as insecure credit card authorization
        
$o_socket fsockopen('ssl://'.$s_host443);
        if ( ! 
$o_socket) {
            return 
SIP_AUTHORIZE_NET_ERROR_NO_SOCKET;
        }

        
// send the request
        
fwrite($o_socket"POST $s_uri HTTP/1.1\r\nHost: $s_host\r\n");
        
/* XXX: can't use this until we get a test account from authorize.net
         */
        
fwrite($o_socket"User-Agent: SyberIsleProductions AuthorizeNet\r\n");
        
fwrite($o_socket"Content-Type: application/x-www-form-urlencoded\r\n");
        
fwrite($o_socket"Content-Length: $s_length\r\n\r\n");
        
fwrite($o_socket"$in_body\r\n");

        
$s_head '';
        
/* pass by the headers */
        
do {
            
$s_tmp = @fgets($o_socket);
            
$s_head .= $s_tmp;
        } while ( ! 
preg_match("/^\r?\n$/sim"$s_tmp));

        if (
SIP_AUTHORIZE_NET_DEBUG) {
            
openlog('WiFi'LOG_PID|LOG_PERRORLOG_AUTH);
            
syslog(LOG_WARNING"$s_head");
            
closelog();
        }

        
/* retrieve the response and then close the connection */
        
$a_data = array();
        while( ! 
feof($o_socket)) {
            
$a_data[] = @fgets($o_socket);
        }
        
fclose($o_socket);

        if (
SIP_AUTHORIZE_NET_DEBUG) {
            
$s_tmp join('|'$a_data);
            
openlog('WiFi-data'LOG_PID|LOG_PERRORLOG_AUTH);
            
syslog(LOG_WARNING$s_tmp);
            
closelog();
        }

        return 
$a_data;
    }

    
/**
     * Parses the results that the Authorize.Net server sent back. Returns a
     * hash of the parsed values.
     *
     * @param   array $in_data the data returned from the server.
     * @returns array The parsed values in an array hash
     */
    
private function _parse_results($in_data)
    {
        if ( ! 
is_array($in_data)) {
            return 
false;
        }

        
$this->raw_data $in_data;

        
$s_response implode(''$in_data);
        
$s_response trim($s_response);

        if (
SIP_AUTHORIZE_NET_DEBUG) {
            
openlog('WiFi'LOG_PID|LOG_PERRORLOG_AUTH);
            
syslog(LOG_WARNING"$s_response");
        }

        
// set the response data for this transaction
        
$a_results explode('|'$s_response);
        
$this->response_data = array(
            
'code'        => $a_results[0],
            
'subcode'     => $a_results[1],
            
'reason_code' => $a_results[2],
            
'reason_text' => $a_results[3],
            
'approval'    => $a_results[4],
            
'avs'         => $a_results[5],
            
'transaction' => $a_results[6],
            
'md5'         => $a_results[37],
            
'card_code'   => $a_results[38],
            
'cavv_code'   => $a_results[39],
        );

        if (
SIP_AUTHORIZE_NET_DEBUG) {
            
syslog(LOG_WARNING"Code: " $results[0]);
            
closelog();
        }

        return 
true;        
    }

    
/**
     * Handles the actual processing of the transcation. Returns the
     * result set from _parse_results.
     *
     * @param   array $in_data The POST data in an array.
     * @returns array An array of the parsed results.
     */
    
private function _process($in_data)
    {
        
$s_body '';
        
// transmute the data array into a POST request
        
foreach($in_data as $s_key => $s_value) {
            
$s_body .= ((== strlen($s_body)) ? '' '&') .
                       
$s_key '=' urlencode($s_value);
        }

        
// try to authorize the information
        
$a_serverResults $this->_authorize($s_body);
        if (
$a_serverResults === SIP_AUTHORIZE_NET_ERROR_NO_SOCKET) {
            return 
$a_serverResults;
        }

        
// pass off to the results determination function
        
return $this->_parse_results($a_serverResults);
    }

    
// }}}
    // {{{ functions: public

    /**
     *  Object constructor.
     *
     * @param   string $in_id  The authorize.net ID.
     * @param   string $in_key The authorize.net key.
     * @param   string $in_url The authorize.net url.
     * @returns object
     */
    
function __construct()
    {    
        
$this->transaction_data['x_version']        = '3.1';
        
$this->transaction_data['x_delim_data']     = 'TRUE';
        
$this->transaction_data['x_relay_responze'] = 'FALSE';
        
$this->transaction_data['x_url']            = 'FALSE';
        
$this->transaction_data['x_delim_char']     = '|';
    }

    
/**
     * Object destructor.
     *
     * @returns void
     */
    
function __destruct()
    {
         
$this->post_url  null;
    }

    
/**
     * Asks Authorize.net if the data is valid, and returns success or failure.
     *
     * @param   array   $in_data      An array of the data to send to authorize.net
     * @param   boolean $in_doCapture whether or not to capture the data
     * @returns void
     */
    
function charge($in_doCapture false)
    {
        
/* REQUIRED BY AUTHORIZE.NET
         *  x_type maybe one of the following:
         *   AUTH_CAPTURE
         *   AUTH_ONLY
         *   CAPTURE_ONLY
         *   CREDIT
         *   VOID
         *   PRIOR_AUTH_CAPTURE)
         */
        
$a_data $this->transaction_data;

        
// our custom data
        
$a_data['x_delim_char'] = '|';
        
$a_data['x_type'] = ($in_doCapture == SIP_AUTHORIZE_NET_TWO_STEP) ?
                             
'AUTH_ONLY' 'AUTH_CAPTURE';

        
// charge it
        
if ( ! $this->_process($a_data)) {
            
trigger_error('SIP_AUTHORIZE_NET: Unable to process response'E_USER_WARNING);
            return 
SIP_AUTHORIZE_NET_TRANSACTION_ERROR;
        }

        
// did it work
        
if (== $this->response_data['code']) {
            return 
SIP_AUTHORIZE_NET_TRANSACTION_DECLINED;
        }
        elseif (
== $this->response_data['code']) {
            return 
SIP_AUTHORIZE_NET_TRANSACTION_ERROR;
        }

        return 
SIP_AUTHORIZE_NET_TRANSACTION_ACCEPTED;
    }

    
/**
     * Retrieves the response data
     */
    
function getResponseData()
    {
        return 
$this->response_data;
    }

    
// }}}
    // {{{ functions: set AuthorizeNet variables
    
function addItem($in_name$in_id$in_description$in_quantity$in_price$in_isTaxable)
    {
        if (
count($this->line_items) == 30) {
            
$this->error 'No More items can be added to the transaction.';
            return 
false;
        }

        
// XXX: validate the line item data

        
$this->items[] = array(
            
$in_id$in_name$in_description$in_quantity$in_price$in_isTaxable
        
);
        return;
    }

    
/**
     * Generic magic function call to set/get Authorize net parameters
     */
    
function __call($in_method$in_params)
    {
        
/* translate CamelCase into underscore */
        
$s_name strtolower(preg_replace('#([A-Z])#''_\1'$in_method));
        if (
'get_' == substr($s_name04)) {
            
$s_name str_replace('get_'''$s_name);
            if (isset(
$this->$s_name)) {
                return 
$this->$s_name;
            }
        }
        elseif (
'set_' == substr($s_name04)) {
            
$s_name str_replace('set_'''$s_name);
            
$this->$s_name $in_params[0];
        }

        return 
null;
    }

    function 
geCountryCodes()
    {
        return 
$this->country_codes;
    }

    function 
__set($in_name$in_value)
    {
        
$in_name strtolower(preg_replace('#([A-Z])#''_\1'$in_name));
        if (isset(
$this->api_fields[$in_name])) {
            if ( ! 
is_array($this->api_fields[$in_name])) {
                
$in_name $this->api_fields[$in_name];
            }

            if (
$in_name == 'line_item') {
                
trigger_error('Please use addItem for adding items to the transaction.'E_USER_ERROR);
                return;
            }

            
$s_fieldName "x_{$in_name}";
            if ( ! empty(
$this->api_fields[$in_name]['api_field'])) {
                
$s_fieldName $this->api_fields[$in_name]['api_field'];
            }

            
$this->transaction_data[$s_fieldName] = $in_value;
        }
    }
    
    
// }}}
}