Version 4.5.0

This commit is contained in:
Neo committed 2025-12-19 05:51:58 -08:00
1 parent 1a0c7fd3c2
commit f79dcf067a
3791 files changed
+248032 -76372

No files matched your search

+140 -21
View File
@@ -12,7 +12,7 @@
namespace IPS\nexus;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -23,6 +23,43 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
*/
class _Gateway extends \IPS\Node\Model
{
/**
* Gateways
*
* @return array
*/
public static function gateways()
{
$return = array(
'Stripe' => 'IPS\nexus\Gateway\Stripe',
'Braintree' => 'IPS\nexus\Gateway\Braintree',
'PayPal' => 'IPS\nexus\Gateway\PayPal',
'AuthorizeNet' => 'IPS\nexus\Gateway\AuthorizeNet',
'TwoCheckout' => 'IPS\nexus\Gateway\TwoCheckout',
'Manual' => 'IPS\nexus\Gateway\Manual',
);
if ( \IPS\NEXUS_TEST_GATEWAYS )
{
$return['Test'] = 'IPS\nexus\Gateway\Test';
}
return $return;
}
/**
* Payout Gateways
*
* @return array
*/
public static function payoutGateways()
{
return array(
'PayPal' => 'IPS\nexus\Gateway\PayPal\Payout',
'Manual' => 'IPS\nexus\Gateway\Manual\Payout',
);
}
/**
* @brief [ActiveRecord] Multiton Store
*/
@@ -62,7 +99,7 @@ class _Gateway extends \IPS\Node\Model
*/
public static function constructFromData( $data, $updateMultitonStoreIfExists = TRUE )
{
$classname = 'IPS\nexus\Gateway\\' . $data['m_gateway'];
$classname = static::gateways()[ $data['m_gateway'] ];
if ( !class_exists( $classname ) )
{
throw new \OutOfRangeException;
@@ -148,7 +185,7 @@ class _Gateway extends \IPS\Node\Model
{
$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 )
$form->add( new \IPS\Helpers\Form\Select( 'paymethod_countries', ( $this->id 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' ) ) );
@@ -170,7 +207,7 @@ class _Gateway extends \IPS\Node\Model
if( isset( $values['paymethod_countries'] ) )
{
$values['countries'] = is_array( $values['paymethod_countries'] ) ? implode( ',', $values['paymethod_countries'] ) : $values['paymethod_countries'];
$values['countries'] = \is_array( $values['paymethod_countries'] ) ? implode( ',', $values['paymethod_countries'] ) : $values['paymethod_countries'];
}
$settings = array();
@@ -193,32 +230,34 @@ class _Gateway extends \IPS\Node\Model
/**
* Get gateways that support storing cards
*
* @param bool $adminCreatableOnly If TRUE, will only return gateways where the admin (opposed to the user) can create a new option
* @return array
*/
public static function cardStorageGateways()
public static function cardStorageGateways( $adminCreatableOnly = FALSE )
{
$return = array();
foreach ( static::roots() as $gateway )
{
if ( $gateway->canStoreCards() )
if ( $gateway->canStoreCards( $adminCreatableOnly ) )
{
$return[ $gateway->id ] = $gateway;
}
}
return $return;
}
/**
* Get gateways that support manual admin charges
*
* @param \IPS\nexus\Customer $customer The customer we're wanting to charge
* @return array
*/
public static function manualChargeGateways()
public static function manualChargeGateways( \IPS\nexus\Customer $customer )
{
$return = array();
foreach ( static::roots() as $gateway )
{
if ( $gateway->canAdminCharge() )
if ( $gateway->canAdminCharge( $customer ) )
{
$return[ $gateway->id ] = $gateway;
}
@@ -254,7 +293,73 @@ class _Gateway extends \IPS\Node\Model
parent::save();
static::recountCardStorageGateways();
}
/**
* [Node] Get buttons to display in tree
* Example code explains return value
*
* @code
array(
array(
'icon' => 'plus-circle', // Name of FontAwesome icon to use
'title' => 'foo', // Language key to use for button's title parameter
'link' => \IPS\Http\Url::internal( 'app=foo...' ) // URI to link to
'class' => 'modalLink' // CSS Class to use on link (Optional)
),
... // Additional buttons
);
* @endcode
* @param string $url Base URL
* @param bool $subnode Is this a subnode?
* @return array
*/
public function getButtons( $url, $subnode=FALSE )
{
$buttons = parent::getButtons( $url, $subnode );
/* If we have active billing agreements and the node isn't currently queued for deletion, add a special warning to the delete confirmation box */
if( $this->hasActiveBillingAgreements() AND isset( $buttons['delete'] ) )
{
$buttons['delete']['data']['delete-warning'] = \IPS\Member::loggedIn()->language()->addToStack('gateway_ba_delete_blurb');
}
return $buttons;
}
/**
* Is this node currently queued for deleting or moving content?
*
* @return bool
*/
public function deleteOrMoveQueued()
{
if( $this->hasActiveBillingAgreements() )
{
/* If we already know, don't bother */
if ( \is_null( $this->queued ) )
{
$this->queued = FALSE;
foreach( \IPS\Db::i()->select( 'data', 'core_queue', array( 'app=? AND `key`=?', 'nexus', 'DeletePaymentMethod' ) ) as $taskData )
{
$data = json_decode( $taskData, TRUE );
if( $data['id'] == $this->id )
{
$this->queued = TRUE;
break;
}
}
}
return $this->queued;
}
else
{
return parent::deleteOrMoveQueued();
}
}
/**
* [ActiveRecord] Delete
*
@@ -291,7 +396,7 @@ class _Gateway extends \IPS\Node\Model
$counts[ $gateway->gateway ]++;
}
\IPS\Settings::i()->changeValues( array( 'card_storage_gateways' => count( static::cardStorageGateways() ), 'billing_agreement_gateways' => count( static::billingAgreementGateways() ), 'gateways_counts' => json_encode( $counts ) ) );
\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) */
@@ -310,11 +415,11 @@ class _Gateway extends \IPS\Node\Model
*/
public function checkValidity( \IPS\nexus\Money $amount, \IPS\GeoLocation $billingAddress = NULL, \IPS\nexus\Customer $customer = NULL, $recurrings = array() )
{
if ( $this->countries and $this->countries !== '*' )
if ( $this->countries !== '*' )
{
if ( $billingAddress )
{
return in_array( $billingAddress->country, explode( ',', $this->countries ) );
return \in_array( $billingAddress->country, explode( ',', $this->countries ) );
}
else
{
@@ -328,9 +433,10 @@ class _Gateway extends \IPS\Node\Model
/**
* Can store cards?
*
* @param bool $adminCreatableOnly If TRUE, will only return gateways where the admin (opposed to the user) can create a new option
* @return bool
*/
public function canStoreCards()
public function canStoreCards( $adminCreatableOnly = FALSE )
{
return FALSE;
}
@@ -338,9 +444,10 @@ class _Gateway extends \IPS\Node\Model
/**
* Admin can manually charge using this gateway?
*
* @param \IPS\nexus\Customer $customer The customer we're wanting to charge
* @return bool
*/
public function canAdminCharge()
public function canAdminCharge( \IPS\nexus\Customer $customer )
{
return FALSE;
}
@@ -354,6 +461,16 @@ class _Gateway extends \IPS\Node\Model
{
return FALSE;
}
/**
* Has active billing agreements?
*
* @return bool
*/
public function hasActiveBillingAgreements()
{
return (bool) \IPS\Db::i()->select( 'COUNT(*)', 'nexus_billing_agreements', array( 'ba_method=? AND ba_canceled=?', $this->id, 0 ) )->first();
}
/* !Payment Gateway */
@@ -370,13 +487,14 @@ class _Gateway extends \IPS\Node\Model
/**
* Payment Screen Fields
*
* @param \IPS\nexus\Invoice $invoice Invoice
* @param \IPS\nexus\Money $amount The amount to pay now
* @param \IPS\nexus\Customer $member The member the payment screen is for (if in the ACP charging to a member's card) or NULL for currently logged in member
* @param array $recurrings Details about recurring costs
* @param \IPS\nexus\Invoice $invoice Invoice
* @param \IPS\nexus\Money $amount The amount to pay now
* @param \IPS\nexus\Customer $member The member the payment screen is for (if in the ACP charging to a member's card) or NULL for currently logged in member
* @param array $recurrings Details about recurring costs
* @param bool $type 'checkout' means the cusotmer is doing this on the normal checkout screen, 'admin' means the admin is doing this in the ACP, 'card' means the user is just adding a card
* @return array
*/
public function paymentScreen( \IPS\nexus\Invoice $invoice, \IPS\nexus\Money $amount, \IPS\nexus\Customer $member = NULL, $recurrings = array() )
public function paymentScreen( \IPS\nexus\Invoice $invoice, \IPS\nexus\Money $amount, \IPS\nexus\Customer $member = NULL, $recurrings = array(), $type = 'checkout' )
{
return array();
}
@@ -400,10 +518,11 @@ class _Gateway extends \IPS\Node\Model
* @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
* @param array $recurrings Details about recurring costs
* @param string|NULL $source 'checkout' if the customer is doing this at a normal checkout, 'renewal' is an automatically generated renewal invoice, 'manual' is admin manually charging. NULL is unknown
* @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, $recurrings = array() )
public function auth( \IPS\nexus\Transaction $transaction, $values, \IPS\nexus\Fraud\MaxMind\Request $maxMind = NULL, $recurrings = array(), $source = NULL )
{
return NULL;
}