Version 5.0.6
This commit is contained in:
1 parent
a3a4a9ccbd
commit
b89858b2ff
1214 files changed
+92828
-14859
No files matched your search
@@ -15,6 +15,7 @@ namespace IPS\nexus\Form;
|
||||
|
||||
use DateInterval;
|
||||
use IPS\Helpers\Form\FormAbstract;
|
||||
use IPS\Math\Number;
|
||||
use IPS\Member;
|
||||
use IPS\nexus\Money;
|
||||
use IPS\nexus\Purchase\RenewalTerm as RenewalTermClass;
|
||||
@@ -126,7 +127,14 @@ class RenewalTerm extends FormAbstract
|
||||
/* If we have no price specified, stop here */
|
||||
if( $costs === NULL OR ( is_array( $costs ) AND !count( $costs ) ) )
|
||||
{
|
||||
return null;
|
||||
if( $this->options['lockPrice'] )
|
||||
{
|
||||
$costs = new Money( new Number( "0" ), $currency );
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/* Work out term */
|
||||
|
||||
@@ -128,6 +128,11 @@ abstract class Gateway extends Model
|
||||
* @brief [Node] Title prefix. If specified, will look for a language key with "{$key}_title" as the key
|
||||
*/
|
||||
public static ?string $titleLangPrefix = 'nexus_paymethod_';
|
||||
|
||||
/**
|
||||
* @brief [Node] Enabled/Disabled Column
|
||||
*/
|
||||
public static ?string $databaseColumnEnabledDisabled = 'active';
|
||||
|
||||
/**
|
||||
* Construct ActiveRecord from database row
|
||||
@@ -176,28 +181,6 @@ abstract class Gateway extends Model
|
||||
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(): ?bool
|
||||
{
|
||||
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( bool|int $enabled ) : void
|
||||
{
|
||||
$this->enabled = $enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief [Node] ACP Restrictions
|
||||
* @code
|
||||
@@ -490,6 +473,12 @@ abstract class Gateway extends Model
|
||||
*/
|
||||
public function checkValidity(Money $amount, ?GeoLocation $billingAddress = NULL, ?Customer $customer = NULL, array $recurrings = array() ) : bool
|
||||
{
|
||||
/* If the gateway is disabled, skip it */
|
||||
if( !$this->active )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $this->countries !== '*' )
|
||||
{
|
||||
if ( $billingAddress )
|
||||
|
||||
@@ -505,7 +505,7 @@ class PayPal extends Gateway
|
||||
/* Send the request */
|
||||
try
|
||||
{
|
||||
$response = $this->api( 'checkout/orders', [
|
||||
$intent = [
|
||||
'intent' => 'AUTHORIZE',
|
||||
'purchase_units' => $this->_getPurchaseUnits( $transaction ),
|
||||
'payment_source' => [
|
||||
@@ -515,16 +515,23 @@ class PayPal extends Gateway
|
||||
'cancel_url' => (string)$transaction->invoice->checkoutUrl(),
|
||||
],
|
||||
'email_address' => $transaction->member->email,
|
||||
'name' => [
|
||||
'given_name' => $this->_getFirstName( $transaction ),
|
||||
'surname' => $this->_getLastName( $transaction )
|
||||
],
|
||||
'address' => ( $transaction->invoice->billaddress instanceof GeoLocation ) ? $this->_getAddress( $transaction->invoice->billaddress, $transaction->member ) : null,
|
||||
]
|
||||
]
|
||||
], 'POST', true, null, md5( $transaction->invoice->checkoutUrl() . ';' . $transaction->id ), 2 );
|
||||
];
|
||||
|
||||
try
|
||||
{
|
||||
$intent['payment_source']['paypal']['name'] = [
|
||||
'given_name' => $this->_getFirstName( $transaction ),
|
||||
'surname' => $this->_getLastName( $transaction )
|
||||
];
|
||||
}
|
||||
catch( UnexpectedValueException ){}
|
||||
|
||||
$response = $this->api( 'checkout/orders', $intent, 'POST', true, null, md5( $transaction->invoice->checkoutUrl() . ';' . $transaction->id ), 2 );
|
||||
}
|
||||
catch(PayPal\Exception $e )
|
||||
catch( PayPal\Exception $e )
|
||||
{
|
||||
$this->processException( $transaction, $e );
|
||||
throw $e;
|
||||
@@ -645,14 +652,10 @@ class PayPal extends Gateway
|
||||
$plan = $this->api( 'billing/plans', $planDetails );
|
||||
|
||||
/* Create a subscription */
|
||||
$subscription = $this->api( 'billing/subscriptions', array(
|
||||
$planData = array(
|
||||
'plan_id' => $plan['id'],
|
||||
'quantity' => '1',
|
||||
'subscriber' => array(
|
||||
'name' => array(
|
||||
'given_name' => $this->_getFirstName( $transaction ),
|
||||
'surname' => $this->_getLastName( $transaction )
|
||||
),
|
||||
'email_address' => $transaction->member->email,
|
||||
),
|
||||
'application_context' => array(
|
||||
@@ -668,7 +671,21 @@ class PayPal extends Gateway
|
||||
'cancel_url' => (string) $transaction->invoice->checkoutUrl(),
|
||||
'return_url' => Settings::i()->base_url . 'applications/nexus/interface/gateways/paypal.php?subscription=1&nexusTransactionId=' . $transaction->id,
|
||||
)
|
||||
) );
|
||||
);
|
||||
|
||||
if( $transaction->invoice->hasItemsRequiringBillingAddress() )
|
||||
{
|
||||
try
|
||||
{
|
||||
$planData['subscriber']['name'] = array(
|
||||
'given_name' => $this->_getFirstName( $transaction ),
|
||||
'surname' => $this->_getLastName( $transaction )
|
||||
);
|
||||
}
|
||||
catch( UnexpectedValueException ){}
|
||||
}
|
||||
|
||||
$subscription = $this->api( 'billing/subscriptions', $planData );
|
||||
|
||||
/* Redirect */
|
||||
foreach ( $subscription['links'] as $link )
|
||||
@@ -1250,27 +1267,43 @@ class PayPal extends Gateway
|
||||
/* Return */
|
||||
return $address;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get first name for PayPal
|
||||
*
|
||||
* @param Transaction $transaction Transaction
|
||||
* @return string
|
||||
* @throws UnexpectedValueException
|
||||
*/
|
||||
protected function _getFirstName( Transaction $transaction ) : string
|
||||
{
|
||||
return $transaction->invoice->member->member_id ? $transaction->invoice->member->cm_first_name : $transaction->invoice->guest_data['member']['cm_first_name'];
|
||||
$name = $transaction->invoice->member->member_id ? $transaction->invoice->member->cm_first_name : $transaction->invoice->guest_data['member']['cm_first_name'];
|
||||
|
||||
if( empty( $name ) )
|
||||
{
|
||||
throw new UnexpectedValueException;
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get last name for PayPal
|
||||
*
|
||||
* @param Transaction $transaction Transaction
|
||||
* @return string
|
||||
* @throws UnexpectedValueException
|
||||
*/
|
||||
protected function _getLastName( Transaction $transaction ) : string
|
||||
{
|
||||
return $transaction->invoice->member->member_id ? $transaction->invoice->member->cm_last_name : $transaction->invoice->guest_data['member']['cm_last_name'];
|
||||
$name = $transaction->invoice->member->member_id ? $transaction->invoice->member->cm_last_name : $transaction->invoice->guest_data['member']['cm_last_name'];
|
||||
|
||||
if( empty( $name ) )
|
||||
{
|
||||
throw new UnexpectedValueException;
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -55,6 +55,7 @@ use function in_array;
|
||||
use function intval;
|
||||
use function is_numeric;
|
||||
use function is_string;
|
||||
use function str_starts_with;
|
||||
use function strlen;
|
||||
use const IPS\CIC;
|
||||
use const IPS\LONG_REQUEST_TIMEOUT;
|
||||
@@ -89,6 +90,19 @@ class Stripe extends Gateway
|
||||
{
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
|
||||
/* Check if we are using test or live keys */
|
||||
if( \IPS\NEXUS_TEST_GATEWAYS )
|
||||
{
|
||||
if( !str_starts_with( $settings['secret_key'], 'sk_test_' ) or !str_starts_with( $settings['publishable_key'], 'pk_test_' ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
elseif( !str_starts_with( $settings['secret_key'], 'sk_live_' ) or !str_starts_with( $settings['publishable_key'], 'pk_live_' ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Stripe has a minimum transaction fee. This is based on the businesses currency, but as we don't know what the transaction rate is
|
||||
we'll do this check only in the transactions we know - anything else will be rejected when the user tries to pay */
|
||||
switch ( $amount->currency )
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace IPS\nexus\Gateway;
|
||||
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use IPS\GeoLocation;
|
||||
use IPS\Helpers\Form;
|
||||
use IPS\nexus\Customer;
|
||||
use IPS\nexus\Gateway;
|
||||
@@ -41,6 +42,25 @@ class Test extends Gateway
|
||||
const SUPPORTS_PARTIAL_REFUNDS = TRUE;
|
||||
|
||||
/* !Payment Gateway */
|
||||
|
||||
/**
|
||||
* Check the gateway can process this...
|
||||
*
|
||||
* @param $amount Money The amount
|
||||
* @param $billingAddress GeoLocation|NULL The billing address, which may be NULL if one if not provided
|
||||
* @param $customer Customer|null The customer (Default NULL value is for backwards compatibility - it should always be provided.)
|
||||
* @param array $recurrings Details about recurring costs
|
||||
* @return bool
|
||||
*/
|
||||
public function checkValidity( Money $amount, ?GeoLocation $billingAddress = NULL, ?Customer $customer = NULL, array $recurrings = array() ) : bool
|
||||
{
|
||||
if( !NEXUS_TEST_GATEWAYS )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return parent::checkValidity( $amount, $billingAddress, $customer, $recurrings );
|
||||
}
|
||||
|
||||
/**
|
||||
* Payment Screen Fields
|
||||
|
||||
@@ -231,7 +231,7 @@ class Item extends ContentItem implements Embeddable
|
||||
* @param array $where Where clause
|
||||
* @param string|null $order MySQL ORDER BY clause (NULL to order by date)
|
||||
* @param int|array|null $limit Limit clause
|
||||
* @param string $permissionKey A key which has a value in the permission map (either of the container or of this class) matching a column ID in core_permission_index or NULL to ignore permissions
|
||||
* @param string|null $permissionKey A key which has a value in the permission map (either of the container or of this class) matching a column ID in core_permission_index or NULL to ignore permissions
|
||||
* @param int|bool|null $includeHiddenItems Include hidden items? NULL to detect if currently logged in member has permission, -1 to return public content only, TRUE to return unapproved content and FALSE to only return unapproved content the viewing member submitted
|
||||
* @param int $queryFlags Select bitwise flags
|
||||
* @param Member|null $member The member (NULL to use currently logged in member)
|
||||
@@ -248,7 +248,7 @@ class Item extends ContentItem implements Embeddable
|
||||
* @param array|null $location Array of item lat and long
|
||||
* @return ActiveRecordIterator|int
|
||||
*/
|
||||
public static function getItemsWithPermission( array $where=array(), string $order=NULL, int|array|null $limit=10, string $permissionKey='read', int|bool|null $includeHiddenItems= Filter::FILTER_AUTOMATIC, int $queryFlags=0, ?Member $member=null, bool $joinContainer=FALSE, bool $joinComments=FALSE, bool $joinReviews=FALSE, bool $countOnly=FALSE, array|null $joins=null, bool|Model $skipPermission=FALSE, bool $joinTags=TRUE, bool $joinAuthor=TRUE, bool $joinLastCommenter=TRUE, bool $showMovedLinks=FALSE, array|null $location=null ): ActiveRecordIterator|int
|
||||
public static function getItemsWithPermission( array $where=array(), string $order=NULL, int|array|null $limit=10, ?string $permissionKey='read', int|bool|null $includeHiddenItems= Filter::FILTER_AUTOMATIC, int $queryFlags=0, ?Member $member=null, bool $joinContainer=FALSE, bool $joinComments=FALSE, bool $joinReviews=FALSE, bool $countOnly=FALSE, array|null $joins=null, bool|Model $skipPermission=FALSE, bool $joinTags=TRUE, bool $joinAuthor=TRUE, bool $joinLastCommenter=TRUE, bool $showMovedLinks=FALSE, array|null $location=null ): ActiveRecordIterator|int
|
||||
{
|
||||
$member = $member ?: Member::loggedIn();
|
||||
|
||||
|
||||
@@ -148,10 +148,17 @@ class Package extends Model
|
||||
*/
|
||||
public static function packageTypes() : array
|
||||
{
|
||||
return array(
|
||||
$return = array(
|
||||
'Product' => 'IPS\nexus\Package\Product',
|
||||
'Ad' => 'IPS\nexus\Package\Ad'
|
||||
);
|
||||
|
||||
foreach( Application::allExtensions( 'nexus', 'PackageType', null, null, null, false ) as $key => $ext )
|
||||
{
|
||||
$return[ $key ] = $ext;
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/* !ActiveRecord */
|
||||
@@ -621,7 +628,7 @@ class Package extends Model
|
||||
catch ( OutOfRangeException ) { }
|
||||
}
|
||||
|
||||
return static::lowestPriceFromData( $customer, $currency, $this->id, json_decode( $this->base_price, TRUE ), json_decode( $this->discounts, TRUE ), $renewOptions, $this->stock, $tax, $priceMayChange, $priceNotIncludingDiscounts, $relevantRenewalTerm );
|
||||
return static::lowestPriceFromData( $customer, $currency, $this->id, json_decode( $this->base_price, TRUE ), ( $this->discounts ? json_decode( $this->discounts, TRUE ) : [] ), $renewOptions, $this->stock, $tax, $priceMayChange, $priceNotIncludingDiscounts, $relevantRenewalTerm );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1105,7 +1112,7 @@ class Package extends Model
|
||||
);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return parent::get__badge();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1330,7 +1337,9 @@ class Package extends Model
|
||||
|
||||
$form->addHeader( 'package_renewals' );
|
||||
$form->add( new YesNo( 'p_renews', !empty( $renewOptions ), FALSE, array( 'togglesOn' => array( 'p_initial_term', 'p_renew_options', 'p_grace_period', 'p_renew', ( $this->id ? "form_{$this->id}" : 'form_new' ) . '_header_package_client_area_renewals', 'p_email_expire_soon_type', 'p_email_expire_type' ) ), NULL, NULL, NULL, 'p_renews' ) );
|
||||
$form->add( new \IPS\nexus\Form\RenewalTerm( 'p_initial_term', $this->initial_term ?: NULL, FALSE, array( 'initialTerm' => TRUE, 'initialTermLang' => 'term_same_as_renewal', 'lockPrice' => TRUE ), NULL, NULL, NULL, 'p_initial_term' ) );
|
||||
|
||||
/* The price is ignored on this field anyway, so we can hard-code to $0 */
|
||||
$form->add( new \IPS\nexus\Form\RenewalTerm( 'p_initial_term', $this->initial_term ? new RenewalTerm( new Money( "0", "USD" ), new DateInterval( "P" . $this->initial_term ) ) : NULL, FALSE, array( 'initialTerm' => TRUE, 'initialTermLang' => 'term_same_as_renewal', 'lockPrice' => TRUE ), NULL, NULL, NULL, 'p_initial_term' ) );
|
||||
$form->add( new Stack( 'p_renew_options', $renewOptions, FALSE, array(
|
||||
'stackFieldType' => 'IPS\nexus\Form\RenewalTerm',
|
||||
'allCurrencies' => TRUE,
|
||||
|
||||
@@ -709,6 +709,20 @@ class Package extends Model
|
||||
return new Money( $priceOfThisPackage - $priceOfExistingPackage, $currency );
|
||||
}
|
||||
}
|
||||
|
||||
/* If the purchase is expired, charge the full amount */
|
||||
if( !$purchase->active or ( $purchase->expire instanceof DateTime and $purchase->expire->getTimestamp() < time() ) )
|
||||
{
|
||||
$newPrice = new Money( $priceOfThisPackage, $currency );
|
||||
|
||||
/* If the package has a free trial, charge the renewal fee instead to stop endless free trials */
|
||||
if( $newPrice->amount->isZero() )
|
||||
{
|
||||
return new Money( $renewalOptionsOnNewPackage['cost'][ $currency ]['amount'], $currency );
|
||||
}
|
||||
|
||||
return new Money( $priceOfThisPackage, $currency );
|
||||
}
|
||||
|
||||
/* It's a recurring subscription */
|
||||
if ( $priceOfThisPackage >= $priceOfExistingPackage )
|
||||
@@ -729,20 +743,6 @@ class Package extends Model
|
||||
return new Money( 0, $currency );
|
||||
|
||||
case 1:
|
||||
/* If the purchase is expired, charge the full amount */
|
||||
if( !$purchase->active or ( $purchase->expire instanceof DateTime and $purchase->expire->getTimestamp() < time() ) )
|
||||
{
|
||||
$newPrice = new Money( $priceOfThisPackage, $currency );
|
||||
|
||||
/* If the package has a free trial, charge the renewal fee instead to stop endless free trials */
|
||||
if( $newPrice->amount->isZero() )
|
||||
{
|
||||
return new Money( $renewalOptionsOnNewPackage['cost'][ $currency ]['amount'], $currency );
|
||||
}
|
||||
|
||||
return new Money( $priceOfThisPackage, $currency );
|
||||
}
|
||||
|
||||
return new Money( $priceOfThisPackage - $priceOfExistingPackage, $currency );
|
||||
|
||||
case 2:
|
||||
|
||||
Reference in new issue
Block a user