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,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.
Reference in new issue
Block a user