Version 4.0.13.1
This commit is contained in:
1 parent
f9e857d255
commit
c6a86f0d9b
7517 files changed
+597400
-668041
No files matched your search
@@ -0,0 +1,462 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Authorize.Net Gateway
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @subpackage Nexus
|
||||
* @since 17 Mar 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\nexus\Gateway;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorize.Net Gateway
|
||||
*/
|
||||
class _AuthorizeNet extends \IPS\nexus\Gateway
|
||||
{
|
||||
/* !Features */
|
||||
|
||||
const SUPPORTS_REFUNDS = TRUE;
|
||||
const SUPPORTS_PARTIAL_REFUNDS = TRUE;
|
||||
|
||||
/**
|
||||
* Check the gateway can process this...
|
||||
*
|
||||
* @param $amount \IPS\nexus\Money The amount
|
||||
* @param $billingAddress \IPS\GeoLocation The billing address
|
||||
* @return bool
|
||||
*/
|
||||
public function checkValidity( \IPS\nexus\Money $amount, \IPS\GeoLocation $billingAddress )
|
||||
{
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
if ( !$settings['processor'] )
|
||||
{
|
||||
return parent::checkValidity( $amount, $billingAddress );
|
||||
}
|
||||
|
||||
$currencies = array();
|
||||
|
||||
if ( in_array( $settings['processor'], array( 1, 2, 4, 5, 6, 7, 8, 13, 14 ) ) )
|
||||
{
|
||||
$currencies[] = 'USD';
|
||||
}
|
||||
|
||||
if ( in_array( $settings['processor'], array( 1, 2, 4 ) ) )
|
||||
{
|
||||
$currencies[] = 'CAD';
|
||||
}
|
||||
|
||||
if ( in_array( $settings['processor'], array( 8, 9, 10, 11, 12, 13 ) ) )
|
||||
{
|
||||
$currencies[] = 'GBP';
|
||||
}
|
||||
|
||||
if ( in_array( $settings['processor'], array( 8, 9, 11, 13 ) ) )
|
||||
{
|
||||
$currencies[] = 'EUR';
|
||||
}
|
||||
|
||||
if ( in_array( $settings['processor'], array( 14, 15 ) ) )
|
||||
{
|
||||
$currencies[] = 'AUD';
|
||||
}
|
||||
|
||||
if ( in_array( $settings['processor'], array( 14 ) ) )
|
||||
{
|
||||
$currencies[] = 'NZD';
|
||||
}
|
||||
|
||||
if ( !in_array( $amount->currency, $currencies ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return parent::checkValidity( $amount, $billingAddress );
|
||||
}
|
||||
|
||||
/**
|
||||
* Can store cards?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canStoreCards()
|
||||
{
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
return ( $settings['method'] === 'AIM' and $settings['cim'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin can manually charge using this gateway?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canAdminCharge()
|
||||
{
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
return ( $settings['method'] === 'AIM' );
|
||||
}
|
||||
|
||||
/* !Payment Gateway */
|
||||
|
||||
/**
|
||||
* Payment Screen Fields
|
||||
*
|
||||
* @param \IPS\nexus\Invoice $invoice Invoice
|
||||
* @param \IPS\nexus\Money $amount The amount to pay now
|
||||
* @return array
|
||||
*/
|
||||
public function paymentScreen( \IPS\nexus\Invoice $invoice, \IPS\nexus\Money $amount )
|
||||
{
|
||||
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'global_gateways.js', 'nexus', 'global' ) );
|
||||
|
||||
$return = array();
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
|
||||
/* Accepted types */
|
||||
if( $settings['processor'] )
|
||||
{
|
||||
$types = array();
|
||||
|
||||
if ( in_array( $settings['processor'], array( 1, 2, 3, 4, 5, 6, 7 ) ) )
|
||||
{
|
||||
$types[] = \IPS\nexus\CreditCard::TYPE_AMERICAN_EXPRESS;
|
||||
$types[] = \IPS\nexus\CreditCard::TYPE_DINERS_CLUB;
|
||||
$types[] = \IPS\nexus\CreditCard::TYPE_DISCOVER;
|
||||
$types[] = \IPS\nexus\CreditCard::TYPE_JCB;
|
||||
}
|
||||
elseif ( in_array( $settings['processor'], array( 9, 13 ) ) )
|
||||
{
|
||||
$types[] = \IPS\nexus\CreditCard::TYPE_JCB;
|
||||
}
|
||||
|
||||
$types[] = \IPS\nexus\CreditCard::TYPE_MASTERCARD;
|
||||
$types[] = \IPS\nexus\CreditCard::TYPE_VISA;
|
||||
}
|
||||
else
|
||||
{
|
||||
$types = array( \IPS\nexus\CreditCard::TYPE_AMERICAN_EXPRESS, \IPS\nexus\CreditCard::TYPE_DINERS_CLUB, \IPS\nexus\CreditCard::TYPE_DISCOVER, \IPS\nexus\CreditCard::TYPE_JCB, \IPS\nexus\CreditCard::TYPE_MASTERCARD, \IPS\nexus\CreditCard::TYPE_VISA );
|
||||
}
|
||||
$options = array( 'types' => $types );
|
||||
|
||||
/* If we're using DPM, we include all that data in here */
|
||||
if ( $settings['method'] == 'DPM' )
|
||||
{
|
||||
$timestamp = time();
|
||||
|
||||
$options['jsRequired'] = TRUE;
|
||||
$options['names'] = FALSE;
|
||||
$options['attr'] = array(
|
||||
'data-controller' => 'nexus.global.gateways.authorizenet',
|
||||
'data-id' => $this->id,
|
||||
'class' => 'ipsHide',
|
||||
'data-url' => \IPS\NEXUS_TEST_GATEWAYS ? 'https://test.authorize.net/gateway/transact.dll' : 'https://secure.authorize.net/gateway/transact.dll',
|
||||
'data-fields' => json_encode( array(
|
||||
'x_login' => $settings['login'],
|
||||
'x_version' => '3.1',
|
||||
'x_type' => 'AUTH_ONLY',
|
||||
'x_method' => 'CC',
|
||||
'x_amount' => $amount->amount,
|
||||
'x_currency_code' => $amount->currency,
|
||||
'x_fp_hash' => hash_hmac( 'md5', "{$settings['login']}^{$invoice->id}^{$timestamp}^{$amount->amount}^{$amount->currency}", $settings['tran_key'] ),
|
||||
'x_fp_sequence' => $invoice->id,
|
||||
'x_fp_timestamp' => $timestamp,
|
||||
'x_invoice_num' => $invoice->id,
|
||||
'x_first_name' => $invoice->member->cm_first_name,
|
||||
'x_last_name' => $invoice->member->cm_last_name,
|
||||
'x_address' => $invoice->billaddress ? implode( ', ', $invoice->billaddress->addressLines ) : '',
|
||||
'x_city' => $invoice->billaddress ? $invoice->billaddress->city : '',
|
||||
'x_state' => $invoice->billaddress ? $invoice->billaddress->region : '',
|
||||
'x_zip' => $invoice->billaddress ? $invoice->billaddress->postalCode : '',
|
||||
'x_country' => $invoice->billaddress ? $invoice->billaddress->country : '',
|
||||
'x_phone' => $invoice->member->cm_phone,
|
||||
'x_email' => $invoice->member->email,
|
||||
'x_email_customer' => 'FALSE',
|
||||
'x_cust_id' => $invoice->member->member_id,
|
||||
'x_customer_ip' => \IPS\Request::i()->ipAddress(),
|
||||
'x_relay_response' => 'TRUE',
|
||||
'x_relay_url' => \IPS\Settings::i()->base_url . 'applications/nexus/interface/gateways/authorize.php',
|
||||
) )
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/* If we're using AIM, we might be able to save */
|
||||
elseif ( $this->canStoreCards() and \IPS\Member::loggedIn()->member_id )
|
||||
{
|
||||
$options['save'] = $this;
|
||||
$options['member'] = $invoice->member;
|
||||
}
|
||||
|
||||
/* And then return the card field */
|
||||
$return['card'] = new \IPS\nexus\Form\CreditCard( $this->id . '_card', NULL, FALSE, $options );
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorize (AIM only)
|
||||
*
|
||||
* @param \IPS\nexus\Transaction $transaction Transaction
|
||||
* @param array|\IPS\nexus\Customer\CreditCard $values Values from form OR a stored card object if this gateway supports them
|
||||
* @param \IPS\nexus\Fraud\MaxMind\Request|NULL $maxMind *If* MaxMind is enabled, the request object will be passed here so gateway can additional data before request is made
|
||||
* @return \IPS\DateTime|NULL Auth is valid until or NULL to indicate auth is good forever
|
||||
* @throws \LogicException Message will be displayed to user
|
||||
*/
|
||||
public function auth( \IPS\nexus\Transaction $transaction, $values, \IPS\nexus\Fraud\MaxMind\Request $maxMind = NULL )
|
||||
{
|
||||
$card = is_array( $values ) ? $values[ $this->id . '_card' ] : $values;
|
||||
|
||||
/* Stored Card */
|
||||
if ( $card instanceof \IPS\nexus\Gateway\AuthorizeNet\CreditCard )
|
||||
{
|
||||
/* MaxMind */
|
||||
if ( $maxMind )
|
||||
{
|
||||
$maxMind->setTransactionType( 'creditcard' );
|
||||
}
|
||||
|
||||
/* Authorize */
|
||||
$profiles = $card->member->cm_profiles;
|
||||
$xml = $card->create( 'createCustomerProfileTransactionRequest' );
|
||||
$xml->addChild( 'transaction', array(
|
||||
'profileTransAuthOnly' => array(
|
||||
'amount' => $transaction->amount->amount,
|
||||
'customerProfileId' => $profiles[ $card->method->id ],
|
||||
'customerPaymentProfileId' => $card->data,
|
||||
),
|
||||
) );
|
||||
$response = $this->_handleResponse( explode( ',', $card->api( $xml )->directResponse ) );
|
||||
}
|
||||
|
||||
/* New Card */
|
||||
else
|
||||
{
|
||||
/* MaxMind */
|
||||
if ( $maxMind )
|
||||
{
|
||||
$maxMind->setCard( $card );
|
||||
}
|
||||
|
||||
/* Authorize */
|
||||
$response = $this->api( array(
|
||||
'x_type' => 'AUTH_ONLY',
|
||||
'x_method' => 'CC',
|
||||
'x_amount' => $transaction->amount->amount,
|
||||
'x_currency_code' => $transaction->amount->currency,
|
||||
'x_card_num' => $card->number,
|
||||
'x_exp_date' => str_pad( $card->expMonth, 2, '0', STR_PAD_LEFT ) . '-' . $card->expYear,
|
||||
'x_card_code' => $card->ccv,
|
||||
'x_first_name' => $transaction->member->cm_first_name,
|
||||
'x_last_name' => $transaction->member->cm_last_name,
|
||||
'x_address' => implode( ', ', $transaction->invoice->billaddress->addressLines ),
|
||||
'x_city' => $transaction->invoice->billaddress->city,
|
||||
'x_state' => $transaction->invoice->billaddress->region,
|
||||
'x_zip' => $transaction->invoice->billaddress->postalCode,
|
||||
'x_country' => $transaction->invoice->billaddress->country,
|
||||
'x_phone' => $transaction->member->cm_phone,
|
||||
'x_email' => $transaction->member->email,
|
||||
'x_email_customer' => 'FALSE',
|
||||
'x_cust_id' => $transaction->member->member_id,
|
||||
'x_customer_ip' => \IPS\Request::i()->ipAddress(),
|
||||
) );
|
||||
|
||||
/* Save? */
|
||||
if ( $card->save )
|
||||
{
|
||||
try
|
||||
{
|
||||
$storedCard = new \IPS\nexus\Gateway\AuthorizeNet\CreditCard;
|
||||
$storedCard->member = $transaction->member;
|
||||
$storedCard->method = $this;
|
||||
$storedCard->card = $card;
|
||||
$storedCard->save();
|
||||
}
|
||||
catch ( \Exception $e ) { }
|
||||
}
|
||||
}
|
||||
|
||||
/* Set AVS code for MaxMind */
|
||||
if ( $maxMind and $response['avs'] )
|
||||
{
|
||||
$maxMind->setAVS( $response['avs'] );
|
||||
}
|
||||
|
||||
/* Remember the last 4 digits of the card number as we'll need them to refund */
|
||||
$extra = $transaction->extra;
|
||||
$extra['lastFour'] = $card->lastFour;
|
||||
$transaction->extra = $extra;
|
||||
|
||||
/* Return */
|
||||
$transaction->gw_id = $response['id'];
|
||||
return \IPS\DateTime::create()->add( new \DateInterval( 'P30D' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Void (AIM and DPM)
|
||||
*
|
||||
* @param \IPS\nexus\Transaction $transaction Transaction
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function void( \IPS\nexus\Transaction $transaction )
|
||||
{
|
||||
$this->api( array(
|
||||
'x_type' => 'VOID',
|
||||
'x_trans_id' => $transaction->gw_id,
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Capture (AIM and DPM)
|
||||
*
|
||||
* @param \IPS\nexus\Transaction $transaction Transaction
|
||||
* @return void
|
||||
* @throws \LogicException
|
||||
*/
|
||||
public function capture( \IPS\nexus\Transaction $transaction )
|
||||
{
|
||||
$this->api( array(
|
||||
'x_type' => 'PRIOR_AUTH_CAPTURE',
|
||||
'x_trans_id' => $transaction->gw_id,
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Refund (AIM and DPM)
|
||||
*
|
||||
* @param \IPS\nexus\Transaction $transaction Transaction to be refunded
|
||||
* @param float|NULL $amount Amount to refund (NULL for full amount - always in same currency as transaction)
|
||||
* @return mixed Gateway reference ID for refund, if applicable
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function refund( \IPS\nexus\Transaction $transaction, $amount = NULL )
|
||||
{
|
||||
$extra = json_decode( $transaction->extra, TRUE );
|
||||
|
||||
$this->api( array(
|
||||
'x_type' => 'CREDIT',
|
||||
'x_trans_id' => $transaction->gw_id,
|
||||
'x_amount' => $amount ?: $transaction->amount->amount,
|
||||
'x_card_num' => $extra['lastFour']
|
||||
) );
|
||||
}
|
||||
|
||||
/* !ACP Configuration */
|
||||
|
||||
/**
|
||||
* Settings
|
||||
*
|
||||
* @param \IPS\Helpers\Form $form The form
|
||||
* @return void
|
||||
*/
|
||||
public function settings( &$form )
|
||||
{
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'authorizenet_login', $settings['login'], TRUE ) );
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'authorizenet_tran_key', $settings['tran_key'], TRUE ) );
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'authorizenet_method', $settings['method'], TRUE, array(
|
||||
'options' => array(
|
||||
'AIM' => 'authorizenet_AIM',
|
||||
'DPM' => 'authorizenet_DPM'
|
||||
),
|
||||
'toggles' => array(
|
||||
'AIM' => array( 'authorizenet_cim' ),
|
||||
'DPM' => array( 'authorizenet_hash' )
|
||||
)
|
||||
) ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'authorizenet_cim', $settings['cim'], FALSE, array(), NULL, NULL, NULL, 'authorizenet_cim' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'authorizenet_hash', $settings['hash'], FALSE, array(), NULL, NULL, NULL, 'authorizenet_hash' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Select( 'authorizenet_processor', $settings['processor'], FALSE, array( 'options' => array(
|
||||
0 => 'dont_know',
|
||||
'North American Payment Processors' => array(
|
||||
1 => 'Chase Paymentech Tampa Processing Platform',
|
||||
2 => 'Elavon',
|
||||
3 => 'First Data Merchant Services (FDMS) Omaha, Nashville, and EFSNet Processing Platforms',
|
||||
4 => 'Global Payments',
|
||||
5 => 'Heartland Payment Systems',
|
||||
6 => 'TSYS Acquiring Solutions',
|
||||
7 => 'WorldPay Atlanta Processing Platform',
|
||||
),
|
||||
'European Payment Processors' => array(
|
||||
8 => 'AIB Merchant Services',
|
||||
9 => 'Barclaycard',
|
||||
10 => 'First Data Merchant Solutions (MSIP platform)',
|
||||
11 => 'HSBC Merchant Services',
|
||||
12 => 'Lloyds Bank Cardnet',
|
||||
13 => 'Streamline',
|
||||
),
|
||||
'Asia-Pacific Processors' => array(
|
||||
14 => 'FDI Australia',
|
||||
15 => 'Westpac',
|
||||
)
|
||||
) ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Settings
|
||||
*
|
||||
* @param array $settings Settings
|
||||
* @return array
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function testSettings( $settings )
|
||||
{
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/* !Utility Methods */
|
||||
|
||||
/**
|
||||
* Send API Request
|
||||
*
|
||||
* @param array $data The data to send
|
||||
* @return array
|
||||
* @throws \IPS\Http|Exception
|
||||
* @throws \IPS\nexus\Gateway\AuthorizeNet\Exception
|
||||
*/
|
||||
public function api( $data=array() )
|
||||
{
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
|
||||
$response = \IPS\Http\Url::external( \IPS\NEXUS_TEST_GATEWAYS ? 'https://test.authorize.net/gateway/transact.dll' : 'https://secure.authorize.net/gateway/transact.dll' )->request()->post( array_merge( array(
|
||||
'x_login' => $settings['login'],
|
||||
'x_tran_key' => $settings['tran_key'],
|
||||
'x_version' => '3.1',
|
||||
'x_delim_data' => 'TRUE',
|
||||
'x_delim_char' => '~',
|
||||
'x_encap_char' => '',
|
||||
), $data ) );
|
||||
|
||||
return $this->_handleResponse( explode( '~', $response ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle response
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
* @throws \IPS\nexus\Gateway\AuthorizeNet\Exception
|
||||
*/
|
||||
protected function _handleResponse( $response )
|
||||
{
|
||||
if ( $response[0] != 1 )
|
||||
{
|
||||
throw new \IPS\nexus\Gateway\AuthorizeNet\Exception( $response[2] );
|
||||
}
|
||||
|
||||
return array(
|
||||
'id' => $response[6],
|
||||
'avs' => $response[5],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Authorize.Net CIM Stored Card
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @subpackage Nexus
|
||||
* @since 17 Mar 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\nexus\Gateway\AuthorizeNet;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorize.Net CIM Stored Card
|
||||
*/
|
||||
class _CreditCard extends \IPS\nexus\Customer\CreditCard
|
||||
{
|
||||
/**
|
||||
* @brief Card
|
||||
*/
|
||||
protected $_card;
|
||||
|
||||
/**
|
||||
* Get card
|
||||
*
|
||||
* @return \IPS\nexus\CreditCard
|
||||
*/
|
||||
public function get_card()
|
||||
{
|
||||
if ( !$this->_card )
|
||||
{
|
||||
$profiles = $this->member->cm_profiles;
|
||||
if ( !isset( $profiles[ $this->method->id ] ) )
|
||||
{
|
||||
throw new \UnexpectedValueException;
|
||||
}
|
||||
|
||||
$xml = $this->create('getCustomerPaymentProfileRequest');
|
||||
$xml->addChild( 'customerProfileId', $profiles[ $this->method->id ] );
|
||||
$xml->addChild( 'customerPaymentProfileId', $this->data );
|
||||
$response = $this->api( $xml );
|
||||
|
||||
$this->_card = new \IPS\nexus\CreditCard;
|
||||
$this->_card->lastFour = mb_substr( $response->paymentProfile->payment->creditCard->cardNumber, -4 );
|
||||
}
|
||||
return $this->_card;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set card
|
||||
*
|
||||
* @param \IPS\nexus\CreditCard $card The card
|
||||
* @return void
|
||||
*/
|
||||
public function set_card( \IPS\nexus\CreditCard $card )
|
||||
{
|
||||
/* Create Profile */
|
||||
$profiles = $this->member->cm_profiles;
|
||||
if ( !isset( $profiles[ $this->method->id ] ) )
|
||||
{
|
||||
$xml = $this->create( 'createCustomerProfileRequest' );
|
||||
$xml->addChild( 'profile', array(
|
||||
'merchantCustomerId' => $this->member->member_id
|
||||
) );
|
||||
$response = $this->api( $xml );
|
||||
if ( !$response->customerProfileId )
|
||||
{
|
||||
throw new \UnexpectedValueException;
|
||||
}
|
||||
|
||||
$profiles[ $this->method->id ] = (string) $response->customerProfileId;
|
||||
$this->member->cm_profiles = $profiles;
|
||||
$this->member->save();
|
||||
}
|
||||
|
||||
/* Add the card */
|
||||
$xml = $this->create( 'createCustomerPaymentProfileRequest' );
|
||||
$xml->addChild( 'customerProfileId', $profiles[ $this->method->id ] );
|
||||
$xml->addChild( 'paymentProfile', array(
|
||||
'payment' => array(
|
||||
'creditCard' => array(
|
||||
'cardNumber' => $card->number,
|
||||
'expirationDate'=> $card->expYear . '-' . str_pad( $card->expMonth, 2, '0', STR_PAD_LEFT ),
|
||||
'cardCode' => $card->ccv
|
||||
)
|
||||
)
|
||||
) );
|
||||
$xml->addChild( 'validationMode', 'none' );
|
||||
$response = $this->api( $xml );
|
||||
if ( !$response->customerPaymentProfileId )
|
||||
{
|
||||
throw new \UnexpectedValueException;
|
||||
}
|
||||
|
||||
/* Save */
|
||||
$this->data = (string) $response->customerPaymentProfileId;
|
||||
$this->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
$profiles = $this->member->cm_profiles;
|
||||
if ( isset( $profiles[ $this->method->id ] ) )
|
||||
{
|
||||
$xml = $this->create( 'deleteCustomerPaymentProfileRequest' );
|
||||
$xml->addChild( 'customerProfileId', $profiles[ $this->method->id ] );
|
||||
$xml->addChild( 'customerPaymentProfileId', $this->data );
|
||||
$response = $this->api( $xml );
|
||||
}
|
||||
|
||||
parent::delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send API Request
|
||||
*
|
||||
* @param \IPS\Xml\SimpleXML $xml The XML to send
|
||||
* @return \IPS\Xml\SimpleXML
|
||||
*/
|
||||
public function api( \IPS\Xml\SimpleXML $xml )
|
||||
{
|
||||
return \IPS\Http\Url::external( \IPS\NEXUS_TEST_GATEWAYS ? 'https://apitest.authorize.net/xml/v1/request.api' : 'https://api.authorize.net/xml/v1/request.api' )
|
||||
->request()
|
||||
->setHeaders( array( 'Content-Type' => 'application/xml' ) )
|
||||
->post( $xml->asXML() )
|
||||
->decodeXml();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create XML document with authentication credentials
|
||||
*
|
||||
* @param string $method The API method we will be calling
|
||||
* @return \IPS\Xml\SimpleXML
|
||||
*/
|
||||
public function create( $method )
|
||||
{
|
||||
$settings = json_decode( $this->method->settings, TRUE );
|
||||
$xml = \IPS\Xml\SimpleXML::create( $method, 'AnetApi/xml/v1/schema/AnetApiSchema.xsd' );
|
||||
$authentication = $xml->addChild( 'merchantAuthentication' );
|
||||
$authentication->addChild( 'name', $settings['login'] );
|
||||
$authentication->addChild( 'transactionKey', $settings['tran_key'] );
|
||||
|
||||
return $xml;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Authorize.Net Exception
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @subpackage Nexus
|
||||
* @since 17 Mar 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\nexus\Gateway\AuthorizeNet;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* AuthorizeNet Exception
|
||||
*/
|
||||
class _Exception extends \DomainException
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param int $reasonCode Response Reason Code
|
||||
* @return void
|
||||
*/
|
||||
public function __construct( $reasonCode )
|
||||
{
|
||||
switch ( $reasonCode )
|
||||
{
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 41:
|
||||
case 45:
|
||||
$message = \IPS\Member::loggedIn()->language()->get( 'card_refused' );
|
||||
break;
|
||||
|
||||
case 6:
|
||||
case 37:
|
||||
$message = \IPS\Member::loggedIn()->language()->get( 'card_number_invalid' );
|
||||
break;
|
||||
|
||||
case 8:
|
||||
$message = \IPS\Member::loggedIn()->language()->get( 'card_expire_expired' );
|
||||
break;
|
||||
|
||||
case 44:
|
||||
case 65:
|
||||
case 78:
|
||||
$message = \IPS\Member::loggedIn()->language()->get( 'ccv_invalid' );
|
||||
break;
|
||||
|
||||
default:
|
||||
$message = \IPS\Member::loggedIn()->language()->get( 'gateway_err' );
|
||||
break;
|
||||
}
|
||||
|
||||
return parent::__construct( $message, $reasonCode );
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,336 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Gateway Node
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @subpackage Nexus
|
||||
* @since 10 Feb 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\nexus;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gateway Node
|
||||
*/
|
||||
class _Gateway extends \IPS\Node\Model
|
||||
{
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Table
|
||||
*/
|
||||
public static $databaseTable = 'nexus_paymethods';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'm_';
|
||||
|
||||
/**
|
||||
* @brief [Node] Order Database Column
|
||||
*/
|
||||
public static $databaseColumnOrder = 'position';
|
||||
|
||||
/**
|
||||
* @brief [Node] Node Title
|
||||
*/
|
||||
public static $nodeTitle = 'payment_methods';
|
||||
|
||||
/**
|
||||
* @brief [Node] Title prefix. If specified, will look for a language key with "{$key}_title" as the key
|
||||
*/
|
||||
public static $titleLangPrefix = 'nexus_paymethod_';
|
||||
|
||||
/**
|
||||
* Construct ActiveRecord from database row
|
||||
*
|
||||
* @param array $data Row from database table
|
||||
* @param bool $updateMultitonStoreIfExists Replace current object in multiton store if it already exists there?
|
||||
* @return static
|
||||
*/
|
||||
public static function constructFromData( $data, $updateMultitonStoreIfExists = TRUE )
|
||||
{
|
||||
$classname = 'IPS\nexus\Gateway\\' . $data['m_gateway'];
|
||||
if ( !class_exists( $classname ) )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
|
||||
/* Initiate an object */
|
||||
$obj = new $classname;
|
||||
$obj->_new = FALSE;
|
||||
|
||||
/* Import data */
|
||||
foreach ( $data as $k => $v )
|
||||
{
|
||||
if( static::$databasePrefix AND mb_strpos( $k, static::$databasePrefix ) === 0 )
|
||||
{
|
||||
$k = \substr( $k, \strlen( static::$databasePrefix ) );
|
||||
}
|
||||
|
||||
$obj->_data[ $k ] = $v;
|
||||
}
|
||||
$obj->changed = array();
|
||||
|
||||
/* Init */
|
||||
if ( method_exists( $obj, 'init' ) )
|
||||
{
|
||||
$obj->init();
|
||||
}
|
||||
|
||||
/* Return */
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Get whether or not this node is enabled
|
||||
*
|
||||
* @note Return value NULL indicates the node cannot be enabled/disabled
|
||||
* @return bool|null
|
||||
*/
|
||||
protected function get__enabled()
|
||||
{
|
||||
return $this->enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Set whether or not this node is enabled
|
||||
*
|
||||
* @param bool|int $enabled Whether to set it enabled or disabled
|
||||
* @return void
|
||||
*/
|
||||
protected function set__enabled( $enabled )
|
||||
{
|
||||
$this->enabled = $enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief [Node] ACP Restrictions
|
||||
* @code
|
||||
array(
|
||||
'app' => 'core', // The application key which holds the restrictrions
|
||||
'module' => 'foo', // The module key which holds the restrictions
|
||||
'map' => array( // [Optional] The key for each restriction - can alternatively use "prefix"
|
||||
'add' => 'foo_add',
|
||||
'edit' => 'foo_edit',
|
||||
'permissions' => 'foo_perms',
|
||||
'delete' => 'foo_delete'
|
||||
),
|
||||
'all' => 'foo_manage', // [Optional] The key to use for any restriction not provided in the map (only needed if not providing all 4)
|
||||
'prefix' => 'foo_', // [Optional] Rather than specifying each key in the map, you can specify a prefix, and it will automatically look for restrictions with the key "[prefix]_add/edit/permissions/delete"
|
||||
* @endcode
|
||||
*/
|
||||
protected static $restrictions = array(
|
||||
'app' => 'nexus',
|
||||
'module' => 'payments',
|
||||
'all' => 'gateways_manage',
|
||||
);
|
||||
|
||||
/**
|
||||
* [Node] Add/Edit Form
|
||||
*
|
||||
* @param \IPS\Helpers\Form $form The form
|
||||
* @return void
|
||||
*/
|
||||
public function form( &$form )
|
||||
{
|
||||
$form->add( new \IPS\Helpers\Form\Translatable( 'paymethod_name', NULL, TRUE, array( 'app' => 'nexus', 'key' => "nexus_paymethod_{$this->id}" ) ) );
|
||||
$this->settings( $form );
|
||||
$form->add( new \IPS\Helpers\Form\Select( 'paymethod_countries', ( $this->countries and $this->countries !== '*' ) ? explode( ',', $this->countries ) : '*', FALSE, array( 'options' => array_map( function( $val )
|
||||
{
|
||||
return "country-{$val}";
|
||||
}, array_combine( \IPS\GeoLocation::$countries, \IPS\GeoLocation::$countries ) ), 'multiple' => TRUE, 'unlimited' => '*', 'unlimitedLang' => 'no_restriction' ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Format form values from add/edit form for save
|
||||
*
|
||||
* @param array $values Values from the form
|
||||
* @return array
|
||||
*/
|
||||
public function formatFormValues( $values )
|
||||
{
|
||||
if( isset( $values['paymethod_name'] ) )
|
||||
{
|
||||
\IPS\Lang::saveCustom( 'nexus', "nexus_paymethod_{$this->id}", $values['paymethod_name'] );
|
||||
unset( $values['paymethod_name'] );
|
||||
}
|
||||
|
||||
if( isset( $values['paymethod_countries'] ) )
|
||||
{
|
||||
$values['countries'] = is_array( $values['paymethod_countries'] ) ? implode( ',', $values['paymethod_countries'] ) : $values['paymethod_countries'];
|
||||
}
|
||||
|
||||
$settings = array();
|
||||
foreach ( $values as $k => $v )
|
||||
{
|
||||
if ( mb_substr( $k, 0, mb_strlen( $this->gateway ) + 1 ) === mb_strtolower( "{$this->gateway}_" ) )
|
||||
{
|
||||
$settings[ mb_substr( $k, mb_strlen( $this->gateway ) + 1 ) ] = $v;
|
||||
}
|
||||
if( $k != "countries" )
|
||||
{
|
||||
unset( $values[$k] );
|
||||
}
|
||||
}
|
||||
$values['settings'] = json_encode( $this->testSettings( $settings ) );
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get gateways that support storing cards
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function cardStorageGateways()
|
||||
{
|
||||
$return = array();
|
||||
foreach ( static::roots() as $gateway )
|
||||
{
|
||||
if ( $gateway->canStoreCards() )
|
||||
{
|
||||
$return[ $gateway->id ] = $gateway;
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get gateways that support manual admin charges
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function manualChargeGateways()
|
||||
{
|
||||
$return = array();
|
||||
foreach ( static::roots() as $gateway )
|
||||
{
|
||||
if ( $gateway->canAdminCharge() )
|
||||
{
|
||||
$return[ $gateway->id ] = $gateway;
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/* !Features (Each gateway will override) */
|
||||
|
||||
const SUPPORTS_REFUNDS = FALSE;
|
||||
const SUPPORTS_PARTIAL_REFUNDS = FALSE;
|
||||
|
||||
/**
|
||||
* Check the gateway can process this...
|
||||
*
|
||||
* @param $amount \IPS\nexus\Money The amount
|
||||
* @param $billingAddress \IPS\GeoLocation The billing address
|
||||
* @return bool
|
||||
*/
|
||||
public function checkValidity( \IPS\nexus\Money $amount, \IPS\GeoLocation $billingAddress )
|
||||
{
|
||||
if ( $this->countries and $this->countries !== '*' )
|
||||
{
|
||||
return in_array( $billingAddress->country, explode( ',', $this->countries ) );
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can store cards?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canStoreCards()
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin can manually charge using this gateway?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canAdminCharge()
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* !Payment Gateway */
|
||||
|
||||
/**
|
||||
* Payment Screen Fields
|
||||
*
|
||||
* @param \IPS\nexus\Invoice $invoice Invoice
|
||||
* @param \IPS\nexus\Money $amount The amount to pay now
|
||||
* @return array
|
||||
*/
|
||||
public function paymentScreen( \IPS\nexus\Invoice $invoice, \IPS\nexus\Money $amount )
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorize
|
||||
*
|
||||
* @param \IPS\nexus\Transaction $transaction Transaction
|
||||
* @param array|\IPS\nexus\Customer\StoredCard $values Values from form OR a stored card object if this gateway supports them
|
||||
* @param \IPS\nexus\Fraud\MaxMind\Request|NULL $maxMind *If* MaxMind is enabled, the request object will be passed here so gateway can additional data before request is made
|
||||
* @return \IPS\DateTime|NULL Auth is valid until or NULL to indicate auth is good forever
|
||||
* @throws \LogicException Message will be displayed to user
|
||||
*/
|
||||
public function auth( \IPS\nexus\Transaction $transaction, $values, \IPS\nexus\Fraud\MaxMind\Request $maxMind = NULL )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Void
|
||||
*
|
||||
* @param \IPS\nexus\Transaction $transaction Transaction
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function void( \IPS\nexus\Transaction $transaction )
|
||||
{
|
||||
return $this->refund( $transaction );
|
||||
}
|
||||
|
||||
/**
|
||||
* Capture
|
||||
*
|
||||
* @param \IPS\nexus\Transaction $transaction Transaction
|
||||
* @return void
|
||||
* @throws \LogicException
|
||||
*/
|
||||
public function capture( \IPS\nexus\Transaction $transaction )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Refund
|
||||
*
|
||||
* @param \IPS\nexus\Transaction $transaction Transaction to be refunded
|
||||
* @param float|NULL $amount Amount to refund (NULL for full amount - always in same currency as transaction)
|
||||
* @return mixed Gateway reference ID for refund, if applicable
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function refund( \IPS\nexus\Transaction $transaction, $amount = NULL )
|
||||
{
|
||||
throw new \Exception;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Manual Gateway
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @subpackage Nexus
|
||||
* @since 18 Mar 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\nexus\Gateway;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manual Gateway
|
||||
*/
|
||||
class _Manual extends \IPS\nexus\Gateway
|
||||
{
|
||||
/* !Payment Gateway */
|
||||
|
||||
/**
|
||||
* Authorize
|
||||
*
|
||||
* @param \IPS\nexus\Transaction $transaction Transaction
|
||||
* @param array|\IPS\nexus\Customer\CreditCard $values Values from form OR a stored card object if this gateway supports them
|
||||
* @param \IPS\nexus\Fraud\MaxMind\Request|NULL $maxMind *If* MaxMind is enabled, the request object will be passed here so gateway can additional data before request is made
|
||||
* @return \IPS\DateTime|NULL Auth is valid until or NULL to indicate auth is good forever
|
||||
* @throws \LogicException Message will be displayed to user
|
||||
*/
|
||||
public function auth( \IPS\nexus\Transaction $transaction, $values, \IPS\nexus\Fraud\MaxMind\Request $maxMind = NULL )
|
||||
{
|
||||
$transaction->status = \IPS\nexus\Transaction::STATUS_WAITING;
|
||||
$extra = $transaction->extra;
|
||||
$extra['history'][] = array( 's' => \IPS\nexus\Transaction::STATUS_WAITING );
|
||||
$transaction->extra = $extra;
|
||||
$transaction->save();
|
||||
\IPS\Output::i()->redirect( $transaction->url() );
|
||||
}
|
||||
|
||||
/* !ACP Configuration */
|
||||
|
||||
/**
|
||||
* Settings
|
||||
*
|
||||
* @param \IPS\Helpers\Form $form The form
|
||||
* @return void
|
||||
*/
|
||||
public function settings( &$form )
|
||||
{
|
||||
$form->add( new \IPS\Helpers\Form\Translatable( 'manual_instructions', NULL, TRUE, array( 'app' => 'nexus', 'key' => ( $this->id ? "nexus_gateway_{$this->id}_ins" : NULL ), 'editor' => array( 'app' => 'nexus', 'key' => 'Admin', 'autoSaveKey' => ( $this->id ? "nexus-gateway-{$this->id}" : "nexus-new-gateway" ), 'attachIds' => $this->id ? array( $this->id, NULL, 'description' ) : NULL, 'minimize' => 'forum_description_placeholder' ) ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Format form values from add/edit form for save
|
||||
*
|
||||
* @param array $values Values from the form
|
||||
* @return array
|
||||
*/
|
||||
public function formatFormValues( $values )
|
||||
{
|
||||
if( isset( $values['manual_instructions'] ) )
|
||||
{
|
||||
\IPS\Lang::saveCustom( 'nexus', "nexus_gateway_{$this->id}_ins", $values['manual_instructions'] );
|
||||
unset( $values['manual_instructions'] );
|
||||
}
|
||||
|
||||
if ( !$this->id )
|
||||
{
|
||||
$this->save();
|
||||
\IPS\File::claimAttachments( 'nexus_gateway_new', $this->id, NULL, 'gateway', TRUE );
|
||||
}
|
||||
|
||||
return parent::formatFormValues( $values );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Settings
|
||||
*
|
||||
* @param array $settings Settings
|
||||
* @return array
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function testSettings( $settings=array() )
|
||||
{
|
||||
return $settings;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Manual Pay Out Gateway
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @subpackage Nexus
|
||||
* @since 7 Apr 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\nexus\Gateway\Manual;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manual Pay Out Gateway
|
||||
*/
|
||||
class _Payout extends \IPS\nexus\Payout
|
||||
{
|
||||
/**
|
||||
* @brief Requires manual approval?
|
||||
*/
|
||||
public static $requiresApproval = TRUE;
|
||||
|
||||
/**
|
||||
* ACP Settings
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function settings()
|
||||
{
|
||||
$settings = json_decode( \IPS\Settings::i()->nexus_payout, TRUE );
|
||||
|
||||
$return = array();
|
||||
$return[] = new \IPS\Helpers\Form\Text( 'manual_name', isset( $settings['Manual'] ) ? $settings['Manual']['name'] : '' );
|
||||
$return[] = new \IPS\Helpers\Form\Text( 'manual_title', isset( $settings['Manual'] ) ? $settings['Manual']['title'] : '' );
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Payout Form
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function form()
|
||||
{
|
||||
$settings = json_decode( \IPS\Settings::i()->nexus_payout, TRUE );
|
||||
|
||||
$field = new \IPS\Helpers\Form\TextArea( 'manual_details', NULL, NULL, array(), function( $val )
|
||||
{
|
||||
if ( !$val and \IPS\Request::i()->withdraw_method === 'Manual' )
|
||||
{
|
||||
throw new \DomainException('form_required');
|
||||
}
|
||||
} );
|
||||
$field->label = $settings['Manual']['title'];
|
||||
return array( $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get data and validate
|
||||
*
|
||||
* @param array $values Values from form
|
||||
* @return mixed
|
||||
* @throws \DomainException
|
||||
*/
|
||||
public function getData( array $values )
|
||||
{
|
||||
return $values['manual_details'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Process
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function process()
|
||||
{
|
||||
$this->status = static::STATUS_COMPLETE;
|
||||
$this->completed = new \IPS\DateTime;
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief PayPal Stored Card
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @subpackage Nexus
|
||||
* @since 10 Feb 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\nexus\Gateway\PayPal;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* PayPal Stored Card
|
||||
*/
|
||||
class _CreditCard extends \IPS\nexus\Customer\CreditCard
|
||||
{
|
||||
/**
|
||||
* @brief Card
|
||||
*/
|
||||
protected $_card;
|
||||
|
||||
/**
|
||||
* Get card
|
||||
*
|
||||
* @return \IPS\nexus\CreditCard
|
||||
*/
|
||||
public function get_card()
|
||||
{
|
||||
if ( !$this->_card )
|
||||
{
|
||||
$response = $this->method->api( 'vault/credit-card/' . $this->data, NULL, 'get' );
|
||||
|
||||
$this->_card = new \IPS\nexus\CreditCard;
|
||||
$this->_card->lastFour = mb_substr( $response['number'], -4 );
|
||||
switch ( $response['type'] )
|
||||
{
|
||||
case 'visa':
|
||||
$this->_card->type = \IPS\nexus\CreditCard::TYPE_VISA;
|
||||
break;
|
||||
case 'mastercard':
|
||||
$this->_card->type = \IPS\nexus\CreditCard::TYPE_MASTERCARD;
|
||||
break;
|
||||
case 'discover':
|
||||
$this->_card->type = \IPS\nexus\CreditCard::TYPE_DISCOVER;
|
||||
break;
|
||||
case 'amex':
|
||||
$this->_card->type = \IPS\nexus\CreditCard::TYPE_AMERICAN_EXPRESS;
|
||||
break;
|
||||
}
|
||||
$this->_card->expMonth = $response['expire_month'];
|
||||
$this->_card->expYear = $response['expire_year'];
|
||||
}
|
||||
return $this->_card;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set card
|
||||
*
|
||||
* @param \IPS\nexus\CreditCard $card The card
|
||||
* @return void
|
||||
*/
|
||||
public function set_card( \IPS\nexus\CreditCard $card )
|
||||
{
|
||||
switch ( $card->type )
|
||||
{
|
||||
case \IPS\nexus\CreditCard::TYPE_VISA:
|
||||
$cardType = 'visa';
|
||||
break;
|
||||
case \IPS\nexus\CreditCard::TYPE_MASTERCARD:
|
||||
$cardType = 'mastercard';
|
||||
break;
|
||||
case \IPS\nexus\CreditCard::TYPE_DISCOVER:
|
||||
$cardType = 'discover';
|
||||
break;
|
||||
case \IPS\nexus\CreditCard::TYPE_AMERICAN_EXPRESS:
|
||||
$cardType = 'amex';
|
||||
break;
|
||||
}
|
||||
|
||||
$response = $this->method->api( 'vault/credit-card', array(
|
||||
'number' => $card->number,
|
||||
'type' => $cardType,
|
||||
'expire_month' => intval( $card->expMonth ),
|
||||
'expire_year' => intval( $card->expYear ),
|
||||
'cvv2' => intval( $card->ccv ),
|
||||
'first_name' => $this->member->cm_first_name,
|
||||
'last_name' => $this->member->cm_last_name,
|
||||
) );
|
||||
|
||||
$this->data = $response['id'];
|
||||
$this->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
$this->method->api( 'vault/credit-card/' . $this->data, NULL, 'delete' );
|
||||
return parent::delete();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief PayPal Exception
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @subpackage Nexus
|
||||
* @since 10 Mar 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\nexus\Gateway\PayPal;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* PayPal Exception
|
||||
*/
|
||||
class _Exception extends \DomainException
|
||||
{
|
||||
/**
|
||||
* @brief Name
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* @brief Details
|
||||
*/
|
||||
protected $details = array();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \IPS\Http\Response $response Response from PayPal
|
||||
* @param bool $refund request is for a refund?
|
||||
* @return void
|
||||
*/
|
||||
public function __construct( \IPS\Http\Response $response, $refund=FALSE )
|
||||
{
|
||||
\IPS\Log::i( \LOG_DEBUG )->write( (string) $response );
|
||||
|
||||
$details = $response->decodeJson();
|
||||
$this->name = $details['name'];
|
||||
if ( isset( $details['details'] ) )
|
||||
{
|
||||
$this->details = $details['details'];
|
||||
}
|
||||
|
||||
switch ( $this->name )
|
||||
{
|
||||
case 'EXPIRED_CREDIT_CARD':
|
||||
$message = \IPS\Member::loggedIn()->language()->get( 'card_expire_expired' );
|
||||
break;
|
||||
|
||||
case 'CREDIT_CARD_REFUSED':
|
||||
$message = \IPS\Member::loggedIn()->language()->get( 'card_refused' );
|
||||
break;
|
||||
|
||||
case 'CREDIT_CARD_CVV_CHECK_FAILED':
|
||||
$message = \IPS\Member::loggedIn()->language()->get( 'ccv_invalid' );
|
||||
break;
|
||||
|
||||
case 'REFUND_EXCEEDED_TRANSACTION_AMOUNT':
|
||||
case 'FULL_REFUND_NOT_ALLOWED_AFTER_PARTIAL_REFUND':
|
||||
$message = \IPS\Member::loggedIn()->language()->get( 'refund_amount_exceeds' );
|
||||
break;
|
||||
|
||||
case 'REFUND_TIME_LIMIT_EXCEEDED':
|
||||
$message = \IPS\Member::loggedIn()->language()->get( 'refund_time_limit' );
|
||||
break;
|
||||
|
||||
case 'TRANSACTION_ALREADY_REFUNDED':
|
||||
$message = \IPS\Member::loggedIn()->language()->get( 'refund_already_processed' );
|
||||
break;
|
||||
|
||||
case 'ADDRESS_INVALID':
|
||||
$message = \IPS\Member::loggedIn()->language()->get( 'address_invalid' );
|
||||
break;
|
||||
|
||||
default:
|
||||
if ( $refund )
|
||||
{
|
||||
$message = \IPS\Member::loggedIn()->language()->get( 'refund_failed' );
|
||||
}
|
||||
else
|
||||
{
|
||||
$message = \IPS\Member::loggedIn()->language()->get( 'gateway_err' );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return parent::__construct( $message, $response->httpResponseCode );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,664 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief PayPal Gateway
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @subpackage Nexus
|
||||
* @since 10 Feb 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\nexus\Gateway;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* PayPal Gateway
|
||||
*/
|
||||
class _PayPal extends \IPS\nexus\Gateway
|
||||
{
|
||||
/* !Features */
|
||||
|
||||
const SUPPORTS_REFUNDS = TRUE;
|
||||
const SUPPORTS_PARTIAL_REFUNDS = TRUE;
|
||||
|
||||
/**
|
||||
* Check the gateway can process this...
|
||||
*
|
||||
* @param $amount \IPS\nexus\Money The amount
|
||||
* @param $billingAddress \IPS\GeoLocation The billing address
|
||||
* @return bool
|
||||
* @see <a href="https://developer.paypal.com/docs/integration/direct/rest_api_payment_country_currency_support/">PayPal REST API Country & Currency Support</a>
|
||||
*/
|
||||
public function checkValidity( \IPS\nexus\Money $amount, \IPS\GeoLocation $billingAddress )
|
||||
{
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
if ( $settings['type'] === 'card' )
|
||||
{
|
||||
if ( !in_array( $amount->currency, array( 'USD', 'GBP', 'CAD', 'EUR', 'JPY' ) ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
switch ( $amount->currency )
|
||||
{
|
||||
case 'AUD':
|
||||
if ( $amount->amount >= 12500 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 'BRL':
|
||||
if ( $amount->amount >= 20000 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 'CAD':
|
||||
if ( $amount->amount >= 12500 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 'CZK':
|
||||
if ( $amount->amount >= 240000 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 'DKK':
|
||||
if ( $amount->amount >= 60000 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 'EUR':
|
||||
if ( $amount->amount >= 8000 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 'HKD':
|
||||
if ( $amount->amount >= 80000 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 'HUF':
|
||||
if ( $amount->amount >= 2000000 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 'ILS':
|
||||
if ( $amount->amount >= 40000 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 'JPY':
|
||||
if ( $amount->amount >= 1000000 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 'MYR':
|
||||
if ( $amount->amount >= 40000 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 'MXN':
|
||||
if ( $amount->amount >= 110000 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 'TWD':
|
||||
if ( $amount->amount >= 330000 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 'NZD':
|
||||
if ( $amount->amount >= 15000 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 'NOK':
|
||||
if ( $amount->amount >= 70000 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 'PHP':
|
||||
if ( $amount->amount >= 500000 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 'PLN':
|
||||
if ( $amount->amount >= 32000 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 'GBP':
|
||||
if ( $amount->amount >= 5500 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 'SGD':
|
||||
if ( $amount->amount >= 16000 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 'SEK':
|
||||
if ( $amount->amount >= 80000 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 'CHF':
|
||||
if ( $amount->amount >= 13000 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 'THB':
|
||||
if ( $amount->amount >= 360000 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 'TRY':
|
||||
if ( $amount->amount >= 25000 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 'USD':
|
||||
if ( $amount->amount >= 10000 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return parent::checkValidity( $amount, $billingAddress );
|
||||
}
|
||||
|
||||
/**
|
||||
* Can store cards?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canStoreCards()
|
||||
{
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
return ( isset( $settings['type'] ) and $settings['type'] === 'card' and $settings['vault'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin can manually charge using this gateway?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canAdminCharge()
|
||||
{
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
return ( isset( $settings['type'] ) and $settings['type'] === 'card' );
|
||||
}
|
||||
|
||||
/* !Payment Gateway */
|
||||
|
||||
/**
|
||||
* Payment Screen Fields
|
||||
*
|
||||
* @param \IPS\nexus\Invoice $invoice Invoice
|
||||
* @param \IPS\nexus\Money $amount The amount to pay now
|
||||
* @return array
|
||||
*/
|
||||
public function paymentScreen( \IPS\nexus\Invoice $invoice, \IPS\nexus\Money $amount )
|
||||
{
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
if ( $settings['type'] === 'card' )
|
||||
{
|
||||
return array( 'card' => new \IPS\nexus\Form\CreditCard( $this->id . '_card', NULL, FALSE, array(
|
||||
'types' => array( \IPS\nexus\CreditCard::TYPE_VISA, \IPS\nexus\CreditCard::TYPE_MASTERCARD, \IPS\nexus\CreditCard::TYPE_DISCOVER, \IPS\nexus\CreditCard::TYPE_AMERICAN_EXPRESS ),
|
||||
'save' => ( $settings['vault'] and \IPS\Member::loggedIn()->member_id ) ? $this : NULL
|
||||
) ) );
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorize
|
||||
*
|
||||
* @param \IPS\nexus\Transaction $transaction Transaction
|
||||
* @param array|\IPS\nexus\Customer\CreditCard $values Values from form OR a stored card object if this gateway supports them
|
||||
* @param \IPS\nexus\Fraud\MaxMind\Request|NULL $maxMind *If* MaxMind is enabled, the request object will be passed here so gateway can additional data before request is made
|
||||
* @return \IPS\DateTime|NULL Auth is valid until or NULL to indicate auth is good forever
|
||||
* @throws \LogicException Message will be displayed to user
|
||||
*/
|
||||
public function auth( \IPS\nexus\Transaction $transaction, $values, \IPS\nexus\Fraud\MaxMind\Request $maxMind = NULL )
|
||||
{
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
|
||||
/* Build data */
|
||||
if ( $settings['type'] === 'card' )
|
||||
{
|
||||
$card = is_array( $values ) ? $values[ $this->id . '_card' ] : $values;
|
||||
|
||||
if ( $card instanceof \IPS\nexus\Customer\CreditCard )
|
||||
{
|
||||
$payer = array(
|
||||
'payment_method' => 'credit_card',
|
||||
'funding_instruments' => array(
|
||||
array(
|
||||
'credit_card_token' => array(
|
||||
'credit_card_id' => $card->data
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( $maxMind )
|
||||
{
|
||||
$maxMind->setCard( $card );
|
||||
}
|
||||
|
||||
switch ( $card->type )
|
||||
{
|
||||
case \IPS\nexus\CreditCard::TYPE_VISA:
|
||||
$cardType = 'visa';
|
||||
break;
|
||||
case \IPS\nexus\CreditCard::TYPE_MASTERCARD:
|
||||
$cardType = 'mastercard';
|
||||
break;
|
||||
case \IPS\nexus\CreditCard::TYPE_DISCOVER:
|
||||
$cardType = 'discover';
|
||||
break;
|
||||
case \IPS\nexus\CreditCard::TYPE_AMERICAN_EXPRESS:
|
||||
$cardType = 'amex';
|
||||
break;
|
||||
}
|
||||
|
||||
/* PayPal requires short codes for states */
|
||||
$billingState = $transaction->invoice->billaddress->region;
|
||||
if ( isset( \IPS\nexus\Customer\Address::$stateCodes[ $transaction->invoice->billaddress->country ] ) )
|
||||
{
|
||||
if ( !array_key_exists( $billingState, \IPS\nexus\Customer\Address::$stateCodes[ $transaction->invoice->billaddress->country ] ) )
|
||||
{
|
||||
$_billingState = array_search( $transaction->invoice->billaddress->region, \IPS\nexus\Customer\Address::$stateCodes[ $transaction->invoice->billaddress->country ] );
|
||||
if ( $_billingState !== FALSE )
|
||||
{
|
||||
$billingState = $_billingState;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$billingAddress = array(
|
||||
'line1' => $transaction->invoice->billaddress->addressLines[0],
|
||||
'line2' => isset( $transaction->invoice->billaddress->addressLines[1] ) ? $transaction->invoice->billaddress->addressLines[1] : '',
|
||||
'city' => $transaction->invoice->billaddress->city,
|
||||
'country_code' => $transaction->invoice->billaddress->country,
|
||||
'postal_code' => $transaction->invoice->billaddress->postalCode,
|
||||
'state' => $billingState,
|
||||
);
|
||||
if ( $transaction->member->cm_phone )
|
||||
{
|
||||
$billingAddress['phone'] = preg_replace( '/[^\+0-9\s]/', '', $transaction->member->cm_phone );
|
||||
}
|
||||
|
||||
$payer = array(
|
||||
'payment_method' => 'credit_card',
|
||||
'funding_instruments' => array(
|
||||
array(
|
||||
'credit_card' => array(
|
||||
'number' => $card->number,
|
||||
'type' => $cardType,
|
||||
'expire_month' => intval( $card->expMonth ),
|
||||
'expire_year' => intval( $card->expYear ),
|
||||
'cvv2' => intval( $card->ccv ),
|
||||
'first_name' => $transaction->member->cm_first_name,
|
||||
'last_name' => $transaction->member->cm_last_name,
|
||||
'billing_address' => $billingAddress
|
||||
)
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$payer = array( 'payment_method' => 'paypal' );
|
||||
}
|
||||
|
||||
/* We need a transaction ID */
|
||||
$transaction->save();
|
||||
|
||||
/* Item list */
|
||||
$payPalTransactionData = array(
|
||||
'amount' => array(
|
||||
'currency' => $transaction->amount->currency,
|
||||
'total' => $transaction->amount->amountAsString(),
|
||||
),
|
||||
'invoice_number'=> $transaction->id,
|
||||
);
|
||||
if ( $transaction->amount->amount == $transaction->invoice->total->amount )
|
||||
{
|
||||
$summary = $transaction->invoice->summary();
|
||||
$payPalTransactionData['amount']['details'] = array(
|
||||
'shipping' => $summary['shippingTotal']->amountAsString(),
|
||||
'subtotal' => $summary['subtotal']->amountAsString(),
|
||||
'tax' => $summary['taxTotal']->amountAsString(),
|
||||
);
|
||||
|
||||
$payPalTransactionData['item_list'] = array( 'items' => array() );
|
||||
foreach ( $summary['items'] as $item )
|
||||
{
|
||||
$payPalTransactionData['item_list']['items'][] = array(
|
||||
'quantity' => $item->quantity,
|
||||
'name' => $item->name,
|
||||
'price' => $item->price->amountAsString(),
|
||||
'currency' => $transaction->amount->currency,
|
||||
);
|
||||
}
|
||||
|
||||
if ( $transaction->invoice->shipaddress )
|
||||
{
|
||||
/* PayPal requires shortcodes for states */
|
||||
$shippingState = $transaction->invoice->shipaddress->region;
|
||||
if ( isset( \IPS\nexus\Customer\Address::$stateCodes[ $transaction->invoice->shipaddress->country ] ) )
|
||||
{
|
||||
if ( !array_key_exists( $shippingState, \IPS\nexus\Customer\Address::$stateCodes[ $transaction->invoice->shipaddress->country ] ) )
|
||||
{
|
||||
$_shippingState = array_search( $transaction->invoice->shipaddress->region, \IPS\nexus\Customer\Address::$stateCodes[ $transaction->invoice->shipaddress->country ] );
|
||||
if ( $_shippingState !== FALSE )
|
||||
{
|
||||
$shippingState = $_shippingState;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$payPalTransactionData['item_list']['shipping_address'] = array(
|
||||
'recipient_name' => $transaction->invoice->member->cm_name,
|
||||
'line1' => $transaction->invoice->shipaddress->addressLines[0],
|
||||
'line2' => isset( $transaction->invoice->shipaddress->addressLines[1] ) ? $transaction->invoice->shipaddress->addressLines[1] : '',
|
||||
'city' => $transaction->invoice->shipaddress->city,
|
||||
'country_code' => $transaction->invoice->shipaddress->country,
|
||||
'postal_code' => $transaction->invoice->shipaddress->postalCode,
|
||||
'state' => $shippingState,
|
||||
);
|
||||
if ( $transaction->member->cm_phone )
|
||||
{
|
||||
$payPalTransactionData['item_list']['shipping_address']['phone'] = preg_replace( '/[^\+0-9\s]/', '', $transaction->member->cm_phone );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$payPalTransactionData['description'] = sprintf( $transaction->member->language()->get('partial_payment_desc'), $transaction->invoice->id );
|
||||
}
|
||||
|
||||
/* Send the request */
|
||||
$response = $this->api( 'payments/payment', array(
|
||||
'intent' => 'authorize',
|
||||
'payer' => $payer,
|
||||
'transactions' => array( $payPalTransactionData ),
|
||||
'redirect_urls' => array(
|
||||
'return_url' => \IPS\Settings::i()->base_url . 'applications/nexus/interface/gateways/paypal.php?nexusTransactionId=' . $transaction->id,
|
||||
'cancel_url' => (string) $transaction->invoice->checkoutUrl(),
|
||||
)
|
||||
) );
|
||||
|
||||
$transaction->gw_id = $response['id'];
|
||||
|
||||
/* If this is a PayPal payment (opposed to credit card) we need to get approval from the user */
|
||||
if ( $settings['type'] == 'paypal' )
|
||||
{
|
||||
$transaction->save();
|
||||
foreach ( $response['links'] as $link )
|
||||
{
|
||||
if ( $link['rel'] === 'approval_url' )
|
||||
{
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::external( $link['href'] ) );
|
||||
}
|
||||
}
|
||||
throw new \RuntimeException;
|
||||
}
|
||||
/* Otherwise, return how long we've got */
|
||||
else
|
||||
{
|
||||
/* Save the card first if the user wants */
|
||||
if ( $card->save )
|
||||
{
|
||||
try
|
||||
{
|
||||
$storedCard = new \IPS\nexus\Gateway\PayPal\CreditCard;
|
||||
$storedCard->member = $transaction->member;
|
||||
$storedCard->method = $this;
|
||||
$storedCard->card = $card;
|
||||
$storedCard->save();
|
||||
}
|
||||
catch ( \Exception $e ) { }
|
||||
}
|
||||
|
||||
/* And return */
|
||||
return \IPS\DateTime::ts( strtotime( $response['transactions'][0]['related_resources'][0]['authorization']['valid_until'] ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Void
|
||||
*
|
||||
* @param \IPS\nexus\Transaction $transaction Transaction
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function void( \IPS\nexus\Transaction $transaction )
|
||||
{
|
||||
$payment = $this->api( "payments/payment/{$transaction->gw_id}", NULL, 'get' );
|
||||
foreach ( $payment['transactions'][0]['related_resources'] as $rr )
|
||||
{
|
||||
if ( isset( $rr['authorization'] ) )
|
||||
{
|
||||
return $this->api( "payments/authorization/{$rr['authorization']['id']}/void" );
|
||||
}
|
||||
}
|
||||
|
||||
throw new \RuntimeException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Capture
|
||||
*
|
||||
* @param \IPS\nexus\Transaction $transaction Transaction
|
||||
* @return void
|
||||
* @throws \LogicException
|
||||
*/
|
||||
public function capture( \IPS\nexus\Transaction $transaction )
|
||||
{
|
||||
$payment = $this->api( "payments/payment/{$transaction->gw_id}", NULL, 'get' );
|
||||
foreach ( $payment['transactions'][0]['related_resources'] as $rr )
|
||||
{
|
||||
if ( isset( $rr['authorization'] ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
$response = $this->api( "payments/authorization/{$rr['authorization']['id']}/capture", array(
|
||||
'amount' => array(
|
||||
'currency' => $transaction->amount->currency,
|
||||
'total' => $transaction->amount->amountAsString(),
|
||||
),
|
||||
'is_final_capture' => TRUE,
|
||||
) );
|
||||
}
|
||||
catch ( \IPS\nexus\Gateway\PayPal\Exception $e )
|
||||
{
|
||||
if ( $e->getName() == 'AUTHORIZATION_ALREADY_COMPLETED' )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
throw new \RuntimeException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refund
|
||||
*
|
||||
* @param \IPS\nexus\Transaction $transaction Transaction to be refunded
|
||||
* @param float|NULL $amount Amount to refund (NULL for full amount - always in same currency as transaction)
|
||||
* @return mixed Gateway reference ID for refund, if applicable
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function refund( \IPS\nexus\Transaction $transaction, $amount = NULL )
|
||||
{
|
||||
$payment = $this->api( "payments/payment/{$transaction->gw_id}", NULL, 'get' );
|
||||
foreach ( $payment['transactions'][0]['related_resources'] as $rr )
|
||||
{
|
||||
if ( isset( $rr['capture'] ) )
|
||||
{
|
||||
$amount = $amount ? new \IPS\nexus\Money( $amount, $transaction->currency ) : $transaction->amount;
|
||||
$response = $this->api( "payments/capture/{$rr['capture']['id']}/refund", array( 'amount' => array(
|
||||
'currency' => $amount->currency,
|
||||
'total' => $amount->amountAsString()
|
||||
) ) );
|
||||
return $response['id'];
|
||||
}
|
||||
}
|
||||
|
||||
throw new \RuntimeException;
|
||||
}
|
||||
|
||||
/* !ACP Configuration */
|
||||
|
||||
/**
|
||||
* Settings
|
||||
*
|
||||
* @param \IPS\Helpers\Form $form The form
|
||||
* @return void
|
||||
*/
|
||||
public function settings( &$form )
|
||||
{
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'paypal_type', $settings['type'], TRUE, array( 'options' => array( 'paypal' => 'paypal_type_paypal', 'card' => 'paypal_type_card' ), 'toggles' => array( 'card' => array( 'paypal_vault' ) ) ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'paypal_vault', $this->id ? $settings['vault'] : TRUE, FALSE, array(), NULL, NULL, NULL, 'paypal_vault' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'paypal_client_id', $settings['client_id'], TRUE ) );
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'paypal_secret', $settings['secret'], TRUE ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Settings
|
||||
*
|
||||
* @param array $settings Settings
|
||||
* @return array
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function testSettings( $settings )
|
||||
{
|
||||
try
|
||||
{
|
||||
$this->getNewToken( $settings );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
throw new \InvalidArgumentException( $e->getMessage(), $e->getCode() );
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/* !Utility Methods */
|
||||
|
||||
/**
|
||||
* Send API Request
|
||||
*
|
||||
* @param string $uri The API to request (e.g. "payments/payment")
|
||||
* @param array $data The data to send
|
||||
* @param string $method Method (get/post)
|
||||
* @return array
|
||||
* @throws \IPS\Http|Exception
|
||||
* @throws \IPS\nexus\Gateway\PayPal\Exception
|
||||
*/
|
||||
public function api( $uri, $data=NULL, $method='post' )
|
||||
{
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
if ( !isset( $settings['token'] ) or $settings['token_expire'] < time() )
|
||||
{
|
||||
$token = $this->getNewToken();
|
||||
$settings['token'] = $token['access_token'];
|
||||
$settings['token_expire'] = ( time() + $token['expires_in'] );
|
||||
$this->settings = json_encode( $settings );
|
||||
$this->save();
|
||||
}
|
||||
|
||||
$response = \IPS\Http\Url::external( 'https://' . ( \IPS\NEXUS_TEST_GATEWAYS ? 'api.sandbox.paypal.com' : 'api.paypal.com' ) . '/v1/' . $uri )
|
||||
->request( 30 )
|
||||
->setHeaders( array(
|
||||
'Content-Type' => 'application/json',
|
||||
'Authorization' => "Bearer {$settings['token']}",
|
||||
) )
|
||||
->$method( $data === NULL ? NULL : json_encode( $data ) );
|
||||
|
||||
if ( mb_substr( $response->httpResponseCode, 0, 1 ) !== '2' )
|
||||
{
|
||||
throw new \IPS\nexus\Gateway\PayPal\Exception( $response );
|
||||
}
|
||||
|
||||
return $method === 'delete' ? NULL : $response->decodeJson();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Token
|
||||
*
|
||||
* @param array|NULL $settings Settings (NULL for saved setting)
|
||||
* @return array
|
||||
* @throws \IPS\Http|Exception
|
||||
* @throws \UnexpectedValueException
|
||||
*/
|
||||
protected function getNewToken( $settings = NULL )
|
||||
{
|
||||
$settings = $settings ?: json_decode( $this->settings, TRUE );
|
||||
|
||||
$response = \IPS\Http\Url::external( 'https://' . ( \IPS\NEXUS_TEST_GATEWAYS ? 'api.sandbox.paypal.com' : 'api.paypal.com' ) . '/v1/oauth2/token' )
|
||||
->request()
|
||||
->setHeaders( array(
|
||||
'Accept' => 'application/json',
|
||||
'Accept-Language' => 'en_US',
|
||||
) )
|
||||
->login( $settings['client_id'], $settings['secret'] )
|
||||
->post( array( 'grant_type' => 'client_credentials' ) )
|
||||
->decodeJson();
|
||||
|
||||
if ( !isset( $response['access_token'] ) )
|
||||
{
|
||||
throw new \UnexpectedValueException( isset( $response['error_description'] ) ? $response['error_description'] : $response );
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief PayPal Pay Out Gateway
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @subpackage Nexus
|
||||
* @since 7 Apr 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\nexus\Gateway\PayPal;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* PayPal Pay Out Gateway
|
||||
*/
|
||||
class _Payout extends \IPS\nexus\Payout
|
||||
{
|
||||
/**
|
||||
* ACP Settings
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function settings()
|
||||
{
|
||||
$settings = json_decode( \IPS\Settings::i()->nexus_payout, TRUE );
|
||||
|
||||
$return = array();
|
||||
$return[] = new \IPS\Helpers\Form\Text( 'paypal_api_username', isset( $settings['PayPal'] ) ? $settings['PayPal']['api_username'] : '' );
|
||||
$return[] = new \IPS\Helpers\Form\Text( 'paypal_api_password', isset( $settings['PayPal'] ) ? $settings['PayPal']['api_password'] : '' );
|
||||
$return[] = new \IPS\Helpers\Form\Text( 'paypal_api_signature', isset( $settings['PayPal'] ) ? $settings['PayPal']['api_signature'] : '' );
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Payout Form
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function form()
|
||||
{
|
||||
$return = array();
|
||||
$return[] = new \IPS\Helpers\Form\Email( 'paypal_email', \IPS\Member::loggedIn()->email, NULL, array(), function( $val )
|
||||
{
|
||||
if ( !$val and \IPS\Request::i()->withdraw_method === 'PayPal' )
|
||||
{
|
||||
throw new \DomainException('form_required');
|
||||
}
|
||||
} );
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get data and validate
|
||||
*
|
||||
* @param array $values Values from form
|
||||
* @return mixed
|
||||
* @throws \DomainException
|
||||
*/
|
||||
public function getData( array $values )
|
||||
{
|
||||
return $values['paypal_email'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Process
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function process()
|
||||
{
|
||||
$settings = json_decode( \IPS\Settings::i()->nexus_payout, TRUE );
|
||||
|
||||
$response = \IPS\Http\Url::external( \IPS\NEXUS_TEST_GATEWAYS ? 'https://api-3t.sandbox.paypal.com/nvp' : 'https://api-3t.paypal.com/nvp' )->request()->post( array(
|
||||
'METHOD' => 'MassPay',
|
||||
'VERSION' => '90',
|
||||
'USER' => $settings['PayPal']['api_username'],
|
||||
'PWD' => $settings['PayPal']['api_password'],
|
||||
'SIGNATURE' => $settings['PayPal']['api_signature'],
|
||||
'RECEIVERTYPE' => 'EmailAddress',
|
||||
'CURRENCYCODE' => $this->amount->currency,
|
||||
'L_EMAIL0' => $this->data,
|
||||
'L_AMT0' => $this->amount->amountAsString()
|
||||
) )->decodeQueryString();
|
||||
|
||||
if ( $response['ACK'] != 'Success' )
|
||||
{
|
||||
throw new \DomainException( $response['L_LONGMESSAGE0'] );
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->status = static::STATUS_COMPLETE;
|
||||
$this->completed = new \IPS\DateTime;
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mass Process
|
||||
*
|
||||
* @param \IPS\Patterns\ActiveRecordIterator
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function massProcess( \IPS\Patterns\ActiveRecordIterator $payouts )
|
||||
{
|
||||
$settings = json_decode( \IPS\Settings::i()->nexus_payout, TRUE );
|
||||
|
||||
$byCurrency = array();
|
||||
foreach ( $payouts as $payout )
|
||||
{
|
||||
$byCurrency[ $payout->amount->currency ][] = array( 'email' => $payout->data, 'amount' => $payout->amount->amountAsString() );
|
||||
}
|
||||
|
||||
$batches = array();
|
||||
foreach ( $byCurrency as $currency => $recipients )
|
||||
{
|
||||
$baseData = array(
|
||||
'METHOD' => 'MassPay',
|
||||
'VERSION' => '90',
|
||||
'USER' => $settings['PayPal']['api_username'],
|
||||
'PWD' => $settings['PayPal']['api_password'],
|
||||
'SIGNATURE' => $settings['PayPal']['api_signature'],
|
||||
'RECEIVERTYPE' => 'EmailAddress',
|
||||
'CURRENCYCODE' => $currency,
|
||||
);
|
||||
|
||||
$data = $baseData;
|
||||
foreach ( $recipients as $i => $recipient )
|
||||
{
|
||||
$data["L_EMAIL{$i}"] = $recipient['email'];
|
||||
$data["L_AMT{$i}"] = $recipient['amount'];
|
||||
|
||||
if ( $i >= 249 )
|
||||
{
|
||||
$batches[] = $data;
|
||||
$data = $baseData;
|
||||
}
|
||||
}
|
||||
|
||||
$batches[] = $data;
|
||||
}
|
||||
|
||||
$error = NULL;
|
||||
foreach ( $batches as $batchData )
|
||||
{
|
||||
$response = \IPS\Http\Url::external( \IPS\NEXUS_TEST_GATEWAYS ? 'https://api-3t.sandbox.paypal.com/nvp' : 'https://api-3t.paypal.com/nvp' )->request()->post( $batchData )->decodeQueryString();
|
||||
|
||||
if ( $response['ACK'] != 'Success' )
|
||||
{
|
||||
$error = $response['L_LONGMESSAGE0'];
|
||||
}
|
||||
}
|
||||
|
||||
if ( $error )
|
||||
{
|
||||
throw new \DomainException( $error );
|
||||
}
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,391 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief SagePay Gateway
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @subpackage Nexus
|
||||
* @since 17 Mar 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\nexus\Gateway;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* SagePay Gateway
|
||||
*/
|
||||
class _SagePay extends \IPS\nexus\Gateway
|
||||
{
|
||||
/* !Features (Each gateway will override) */
|
||||
|
||||
const SUPPORTS_REFUNDS = TRUE;
|
||||
const SUPPORTS_PARTIAL_REFUNDS = TRUE;
|
||||
|
||||
/**
|
||||
* Can store cards?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canStoreCards()
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin can manually charge using this gateway?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canAdminCharge()
|
||||
{
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
return ( $settings['method'] === 'direct' );
|
||||
}
|
||||
|
||||
/* !Payment Gateway */
|
||||
|
||||
/**
|
||||
* Payment Screen Fields
|
||||
*
|
||||
* @param \IPS\nexus\Invoice $invoice Invoice
|
||||
* @param \IPS\nexus\Money $amount The amount to pay now
|
||||
* @return array
|
||||
*/
|
||||
public function paymentScreen( \IPS\nexus\Invoice $invoice, \IPS\nexus\Money $amount )
|
||||
{
|
||||
$return = array();
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
|
||||
if ( $settings['method'] === 'direct' )
|
||||
{
|
||||
$options = array();
|
||||
$options['types'] = array( \IPS\nexus\CreditCard::TYPE_VISA, \IPS\nexus\CreditCard::TYPE_MASTERCARD, \IPS\nexus\CreditCard::TYPE_AMERICAN_EXPRESS, \IPS\nexus\CreditCard::TYPE_DINERS_CLUB, \IPS\nexus\CreditCard::TYPE_DISCOVER, \IPS\nexus\CreditCard::TYPE_JCB );
|
||||
$return['card'] = new \IPS\nexus\Form\CreditCard( $this->id . '_card', NULL, FALSE, $options );
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorize
|
||||
*
|
||||
* @param \IPS\nexus\Transaction $transaction Transaction
|
||||
* @param array|\IPS\nexus\Customer\CreditCard $values Values from form OR a stored card object if this gateway supports them
|
||||
* @param \IPS\nexus\Fraud\MaxMind\Request|NULL $maxMind *If* MaxMind is enabled, the request object will be passed here so gateway can additional data before request is made
|
||||
* @return \IPS\DateTime|NULL Auth is valid until or NULL to indicate auth is good forever
|
||||
* @throws \LogicException Message will be displayed to user
|
||||
*/
|
||||
public function auth( \IPS\nexus\Transaction $transaction, $values, \IPS\nexus\Fraud\MaxMind\Request $maxMind = NULL )
|
||||
{
|
||||
/* Init */
|
||||
$transaction->save();
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
|
||||
/* Build basic data */
|
||||
$shipAddress = $transaction->invoice->shipaddress ?: $transaction->invoice->billaddress;
|
||||
$data = array(
|
||||
'TxType' => 'PAYMENT',
|
||||
'VendorTxCode' => $transaction->id,
|
||||
'Amount' => $transaction->amount->amount,
|
||||
'Currency' => $transaction->amount->currency,
|
||||
'Description' => mb_substr( $transaction->invoice->title, 0, 100 ),
|
||||
'BillingSurname' => $transaction->member->cm_last_name,
|
||||
'BillingFirstnames' => $transaction->member->cm_first_name,
|
||||
'BillingAddress1' => $transaction->invoice->billaddress->addressLines[0],
|
||||
'BillingAddress2' => isset( $transaction->invoice->billaddress->addressLines[1] ) ? $transaction->invoice->billaddress->addressLines[0] : NULL,
|
||||
'BillingCity' => $transaction->invoice->billaddress->city,
|
||||
'BillingPostCode' => $transaction->invoice->billaddress->postalCode,
|
||||
'BillingCountry' => $transaction->invoice->billaddress->country,
|
||||
'BillingState' => ( $transaction->invoice->billaddress->country === 'US' ) ? $transaction->invoice->billaddress->region : NULL,
|
||||
'BillingPhone' => $transaction->member->cm_phone,
|
||||
'DeliverySurname' => $transaction->member->cm_last_name,
|
||||
'DeliveryFirstnames'=> $transaction->member->cm_first_name,
|
||||
'DeliveryAddress1' => $shipAddress->addressLines[0],
|
||||
'DeliveryAddress2' => isset( $shipAddress->addressLines[1] ) ? $shipAddress->addressLines[0] : NULL,
|
||||
'DeliveryCity' => $shipAddress->city,
|
||||
'DeliveryPostCode' => $shipAddress->postalCode,
|
||||
'DeliveryCountry' => $shipAddress->country,
|
||||
'DeliveryState' => ( $shipAddress->country === 'US' ) ? $shipAddress->region : NULL,
|
||||
'DeliveryPhone' => $transaction->member->cm_phone,
|
||||
'CustomerEMail' => $transaction->member->email,
|
||||
);
|
||||
|
||||
/* Add method-specific data */
|
||||
if ( $settings['method'] === 'direct' )
|
||||
{
|
||||
$data['ClientIPAddress'] = \IPS\Request::i()->ipAddress();
|
||||
|
||||
$card = $values[ $this->id . '_card' ];
|
||||
$data['CardHolder'] = $transaction->member->cm_first_name . ' ' . $transaction->member->cm_last_name;
|
||||
$data['CardNumber'] = $card->number;
|
||||
$data['ExpiryDate'] = $card->expMonth . mb_substr( $card->expYear, 2 );
|
||||
$data['CV2'] = $card->ccv;
|
||||
$data['CardType'] = static::cardType( $card );
|
||||
}
|
||||
else
|
||||
{
|
||||
$data['NotificationURL'] = \IPS\Settings::i()->base_url . 'applications/nexus/interface/gateways/sagepay.php';
|
||||
}
|
||||
|
||||
/* Add Basket XML */
|
||||
if ( $transaction->amount->amount == $transaction->invoice->total->amount )
|
||||
{
|
||||
$summary = $transaction->invoice->summary();
|
||||
|
||||
$basketXml = \IPS\Xml\SimpleXml::create( 'basket' );
|
||||
$discounts = array();
|
||||
|
||||
foreach ( $summary['items'] as $item )
|
||||
{
|
||||
if ( $item->price->amount < 0 )
|
||||
{
|
||||
$discounts[] = array(
|
||||
'fixed' => abs( $item->price->amount * $item->quantity )
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$basketXml->addChild( 'item', array(
|
||||
'description' => $item->name,
|
||||
'quantity' => $item->quantity,
|
||||
'unitNetAmount' => $item->price->amount,
|
||||
'unitTaxAmount' => $item->price->amount * $item->taxRate(),
|
||||
'unitGrossAmount' => $item->price->amount + ( $item->price->amount * $item->taxRate() ),
|
||||
'totalGrossAmount' => $item->grossLinePrice()->amount,
|
||||
) );
|
||||
}
|
||||
}
|
||||
|
||||
$shippingNet = 0;
|
||||
$shippingTax = 0;
|
||||
foreach ( $summary['shipping'] as $shipping )
|
||||
{
|
||||
$shippingNet += $shipping->price->amount;
|
||||
$shippingTax += ( $shipping->price->amount * $shipping->taxRate() );
|
||||
}
|
||||
if ( $shippingNet )
|
||||
{
|
||||
$basketXml->addChild( 'deliveryNetAmount', $shippingNet );
|
||||
$basketXml->addChild( 'deliveryTaxAmount', $shippingTax );
|
||||
$basketXml->addChild( 'deliveryGrossAmount', $shippingNet + $shippingTax );
|
||||
}
|
||||
|
||||
if ( count( $discounts ) )
|
||||
{
|
||||
$basketXml->addChild( 'discounts', $discounts );
|
||||
}
|
||||
|
||||
$data['BasketXML'] = trim( str_replace( '<?xml version="1.0" encoding="UTF-8"?>', '', $basketXml->asXml() ) );
|
||||
}
|
||||
|
||||
/* Send */
|
||||
try
|
||||
{
|
||||
if ( $settings['method'] === 'direct' )
|
||||
{
|
||||
$response = $this->api( 'vspdirect-register.vsp', $data );
|
||||
|
||||
if ( isset( $data['CreateToken'] ) and isset( $response['Token'] ) and $response['Token'] )
|
||||
{
|
||||
echo 'xx<pre>';
|
||||
print_r( $response );
|
||||
exit;
|
||||
}
|
||||
|
||||
echo 'zz<pre>';
|
||||
print_r( $response );
|
||||
exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
$response = $this->api( 'vspserver-register.vsp', $data );
|
||||
}
|
||||
}
|
||||
catch ( \DomainException $e )
|
||||
{
|
||||
echo '<pre>';
|
||||
print_r( $e );
|
||||
exit;
|
||||
throw new \DomainException( $transaction->member->language()->addToStack('gateway_err') );
|
||||
}
|
||||
|
||||
/* Save details */
|
||||
$transaction->gw_id = $response['VPSTxId'];
|
||||
$extra = $transaction->extra;
|
||||
$extra['sagepaySecurityKey'] = $response['SecurityKey'];
|
||||
$transaction->extra = $extra;
|
||||
$transaction->save();
|
||||
|
||||
/* Continue */
|
||||
if ( $settings['method'] === 'direct' )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->redirect( $response['NextURL'] . '=' . $response['VPSTxId'] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refund
|
||||
*
|
||||
* @param \IPS\nexus\Transaction $transaction Transaction to be refunded
|
||||
* @param float|NULL $amount Amount to refund (NULL for full amount - always in same currency as transaction)
|
||||
* @return mixed Gateway reference ID for refund, if applicable
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function refund( \IPS\nexus\Transaction $transaction, $amount = NULL )
|
||||
{
|
||||
$refundId = $transaction->id . 'R' . rand( 1, 999 );
|
||||
|
||||
$extra = $transaction->extra;
|
||||
$response = $this->api( 'refund.vsp', array(
|
||||
'TxType' => 'REFUND',
|
||||
'VendorTxCode' => $refundId,
|
||||
'Amount' => $amount ?: $transaction->amount->amount,
|
||||
'Currency' => $transaction->currency,
|
||||
'Description' => $transaction->invoice->title,
|
||||
'RelatedVPSTxId' => $transaction->gw_id,
|
||||
'RelatedVendorTxCode' => $transaction->id,
|
||||
'RelatedSecurityKey' => $extra['sagepaySecurityKey'],
|
||||
'RelatedTxAuthNo' => $extra['sagepayAuth'],
|
||||
|
||||
) );
|
||||
|
||||
return $response['VPSTxId'];
|
||||
}
|
||||
|
||||
/* !ACP Configuration */
|
||||
|
||||
/**
|
||||
* Settings
|
||||
*
|
||||
* @param \IPS\Helpers\Form $form The form
|
||||
* @return void
|
||||
*/
|
||||
public function settings( &$form )
|
||||
{
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'sagepay_vendor', $settings ? $settings['vendor'] : '', TRUE ) );
|
||||
\IPS\Member::loggedIn()->language()->words['sagepay_vendor_desc'] = sprintf( \IPS\Member::loggedIn()->language()->get( 'sagepay_vendor_desc' ), gethostbyname( gethostname() ) );
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'sagepay_method', $settings ? $settings['method'] : 'server', TRUE, array( 'options' => array( 'server' => 'sagepay_method_server', 'direct' => 'sagepay_method_direct' ) ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Settings
|
||||
*
|
||||
* @param array $settings Settings
|
||||
* @return array
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function testSettings( $settings )
|
||||
{
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/* !Utility Methods */
|
||||
|
||||
/**
|
||||
* Get card type
|
||||
*
|
||||
* @param \IPS\nexus\CreditCard $card The card
|
||||
* @return string
|
||||
*/
|
||||
public static function cardType( \IPS\nexus\CreditCard $card )
|
||||
{
|
||||
switch ( $card->type )
|
||||
{
|
||||
case \IPS\nexus\CreditCard::TYPE_VISA:
|
||||
if ( preg_match( '/^(400626|40854749|40940002|41228586|41373337|41378788|418760|41917679|419772|420672|42159294|422793|423769|431072|444001|44400508|44620011|44621354|44625772|44627483|446286|446294|450875|45397|454313|45443235|454742|45672545|46583079|46590150|47511059|47571059|47622069|47634089|48440910|484427|49096079|49218182)/', $card->number ) )
|
||||
{
|
||||
return 'DELTA';
|
||||
}
|
||||
elseif ( preg_match( '/^(400(115|121|83[7-9])|401773|4026|405670|410654|41292[1-3]|4140(49|99)|415045|416(039|451|896)|417(7|935)|4197(4[0-1]|7[3-6])|420796|429158|431262|4329(19|37)|433445|435225|44(0(626|753)|615[578]|8360)|4508|453904|479(056|731)|4844(0[6-9]|1[013489]|2[0-68-9]|[3-5][0-9])|491(3|7([3-5][0-9])|859)|4935|494114)
|
||||
/', $card->number ) )
|
||||
{
|
||||
return 'UKE';
|
||||
}
|
||||
else
|
||||
{
|
||||
return 'VISA';
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case \IPS\nexus\CreditCard::TYPE_MASTERCARD:
|
||||
if ( preg_match( '/^(?:5[0678]\d\d|6304|6390|67\d\d)\d{8,15}$/', $card->number ) )
|
||||
{
|
||||
return 'MAESTRO';
|
||||
}
|
||||
elseif ( in_array( mb_substr( $card->number, 0, 6 ), array( '516730', '516979', '517000', '517049', '535110', '535309', '535420', '535819', '537210', '537609', '557347', '557496', '557498', '557547' ) ) )
|
||||
{
|
||||
return 'MCDEBIT';
|
||||
}
|
||||
else
|
||||
{
|
||||
return 'MC';
|
||||
}
|
||||
break;
|
||||
|
||||
case \IPS\nexus\CreditCard::TYPE_AMERICAN_EXPRESS:
|
||||
return 'AMEX';
|
||||
break;
|
||||
|
||||
case \IPS\nexus\CreditCard::TYPE_DINERS_CLUB:
|
||||
case \IPS\nexus\CreditCard::TYPE_DISCOVER:
|
||||
return 'DC';
|
||||
break;
|
||||
|
||||
case \IPS\nexus\CreditCard::TYPE_JCB:
|
||||
return 'JCB';
|
||||
break;
|
||||
}
|
||||
|
||||
throw new \UnexpectedValueException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send API Request
|
||||
*
|
||||
* @param string $uri The API to request (e.g. "payments/payment")
|
||||
* @param array $data The data to send
|
||||
* @return array
|
||||
* @throws \IPS\Http|Exception
|
||||
*/
|
||||
public function api( $uri, $data=NULL )
|
||||
{
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
$data = array_merge( array(
|
||||
'VPSProtocol' => '3.00',
|
||||
'Vendor' => $settings['vendor'],
|
||||
), $data );
|
||||
|
||||
$_response = \IPS\Http\Url::external( \IPS\NEXUS_TEST_GATEWAYS ? 'https://test.sagepay.com/gateway/service/' . $uri : 'https://live.sagepay.com/gateway/service/' . $uri )->request()->post( $data );
|
||||
$response = array();
|
||||
foreach ( explode( "\n", $_response ) as $line )
|
||||
{
|
||||
$line = trim( $line );
|
||||
if ( $line )
|
||||
{
|
||||
$ex = explode( '=', $line );
|
||||
$response[ $ex[0] ] = $ex[1];
|
||||
}
|
||||
}
|
||||
|
||||
if ( !isset( $response['Status'] ) or $response['Status'] !== 'OK' )
|
||||
{
|
||||
throw new \DomainException( $response['StatusDetail'] );
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief PayPal Stored Card
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @subpackage Nexus
|
||||
* @since 10 Feb 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\nexus\Gateway\Stripe;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stripe Stored Card
|
||||
*/
|
||||
class _CreditCard extends \IPS\nexus\Customer\CreditCard
|
||||
{
|
||||
/**
|
||||
* @brief Card
|
||||
*/
|
||||
protected $_card;
|
||||
|
||||
/**
|
||||
* Get card
|
||||
*
|
||||
* @return \IPS\nexus\CreditCard
|
||||
*/
|
||||
public function get_card()
|
||||
{
|
||||
if ( !$this->_card )
|
||||
{
|
||||
$profiles = $this->member->cm_profiles;
|
||||
if ( !isset( $profiles[ $this->method->id ] ) )
|
||||
{
|
||||
throw new \UnexpectedValueException;
|
||||
}
|
||||
|
||||
$response = $this->method->api( "customers/{$profiles[ $this->method->id ]}/cards/{$this->data}", NULL, 'get' );
|
||||
|
||||
$this->_card = new \IPS\nexus\CreditCard;
|
||||
$this->_card->lastFour = $response['last4'];
|
||||
switch ( $response['type'] )
|
||||
{
|
||||
case 'Visa':
|
||||
$this->_card->type = \IPS\nexus\CreditCard::TYPE_VISA;
|
||||
break;
|
||||
case 'American Express':
|
||||
$this->_card->type = \IPS\nexus\CreditCard::TYPE_AMERICAN_EXPRESS;
|
||||
break;
|
||||
case 'MasterCard':
|
||||
$this->_card->type = \IPS\nexus\CreditCard::TYPE_MASTERCARD;
|
||||
break;
|
||||
case 'Discover':
|
||||
$this->_card->type = \IPS\nexus\CreditCard::TYPE_DISCOVER;
|
||||
break;
|
||||
case 'JCB':
|
||||
$this->_card->type = \IPS\nexus\CreditCard::TYPE_JCB;
|
||||
break;
|
||||
case 'Diners Club':
|
||||
$this->_card->type = \IPS\nexus\CreditCard::TYPE_DINERS_CLUB;
|
||||
break;
|
||||
}
|
||||
$this->_card->expMonth = $response['exp_month'];
|
||||
$this->_card->expYear = $response['exp_year'];
|
||||
}
|
||||
return $this->_card;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set card
|
||||
*
|
||||
* @param \IPS\nexus\CreditCard $card The card
|
||||
* @return void
|
||||
*/
|
||||
public function set_card( \IPS\nexus\CreditCard $card )
|
||||
{
|
||||
$profiles = $this->member->cm_profiles;
|
||||
|
||||
if ( !isset( $profiles[ $this->method->id ] ) )
|
||||
{
|
||||
$response = $this->method->api( 'customers', array( 'metadata' => array( 'id' => $this->member->member_id ) ) );
|
||||
$profiles[ $this->method->id ] = $response['id'];
|
||||
$this->member->cm_profiles = $profiles;
|
||||
$this->member->save();
|
||||
}
|
||||
|
||||
$response = $this->method->api( "customers/{$profiles[ $this->method->id ]}/cards", array(
|
||||
'card' => $card->token
|
||||
) );
|
||||
$this->data = $response['id'];
|
||||
|
||||
$this->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
$profiles = $this->member->cm_profiles;
|
||||
try
|
||||
{
|
||||
$this->method->api( "customers/{$profiles[ $this->method->id ]}/cards/{$this->data}", NULL, 'delete' );
|
||||
}
|
||||
catch ( \IPS\nexus\Gateway\Stripe\Exception $e ) { }
|
||||
return parent::delete();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Stripe Exception
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @subpackage Nexus
|
||||
* @since 10 Mar 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\nexus\Gateway\Stripe;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stripe Exception
|
||||
*/
|
||||
class _Exception extends \DomainException
|
||||
{
|
||||
/**
|
||||
* @brief Details
|
||||
*/
|
||||
public $details;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $error Error details
|
||||
* @return void
|
||||
*/
|
||||
public function __construct( array $response )
|
||||
{
|
||||
$this->details = $response;
|
||||
if ( $response['type'] == 'card_error' )
|
||||
{
|
||||
parent::__construct( $response['message'] );
|
||||
}
|
||||
else
|
||||
{
|
||||
parent::__construct( \IPS\Member::loggedIn()->language()->get( 'gateway_err' ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Stripe Pay Out Gateway
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @subpackage Nexus
|
||||
* @since 7 Apr 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\nexus\Gateway\Stripe;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stripe Pay Out Gateway
|
||||
*/
|
||||
class _Payout extends \IPS\nexus\Payout
|
||||
{
|
||||
/**
|
||||
* ACP Settings
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function settings()
|
||||
{
|
||||
$settings = json_decode( \IPS\Settings::i()->nexus_payout, TRUE );
|
||||
if ( !isset( $settings['Stripe'] ) or !count( $settings['Stripe'] ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
$method = \IPS\Db::i()->select( '*', 'nexus_paymethods', array( 'm_gateway=? AND m_active=1', 'Stripe' ) )->first();
|
||||
$_settings = json_decode( $method['m_settings'], TRUE );
|
||||
$settings['Stripe']['secret_key'] = $_settings['secret_key'];
|
||||
}
|
||||
catch ( \UnderflowException $e ) { }
|
||||
}
|
||||
|
||||
return array( new \IPS\Helpers\Form\Text( 'stripe_secret_key', ( isset( $settings['Stripe'] ) and isset( $settings['Stripe']['secret_key'] ) ) ? $settings['Stripe']['secret_key'] : NULL ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Payout Form
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function form()
|
||||
{
|
||||
$return = array();
|
||||
|
||||
/* Get any details we've used before */
|
||||
$previous = \IPS\Db::i()->select( 'po_data', 'nexus_payouts', array( 'po_member=? AND po_gateway=?', \IPS\Member::loggedIn()->member_id, 'Stripe' ) );
|
||||
if ( count( $previous ) )
|
||||
{
|
||||
$options = array();
|
||||
foreach ( $previous as $id )
|
||||
{
|
||||
$recipient = static::api( "recipients/{$id}", NULL, 'get' );
|
||||
$options[ $id ] = "{$recipient['active_account']['bank_name']} - XXXX{$recipient['active_account']['last4']}";
|
||||
}
|
||||
$options[0] = 'other';
|
||||
$return[] = new \IPS\Helpers\Form\Radio( 'stripe_recipient', NULL, NULL, array( 'options' => $options, 'toggles' => array( 0 => array( 'stripe_country', 'stripe_routing_number', 'stripe_account_number', 'stripe_account_type' ) ) ) );
|
||||
}
|
||||
|
||||
/* Required Validation */
|
||||
$requiredValidation = function( $val )
|
||||
{
|
||||
if ( !$val and \IPS\Request::i()->withdraw_method === 'Stripe' and isset( \IPS\Request::i()->stripe_recipient ) and !\IPS\Request::i()->stripe_recipient )
|
||||
{
|
||||
throw new \DomainException('form_required');
|
||||
}
|
||||
};
|
||||
|
||||
/* Build form for new */
|
||||
return array_merge( $return, array(
|
||||
'country' => new \IPS\Helpers\Form\Select( 'stripe_country', 'US', NULL, array( 'options' => array_map( function( $val )
|
||||
{
|
||||
return 'country-' . $val;
|
||||
}, array_combine( \IPS\GeoLocation::$countries, \IPS\GeoLocation::$countries ) ) ), NULL, NULL, NULL, 'stripe_country' ),
|
||||
'routing_number' => new \IPS\Helpers\Form\Text( 'stripe_routing_number', NULL, NULL, array(), $requiredValidation, NULL, NULL, 'stripe_routing_number' ),
|
||||
'account_number' => new \IPS\Helpers\Form\Text( 'stripe_account_number', NULL, NULL, array(), $requiredValidation, NULL, NULL, 'stripe_account_number' ),
|
||||
'account_type' => new \IPS\Helpers\Form\Radio( 'stripe_account_type', 'individual', NULL, array(
|
||||
'options' => array(
|
||||
'individual' => 'stripe_account_type_individual',
|
||||
'corporation' => 'stripe_account_type_corporation'
|
||||
),
|
||||
'toggles' => array(
|
||||
'individual' => array( 'stripe_individual_name' ),
|
||||
'corporation' => array( 'stripe_corporation_name' )
|
||||
)
|
||||
), NULL, NULL, NULL, 'stripe_account_type' ),
|
||||
'individual_name' => new \IPS\Helpers\Form\Text( 'stripe_individual_name', \IPS\nexus\Customer::loggedIn()->cm_name, NULL, array(), function( $val )
|
||||
{
|
||||
if ( !$val and \IPS\Request::i()->withdraw_method === 'Stripe' and isset( \IPS\Request::i()->stripe_recipient ) and !\IPS\Request::i()->stripe_recipient and \IPS\Request::i()->stripe_account_type === 'individual' )
|
||||
{
|
||||
throw new \DomainException('form_required');
|
||||
}
|
||||
}, NULL, NULL, 'stripe_individual_name' ),
|
||||
'corporation_name' => new \IPS\Helpers\Form\Text( 'stripe_corporation_name', NULL, NULL, array(), function( $val )
|
||||
{
|
||||
if ( !$val and \IPS\Request::i()->withdraw_method === 'Stripe' and isset( \IPS\Request::i()->stripe_recipient ) and !\IPS\Request::i()->stripe_recipient and \IPS\Request::i()->stripe_account_type === 'corporation' )
|
||||
{
|
||||
throw new \DomainException('form_required');
|
||||
}
|
||||
}, NULL, NULL, 'stripe_corporation_name' ),
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get data and validate
|
||||
*
|
||||
* @param array $values Values from form
|
||||
* @return mixed
|
||||
* @throws \DomainException
|
||||
*/
|
||||
public function getData( array $values )
|
||||
{
|
||||
if ( isset( $values['stripe_recipient'] ) and $values['stripe_recipient'] )
|
||||
{
|
||||
return $values['stripe_recipient'];
|
||||
}
|
||||
|
||||
$recipient = static::api( 'recipients', array(
|
||||
'name' => $values['stripe_account_type'] === 'individual' ? $values['stripe_individual_name'] : $values['stripe_corporation_name'],
|
||||
'type' => $values['stripe_account_type'],
|
||||
'bank_account' => array(
|
||||
'country' => $values['stripe_country'],
|
||||
'routing_number' => $values['stripe_routing_number'],
|
||||
'account_number' => $values['stripe_account_number']
|
||||
),
|
||||
'metadata' => array(
|
||||
'id' => \IPS\Member::loggedIn()->member_id
|
||||
),
|
||||
) );
|
||||
|
||||
return $recipient['id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Process
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function process()
|
||||
{
|
||||
$response = static::api( 'transfers', array(
|
||||
'amount' => $this->amount->amount,
|
||||
'currency' => $this->amount->currency,
|
||||
'recipient' => $this->data
|
||||
) );
|
||||
|
||||
$this->status = static::STATUS_COMPLETE;
|
||||
$this->completed = new \IPS\DateTime;
|
||||
$this->gw_id = $response['id'];
|
||||
$this->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get recipient
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function recipient()
|
||||
{
|
||||
return static::api( "recipients/{$this->data}", NULL, 'get' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Send API Request
|
||||
*
|
||||
* @param string $uri The API to request (e.g. "charges")
|
||||
* @param array $data The data to send
|
||||
* @param string $method Method (get/post)
|
||||
* @return array
|
||||
* @throws \IPS\Http|Exception
|
||||
* @throws \IPS\nexus\Gateway\PayPal\Exception
|
||||
*/
|
||||
protected static function api( $uri, $data=NULL, $method='post' )
|
||||
{
|
||||
$settings = json_decode( \IPS\Settings::i()->nexus_payout, TRUE );
|
||||
|
||||
$response = \IPS\Http\Url::external( 'https://api.stripe.com/v1/' . $uri )
|
||||
->request()
|
||||
->setHeaders( array( 'Stripe-Version' => '2014-01-31' ) )
|
||||
->login( $settings['Stripe']['secret_key'], '' )
|
||||
->$method( $data )
|
||||
->decodeJson();
|
||||
|
||||
if ( isset( $response['error'] ) )
|
||||
{
|
||||
throw new \DomainException( $response['error']['message'] );
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,336 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Stripe Gateway
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @subpackage Nexus
|
||||
* @since 13 Mar 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\nexus\Gateway;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stripe Gateway
|
||||
*/
|
||||
class _Stripe extends \IPS\nexus\Gateway
|
||||
{
|
||||
/* !Features */
|
||||
|
||||
const SUPPORTS_REFUNDS = TRUE;
|
||||
const SUPPORTS_PARTIAL_REFUNDS = TRUE;
|
||||
|
||||
/**
|
||||
* Check the gateway can process this...
|
||||
*
|
||||
* @param $amount \IPS\nexus\Money The amount
|
||||
* @param $billingAddress \IPS\GeoLocation The billing address
|
||||
* @return bool
|
||||
* @see <a href="https://support.stripe.com/questions/which-currencies-does-stripe-support/">Which currencies does Stripe support?</a>
|
||||
*/
|
||||
public function checkValidity( \IPS\nexus\Money $amount, \IPS\GeoLocation $billingAddress )
|
||||
{
|
||||
if ( static::_amountAsCents( $amount ) < 50 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
switch ( $settings['country'] )
|
||||
{
|
||||
case 'CA':
|
||||
if ( !in_array( $amount->currency, array( 'CAD', 'USD' ) ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'AU':
|
||||
if( $amount->currency != 'AUD' )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if ( !in_array( $amount->currency, array( 'AED', 'AFN', 'ALL', 'AMD', 'ANG', 'AOA', 'ARS', 'AUD', 'AWG', 'AZN', 'BAM', 'BBD', 'BDT', 'BGN', 'BIF', 'BMD', 'BND', 'BOB', 'BRL', 'BSD', 'BWP', 'BZD', 'CAD', 'CDF', 'CHF', 'CLP', 'CNY', 'COP', 'CRC', 'CVE', 'CZK', 'DJF', 'DKK', 'DOP', 'DZD', 'EEK', 'EGP', 'ETB', 'EUR', 'FJD', 'FKP', 'GBP', 'GEL', 'GIP', 'GMD', 'GNF', 'GTQ', 'GYD', 'HKD', 'HNL', 'HRK', 'HTG', 'HUF', 'IDR', 'ILS', 'INR', 'ISK', 'JMD', 'JPY', 'KES', 'KGS', 'KHR', 'KMF', 'KRW', 'KYD', 'KZT', 'LAK', 'LBP', 'LKR', 'LRD', 'LSL', 'LTL', 'LVL', 'MAD', 'MDL', 'MGA', 'MKD', 'MNT', 'MOP', 'MRO', 'MUR', 'MVR', 'MWK', 'MXN', 'MYR', 'MZN', 'NAD', 'NGN', 'NIO', 'NOK', 'NPR', 'NZD', 'PAB', 'PEN', 'PGK', 'PHP', 'PKR', 'PLN', 'PYG', 'QAR', 'RON', 'RSD', 'RUB', 'RWF', 'SAR', 'SBD', 'SCR', 'SEK', 'SGD', 'SHP', 'SLL', 'SOS', 'SRD', 'STD', 'SVC', 'SZL', 'THB', 'TJS', 'TOP', 'TRY', 'TTD', 'TWD', 'TZS', 'UAH', 'UGX', 'USD', 'UYI', 'UZS', 'VEF', 'VND', 'VUV', 'WST', 'XAF', 'XCD', 'XOF', 'XPF', 'YER', 'ZAR', 'ZMW' ) ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return parent::checkValidity( $amount, $billingAddress );
|
||||
}
|
||||
|
||||
/**
|
||||
* Can store cards?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canStoreCards()
|
||||
{
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
return ( $settings['cards'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin can manually charge using this gateway?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canAdminCharge()
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* !Payment Gateway */
|
||||
|
||||
/**
|
||||
* Payment Screen Fields
|
||||
*
|
||||
* @param \IPS\nexus\Invoice $invoice Invoice
|
||||
* @param \IPS\nexus\Money $amount The amount to pay now
|
||||
* @return array
|
||||
*/
|
||||
public function paymentScreen( \IPS\nexus\Invoice $invoice, \IPS\nexus\Money $amount )
|
||||
{
|
||||
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'global_gateways.js', 'nexus', 'global' ) );
|
||||
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
|
||||
$supportedCards = array( \IPS\nexus\CreditCard::TYPE_VISA, \IPS\nexus\CreditCard::TYPE_MASTERCARD );
|
||||
if ( !in_array( $invoice->currency, array( 'AFN', 'AOA', 'ARS', 'AUD', 'BOB', 'BRL', 'CAD', 'CLP', 'COP', 'CRC', 'CVE', 'CZK', 'DJF', 'EEK', 'FKP', 'GNF', 'GTQ', 'HNL', 'INR', 'LAK', 'MUR', 'MXN', 'NIO', 'PAB', 'PEN', 'PYG', 'SHP', 'SRD', 'SVC', 'UYI', 'VEF', 'XOF', 'XPF' ) ) )
|
||||
{
|
||||
$supportedCards[] = \IPS\nexus\CreditCard::TYPE_AMERICAN_EXPRESS;
|
||||
}
|
||||
if ( $settings['country'] == 'US' )
|
||||
{
|
||||
$supportedCards[] = \IPS\nexus\CreditCard::TYPE_DISCOVER;
|
||||
$supportedCards[] = \IPS\nexus\CreditCard::TYPE_DINERS_CLUB;
|
||||
$supportedCards[] = \IPS\nexus\CreditCard::TYPE_JCB;
|
||||
}
|
||||
|
||||
return array( 'card' => new \IPS\nexus\Form\CreditCard( $this->id . '_card', NULL, FALSE, array(
|
||||
'types' => $supportedCards,
|
||||
'attr' => array(
|
||||
'data-controller' => 'nexus.global.gateways.stripe',
|
||||
'data-id' => $this->id,
|
||||
'class' => 'ipsHide',
|
||||
'data-key' => $settings['publishable_key']
|
||||
),
|
||||
'jsRequired' => TRUE,
|
||||
'names' => FALSE,
|
||||
'save' => ( $settings['cards'] and \IPS\Member::loggedIn()->member_id ) ? $this : NULL,
|
||||
'member' => $invoice->member,
|
||||
) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorize
|
||||
*
|
||||
* @param \IPS\nexus\Transaction $transaction Transaction
|
||||
* @param array|\IPS\nexus\Customer\CreditCard $values Values from form OR a stored card object if this gateway supports them
|
||||
* @param \IPS\nexus\Fraud\MaxMind\Request|NULL $maxMind *If* MaxMind is enabled, the request object will be passed here so gateway can additional data before request is made
|
||||
* @return \IPS\DateTime|NULL Auth is valid until or NULL to indicate auth is good forever
|
||||
* @throws \LogicException Message will be displayed to user
|
||||
*/
|
||||
public function auth( \IPS\nexus\Transaction $transaction, $values, \IPS\nexus\Fraud\MaxMind\Request $maxMind = NULL )
|
||||
{
|
||||
/* Set MaxMind type */
|
||||
if ( $maxMind )
|
||||
{
|
||||
$maxMind->setTransactionType('creditcard');
|
||||
}
|
||||
|
||||
/* Build data */
|
||||
$data = array(
|
||||
'amount' => static::_amountAsCents( $transaction->amount ),
|
||||
'currency' => $transaction->amount->currency,
|
||||
'capture' => 'false'
|
||||
);
|
||||
$card = $values[ $this->id . '_card' ];
|
||||
|
||||
/* Stored Card */
|
||||
if ( $card instanceof \IPS\nexus\Gateway\Stripe\CreditCard )
|
||||
{
|
||||
$profiles = $card->member->cm_profiles;
|
||||
$data['customer'] = $profiles[ $this->id ];
|
||||
$data['card'] = $values[ $this->id . '_card' ]->data;
|
||||
}
|
||||
|
||||
/* New Card */
|
||||
else
|
||||
{
|
||||
/* Are we saving it? */
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
if ( $settings['cards'] and $card->save )
|
||||
{
|
||||
$storedCard = new \IPS\nexus\Gateway\Stripe\CreditCard;
|
||||
$storedCard->member = $transaction->member;
|
||||
$storedCard->method = $this;
|
||||
$storedCard->card = $card;
|
||||
$storedCard->save();
|
||||
|
||||
$profiles = $transaction->member->cm_profiles;
|
||||
$data['customer'] = $profiles[ $this->id ];
|
||||
$data['card'] = $storedCard->data;
|
||||
}
|
||||
/* Nope, just use the token */
|
||||
else
|
||||
{
|
||||
$data['card'] = $card->token;
|
||||
}
|
||||
}
|
||||
|
||||
/* Authorize */
|
||||
$response = $this->api( 'charges', $data );
|
||||
$transaction->gw_id = $response['id'];
|
||||
|
||||
/* Return */
|
||||
return \IPS\DateTime::ts( $response['created'] )->add( new \DateInterval( 'P7D' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Void
|
||||
*
|
||||
* @param \IPS\nexus\Transaction $transaction Transaction
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function void( \IPS\nexus\Transaction $transaction )
|
||||
{
|
||||
try
|
||||
{
|
||||
$response = $this->refund( $transaction );
|
||||
}
|
||||
catch ( \Exception $e ) { }
|
||||
}
|
||||
|
||||
/**
|
||||
* Capture
|
||||
*
|
||||
* @param \IPS\nexus\Transaction $transaction Transaction
|
||||
* @return void
|
||||
* @throws \LogicException
|
||||
*/
|
||||
public function capture( \IPS\nexus\Transaction $transaction )
|
||||
{
|
||||
$this->api( "charges/{$transaction->gw_id}/capture" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Refund
|
||||
*
|
||||
* @param \IPS\nexus\Transaction $transaction Transaction to be refunded
|
||||
* @param float|NULL $amount Amount to refund (NULL for full amount - always in same currency as transaction)
|
||||
* @return mixed Gateway reference ID for refund, if applicable
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function refund( \IPS\nexus\Transaction $transaction, $amount = NULL )
|
||||
{
|
||||
$data = NULL;
|
||||
if ( $amount )
|
||||
{
|
||||
$data['amount'] = static::_amountAscents( new \IPS\nexus\Money( $amount, $transaction->currency ) );
|
||||
}
|
||||
|
||||
$this->api( "charges/{$transaction->gw_id}/refund", $data );
|
||||
}
|
||||
|
||||
/* !ACP Configuration */
|
||||
|
||||
/**
|
||||
* Settings
|
||||
*
|
||||
* @param \IPS\Helpers\Form $form The form
|
||||
* @return void
|
||||
*/
|
||||
public function settings( &$form )
|
||||
{
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'stripe_secret_key', $settings ? $settings['secret_key'] : NULL, TRUE ) );
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'stripe_publishable_key', $settings ? $settings['publishable_key'] : NULL, TRUE ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'stripe_cards', $settings ? $settings['cards'] : TRUE, TRUE ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Settings
|
||||
*
|
||||
* @param array $settings Settings
|
||||
* @return array
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function testSettings( $settings )
|
||||
{
|
||||
try
|
||||
{
|
||||
$response = $this->api( 'account', NULL, 'get', $settings );
|
||||
$settings['country'] = $response['country'];
|
||||
return $settings;
|
||||
}
|
||||
catch ( \IPS\nexus\Gateway\Stripe\Exception $e )
|
||||
{
|
||||
throw new \InvalidArgumentException( $e->details['message'] );
|
||||
}
|
||||
}
|
||||
|
||||
/* !Utility Methods */
|
||||
|
||||
/**
|
||||
* Send API Request
|
||||
*
|
||||
* @param string $uri The API to request (e.g. "charges")
|
||||
* @param array $data The data to send
|
||||
* @param string $method Method (get/post)
|
||||
* @param array|NULL $settings Settings (NULL for saved setting)
|
||||
* @return array
|
||||
* @throws \IPS\Http|Exception
|
||||
* @throws \IPS\nexus\Gateway\PayPal\Exception
|
||||
*/
|
||||
public function api( $uri, $data=NULL, $method='post', $settings = NULL )
|
||||
{
|
||||
$settings = $settings ?: json_decode( $this->settings, TRUE );
|
||||
|
||||
$response = \IPS\Http\Url::external( 'https://api.stripe.com/v1/' . $uri )
|
||||
->request()
|
||||
->setHeaders( array( 'Stripe-Version' => '2014-01-31' ) )
|
||||
->login( $settings['secret_key'], '' )
|
||||
->$method( $data )
|
||||
->decodeJson();
|
||||
|
||||
if ( isset( $response['error'] ) )
|
||||
{
|
||||
throw new \IPS\nexus\Gateway\Stripe\Exception( $response['error'] );
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert amount into cents
|
||||
*
|
||||
* @param \IPS\nexus\Money $amount The amount
|
||||
* @return int
|
||||
*/
|
||||
protected static function _amountAsCents( \IPS\nexus\Money $amount )
|
||||
{
|
||||
if ( in_array( $amount->currency, array( 'BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'VUV', 'XAF', 'XOF', 'XPF' ) ) )
|
||||
{
|
||||
return intval( $amount->amount );
|
||||
}
|
||||
else
|
||||
{
|
||||
return intval( $amount->amount * 100 );
|
||||
}
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Test Gateway
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @subpackage Nexus
|
||||
* @since 10 Feb 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\nexus\Gateway;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Gateway
|
||||
*/
|
||||
class _Test extends \IPS\nexus\Gateway
|
||||
{
|
||||
/* !Features */
|
||||
|
||||
const SUPPORTS_REFUNDS = FALSE;
|
||||
const SUPPORTS_PARTIAL_REFUNDS = FALSE;
|
||||
|
||||
/* !Payment Gateway */
|
||||
|
||||
/**
|
||||
* Payment Screen Fields
|
||||
*
|
||||
* @param \IPS\nexus\Invoice $invoice Invoice
|
||||
* @param \IPS\nexus\Money $amount The amount to pay now
|
||||
* @return array
|
||||
*/
|
||||
public function paymentScreen( \IPS\nexus\Invoice $invoice, \IPS\nexus\Money $amount )
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Capture
|
||||
*
|
||||
* @param \IPS\nexus\Transaction $transaction Transaction
|
||||
* @return void
|
||||
* @throws \LogicException
|
||||
*/
|
||||
public function capture( \IPS\nexus\Transaction $transaction )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/* !ACP Configuration */
|
||||
|
||||
/**
|
||||
* Settings
|
||||
*
|
||||
* @param \IPS\Helpers\Form $form The form
|
||||
* @return void
|
||||
*/
|
||||
public function settings( &$form )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Settings
|
||||
*
|
||||
* @param array $settings Settings
|
||||
* @return array
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function testSettings( $settings )
|
||||
{
|
||||
return $settings;
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,225 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief 2Checkout Gateway
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @subpackage Nexus
|
||||
* @since 17 Mar 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\nexus\Gateway;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 2Checkout Gateway
|
||||
*/
|
||||
class _TwoCheckout extends \IPS\nexus\Gateway
|
||||
{
|
||||
/* !Features (Each gateway will override) */
|
||||
|
||||
const SUPPORTS_REFUNDS = TRUE;
|
||||
const SUPPORTS_PARTIAL_REFUNDS = TRUE;
|
||||
|
||||
/* !Payment Gateway */
|
||||
|
||||
/**
|
||||
* Authorize
|
||||
*
|
||||
* @param \IPS\nexus\Transaction $transaction Transaction
|
||||
* @param array|\IPS\nexus\Customer\CreditCard $values Values from form OR a stored card object if this gateway supports them
|
||||
* @param \IPS\nexus\Fraud\MaxMind\Request|NULL $maxMind *If* MaxMind is enabled, the request object will be passed here so gateway can additional data before request is made
|
||||
* @return \IPS\DateTime|NULL Auth is valid until or NULL to indicate auth is good forever
|
||||
* @throws \LogicException Message will be displayed to user
|
||||
*/
|
||||
public function auth( \IPS\nexus\Transaction $transaction, $values, \IPS\nexus\Fraud\MaxMind\Request $maxMind = NULL )
|
||||
{
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
$transaction->save();
|
||||
|
||||
/* Basic Data */
|
||||
$data = array(
|
||||
'sid' => $settings['sid'],
|
||||
'nexustransactionid' => $transaction->id,
|
||||
'mode' => '2CO',
|
||||
'currency_code' => $transaction->amount->currency,
|
||||
'purchase_step' => 'payment-method',
|
||||
'x_receipt_link_url' => \IPS\Settings::i()->base_url . 'applications/nexus/interface/gateways/2checkout.php',
|
||||
'card_holder_name' => $transaction->member->cm_name,
|
||||
'street_address' => $transaction->invoice->billaddress->addressLines[0],
|
||||
'street_address2' => isset( $transaction->invoice->billaddress->addressLines[1] ) ? $transaction->invoice->billaddress->addressLines[1] : '',
|
||||
'city' => $transaction->invoice->billaddress->city,
|
||||
'state' => $transaction->invoice->billaddress->region,
|
||||
'zip' => $transaction->invoice->billaddress->postalCode,
|
||||
'country' => $transaction->invoice->billaddress->country,
|
||||
'email' => $transaction->member->email,
|
||||
'phone' => $transaction->member->cm_phone
|
||||
);
|
||||
|
||||
/* Shipping address */
|
||||
if ( $transaction->invoice->shipaddress )
|
||||
{
|
||||
$data['ship_name'] = $transaction->member->cm_name;
|
||||
$data['ship_street_address'] = $transaction->invoice->shipaddress->addressLines[0];
|
||||
if ( isset( $transaction->invoice->shipaddress->addressLines[1] ) )
|
||||
{
|
||||
$data['ship_street_address2'] = $transaction->invoice->shipaddress->addressLines[1];
|
||||
}
|
||||
$data['ship_city'] = $transaction->invoice->shipaddress->city;
|
||||
$data['ship_state'] = $transaction->invoice->shipaddress->region;
|
||||
$data['ship_zip'] = $transaction->invoice->shipaddress->postalCode;
|
||||
$data['ship_country'] = $transaction->invoice->shipaddress->country;
|
||||
}
|
||||
|
||||
/* Items */
|
||||
if ( $transaction->amount->amount == $transaction->invoice->total->amount )
|
||||
{
|
||||
$summary = $transaction->invoice->summary();
|
||||
|
||||
$k = 0;
|
||||
foreach ( $summary['items'] as $item )
|
||||
{
|
||||
$data["li_{$k}_type"] = $item->price->amount >= 0 ? 'product' : 'coupon';
|
||||
$data["li_{$k}_name"] = $item->name;
|
||||
$data["li_{$k}_quantity"] = $item->quantity;
|
||||
$data["li_{$k}_price"] = abs( $item->price->amount );
|
||||
$data["li_{$k}_tangible"] = $item->physical ?'Y' : 'N';
|
||||
|
||||
$d = 0;
|
||||
foreach ( $item->details as $label => $value )
|
||||
{
|
||||
$data["li_{$k}_option_{$d}_name"] = $label;
|
||||
$data["li_{$k}_option_{$d}_value"] = $value;
|
||||
$d++;
|
||||
}
|
||||
|
||||
$k++;
|
||||
}
|
||||
|
||||
foreach ( $summary['shipping'] as $shipping )
|
||||
{
|
||||
$data["li_{$k}_type"] = 'shipping';
|
||||
$data["li_{$k}_name"] = $shipping->name;
|
||||
$data["li_{$k}_quantity"] = 1;
|
||||
$data["li_{$k}_price"] = $shipping->price->amount;
|
||||
$data["li_{$k}_tangible"] = 'Y';
|
||||
|
||||
$k++;
|
||||
}
|
||||
|
||||
foreach ( $summary['tax'] as $tax )
|
||||
{
|
||||
$data["li_{$k}_type"] = 'tax';
|
||||
$data["li_{$k}_name"] = $tax['name'];
|
||||
$data["li_{$k}_quantity"] = 1;
|
||||
$data["li_{$k}_price"] = $tax['amount']->amount;
|
||||
$data["li_{$k}_tangible"] = 'N';
|
||||
|
||||
$d = 0;
|
||||
foreach ( $item['details'] as $label => $value )
|
||||
{
|
||||
$data["li_{$k}_option_{$d}_name"] = $label;
|
||||
$data["li_{$k}_option_{$d}_value"] = $value;
|
||||
$d++;
|
||||
}
|
||||
|
||||
$k++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$data["li_0_type"] = 'product';
|
||||
$data["li_0_name"] = $transaction->member->language()->addToStack( 'partial_payment_desc', FALSE, array( 'sprintf' => array( $transaction->invoice->id ) ) );
|
||||
$data["li_0_quantity"] = 1;
|
||||
$data["li_0_price"] = $transaction->amount->amount;
|
||||
$data["li_0_tangible"] = 'N';
|
||||
}
|
||||
|
||||
/* Test mode */
|
||||
if ( \IPS\NEXUS_TEST_GATEWAYS )
|
||||
{
|
||||
$data['demo'] = 'Y';
|
||||
}
|
||||
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::external( 'https://www.2checkout.com/checkout/purchase' )->setQueryString( $data ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Refund
|
||||
*
|
||||
* @param \IPS\nexus\Transaction $transaction Transaction to be refunded
|
||||
* @param float|NULL $amount Amount to refund (NULL for full amount - always in same currency as transaction)
|
||||
* @return mixed Gateway reference ID for refund, if applicable
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function refund( \IPS\nexus\Transaction $transaction, $amount = NULL )
|
||||
{
|
||||
$data = array(
|
||||
'sale_id' => $transaction->gw_id,
|
||||
'category' => 5,
|
||||
'comment' => 'Nexus'
|
||||
);
|
||||
|
||||
if ( $amount )
|
||||
{
|
||||
$data['amount'] = $amount;
|
||||
$data['currency'] = 'vendor';
|
||||
}
|
||||
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
$response = \IPS\Http\Url::external( 'https://www.2checkout.com/api/sales/refund_invoice' )->request()->login( $settings['api_username'], $settings['api_password'] )->post( $data )->decodeJson();
|
||||
|
||||
if ( $response['response_code'] != 'OK' )
|
||||
{
|
||||
throw new \LogicException( $response['response_message'] );
|
||||
}
|
||||
}
|
||||
|
||||
/* !ACP Configuration */
|
||||
|
||||
/**
|
||||
* Settings
|
||||
*
|
||||
* @param \IPS\Helpers\Form $form The form
|
||||
* @return void
|
||||
*/
|
||||
public function settings( &$form )
|
||||
{
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'twocheckout_api_username', $settings['api_username'], TRUE ) );
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'twocheckout_api_password', $settings['api_password'], TRUE ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Settings
|
||||
*
|
||||
* @param array $settings Settings
|
||||
* @return array
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function testSettings( $settings )
|
||||
{
|
||||
$response = \IPS\Http\Url::external( 'https://www.2checkout.com/api/acct/detail_company_info' )->request()->setHeaders( array( 'Accept' => 'application/json' ) )->login( $settings['api_username'], $settings['api_password'] )->get()->decodeJson();
|
||||
if ( isset( $response['errors'] ) )
|
||||
{
|
||||
throw new \LogicException( $response['errors'][0]['message'] );
|
||||
}
|
||||
if ( $response['response_code'] != 'OK' )
|
||||
{
|
||||
throw new \LogicException( $response['response_message'] );
|
||||
}
|
||||
|
||||
$settings['sid'] = $response['vendor_company_info']['vendor_id'];
|
||||
$settings['word'] = $response['vendor_company_info']['secret_word'];
|
||||
return $settings;
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
Whitespace-only changes.
Reference in new issue
Block a user