Version 5.0.0 beta 1
This commit is contained in:
1 parent
25ddeb65d6
commit
15c7beabc5
6736 files changed
+627902
-497943
No files matched your search
@@ -12,32 +12,42 @@
|
||||
namespace IPS\nexus\Customer;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\DateTime;
|
||||
use IPS\GeoLocation;
|
||||
use IPS\Member;
|
||||
use IPS\nexus\Customer;
|
||||
use IPS\Patterns\ActiveRecord;
|
||||
use function defined;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Customer Address Model
|
||||
*/
|
||||
class _Address extends \IPS\Patterns\ActiveRecord
|
||||
|
||||
/* @property Customer $member */
|
||||
class Address extends ActiveRecord
|
||||
{
|
||||
/**
|
||||
* @brief Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
protected static array $multitons;
|
||||
|
||||
/**
|
||||
* @brief Database Table
|
||||
*/
|
||||
public static $databaseTable = 'nexus_customer_addresses';
|
||||
public static ?string $databaseTable = 'nexus_customer_addresses';
|
||||
|
||||
/**
|
||||
* @brief State Codes
|
||||
* @see https://developer.paypal.com/docs/classic/api/state_codes/
|
||||
*/
|
||||
public static $stateCodes = array(
|
||||
public static array $stateCodes = array(
|
||||
'CA' => array(
|
||||
'AB' => "Alberta",
|
||||
'BC' => "British Columbia",
|
||||
@@ -121,28 +131,28 @@ class _Address extends \IPS\Patterns\ActiveRecord
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setDefaultValues()
|
||||
public function setDefaultValues() : void
|
||||
{
|
||||
$this->added = new \IPS\DateTime;
|
||||
$this->added = new DateTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get member
|
||||
*
|
||||
* @return \IPS\nexus\Customer
|
||||
* @return Customer
|
||||
*/
|
||||
public function get_member()
|
||||
public function get_member(): Customer
|
||||
{
|
||||
return \IPS\nexus\Customer::load( $this->_data['member'] );
|
||||
return Customer::load( $this->_data['member'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set member
|
||||
*
|
||||
* @param \IPS\Member $member Member
|
||||
* @param Member $member Member
|
||||
* @return void
|
||||
*/
|
||||
public function set_member( \IPS\Member $member )
|
||||
public function set_member( Member $member ) : void
|
||||
{
|
||||
$this->_data['member'] = $member->member_id;
|
||||
}
|
||||
@@ -150,20 +160,20 @@ class _Address extends \IPS\Patterns\ActiveRecord
|
||||
/**
|
||||
* Get address
|
||||
*
|
||||
* @return \IPS\GeoLocation
|
||||
* @return GeoLocation
|
||||
*/
|
||||
public function get_address()
|
||||
public function get_address(): GeoLocation
|
||||
{
|
||||
return isset( $this->_data['address'] ) ? \IPS\GeoLocation::buildFromJson( $this->_data['address'] ) : new \IPS\GeoLocation;
|
||||
return isset( $this->_data['address'] ) ? GeoLocation::buildFromJson( $this->_data['address'] ) : new GeoLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set member
|
||||
*
|
||||
* @param \IPS\GeoLocation $address Address
|
||||
* @param GeoLocation $address Address
|
||||
* @return void
|
||||
*/
|
||||
public function set_address( \IPS\GeoLocation $address )
|
||||
public function set_address( GeoLocation $address ) : void
|
||||
{
|
||||
$this->_data['address'] = json_encode( $address );
|
||||
}
|
||||
@@ -171,20 +181,20 @@ class _Address extends \IPS\Patterns\ActiveRecord
|
||||
/**
|
||||
* Get added date
|
||||
*
|
||||
* @return \IPS\DateTime
|
||||
* @return DateTime
|
||||
*/
|
||||
public function get_added()
|
||||
public function get_added(): DateTime
|
||||
{
|
||||
return \IPS\DateTime::ts( $this->_data['added'] );
|
||||
return DateTime::ts( $this->_data['added'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set added date
|
||||
*
|
||||
* @param \IPS\DateTime $date The invoice date
|
||||
* @param DateTime $date The invoice date
|
||||
* @return void
|
||||
*/
|
||||
public function set_added( \IPS\DateTime $date )
|
||||
public function set_added( DateTime $date ) : void
|
||||
{
|
||||
$this->_data['added'] = $date->getTimestamp();
|
||||
}
|
||||
|
||||
@@ -12,49 +12,59 @@
|
||||
namespace IPS\nexus\Customer;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\Db;
|
||||
use IPS\Member;
|
||||
use IPS\nexus\Customer;
|
||||
use IPS\Patterns\ActiveRecord;
|
||||
use IPS\Patterns\ActiveRecordIterator;
|
||||
use IPS\Patterns\Bitwise;
|
||||
use function defined;
|
||||
use function intval;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alternative Contact Model
|
||||
*/
|
||||
class _AlternativeContact extends \IPS\Patterns\ActiveRecord
|
||||
class AlternativeContact extends ActiveRecord
|
||||
{
|
||||
/**
|
||||
* @brief Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
protected static array $multitons;
|
||||
|
||||
/**
|
||||
* @brief Database Table
|
||||
*/
|
||||
public static $databaseTable = 'nexus_alternate_contacts';
|
||||
public static ?string $databaseTable = 'nexus_alternate_contacts';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] ID Database Column
|
||||
*/
|
||||
public static $databaseColumnId = NULL;
|
||||
|
||||
public static string $databaseColumnId = "";
|
||||
|
||||
/**
|
||||
* Get main account
|
||||
*
|
||||
* @return \IPS\nexus\Customer
|
||||
* @return Customer
|
||||
*/
|
||||
public function get_main_id()
|
||||
public function get_main_id() : Customer
|
||||
{
|
||||
return \IPS\nexus\Customer::load( $this->_data['main_id'] );
|
||||
return Customer::load( $this->_data['main_id'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set main account
|
||||
*
|
||||
* @param \IPS\Member $member Member
|
||||
* @param Member $member Member
|
||||
* @return void
|
||||
*/
|
||||
public function set_main_id( \IPS\Member $member )
|
||||
public function set_main_id( Member $member ) : void
|
||||
{
|
||||
$this->_data['main_id'] = $member->member_id;
|
||||
}
|
||||
@@ -62,20 +72,20 @@ class _AlternativeContact extends \IPS\Patterns\ActiveRecord
|
||||
/**
|
||||
* Get alternate account
|
||||
*
|
||||
* @return \IPS\nexus\Customer
|
||||
* @return Customer
|
||||
*/
|
||||
public function get_alt_id()
|
||||
public function get_alt_id() : Customer
|
||||
{
|
||||
return \IPS\nexus\Customer::load( $this->_data['alt_id'] );
|
||||
return Customer::load( $this->_data['alt_id'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set alternate account
|
||||
*
|
||||
* @param \IPS\Member $member Member
|
||||
* @param Member $member Member
|
||||
* @return void
|
||||
*/
|
||||
public function set_alt_id( \IPS\Member $member )
|
||||
public function set_alt_id( Member $member ) : void
|
||||
{
|
||||
$this->_data['alt_id'] = $member->member_id;
|
||||
}
|
||||
@@ -83,11 +93,11 @@ class _AlternativeContact extends \IPS\Patterns\ActiveRecord
|
||||
/**
|
||||
* Get purchases
|
||||
*
|
||||
* @return \IPS\Patterns\ActiveRecordIterator
|
||||
* @return ActiveRecordIterator
|
||||
*/
|
||||
public function get_purchases()
|
||||
public function get_purchases() : ActiveRecordIterator
|
||||
{
|
||||
return new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'nexus_purchases', array( array( 'ps_member=?', $this->main_id->member_id ), \IPS\Db::i()->in( 'ps_id', $this->purchaseIds() ) ) ), 'IPS\nexus\Purchase' );
|
||||
return new ActiveRecordIterator( Db::i()->select( '*', 'nexus_purchases', array( array( 'ps_member=?', $this->main_id->member_id ), Db::i()->in( 'ps_id', $this->purchaseIds() ) ) ), 'IPS\nexus\Purchase' );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,7 +105,7 @@ class _AlternativeContact extends \IPS\Patterns\ActiveRecord
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function purchaseIds()
|
||||
public function purchaseIds() : array
|
||||
{
|
||||
return explode( ',', $this->_data['purchases'] );
|
||||
}
|
||||
@@ -106,17 +116,43 @@ class _AlternativeContact extends \IPS\Patterns\ActiveRecord
|
||||
* @param array $purchases The purchases
|
||||
* @return void
|
||||
*/
|
||||
public function set_purchases( array $purchases )
|
||||
public function set_purchases( array $purchases ) : void
|
||||
{
|
||||
$this->_data['purchases'] = implode( ',', array_keys( $purchases ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct ActiveRecord from database row
|
||||
*
|
||||
* @param array $data Row from database table
|
||||
* @param bool $updateMultitonStoreIfExists Replace current object in multiton store if it already exists there?
|
||||
* @return ActiveRecord
|
||||
*/
|
||||
public static function constructFromData( array $data, bool $updateMultitonStoreIfExists = TRUE ): ActiveRecord
|
||||
{
|
||||
/* Initiate an object */
|
||||
$classname = get_called_class();
|
||||
$obj = new $classname;
|
||||
$obj->_new = FALSE;
|
||||
$obj->_data = array();
|
||||
|
||||
/* Import data */
|
||||
foreach ( $data as $k => $v )
|
||||
{
|
||||
$obj->_data[ $k ] = $v;
|
||||
}
|
||||
|
||||
$obj->changed = array();
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save Changed Columns
|
||||
*
|
||||
* @return void
|
||||
* @return void
|
||||
*/
|
||||
public function save()
|
||||
public function save(): void
|
||||
{
|
||||
if ( $this->_new )
|
||||
{
|
||||
@@ -133,14 +169,13 @@ class _AlternativeContact extends \IPS\Patterns\ActiveRecord
|
||||
{
|
||||
foreach( $this->$k->values as $field => $value )
|
||||
{
|
||||
$data[ $field ] = \intval( $value );
|
||||
$data[ $field ] = intval( $value );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $this->_new )
|
||||
{
|
||||
$insert = array();
|
||||
if( static::$databasePrefix === NULL )
|
||||
{
|
||||
$insert = $data;
|
||||
@@ -188,9 +223,9 @@ class _AlternativeContact extends \IPS\Patterns\ActiveRecord
|
||||
/**
|
||||
* [ActiveRecord] Delete Record
|
||||
*
|
||||
* @return void
|
||||
* @return void
|
||||
*/
|
||||
public function delete()
|
||||
public function delete(): void
|
||||
{
|
||||
static::db()->delete( 'nexus_alternate_contacts', array( 'main_id=? AND alt_id=?', $this->_data['main_id'], $this->_data['alt_id'] ) );
|
||||
}
|
||||
|
||||
@@ -12,16 +12,43 @@
|
||||
namespace IPS\nexus\Customer;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use DomainException;
|
||||
use IPS\DateTime;
|
||||
use IPS\Db;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Member;
|
||||
use IPS\nexus\Customer;
|
||||
use IPS\nexus\Gateway;
|
||||
use IPS\nexus\Invoice;
|
||||
use IPS\nexus\Invoice\Item\Renewal;
|
||||
use IPS\nexus\Transaction;
|
||||
use IPS\Patterns\ActiveRecord;
|
||||
use IPS\Patterns\ActiveRecordIterator;
|
||||
use OutOfRangeException;
|
||||
use UnderflowException;
|
||||
use function defined;
|
||||
use function strlen;
|
||||
use function substr;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Billing Agreement Model
|
||||
*
|
||||
* @method status() : string
|
||||
* @method nextPaymentDate() : DateTime
|
||||
* @method doSuspend()
|
||||
* @method doReactivate()
|
||||
* @method doCancel()
|
||||
* @method latestUnclaimedTransaction() : Transaction
|
||||
* @method term() : RenewalTerm
|
||||
*/
|
||||
class _BillingAgreement extends \IPS\Patterns\ActiveRecord
|
||||
class BillingAgreement extends ActiveRecord
|
||||
{
|
||||
/**
|
||||
* @brief Billing Agreement is active and will charge automatically
|
||||
@@ -41,28 +68,28 @@ class _BillingAgreement extends \IPS\Patterns\ActiveRecord
|
||||
/**
|
||||
* @brief Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
protected static array $multitons;
|
||||
|
||||
/**
|
||||
* @brief Database Table
|
||||
*/
|
||||
public static $databaseTable = 'nexus_billing_agreements';
|
||||
public static ?string $databaseTable = 'nexus_billing_agreements';
|
||||
|
||||
/**
|
||||
* @brief Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'ba_';
|
||||
public static string $databasePrefix = 'ba_';
|
||||
|
||||
/**
|
||||
* Construct ActiveRecord from database row
|
||||
*
|
||||
* @param array $data Row from database table
|
||||
* @param bool $updateMultitonStoreIfExists Replace current object in multiton store if it already exists there?
|
||||
* @return static
|
||||
* @param array $data Row from database table
|
||||
* @param bool $updateMultitonStoreIfExists Replace current object in multiton store if it already exists there?
|
||||
* @return static
|
||||
*/
|
||||
public static function constructFromData( $data, $updateMultitonStoreIfExists = TRUE )
|
||||
public static function constructFromData( array $data, bool $updateMultitonStoreIfExists = TRUE ): static
|
||||
{
|
||||
$gateway = \IPS\nexus\Gateway::load( $data['ba_method'] );
|
||||
$gateway = Gateway::load( $data['ba_method'] );
|
||||
$classname = 'IPS\nexus\Gateway\\' . $gateway->gateway . '\\BillingAgreement';
|
||||
|
||||
/* Initiate an object */
|
||||
@@ -74,7 +101,7 @@ class _BillingAgreement extends \IPS\Patterns\ActiveRecord
|
||||
{
|
||||
if( static::$databasePrefix AND mb_strpos( $k, static::$databasePrefix ) === 0 )
|
||||
{
|
||||
$k = \substr( $k, \strlen( static::$databasePrefix ) );
|
||||
$k = substr( $k, strlen( static::$databasePrefix ) );
|
||||
}
|
||||
|
||||
$obj->_data[ $k ] = $v;
|
||||
@@ -94,17 +121,17 @@ class _BillingAgreement extends \IPS\Patterns\ActiveRecord
|
||||
/**
|
||||
* Load and check permissions
|
||||
*
|
||||
* @param mixed $id ID to load
|
||||
* @return \IPS\Content\Item
|
||||
* @throws \OutOfRangeException
|
||||
* @param int $id ID to load
|
||||
* @return static
|
||||
* @throws OutOfRangeException
|
||||
*/
|
||||
public static function loadAndCheckPerms( $id )
|
||||
public static function loadAndCheckPerms( int $id ) : static
|
||||
{
|
||||
$obj = static::load( $id );
|
||||
|
||||
if ( !$obj->canView() )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
throw new OutOfRangeException;
|
||||
}
|
||||
|
||||
return $obj;
|
||||
@@ -113,12 +140,12 @@ class _BillingAgreement extends \IPS\Patterns\ActiveRecord
|
||||
/**
|
||||
* Member can view?
|
||||
*
|
||||
* @param \IPS\Member|NULL $member The member to check for, or NULL for currently logged in member
|
||||
* @param Member|NULL $member The member to check for, or NULL for currently logged in member
|
||||
* @return bool
|
||||
*/
|
||||
public function canView( \IPS\Member $member = NULL )
|
||||
public function canView( Member $member = null ) : bool
|
||||
{
|
||||
$member = $member ?: \IPS\Member::loggedIn();
|
||||
$member = $member ?: Member::loggedIn();
|
||||
|
||||
return $this->member->member_id === $member->member_id or array_key_exists( $member->member_id, iterator_to_array( $this->member->alternativeContacts( array( 'billing=1' ) ) ) );
|
||||
}
|
||||
@@ -126,20 +153,20 @@ class _BillingAgreement extends \IPS\Patterns\ActiveRecord
|
||||
/**
|
||||
* Get member
|
||||
*
|
||||
* @return \IPS\Member
|
||||
* @return Customer
|
||||
*/
|
||||
public function get_member()
|
||||
public function get_member() : Customer
|
||||
{
|
||||
return \IPS\nexus\Customer::load( $this->_data['member'] );
|
||||
return Customer::load( $this->_data['member'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set member
|
||||
*
|
||||
* @param \IPS\Member $member Member
|
||||
* @param Member $member Member
|
||||
* @return void
|
||||
*/
|
||||
public function set_member( \IPS\Member $member )
|
||||
public function set_member( Member $member ) : void
|
||||
{
|
||||
$this->_data['member'] = $member->member_id;
|
||||
}
|
||||
@@ -147,20 +174,20 @@ class _BillingAgreement extends \IPS\Patterns\ActiveRecord
|
||||
/**
|
||||
* Get payment gateway
|
||||
*
|
||||
* @return \IPS\nexus\Gateway
|
||||
* @return Gateway
|
||||
*/
|
||||
public function get_method()
|
||||
public function get_method() : Gateway
|
||||
{
|
||||
return \IPS\nexus\Gateway::load( $this->_data['method'] );
|
||||
return Gateway::load( $this->_data['method'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set payment gateway
|
||||
*
|
||||
* @param \IPS\nexus\Gateway $gateway Payment gateway
|
||||
* @param Gateway $gateway Payment gateway
|
||||
* @return void
|
||||
*/
|
||||
public function set_method( \IPS\nexus\Gateway $gateway )
|
||||
public function set_method( Gateway $gateway ) : void
|
||||
{
|
||||
$this->_data['method'] = $gateway->id;
|
||||
}
|
||||
@@ -168,41 +195,41 @@ class _BillingAgreement extends \IPS\Patterns\ActiveRecord
|
||||
/**
|
||||
* Get start date
|
||||
*
|
||||
* @return \IPS\DateTime
|
||||
* @return DateTime
|
||||
*/
|
||||
public function get_started()
|
||||
public function get_started() : DateTime
|
||||
{
|
||||
return \IPS\DateTime::ts( $this->_data['started'] );
|
||||
return DateTime::ts( $this->_data['started'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set next payment date
|
||||
*
|
||||
* @param \IPS\DateTime $date The invoice date
|
||||
* @param DateTime|null $date The invoice date
|
||||
* @return void
|
||||
*/
|
||||
public function set_next_cycle( \IPS\DateTime $date = NULL )
|
||||
public function set_next_cycle( ?DateTime $date = NULL ) : void
|
||||
{
|
||||
$this->_data['next_cycle'] = $date ? $date->getTimestamp() : NULL;
|
||||
$this->_data['next_cycle'] = $date?->getTimestamp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get next payment date
|
||||
*
|
||||
* @return \IPS\DateTime
|
||||
* @return DateTime|null
|
||||
*/
|
||||
public function get_next_cycle()
|
||||
public function get_next_cycle() : DateTime|null
|
||||
{
|
||||
return $this->_data['next_cycle'] ? \IPS\DateTime::ts( $this->_data['next_cycle'] ) : NULL;
|
||||
return $this->_data['next_cycle'] ? DateTime::ts( $this->_data['next_cycle'] ) : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set start date
|
||||
*
|
||||
* @param \IPS\DateTime $date The invoice date
|
||||
* @param DateTime $date The invoice date
|
||||
* @return void
|
||||
*/
|
||||
public function set_started( \IPS\DateTime $date )
|
||||
public function set_started( DateTime $date ) : void
|
||||
{
|
||||
$this->_data['started'] = $date->getTimestamp();
|
||||
}
|
||||
@@ -211,9 +238,9 @@ class _BillingAgreement extends \IPS\Patterns\ActiveRecord
|
||||
* Suspend
|
||||
*
|
||||
* @return void
|
||||
* @throws \DomainException
|
||||
* @throws DomainException
|
||||
*/
|
||||
public function refresh()
|
||||
public function refresh() : void
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -222,7 +249,7 @@ class _BillingAgreement extends \IPS\Patterns\ActiveRecord
|
||||
$this->checkForLatestTransaction();
|
||||
}
|
||||
}
|
||||
catch( \OutOfRangeException | \UnderflowException $e )
|
||||
catch( OutOfRangeException | UnderflowException )
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -232,9 +259,9 @@ class _BillingAgreement extends \IPS\Patterns\ActiveRecord
|
||||
* Suspend
|
||||
*
|
||||
* @return void
|
||||
* @throws \DomainException
|
||||
* @throws DomainException
|
||||
*/
|
||||
public function suspend()
|
||||
public function suspend() : void
|
||||
{
|
||||
$this->doSuspend();
|
||||
|
||||
@@ -247,9 +274,9 @@ class _BillingAgreement extends \IPS\Patterns\ActiveRecord
|
||||
* Reactivate
|
||||
*
|
||||
* @return void
|
||||
* @throws \DomainException
|
||||
* @throws DomainException
|
||||
*/
|
||||
public function reactivate()
|
||||
public function reactivate() : void
|
||||
{
|
||||
$this->doReactivate();
|
||||
|
||||
@@ -262,9 +289,9 @@ class _BillingAgreement extends \IPS\Patterns\ActiveRecord
|
||||
* Cancel
|
||||
*
|
||||
* @return void
|
||||
* @throws \DomainException
|
||||
* @throws DomainException
|
||||
*/
|
||||
public function cancel()
|
||||
public function cancel() : void
|
||||
{
|
||||
$this->doCancel();
|
||||
|
||||
@@ -277,21 +304,21 @@ class _BillingAgreement extends \IPS\Patterns\ActiveRecord
|
||||
/**
|
||||
* Front-End URL
|
||||
*
|
||||
* @return \IPS\Http\Url
|
||||
* @return Url
|
||||
*/
|
||||
public function url()
|
||||
function url(): Url
|
||||
{
|
||||
return \IPS\Http\Url::internal( "app=nexus&module=clients&controller=billingagreements&do=view&id={$this->id}", 'front', 'clientsbillingagreement' );
|
||||
return Url::internal( "app=nexus&module=clients&controller=billingagreements&do=view&id={$this->id}", 'front', 'clientsbillingagreement' );
|
||||
}
|
||||
|
||||
/**
|
||||
* ACP URL
|
||||
*
|
||||
* @return \IPS\Http\Url
|
||||
* @return Url
|
||||
*/
|
||||
public function acpUrl()
|
||||
public function acpUrl() : Url
|
||||
{
|
||||
return \IPS\Http\Url::internal( "app=nexus&module=payments&controller=billingagreements&id={$this->id}", 'admin' );
|
||||
return Url::internal( "app=nexus&module=payments&controller=billingagreements&id={$this->id}", 'admin' );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -299,7 +326,7 @@ class _BillingAgreement extends \IPS\Patterns\ActiveRecord
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function checkForLatestTransaction()
|
||||
public function checkForLatestTransaction() : void
|
||||
{
|
||||
/* Fetch the latest unclaimed transaction */
|
||||
try
|
||||
@@ -307,11 +334,11 @@ class _BillingAgreement extends \IPS\Patterns\ActiveRecord
|
||||
$transaction = $this->latestUnclaimedTransaction();
|
||||
}
|
||||
/* If there isn't one yet, it might just be that PayPal hasn't taken it yet. Let it try for up to 11 days before giving up, which is how long PayPal will try for if there's an issue. */
|
||||
catch ( \OutOfRangeException $e )
|
||||
catch ( OutOfRangeException $e )
|
||||
{
|
||||
if ( $this->next_cycle->getTimestamp() > ( time() - ( 86400 * 11 ) ) )
|
||||
{
|
||||
throw new \UnderflowException;
|
||||
throw new UnderflowException;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -323,7 +350,7 @@ class _BillingAgreement extends \IPS\Patterns\ActiveRecord
|
||||
$this->next_cycle = $nextPaymentDate;
|
||||
$this->save();
|
||||
|
||||
throw new \UnderflowException;
|
||||
throw new UnderflowException;
|
||||
}
|
||||
|
||||
throw $e;
|
||||
@@ -331,17 +358,17 @@ class _BillingAgreement extends \IPS\Patterns\ActiveRecord
|
||||
}
|
||||
|
||||
/* Get purchases */
|
||||
$purchases = new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'nexus_purchases', array( 'ps_billing_agreement=?', $this->id ) ), 'IPS\nexus\Purchase' );
|
||||
$purchases = new ActiveRecordIterator( Db::i()->select( '*', 'nexus_purchases', array( 'ps_billing_agreement=?', $this->id ) ), 'IPS\nexus\Purchase' );
|
||||
|
||||
/* Generate an invoice */
|
||||
$invoice = new \IPS\nexus\Invoice;
|
||||
$invoice = new Invoice;
|
||||
$invoice->system = TRUE;
|
||||
$invoice->currency = $transaction->amount->currency;
|
||||
$invoice->member = $this->member;
|
||||
$invoice->billaddress = $this->member->primaryBillingAddress();
|
||||
foreach ( $purchases as $purchase )
|
||||
{
|
||||
$invoice->addItem( \IPS\nexus\Invoice\Item\Renewal::create( $purchase ) );
|
||||
$invoice->addItem( Renewal::create( $purchase ) );
|
||||
}
|
||||
$invoice->save();
|
||||
|
||||
@@ -354,7 +381,7 @@ class _BillingAgreement extends \IPS\Patterns\ActiveRecord
|
||||
/* Log */
|
||||
$invoice->member->log( 'transaction', array(
|
||||
'type' => 'paid',
|
||||
'status' => \IPS\nexus\Transaction::STATUS_PAID,
|
||||
'status' => Transaction::STATUS_PAID,
|
||||
'id' => $transaction->id,
|
||||
'invoice_id' => $invoice->id,
|
||||
'invoice_title' => $invoice->title,
|
||||
|
||||
@@ -12,43 +12,66 @@
|
||||
namespace IPS\nexus\Customer;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use DomainException;
|
||||
use Exception;
|
||||
use IPS\Helpers\Form;
|
||||
use IPS\Helpers\Form\Radio;
|
||||
use IPS\Member;
|
||||
use IPS\nexus\Customer;
|
||||
use IPS\nexus\Gateway;
|
||||
use IPS\nexus\Invoice;
|
||||
use IPS\nexus\Transaction;
|
||||
use IPS\Patterns\ActiveRecord;
|
||||
use IPS\Theme;
|
||||
use function count;
|
||||
use function defined;
|
||||
use function is_array;
|
||||
use function strlen;
|
||||
use function substr;
|
||||
|
||||
/* @property Customer $member
|
||||
* @property \IPS\nexus\CreditCard $card
|
||||
*/
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Customer Stored Card Model
|
||||
*/
|
||||
class _CreditCard extends \IPS\Patterns\ActiveRecord
|
||||
|
||||
/* @property Customer $member */
|
||||
class CreditCard extends ActiveRecord
|
||||
{
|
||||
/**
|
||||
* @brief Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
protected static array $multitons;
|
||||
|
||||
/**
|
||||
* @brief Database Table
|
||||
*/
|
||||
public static $databaseTable = 'nexus_customer_cards';
|
||||
public static ?string $databaseTable = 'nexus_customer_cards';
|
||||
|
||||
/**
|
||||
* @brief Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'card_';
|
||||
public static string $databasePrefix = 'card_';
|
||||
|
||||
/**
|
||||
* Construct ActiveRecord from database row
|
||||
*
|
||||
* @param array $data Row from database table
|
||||
* @param bool $updateMultitonStoreIfExists Replace current object in multiton store if it already exists there?
|
||||
* @return static
|
||||
* @param array $data Row from database table
|
||||
* @param bool $updateMultitonStoreIfExists Replace current object in multiton store if it already exists there?
|
||||
* @return static
|
||||
*/
|
||||
public static function constructFromData( $data, $updateMultitonStoreIfExists = TRUE )
|
||||
public static function constructFromData( array $data, bool $updateMultitonStoreIfExists = TRUE ): static
|
||||
{
|
||||
$gateway = \IPS\nexus\Gateway::load( $data['card_method'] );
|
||||
$classname = \IPS\nexus\Gateway::gateways()[ $gateway->gateway ] . '\\CreditCard';
|
||||
$gateway = Gateway::load( $data['card_method'] );
|
||||
$classname = Gateway::gateways()[ $gateway->gateway ] . '\\CreditCard';
|
||||
|
||||
/* Initiate an object */
|
||||
$obj = new $classname;
|
||||
@@ -57,13 +80,13 @@ class _CreditCard extends \IPS\Patterns\ActiveRecord
|
||||
/* Import data */
|
||||
if ( static::$databasePrefix )
|
||||
{
|
||||
$databasePrefixLength = \strlen( static::$databasePrefix );
|
||||
$databasePrefixLength = strlen( static::$databasePrefix );
|
||||
}
|
||||
foreach ( $data as $k => $v )
|
||||
{
|
||||
if( static::$databasePrefix AND mb_strpos( $k, static::$databasePrefix ) === 0 )
|
||||
{
|
||||
$k = \substr( $k, $databasePrefixLength );
|
||||
$k = substr( $k, $databasePrefixLength );
|
||||
}
|
||||
|
||||
$obj->_data[ $k ] = $v;
|
||||
@@ -83,13 +106,13 @@ class _CreditCard extends \IPS\Patterns\ActiveRecord
|
||||
/**
|
||||
* Add Form
|
||||
*
|
||||
* @param \IPS\nexus\Customer $customer The customer
|
||||
* @param Customer $customer The customer
|
||||
* @param bool $admin Set to TRUE if the *admin* (opposed to the customer themselves) wants to create a new payment method
|
||||
* @return \IPS\Helpers\Form|\IPS\nexus\CreditCard
|
||||
* @return string|CreditCard
|
||||
*/
|
||||
public static function create( \IPS\nexus\Customer $customer, $admin )
|
||||
public static function create( Customer $customer, bool $admin ) : string|CreditCard
|
||||
{
|
||||
$form = new \IPS\Helpers\Form;
|
||||
$form = new Form;
|
||||
$showSubmitButton = FALSE;
|
||||
$hiddenValues = array();
|
||||
foreach ( static::createFormElements( $customer, $admin, $showSubmitButton, $hiddenValues ) as $element )
|
||||
@@ -107,62 +130,33 @@ class _CreditCard extends \IPS\Patterns\ActiveRecord
|
||||
{
|
||||
return static::createFormSubmit( $values, $customer, $admin );
|
||||
}
|
||||
catch ( \DomainException $e )
|
||||
catch ( DomainException $e )
|
||||
{
|
||||
$form->error = $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
return $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'nexus', 'global' ), 'addPaymentMethodForm' ), $showSubmitButton );
|
||||
return $form->customTemplate( array( Theme::i()->getTemplate( 'forms', 'nexus', 'global' ), 'addPaymentMethodForm' ), $showSubmitButton );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get form elements for creating a new card
|
||||
*
|
||||
* @param \IPS\nexus\Customer $customer The customer
|
||||
* @param Customer $customer The customer
|
||||
* @param bool $admin Set to TRUE if the *admin* (opposed to the customer themselves) wants to create a new payment method
|
||||
* @param bool $showSubmitButton Will be set to a bool indicating if the submit button should be shown
|
||||
* @param array $hiddenValues Hidden values to add to the form
|
||||
* @param array|null $allowedPaymentMethods Payment method IDs that should be included. Populated when called from checkout.
|
||||
* @return array
|
||||
*/
|
||||
public static function createFormElements( \IPS\nexus\Customer $customer, $admin, &$showSubmitButton, &$hiddenValues, $allowedPaymentMethods=null )
|
||||
public static function createFormElements( Customer $customer, bool $admin, bool &$showSubmitButton, array &$hiddenValues ) : array
|
||||
{
|
||||
$gateways = \IPS\nexus\Gateway::cardStorageGateways( $admin );
|
||||
|
||||
/* Remove any gateways that can't be used here */
|
||||
if( !empty( $allowedPaymentMethods ) )
|
||||
{
|
||||
foreach( $gateways as $id => $gateway )
|
||||
{
|
||||
if( !\in_array( $id, $allowedPaymentMethods ) )
|
||||
{
|
||||
unset( $gateways[ $id ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif( $address = $customer->primaryBillingAddress() )
|
||||
{
|
||||
/* If we're not coming from the checkout, we're trying to manually add a card.
|
||||
Check the user's country, and if it's not available, skip it */
|
||||
foreach( $gateways as $id => $gateway )
|
||||
{
|
||||
/* @var \IPS\nexus\Gateway $gateway */
|
||||
if( $gateway->countries !== '*' )
|
||||
{
|
||||
if( !\in_array( $address->country, explode( ',', $gateway->countries ) ) )
|
||||
{
|
||||
unset( $gateways[ $id ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$gateways = Gateway::cardStorageGateways( $admin );
|
||||
|
||||
$elements = array();
|
||||
$paymentMethodsToggles = array();
|
||||
foreach ( $gateways as $gateway )
|
||||
{
|
||||
$invoice = new \IPS\nexus\Invoice;
|
||||
$invoice = new Invoice;
|
||||
$invoice->currency = $customer->defaultCurrency();
|
||||
foreach ( $gateway->paymentScreen( $invoice, $invoice->total, $customer, array(), 'card' ) as $element )
|
||||
{
|
||||
@@ -179,11 +173,10 @@ class _CreditCard extends \IPS\Patterns\ActiveRecord
|
||||
}
|
||||
}
|
||||
|
||||
if ( \count( $gateways ) > 1 )
|
||||
if ( count( $gateways ) > 1 )
|
||||
{
|
||||
$showSubmitButton = FALSE;
|
||||
$options = array();
|
||||
$toggles = array();
|
||||
foreach ( $gateways as $gateway )
|
||||
{
|
||||
$options[ $gateway->id ] = $gateway->_title;
|
||||
@@ -194,8 +187,8 @@ class _CreditCard extends \IPS\Patterns\ActiveRecord
|
||||
}
|
||||
}
|
||||
|
||||
$element = new \IPS\Helpers\Form\Radio( 'payment_method', NULL, TRUE, array( 'options' => $options, 'toggles' => $paymentMethodsToggles ) );
|
||||
$element->label = \IPS\Member::loggedIn()->language()->addToStack('card_gateway');
|
||||
$element = new Radio( 'payment_method', NULL, TRUE, array( 'options' => $options, 'toggles' => $paymentMethodsToggles ) );
|
||||
$element->label = Member::loggedIn()->language()->addToStack('card_gateway');
|
||||
|
||||
array_unshift( $elements, $element );
|
||||
}
|
||||
@@ -215,41 +208,41 @@ class _CreditCard extends \IPS\Patterns\ActiveRecord
|
||||
* Handle submission of the form for creating a new card
|
||||
*
|
||||
* @param array $values Values from the form
|
||||
* @param \IPS\nexus\Customer $customer The customer
|
||||
* @param Customer $customer The customer
|
||||
* @param bool $admin Set to TRUE if the *admin* (opposed to the customer themselves) wants to create a new payment method
|
||||
* @param ?\IPS\nexus\Invoice $invoice If customer is a guest, will sa`ve the guest data onto the provided invoice
|
||||
* @return \IPS\nexus\CreditCard
|
||||
* @throws \DomainException
|
||||
* @param ?Invoice $invoice If customer is a guest, will sa`ve the guest data onto the provided invoice
|
||||
* @return CreditCard
|
||||
* @throws DomainException
|
||||
*/
|
||||
public static function createFormSubmit( $values, $customer, $admin, \IPS\nexus\Invoice $invoice = NULL )
|
||||
public static function createFormSubmit( array $values, Customer $customer, bool $admin, ?Invoice $invoice = NULL ) : CreditCard
|
||||
{
|
||||
if ( isset( $values['payment_method'] ) )
|
||||
{
|
||||
if ( $values['payment_method'] != 0 )
|
||||
{
|
||||
$gateway = \IPS\nexus\Gateway::load( $values['payment_method'] );
|
||||
$gateway = Gateway::load( $values['payment_method'] );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$gateways = \IPS\nexus\Gateway::cardStorageGateways( $admin );
|
||||
$gateways = Gateway::cardStorageGateways( $admin );
|
||||
$gateway = array_pop( $gateways );
|
||||
}
|
||||
|
||||
if ( !$values[ $gateway->id . '_card' ] )
|
||||
{
|
||||
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack('card_number_invalid') );
|
||||
throw new DomainException( Member::loggedIn()->language()->addToStack('card_number_invalid') );
|
||||
}
|
||||
else
|
||||
{
|
||||
$classname = \IPS\nexus\Gateway::gateways()[ $gateway->gateway ] . '\\CreditCard';
|
||||
$classname = Gateway::gateways()[ $gateway->gateway ] . '\\CreditCard';
|
||||
$card = new $classname;
|
||||
$card->member = $customer;
|
||||
$card->method = $gateway;
|
||||
|
||||
if ( \is_array( $values[ $gateway->id . '_card' ] ) )
|
||||
if ( is_array( $values[ $gateway->id . '_card' ] ) )
|
||||
{
|
||||
$_card = new \IPS\nexus\CreditCard;
|
||||
$_card = new CreditCard;
|
||||
$_card->token = $values[ $gateway->id . '_card' ]['token'];
|
||||
$card->set_card( $_card, $invoice );
|
||||
}
|
||||
@@ -268,20 +261,20 @@ class _CreditCard extends \IPS\Patterns\ActiveRecord
|
||||
/**
|
||||
* Get member
|
||||
*
|
||||
* @return \IPS\Member
|
||||
* @return Customer
|
||||
*/
|
||||
public function get_member()
|
||||
public function get_member() : Customer
|
||||
{
|
||||
return \IPS\nexus\Customer::load( $this->_data['member'] );
|
||||
return Customer::load( $this->_data['member'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set member
|
||||
*
|
||||
* @param \IPS\Member $member Member
|
||||
* @param Member $member Member
|
||||
* @return void
|
||||
*/
|
||||
public function set_member( \IPS\Member $member )
|
||||
public function set_member( Member $member ) : void
|
||||
{
|
||||
$this->_data['member'] = $member->member_id ?: 0;
|
||||
}
|
||||
@@ -289,21 +282,83 @@ class _CreditCard extends \IPS\Patterns\ActiveRecord
|
||||
/**
|
||||
* Get payment gateway
|
||||
*
|
||||
* @return \IPS\nexus\Gateway
|
||||
* @return Gateway
|
||||
*/
|
||||
public function get_method()
|
||||
public function get_method() : Gateway
|
||||
{
|
||||
return \IPS\nexus\Gateway::load( $this->_data['method'] );
|
||||
return Gateway::load( $this->_data['method'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set payment gateway
|
||||
*
|
||||
* @param \IPS\nexus\Gateway $gateway Payment gateway
|
||||
* @param Gateway $gateway Payment gateway
|
||||
* @return void
|
||||
*/
|
||||
public function set_method( \IPS\nexus\Gateway $gateway )
|
||||
public function set_method( Gateway $gateway ) : void
|
||||
{
|
||||
$this->_data['method'] = $gateway->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Automatically take payment
|
||||
*
|
||||
* @param Invoice $invoice
|
||||
* @return Transaction
|
||||
* @throws Exception
|
||||
*/
|
||||
public function takePayment( Invoice $invoice ) : Transaction
|
||||
{
|
||||
$cardDetails = $this->card; // We're just checking this doesn't throw an exception
|
||||
|
||||
$amountToPay = $invoice->amountToPay();
|
||||
$gateway = $this->method;
|
||||
|
||||
$transaction = new Transaction;
|
||||
$transaction->member = $invoice->member;
|
||||
$transaction->invoice = $invoice;
|
||||
$transaction->method = $gateway;
|
||||
$transaction->amount = $amountToPay;
|
||||
$transaction->currency = $amountToPay->currency;
|
||||
$transaction->extra = array( 'automatic' => TRUE );
|
||||
|
||||
try
|
||||
{
|
||||
$transaction->auth = $gateway->auth( $transaction, array(
|
||||
( $gateway->id . '_card' ) => $this
|
||||
), NULL, array(), 'renewal' );
|
||||
$transaction->capture();
|
||||
|
||||
$transaction->member->log( 'transaction', array(
|
||||
'type' => 'paid',
|
||||
'status' => Transaction::STATUS_PAID,
|
||||
'id' => $transaction->id,
|
||||
'invoice_id' => $invoice->id,
|
||||
'invoice_title' => $invoice->title,
|
||||
'automatic' => TRUE,
|
||||
), FALSE );
|
||||
|
||||
$transaction->approve();
|
||||
return $transaction;
|
||||
}
|
||||
catch ( Exception $e )
|
||||
{
|
||||
$transaction->status = Transaction::STATUS_REFUSED;
|
||||
$extra = $transaction->extra;
|
||||
$extra['history'][] = array( 's' => Transaction::STATUS_REFUSED, 'noteRaw' => $e->getMessage() );
|
||||
$transaction->extra = $extra;
|
||||
$transaction->save();
|
||||
|
||||
$transaction->member->log( 'transaction', array(
|
||||
'type' => 'paid',
|
||||
'status' => Transaction::STATUS_REFUSED,
|
||||
'id' => $transaction->id,
|
||||
'invoice_id' => $invoice->id,
|
||||
'invoice_title' => $invoice->title,
|
||||
'automatic' => TRUE,
|
||||
), FALSE );
|
||||
|
||||
return $transaction;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,46 +12,57 @@
|
||||
namespace IPS\nexus\Customer;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\CustomField as SystemCustomField;
|
||||
use IPS\Helpers\Form;
|
||||
use IPS\Helpers\Form\YesNo;
|
||||
use IPS\Login;
|
||||
use IPS\Member\ProfileStep;
|
||||
use IPS\Settings;
|
||||
use IPS\Widget;
|
||||
use function count;
|
||||
use function defined;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom Profile Field Node
|
||||
*/
|
||||
class _CustomField extends \IPS\CustomField
|
||||
class CustomField extends SystemCustomField
|
||||
{
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
protected static array $multitons;
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Table
|
||||
*/
|
||||
public static $databaseTable = 'nexus_customer_fields';
|
||||
public static ?string $databaseTable = 'nexus_customer_fields';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'f_';
|
||||
public static string $databasePrefix = 'f_';
|
||||
|
||||
/**
|
||||
* @brief [Node] Order Database Column
|
||||
*/
|
||||
public static $databaseColumnOrder = 'position';
|
||||
public static ?string $databaseColumnOrder = 'position';
|
||||
|
||||
/**
|
||||
* @brief [CustomField] Title/Description lang prefix
|
||||
*/
|
||||
protected static $langKey = 'nexus_ccfield';
|
||||
protected static string $langKey = 'nexus_ccfield';
|
||||
|
||||
/**
|
||||
* @brief [CustomField] Content database table
|
||||
*/
|
||||
protected static $contentDatabaseTable = 'nexus_customers';
|
||||
protected static string $contentDatabaseTable = 'nexus_customers';
|
||||
|
||||
/**
|
||||
* @brief [Node] ACP Restrictions
|
||||
@@ -69,7 +80,7 @@ class _CustomField extends \IPS\CustomField
|
||||
'prefix' => 'foo_', // [Optional] Rather than specifying each key in the map, you can specify a prefix, and it will automatically look for restrictions with the key "[prefix]_add/edit/permissions/delete"
|
||||
* @endcode
|
||||
*/
|
||||
protected static $restrictions = array(
|
||||
protected static ?array $restrictions = array(
|
||||
'app' => 'nexus',
|
||||
'module' => 'customers',
|
||||
'prefix' => 'customer_fields_'
|
||||
@@ -78,17 +89,17 @@ class _CustomField extends \IPS\CustomField
|
||||
/**
|
||||
* @brief [Node] Node Title
|
||||
*/
|
||||
public static $nodeTitle = 'nexus_customer_fields';
|
||||
public static string $nodeTitle = 'nexus_customer_fields';
|
||||
|
||||
/**
|
||||
* @brief [Node] Title prefix. If specified, will look for a language key with "{$key}_title" as the key
|
||||
*/
|
||||
public static $titleLangPrefix = 'nexus_ccfield_';
|
||||
public static ?string $titleLangPrefix = 'nexus_ccfield_';
|
||||
|
||||
/**
|
||||
* @brief [CustomField] Column Map
|
||||
*/
|
||||
public static $databaseColumnMap = array(
|
||||
public static array $databaseColumnMap = array(
|
||||
'content' => 'extra',
|
||||
'not_null' => 'reg_require'
|
||||
);
|
||||
@@ -96,34 +107,34 @@ class _CustomField extends \IPS\CustomField
|
||||
/**
|
||||
* @brief [CustomField] Editor Options
|
||||
*/
|
||||
public static $editorOptions = array( 'app' => 'nexus', 'key' => 'Customer' );
|
||||
public static array $editorOptions = array( 'app' => 'nexus', 'key' => 'Customer' );
|
||||
|
||||
/**
|
||||
* @brief [CustomField] Upload Storage Extension
|
||||
*/
|
||||
public static $uploadStorageExtension = 'nexus_Customer';
|
||||
public static string $uploadStorageExtension = 'nexus_Customer';
|
||||
|
||||
/**
|
||||
* [Node] Add/Edit Form
|
||||
*
|
||||
* @param \IPS\Helpers\Form $form The form
|
||||
* @param Form $form The form
|
||||
* @return void
|
||||
*/
|
||||
public function form( &$form )
|
||||
public function form( Form &$form ) : void
|
||||
{
|
||||
parent::form( $form );
|
||||
|
||||
if ( \IPS\Login::registrationType() == 'full' )
|
||||
if ( Login::registrationType() == 'full' )
|
||||
{
|
||||
/* Quick register is disabled */
|
||||
$form->addHeader( 'customer_field_registration' );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'f_reg_show', $this->reg_show ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'f_reg_require', $this->reg_require ) );
|
||||
$form->add( new YesNo( 'f_reg_show', $this->reg_show ) );
|
||||
$form->add( new YesNo( 'f_reg_require', $this->reg_require ) );
|
||||
}
|
||||
|
||||
$form->addHeader( 'customer_field_purchase' );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'f_purchase_show', $this->purchase_show ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'f_purchase_require', $this->purchase_require ) );
|
||||
$form->add( new YesNo( 'f_purchase_show', $this->purchase_show ) );
|
||||
$form->add( new YesNo( 'f_purchase_require', $this->purchase_require ) );
|
||||
|
||||
unset( $form->elements[''][1] );
|
||||
unset( $form->elements['']['pf_not_null'] );
|
||||
@@ -141,50 +152,39 @@ class _CustomField extends \IPS\CustomField
|
||||
* @param array $values Values from the form
|
||||
* @return void
|
||||
*/
|
||||
public function postSaveForm( $values )
|
||||
public function postSaveForm( array $values ) : void
|
||||
{
|
||||
if ( !$this->column )
|
||||
{
|
||||
$this->column = "field_{$this->id}";
|
||||
$this->save();
|
||||
}
|
||||
|
||||
parent::postSaveForm( $values );
|
||||
}
|
||||
|
||||
/**
|
||||
* [ActiveRecord] Save Changed Columns
|
||||
*
|
||||
* @return void
|
||||
* @return void
|
||||
*/
|
||||
public function save()
|
||||
public function save(): void
|
||||
{
|
||||
parent::save();
|
||||
\IPS\Widget::deleteCaches( 'donations', 'nexus' );
|
||||
static::recountCustomerFields();
|
||||
Widget::deleteCaches( 'donations', 'nexus' );
|
||||
}
|
||||
|
||||
/**
|
||||
* [ActiveRecord] Delete
|
||||
*
|
||||
* @return void
|
||||
* @return void
|
||||
*/
|
||||
public function delete()
|
||||
public function delete(): void
|
||||
{
|
||||
parent::delete();
|
||||
static::recountCustomerFields();
|
||||
|
||||
/* Do we need to do stuff with profile steps? */
|
||||
\IPS\Member\ProfileStep::resync();
|
||||
}
|
||||
|
||||
/**
|
||||
* Recount card storage gateays
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function recountCustomerFields()
|
||||
{
|
||||
$count = \count( static::roots() );
|
||||
\IPS\Settings::i()->changeValues( array( 'customer_fields' => $count ) );
|
||||
ProfileStep::resync();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -193,7 +193,7 @@ class _CustomField extends \IPS\CustomField
|
||||
* @param array $values Values from the form
|
||||
* @return array
|
||||
*/
|
||||
public function formatFormValues( $values )
|
||||
public function formatFormValues( array $values ): array
|
||||
{
|
||||
$values['allow_attachments'] = $values['pf_allow_attachments'];
|
||||
unset( $values['pf_allow_attachments'] );
|
||||
|
||||
@@ -12,38 +12,60 @@
|
||||
namespace IPS\nexus;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use IPS\Db;
|
||||
use IPS\Db\Select;
|
||||
use IPS\GeoLocation;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Math\Number;
|
||||
use IPS\Member;
|
||||
use IPS\nexus\Customer\CustomField;
|
||||
use IPS\nexus\Donation\Goal;
|
||||
use IPS\Patterns\ActiveRecordIterator;
|
||||
use IPS\Request;
|
||||
use IPS\Settings;
|
||||
use OutOfRangeException;
|
||||
use UnderflowException;
|
||||
use function count;
|
||||
use function defined;
|
||||
use function get_called_class;
|
||||
use function in_array;
|
||||
use function is_array;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Customer Model
|
||||
*/
|
||||
class _Customer extends \IPS\Member
|
||||
class Customer extends Member
|
||||
{
|
||||
/**
|
||||
* @brief Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
protected static array $multitons;
|
||||
|
||||
/**
|
||||
* @brief Cached logged in member
|
||||
*/
|
||||
public static $loggedInMember = NULL;
|
||||
public static ?Member $loggedInMember = NULL;
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] ID Database Column
|
||||
*/
|
||||
public static $databaseColumnId = 'member_id';
|
||||
public static string $databaseColumnId = 'member_id';
|
||||
|
||||
/**
|
||||
* Get logged in member
|
||||
*
|
||||
* @return \IPS\Member
|
||||
* @return Member|null
|
||||
*/
|
||||
public static function loggedIn()
|
||||
public static function loggedIn(): ?static
|
||||
{
|
||||
/* If we haven't loaded the member yet, or if the session member has changed since we last loaded the member, reload and cache */
|
||||
if( static::$loggedInMember === NULL )
|
||||
@@ -60,14 +82,14 @@ class _Customer extends \IPS\Member
|
||||
* @param int|string $id ID
|
||||
* @param string $idField The database column that the $id parameter pertains to
|
||||
* @param mixed $extraWhereClause Additional where clause(s)
|
||||
* @return \IPS\Db\Select
|
||||
* @return Select
|
||||
*/
|
||||
protected static function constructLoadQuery( $id, $idField, $extraWhereClause )
|
||||
protected static function constructLoadQuery( int|string $id, string $idField, mixed $extraWhereClause ): Select
|
||||
{
|
||||
$where = array( array( 'core_members.' . $idField . '=?', $id ) );
|
||||
if( $extraWhereClause !== NULL )
|
||||
{
|
||||
if ( !\is_array( $extraWhereClause ) or !\is_array( $extraWhereClause[0] ) )
|
||||
if ( !is_array( $extraWhereClause ) or !is_array( $extraWhereClause[0] ) )
|
||||
{
|
||||
$extraWhereClause = array( $extraWhereClause );
|
||||
}
|
||||
@@ -80,20 +102,20 @@ class _Customer extends \IPS\Member
|
||||
/**
|
||||
* Load Record
|
||||
*
|
||||
* @see \IPS\Db::build
|
||||
* @param int|string $id ID
|
||||
* @param string $idField The database column that the $id parameter pertains to (NULL will use static::$databaseColumnId)
|
||||
* @see Db::build
|
||||
* @param int|string|null $id ID
|
||||
* @param string|null $idField The database column that the $id parameter pertains to (NULL will use static::$databaseColumnId)
|
||||
* @param mixed $extraWhereClause Additional where clause(s) (see \IPS\Db::build for details)
|
||||
* @return static
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws \OutOfRangeException
|
||||
* @throws InvalidArgumentException
|
||||
* @throws OutOfRangeException
|
||||
*/
|
||||
public static function load( $id, $idField=NULL, $extraWhereClause=NULL )
|
||||
public static function load( int|string|null $id, string $idField=NULL, mixed $extraWhereClause=NULL ): static
|
||||
{
|
||||
/* Guests */
|
||||
if( $id === NULL OR $id === 0 OR $id === '' )
|
||||
{
|
||||
$classname = \get_called_class();
|
||||
$classname = get_called_class();
|
||||
return new $classname;
|
||||
}
|
||||
|
||||
@@ -104,9 +126,9 @@ class _Customer extends \IPS\Member
|
||||
}
|
||||
|
||||
/* If we did, check it's valid */
|
||||
elseif( !\in_array( $idField, static::$databaseIdFields ) )
|
||||
elseif( !in_array( $idField, static::$databaseIdFields ) )
|
||||
{
|
||||
throw new \InvalidArgumentException;
|
||||
throw new InvalidArgumentException;
|
||||
}
|
||||
|
||||
/* Does that exist in the multiton store? */
|
||||
@@ -123,9 +145,9 @@ class _Customer extends \IPS\Member
|
||||
{
|
||||
$row = static::constructLoadQuery( $id, $idField, $extraWhereClause )->first();
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
catch ( UnderflowException )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
throw new OutOfRangeException;
|
||||
}
|
||||
|
||||
/* If it doesn't exist in the multiton store, set it */
|
||||
@@ -142,11 +164,11 @@ class _Customer extends \IPS\Member
|
||||
/**
|
||||
* Construct ActiveRecord from database row
|
||||
*
|
||||
* @param array $data Row from database table
|
||||
* @param bool $updateMultitonStoreIfExists Replace current object in multiton store if it already exists there?
|
||||
* @return static
|
||||
* @param array $data Row from database table
|
||||
* @param bool $updateMultitonStoreIfExists Replace current object in multiton store if it already exists there?
|
||||
* @return static
|
||||
*/
|
||||
public static function constructFromData( $data, $updateMultitonStoreIfExists = TRUE )
|
||||
public static function constructFromData( array $data, bool $updateMultitonStoreIfExists = TRUE ): static
|
||||
{
|
||||
if ( isset( $data['_member_id'] ) )
|
||||
{
|
||||
@@ -168,7 +190,7 @@ class _Customer extends \IPS\Member
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setDefaultValues()
|
||||
public function setDefaultValues() : void
|
||||
{
|
||||
$this->_data['cm_first_name'] = '';
|
||||
$this->_data['cm_last_name'] = '';
|
||||
@@ -180,7 +202,7 @@ class _Customer extends \IPS\Member
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_cm_name()
|
||||
public function get_cm_name(): string
|
||||
{
|
||||
return ( $this->cm_first_name or $this->cm_last_name ) ? "{$this->cm_first_name} {$this->cm_last_name}" : $this->name;
|
||||
}
|
||||
@@ -190,19 +212,19 @@ class _Customer extends \IPS\Member
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_cm_credits()
|
||||
public function get_cm_credits(): array
|
||||
{
|
||||
$amounts = $this->member_id ? json_decode( $this->_data['cm_credits'], TRUE ) : array();
|
||||
$amounts = ( $this->member_id AND isset( $this->_data['cm_credits'] ) ) ? json_decode( $this->_data['cm_credits'], TRUE ) : array();
|
||||
$return = array();
|
||||
foreach ( \IPS\nexus\Money::currencies() as $currency )
|
||||
foreach (Money::currencies() as $currency )
|
||||
{
|
||||
if ( isset( $amounts[ $currency ] ) )
|
||||
{
|
||||
$return[ $currency ] = new \IPS\nexus\Money( $amounts[ $currency ], $currency );
|
||||
$return[ $currency ] = new Money( $amounts[ $currency ], $currency );
|
||||
}
|
||||
else
|
||||
{
|
||||
$return[ $currency ] = new \IPS\nexus\Money( 0, $currency );
|
||||
$return[ $currency ] = new Money( 0, $currency );
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
@@ -211,10 +233,10 @@ class _Customer extends \IPS\Member
|
||||
/**
|
||||
* Set account credit
|
||||
*
|
||||
* @param array $amounts Amounts
|
||||
* @param array $amounts Amounts
|
||||
* @return void
|
||||
*/
|
||||
public function set_cm_credits( $amounts )
|
||||
public function set_cm_credits( array $amounts ) : void
|
||||
{
|
||||
$save = array();
|
||||
foreach ( $amounts as $amount )
|
||||
@@ -229,7 +251,7 @@ class _Customer extends \IPS\Member
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_cm_profiles()
|
||||
public function get_cm_profiles(): array
|
||||
{
|
||||
return ( isset( $this->_data['cm_profiles'] ) and $this->_data['cm_profiles'] ) ? json_decode( $this->_data['cm_profiles'], TRUE ) : array();
|
||||
}
|
||||
@@ -237,10 +259,10 @@ class _Customer extends \IPS\Member
|
||||
/**
|
||||
* Set profiles
|
||||
*
|
||||
* @param array $profiles Profiles
|
||||
* @return array
|
||||
* @param array $profiles Profiles
|
||||
* @return void
|
||||
*/
|
||||
public function set_cm_profiles( $profiles )
|
||||
public function set_cm_profiles( array $profiles ) : void
|
||||
{
|
||||
$this->_data['cm_profiles'] = json_encode( $profiles );
|
||||
}
|
||||
@@ -248,15 +270,15 @@ class _Customer extends \IPS\Member
|
||||
/**
|
||||
* Get default currency
|
||||
*
|
||||
* @return void
|
||||
* @return string
|
||||
*/
|
||||
public function defaultCurrency()
|
||||
public function defaultCurrency() : string
|
||||
{
|
||||
if ( $currencies = json_decode( \IPS\Settings::i()->nexus_currency, TRUE ) )
|
||||
if ( $currencies = json_decode( Settings::i()->nexus_currency, TRUE ) )
|
||||
{
|
||||
foreach ( $currencies as $k => $v )
|
||||
{
|
||||
if ( \in_array( $this->language()->id, $v ) )
|
||||
if ( in_array( $this->language()->id, $v ) )
|
||||
{
|
||||
return $k;
|
||||
}
|
||||
@@ -267,29 +289,29 @@ class _Customer extends \IPS\Member
|
||||
}
|
||||
else
|
||||
{
|
||||
return \IPS\Settings::i()->nexus_currency;
|
||||
return Settings::i()->nexus_currency;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Cache primary billing address in case the method is called multiple times
|
||||
*/
|
||||
protected $primaryBillingAddress = FALSE;
|
||||
protected GeoLocation|bool|null $primaryBillingAddress = false;
|
||||
|
||||
/**
|
||||
* Get primary billing address, if one exists
|
||||
*
|
||||
* @return \IPS\GeoLocation|NULL
|
||||
* @return GeoLocation|NULL
|
||||
*/
|
||||
public function primaryBillingAddress()
|
||||
public function primaryBillingAddress() : GeoLocation|null
|
||||
{
|
||||
if( $this->primaryBillingAddress === FALSE )
|
||||
{
|
||||
try
|
||||
{
|
||||
$this->primaryBillingAddress = \IPS\GeoLocation::buildFromJson( \IPS\Db::i()->select( 'address', 'nexus_customer_addresses', array( '`member`=? AND primary_billing=1', $this->member_id ) )->first() );
|
||||
$this->primaryBillingAddress = GeoLocation::buildFromJson( Db::i()->select( 'address', 'nexus_customer_addresses', array( '`member`=? AND primary_billing=1', $this->member_id ) )->first() );
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
catch ( UnderflowException )
|
||||
{
|
||||
$this->primaryBillingAddress = NULL;
|
||||
}
|
||||
@@ -301,19 +323,19 @@ class _Customer extends \IPS\Member
|
||||
/**
|
||||
* Estimated location
|
||||
*
|
||||
* @return \IPS\GeoLocation|NULL
|
||||
* @return GeoLocation|NULL
|
||||
*/
|
||||
public function estimatedLocation()
|
||||
public function estimatedLocation(): ?GeoLocation
|
||||
{
|
||||
if ( $this->member_id === \IPS\nexus\Customer::loggedIn()->member_id )
|
||||
if ( $this->member_id === Customer::loggedIn()->member_id )
|
||||
{
|
||||
if ( isset( \IPS\Request::i()->cookie['location'] ) AND ( !\IPS\Request::i()->cookie['location'] OR ( \IPS\Request::i()->cookie['location'] AND $data = json_decode( \IPS\Request::i()->cookie['location'], true ) AND array_key_exists( 'member_id', $data ) AND $data['member_id'] == $this->member_id ) ) )
|
||||
if ( isset( Request::i()->cookie['location'] ) AND ( !Request::i()->cookie['location'] OR ( Request::i()->cookie['location'] AND $data = json_decode( Request::i()->cookie['location'], true ) AND array_key_exists( 'member_id', $data ) AND $data['member_id'] == $this->member_id ) ) )
|
||||
{
|
||||
$location = NULL;
|
||||
|
||||
if( \IPS\Request::i()->cookie['location'] AND $data = json_decode( \IPS\Request::i()->cookie['location'], true ) AND $data['member_id'] == $this->member_id )
|
||||
if( Request::i()->cookie['location'] AND $data = json_decode( Request::i()->cookie['location'], true ) AND $data['member_id'] == $this->member_id )
|
||||
{
|
||||
$location = \IPS\GeoLocation::buildFromJson( \IPS\Request::i()->cookie['location'] );
|
||||
$location = GeoLocation::buildFromJson( Request::i()->cookie['location'] );
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -323,32 +345,32 @@ class _Customer extends \IPS\Member
|
||||
{
|
||||
try
|
||||
{
|
||||
$location = \IPS\GeoLocation::getRequesterLocation();
|
||||
\IPS\Request::i()->setCookie( 'location', $this->_addMemberToAddress( $location ) );
|
||||
$location = GeoLocation::getRequesterLocation();
|
||||
Request::i()->setCookie( 'location', $this->_addMemberToAddress( $location ) );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
catch ( Exception )
|
||||
{
|
||||
if( isset( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) )
|
||||
{
|
||||
$languages = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE'] );
|
||||
$exploded = explode( '-', array_shift( $languages ) );
|
||||
|
||||
if ( \in_array( mb_strtoupper( $exploded[1] ), \IPS\GeoLocation::$countries ) )
|
||||
if ( in_array( mb_strtoupper( $exploded[1] ), GeoLocation::$countries ) )
|
||||
{
|
||||
$location = new \IPS\GeoLocation;
|
||||
$location = new GeoLocation;
|
||||
$location->country = mb_strtoupper( $exploded[1] );
|
||||
\IPS\Request::i()->setCookie( 'location', $this->_addMemberToAddress( $location ) );
|
||||
Request::i()->setCookie( 'location', $this->_addMemberToAddress( $location ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
$location = NULL;
|
||||
\IPS\Request::i()->setCookie( 'location', '' );
|
||||
Request::i()->setCookie( 'location', '' );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$location = NULL;
|
||||
\IPS\Request::i()->setCookie( 'location', '' );
|
||||
Request::i()->setCookie( 'location', '' );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -365,10 +387,10 @@ class _Customer extends \IPS\Member
|
||||
/**
|
||||
* Add the member ID to the address object so we can validate it on subsequent requests
|
||||
*
|
||||
* @param \IPS\GeoLocation $location Location object
|
||||
* @param GeoLocation $location Location object
|
||||
* @return string
|
||||
*/
|
||||
protected function _addMemberToAddress( $location )
|
||||
protected function _addMemberToAddress( GeoLocation $location ): string
|
||||
{
|
||||
return json_encode( array_merge( json_decode( json_encode( $location ), true ), array( 'member_id' => $this->member_id ) ) );
|
||||
}
|
||||
@@ -376,16 +398,16 @@ class _Customer extends \IPS\Member
|
||||
/**
|
||||
* Save Changed Columns
|
||||
*
|
||||
* @return void
|
||||
* @return void
|
||||
*/
|
||||
public function save()
|
||||
public function save(): void
|
||||
{
|
||||
$data = $this->_data;
|
||||
|
||||
$customerTable = array();
|
||||
foreach ( ( $this->_new ? $this->_data : $this->changed ) as $k => $v )
|
||||
{
|
||||
if ( ( mb_substr( $k, 0, 3 ) === 'cm_' and !\in_array( $k, array( 'cm_credits', 'cm_no_sev', 'cm_return_group', 'cm_reg' ) ) ) or mb_substr( $k, 0, 6 ) === 'field_' )
|
||||
if ( ( mb_substr( $k, 0, 3 ) === 'cm_' and !in_array( $k, array( 'cm_credits', 'cm_return_group', 'cm_reg' ) ) ) or mb_substr( $k, 0, 6 ) === 'field_' )
|
||||
{
|
||||
$customerTable[ $k ] = $v;
|
||||
unset( $this->_data[ $k ] );
|
||||
@@ -397,62 +419,62 @@ class _Customer extends \IPS\Member
|
||||
$data['member_id'] = $this->_data['member_id'];
|
||||
$this->_data = $data;
|
||||
|
||||
if ( \count( $customerTable ) )
|
||||
if ( count( $customerTable ) )
|
||||
{
|
||||
$customerTable['member_id'] = $this->member_id;
|
||||
\IPS\Db::i()->insert( 'nexus_customers', $customerTable, TRUE );
|
||||
Db::i()->insert( 'nexus_customers', $customerTable, TRUE );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log Action
|
||||
*
|
||||
* @param string $type Log type
|
||||
* @param mixed $extra Any extra data for the type
|
||||
* @param mixed $by The member performing the action. NULL for currently logged in member or FALSE for no member
|
||||
* @param string $type Log type
|
||||
* @param mixed|null $extra Any extra data for the type
|
||||
* @param mixed|null $by The member performing the action. NULL for currently logged in member or FALSE for no member
|
||||
* @return void
|
||||
*/
|
||||
public function log( $type, $extra=NULL, $by=NULL )
|
||||
public function log( string $type, mixed $extra=NULL, mixed $by=NULL ) : void
|
||||
{
|
||||
$this->logHistory( 'nexus', $type, $extra, $by, TRUE );
|
||||
$this->logHistory( 'nexus', $type, $extra, $by );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get total amount spent
|
||||
*
|
||||
* @return string
|
||||
* @return Money|string
|
||||
*/
|
||||
public function totalSpent()
|
||||
public function totalSpent(): Money|string
|
||||
{
|
||||
$return = array();
|
||||
foreach ( \IPS\Db::i()->select( 't_currency, ( SUM(t_amount)-SUM(t_partial_refund) ) AS amount', 'nexus_transactions', array( 't_member=? AND ( t_status=? OR t_status=? )', $this->member_id, \IPS\nexus\Transaction::STATUS_PAID, \IPS\nexus\Transaction::STATUS_PART_REFUNDED ), NULL, NULL, 't_currency' ) as $amount )
|
||||
foreach (Db::i()->select( 't_currency, ( SUM(t_amount)-SUM(t_partial_refund) ) AS amount', 'nexus_transactions', array( 't_member=? AND ( t_status=? OR t_status=? )', $this->member_id, Transaction::STATUS_PAID, Transaction::STATUS_PART_REFUNDED ), NULL, NULL, 't_currency' ) as $amount )
|
||||
{
|
||||
$return[] = (string) new \IPS\nexus\Money( $amount['amount'], $amount['t_currency'] );
|
||||
$return[] = (string) new Money( $amount['amount'], $amount['t_currency'] );
|
||||
}
|
||||
return \count( $return ) ? implode( ' + ', $return ) : new \IPS\nexus\Money( 0, $this->defaultCurrency() );
|
||||
return count( $return ) ? implode( ' + ', $return ) : new Money( 0, $this->defaultCurrency() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Number of previous purchases by package ID
|
||||
*/
|
||||
protected $previousPurchasesCount;
|
||||
protected mixed $previousPurchasesCount = NULL;
|
||||
|
||||
/**
|
||||
* Get number of previous purchases of a package ID (used to calculate loyalty discounts)
|
||||
*
|
||||
* @param int $packageID Package ID
|
||||
* @param bool $activeOnly Active only?
|
||||
* @return array
|
||||
* @param int $packageID Package ID
|
||||
* @param bool $activeOnly Active only?
|
||||
* @return int|array
|
||||
*/
|
||||
public function previousPurchasesCount( $packageID, $activeOnly )
|
||||
public function previousPurchasesCount( int $packageID, bool $activeOnly=FALSE ): int|array
|
||||
{
|
||||
if ( $this->previousPurchasesCount === NULL )
|
||||
{
|
||||
$this->previousPurchasesCount['all'] = iterator_to_array( \IPS\Db::i()->select( 'ps_item_id, COUNT(*)', 'nexus_purchases', array( 'ps_app=? AND ps_type=? AND ps_member=?', 'nexus', 'package', $this->member_id ), NULL, NULL, 'ps_item_id' )->setKeyField('ps_item_id')->setValueField('COUNT(*)') );
|
||||
$this->previousPurchasesCount['active'] = iterator_to_array( \IPS\Db::i()->select( 'ps_item_id, COUNT(*)', 'nexus_purchases', array( 'ps_app=? AND ps_type=? AND ps_member=? AND ps_active=1', 'nexus', 'package', $this->member_id ), NULL, NULL, 'ps_item_id' )->setKeyField('ps_item_id')->setValueField('COUNT(*)') );
|
||||
$this->previousPurchasesCount['all'] = iterator_to_array( Db::i()->select( 'ps_item_id, COUNT(*)', 'nexus_purchases', array( 'ps_app=? AND ps_type=? AND ps_member=?', 'nexus', 'package', $this->member_id ), NULL, NULL, 'ps_item_id' )->setKeyField('ps_item_id')->setValueField('COUNT(*)') );
|
||||
$this->previousPurchasesCount['active'] = iterator_to_array( Db::i()->select( 'ps_item_id, COUNT(*)', 'nexus_purchases', array( 'ps_app=? AND ps_type=? AND ps_member=? AND ps_active=1', 'nexus', 'package', $this->member_id ), NULL, NULL, 'ps_item_id' )->setKeyField('ps_item_id')->setValueField('COUNT(*)') );
|
||||
}
|
||||
|
||||
return isset( $this->previousPurchasesCount[ $activeOnly ? 'active' : 'all' ][ $packageID ] ) ? $this->previousPurchasesCount[ $activeOnly ? 'active' : 'all' ][ $packageID ] : 0;
|
||||
return $this->previousPurchasesCount[$activeOnly ? 'active' : 'all'][$packageID] ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -460,37 +482,37 @@ class _Customer extends \IPS\Member
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function clientAreaLinks()
|
||||
public function clientAreaLinks(): array
|
||||
{
|
||||
$return = array( 'invoices' );
|
||||
if ( \IPS\Db::i()->select( 'COUNT(*)', 'nexus_purchases', array( 'ps_member=? AND ps_show=1', $this->member_id ) ) )
|
||||
if ( Db::i()->select( 'COUNT(*)', 'nexus_purchases', array( 'ps_member=? AND ps_show=1', $this->member_id ) ) )
|
||||
{
|
||||
$return[] = 'purchases';
|
||||
}
|
||||
|
||||
$return[] = 'addresses';
|
||||
if ( \count( \IPS\nexus\Gateway::cardStorageGateways() ) or \count( \IPS\nexus\Gateway::otherStoredPaymentMethodGateways() ) )
|
||||
if ( count( Gateway::cardStorageGateways() ) )
|
||||
{
|
||||
$return[] = 'cards';
|
||||
}
|
||||
if ( \count( \IPS\nexus\Customer\CustomField::roots() ) )
|
||||
if ( count( CustomField::roots() ) )
|
||||
{
|
||||
$return[] = 'info';
|
||||
}
|
||||
|
||||
if ( \IPS\Settings::i()->nexus_min_topup or \count( json_decode( \IPS\Settings::i()->nexus_payout, TRUE ) ) )
|
||||
if ( Settings::i()->nexus_min_topup or count( json_decode( Settings::i()->nexus_payout, TRUE ) ) )
|
||||
{
|
||||
$return[] = 'credit';
|
||||
}
|
||||
|
||||
$return[] = 'alternatives';
|
||||
|
||||
if ( \count( \IPS\nexus\Donation\Goal::roots() ) )
|
||||
if ( count( Goal::roots() ) )
|
||||
{
|
||||
$return[] = 'donations';
|
||||
}
|
||||
|
||||
if ( \IPS\Settings::i()->ref_on )
|
||||
if ( Settings::i()->ref_on )
|
||||
{
|
||||
$return[] = 'referrals';
|
||||
}
|
||||
@@ -501,35 +523,35 @@ class _Customer extends \IPS\Member
|
||||
/**
|
||||
* Alternative Contacts
|
||||
*
|
||||
* @param array $where WHERE clause
|
||||
* @return \IPS\Patterns\ActiveRecordIterator
|
||||
* @param array $where WHERE clause
|
||||
* @return ActiveRecordIterator
|
||||
*/
|
||||
public function alternativeContacts( $where = array() )
|
||||
public function alternativeContacts( array $where = array() ): ActiveRecordIterator
|
||||
{
|
||||
$where = \count( $where ) ? array( $where ) : $where;
|
||||
$where = count( $where ) ? array( $where ) : $where;
|
||||
$where[] = array( 'main_id=?', $this->member_id );
|
||||
return new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'nexus_alternate_contacts', $where )->setKeyField( 'alt_id' ), 'IPS\nexus\Customer\AlternativeContact' );
|
||||
return new ActiveRecordIterator( Db::i()->select( '*', 'nexus_alternate_contacts', $where )->setKeyField( 'alt_id' ), 'IPS\nexus\Customer\AlternativeContact' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Parent Contacts
|
||||
*
|
||||
* @param array $where WHERE clause
|
||||
* @return \IPS\Patterns\ActiveRecordIterator
|
||||
* @param array $where WHERE clause
|
||||
* @return ActiveRecordIterator
|
||||
*/
|
||||
public function parentContacts( $where = array() )
|
||||
public function parentContacts( array $where = array() ): ActiveRecordIterator
|
||||
{
|
||||
$where = \count( $where ) ? array( $where ) : $where;
|
||||
$where = count( $where ) ? array( $where ) : $where;
|
||||
$where[] = array( 'alt_id=?', $this->member_id );
|
||||
return new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'nexus_alternate_contacts', $where )->setKeyField( 'main_id' ), 'IPS\nexus\Customer\AlternativeContact' );
|
||||
return new ActiveRecordIterator( Db::i()->select( '*', 'nexus_alternate_contacts', $where )->setKeyField( 'main_id' ), 'IPS\nexus\Customer\AlternativeContact' );
|
||||
}
|
||||
|
||||
/**
|
||||
* ACP Customer Page URL
|
||||
*
|
||||
* @return \IPS\Http\Url
|
||||
* @return Url
|
||||
*/
|
||||
public function acpUrl()
|
||||
public function acpUrl(): Url
|
||||
{
|
||||
return parent::acpUrl()->setQueryString( 'tab', 'nexus_Main' );
|
||||
}
|
||||
@@ -537,24 +559,24 @@ class _Customer extends \IPS\Member
|
||||
/**
|
||||
* ACP Customer Page URL
|
||||
*
|
||||
* @param \IPS\Math\Number $amount Adjustment amount
|
||||
* @param string $currency Currency code
|
||||
* @param bool $refund Should the spend be reduced?
|
||||
* @param Number $amount Adjustment amount
|
||||
* @param string $currency Currency code
|
||||
* @param bool $refund Should the spend be reduced?
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function updateSpend( \IPS\Math\Number $amount, $currency, $refund=false )
|
||||
public function updateSpend( Number $amount, string $currency, bool $refund=FALSE ) : void
|
||||
{
|
||||
try
|
||||
{
|
||||
$currentSpend = \IPS\Db::i()->select( 'spend_amount', 'nexus_customer_spend', array( "spend_member_id=? AND spend_currency=?", $this->member_id, $currency ) )->first();
|
||||
$newSpend = new \IPS\Math\Number( number_format( $currentSpend, \IPS\nexus\Money::numberOfDecimalsForCurrency( $currency ), '.', '' ) );
|
||||
$currentSpend = Db::i()->select( 'spend_amount', 'nexus_customer_spend', array( "spend_member_id=? AND spend_currency=?", $this->member_id, $currency ) )->first();
|
||||
$newSpend = new Number( number_format( $currentSpend, Money::numberOfDecimalsForCurrency( $currency ), '.', '' ) );
|
||||
$newSpend = ( $refund ) ? $newSpend->subtract( $amount ) : $newSpend->add( $amount );
|
||||
\IPS\Db::i()->replace( 'nexus_customer_spend', array( 'spend_member_id' => $this->member_id, 'spend_amount' => $newSpend, 'spend_currency' => $currency ) );
|
||||
Db::i()->replace( 'nexus_customer_spend', array( 'spend_member_id' => $this->member_id, 'spend_amount' => $newSpend, 'spend_currency' => $currency ) );
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
catch ( UnderflowException )
|
||||
{
|
||||
\IPS\Db::i()->insert( 'nexus_customer_spend', array( 'spend_member_id' => $this->member_id, 'spend_amount' => ( $refund ) ? $amount->multiply( new \IPS\Math\Number( "-1" ) ) : $amount, 'spend_currency' => $currency ), TRUE );
|
||||
Db::i()->insert( 'nexus_customer_spend', array( 'spend_member_id' => $this->member_id, 'spend_amount' => ( $refund ) ? $amount->multiply( new Number( "-1" ) ) : $amount, 'spend_currency' => $currency ), TRUE );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -563,19 +585,19 @@ class _Customer extends \IPS\Member
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function recountTotalSpend()
|
||||
public function recountTotalSpend() : void
|
||||
{
|
||||
\IPS\Db::i()->delete( 'nexus_customer_spend', array( 'spend_member_id=?', $this->member_id ) );
|
||||
Db::i()->delete( 'nexus_customer_spend', array( 'spend_member_id=?', $this->member_id ) );
|
||||
|
||||
$spend = array();
|
||||
foreach ( \IPS\Db::i()->select( 't_currency, ( SUM(t_amount)-SUM(t_partial_refund) ) AS amount', 'nexus_transactions', array( 't_member=? AND ( t_status=? OR t_status=? )', $this->member_id, \IPS\nexus\Transaction::STATUS_PAID, \IPS\nexus\Transaction::STATUS_PART_REFUNDED ), NULL, NULL, 't_currency' ) as $amount )
|
||||
foreach (Db::i()->select( 't_currency, ( SUM(t_amount)-SUM(t_partial_refund) ) AS amount', 'nexus_transactions', array( 't_member=? AND ( t_status=? OR t_status=? )', $this->member_id, Transaction::STATUS_PAID, Transaction::STATUS_PART_REFUNDED ), NULL, NULL, 't_currency' ) as $amount )
|
||||
{
|
||||
$spend[] = array( 'spend_member_id' => $this->member_id, 'spend_amount' => $amount['amount'], 'spend_currency' => $amount['t_currency'] );
|
||||
}
|
||||
|
||||
if( \count( $spend ) )
|
||||
if( count( $spend ) )
|
||||
{
|
||||
\IPS\Db::i()->insert( 'nexus_customer_spend', $spend );
|
||||
Db::i()->insert( 'nexus_customer_spend', $spend );
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user