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