Version 4.3.0
This commit is contained in:
1 parent
96997ddd8e
commit
fe1acf984a
1349 files changed
+116159
-67711
No files matched your search
@@ -134,8 +134,6 @@ class _AuthorizeNet extends \IPS\nexus\Gateway
|
||||
*/
|
||||
public function paymentScreen( \IPS\nexus\Invoice $invoice, \IPS\nexus\Money $amount, \IPS\nexus\Customer $member = NULL, $recurrings = array() )
|
||||
{
|
||||
\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 );
|
||||
|
||||
@@ -308,7 +306,7 @@ class _AuthorizeNet extends \IPS\nexus\Gateway
|
||||
$storedCard->card = $card;
|
||||
$storedCard->save();
|
||||
}
|
||||
catch ( \Exception $e ) { }
|
||||
catch ( \Exception $e ) { /* If there's any issue with saving (which may happen for a duplicate card) we can just carry on since we already auth'd */ }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ class _CreditCard extends \IPS\nexus\Customer\CreditCard
|
||||
$this->member->cm_profiles = $profiles;
|
||||
$this->member->save();
|
||||
}
|
||||
|
||||
|
||||
/* Add the card */
|
||||
$xml = $this->createAuthenticationXml( 'createCustomerPaymentProfileRequest' );
|
||||
$xml->addChild( 'customerProfileId', $profiles[ $this->method->id ] );
|
||||
@@ -133,6 +133,12 @@ class _CreditCard extends \IPS\nexus\Customer\CreditCard
|
||||
throw new \UnexpectedValueException;
|
||||
}
|
||||
|
||||
/* Check it doesn't already exist */
|
||||
if ( count( \IPS\Db::i()->select( 'card_data', 'nexus_customer_cards', array( 'card_member=? AND card_method=? AND card_data=?', $this->member->member_id, $this->method->id, (string) $response->customerPaymentProfileId ) ) ) )
|
||||
{
|
||||
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack('card_is_duplicate') );
|
||||
}
|
||||
|
||||
/* Save */
|
||||
$this->data = (string) $response->customerPaymentProfileId;
|
||||
$this->save();
|
||||
|
||||
@@ -280,12 +280,18 @@ class _Gateway extends \IPS\Node\Model
|
||||
*/
|
||||
protected static function recountCardStorageGateways()
|
||||
{
|
||||
foreach ( array( 'card_storage_gateways' => count( static::cardStorageGateways() ), 'billing_agreement_gateways' => count( static::billingAgreementGateways() ) ) as $k => $v )
|
||||
$counts = array();
|
||||
foreach ( static::roots() as $gateway )
|
||||
{
|
||||
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => $v ), array( 'conf_key=?', $k ) );
|
||||
\IPS\Settings::i()->$k = $v;
|
||||
if ( !isset( $counts[ $gateway->gateway ] ) )
|
||||
{
|
||||
$counts[ $gateway->gateway ] = 0;
|
||||
}
|
||||
|
||||
$counts[ $gateway->gateway ]++;
|
||||
}
|
||||
unset( \IPS\Data\Store::i()->settings );
|
||||
|
||||
\IPS\Settings::i()->changeValues( array( 'card_storage_gateways' => count( static::cardStorageGateways() ), 'billing_agreement_gateways' => count( static::billingAgreementGateways() ), 'gateways_counts' => json_encode( $counts ) ) );
|
||||
}
|
||||
|
||||
/* !Features (Each gateway will override) */
|
||||
@@ -351,6 +357,16 @@ class _Gateway extends \IPS\Node\Model
|
||||
|
||||
/* !Payment Gateway */
|
||||
|
||||
/**
|
||||
* Should the submit button show when this payment method is shown?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function showSubmitButton()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Payment Screen Fields
|
||||
*
|
||||
@@ -364,6 +380,18 @@ class _Gateway extends \IPS\Node\Model
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Manual Payment Instructions
|
||||
*
|
||||
* @param \IPS\nexus\Transaction $transaction Transaction
|
||||
* @param string|NULL $email If this is for the email, will be 'html' or 'plaintext'. If for UI, will be NULL.
|
||||
* @return array
|
||||
*/
|
||||
public function manualPaymentInstructions( \IPS\nexus\Transaction $transaction, $email = NULL )
|
||||
{
|
||||
return $transaction->member->language()->addToStack( "nexus_gateway_{$this->id}_ins" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorize
|
||||
@@ -417,6 +445,16 @@ class _Gateway extends \IPS\Node\Model
|
||||
throw new \Exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refund Reasons that the gateway understands, if the gateway supports this
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function refundReasons()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extra data to show on the ACP transaction page
|
||||
*
|
||||
@@ -428,14 +466,50 @@ class _Gateway extends \IPS\Node\Model
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Extra data to show on the ACP transaction page for a dispute
|
||||
*
|
||||
* @param \IPS\nexus\Transaction $transaction Transaction
|
||||
* @param string $ref Dispute reference ID
|
||||
* @return string
|
||||
*/
|
||||
public function disputeData( \IPS\nexus\Transaction $transaction, $ref )
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Run any gateway-specific anti-fraud checks and return status for transaction
|
||||
* This is only called if our local anti-fraud rules have not matched
|
||||
*
|
||||
* @param \IPS\nexus\Transaction $transaction Transaction
|
||||
* @return string
|
||||
*/
|
||||
public function fraudCheck( \IPS\nexus\Transaction $transaction )
|
||||
{
|
||||
return $transaction::STATUS_PAID;
|
||||
}
|
||||
|
||||
/**
|
||||
* URL to view transaction in gateway
|
||||
*
|
||||
* @param \IPS\nexus\Transaction $transaction Transaction
|
||||
* @return \IPS\Http\Url|NULL
|
||||
*/
|
||||
public function gatewayUrl( \IPS\nexus\Transaction $transaction )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get output for API
|
||||
*
|
||||
* @param \IPS\Member|NULL $authorizedMember The member making the API request or NULL for API Key / client_credentials
|
||||
* @return array
|
||||
* @apiresponse int id ID number
|
||||
* @apiresponse string name Name
|
||||
*/
|
||||
public function apiOutput()
|
||||
public function apiOutput( \IPS\Member $authorizedMember = NULL )
|
||||
{
|
||||
return array(
|
||||
'id' => $this->id,
|
||||
|
||||
@@ -96,4 +96,16 @@ class _Manual extends \IPS\nexus\Gateway
|
||||
{
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public function refund( \IPS\nexus\Transaction $transaction, $amount = NULL )
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -83,40 +83,49 @@ class _BillingAgreement extends \IPS\nexus\Customer\BillingAgreement
|
||||
|
||||
return new \IPS\DateTime( $data['agreement_details']['next_billing_date'] );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get latest unclaimed transaction (only gets transactions within the last 31 days which do not yet have a matching transaction)
|
||||
*
|
||||
* @return \IPS\nexus\Transaction
|
||||
* @throws \IPS\nexus\Gateway\PayPal\Exception
|
||||
* @throws \OutOfRangeException
|
||||
* @throws \IPS\Http\Exception
|
||||
*/
|
||||
public function latestUnclaimedTransaction()
|
||||
{
|
||||
$url = "payments/billing-agreements/{$this->gw_id}/transactions?start_date=" . date( 'Y-m-d', time() - ( 86400 * 31 ) ) . '&end_date=' . date( 'Y-m-d' );
|
||||
$transactions = $this->method->api( $url, NULL, 'get' );
|
||||
foreach ( array_reverse( $transactions['agreement_transaction_list'] ) as $t )
|
||||
$url = "payments/billing-agreements/{$this->gw_id}/transactions?start_date=" . date('Y-m-d', time() - (86400 * 31)) . '&end_date=' . date('Y-m-d');
|
||||
try
|
||||
{
|
||||
if ( $t['status'] == 'Completed' )
|
||||
$transactions = $this->method->api( $url, NULL, 'get' );
|
||||
foreach ( array_reverse( $transactions['agreement_transaction_list'] ) as $t )
|
||||
{
|
||||
try
|
||||
if ( $t['status'] == 'Completed' )
|
||||
{
|
||||
$existingTransaction = \IPS\Db::i()->select( 't_id', 'nexus_transactions', array( 't_method=? AND t_gw_id=?', $this->method->id, $t['transaction_id'] ) )->first();
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
{
|
||||
$transaction = new \IPS\nexus\Transaction;
|
||||
$transaction->member = $this->member;
|
||||
$transaction->method = $this->method;
|
||||
$transaction->amount = new \IPS\nexus\Money( $t['amount']['value'], $t['amount']['currency'] );
|
||||
$transaction->date = new \IPS\DateTime( $t['time_stamp'] );
|
||||
$transaction->extra = array( 'automatic' => TRUE );
|
||||
$transaction->gw_id = $t['transaction_id'];
|
||||
$transaction->billing_agreement = $this;
|
||||
return $transaction;
|
||||
try
|
||||
{
|
||||
$existingTransaction = \IPS\Db::i()->select( 't_id', 'nexus_transactions', array( 't_method=? AND t_gw_id=?', $this->method->id, $t['transaction_id'] ) )->first();
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
{
|
||||
$transaction = new \IPS\nexus\Transaction;
|
||||
$transaction->member = $this->member;
|
||||
$transaction->method = $this->method;
|
||||
$transaction->amount = new \IPS\nexus\Money( $t['amount']['value'], $t['amount']['currency'] );
|
||||
$transaction->date = new \IPS\DateTime( $t['time_stamp'] );
|
||||
$transaction->extra = array( 'automatic' => TRUE );
|
||||
$transaction->gw_id = $t['transaction_id'];
|
||||
$transaction->billing_agreement = $this;
|
||||
return $transaction;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( \IPS\Http\Exception $e )
|
||||
{
|
||||
throw $e;
|
||||
}
|
||||
|
||||
throw new \OutOfRangeException( "{$this->id} ({$this->gw_id})\n{$url}\n\n" . print_r( $transactions, TRUE ) );
|
||||
}
|
||||
|
||||
|
||||
@@ -86,6 +86,21 @@ class _CreditCard extends \IPS\nexus\Customer\CreditCard
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check it doesn't already exist */
|
||||
$otherCards = \IPS\Db::i()->select( 'card_data', 'nexus_customer_cards', array( 'card_member=? AND card_method=?', $this->member->member_id, $this->method->id ) );
|
||||
if ( count( $otherCards ) )
|
||||
{
|
||||
foreach ( $otherCards as $otherCardId )
|
||||
{
|
||||
$otherCardData = $this->method->api( 'vault/credit-card/' . $otherCardId, NULL, 'get' );
|
||||
if ( $otherCardData['state'] === 'ok' and mb_substr( $otherCardData['number'], -4 ) === mb_substr( $card->number, -4 ) and intval( $otherCardData['expire_month'] ) === intval( $card->expMonth ) and intval( $otherCardData['expire_year'] ) === intval( $card->expYear ) )
|
||||
{
|
||||
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack('card_is_duplicate') );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Save */
|
||||
$response = $this->method->api( 'vault/credit-card', array(
|
||||
'number' => $card->number,
|
||||
'type' => $cardType,
|
||||
@@ -95,7 +110,6 @@ class _CreditCard extends \IPS\nexus\Customer\CreditCard
|
||||
'first_name' => $this->member->cm_first_name,
|
||||
'last_name' => $this->member->cm_last_name,
|
||||
) );
|
||||
|
||||
$this->data = $response['id'];
|
||||
$this->save();
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@ class _PayPal extends \IPS\nexus\Gateway
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
if ( $settings['type'] === 'card' )
|
||||
{
|
||||
return array( 'card' => new \IPS\nexus\Form\CreditCard( $this->id . '_card', NULL, FALSE, array(
|
||||
return array( 'card' => new \IPS\nexus\Form\CreditCard( $this->id . '_card', NULL, TRUE, 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'] ? $this : NULL,
|
||||
'member' => $member
|
||||
@@ -417,7 +417,7 @@ class _PayPal extends \IPS\nexus\Gateway
|
||||
$storedCard->card = $card;
|
||||
$storedCard->save();
|
||||
}
|
||||
catch ( \Exception $e ) { }
|
||||
catch ( \Exception $e ) { /* If there's any issue with saving (which may happen for a duplicate card) we can just carry on since we already auth'd */ }
|
||||
}
|
||||
|
||||
/* And return */
|
||||
@@ -1008,7 +1008,7 @@ class _PayPal extends \IPS\nexus\Gateway
|
||||
{
|
||||
$payPalTransactionData['item_list']['items'][] = array(
|
||||
'quantity' => $item->quantity,
|
||||
'name' => $item->name,
|
||||
'name' => mb_strlen( $item->name ) > 127 ? mb_substr( $item->name, 0, 124 ) . '...' : $item->name,
|
||||
'price' => $item->price->amountAsString(),
|
||||
'currency' => $transaction->amount->currency,
|
||||
);
|
||||
|
||||
@@ -36,40 +36,73 @@ class _CreditCard extends \IPS\nexus\Customer\CreditCard
|
||||
public function get_card()
|
||||
{
|
||||
if ( !$this->_card )
|
||||
{
|
||||
$profiles = $this->member->cm_profiles;
|
||||
if ( !isset( $profiles[ $this->method->id ] ) )
|
||||
{
|
||||
if ( mb_substr( $this->data, 0, 4 ) === 'src_' )
|
||||
{
|
||||
throw new \UnexpectedValueException;
|
||||
$response = $this->method->api( "sources/{$this->data}", NULL, 'get' );
|
||||
|
||||
$this->_card = new \IPS\nexus\CreditCard;
|
||||
$this->_card->lastFour = $response['card']['last4'];
|
||||
switch ( $response['card']['brand'] )
|
||||
{
|
||||
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['card']['exp_month'];
|
||||
$this->_card->expYear = $response['card']['exp_year'];
|
||||
}
|
||||
|
||||
$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;
|
||||
else
|
||||
{
|
||||
$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'];
|
||||
}
|
||||
$this->_card->expMonth = $response['exp_month'];
|
||||
$this->_card->expYear = $response['exp_year'];
|
||||
}
|
||||
return $this->_card;
|
||||
}
|
||||
@@ -82,8 +115,8 @@ class _CreditCard extends \IPS\nexus\Customer\CreditCard
|
||||
*/
|
||||
public function set_card( \IPS\nexus\CreditCard $card )
|
||||
{
|
||||
/* Create a customer object if we don't have one */
|
||||
$profiles = $this->member->cm_profiles;
|
||||
|
||||
if ( !isset( $profiles[ $this->method->id ] ) )
|
||||
{
|
||||
$response = $this->method->api( 'customers', array(
|
||||
@@ -98,11 +131,37 @@ class _CreditCard extends \IPS\nexus\Customer\CreditCard
|
||||
$this->member->save();
|
||||
}
|
||||
|
||||
$response = $this->method->api( "customers/{$profiles[ $this->method->id ]}/cards", array(
|
||||
'card' => isset( $card->token ) ? $card->token : NULL
|
||||
/* If the source is a 3D Secure Authorization, get the actual card */
|
||||
$sourceId = $card->token;
|
||||
$response = $this->method->api( "sources/{$card->token}", NULL, 'get' );
|
||||
if ( $response['type'] === 'three_d_secure' )
|
||||
{
|
||||
$sourceId = $response['three_d_secure']['card'];
|
||||
}
|
||||
|
||||
/* Check it doesn't already exist */
|
||||
$otherCards = \IPS\Db::i()->select( 'card_data', 'nexus_customer_cards', array( 'card_member=? AND card_method=?', $this->member->member_id, $this->method->id ) );
|
||||
if ( count( $otherCards ) )
|
||||
{
|
||||
$sourceData = $this->method->api( "sources/{$sourceId}", NULL, 'get' );
|
||||
if ( isset( $sourceData['card']['fingerprint'] ) )
|
||||
{
|
||||
foreach ( $otherCards as $otherCardId )
|
||||
{
|
||||
$otherCardData = $this->method->api( "sources/{$otherCardId}", NULL, 'get' );
|
||||
if ( isset( $otherCardData['card']['fingerprint'] ) and $otherCardData['card']['fingerprint'] === $sourceData['card']['fingerprint'] )
|
||||
{
|
||||
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack('card_is_duplicate') );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Save the card */
|
||||
$response = $this->method->api( "customers/{$profiles[ $this->method->id ]}/sources", array(
|
||||
'source' => $sourceId
|
||||
) );
|
||||
$this->data = $response['id'];
|
||||
|
||||
$this->save();
|
||||
}
|
||||
|
||||
|
||||
@@ -41,10 +41,6 @@ class _Exception extends \DomainException
|
||||
{
|
||||
parent::__construct( $response['message'] );
|
||||
}
|
||||
elseif ( $response['type'] == 'invalid_request_error' )
|
||||
{
|
||||
parent::__construct( \IPS\Member::loggedIn()->language()->get( 'card_number_invalid' ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
parent::__construct( \IPS\Member::loggedIn()->language()->get( 'gateway_err' ) );
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user