Version 5.0.0 beta 1

This commit is contained in:
Neo committed 2025-12-19 16:27:35 -08:00
1 parent 25ddeb65d6
commit 15c7beabc5
6736 files changed
+627902 -497943

No files matched your search

File diff suppressed because it is too large. Load diff
@@ -12,38 +12,56 @@
namespace IPS\nexus\modules\front\clients;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Db;
use IPS\Dispatcher\Controller;
use IPS\Helpers\Form;
use IPS\Http\Url;
use IPS\Member;
use IPS\MFA\MFAHandler;
use IPS\nexus\Customer;
use IPS\nexus\Customer\Address;
use IPS\nexus\Tax;
use IPS\Output;
use IPS\Patterns\ActiveRecordIterator;
use IPS\Request;
use IPS\Session;
use IPS\Theme;
use OutOfRangeException;
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;
}
/**
* Addresses
*/
class _addresses extends \IPS\Dispatcher\Controller
class addresses extends Controller
{
/**
* Execute
*
* @return void
*/
public function execute()
public function execute() : void
{
if ( !\IPS\Member::loggedIn()->member_id )
if ( !Member::loggedIn()->member_id )
{
\IPS\Output::i()->error( 'no_module_permission_guest', '2X235/1', 403, '' );
Output::i()->error( 'no_module_permission_guest', '2X235/1', 403, '' );
}
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'global_forms.js', 'nexus', 'global' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'clients.css', 'nexus' ) );
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( 'app=nexus&module=clients&controller=addresses', 'front', 'clientsaddresses' ), \IPS\Member::loggedIn()->language()->addToStack('client_addresses') );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('client_addresses');
\IPS\Output::i()->sidebar['enabled'] = FALSE;
Output::i()->jsFiles = array_merge( Output::i()->jsFiles, Output::i()->js( 'global_forms.js', 'nexus', 'global' ) );
Output::i()->cssFiles = array_merge( Output::i()->cssFiles, Theme::i()->css( 'clients.css', 'nexus' ) );
Output::i()->breadcrumb[] = array( Url::internal( 'app=nexus&module=clients&controller=addresses', 'front', 'clientsaddresses' ), Member::loggedIn()->language()->addToStack('client_addresses') );
Output::i()->title = Member::loggedIn()->language()->addToStack('client_addresses');
Output::i()->sidebar['enabled'] = FALSE;
if ( $output = \IPS\MFA\MFAHandler::accessToArea( 'nexus', 'Addresses', \IPS\Http\Url::internal( 'app=nexus&module=clients&controller=addresses', 'front', 'clientsaddresses' ) ) )
if ( $output = MFAHandler::accessToArea( 'nexus', 'Addresses', Url::internal( 'app=nexus&module=clients&controller=addresses', 'front', 'clientsaddresses' ) ) )
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('clients')->addresses( NULL, NULL, array() ) . $output;
Output::i()->output = Theme::i()->getTemplate('clients')->addresses( NULL, NULL, array() ) . $output;
return;
}
@@ -55,11 +73,10 @@ class _addresses extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function manage()
protected function manage() : void
{
$addresses = new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'nexus_customer_addresses', array( '`member`=?', \IPS\Member::loggedIn()->member_id ) ), 'IPS\nexus\Customer\Address' );
$addresses = new ActiveRecordIterator( Db::i()->select( '*', 'nexus_customer_addresses', array( '`member`=?', Member::loggedIn()->member_id ) ), 'IPS\nexus\Customer\Address' );
$shippingAddress = NULL;
$billingAddress = NULL;
$otherAddresses = array();
@@ -69,19 +86,13 @@ class _addresses extends \IPS\Dispatcher\Controller
{
$billingAddress = $address;
}
if( $address->primary_shipping )
{
$shippingAddress = $address;
}
if( !$address->primary_shipping && !$address->primary_billing )
else
{
$otherAddresses[] = $address;
}
}
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('clients')->addresses( $billingAddress, $shippingAddress, $otherAddresses );
Output::i()->output = Theme::i()->getTemplate('clients')->addresses( $billingAddress, $otherAddresses );
}
/**
@@ -89,27 +100,27 @@ class _addresses extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function form()
protected function form() : void
{
$existing = NULL;
if ( isset( \IPS\Request::i()->id ) )
if ( isset( Request::i()->id ) )
{
try
{
$existing = \IPS\nexus\Customer\Address::load( \IPS\Request::i()->id );
if ( $existing->member->member_id != \IPS\Member::loggedIn()->member_id )
$existing = Address::load( Request::i()->id );
if ( $existing->member->member_id != Member::loggedIn()->member_id )
{
throw new \OutOfRangeException;
throw new OutOfRangeException;
}
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException )
{
$existing = NULL;
}
}
$needTaxStatus = NULL;
foreach ( \IPS\nexus\Tax::roots() as $tax )
foreach ( Tax::roots() as $tax )
{
if ( $tax->type === 'eu' )
{
@@ -124,41 +135,40 @@ class _addresses extends \IPS\Dispatcher\Controller
$addressHelperClass = $needTaxStatus ? 'IPS\nexus\Form\BusinessAddress' : 'IPS\Helpers\Form\Address';
$addressHelperOptions = ( $needTaxStatus === 'eu' ) ? array( 'vat' => TRUE ) : array();
$form = new \IPS\Helpers\Form;
$form->add( new $addressHelperClass( 'address', $existing ? $existing->address : NULL, TRUE, $addressHelperOptions ) );
$form = new Form;
$form->add( new $addressHelperClass( 'address', $existing?->address, TRUE, $addressHelperOptions ) );
if ( $values = $form->values() )
{
if ( !$existing )
{
$existing = new \IPS\nexus\Customer\Address;
$existing->member = \IPS\Member::loggedIn();
$existing->primary_billing = !\IPS\Db::i()->select( 'count(*)', 'nexus_customer_addresses', array( '`member`=? AND primary_billing=1', \IPS\Member::loggedIn()->member_id ) )->first();
$existing->primary_shipping = !\IPS\Db::i()->select( 'count(*)', 'nexus_customer_addresses', array( '`member`=? AND primary_shipping=1', \IPS\Member::loggedIn()->member_id ) )->first();
\IPS\nexus\Customer::loggedIn()->log( 'address', array( 'type' => 'add', 'details' => json_encode( $values['address'] ) ) );
$existing = new Address;
$existing->member = Member::loggedIn();
$existing->primary_billing = !Db::i()->select( 'count(*)', 'nexus_customer_addresses', array( '`member`=? AND primary_billing=1', Member::loggedIn()->member_id ) )->first();
Customer::loggedIn()->log( 'address', array( 'type' => 'add', 'details' => json_encode( $values['address'] ) ) );
}
else
{
\IPS\nexus\Customer::loggedIn()->log( 'address', array( 'type' => 'edit', 'new' => json_encode( $values['address'] ), 'old' => json_encode( $existing->address ) ) );
Customer::loggedIn()->log( 'address', array( 'type' => 'edit', 'new' => json_encode( $values['address'] ), 'old' => json_encode( $existing->address ) ) );
}
$existing->address = $values['address'];
$existing->save();
\IPS\Request::i()->setCookie( 'location', NULL );
Request::i()->setCookie( 'location', NULL );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=nexus&module=clients&controller=addresses', 'front', 'clientsaddresses' ) );
Output::i()->redirect( Url::internal( 'app=nexus&module=clients&controller=addresses', 'front', 'clientsaddresses' ) );
}
if ( \IPS\Request::i()->isAjax() )
if ( Request::i()->isAjax() )
{
$form->class = 'ipsForm_vertical ipsForm_noLabels';
\IPS\Output::i()->sendOutput( $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) ) );
$form->class = 'ipsForm--vertical ipsForm--edit-address ipsForm--noLabels';
Output::i()->sendOutput( $form->customTemplate( array( Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) ) );
}
else
{
\IPS\Output::i()->output = $form;
Output::i()->output = $form;
}
}
@@ -167,28 +177,27 @@ class _addresses extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function primary()
protected function primary() : void
{
\IPS\Session::i()->csrfCheck();
Session::i()->csrfCheck();
try
{
$address = \IPS\nexus\Customer\Address::load( \IPS\Request::i()->id );
if ( $address->member->member_id == \IPS\Member::loggedIn()->member_id )
$address = Address::load( Request::i()->id );
if ( $address->member->member_id == Member::loggedIn()->member_id )
{
$field = \IPS\Request::i()->primary === 'billing' ? 'primary_billing' : 'primary_shipping';
\IPS\Db::i()->update( 'nexus_customer_addresses', array( $field => 0 ), array( '`member`=?', \IPS\Member::loggedIn()->member_id ) );
$address->$field = TRUE;
Db::i()->update( 'nexus_customer_addresses', array( 'primary_billing' => 0 ), array( '`member`=?', Member::loggedIn()->member_id ) );
$address->primary_billing = TRUE;
$address->save();
\IPS\nexus\Customer::loggedIn()->log( 'address', array( 'type' => ( \IPS\Request::i()->primary === 'billing' ? 'primary_billing' : 'primary_shipping' ), 'details' => json_encode( $address->address ) ) );
Customer::loggedIn()->log( 'address', array( 'type' => 'primary_billing', 'details' => json_encode( $address->address ) ) );
}
}
catch ( \OutOfRangeException $e ) {}
catch ( OutOfRangeException ) {}
\IPS\Request::i()->setCookie( 'location', NULL );
Request::i()->setCookie( 'location', NULL );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=nexus&module=clients&controller=addresses', 'front', 'clientsaddresses' ) );
Output::i()->redirect( Url::internal( 'app=nexus&module=clients&controller=addresses', 'front', 'clientsaddresses' ) );
}
/**
@@ -196,24 +205,24 @@ class _addresses extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function delete()
protected function delete() : void
{
\IPS\Session::i()->csrfCheck();
Session::i()->csrfCheck();
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
Request::i()->confirmedDelete();
try
{
$address = \IPS\nexus\Customer\Address::load( \IPS\Request::i()->id );
if ( $address->member->member_id == \IPS\Member::loggedIn()->member_id )
$address = Address::load( Request::i()->id );
if ( $address->member->member_id == Member::loggedIn()->member_id )
{
$address->delete();
\IPS\nexus\Customer::loggedIn()->log( 'address', array( 'type' => 'delete', 'details' => json_encode( $address->address ) ) );
Customer::loggedIn()->log( 'address', array( 'type' => 'delete', 'details' => json_encode( $address->address ) ) );
}
}
catch ( \OutOfRangeException $e ) {}
catch ( OutOfRangeException ) {}
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=nexus&module=clients&controller=addresses', 'front', 'clientsaddresses' ) );
Output::i()->redirect( Url::internal( 'app=nexus&module=clients&controller=addresses', 'front', 'clientsaddresses' ) );
}
}
@@ -12,155 +12,173 @@
namespace IPS\nexus\modules\front\clients;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use DomainException;
use IPS\Db;
use IPS\Dispatcher\Controller;
use IPS\Helpers\Form;
use IPS\Helpers\Form\Checkbox;
use IPS\Helpers\Form\Email;
use IPS\Helpers\Form\Node;
use IPS\Http\Url;
use IPS\Member;
use IPS\MFA\MFAHandler;
use IPS\nexus\Customer;
use IPS\nexus\Customer\AlternativeContact;
use IPS\Output;
use IPS\Request;
use IPS\Session;
use IPS\Theme;
use UnderflowException;
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;
}
/**
* Alternative Contacts
*/
class _alternatives extends \IPS\Dispatcher\Controller
class alternatives extends Controller
{
/**
* Execute
*
* @return void
*/
public function execute()
public function execute() : void
{
if ( !\IPS\Member::loggedIn()->member_id )
if ( !Member::loggedIn()->member_id )
{
\IPS\Output::i()->error( 'no_module_permission_guest', '2X237/1', 403, '' );
Output::i()->error( 'no_module_permission_guest', '2X237/1', 403, '' );
}
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'clients.css', 'nexus' ) );
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( 'app=nexus&module=clients&controller=alternatives', 'front', 'clientsalternatives' ), \IPS\Member::loggedIn()->language()->addToStack('client_alternatives') );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('client_alternatives');
\IPS\Output::i()->sidebar['enabled'] = FALSE;
if ( $output = \IPS\MFA\MFAHandler::accessToArea( 'nexus', 'Alternatives', \IPS\Http\Url::internal( 'app=nexus&module=clients&controller=alternatives', 'front', 'clientsalternatives' ) ) )
Output::i()->cssFiles = array_merge( Output::i()->cssFiles, Theme::i()->css( 'clients.css', 'nexus' ) );
Output::i()->breadcrumb[] = array( Url::internal( 'app=nexus&module=clients&controller=alternatives', 'front', 'clientsalternatives' ), Member::loggedIn()->language()->addToStack('client_alternatives') );
Output::i()->title = Member::loggedIn()->language()->addToStack('client_alternatives');
Output::i()->sidebar['enabled'] = FALSE;
if ( $output = MFAHandler::accessToArea( 'nexus', 'Alternatives', Url::internal( 'app=nexus&module=clients&controller=alternatives', 'front', 'clientsalternatives' ) ) )
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('clients')->alternatives( TRUE ) . $output;
Output::i()->output = Theme::i()->getTemplate('clients')->alternatives( TRUE ) . $output;
return;
}
parent::execute();
}
/**
* View List
*
* @return void
*/
protected function manage()
protected function manage() : void
{
foreach ( \IPS\nexus\Customer::loggedIn()->alternativeContacts() as $contact )
foreach ( Customer::loggedIn()->alternativeContacts() as $contact )
{
$contact->alt_id;
}
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('clients')->alternatives();
Output::i()->output = Theme::i()->getTemplate('clients')->alternatives();
}
/**
* Add/Edit
*
* @return void
*/
protected function form()
protected function form() : void
{
$existing = NULL;
if ( isset( \IPS\Request::i()->id ) )
if ( isset( Request::i()->id ) )
{
try
{
$existing = \IPS\nexus\Customer\AlternativeContact::constructFromData( \IPS\Db::i()->select( '*', 'nexus_alternate_contacts', array( 'main_id=? AND alt_id=?', \IPS\nexus\Customer::loggedIn()->member_id, \IPS\Request::i()->id ) )->first() );
$existing = AlternativeContact::constructFromData( Db::i()->select( '*', 'nexus_alternate_contacts', array( 'main_id=? AND alt_id=?', Customer::loggedIn()->member_id, Request::i()->id ) )->first() );
}
catch ( \UnderflowException $e ) {}
catch ( UnderflowException ) {}
}
$form = new \IPS\Helpers\Form;
$form->class = 'ipsForm_vertical';
$form = new Form;
$form->class = 'ipsForm--vertical ipsForm--edit-alernatives';
if ( !$existing )
{
$form->add( new \IPS\Helpers\Form\Email( 'altcontact_email', NULL, TRUE, array(), function( $val )
$form->add( new Email( 'altcontact_email', NULL, TRUE, array(), function( $val )
{
if( \IPS\Member::loggedIn()->email == $val )
if( Member::loggedIn()->email == $val )
{
throw new \DomainException('altcontact_email_self');
throw new DomainException('altcontact_email_self');
}
$member = \IPS\Member::load( $val, 'email' );
$member = Member::load( $val, 'email' );
if ( !$member->member_id )
{
throw new \DomainException('altcontact_email_error');
throw new DomainException('altcontact_email_error');
}
try
{
\IPS\Db::i()->select( '*', 'nexus_alternate_contacts', array( 'main_id=? AND alt_id=?', \IPS\nexus\Customer::loggedIn()->member_id, $member->member_id ) )->first();
throw new \DomainException('altcontact_already_exists');
Db::i()->select( '*', 'nexus_alternate_contacts', array( 'main_id=? AND alt_id=?', Customer::loggedIn()->member_id, $member->member_id ) )->first();
throw new DomainException('altcontact_already_exists');
}
catch ( \UnderflowException $e ) {}
catch ( UnderflowException ) {}
} ) );
}
$form->add( new \IPS\Helpers\Form\Node( 'altcontact_purchases', $existing ? iterator_to_array( $existing->purchases ) : NULL, FALSE, array( 'class' => 'IPS\nexus\Purchase', 'forceOwner' => \IPS\Member::loggedIn(), 'multiple' => TRUE ) ) );
$form->add( new \IPS\Helpers\Form\Checkbox( 'altcontact_support', $existing ? $existing->support : FALSE ) );
$form->add( new \IPS\Helpers\Form\Checkbox( 'altcontact_billing', $existing ? $existing->billing : FALSE ) );
$form->add( new Node( 'altcontact_purchases', $existing ? iterator_to_array( $existing->purchases ) : NULL, FALSE, array( 'class' => 'IPS\nexus\Purchase', 'forceOwner' => Member::loggedIn(), 'multiple' => TRUE ) ) );
$form->add( new Checkbox( 'altcontact_billing', $existing ? $existing->billing : FALSE ) );
if ( $values = $form->values() )
{
if ( $existing )
{
$altContact = $existing;
\IPS\nexus\Customer::loggedIn()->log( 'alternative', array( 'type' => 'edit', 'alt_id' => $altContact->alt_id->member_id, 'alt_name' => $altContact->alt_id->name, 'purchases' => json_encode( $values['altcontact_purchases'] ? $values['altcontact_purchases'] : array() ), 'billing' => $values['altcontact_billing'], 'support' => $values['altcontact_support'] ) );
Customer::loggedIn()->log( 'alternative', array( 'type' => 'edit', 'alt_id' => $altContact->alt_id->member_id, 'alt_name' => $altContact->alt_id->name, 'purchases' => json_encode( $values['altcontact_purchases'] ?: array() ), 'billing' => $values['altcontact_billing'] ) );
}
else
{
$altContact = new \IPS\nexus\Customer\AlternativeContact;
$altContact->main_id = \IPS\nexus\Customer::loggedIn();
$altContact->alt_id = \IPS\Member::load( $values['altcontact_email'], 'email' );
\IPS\nexus\Customer::loggedIn()->log( 'alternative', array( 'type' => 'add', 'alt_id' => $altContact->alt_id->member_id, 'alt_name' => $altContact->alt_id->name, 'purchases' => json_encode( $values['altcontact_purchases'] ? $values['altcontact_purchases'] : array() ), 'billing' => $values['altcontact_billing'], 'support' => $values['altcontact_support'] ) );
$altContact = new AlternativeContact;
$altContact->main_id = Customer::loggedIn();
$altContact->alt_id = Member::load( $values['altcontact_email'], 'email' );
Customer::loggedIn()->log( 'alternative', array( 'type' => 'add', 'alt_id' => $altContact->alt_id->member_id, 'alt_name' => $altContact->alt_id->name, 'purchases' => json_encode( $values['altcontact_purchases'] ?: array() ), 'billing' => $values['altcontact_billing'] ) );
}
$altContact->purchases = $values['altcontact_purchases'] ? $values['altcontact_purchases'] : array();
$altContact->purchases = $values['altcontact_purchases'] ?: array();
$altContact->billing = $values['altcontact_billing'];
$altContact->support = $values['altcontact_support'];
$altContact->save();
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=nexus&module=clients&controller=alternatives', 'front', 'clientsalternatives' ) );
Output::i()->redirect( Url::internal( 'app=nexus&module=clients&controller=alternatives', 'front', 'clientsalternatives' ) );
}
if( \IPS\Request::i()->isAjax() )
if( Request::i()->isAjax() )
{
\IPS\Output::i()->sendOutput( $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) ) );
Output::i()->sendOutput( $form->customTemplate( array( Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) ) );
}
else
{
\IPS\Output::i()->output = $form;
}
Output::i()->output = $form;
}
}
/**
* Delete
*
* @return void
*/
protected function delete()
protected function delete() : void
{
\IPS\Session::i()->csrfCheck();
Session::i()->csrfCheck();
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
Request::i()->confirmedDelete();
try
{
$contact = \IPS\nexus\Customer\AlternativeContact::constructFromData( \IPS\Db::i()->select( '*', 'nexus_alternate_contacts', array( 'main_id=? AND alt_id=?', \IPS\nexus\Customer::loggedIn()->member_id, \IPS\Request::i()->id ) )->first() );
$contact = AlternativeContact::constructFromData( Db::i()->select( '*', 'nexus_alternate_contacts', array( 'main_id=? AND alt_id=?', Customer::loggedIn()->member_id, Request::i()->id ) )->first() );
$contact->delete();
\IPS\nexus\Customer::loggedIn()->log( 'alternative', array( 'type' => 'delete', 'alt_id' => $contact->alt_id->member_id, 'alt_name' => $contact->alt_id->name ) );
Customer::loggedIn()->log( 'alternative', array( 'type' => 'delete', 'alt_id' => $contact->alt_id->member_id, 'alt_name' => $contact->alt_id->name ) );
}
catch ( \UnderflowException $e ) {}
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=nexus&module=clients&controller=alternatives', 'front', 'clientsalternatives' ) );
catch (UnderflowException ) {}
Output::i()->redirect( Url::internal( 'app=nexus&module=clients&controller=alternatives', 'front', 'clientsalternatives' ) );
}
}
@@ -12,37 +12,58 @@
namespace IPS\nexus\modules\front\clients;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use DomainException;
use IPS\Db;
use IPS\Dispatcher\Controller;
use IPS\Http\Url;
use IPS\Member;
use IPS\MFA\MFAHandler;
use IPS\nexus\Customer;
use IPS\nexus\Customer\BillingAgreement;
use IPS\nexus\Gateway\PayPal\Exception;
use IPS\Output;
use IPS\Patterns\ActiveRecordIterator;
use IPS\Request;
use IPS\Session;
use IPS\Theme;
use OutOfRangeException;
use function count;
use function defined;
use function in_array;
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;
}
/**
* Billing Agreements
*/
class _billingagreements extends \IPS\Dispatcher\Controller
class billingagreements extends Controller
{
/**
* Execute
*
* @return void
*/
public function execute()
public function execute() : void
{
if ( !\IPS\Member::loggedIn()->member_id )
if ( !Member::loggedIn()->member_id )
{
\IPS\Output::i()->error( 'no_module_permission_guest', '2X321/1', 403, '' );
Output::i()->error( 'no_module_permission_guest', '2X321/1', 403, '' );
}
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'clients.css', 'nexus' ) );
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( 'app=nexus&module=clients&controller=billingagreements', 'front', 'clientsbillingagreements' ), \IPS\Member::loggedIn()->language()->addToStack('client_billing_agreements') );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('client_billing_agreements');
\IPS\Output::i()->sidebar['enabled'] = FALSE;
Output::i()->cssFiles = array_merge( Output::i()->cssFiles, Theme::i()->css( 'clients.css', 'nexus' ) );
Output::i()->breadcrumb[] = array( Url::internal( 'app=nexus&module=clients&controller=billingagreements', 'front', 'clientsbillingagreements' ), Member::loggedIn()->language()->addToStack('client_billing_agreements') );
Output::i()->title = Member::loggedIn()->language()->addToStack('client_billing_agreements');
Output::i()->sidebar['enabled'] = FALSE;
if ( $output = \IPS\MFA\MFAHandler::accessToArea( 'nexus', 'BillingAgreements', \IPS\Http\Url::internal( 'app=nexus&module=clients&controller=billingagreements', 'front', 'clientsbillingagreements' ) ) )
if ( $output = MFAHandler::accessToArea( 'nexus', 'BillingAgreements', Url::internal( 'app=nexus&module=clients&controller=billingagreements', 'front', 'clientsbillingagreements' ) ) )
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('clients')->billingAgreements( array() ) . $output;
Output::i()->output = Theme::i()->getTemplate('clients')->billingAgreements( array() ) . $output;
return;
}
@@ -54,15 +75,14 @@ class _billingagreements extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function manage()
protected function manage() : void
{
$billingAgreements = array();
$where = array( 'ba_member=?', \IPS\Member::loggedIn()->member_id );
$parentContacts = \IPS\nexus\Customer::loggedIn()->parentContacts( array( 'billing=1' ) );
if ( \count( $parentContacts ) )
$where = array( 'ba_member=?', Member::loggedIn()->member_id );
$parentContacts = Customer::loggedIn()->parentContacts( array( 'billing=1' ) );
if ( count( $parentContacts ) )
{
$or = array();
foreach ( array_keys( iterator_to_array( $parentContacts ) ) as $id )
{
$where[0] .= ' OR ba_member=?';
@@ -70,13 +90,14 @@ class _billingagreements extends \IPS\Dispatcher\Controller
}
}
foreach ( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'nexus_billing_agreements', $where ), 'IPS\nexus\Customer\BillingAgreement' ) as $billingAgreement )
{
foreach ( new ActiveRecordIterator( Db::i()->select( '*', 'nexus_billing_agreements', $where ), 'IPS\nexus\Customer\BillingAgreement' ) as $billingAgreement )
{
/* @var BillingAgreement $billingAgreement */
try
{
$status = $billingAgreement->status();
}
catch ( \Exception $e )
catch ( \Exception )
{
$status = NULL;
}
@@ -85,7 +106,7 @@ class _billingagreements extends \IPS\Dispatcher\Controller
{
$term = $billingAgreement->term();
}
catch ( \Exception $e )
catch ( \Exception )
{
$term = NULL;
}
@@ -98,7 +119,7 @@ class _billingagreements extends \IPS\Dispatcher\Controller
);
}
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('clients')->billingAgreements( $billingAgreements );
Output::i()->output = Theme::i()->getTemplate('clients')->billingAgreements( $billingAgreements );
}
/**
@@ -106,48 +127,48 @@ class _billingagreements extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function view()
protected function view() : void
{
/* Load Billing Agreement */
try
{
$billingAgreement = \IPS\nexus\Customer\BillingAgreement::loadAndCheckPerms( \IPS\Request::i()->id );
$billingAgreement = BillingAgreement::loadAndCheckPerms( Request::i()->id );
$billingAgreement->status(); // Just to make the API call so we can catch the error if there is one
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException )
{
\IPS\Output::i()->error( 'node_error', '2X320/4', 404, '' );
Output::i()->error( 'node_error', '2X320/4', 404, '' );
}
catch ( \IPS\nexus\Gateway\PayPal\Exception $e )
catch ( Exception $e )
{
\IPS\Output::i()->error( 'billing_agreement_error', '4X321/5', 500, '', array(), $e->getName() );
Output::i()->error( 'billing_agreement_error', '4X321/5', 500, '', array(), $e->getName() );
}
/* Get associated purchases */
$purchases = array();
foreach( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'nexus_purchases', array( 'ps_billing_agreement=?', $billingAgreement->id ) ), 'IPS\nexus\Purchase' ) as $purchase )
foreach( new ActiveRecordIterator( Db::i()->select( '*', 'nexus_purchases', array( 'ps_billing_agreement=?', $billingAgreement->id ) ), 'IPS\nexus\Purchase' ) as $purchase )
{
$purchases[0][ $purchase->id ] = $purchase;
}
/* Transactions */
$currentPage = isset( \IPS\Request::i()->page ) ? \intval( \IPS\Request::i()->page ) : 1;
$currentPage = isset( Request::i()->page ) ? intval( Request::i()->page ) : 1;
$perPage = 25;
$invoices = new \IPS\Patterns\ActiveRecordIterator(
\IPS\Db::i()->select(
$invoices = new ActiveRecordIterator(
Db::i()->select(
'*',
'nexus_invoices',
array( 'i_id IN(?)', \IPS\Db::i()->select( 't_invoice', 'nexus_transactions', array( 't_billing_agreement=?', $billingAgreement->id ) ) ),
array( 'i_id IN(?)', Db::i()->select( 't_invoice', 'nexus_transactions', array( 't_billing_agreement=?', $billingAgreement->id ) ) ),
'i_date DESC',
array( ( $currentPage - 1 ) * $perPage, $perPage )
),
'IPS\nexus\Invoice'
);
$invoicesCount = \IPS\Db::i()->select( 'COUNT(*)', 'nexus_invoices', array( 'i_id IN(?)', \IPS\Db::i()->select( 't_invoice', 'nexus_transactions', array( 't_billing_agreement=?', $billingAgreement->id ) ) ) )->first();
$pagination = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination( $billingAgreement->url(), ceil( $invoicesCount / $perPage ), $currentPage, $perPage );
$invoicesCount = Db::i()->select( 'COUNT(*)', 'nexus_invoices', array( 'i_id IN(?)', Db::i()->select( 't_invoice', 'nexus_transactions', array( 't_billing_agreement=?', $billingAgreement->id ) ) ) )->first();
$pagination = Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination( $billingAgreement->url(), ceil( $invoicesCount / $perPage ), $currentPage, $perPage );
\IPS\Output::i()->breadcrumb[] = array( $billingAgreement->url(), $billingAgreement->gw_id );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('clients')->billingAgreement( $billingAgreement, $purchases, $invoices, $pagination );
Output::i()->breadcrumb[] = array( $billingAgreement->url(), $billingAgreement->gw_id );
Output::i()->output = Theme::i()->getTemplate('clients')->billingAgreement( $billingAgreement, $purchases, $invoices, $pagination );
}
/**
@@ -155,25 +176,25 @@ class _billingagreements extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function act()
protected function act() : void
{
\IPS\Session::i()->csrfCheck();
Session::i()->csrfCheck();
/* Check act */
$act = \IPS\Request::i()->act;
if ( !\in_array( $act, array( 'suspend', 'reactivate', 'cancel' ) ) )
$act = Request::i()->act;
if ( !in_array( $act, array( 'suspend', 'reactivate', 'cancel' ) ) )
{
\IPS\Output::i()->error( 'node_error', '3X321/3', 403, '' );
Output::i()->error( 'node_error', '3X321/3', 403, '' );
}
/* Load Billing Agreement */
try
{
$billingAgreement = \IPS\nexus\Customer\BillingAgreement::loadAndCheckPerms( \IPS\Request::i()->id );
$billingAgreement = BillingAgreement::loadAndCheckPerms( Request::i()->id );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException )
{
\IPS\Output::i()->error( 'node_error', '2X321/2', 404, '' );
Output::i()->error( 'node_error', '2X321/2', 404, '' );
}
/* Perform Action */
@@ -181,11 +202,11 @@ class _billingagreements extends \IPS\Dispatcher\Controller
{
$billingAgreement->$act();
\IPS\Output::i()->redirect( $billingAgreement->url() );
Output::i()->redirect( $billingAgreement->url() );
}
catch ( \DomainException $e )
catch ( DomainException )
{
\IPS\Output::i()->error( 'billing_agreement_error_public', '3X321/4', 500, '' );
Output::i()->error( 'billing_agreement_error_public', '3X321/4', 500, '' );
}
}
}
@@ -12,37 +12,54 @@
namespace IPS\nexus\modules\front\clients;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use Exception;
use IPS\Db;
use IPS\Dispatcher\Controller;
use IPS\Http\Url;
use IPS\Member;
use IPS\MFA\MFAHandler;
use IPS\nexus\Customer;
use IPS\nexus\Customer\CreditCard;
use IPS\Output;
use IPS\Patterns\ActiveRecordIterator;
use IPS\Request;
use IPS\Session;
use IPS\Theme;
use function defined;
use function is_null;
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;
}
/**
* Cards
*/
class _cards extends \IPS\Dispatcher\Controller
class cards extends Controller
{
/**
* Execute
*
* @return void
*/
public function execute()
public function execute() : void
{
if ( !\IPS\Member::loggedIn()->member_id )
if ( !Member::loggedIn()->member_id )
{
\IPS\Output::i()->error( 'no_module_permission_guest', '2X236/1', 403, '' );
Output::i()->error( 'no_module_permission_guest', '2X236/1', 403, '' );
}
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'clients.css', 'nexus' ) );
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( 'app=nexus&module=clients&controller=cards', 'front', 'clientscards' ), \IPS\Member::loggedIn()->language()->addToStack('client_cards') );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('client_cards');
\IPS\Output::i()->sidebar['enabled'] = FALSE;
Output::i()->cssFiles = array_merge( Output::i()->cssFiles, Theme::i()->css( 'clients.css', 'nexus' ) );
Output::i()->breadcrumb[] = array( Url::internal( 'app=nexus&module=clients&controller=cards', 'front', 'clientscards' ), Member::loggedIn()->language()->addToStack('client_cards') );
Output::i()->title = Member::loggedIn()->language()->addToStack('client_cards');
Output::i()->sidebar['enabled'] = FALSE;
if ( $output = \IPS\MFA\MFAHandler::accessToArea( 'nexus', 'Cards', \IPS\Http\Url::internal( 'app=nexus&module=clients&controller=cards', 'front', 'clientscards' ) ) )
if ( $output = MFAHandler::accessToArea( 'nexus', 'Cards', Url::internal( 'app=nexus&module=clients&controller=cards', 'front', 'clientscards' ) ) )
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('clients')->cards( array() ) . $output;
Output::i()->output = Theme::i()->getTemplate('clients')->cards( array() ) . $output;
return;
}
@@ -54,10 +71,10 @@ class _cards extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function manage()
protected function manage() : void
{
$cards = array();
foreach ( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'nexus_customer_cards', array( 'card_member=?', \IPS\nexus\Customer::loggedIn()->member_id ) ), 'IPS\nexus\Customer\CreditCard' ) as $card )
foreach ( new ActiveRecordIterator( Db::i()->select( '*', 'nexus_customer_cards', array( 'card_member=?', Customer::loggedIn()->member_id ) ), 'IPS\nexus\Customer\CreditCard' ) as $card )
{
try
{
@@ -66,13 +83,13 @@ class _cards extends \IPS\Dispatcher\Controller
'id' => $card->id,
'card_type' => $cardData->type,
'card_number' => $cardData->lastFour ?: $cardData->number,
'card_expire' => ( !\is_null( $cardData->expMonth ) AND !\is_null( $cardData->expYear ) ) ? str_pad( $cardData->expMonth , 2, '0', STR_PAD_LEFT ). '/' . $cardData->expYear : NULL
'card_expire' => ( !is_null( $cardData->expMonth ) AND !is_null( $cardData->expYear ) ) ? str_pad( $cardData->expMonth , 2, '0', STR_PAD_LEFT ). '/' . $cardData->expYear : NULL
);
}
catch ( \Exception $e ) { }
catch ( Exception ) { }
}
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('clients')->cards( $cards );
Output::i()->output = Theme::i()->getTemplate('clients')->cards( $cards );
}
/**
@@ -80,19 +97,19 @@ class _cards extends \IPS\Dispatcher\Controller
*
* @return void
*/
public function add()
public function add() : void
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'checkout.css', 'nexus' ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'global_gateways.js', 'nexus', 'global' ) );
$form = \IPS\nexus\Customer\CreditCard::create( \IPS\nexus\Customer::loggedIn(), FALSE );
if ( $form instanceof \IPS\nexus\Customer\CreditCard )
Output::i()->cssFiles = array_merge( Output::i()->cssFiles, Theme::i()->css( 'checkout.css', 'nexus' ) );
Output::i()->jsFiles = array_merge( Output::i()->jsFiles, Output::i()->js( 'global_gateways.js', 'nexus', 'global' ) );
$form = CreditCard::create( Customer::loggedIn(), FALSE );
if ( $form instanceof CreditCard )
{
\IPS\nexus\Customer::loggedIn()->log( 'card', array( 'type' => 'add', 'number' => $form->card->lastFour ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=nexus&module=clients&controller=cards', 'front', 'clientscards' ) );
Customer::loggedIn()->log( 'card', array( 'type' => 'add', 'number' => $form->card->lastFour ) );
Output::i()->redirect( Url::internal( 'app=nexus&module=clients&controller=cards', 'front', 'clientscards' ) );
}
else
{
\IPS\Output::i()->output = $form;
Output::i()->output = $form;
}
}
@@ -101,26 +118,26 @@ class _cards extends \IPS\Dispatcher\Controller
*
* @return void
*/
public function delete()
public function delete() : void
{
\IPS\Session::i()->csrfCheck();
Session::i()->csrfCheck();
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
Request::i()->confirmedDelete();
try
{
$card = \IPS\nexus\Customer\CreditCard::load( \IPS\Request::i()->id );
if ( $card->member->member_id === \IPS\nexus\Customer::loggedIn()->member_id )
$card = CreditCard::load( Request::i()->id );
if ( $card->member->member_id === Customer::loggedIn()->member_id )
{
$cardData = $card->card;
$card->delete();
\IPS\nexus\Customer::loggedIn()->log( 'card', array( 'type' => 'delete', 'number' => $cardData->lastFour ) );
Customer::loggedIn()->log( 'card', array( 'type' => 'delete', 'number' => $cardData->lastFour ) );
}
}
catch ( \Exception $e ) { }
catch ( Exception ) { }
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=nexus&module=clients&controller=cards', 'front', 'clientscards' ) );
Output::i()->redirect( Url::internal( 'app=nexus&module=clients&controller=cards', 'front', 'clientscards' ) );
}
}
@@ -12,37 +12,72 @@
namespace IPS\nexus\modules\front\clients;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use DateInterval;
use DomainException;
use Exception;
use IPS\core\AdminNotification;
use IPS\DateTime;
use IPS\Db;
use IPS\Dispatcher\Controller;
use IPS\Helpers\Form;
use IPS\Helpers\Form\Number;
use IPS\Helpers\Form\Radio;
use IPS\Http\Url;
use IPS\Member;
use IPS\MFA\MFAHandler;
use IPS\nexus\Customer;
use IPS\nexus\Customer\AlternativeContact;
use IPS\nexus\extensions\nexus\Item\AccountCreditIncrease;
use IPS\nexus\Gateway;
use IPS\nexus\Invoice;
use IPS\nexus\Money;
use IPS\nexus\Payout;
use IPS\Output;
use IPS\Patterns\ActiveRecordIterator;
use IPS\Request;
use IPS\Session;
use IPS\Settings;
use IPS\Theme;
use OutOfRangeException;
use function count;
use function defined;
use function in_array;
use function intval;
use function is_countable;
use function is_null;
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;
}
/**
* Account Credit
*/
class _credit extends \IPS\Dispatcher\Controller
class credit extends Controller
{
/**
* Execute
*
* @return void
*/
public function execute()
public function execute() : void
{
if ( !\IPS\Member::loggedIn()->member_id )
if ( !Member::loggedIn()->member_id )
{
\IPS\Output::i()->error( 'no_module_permission_guest', '2X239/1', 403, '' );
Output::i()->error( 'no_module_permission_guest', '2X239/1', 403, '' );
}
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'clients.css', 'nexus' ) );
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( 'app=nexus&module=clients&controller=credit', 'front', 'clientscredit' ), \IPS\Member::loggedIn()->language()->addToStack('client_credit') );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('client_credit');
\IPS\Output::i()->sidebar['enabled'] = FALSE;
Output::i()->cssFiles = array_merge( Output::i()->cssFiles, Theme::i()->css( 'clients.css', 'nexus' ) );
Output::i()->breadcrumb[] = array( Url::internal( 'app=nexus&module=clients&controller=credit', 'front', 'clientscredit' ), Member::loggedIn()->language()->addToStack('client_credit') );
Output::i()->title = Member::loggedIn()->language()->addToStack('client_credit');
Output::i()->sidebar['enabled'] = FALSE;
if ( $output = \IPS\MFA\MFAHandler::accessToArea( 'nexus', 'AccountCredit', \IPS\Http\Url::internal( 'app=nexus&module=clients&controller=credit', 'front', 'clientscredit' ) ) )
if ( $output = MFAHandler::accessToArea( 'nexus', 'AccountCredit', Url::internal( 'app=nexus&module=clients&controller=credit', 'front', 'clientscredit' ) ) )
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('clients')->credit( NULL, array(), NULL, FALSE, FALSE ) . $output;
Output::i()->output = Theme::i()->getTemplate('clients')->credit( NULL, array(), NULL, FALSE, FALSE ) . $output;
return;
}
@@ -54,38 +89,38 @@ class _credit extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function manage()
protected function manage() : void
{
/* Get Balance(s) */
$balance = array_filter( \IPS\nexus\Customer::loggedIn()->cm_credits, function( $val )
$balance = array_filter( Customer::loggedIn()->cm_credits, function( $val )
{
return $val->amount;
} );
/* Pending Withdrawls */
$perPage = 10;
$page = isset( \IPS\Request::i()->page ) ? \intval( \IPS\Request::i()->page ) : 1;
$page = isset( Request::i()->page ) ? intval( Request::i()->page ) : 1;
if( $page < 1 )
{
$page = 1;
}
$pastWithdrawalsSelect = \IPS\Db::i()->select( '*', 'nexus_payouts', array( 'po_member=?', \IPS\nexus\Customer::loggedIn()->member_id ), 'po_date DESC', array( ( $page - 1 ) * $perPage, $perPage ) );
$pastWithdrawalsPagination = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination(
\IPS\Http\Url::internal( 'app=nexus&module=clients&controller=credit', 'front', 'clientscredit' ),
ceil( \IPS\Db::i()->select( 'COUNT(*)', 'nexus_payouts', array( 'po_member=?', \IPS\nexus\Customer::loggedIn()->member_id ) )->first() / $perPage ),
$pastWithdrawalsSelect = Db::i()->select( '*', 'nexus_payouts', array( 'po_member=?', Customer::loggedIn()->member_id ), 'po_date DESC', array( ( $page - 1 ) * $perPage, $perPage ) );
$pastWithdrawalsPagination = Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination(
Url::internal( 'app=nexus&module=clients&controller=credit', 'front', 'clientscredit' ),
ceil( Db::i()->select( 'COUNT(*)', 'nexus_payouts', array( 'po_member=?', Customer::loggedIn()->member_id ) )->first() / $perPage ),
$page,
$perPage
);
$pastWithdrawals = new \IPS\Patterns\ActiveRecordIterator( $pastWithdrawalsSelect, 'IPS\nexus\Payout' );
$pastWithdrawals = new ActiveRecordIterator( $pastWithdrawalsSelect, 'IPS\nexus\Payout' );
$activePayouts = [];
if( !\IPS\Settings::i()->nexus_payout_unlimited_times )
if( !Settings::i()->nexus_payout_unlimited_times )
{
foreach ( $pastWithdrawals as $payout )
{
if ( $payout->status == \IPS\nexus\Payout::STATUS_PENDING )
if ( $payout->status == Payout::STATUS_PENDING )
{
$activePayouts[ $payout->currency ] = TRUE;
}
@@ -94,10 +129,10 @@ class _credit extends \IPS\Dispatcher\Controller
/* Can we withdraw? */
$canWithdraw = FALSE;
$withdrawOptions = json_decode( \IPS\Settings::i()->nexus_payout, TRUE );
if( \is_countable( $withdrawOptions ) AND \count( $withdrawOptions ) )
$withdrawOptions = json_decode( Settings::i()->nexus_payout, TRUE );
if( is_countable( $withdrawOptions ) AND count( $withdrawOptions ) )
{
foreach ( \IPS\nexus\Money::currencies() as $currency )
foreach ( Money::currencies() as $currency )
{
if ( isset( $balance[ $currency ] ) and $balance[ $currency ]->amount->isGreaterThanZero() and !isset( $activePayouts[ $currency ] ) )
{
@@ -108,22 +143,20 @@ class _credit extends \IPS\Dispatcher\Controller
/* Can we topup? */
$canTopup = FALSE;
if ( \IPS\Settings::i()->nexus_min_topup )
if ( Settings::i()->nexus_min_topup )
{
$minimumTopupAmounts = ( \IPS\Settings::i()->nexus_min_topup and \IPS\Settings::i()->nexus_min_topup !== '*' ) ? json_decode( \IPS\Settings::i()->nexus_min_topup, TRUE ) : NULL;
$maximumBalanceAmounts = ( \IPS\Settings::i()->nexus_max_credit and \IPS\Settings::i()->nexus_max_credit !== '*' ) ? json_decode( \IPS\Settings::i()->nexus_max_credit, TRUE ) : NULL;
$maximumBalanceAmounts = ( Settings::i()->nexus_max_credit and Settings::i()->nexus_max_credit !== '*' ) ? json_decode( Settings::i()->nexus_max_credit, TRUE ) : NULL;
$maximums = array();
foreach ( array_merge( array( \IPS\nexus\Customer::loggedIn() ), iterator_to_array( \IPS\nexus\Customer::loggedIn()->parentContacts( array('billing=1') ) ) ) as $account )
foreach ( array_merge( array( Customer::loggedIn() ), iterator_to_array( Customer::loggedIn()->parentContacts( array('billing=1') ) ) ) as $account )
{
if ( $account instanceof \IPS\nexus\Customer\AlternativeContact )
if ( $account instanceof AlternativeContact )
{
$account = $account->main_id;
}
foreach ( $account->cm_credits as $value )
{
if ( $maximumBalanceAmounts === NULL or $value->amount->compare( new \IPS\Math\Number( number_format( $maximumBalanceAmounts[ $value->currency ]['amount'], \IPS\nexus\Money::numberOfDecimalsForCurrency( $value->currency ), '.', '' ) ) ) === -1 )
if ( $maximumBalanceAmounts === NULL or $value->amount->compare( new \IPS\Math\Number( number_format( $maximumBalanceAmounts[ $value->currency ]['amount'], Money::numberOfDecimalsForCurrency( $value->currency ), '.', '' ) ) ) === -1 )
{
$canTopup = TRUE;
}
@@ -132,7 +165,7 @@ class _credit extends \IPS\Dispatcher\Controller
}
/* Display */
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('clients')->credit( $balance, $pastWithdrawals, $pastWithdrawalsPagination, $canWithdraw, $canTopup );
Output::i()->output = Theme::i()->getTemplate('clients')->credit( $balance, $pastWithdrawals, $pastWithdrawalsPagination, $canWithdraw, $canTopup );
}
/**
@@ -140,47 +173,47 @@ class _credit extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function withdraw()
protected function withdraw() : void
{
$activeWithdrawals = \IPS\Settings::i()->nexus_payout_unlimited_times ? [] : iterator_to_array( \IPS\Db::i()->select( 'po_currency', 'nexus_payouts', array( 'po_status=? AND po_member=?', \IPS\nexus\Payout::STATUS_PENDING, \IPS\nexus\Customer::loggedIn()->member_id ) ) );
$activeWithdrawals = Settings::i()->nexus_payout_unlimited_times ? [] : iterator_to_array( Db::i()->select( 'po_currency', 'nexus_payouts', array( 'po_status=? AND po_member=?', Payout::STATUS_PENDING, Customer::loggedIn()->member_id ) ) );
$withdrawForm = NULL;
$withdrawOptions = json_decode( \IPS\Settings::i()->nexus_payout, TRUE );
$withdrawOptions = json_decode( Settings::i()->nexus_payout, TRUE );
if ( isset( $withdrawOptions['Stripe'] ) )
{
unset( $withdrawOptions['Stripe'] );
}
if ( \is_countable( $withdrawOptions ) AND \count( $withdrawOptions ) )
if ( is_countable( $withdrawOptions ) AND count( $withdrawOptions ) )
{
$withdrawForm = new \IPS\Helpers\Form( 'withdraw', 'withdraw_credit' );
$withdrawForm = new Form( 'withdraw', 'withdraw_credit' );
$minimumWithdrawalsAmounts = ( \IPS\Settings::i()->nexus_payout_min and \IPS\Settings::i()->nexus_payout_min !== '*' ) ? json_decode( \IPS\Settings::i()->nexus_payout_min, TRUE ) : NULL;
$maximumWithdrawalsAmounts = ( \IPS\Settings::i()->nexus_payout_max and \IPS\Settings::i()->nexus_payout_max !== '*' ) ? json_decode( \IPS\Settings::i()->nexus_payout_max, TRUE ) : NULL;
$minimumWithdrawalsAmounts = ( Settings::i()->nexus_payout_min and Settings::i()->nexus_payout_min !== '*' ) ? json_decode( Settings::i()->nexus_payout_min, TRUE ) : NULL;
$maximumWithdrawalsAmounts = ( Settings::i()->nexus_payout_max and Settings::i()->nexus_payout_max !== '*' ) ? json_decode( Settings::i()->nexus_payout_max, TRUE ) : NULL;
$balance = array_filter( \IPS\nexus\Customer::loggedIn()->cm_credits, function( $val )
$balance = array_filter( Customer::loggedIn()->cm_credits, function( $val )
{
return $val->amount;
} );
$currencyOptions = array();
if ( \count( $balance ) > 1 )
if ( count( $balance ) > 1 )
{
$currencyToggles = array();
foreach ( \IPS\nexus\Money::currencies() as $currency )
foreach ( Money::currencies() as $currency )
{
if ( isset( $balance[ $currency ] ) AND !\in_array( $currency, $activeWithdrawals ) )
if ( isset( $balance[ $currency ] ) AND !in_array( $currency, $activeWithdrawals ) )
{
$currencyOptions[ $currency ] = $currency;
$currencyToggles[ $currency ] = array( 'withdraw_amount_' . $currency );
}
}
$withdrawForm->add( new \IPS\Helpers\Form\Radio( 'withdraw_currency', NULL, TRUE, array( 'options' => $currencyOptions, 'toggles' => $currencyToggles ) ) );
$withdrawForm->add( new Radio( 'withdraw_currency', NULL, TRUE, array( 'options' => $currencyOptions, 'toggles' => $currencyToggles ) ) );
}
$canWithdraw = FALSE;
foreach ( \IPS\nexus\Money::currencies() as $currency )
foreach ( Money::currencies() as $currency )
{
if ( !isset( $balance[ $currency ] ) OR ( !\IPS\Settings::i()->nexus_payout_unlimited_times AND \in_array( $currency, $activeWithdrawals ) ) )
if ( !isset( $balance[ $currency ] ) OR ( !Settings::i()->nexus_payout_unlimited_times AND in_array( $currency, $activeWithdrawals ) ) )
{
continue;
}
@@ -197,13 +230,13 @@ class _credit extends \IPS\Dispatcher\Controller
$upperLimit = $maximumWithdrawalsAmounts[ $currency ];
/* Determine our date cutoff */
$periodRestrictions = json_decode( \IPS\Settings::i()->nexus_payout_max_period, TRUE );
$periodRestrictions = json_decode( Settings::i()->nexus_payout_max_period, TRUE );
$interval = 'P' . (int) $periodRestrictions[0] . ( mb_strtoupper( mb_substr( $periodRestrictions[1], 0, 1 ) ) );
$date = \IPS\DateTime::create()->sub( new \DateInterval( $interval ) )->getTimestamp();
$date = DateTime::create()->sub( new DateInterval( $interval ) )->getTimestamp();
/* Get our (non-cancelled) payout requests since the date cutoff */
foreach( \IPS\Db::i()->select( '*', 'nexus_payouts', array( 'po_member=? AND po_date>? AND po_status NOT IN(?) AND po_currency=?', \IPS\nexus\Customer::loggedIn()->member_id, $date, 'canc', $currency ) ) as $request )
foreach( Db::i()->select( '*', 'nexus_payouts', array( 'po_member=? AND po_date>? AND po_status NOT IN(?) AND po_currency=?', Customer::loggedIn()->member_id, $date, 'canc', $currency ) ) as $request )
{
$upperLimit -= $request['po_amount'];
}
@@ -217,17 +250,17 @@ class _credit extends \IPS\Dispatcher\Controller
if( $max <= 0 )
{
\IPS\Member::loggedIn()->language()->words[ 'withdraw_amount_' . $currency . '_desc' ] = \IPS\Member::loggedIn()->language()->addToStack( 'max_withdrawl_exceeded' );
Member::loggedIn()->language()->words[ 'withdraw_amount_' . $currency . '_desc' ] = Member::loggedIn()->language()->addToStack( 'max_withdrawl_exceeded' );
}
$field = new \IPS\Helpers\Form\Number( 'withdraw_amount_' . $currency, (string) $max, \count( $currencyOptions ) ? NULL : TRUE, array( 'min' => $min, 'max' => (string) $max, 'decimals' => \IPS\nexus\Money::numberOfDecimalsForCurrency( $currency ), 'disabled' => ( $max <= 0 ) ), \count( $currencyOptions ) ? NULL : function( $val ) use ( $currency )
$field = new Number( 'withdraw_amount_' . $currency, (string) $max, count( $currencyOptions ) ? NULL : TRUE, array( 'min' => $min, 'max' => (string) $max, 'decimals' => Money::numberOfDecimalsForCurrency( $currency ), 'disabled' => ( $max <= 0 ) ), count( $currencyOptions ) ? NULL : function( $val ) use ( $currency )
{
if ( !$val and \IPS\Request::i()->withdraw_currency === $currency )
if ( !$val and Request::i()->withdraw_currency === $currency )
{
throw new \DomainException('form_required');
throw new DomainException('form_required');
}
}, NULL, $currency, 'withdraw_amount_' . $currency );
$field->label = \IPS\Member::loggedIn()->language()->addToStack('withdraw_amount');
$field->label = Member::loggedIn()->language()->addToStack('withdraw_amount');
$withdrawForm->add( $field );
$canWithdraw = TRUE;
@@ -242,7 +275,9 @@ class _credit extends \IPS\Dispatcher\Controller
{
$options[ $k ] = $k === 'Manual' ? $settings['name'] : 'withdraw__' . $k;
$toggles[ $k ] = array();
$class = \IPS\nexus\Gateway::payoutGateways()[ $k ];
/* @var Payout $class */
$class = Gateway::payoutGateways()[ $k ];
foreach ( $class::form() as $field )
{
if ( !$field->htmlId )
@@ -254,9 +289,9 @@ class _credit extends \IPS\Dispatcher\Controller
}
}
if ( \is_countable( $withdrawOptions ) AND \count( $withdrawOptions ) > 1 )
if ( is_countable( $withdrawOptions ) AND count( $withdrawOptions ) > 1 )
{
$withdrawForm->add( new \IPS\Helpers\Form\Radio( 'withdraw_method', NULL, TRUE, array( 'options' => $options, 'toggles' => $toggles ) ) );
$withdrawForm->add( new Radio( 'withdraw_method', NULL, TRUE, array( 'options' => $options, 'toggles' => $toggles ) ) );
}
foreach ( $fields as $field )
@@ -266,55 +301,55 @@ class _credit extends \IPS\Dispatcher\Controller
if ( $values = $withdrawForm->values() )
{
$currencies = array_keys( $balance );
$currency = \count( $currencyOptions ) ? $values['withdraw_currency'] : array_pop( $currencies );
$currency = count( $currencyOptions ) ? $values['withdraw_currency'] : array_pop( $currencies );
$withdrawMethods = array_keys( $options );
if ( \count( $withdrawMethods ) === 1 )
if ( count( $withdrawMethods ) === 1 )
{
$key = array_pop( $withdrawMethods );
$class = \IPS\nexus\Gateway::payoutGateways()[ $key ];
$class = Gateway::payoutGateways()[ $key ];
}
else
{
$class = \IPS\nexus\Gateway::payoutGateways()[ $values['withdraw_method'] ];
$class = Gateway::payoutGateways()[ $values['withdraw_method'] ];
}
$payout = new $class;
$payout->amount = new \IPS\nexus\Money( $values[ 'withdraw_amount_' . $currency ], $currency );
$payout->member = \IPS\nexus\Customer::loggedIn();
$payout->amount = new Money( $values[ 'withdraw_amount_' . $currency ], $currency );
$payout->member = Customer::loggedIn();
try
{
$payout->data = $payout->getData( $values );
}
catch ( \DomainException $e )
catch ( DomainException $e )
{
\IPS\Output::i()->error( $e->getMessage(), '1X239/2', 403, '' );
Output::i()->error( $e->getMessage(), '1X239/2', 403, '' );
}
$payout->ip = \IPS\Request::i()->ipAddress();
$payout->ip = Request::i()->ipAddress();
$payout->save();
$credits = \IPS\nexus\Customer::loggedIn()->cm_credits;
$credits[ $currency ]->amount = $credits[ $currency ]->amount->subtract( new \IPS\Math\Number( number_format( $values[ 'withdraw_amount_' . $currency ], \IPS\nexus\Money::numberOfDecimalsForCurrency( $currency ), '.', '' ) ) );
\IPS\nexus\Customer::loggedIn()->cm_credits = $credits;
\IPS\nexus\Customer::loggedIn()->save();
$credits = Customer::loggedIn()->cm_credits;
$credits[ $currency ]->amount = $credits[ $currency ]->amount->subtract( new \IPS\Math\Number( number_format( $values[ 'withdraw_amount_' . $currency ], Money::numberOfDecimalsForCurrency( $currency ), '.', '' ) ) );
Customer::loggedIn()->cm_credits = $credits;
Customer::loggedIn()->save();
if ( !\IPS\Settings::i()->nexus_payout_approve and !$payout::$requiresApproval )
if ( !Settings::i()->nexus_payout_approve and !$payout::$requiresApproval )
{
try
{
$payout->process();
\IPS\nexus\Customer::loggedIn()->log( 'payout', array( 'type' => 'autoprocess', 'amount' => $values[ 'withdraw_amount_' . $currency ], 'currency' => $currency, 'payout_id' => $payout->id ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=nexus&module=clients&controller=credit&withdraw=success', 'front', 'clientscredit' ) );
Customer::loggedIn()->log( 'payout', array( 'type' => 'autoprocess', 'amount' => $values[ 'withdraw_amount_' . $currency ], 'currency' => $currency, 'payout_id' => $payout->id ) );
Output::i()->redirect( Url::internal( 'app=nexus&module=clients&controller=credit&withdraw=success', 'front', 'clientscredit' ) );
}
catch ( \Exception $e ) {}
catch ( Exception ) {}
}
else
{
\IPS\core\AdminNotification::send( 'nexus', 'Withdrawal', NULL, TRUE, $payout );
AdminNotification::send( 'nexus', 'Withdrawal', NULL, TRUE, $payout );
}
\IPS\nexus\Customer::loggedIn()->log( 'payout', array( 'type' => 'request', 'amount' => $values[ 'withdraw_amount_' . $currency ], 'currency' => $currency, 'payout_id' => $payout->id ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=nexus&module=clients&controller=credit&withdraw=pending', 'front', 'clientscredit' ) );
Customer::loggedIn()->log( 'payout', array( 'type' => 'request', 'amount' => $values[ 'withdraw_amount_' . $currency ], 'currency' => $currency, 'payout_id' => $payout->id ) );
Output::i()->redirect( Url::internal( 'app=nexus&module=clients&controller=credit&withdraw=pending', 'front', 'clientscredit' ) );
}
}
else
@@ -325,10 +360,10 @@ class _credit extends \IPS\Dispatcher\Controller
if ( !$withdrawForm )
{
\IPS\Output::i()->error( 'no_module_permission', '2X239/3', 403, '' );
Output::i()->error( 'no_module_permission', '2X239/3', 403, '' );
}
\IPS\Output::i()->output = $withdrawForm->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
Output::i()->output = $withdrawForm->customTemplate( array( Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
}
/**
@@ -336,54 +371,55 @@ class _credit extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function topup()
protected function topup() : void
{
$topupForm = NULL;
if ( \IPS\Settings::i()->nexus_min_topup )
if ( Settings::i()->nexus_min_topup )
{
$minimumTopupAmounts = ( \IPS\Settings::i()->nexus_min_topup and \IPS\Settings::i()->nexus_min_topup !== '*' ) ? json_decode( \IPS\Settings::i()->nexus_min_topup, TRUE ) : NULL;
$maximumBalanceAmounts = ( \IPS\Settings::i()->nexus_max_credit and \IPS\Settings::i()->nexus_max_credit !== '*' ) ? json_decode( \IPS\Settings::i()->nexus_max_credit, TRUE ) : NULL;
$minimumTopupAmounts = ( Settings::i()->nexus_min_topup and Settings::i()->nexus_min_topup !== '*' ) ? json_decode( Settings::i()->nexus_min_topup, TRUE ) : NULL;
$maximumBalanceAmounts = ( Settings::i()->nexus_max_credit and Settings::i()->nexus_max_credit !== '*' ) ? json_decode( Settings::i()->nexus_max_credit, TRUE ) : NULL;
$maximums = array();
foreach ( array_merge( array( \IPS\nexus\Customer::loggedIn() ), iterator_to_array( \IPS\nexus\Customer::loggedIn()->parentContacts( array('billing=1') ) ) ) as $account )
foreach ( array_merge( array( Customer::loggedIn() ), iterator_to_array( Customer::loggedIn()->parentContacts( array('billing=1') ) ) ) as $account )
{
if ( $account instanceof \IPS\nexus\Customer\AlternativeContact )
if ( $account instanceof AlternativeContact )
{
$account = $account->main_id;
}
foreach ( $account->cm_credits as $value )
{
$max = $maximumBalanceAmounts ? ( ( new \IPS\Math\Number( number_format( $maximumBalanceAmounts[ $value->currency ]['amount'], \IPS\nexus\Money::numberOfDecimalsForCurrency( $value->currency ), '.', '' ) ) )->subtract( $value->amount ) ) : NULL;
if ( \is_null( $max ) or $max->isGreaterThanZero() )
$max = $maximumBalanceAmounts ? ( ( new \IPS\Math\Number( number_format( $maximumBalanceAmounts[ $value->currency ]['amount'], Money::numberOfDecimalsForCurrency( $value->currency ), '.', '' ) ) )->subtract( $value->amount ) ) : NULL;
if ( is_null( $max ) or $max->isGreaterThanZero() )
{
$maximums[ $account->member_id ][ $value->currency ] = \is_null( $max ) ? NULL : (string) $max;
$maximums[ $account->member_id ][ $value->currency ] = is_null( $max ) ? NULL : (string) $max;
}
}
}
if ( \count( $maximums ) )
if ( count( $maximums ) )
{
$topupForm = new \IPS\Helpers\Form( 'topup', 'checkout' );
$topupForm = new Form( 'topup', 'checkout' );
$accountOptions = array();
$accountOptionToggles = array();
foreach ( $maximums as $accountId => $data )
{
$currency = NULL;
if ( \count( $data ) === 1 )
if ( count( $data ) === 1 )
{
$currencies = array_keys( $data );
$currency = array_pop( $currencies );
}
$accountOptions[ $accountId ] = $accountId === \IPS\nexus\Customer::loggedIn()->id ? \IPS\nexus\Customer::loggedIn()->language()->addToStack( 'my_account', FALSE, array( 'sprintf' => array( \IPS\nexus\Customer::loggedIn()->cm_name ) ) ) : \IPS\nexus\Customer::load( $accountId )->cm_name;
$accountOptionToggles[ $accountId ] = ( \count( $data ) > 1 ) ? array( 'topup_currency_' . $accountId ) : array( 'topup_amount_' . $accountId . '_' . $currency );
$accountOptions[ $accountId ] = $accountId === Customer::loggedIn()->id ? Customer::loggedIn()->language()->addToStack( 'my_account', FALSE, array( 'sprintf' => array( Customer::loggedIn()->cm_name ) ) ) : Customer::load( $accountId )->cm_name;
$accountOptionToggles[ $accountId ] = ( count( $data ) > 1 ) ? array( 'topup_currency_' . $accountId ) : array( 'topup_amount_' . $accountId . '_' . $currency );
}
$topupForm->add( new \IPS\Helpers\Form\Radio( 'topup_account', NULL, TRUE, array( 'options' => $accountOptions, 'parse' => 'normal', 'toggles' => $accountOptionToggles ) ) );
$topupForm->add( new Radio( 'topup_account', NULL, TRUE, array( 'options' => $accountOptions, 'parse' => 'normal', 'toggles' => $accountOptionToggles ) ) );
foreach ( $maximums as $accountId => $data )
{
if ( \count( $data ) > 1 )
if ( count( $data ) > 1 )
{
$currencyToggles = array();
foreach ( $data as $currency => $maximum )
@@ -391,8 +427,8 @@ class _credit extends \IPS\Dispatcher\Controller
$currencyToggles[ $currency ] = array( 'topup_amount_' . $accountId . '_' . $currency );
}
$field = new \IPS\Helpers\Form\Radio( 'topup_currency_' . $accountId, NULL, NULL, array( 'options' => array_combine( array_keys( $data ), array_keys( $data ) ), 'toggles' => $currencyToggles ), NULL, NULL, NULL, 'topup_currency_' . $accountId );
$field->label = \IPS\Member::loggedIn()->language()->addToStack( 'topup_currency' );
$field = new Radio( 'topup_currency_' . $accountId, NULL, NULL, array( 'options' => array_combine( array_keys( $data ), array_keys( $data ) ), 'toggles' => $currencyToggles ), NULL, NULL, NULL, 'topup_currency_' . $accountId );
$field->label = Member::loggedIn()->language()->addToStack( 'topup_currency' );
$topupForm->add( $field );
}
@@ -400,29 +436,29 @@ class _credit extends \IPS\Dispatcher\Controller
{
$min = $minimumTopupAmounts ? ( $minimumTopupAmounts[ $currency ]['amount'] ) : 0.01;
$field = new \IPS\Helpers\Form\Number( 'topup_amount_' . $accountId . '_' . $currency, NULL, NULL, array( 'decimals' => \IPS\nexus\Money::numberOfDecimalsForCurrency( $currency ) ), function( $val ) use ( $currency, $accountOptions, $accountId, $data, $min, $maximum )
$field = new Number( 'topup_amount_' . $accountId . '_' . $currency, NULL, NULL, array( 'decimals' => Money::numberOfDecimalsForCurrency( $currency ) ), function( $val ) use ( $currency, $accountOptions, $accountId, $data, $min, $maximum )
{
if ( \count( $accountOptions ) === 1 or \IPS\Request::i()->topup_account == $accountId )
if ( count( $accountOptions ) === 1 or Request::i()->topup_account == $accountId )
{
$key = "topup_currency_{$accountId}";
if ( \count( $data ) === 1 or \IPS\Request::i()->$key == $currency )
if ( count( $data ) === 1 or Request::i()->$key == $currency )
{
if ( !$val )
{
throw new \DomainException('form_required');
throw new DomainException('form_required');
}
elseif ( !\is_null( $min ) and $val < $min )
elseif ( !is_null( $min ) and $val < $min )
{
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack( 'form_number_min', FALSE, array( 'sprintf' => array( $min ) ) ) );
throw new DomainException( Member::loggedIn()->language()->addToStack( 'form_number_min', FALSE, array( 'sprintf' => array( $min ) ) ) );
}
elseif ( $maximum and $val > $maximum )
{
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack( 'form_number_max', FALSE, array( 'sprintf' => array( $maximum ) ) ) );
throw new DomainException( Member::loggedIn()->language()->addToStack( 'form_number_max', FALSE, array( 'sprintf' => array( $maximum ) ) ) );
}
}
}
}, NULL, $currency, 'topup_amount_' . $accountId . '_' . $currency );
$field->label = \IPS\Member::loggedIn()->language()->addToStack('topup_amount');
$field->label = Member::loggedIn()->language()->addToStack('topup_amount');
$topupForm->add( $field );
}
}
@@ -430,7 +466,7 @@ class _credit extends \IPS\Dispatcher\Controller
if ( $values = $topupForm->values() )
{
$account = isset( $values['topup_account'] ) ? \IPS\nexus\Customer::load( $values['topup_account'] ) : \IPS\nexus\Customer::loggedIn();
$account = isset( $values['topup_account'] ) ? Customer::load( $values['topup_account'] ) : Customer::loggedIn();
if ( isset( $values[ 'topup_currency_' . $account->member_id ] ) )
{
$currency = $values[ 'topup_currency_' . $account->member_id ];
@@ -441,22 +477,22 @@ class _credit extends \IPS\Dispatcher\Controller
$currency = array_pop( $currencies );
}
$invoice = new \IPS\nexus\Invoice;
$invoice = new Invoice;
$invoice->member = $account;
$invoice->currency = $currency;
$invoice->return_uri = 'app=nexus&module=clients&controller=credit';
$invoice->addItem( new \IPS\nexus\extensions\nexus\Item\AccountCreditIncrease( \IPS\nexus\Customer::loggedIn()->language()->get('account_credit'), new \IPS\nexus\Money( $values["topup_amount_{$account->member_id}_{$currency}"], $currency ) ) );
\IPS\Output::i()->redirect( $invoice->checkoutUrl() );
$invoice->addItem( new AccountCreditIncrease( Customer::loggedIn()->language()->get('account_credit'), new Money( $values["topup_amount_{$account->member_id}_{$currency}"], $currency ) ) );
Output::i()->redirect( $invoice->checkoutUrl() );
}
}
}
if ( !$topupForm )
{
\IPS\Output::i()->error( 'no_module_permission', '2X239/4', 403, '' );
Output::i()->error( 'no_module_permission', '2X239/4', 403, '' );
}
\IPS\Output::i()->output = $topupForm->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
Output::i()->output = $topupForm->customTemplate( array( Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
}
/**
@@ -464,14 +500,14 @@ class _credit extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function cancel()
protected function cancel() : void
{
\IPS\Session::i()->csrfCheck();
Session::i()->csrfCheck();
try
{
$payout = \IPS\nexus\Payout::load( \IPS\Request::i()->id );
if ( $payout->member->member_id === \IPS\nexus\Customer::loggedIn()->member_id and $payout->status === $payout::STATUS_PENDING )
$payout = Payout::load( Request::i()->id );
if ( $payout->member->member_id === Customer::loggedIn()->member_id and $payout->status === $payout::STATUS_PENDING )
{
$payout->status = $payout::STATUS_CANCELED;
$payout->save();
@@ -481,11 +517,11 @@ class _credit extends \IPS\Dispatcher\Controller
$payout->member->cm_credits = $credits;
$payout->member->save();
\IPS\nexus\Customer::loggedIn()->log( 'payout', array( 'type' => 'cancel', 'amount' => $payout->amount->amount, 'currency' => $payout->amount->currency, 'payout_id' => $payout->id ) );
Customer::loggedIn()->log( 'payout', array( 'type' => 'cancel', 'amount' => $payout->amount->amount, 'currency' => $payout->amount->currency, 'payout_id' => $payout->id ) );
}
}
catch ( \OutOfRangeException $e ) { }
catch ( OutOfRangeException ) { }
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=nexus&module=clients&controller=credit', 'front', 'clientscredit' ) );
Output::i()->redirect( Url::internal( 'app=nexus&module=clients&controller=credit', 'front', 'clientscredit' ) );
}
}
@@ -12,48 +12,60 @@
namespace IPS\nexus\modules\front\clients;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Dispatcher\Controller;
use IPS\Helpers\Form;
use IPS\Helpers\Form\Number;
use IPS\Helpers\Form\Radio;
use IPS\Helpers\Form\YesNo;
use IPS\Http\Url;
use IPS\Member;
use IPS\nexus\Customer;
use IPS\nexus\Donation\Goal;
use IPS\nexus\extensions\nexus\Item\Donation;
use IPS\nexus\Invoice;
use IPS\nexus\Money;
use IPS\Output;
use IPS\Request;
use IPS\Theme;
use OutOfRangeException;
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;
}
/**
* Donations
*/
class _donations extends \IPS\Dispatcher\Controller
class donations extends Controller
{
/**
* View List
*
* @return void
*/
protected function manage()
protected function manage() : void
{
if ( isset( \IPS\Request::i()->id ) )
if ( isset( Request::i()->id ) and !Request::i()->isAjax() )
{
if ( \IPS\Request::i()->isAjax() )
{
}
else
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=nexus&module=clients&controller=donations', 'front', 'clientsdonations' ) );
}
Output::i()->redirect( Url::internal( 'app=nexus&module=clients&controller=donations', 'front', 'clientsdonations' ) );
}
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( 'app=nexus&module=clients&controller=donations', 'front', 'clientsdonations' ), \IPS\Member::loggedIn()->language()->addToStack('client_donations') );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('client_donations');
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'donations.css' ) );
Output::i()->breadcrumb[] = array( Url::internal( 'app=nexus&module=clients&controller=donations', 'front', 'clientsdonations' ), Member::loggedIn()->language()->addToStack('client_donations') );
Output::i()->title = Member::loggedIn()->language()->addToStack('client_donations');
Output::i()->sidebar['enabled'] = FALSE;
/* "Nowt 'ere lad, may as well knock it over tut 404" - Marc */
if( \count( \IPS\nexus\Donation\Goal::roots() ) === 0 )
if( count( Goal::roots() ) === 0 )
{
\IPS\Output::i()->error( 'nexus_no_donations_found', '1X238/2', 404, '' );
Output::i()->error( 'nexus_no_donations_found', '1X238/2', 404, '' );
}
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('clients')->donations();
Output::i()->output = Theme::i()->getTemplate('clients')->donations();
}
/**
@@ -61,45 +73,80 @@ class _donations extends \IPS\Dispatcher\Controller
*
* @return void
*/
public function donate()
public function donate() : void
{
if( !\IPS\Member::loggedIn()->member_id )
if( !Member::loggedIn()->member_id )
{
\IPS\Output::i()->error( 'no_module_permission_guest', '1X238/3', 403, '' );
Output::i()->error( 'no_module_permission_guest', '1X238/3', 403, '' );
}
try
{
$goal = \IPS\nexus\Donation\Goal::load( \IPS\Request::i()->id );
$goal = Goal::load( Request::i()->id );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException )
{
\IPS\Output::i()->error( 'node_error', '2X238/1', 404, '' );
Output::i()->error( 'node_error', '2X238/1', 404, '' );
}
$form = new \IPS\Helpers\Form( 'donate', 'donate' );
$form->class = 'ipsForm_vertical';
if ( !isset( \IPS\Request::i()->noDesc ) and $desc = \IPS\Member::loggedIn()->language()->get("nexus_donategoal_{$goal->id}_desc") )
$form = new Form( 'donate', 'donate' );
$form->class = 'ipsForm--vertical ipsForm--donate';
if ( !isset( Request::i()->noDesc ) and $desc = Member::loggedIn()->language()->get("nexus_donategoal_{$goal->id}_desc") )
{
$form->addMessage( $desc, '', FALSE );
}
$form->add( new \IPS\Helpers\Form\Number( 'donate_amount', 0, TRUE, array( 'decimals' => TRUE, 'min' => 0.01 ), NULL, NULL, $goal->currency ) );
/* Work out what our options are */
$options = array();
if( $goal->suggestions )
{
foreach ( json_decode( $goal->suggestions ) as $suggestion )
{
$options[ $suggestion ] = new Money( $suggestion, $goal->currency );
}
}
if ( empty( $options ) )
{
$form->add( new Number( 'donate_amount', 0, TRUE, array( 'decimals' => TRUE, 'min' => 0.01 ), NULL, NULL, $goal->currency ) );
}
else
{
if( $goal->suggestions_open )
{
$options['x'] = Member::loggedIn()->language()->addToStack('other');
}
$form->add( new Radio( 'donate_amount', NULL, TRUE, array( 'options' => $options, 'parse' => 'normal', 'userSuppliedInput' => 'x' ) ) );
}
$form->add( new YesNo( 'donate_anonymous', FALSE ) );
if ( $values = $form->values() )
{
$item = new \IPS\nexus\extensions\nexus\Item\Donation( \IPS\Member::loggedIn()->language()->get( 'nexus_donategoal_' . $goal->_id ), new \IPS\nexus\Money( $values['donate_amount'], $goal->currency ) );
$item->id = $goal->_id;
$invoice = new \IPS\nexus\Invoice;
$invoice->member = \IPS\nexus\Customer::loggedIn();
$invoice->currency = $goal->currency;
$invoice->addItem( $item );
$invoice->return_uri = 'app=nexus&module=clients&controller=donations&thanks=1';
$invoice->save();
\IPS\Output::i()->redirect( $invoice->checkoutUrl() );
if( !is_numeric( $values['donate_amount'] ) )
{
$form->error = Member::loggedIn()->language()->addToStack( 'donation_invalid_amount' );
}
if( !$form->error )
{
$item = new Donation( Member::loggedIn()->language()->get( 'nexus_donategoal_' . $goal->_id ), new Money( $values['donate_amount'], $goal->currency ) );
$item->id = $goal->_id;
$item->extra = array( 'anonymous' => $values['donate_anonymous'] );
$invoice = new Invoice;
$invoice->member = Customer::loggedIn();
$invoice->currency = $goal->currency;
$invoice->addItem( $item );
$invoice->return_uri = 'app=nexus&module=clients&controller=donations&thanks=1';
$invoice->save();
Output::i()->redirect( $invoice->checkoutUrl() );
}
}
\IPS\Output::i()->title = $goal->_title;
\IPS\Output::i()->output = $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
Output::i()->title = $goal->_title;
Output::i()->output = $form->customTemplate( array( Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
}
}
@@ -1,4 +1,5 @@
<?php
/**
* @brief Custom Fields
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
@@ -12,41 +13,55 @@
namespace IPS\nexus\modules\front\clients;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Dispatcher\Controller;
use IPS\Helpers\Form;
use IPS\Helpers\Form\Text;
use IPS\Helpers\Form\Upload;
use IPS\Http\Url;
use IPS\Member;
use IPS\MFA\MFAHandler;
use IPS\nexus\Customer;
use IPS\nexus\Customer\CustomField;
use IPS\Output;
use IPS\Theme;
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 Fields
*/
class _info extends \IPS\Dispatcher\Controller
class info extends Controller
{
/**
* Execute
*
* @return void
*/
public function execute()
public function execute() : void
{
if ( !\IPS\Member::loggedIn()->member_id )
if ( !Member::loggedIn()->member_id )
{
\IPS\Output::i()->error( 'no_module_permission_guest', '2X242/1', 403, '' );
Output::i()->error( 'no_module_permission_guest', '2X242/1', 403, '' );
}
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( 'app=nexus&module=clients&controller=info', 'front', 'clientsinfo' ), \IPS\Member::loggedIn()->language()->addToStack('client_info') );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('client_info');
\IPS\Output::i()->sidebar['enabled'] = FALSE;
Output::i()->breadcrumb[] = array( Url::internal( 'app=nexus&module=clients&controller=info', 'front', 'clientsinfo' ), Member::loggedIn()->language()->addToStack('client_info') );
Output::i()->title = Member::loggedIn()->language()->addToStack('client_info');
Output::i()->sidebar['enabled'] = FALSE;
if ( $output = \IPS\MFA\MFAHandler::accessToArea( 'nexus', 'BillingInfo', \IPS\Http\Url::internal( 'app=nexus&module=clients&controller=info', 'front', 'clientsinfo' ) ) )
if ( $output = MFAHandler::accessToArea( 'nexus', 'BillingInfo', Url::internal( 'app=nexus&module=clients&controller=info', 'front', 'clientsinfo' ) ) )
{
$form = new \IPS\Helpers\Form;
$form = new Form;
foreach( $this->_buildInfoForm( TRUE ) AS $formElement )
{
$form->add( $formElement );
}
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('clients')->info( $form ) . $output;
Output::i()->output = Theme::i()->getTemplate('clients')->info( $form ) . $output;
return;
}
@@ -58,9 +73,9 @@ class _info extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function manage()
protected function manage() : void
{
$form = new \IPS\Helpers\Form;
$form = new Form;
foreach( $this->_buildInfoForm() AS $formElement )
{
$form->add( $formElement );
@@ -73,24 +88,25 @@ class _info extends \IPS\Dispatcher\Controller
{
if ( isset( $values[ $nameField ] ) )
{
if ( $values[ $nameField ] != \IPS\nexus\Customer::loggedIn()->$nameField )
if ( $values[ $nameField ] != Customer::loggedIn()->$nameField )
{
/* We only need to log this once, so do it if it isn't set */
if ( !isset( $changes['name'] ) )
{
$changes['name'] = \IPS\nexus\Customer::loggedIn()->cm_name;
$changes['name'] = Customer::loggedIn()->cm_name;
}
\IPS\nexus\Customer::loggedIn()->$nameField = $values[ $nameField ];
Customer::loggedIn()->$nameField = $values[ $nameField ];
}
}
}
foreach ( \IPS\nexus\Customer\CustomField::roots() as $field )
foreach ( CustomField::roots() as $field )
{
/* @var CustomField $field */
$column = $field->column;
$helper = $field->buildHelper();
if ( $helper instanceof \IPS\Helpers\Form\Upload )
if ( $helper instanceof Upload )
{
$valueToSave = (string) $values["nexus_ccfield_{$field->id}"];
}
@@ -98,26 +114,26 @@ class _info extends \IPS\Dispatcher\Controller
{
$valueToSave = $helper::stringValue( $values["nexus_ccfield_{$field->id}"] );
}
if ( \IPS\nexus\Customer::loggedIn()->$column != $valueToSave )
if ( Customer::loggedIn()->$column != $valueToSave )
{
$changes['other'][] = array( 'name' => 'nexus_ccfield_' . $field->id, 'value' => $field->displayValue( $valueToSave ), 'old' => $field->displayValue( \IPS\nexus\Customer::loggedIn()->$column ) );
\IPS\nexus\Customer::loggedIn()->$column = $valueToSave;
$changes['other'][] = array( 'name' => 'nexus_ccfield_' . $field->id, 'value' => $field->displayValue( $valueToSave ), 'old' => $field->displayValue( Customer::loggedIn()->$column ) );
Customer::loggedIn()->$column = $valueToSave;
}
if ( $field->type === 'Editor' )
{
$field->claimAttachments( \IPS\nexus\Customer::loggedIn()->member_id );
$field->claimAttachments( Customer::loggedIn()->member_id );
}
}
if ( !empty( $changes ) )
{
\IPS\nexus\Customer::loggedIn()->log( 'info', $changes );
Customer::loggedIn()->log( 'info', $changes );
}
\IPS\nexus\Customer::loggedIn()->save();
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=nexus&module=clients&controller=info', 'front', 'clientsinfo' ) );
Customer::loggedIn()->save();
Output::i()->redirect( Url::internal( 'app=nexus&module=clients&controller=info', 'front', 'clientsinfo' ) );
}
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('clients')->info( $form );
Output::i()->output = Theme::i()->getTemplate('clients')->info( $form );
}
/**
@@ -126,19 +142,20 @@ class _info extends \IPS\Dispatcher\Controller
* @param bool $protected If TRUE, current values will be blanked out
* @return array
*/
protected function _buildInfoForm( $protected = FALSE )
protected function _buildInfoForm( bool $protected = FALSE ) : array
{
$formElements = array();
$formElements['cm_first_name'] = new \IPS\Helpers\Form\Text( 'cm_first_name', $protected ? NULL : \IPS\nexus\Customer::loggedIn()->cm_first_name, TRUE );
$formElements['cm_last_name'] = new \IPS\Helpers\Form\Text( 'cm_last_name', $protected ? NULL : \IPS\nexus\Customer::loggedIn()->cm_last_name, TRUE );
foreach ( \IPS\nexus\Customer\CustomField::roots() as $field )
$formElements['cm_first_name'] = new Text( 'cm_first_name', $protected ? NULL : Customer::loggedIn()->cm_first_name, TRUE );
$formElements['cm_last_name'] = new Text( 'cm_last_name', $protected ? NULL : Customer::loggedIn()->cm_last_name, TRUE );
foreach ( CustomField::roots() as $field )
{
/* @var CustomField $field */
$column = $field->column;
if ( $field->type === 'Editor' )
{
$field::$editorOptions = array_merge( $field::$editorOptions, array( 'attachIds' => array( \IPS\nexus\Customer::loggedIn()->member_id ) ) );
$field::$editorOptions = array_merge( $field::$editorOptions, array( 'attachIds' => array( Customer::loggedIn()->member_id ) ) );
}
$formElements[ $column ] = $field->buildHelper( $protected ? NULL : \IPS\nexus\Customer::loggedIn()->$column );
$formElements[ $column ] = $field->buildHelper( $protected ? NULL : Customer::loggedIn()->$column );
}
return $formElements;
@@ -12,101 +12,128 @@
namespace IPS\nexus\modules\front\clients;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use Exception;
use IPS\Db;
use IPS\Dispatcher\Controller;
use IPS\Events\Event;
use IPS\Helpers\Form;
use IPS\Helpers\Form\Text;
use IPS\Helpers\Form\TextArea;
use IPS\Http\Url;
use IPS\Login;
use IPS\Member;
use IPS\nexus\Customer;
use IPS\nexus\Invoice;
use IPS\nexus\Transaction;
use IPS\Output;
use IPS\Patterns\ActiveRecordIterator;
use IPS\Request;
use IPS\Session;
use IPS\Theme;
use OutOfRangeException;
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;
}
/**
* Invoices
*/
class _invoices extends \IPS\Dispatcher\Controller
class invoices extends Controller
{
/**
* @var Invoice|null
*/
protected ?Invoice $invoice = null;
/**
* Execute
*
* @return void
*/
public function execute()
public function execute() : void
{
/* Load Invoice */
if ( isset( \IPS\Request::i()->id ) )
if ( isset( Request::i()->id ) )
{
if ( isset( \IPS\Request::i()->printout ) )
if ( isset( Request::i()->printout ) )
{
\IPS\Request::i()->do = 'printout';
Request::i()->do = 'printout';
}
if ( \IPS\Member::loggedIn()->member_id )
if ( Member::loggedIn()->member_id )
{
try
{
$this->invoice = \IPS\nexus\Invoice::loadAndCheckPerms( \IPS\Request::i()->id );
$this->invoice = Invoice::loadAndCheckPerms( Request::i()->id );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException )
{
\IPS\Output::i()->error( 'node_error', '2X215/1', 404, '' );
Output::i()->error( 'node_error', '2X215/1', 404, '' );
}
}
else
{
/* Prevent the vid key from being exposed in referrers */
\IPS\Output::i()->sendHeader( "Referrer-Policy: origin" );
Output::i()->sendHeader( "Referrer-Policy: origin" );
$key = isset( \IPS\Request::i()->key ) ? \IPS\Request::i()->key : ( isset( \IPS\Request::i()->cookie['guestTransactionKey'] ) ? \IPS\Request::i()->cookie['guestTransactionKey'] : NULL );
$this->invoice = \IPS\nexus\Invoice::load( \IPS\Request::i()->id );
$key = isset( Request::i()->key ) ? Request::i()->key : ( isset( Request::i()->cookie['guestTransactionKey'] ) ? Request::i()->cookie['guestTransactionKey'] : NULL );
$this->invoice = Invoice::load( Request::i()->id );
if( $this->invoice->member->member_id or !$key or !isset( $this->invoice->guest_data['guestTransactionKey'] ) or !\IPS\Login::compareHashes( $key, $this->invoice->guest_data['guestTransactionKey'] ) )
if( $this->invoice->member->member_id or !$key or !isset( $this->invoice->guest_data['guestTransactionKey'] ) or !Login::compareHashes( $key, $this->invoice->guest_data['guestTransactionKey'] ) )
{
\IPS\Output::i()->error( 'no_module_permission_guest', '2X215/6', 404, '' );
Output::i()->error( 'no_module_permission_guest', '2X215/6', 404, '' );
}
/* Do not cache this guest view invoice */
\IPS\Output::setCacheTime( false );
Output::i()->pageCaching = FALSE;
}
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( 'app=nexus&module=clients&controller=invoices', 'front', 'clientsinvoices' ), \IPS\Member::loggedIn()->language()->addToStack('client_invoices') );
\IPS\Output::i()->breadcrumb[] = array( $this->invoice->url(), $this->invoice->title );
\IPS\Output::i()->title = $this->invoice->title;
Output::i()->breadcrumb[] = array( Url::internal( 'app=nexus&module=clients&controller=invoices', 'front', 'clientsinvoices' ), Member::loggedIn()->language()->addToStack('client_invoices') );
Output::i()->breadcrumb[] = array( $this->invoice->url(), $this->invoice->title );
Output::i()->title = $this->invoice->title;
}
else
{
if ( !\IPS\Member::loggedIn()->member_id )
if ( !Member::loggedIn()->member_id )
{
\IPS\Output::i()->error( 'no_module_permission_guest', '2X215/3', 403, '' );
Output::i()->error( 'no_module_permission_guest', '2X215/3', 403, '' );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('client_invoices');
if ( isset( \IPS\Request::i()->do ) )
Output::i()->title = Member::loggedIn()->language()->addToStack('client_invoices');
if ( isset( Request::i()->do ) )
{
\IPS\Output::i()->error( 'node_error', '2X215/2', 403, '' );
Output::i()->error( 'node_error', '2X215/2', 403, '' );
}
}
/* Execute */
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'clients.css', 'nexus' ) );
\IPS\Output::i()->sidebar['enabled'] = FALSE;
Output::i()->cssFiles = array_merge( Output::i()->cssFiles, Theme::i()->css( 'clients.css', 'nexus' ) );
Output::i()->sidebar['enabled'] = FALSE;
parent::execute();
}
/**
* @brief Invoices Per Page
*/
protected static $invoicesPerPage = 25;
protected static int $invoicesPerPage = 25;
/**
* View List
*
* @return void
*/
protected function manage()
protected function manage() : void
{
$where = array( 'i_member=?', \IPS\Member::loggedIn()->member_id );
$parentContacts = \IPS\nexus\Customer::loggedIn()->parentContacts( array( 'billing=1' ) );
if ( \count( $parentContacts ) )
$where = array( 'i_member=?', Member::loggedIn()->member_id );
$parentContacts = Customer::loggedIn()->parentContacts( array( 'billing=1' ) );
if ( count( $parentContacts ) )
{
$or = array();
foreach ( array_keys( iterator_to_array( $parentContacts ) ) as $id )
{
$where[0] .= ' OR i_member=?';
@@ -114,8 +141,8 @@ class _invoices extends \IPS\Dispatcher\Controller
}
}
$count = \IPS\Db::i()->select( 'COUNT(*)', 'nexus_invoices', $where )->first();
$page = isset( \IPS\Request::i()->page ) ? \IPS\Request::i()->page : 1;
$count = Db::i()->select( 'COUNT(*)', 'nexus_invoices', $where )->first();
$page = isset( Request::i()->page ) ? Request::i()->page : 1;
if ( $page < 1 )
{
@@ -126,13 +153,13 @@ class _invoices extends \IPS\Dispatcher\Controller
if ( $page > $pages )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=nexus&module=clients&controller=invoices", 'front', 'clientsinvoices' ) );
Output::i()->redirect( Url::internal( "app=nexus&module=clients&controller=invoices", 'front', 'clientsinvoices' ) );
}
$pagination = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination( \IPS\Http\Url::internal( "app=nexus&module=clients&controller=invoices", 'front', 'clientsinvoices' ), $pages, $page, static::$invoicesPerPage );
$pagination = Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination( Url::internal( "app=nexus&module=clients&controller=invoices", 'front', 'clientsinvoices' ), $pages, $page, static::$invoicesPerPage );
$invoices = new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'nexus_invoices', $where, 'i_date DESC', array( ( $page - 1 ) * static::$invoicesPerPage, static::$invoicesPerPage ) ), 'IPS\nexus\Invoice' );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('clients')->invoices( $invoices, $pagination );
$invoices = new ActiveRecordIterator( Db::i()->select( '*', 'nexus_invoices', $where, 'i_date DESC', array( ( $page - 1 ) * static::$invoicesPerPage, static::$invoicesPerPage ) ), 'IPS\nexus\Invoice' );
Output::i()->output = Theme::i()->getTemplate('clients')->invoices( $invoices, $pagination );
}
/**
@@ -140,10 +167,9 @@ class _invoices extends \IPS\Dispatcher\Controller
*
* @return void
*/
public function view()
public function view() : void
{
$shipments = $this->invoice->shipments();
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('clients')->invoice( $this->invoice );
Output::i()->output = Theme::i()->getTemplate('clients')->invoice( $this->invoice );
}
/**
@@ -151,18 +177,18 @@ class _invoices extends \IPS\Dispatcher\Controller
*
* @return void
*/
public function poNumber()
public function poNumber() : void
{
$form = new \IPS\Helpers\Form;
$form->class = 'ipsForm_vertical ipsForm_noLabels';
$form->add( new \IPS\Helpers\Form\Text( 'invoice_po_number', $this->invoice->po, FALSE, array( 'maxLength' => 255 ) ) );
$form = new Form;
$form->class = 'ipsForm--vertical ipsForm--po-number ipsForm--noLabels';
$form->add( new Text( 'invoice_po_number', $this->invoice->po, FALSE, array( 'maxLength' => 255 ) ) );
if ( $values = $form->values() )
{
$this->invoice->po = $values['invoice_po_number'];
$this->invoice->save();
\IPS\Output::i()->redirect( $this->invoice->url() );
Output::i()->redirect( $this->invoice->url() );
}
\IPS\Output::i()->output = $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );;
Output::i()->output = $form->customTemplate( array( Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
}
/**
@@ -170,19 +196,19 @@ class _invoices extends \IPS\Dispatcher\Controller
*
* @return void
*/
public function notes()
public function notes() : void
{
$form = new \IPS\Helpers\Form;
$form->class = 'ipsForm_vertical ipsForm_noLabels';
$form->add( new \IPS\Helpers\Form\TextArea( 'invoice_notes', $this->invoice->notes ) );
\IPS\Member::loggedIn()->language()->words['invoice_notes_desc'] = '';
$form = new Form;
$form->class = 'ipsForm--vertical ipsForm--invoice-notes ipsForm--noLabels';
$form->add( new TextArea( 'invoice_notes', $this->invoice->notes ) );
Member::loggedIn()->language()->words['invoice_notes_desc'] = '';
if ( $values = $form->values() )
{
$this->invoice->notes = $values['invoice_notes'];
$this->invoice->save();
\IPS\Output::i()->redirect( $this->invoice->url() );
Output::i()->redirect( $this->invoice->url() );
}
\IPS\Output::i()->output = $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );;
Output::i()->output = $form->customTemplate( array( Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
}
/**
@@ -190,11 +216,11 @@ class _invoices extends \IPS\Dispatcher\Controller
*
* @return void
*/
public function printout()
public function printout() : void
{
$output = \IPS\Theme::i()->getTemplate( 'invoices', 'nexus', 'global' )->printInvoice( $this->invoice, $this->invoice->summary(), $this->invoice->billaddress ?: $this->invoice->member->primaryBillingAddress() );
\IPS\Output::i()->title = 'I' . $this->invoice->id;
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->blankTemplate( $output ) );
$output = Theme::i()->getTemplate( 'invoices', 'nexus', 'global' )->printInvoice( $this->invoice, $this->invoice->summary(), $this->invoice->billaddress ?: $this->invoice->member->primaryBillingAddress() );
Output::i()->title = 'I' . $this->invoice->id;
Output::i()->sendOutput( Theme::i()->getTemplate( 'global', 'core' )->blankTemplate( $output ) );
}
/**
@@ -202,42 +228,45 @@ class _invoices extends \IPS\Dispatcher\Controller
*
* @return void
*/
public function cancel()
public function cancel() : void
{
/* CSRF check */
\IPS\Session::i()->csrfCheck();
Session::i()->csrfCheck();
/* Can only cancel the invoice if it's pending and there are no processing transactions */
if ( $this->invoice->status !== \IPS\nexus\Invoice::STATUS_PENDING or \count( $this->invoice->transactions( [ \IPS\nexus\Transaction::STATUS_HELD, \IPS\nexus\Transaction::STATUS_REVIEW, \IPS\nexus\Transaction::STATUS_GATEWAY_PENDING, \IPS\nexus\Transaction::STATUS_DISPUTED ] ) ) )
if ( $this->invoice->status !== Invoice::STATUS_PENDING or count( $this->invoice->transactions( [ Transaction::STATUS_HELD, Transaction::STATUS_REVIEW, Transaction::STATUS_GATEWAY_PENDING, Transaction::STATUS_DISPUTED ] ) ) )
{
\IPS\Output::i()->error( 'order_already_paid', '2X215/4', 403, '' );
Output::i()->error( 'order_already_paid', '2X215/4', 403, '' );
}
/* If they have already made a partial payment, refund it to their account credit */
foreach ( $this->invoice->transactions( array( \IPS\nexus\Transaction::STATUS_PAID, \IPS\nexus\Transaction::STATUS_PART_REFUNDED ) ) as $transaction )
foreach ( $this->invoice->transactions( array( Transaction::STATUS_PAID, Transaction::STATUS_PART_REFUNDED ) ) as $transaction )
{
/* @var Transaction $transaction */
try
{
$transaction->refund( 'credit' );
}
catch ( \Exception $e )
catch ( Exception $e )
{
\IPS\Output::i()->error( 'order_cancel_error', '4C171/5', 500, $e->getMessage() );
Output::i()->error( 'order_cancel_error', '4C171/5', 500, $e->getMessage() );
}
}
/* Cancel the invoice */
$this->invoice->status = \IPS\nexus\invoice::STATUS_CANCELED;
$this->invoice->status = invoice::STATUS_CANCELED;
$this->invoice->save();
$this->invoice->member->log( 'invoice', array( 'type' => 'status', 'new' => 'canc', 'id' => $this->invoice->id, 'title' => $this->invoice->title ) );
/* Run any callbacks (for example, coupons get unmarked as being used) */
foreach ( $this->invoice->items as $k => $item )
foreach ( $this->invoice->items as $item )
{
$item->onInvoiceCancel( $this->invoice );
Event::fire( 'onInvoiceCancel', $item, array( $this->invoice ) );
}
/* Redirect */
\IPS\Output::i()->redirect( $this->invoice->url() );
Output::i()->redirect( $this->invoice->url() );
}
}
@@ -12,63 +12,91 @@
namespace IPS\nexus\modules\front\clients;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Application;
use IPS\Db;
use IPS\Dispatcher\Controller;
use IPS\Helpers\Form;
use IPS\Helpers\Form\Number;
use IPS\Http\Url;
use IPS\Login;
use IPS\Member;
use IPS\nexus\Customer;
use IPS\nexus\Invoice;
use IPS\nexus\Invoice\Item\Renewal;
use IPS\nexus\Purchase;
use IPS\Output;
use IPS\Patterns\ActiveRecordIterator;
use IPS\Request;
use IPS\Session;
use IPS\Theme;
use OutOfRangeException;
use function count;
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;
}
/**
* Purchases
*/
class _purchases extends \IPS\Dispatcher\Controller
class purchases extends Controller
{
/**
* @brief Purchase object
*/
protected ?Purchase $purchase = NULL;
/**
* Execute
*
* @return void
*/
public function execute()
public function execute() : void
{
if ( !\IPS\Member::loggedIn()->member_id )
if ( !Member::loggedIn()->member_id )
{
\IPS\Output::i()->error( 'no_module_permission_guest', '2X212/6', 403, '' );
Output::i()->error( 'no_module_permission_guest', '2X212/6', 403, '' );
}
/* Purchases breadcrumb */
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( 'app=nexus&module=clients&controller=purchases', 'front', 'clientspurchases' ), \IPS\Member::loggedIn()->language()->addToStack('client_purchases') );
Output::i()->breadcrumb[] = array( Url::internal( 'app=nexus&module=clients&controller=purchases', 'front', 'clientspurchases' ), Member::loggedIn()->language()->addToStack('client_purchases') );
/* Load Purchase */
if ( isset( \IPS\Request::i()->id ) )
if ( isset( Request::i()->id ) )
{
try
{
$this->purchase = \IPS\nexus\Purchase::load( \IPS\Request::i()->id );
$this->purchase = Purchase::load( Request::i()->id );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException )
{
\IPS\Output::i()->error( 'node_error', '2X212/1', 404, '' );
Output::i()->error( 'node_error', '2X212/1', 404, '' );
}
if ( !$this->purchase->canView() )
{
\IPS\Output::i()->error( 'no_module_permission', '2X212/2', 403, '' );
Output::i()->error( 'no_module_permission', '2X212/2', 403, '' );
}
\IPS\Output::i()->breadcrumb[] = array( $this->purchase->url(), $this->purchase->name );
\IPS\Output::i()->title = $this->purchase->name;
Output::i()->breadcrumb[] = array( $this->purchase->url(), $this->purchase->name );
Output::i()->title = $this->purchase->name;
}
else
{
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('client_purchases');
if ( isset( \IPS\Request::i()->do ) )
Output::i()->title = Member::loggedIn()->language()->addToStack('client_purchases');
if ( isset( Request::i()->do ) )
{
\IPS\Output::i()->error( 'node_error', '2X212/3', 403, '' );
Output::i()->error( 'node_error', '2X212/3', 403, '' );
}
}
/* Execute */
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'clients.css', 'nexus' ) );
\IPS\Output::i()->sidebar['enabled'] = FALSE;
Output::i()->cssFiles = array_merge( Output::i()->cssFiles, Theme::i()->css( 'clients.css', 'nexus' ) );
Output::i()->sidebar['enabled'] = FALSE;
parent::execute();
}
@@ -77,30 +105,29 @@ class _purchases extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function manage()
protected function manage() : void
{
$where = array( array( 'ps_member=?', \IPS\Member::loggedIn()->member_id ) );
$where = array( array( 'ps_member=?', Member::loggedIn()->member_id ) );
$parentContacts = \IPS\nexus\Customer::loggedIn()->parentContacts();
if ( \count( $parentContacts ) )
$parentContacts = Customer::loggedIn()->parentContacts();
if ( count( $parentContacts ) )
{
$or = array();
foreach ( $parentContacts as $contact )
{
$where[0][0] .= ' OR ' . \IPS\Db::i()->in( 'ps_id', $contact->purchaseIds() );
$where[0][0] .= ' OR ' . Db::i()->in( 'ps_id', $contact->purchaseIds() );
}
}
$where[] = array( 'ps_show=1' );
/* Get only the purchases from active applications */
$where[] = array( "ps_app IN('" . implode( "','", array_keys( \IPS\Application::enabledApplications() ) ) . "')" );
$where[] = array( "ps_app IN('" . implode( "','", array_keys( Application::enabledApplications() ) ) . "')" );
$purchases = array();
foreach( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'nexus_purchases', $where, 'ps_active DESC, ps_expire DESC, ps_start DESC' ), 'IPS\nexus\Purchase' ) as $purchase )
foreach( new ActiveRecordIterator( Db::i()->select( '*', 'nexus_purchases', $where, 'ps_active DESC, ps_expire DESC, ps_start DESC' ), 'IPS\nexus\Purchase' ) as $purchase )
{
$purchases[ $purchase->parent ][ $purchase->id ] = $purchase;
}
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('clients')->purchases( $purchases );
Output::i()->output = Theme::i()->getTemplate('clients')->purchases( $purchases );
}
/**
@@ -108,9 +135,9 @@ class _purchases extends \IPS\Dispatcher\Controller
*
* @return void
*/
public function view()
public function view() : void
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('clients')->purchase( $this->purchase );
Output::i()->output = Theme::i()->getTemplate('clients')->purchase( $this->purchase );
}
/**
@@ -118,23 +145,10 @@ class _purchases extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function extra()
protected function extra() : void
{
if ( $output = $this->purchase->clientAreaAction() )
{
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->output = $output;
}
else
{
\IPS\Output::i()->output = $output;
}
}
else
{
\IPS\Output::i()->redirect( $this->purchase->url() );
}
$this->purchase->clientAreaAction();
Output::i()->redirect( $this->purchase->url() );
}
/**
@@ -142,20 +156,20 @@ class _purchases extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function renew()
protected function renew() : void
{
$cycles = $this->purchase->canRenewUntil( NULL, TRUE );
if ( $cycles === FALSE )
{
\IPS\Output::i()->error( 'you_cannot_renew', '2X212/4', 403, '' );
Output::i()->error( 'you_cannot_renew', '2X212/4', 403, '' );
}
elseif ( $cycles === 1 )
{
\IPS\Session::i()->csrfCheck();
Session::i()->csrfCheck();
}
elseif ( isset( \IPS\Request::i()->cycles ) and \IPS\Login::compareHashes( (string) \IPS\Session::i()->csrfKey, (string) \IPS\Request::i()->csrfKey ) )
elseif ( isset( Request::i()->cycles ) and Login::compareHashes( (string) Session::i()->csrfKey, (string) Request::i()->csrfKey ) )
{
$_cycles = \intval( \IPS\Request::i()->cycles );
$_cycles = intval( Request::i()->cycles );
if ( $_cycles >= 1 and ( $cycles === TRUE or $_cycles <= $cycles ) )
{
$cycles = $_cycles;
@@ -172,31 +186,31 @@ class _purchases extends \IPS\Dispatcher\Controller
switch( $term['unit'] )
{
case 'd':
$suffix = \IPS\Member::loggedIn()->language()->addToStack('days');
$suffix = Member::loggedIn()->language()->addToStack('days');
break;
case 'm':
$suffix = \IPS\Member::loggedIn()->language()->addToStack('months');
$suffix = Member::loggedIn()->language()->addToStack('months');
break;
case 'y':
$suffix = \IPS\Member::loggedIn()->language()->addToStack('years');
$suffix = Member::loggedIn()->language()->addToStack('years');
break;
}
}
$form = new \IPS\Helpers\Form( 'form', 'continue' );
$form->class = 'ipsForm_vertical';
$form->add( new \IPS\Helpers\Form\Number( 'renew_for', 1, TRUE, array( 'min' => 1, 'max' => $cycles === TRUE ? NULL : $cycles ), NULL, NULL, $suffix ) );
$form = new Form( 'form', 'continue' );
$form->class = 'ipsForm--vertical ipsForm--renew';
$form->add( new Number( 'renew_for', 1, TRUE, array( 'min' => 1, 'max' => $cycles === TRUE ? NULL : $cycles ), NULL, NULL, $suffix ) );
if( $values = $form->values() or $cycles === 1 )
{
if ( $pendingInvoice = $this->purchase->invoice_pending and $pendingInvoice->status === $pendingInvoice::STATUS_PENDING )
{
if ( \count( $pendingInvoice->items ) === 1 )
if ( count( $pendingInvoice->items ) === 1 )
{
foreach ( $pendingInvoice->items as $item )
{
if ( $item instanceof \IPS\nexus\Invoice\Item\Renewal and $item->id === $this->purchase->id and $item->quantity === ( $cycles === 1 ? 1 : $values['renew_for'] ) )
if ( $item instanceof Renewal and $item->id === $this->purchase->id and $item->quantity === ( $cycles === 1 ? 1 : $values['renew_for'] ) )
{
\IPS\Output::i()->redirect( $pendingInvoice->checkoutUrl() );
Output::i()->redirect( $pendingInvoice->checkoutUrl() );
}
}
}
@@ -206,19 +220,19 @@ class _purchases extends \IPS\Dispatcher\Controller
$pendingInvoice->member->log( 'invoice', array( 'type' => 'status', 'new' => 'canc', 'id' => $pendingInvoice->id, 'title' => $pendingInvoice->title ) );
}
$invoice = new \IPS\nexus\Invoice;
$invoice->member = \IPS\nexus\Customer::loggedIn();
$invoice = new Invoice;
$invoice->member = Customer::loggedIn();
$invoice->currency = $this->purchase->renewals->cost->currency;
$invoice->addItem( \IPS\nexus\Invoice\Item\Renewal::create( $this->purchase, $cycles === 1 ? 1 : $values['renew_for'] ) );
$invoice->addItem( Renewal::create( $this->purchase, $cycles === 1 ? 1 : $values['renew_for'] ) );
$invoice->save();
$this->purchase->invoice_pending = $invoice;
$this->purchase->save();
\IPS\Output::i()->redirect( $invoice->checkoutUrl() );
Output::i()->redirect( $invoice->checkoutUrl() );
}
\IPS\Output::i()->output = $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
Output::i()->output = $form->customTemplate( array( Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
}
/**
@@ -226,13 +240,13 @@ class _purchases extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function cancel()
protected function cancel() : void
{
\IPS\Session::i()->csrfCheck();
Session::i()->csrfCheck();
if ( !$this->purchase->canCancel() )
{
\IPS\Output::i()->error( 'you_cannot_cancel', '2X212/5', 403, '' );
Output::i()->error( 'you_cannot_cancel', '2X212/5', 403, '' );
}
$this->purchase->member->log( 'purchase', array( 'type' => 'info', 'id' => $this->purchase->id, 'name' => $this->purchase->name, 'info' => 'remove_renewals' ) );
@@ -240,7 +254,7 @@ class _purchases extends \IPS\Dispatcher\Controller
/* If we have a pending renewal invoice, cancel it (as at this point, we need to reactivate instead) */
if ( $this->purchase->invoice_pending )
{
$this->purchase->invoice_pending->status = \IPS\nexus\Invoice::STATUS_CANCELED; # The constant has a typo and it make me sad
$this->purchase->invoice_pending->status = Invoice::STATUS_CANCELED; # The constant has a typo and it make me sad
$this->purchase->invoice_pending->save();
$this->purchase->invoice_pending = NULL;
@@ -250,10 +264,10 @@ class _purchases extends \IPS\Dispatcher\Controller
$this->purchase->can_reactivate = TRUE;
$this->purchase->save();
if ( $ref = \IPS\Request::i()->referrer( FALSE, TRUE ) )
if ( $ref = Request::i()->referrer( FALSE, TRUE ) )
{
\IPS\Output::i()->redirect( $ref );
Output::i()->redirect( $ref );
}
\IPS\Output::i()->redirect( $this->purchase->url() );
Output::i()->redirect( $this->purchase->url() );
}
}
@@ -12,25 +12,31 @@
namespace IPS\nexus\modules\front\clients;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Dispatcher\Controller;
use IPS\Http\Url;
use IPS\Output;
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;
}
/**
* Legacy Referrals Controller
*/
class _referrals extends \IPS\Dispatcher\Controller
class referrals extends Controller
{
/**
* Manage
*
* @return void
*/
protected function manage()
protected function manage() : void
{
/* Referrals have moved to the core. */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=system&controller=settings&area=referrals", 'front', 'settings_referrals' ) );
Output::i()->redirect( Url::internal( "app=core&module=system&controller=settings&area=referrals", 'front', 'settings_referrals' ) );
}
}
@@ -12,44 +12,53 @@
namespace IPS\nexus\modules\front\clients;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Db;
use IPS\Dispatcher\Controller;
use IPS\Http\Url;
use IPS\Member;
use IPS\nexus\Customer;
use IPS\Output;
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;
}
/**
* Controller to redirect /clients to something sensible
*/
class _splash extends \IPS\Dispatcher\Controller
class splash extends Controller
{
/**
* Execute
*
* @return void
*/
public function execute()
public function execute() : void
{
if ( \IPS\Member::loggedIn()->member_id )
if ( Member::loggedIn()->member_id )
{
$where = array( array( 'ps_member=?', \IPS\Member::loggedIn()->member_id ) );
$parentContacts = \IPS\nexus\Customer::loggedIn()->parentContacts();
if ( \count( $parentContacts ) )
$where = array( array( 'ps_member=?', Member::loggedIn()->member_id ) );
$parentContacts = Customer::loggedIn()->parentContacts();
if ( count( $parentContacts ) )
{
$or = array();
foreach ( $parentContacts as $contact )
{
$where[0][0] .= ' OR ' . \IPS\Db::i()->in( 'ps_id', $contact->purchaseIds() );
$where[0][0] .= ' OR ' . Db::i()->in( 'ps_id', $contact->purchaseIds() );
}
}
$where[] = array( 'ps_show=1' );
if ( \IPS\Db::i()->select( 'COUNT(*)', 'nexus_purchases', $where )->first() )
if ( Db::i()->select( 'COUNT(*)', 'nexus_purchases', $where )->first() )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=nexus&module=clients&controller=purchases', 'front', 'clientspurchases' ) );
Output::i()->redirect( Url::internal( 'app=nexus&module=clients&controller=purchases', 'front', 'clientspurchases' ) );
}
}
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=nexus&module=clients&controller=invoices', 'front', 'clientsinvoices' ) );
Output::i()->redirect( Url::internal( 'app=nexus&module=clients&controller=invoices', 'front', 'clientsinvoices' ) );
}
}
+79 -61
View File
@@ -12,31 +12,49 @@
namespace IPS\nexus\modules\front\store;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\DateTime;
use IPS\Db;
use IPS\Dispatcher\Controller;
use IPS\File;
use IPS\GeoLocation;
use IPS\Http\Url;
use IPS\Math\Number;
use IPS\Member;
use IPS\nexus\Customer;
use IPS\nexus\Invoice;
use IPS\nexus\Money;
use IPS\nexus\Package;
use IPS\Output;
use IPS\Request;
use IPS\Session;
use IPS\Settings;
use IPS\Theme;
use function count;
use function defined;
use function in_array;
use const IPS\CACHE_PAGE_TIMEOUT;
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;
}
/**
* View Cart
*/
class _cart extends \IPS\Dispatcher\Controller
class cart extends Controller
{
/**
* Execute
*
* @return void
*/
public function execute()
public function execute() : void
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'store.css', 'nexus' ) );
Output::i()->cssFiles = array_merge( Output::i()->cssFiles, Theme::i()->css( 'store.css', 'nexus' ) );
if ( \IPS\Theme::i()->settings['responsive'] )
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'store_responsive.css', 'nexus', 'front' ) );
}
parent::execute();
}
@@ -45,20 +63,20 @@ class _cart extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function manage()
protected function manage() : void
{
/* Init */
if ( !isset( $_SESSION['cart'] ) )
{
$_SESSION['cart'] = array();
}
$currency = ( isset( \IPS\Request::i()->cookie['currency'] ) and \in_array( \IPS\Request::i()->cookie['currency'], \IPS\nexus\Money::currencies() ) ) ? \IPS\Request::i()->cookie['currency'] : \IPS\nexus\Customer::loggedIn()->defaultCurrency();
$currency = ( isset( Request::i()->cookie['currency'] ) and in_array( Request::i()->cookie['currency'], Money::currencies() ) ) ? Request::i()->cookie['currency'] : Customer::loggedIn()->defaultCurrency();
/* Display */
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('your_cart');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('store')->cart( ( isset( \IPS\Request::i()->cookie['location'] ) and \IPS\Request::i()->cookie['location'] ) ? \IPS\GeoLocation::buildFromJson( \IPS\Request::i()->cookie['location'] ) : NULL, $currency );
Output::i()->bodyClasses[] = 'ipsLayout_minimal';
Output::i()->sidebar['enabled'] = FALSE;
Output::i()->title = Member::loggedIn()->language()->addToStack('your_cart');
Output::i()->output = Theme::i()->getTemplate('store')->cart( ( isset( Request::i()->cookie['location'] ) and Request::i()->cookie['location'] ) ? GeoLocation::buildFromJson( Request::i()->cookie['location'] ) : NULL, $currency );
}
/**
@@ -66,15 +84,15 @@ class _cart extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function quantities()
protected function quantities() : void
{
\IPS\Session::i()->csrfCheck();
Session::i()->csrfCheck();
foreach ( \IPS\Request::i()->item as $k => $v )
foreach ( Request::i()->item as $k => $v )
{
/* Get item */
$item = $_SESSION['cart'][ $k ];
$package = \IPS\nexus\Package::load( $item->id );
$package = Package::load( $item->id );
/* Are any others just a duplicate for discount purposes? If so, condense them into this one */
foreach ( $_SESSION['cart'] as $_k => $_item )
@@ -88,7 +106,7 @@ class _cart extends \IPS\Dispatcher\Controller
{
$v += $_item->quantity;
unset( $_SESSION['cart'][ $_k ] );
\IPS\Db::i()->update( 'nexus_cart_uploads', array( 'item_id' => $k ), array( 'session_id=? AND item_id=?', \IPS\Session::i()->id, $_k ) );
Db::i()->update( 'nexus_cart_uploads', array( 'item_id' => $k ), array( 'session_id=? AND item_id=?', Session::i()->id, $_k ) );
}
}
}
@@ -96,7 +114,7 @@ class _cart extends \IPS\Dispatcher\Controller
/* Subscriptions can only have 1 */
if ( $package->subscription and $v > 1 )
{
\IPS\Output::i()->error( 'err_subscription_qty', '1X214/4', 403, '' );
Output::i()->error( 'err_subscription_qty', '1X214/4', 403, '' );
}
/* Set the quantity back to 0 and "re-add" the item */
@@ -106,7 +124,7 @@ class _cart extends \IPS\Dispatcher\Controller
$data = $package->optionValuesStockAndPrice( $package->optionValues( $item->details ) );
if ( $data['stock'] != -1 and ( $data['stock'] - $item->quantity ) < $v )
{
\IPS\Output::i()->error( \IPS\Member::loggedIn()->language()->addToStack( 'not_enough_in_stock', FALSE, array( 'sprintf' => array( $data['stock'] - $item->quantity ) ) ), '1X214/3', 403, '' );
Output::i()->error( Member::loggedIn()->language()->addToStack( 'not_enough_in_stock', FALSE, array( 'sprintf' => array( $data['stock'] - $item->quantity ) ) ), '1X214/3', 403, '' );
}
$package->addItemsToCartData( $item->details, $v, $item->renewalTerm, $item->parent );
@@ -128,28 +146,28 @@ class _cart extends \IPS\Dispatcher\Controller
unset( $_SESSION['cart'][ $k ] );
$ids = array();
foreach ( \IPS\Db::i()->select( 'id', 'nexus_cart_uploads', array( 'session_id=? AND item_id=?', \IPS\Session::i()->id, $k ) ) as $id )
foreach ( Db::i()->select( 'id', 'nexus_cart_uploads', array( 'session_id=? AND item_id=?', Session::i()->id, $k ) ) as $id )
{
\IPS\File::unclaimAttachments( 'nexus_Purchases', $id, NULL, 'cart' );
File::unclaimAttachments( 'nexus_Purchases', $id, NULL, 'cart' );
$ids[] = $id;
}
\IPS\Db::i()->delete( 'nexus_cart_uploads', \IPS\Db::i()->in( 'id', $ids ) );
Db::i()->delete( 'nexus_cart_uploads', Db::i()->in( 'id', $ids ) );
}
}
if ( empty( $_SESSION['cart'] ) and \IPS\CACHE_PAGE_TIMEOUT and !\IPS\Member::loggedIn()->member_id )
if ( empty( $_SESSION['cart'] ) and CACHE_PAGE_TIMEOUT and !Member::loggedIn()->member_id )
{
\IPS\Request::i()->setCookie( 'noCache', 0, \IPS\DateTime::ts( time() - 86400 ) );
Request::i()->setCookie( 'noCache', 0, DateTime::ts( time() - 86400 ) );
}
if ( \IPS\Request::i()->isAjax() )
if ( Request::i()->isAjax() )
{
$currency = ( isset( \IPS\Request::i()->cookie['currency'] ) and \in_array( \IPS\Request::i()->cookie['currency'], \IPS\nexus\Money::currencies() ) ) ? \IPS\Request::i()->cookie['currency'] : \IPS\nexus\Customer::loggedIn()->defaultCurrency();
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate('store')->cartContents( ( isset( \IPS\Request::i()->cookie['location'] ) and \IPS\Request::i()->cookie['location'] ) ? \IPS\GeoLocation::buildFromJson( \IPS\Request::i()->cookie['location'] ) : NULL, $currency ), 200, 'text/html' );
$currency = ( isset( Request::i()->cookie['currency'] ) and in_array( Request::i()->cookie['currency'], Money::currencies() ) ) ? Request::i()->cookie['currency'] : Customer::loggedIn()->defaultCurrency();
Output::i()->sendOutput( Theme::i()->getTemplate('store')->cartContents( ( isset( Request::i()->cookie['location'] ) and Request::i()->cookie['location'] ) ? GeoLocation::buildFromJson( Request::i()->cookie['location'] ) : NULL, $currency ) );
}
else
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=nexus&module=store&controller=cart', 'front', 'store_cart' ) );
Output::i()->redirect( Url::internal('app=nexus&module=store&controller=cart', 'front', 'store_cart' ) );
}
}
@@ -158,31 +176,31 @@ class _cart extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function clear()
protected function clear() : void
{
\IPS\Session::i()->csrfCheck();
Session::i()->csrfCheck();
$_SESSION['cart'] = array();
$ids = array();
foreach ( \IPS\Db::i()->select( 'id', 'nexus_cart_uploads', array( 'session_id=?', \IPS\Session::i()->id ) ) as $id )
foreach ( Db::i()->select( 'id', 'nexus_cart_uploads', array( 'session_id=?', Session::i()->id ) ) as $id )
{
\IPS\File::unclaimAttachments( 'nexus_Purchases', $id, NULL, 'cart' );
File::unclaimAttachments( 'nexus_Purchases', $id, NULL, 'cart' );
$ids[] = $id;
}
\IPS\Db::i()->delete( 'nexus_cart_uploads', \IPS\Db::i()->in( 'id', $ids ) );
Db::i()->delete( 'nexus_cart_uploads', Db::i()->in( 'id', $ids ) );
if ( \IPS\CACHE_PAGE_TIMEOUT and !\IPS\Member::loggedIn()->member_id )
if ( CACHE_PAGE_TIMEOUT and !Member::loggedIn()->member_id )
{
\IPS\Request::i()->setCookie( 'noCache', 0, \IPS\DateTime::ts( time() - 86400 ) );
Request::i()->setCookie( 'noCache', 0, DateTime::ts( time() - 86400 ) );
}
if ( \IPS\Request::i()->isAjax() )
if ( Request::i()->isAjax() )
{
\IPS\Output::i()->json( $_SESSION['cart'] );
Output::i()->json( $_SESSION['cart'] );
}
else
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=nexus&module=store&controller=cart', 'front', 'store_cart' ) );
Output::i()->redirect( Url::internal('app=nexus&module=store&controller=cart', 'front', 'store_cart' ) );
}
}
@@ -191,22 +209,22 @@ class _cart extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function checkout()
protected function checkout() : void
{
\IPS\Session::i()->csrfCheck();
Session::i()->csrfCheck();
$currency = ( isset( \IPS\Request::i()->cookie['currency'] ) and \in_array( \IPS\Request::i()->cookie['currency'], \IPS\nexus\Money::currencies() ) ) ? \IPS\Request::i()->cookie['currency'] : \IPS\nexus\Customer::loggedIn()->defaultCurrency();
$currency = ( isset( Request::i()->cookie['currency'] ) and in_array( Request::i()->cookie['currency'], Money::currencies() ) ) ? Request::i()->cookie['currency'] : Customer::loggedIn()->defaultCurrency();
$canRegister = ( !\IPS\Settings::i()->nexus_reg_force or \IPS\Member::loggedIn()->member_id );
$canRegister = ( !Settings::i()->nexus_reg_force or Member::loggedIn()->member_id );
$tempInvoiceKey = md5( mt_rand() );
$invoice = new \IPS\nexus\Invoice;
$invoice->member = \IPS\nexus\Customer::loggedIn();
$invoice = new Invoice;
$invoice->member = Customer::loggedIn();
$invoice->currency = $currency;
foreach ( $_SESSION['cart'] as $k => $item )
{
if ( !$canRegister and \IPS\nexus\Package::load( $item->id )->reg )
if ( !$canRegister and Package::load( $item->id )->reg )
{
$canRegister = TRUE;
}
@@ -214,39 +232,39 @@ class _cart extends \IPS\Dispatcher\Controller
$itemId = $invoice->addItem( $item, $k );
$ids = array();
foreach ( \IPS\Db::i()->select( 'id', 'nexus_cart_uploads', array( 'session_id=? AND item_id=?', \IPS\Session::i()->id, $k ) ) as $id )
foreach ( Db::i()->select( 'id', 'nexus_cart_uploads', array( 'session_id=? AND item_id=?', Session::i()->id, $k ) ) as $id )
{
\IPS\Db::i()->update( 'core_attachments_map', array( 'id1' => $itemId, 'id3' => "invoice-{$tempInvoiceKey}" ), array( 'location_key=? AND id1=? AND id3=?', 'nexus_Purchases', $id, 'cart' ) );
Db::i()->update( 'core_attachments_map', array( 'id1' => $itemId, 'id3' => "invoice-{$tempInvoiceKey}" ), array( 'location_key=? AND id1=? AND id3=?', 'nexus_Purchases', $id, 'cart' ) );
$ids[] = $id;
}
\IPS\Db::i()->delete( 'nexus_cart_uploads', \IPS\Db::i()->in( 'id', $ids ) );
Db::i()->delete( 'nexus_cart_uploads', Db::i()->in( 'id', $ids ) );
}
if ( !\count( $invoice->items ) )
if ( !count( $invoice->items ) )
{
\IPS\Output::i()->error( 'your_cart_empty', '2X214/2', 403, '' );
Output::i()->error( 'your_cart_empty', '2X214/2', 403, '' );
}
if ( !$canRegister )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=nexus&module=store&controller=store&do=register', 'front', 'store' ) );
Output::i()->redirect( Url::internal( 'app=nexus&module=store&controller=store&do=register', 'front', 'store' ) );
}
if ( $minimumOrderAmounts = json_decode( \IPS\Settings::i()->nexus_minimum_order, TRUE ) and ( new \IPS\Math\Number( number_format( $minimumOrderAmounts[ $currency ]['amount'], 2, '.', '' ) ) )->compare( $invoice->total->amount ) === 1 )
if ( $minimumOrderAmounts = json_decode( Settings::i()->nexus_minimum_order, TRUE ) and ( new Number( number_format( $minimumOrderAmounts[ $currency ]['amount'], 2, '.', '' ) ) )->compare( $invoice->total->amount ) === 1 )
{
\IPS\Output::i()->error( \IPS\Member::loggedIn()->language()->addToStack( 'err_minimum_order', FALSE, array( 'sprintf' => array( new \IPS\nexus\Money( $minimumOrderAmounts[ $currency ]['amount'], $currency ) ) ) ), '1X214/1', 403, '' );
Output::i()->error( Member::loggedIn()->language()->addToStack( 'err_minimum_order', FALSE, array( 'sprintf' => array( new Money( $minimumOrderAmounts[ $currency ]['amount'], $currency ) ) ) ), '1X214/1', 403, '' );
}
$_SESSION['cart'] = array();
if ( \IPS\CACHE_PAGE_TIMEOUT and !\IPS\Member::loggedIn()->member_id )
if ( CACHE_PAGE_TIMEOUT and !Member::loggedIn()->member_id )
{
\IPS\Request::i()->setCookie( 'noCache', 0, \IPS\DateTime::ts( time() - 86400 ) );
Request::i()->setCookie( 'noCache', 0, DateTime::ts( time() - 86400 ) );
}
$invoice->save();
\IPS\Db::i()->update( 'core_attachments_map', array( 'id3' => "invoice-{$invoice->id}" ), array( 'location_key=? AND id3=?', 'nexus_Purchases', "invoice-{$tempInvoiceKey}" ) );
Db::i()->update( 'core_attachments_map', array( 'id3' => "invoice-{$invoice->id}" ), array( 'location_key=? AND id3=?', 'nexus_Purchases', "invoice-{$tempInvoiceKey}" ) );
\IPS\Output::i()->redirect( $invoice->checkoutUrl() );
Output::i()->redirect( $invoice->checkoutUrl() );
}
}
@@ -12,16 +12,42 @@
namespace IPS\nexus\modules\front\store;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use DomainException;
use InvalidArgumentException;
use IPS\Dispatcher\Controller;
use IPS\Helpers\Form;
use IPS\Helpers\Form\Color;
use IPS\Helpers\Form\Email;
use IPS\Helpers\Form\Radio;
use IPS\Helpers\Form\Text;
use IPS\Helpers\Form\TextArea;
use IPS\Http\Url;
use IPS\Math\Number;
use IPS\Member;
use IPS\nexus\Customer;
use IPS\nexus\extensions\nexus\Item\GiftVoucher;
use IPS\nexus\Gateway;
use IPS\nexus\Invoice;
use IPS\nexus\Money;
use IPS\Output;
use IPS\Request;
use IPS\Settings;
use IPS\Theme;
use function defined;
use function in_array;
use function is_numeric;
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;
}
/**
* Gift Vouchers
*/
class _gifts extends \IPS\Dispatcher\Controller
class gifts extends Controller
{
/**
@@ -29,15 +55,10 @@ class _gifts extends \IPS\Dispatcher\Controller
*
* @return void
*/
public function execute()
public function execute() : void
{
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_store.js', 'nexus', 'front' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'store.css', 'nexus' ) );
if ( \IPS\Theme::i()->settings['responsive'] )
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'store_responsive.css', 'nexus', 'front' ) );
}
Output::i()->jsFiles = array_merge( Output::i()->jsFiles, Output::i()->js( 'front_store.js', 'nexus', 'front' ) );
Output::i()->cssFiles = array_merge( Output::i()->cssFiles, Theme::i()->css( 'store.css', 'nexus' ) );
parent::execute();
}
@@ -47,59 +68,60 @@ class _gifts extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function manage()
protected function manage() : void
{
/* Work out what our options are */
$memberCurrency = ( ( ( isset( \IPS\Request::i()->cookie['currency'] ) and \in_array( \IPS\Request::i()->cookie['currency'], \IPS\nexus\Money::currencies() ) ) and \in_array( \IPS\Request::i()->cookie['currency'], \IPS\nexus\Money::currencies() ) ) ? \IPS\Request::i()->cookie['currency'] : \IPS\nexus\Customer::loggedIn()->defaultCurrency() );
$memberCurrency = ( ( ( isset( Request::i()->cookie['currency'] ) and in_array( Request::i()->cookie['currency'], Money::currencies() ) ) and in_array( Request::i()->cookie['currency'], Money::currencies() ) ) ? Request::i()->cookie['currency'] : Customer::loggedIn()->defaultCurrency() );
$options = array();
foreach ( json_decode( \IPS\Settings::i()->nexus_gift_vouchers, TRUE ) as $voucher )
foreach ( json_decode( Settings::i()->nexus_gift_vouchers, TRUE ) as $voucher )
{
if ( isset( $voucher[ $memberCurrency ] ) and $voucher[ $memberCurrency ] )
{
$options[ $voucher[ $memberCurrency ] ] = new \IPS\nexus\Money( $voucher[ $memberCurrency ], $memberCurrency );
$options[ $voucher[ $memberCurrency ] ] = new Money( $voucher[ $memberCurrency ], $memberCurrency );
}
}
if ( \IPS\Settings::i()->nexus_gift_vouchers_free )
if ( Settings::i()->nexus_gift_vouchers_free )
{
$options['x'] = \IPS\Member::loggedIn()->language()->addToStack('other');
$options['x'] = Member::loggedIn()->language()->addToStack('other');
}
if ( empty( $options ) )
{
\IPS\Output::i()->error( 'no_module_permission', '4X213/2', 403, '' );
Output::i()->error( 'no_module_permission', '4X213/2', 403, '' );
}
$form = new \IPS\Helpers\Form( 'form', 'buy_gift_voucher' );
$form->class = 'ipsForm_vertical';
$form->add( new \IPS\Helpers\Form\Color( 'gift_voucher_color', '3b3b3b', FALSE ) );
$form->add( new \IPS\Helpers\Form\Radio( 'gift_voucher_amount', NULL, TRUE, array( 'options' => $options, 'parse' => 'normal', 'userSuppliedInput' => 'x' ) ) );
$form->add( new \IPS\Helpers\Form\Radio( 'gift_voucher_method', NULL, TRUE, array( 'options' => array( 'email' => 'email', 'print' => 'gift_voucher_print' ), 'toggles' => array( 'email' => array( 'gift_voucher_email' ) ) ) ) );
$form->add( new \IPS\Helpers\Form\Email( 'gift_voucher_email', NULL, NULL, array(), function( $val )
$form = new Form( 'form', 'buy_gift_voucher' );
$form->class = 'ipsForm--vertical ipsForm--buy-gift-voucher';
$form->add( new Color( 'gift_voucher_color', '3b3b3b', FALSE ) );
$form->add( new Radio( 'gift_voucher_amount', NULL, TRUE, array( 'options' => $options, 'parse' => 'normal', 'userSuppliedInput' => 'x' ) ) );
$form->add( new Radio( 'gift_voucher_method', NULL, TRUE, array( 'options' => array( 'email' => 'email', 'print' => 'gift_voucher_print' ), 'toggles' => array( 'email' => array( 'gift_voucher_email' ) ) ) ) );
$form->add( new Email( 'gift_voucher_email', NULL, NULL, array(), function( $val )
{
if ( !$val and \IPS\Request::i()->gift_voucher_method === 'email' )
if ( !$val and Request::i()->gift_voucher_method === 'email' )
{
throw new \DomainException('form_required');
throw new DomainException('form_required');
}
}, NULL, NULL, 'gift_voucher_email' ) );
$form->add( new \IPS\Helpers\Form\Text( 'gift_voucher_recipient' ) );
$form->add( new \IPS\Helpers\Form\Text( 'gift_voucher_sender', \IPS\Member::loggedIn()->name ) );
$form->add( new \IPS\Helpers\Form\TextArea( 'gift_voucher_message' ) );
$form->add( new Text( 'gift_voucher_recipient' ) );
$form->add( new Text( 'gift_voucher_sender', Member::loggedIn()->name ) );
$form->add( new TextArea( 'gift_voucher_message' ) );
/* Handle submissions */
if ( $values = $form->values() )
{
if( ! \is_numeric( $values['gift_voucher_amount'] ) )
if( ! is_numeric( $values['gift_voucher_amount'] ) )
{
$form->error = \IPS\Member::loggedIn()->language()->addToStack( 'gift_voucher_invalid_value' );
$form->error = Member::loggedIn()->language()->addToStack( 'gift_voucher_invalid_value' );
}
elseif( ! abs( $values['gift_voucher_amount'] ) )
{
$form->error = \IPS\Member::loggedIn()->language()->addToStack( 'gift_voucher_invalid_amount' );
$form->error = Member::loggedIn()->language()->addToStack( 'gift_voucher_invalid_amount' );
}
if( !$form->error )
{
$item = new \IPS\nexus\extensions\nexus\Item\GiftVoucher( \IPS\Member::loggedIn()->language()->get( 'gift_voucher' ), new \IPS\nexus\Money( abs( $values[ 'gift_voucher_amount' ] ), $memberCurrency ) );
$item->paymentMethodIds = array_keys( \IPS\nexus\Gateway::roots( NULL, NULL, array( 'm_active=1 AND m_gateway<>?', 'TwoCheckout' ) ) ); // It is against 2CO terms to use them for buying gift vouchers
$item = new GiftVoucher( Member::loggedIn()->language()->get( 'gift_voucher' ), new Money( abs( $values[ 'gift_voucher_amount' ] ), $memberCurrency ) );
$item->paymentMethodIds = array_keys( Gateway::roots( NULL, NULL, array( 'm_active=1' ) ) );
$item->extra[ 'method' ] = $values[ 'gift_voucher_method' ];
$item->extra[ 'recipient_email' ] = $values[ 'gift_voucher_email' ];
$item->extra[ 'recipient_name' ] = $values[ 'gift_voucher_recipient' ];
@@ -109,22 +131,22 @@ class _gifts extends \IPS\Dispatcher\Controller
$item->extra[ 'color' ] = $values[ 'gift_voucher_color' ];
$item->extra[ 'currency' ] = $memberCurrency;
$invoice = new \IPS\nexus\Invoice;
$invoice = new Invoice;
$invoice->currency = $memberCurrency;
$invoice->member = \IPS\Member::loggedIn();
$invoice->member = Customer::loggedIn();
$invoice->addItem( $item );
$invoice->save();
\IPS\Output::i()->redirect( $invoice->checkoutUrl() );
Output::i()->redirect( $invoice->checkoutUrl() );
}
}
/* Display */
$formTemplate = $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'store', 'nexus' ), 'giftCardForm' ) );
$formTemplate = $form->customTemplate( array( Theme::i()->getTemplate( 'store', 'nexus' ), 'giftCardForm' ) );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('store')->giftCard( $formTemplate );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('buy_gift_voucher');
\IPS\Output::i()->breadcrumb[] = array( NULL, \IPS\Member::loggedIn()->language()->addToStack('buy_gift_voucher') );
Output::i()->output = Theme::i()->getTemplate('store')->giftCard( $formTemplate );
Output::i()->title = Member::loggedIn()->language()->addToStack('buy_gift_voucher');
Output::i()->breadcrumb[] = array( NULL, Member::loggedIn()->language()->addToStack('buy_gift_voucher') );
}
/**
@@ -132,9 +154,9 @@ class _gifts extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function formatCurrency()
protected function formatCurrency() : void
{
\IPS\Output::i()->json( (string) new \IPS\nexus\Money( \IPS\Request::i()->amount, ( ( isset( \IPS\Request::i()->cookie['currency'] ) and \in_array( \IPS\Request::i()->cookie['currency'], \IPS\nexus\Money::currencies() ) ) ? \IPS\Request::i()->cookie['currency'] : \IPS\nexus\Customer::loggedIn()->defaultCurrency() ) ) );
Output::i()->json( (string) new Money( Request::i()->amount, ( ( isset( Request::i()->cookie['currency'] ) and in_array( Request::i()->cookie['currency'], Money::currencies() ) ) ? Request::i()->cookie['currency'] : Customer::loggedIn()->defaultCurrency() ) ) );
}
/**
@@ -142,53 +164,53 @@ class _gifts extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function redeem()
protected function redeem() : void
{
if ( !\IPS\nexus\Customer::loggedIn()->member_id )
if ( !Customer::loggedIn()->member_id )
{
\IPS\Output::i()->error( 'redeem_must_be_logged_in', '1X213/1', 403, '' );
Output::i()->error( 'redeem_must_be_logged_in', '1X213/1', 403, '' );
}
$form = new \IPS\Helpers\Form( 'form', 'redeem_gift_voucher' );
$form->add( new \IPS\Helpers\Form\Text( 'redemption_code', isset( \IPS\Request::i()->code ) ? \IPS\Request::i()->code : NULL, TRUE, array(), function( $val )
$form = new Form( 'form', 'redeem_gift_voucher' );
$form->add( new Text( 'redemption_code', isset( Request::i()->code ) ? Request::i()->code : NULL, TRUE, array(), function( $val )
{
try
{
\IPS\nexus\extensions\nexus\Item\GiftVoucher::getPurchase( $val );
GiftVoucher::getPurchase( $val );
}
catch ( \InvalidArgumentException $e )
catch ( InvalidArgumentException )
{
throw new \DomainException('redeem_gift_voucher_error');
throw new DomainException('redeem_gift_voucher_error');
}
} ) );
if ( $values = $form->values() )
{
$purchase = \IPS\nexus\extensions\nexus\Item\GiftVoucher::getPurchase( $values['redemption_code'] );
$purchase = GiftVoucher::getPurchase( $values['redemption_code'] );
$extra = $purchase->extra;
$currency = isset( $extra['currency'] ) ? $extra['currency'] : \IPS\nexus\Customer::loggedIn()->defaultCurrency();
$currency = isset( $extra['currency'] ) ? $extra['currency'] : Customer::loggedIn()->defaultCurrency();
$credits = \IPS\nexus\Customer::loggedIn()->cm_credits;
$credits[ $currency ]->amount = $credits[ $currency ]->amount->add( new \IPS\Math\Number( number_format( $extra['amount'], \IPS\nexus\Money::numberOfDecimalsForCurrency( $currency ), '.', '' ) ) );
\IPS\nexus\Customer::loggedIn()->cm_credits = $credits;
\IPS\nexus\Customer::loggedIn()->save();
$credits = Customer::loggedIn()->cm_credits;
$credits[ $currency ]->amount = $credits[ $currency ]->amount->add( new Number( number_format( $extra['amount'], Money::numberOfDecimalsForCurrency( $currency ), '.', '' ) ) );
Customer::loggedIn()->cm_credits = $credits;
Customer::loggedIn()->save();
\IPS\nexus\Customer::loggedIn()->log( 'giftvoucher', array( 'type' => 'redeemed', 'code' => $values['redemption_code'], 'amount' => $extra['amount'], 'currency' => $extra['currency'], 'ps_member' => $purchase->member->member_id, 'newCreditAmount' => $credits[ $currency ]->amount ) );
$purchase->member->log( 'giftvoucher', array( 'type' => 'used', 'code' => $values['redemption_code'], 'amount' => $extra['amount'], 'currency' => $extra['currency'], 'by' => \IPS\nexus\Customer::loggedIn()->member_id ) );
Customer::loggedIn()->log( 'giftvoucher', array( 'type' => 'redeemed', 'code' => $values['redemption_code'], 'amount' => $extra['amount'], 'currency' => $extra['currency'], 'ps_member' => $purchase->member->member_id, 'newCreditAmount' => $credits[ $currency ]->amount ) );
$purchase->member->log( 'giftvoucher', array( 'type' => 'used', 'code' => $values['redemption_code'], 'amount' => $extra['amount'], 'currency' => $extra['currency'], 'by' => Customer::loggedIn()->member_id ) );
$purchase->delete();
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=nexus&module=store&controller=store&currency={$currency}", 'front', 'store' ) );
Output::i()->redirect( Url::internal( "app=nexus&module=store&controller=store&currency={$currency}", 'front', 'store' ) );
}
if( \IPS\Request::i()->isAjax() )
if( Request::i()->isAjax() )
{
$form->class = 'ipsForm_vertical';
\IPS\Output::i()->output = $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core', 'front' ), 'popupTemplate' ) );
$form->class = 'ipsForm--vertical ipsForm--redeem-voucher';
Output::i()->output = $form->customTemplate( array( Theme::i()->getTemplate( 'forms', 'core', 'front' ), 'popupTemplate' ) );
}
else
{
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'redemption_code' );
\IPS\Output::i()->output = $form;
Output::i()->title = Member::loggedIn()->language()->addToStack( 'redemption_code' );
Output::i()->output = $form;
}
}
}
+152 -208
View File
@@ -12,38 +12,66 @@
namespace IPS\nexus\modules\front\store;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use DateInterval;
use IPS\Content\Controller;
use IPS\core\Facebook\Pixel;
use IPS\Db;
use IPS\Helpers\Form;
use IPS\Helpers\Form\Radio;
use IPS\Helpers\Form\Select;
use IPS\Helpers\Form\Upload;
use IPS\Http\Url;
use IPS\Math\Number;
use IPS\Member;
use IPS\nexus\Customer;
use IPS\nexus\Money;
use IPS\nexus\Package;
use IPS\nexus\Package\CustomField;
use IPS\nexus\Package\Item;
use IPS\nexus\Purchase;
use IPS\nexus\Purchase\RenewalTerm;
use IPS\nexus\Tax;
use IPS\Output;
use IPS\Patterns\ActiveRecordIterator;
use IPS\Request;
use IPS\Session;
use IPS\Settings;
use IPS\Theme;
use OutOfBoundsException;
use OutOfRangeException;
use UnderflowException;
use function count;
use function defined;
use function in_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;
}
/**
* View product
*/
class _product extends \IPS\Content\Controller
class product extends Controller
{
/**
* [Content\Controller] Class
*/
protected static $contentModel = 'IPS\nexus\Package\Item';
protected static string $contentModel = 'IPS\nexus\Package\Item';
/**
* Execute
*
* @return void
*/
public function execute()
public function execute() : void
{
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_store.js', 'nexus', 'front' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'store.css', 'nexus' ) );
if ( \IPS\Theme::i()->settings['responsive'] )
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'store_responsive.css', 'nexus', 'front' ) );
}
\IPS\Output::setCacheTime( false );
Output::i()->jsFiles = array_merge( Output::i()->jsFiles, Output::i()->js( 'front_store.js', 'nexus', 'front' ) );
Output::i()->cssFiles = array_merge( Output::i()->cssFiles, Theme::i()->css( 'store.css', 'nexus' ) );
Output::i()->pageCaching = FALSE;
parent::execute();
}
@@ -51,24 +79,24 @@ class _product extends \IPS\Content\Controller
/**
* View
*
* @return void
* @return mixed
*/
protected function manage()
protected function manage() : mixed
{
/* Init */
if ( !isset( $_SESSION['cart'] ) )
{
$_SESSION['cart'] = array();
}
$memberCurrency = ( ( isset( \IPS\Request::i()->cookie['currency'] ) and \in_array( \IPS\Request::i()->cookie['currency'], \IPS\nexus\Money::currencies() ) ) ? \IPS\Request::i()->cookie['currency'] : \IPS\nexus\Customer::loggedIn()->defaultCurrency() );
$memberCurrency = ( ( isset( Request::i()->cookie['currency'] ) and in_array( Request::i()->cookie['currency'], Money::currencies() ) ) ? Request::i()->cookie['currency'] : Customer::loggedIn()->defaultCurrency() );
/* Load Package */
$item = parent::manage();
if ( !$item )
{
\IPS\Output::i()->error( 'node_error', '2X240/1', 404, '' );
Output::i()->error( 'node_error', '2X240/1', 404, '' );
}
$package = \IPS\nexus\Package::load( $item->id );
$package = Package::load( $item->id );
/* Do we have any in the cart already (this will affect stock level)? */
$inCart = array();
@@ -91,100 +119,25 @@ class _product extends \IPS\Content\Controller
}
/* Showing just the form to purchase, or full product page? */
if ( \IPS\Request::i()->purchase )
if ( Request::i()->purchase )
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('store')->purchaseForm( $package, $item, $this->_getForm( $package, $inCart, TRUE ) );
Output::i()->output = Theme::i()->getTemplate('store')->purchaseForm( $package, $item, $this->_getForm( $package, $inCart, TRUE ) );
}
/* No - show the full page */
else
{
/* We need to create a dummy item so we can work out ship times/prices */
$itemDataForShipping = NULL;
if ( $package->physical )
{
try
{
$itemDataForShipping = $package->createItemForCart( $package->price() );
}
catch ( \OutOfBoundsException $e ) { }
}
/* If physical, get available shipping methods */
$shippingMethods = array();
$locationType = 'none';
if ( $package->physical )
{
/* Where are we shipping to? */
$shipAddress = NULL;
if ( \IPS\Member::loggedIn()->member_id and $primaryBillingAddress = \IPS\nexus\Customer::loggedIn()->primaryBillingAddress() )
{
$shipAddress = $primaryBillingAddress;
$locationType = 'address';
}
if ( !$shipAddress )
{
try
{
$shipAddress = \IPS\GeoLocation::getRequesterLocation();
$locationType = 'geo';
}
catch ( \Exception $e ) { }
}
/* Standard */
$where = NULL;
if ( $package->shipping != '*' )
{
$where = \IPS\Db::i()->in( 's_id', explode( ',', $package->shipping ) );
}
foreach ( \IPS\nexus\Shipping\FlatRate::roots( NULL, NULL, $where ) as $rate )
{
if ( ( $shipAddress and $rate->isAvailable( $shipAddress, array( $itemDataForShipping ), $memberCurrency ) ) or ( $rate->locations === '*' ) )
{
$shippingMethods[] = $rate;
}
}
/* Easypost */
if ( $shipAddress and \IPS\Settings::i()->easypost_api_key and \IPS\Settings::i()->easypost_show_rates and ( $package->shipping == '*' or \in_array( 'easypost', explode( ',', $package->shipping ) ) ) )
{
try
{
$fromAddress = \IPS\GeoLocation::buildFromJson( \IPS\Settings::i()->easypost_address ?: \IPS\Settings::i()->site_address );
$length = new \IPS\nexus\Shipping\Length( $package->length );
$width = new \IPS\nexus\Shipping\Length( $package->width );
$height = new \IPS\nexus\Shipping\Length( $package->height );
$weight = new \IPS\nexus\Shipping\Weight( $package->weight );
$easyPost = \IPS\nexus\Shipping\EasyPostRate::getRates( $length->float('in'), $width->float('in'), $height->float('in'), $weight->float('oz'), \IPS\nexus\Customer::loggedIn(), $shipAddress, $memberCurrency );
if ( isset( $easyPost['rates'] ) )
{
foreach ( $easyPost['rates'] as $rate )
{
if ( $rate['currency'] === $memberCurrency )
{
$shippingMethods[] = new \IPS\nexus\Shipping\EasyPostRate( $rate );
}
}
}
}
catch ( \IPS\Http\Request\Exception $e ) { }
}
}
/* Do we have renewal terms? */
$renewalTerm = NULL;
$renewOptions = $package->renew_options ? json_decode( $package->renew_options, TRUE ) : array();
$initialTerm = NULL;
if ( \count( $renewOptions ) )
if ( count( $renewOptions ) )
{
$renewalTerm = TRUE;
if ( \count( $renewOptions ) === 1 )
if ( count( $renewOptions ) === 1 )
{
$renewalTerm = array_pop( $renewOptions );
$renewalTerm = new \IPS\nexus\Purchase\RenewalTerm( new \IPS\nexus\Money( $renewalTerm['cost'][ $memberCurrency ]['amount'], $memberCurrency ), new \DateInterval( 'P' . $renewalTerm['term'] . mb_strtoupper( $renewalTerm['unit'] ) ), $package->tax ? \IPS\nexus\Tax::load( $package->tax ) : NULL, $renewalTerm['add'] );
$renewalTerm = new RenewalTerm( new Money( $renewalTerm['cost'][ $memberCurrency ]['amount'], $memberCurrency ), new DateInterval( 'P' . $renewalTerm['term'] . mb_strtoupper( $renewalTerm['unit'] ) ), $package->tax ? Tax::load( $package->tax ) : NULL, $renewalTerm['add'] );
}
if ( $package->initial_term )
{
@@ -192,13 +145,13 @@ class _product extends \IPS\Content\Controller
switch( mb_substr( $package->initial_term, -1 ) )
{
case 'D':
$initialTerm = \IPS\Member::loggedIn()->language()->pluralize( \IPS\Member::loggedIn()->language()->get('renew_days'), array( $term ) );
$initialTerm = Member::loggedIn()->language()->pluralize( Member::loggedIn()->language()->get('renew_days'), array( $term ) );
break;
case 'M':
$initialTerm = \IPS\Member::loggedIn()->language()->pluralize( \IPS\Member::loggedIn()->language()->get('renew_months'), array( $term ) );
$initialTerm = Member::loggedIn()->language()->pluralize( Member::loggedIn()->language()->get('renew_months'), array( $term ) );
break;
case 'Y':
$initialTerm = \IPS\Member::loggedIn()->language()->pluralize( \IPS\Member::loggedIn()->language()->get('renew_years'), array( $term ) );
$initialTerm = Member::loggedIn()->language()->pluralize( Member::loggedIn()->language()->get('renew_years'), array( $term ) );
break;
}
}
@@ -206,29 +159,29 @@ class _product extends \IPS\Content\Controller
/* Display */
$formKey = "package_{$package->id}_submitted";
if ( \IPS\Request::i()->isAjax() and isset( \IPS\Request::i()->$formKey ) )
if ( Request::i()->isAjax() and isset( Request::i()->$formKey ) )
{
\IPS\Output::i()->sendOutput( $this->_getForm( $package, $inCart, TRUE ), 500 );
Output::i()->sendOutput( $this->_getForm( $package, $inCart, TRUE ), 500 );
}
else
{
/* Set default search */
\IPS\Output::i()->defaultSearchOption = array( 'nexus_package_item', "nexus_package_item_el" );
Output::i()->defaultSearchOption = array( 'nexus_package_item', "nexus_package_item_el" );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('store')->package( $package, $item, $this->_getForm( $package, $inCart, TRUE ), array_sum( $inCart ), $shippingMethods, $itemDataForShipping, $locationType, $renewalTerm, $initialTerm );
Output::i()->output = Theme::i()->getTemplate('store')->package( $package, $item, $this->_getForm( $package, $inCart, TRUE ), array_sum( $inCart ), $renewalTerm, $initialTerm );
}
try
{
$price = $package->price();
}
catch( \OutOfBoundsException $e )
catch( OutOfBoundsException )
{
$price = NULL;
}
/* Facebook Pixel */
\IPS\core\Facebook\Pixel::i()->ViewContent = array(
Pixel::i()->ViewContent = array(
'content_ids' => array( $package->id ),
'content_type' => 'product'
);
@@ -236,8 +189,8 @@ class _product extends \IPS\Content\Controller
/* A product MUST have an offer, so if there's no price (i.e. due to currency configuration) don't even output */
if( $price !== NULL )
{
\IPS\Output::i()->jsonLd['package'] = array(
'@context' => "http://schema.org",
Output::i()->jsonLd['package'] = array(
'@context' => "https://schema.org",
'@type' => "Product",
'name' => $package->_title,
'description' => $item->truncated( TRUE, NULL ),
@@ -250,80 +203,70 @@ class _product extends \IPS\Content\Controller
'priceCurrency' => $price->currency,
'seller' => array(
'@type' => 'Organization',
'name' => \IPS\Settings::i()->board_name
'name' => Settings::i()->board_name
),
),
);
/* Stock status */
if( $package->physical )
if( $package->stockLevel() === 0 )
{
if( $package->stockLevel() === 0 )
{
\IPS\Output::i()->jsonLd['package']['offers']['availability'] = 'http://schema.org/OutOfStock';
}
else
{
\IPS\Output::i()->jsonLd['package']['offers']['availability'] = 'http://schema.org/InStock';
}
Output::i()->jsonLd['package']['offers']['availability'] = 'https://schema.org/OutOfStock';
}
else
{
Output::i()->jsonLd['package']['offers']['availability'] = 'https://schema.org/InStock';
}
if( $package->image )
{
\IPS\Output::i()->jsonLd['package']['image'] = (string) $package->image;
\IPS\Output::i()->metaTags['og:image'] = (string)$package->image;
Output::i()->jsonLd['package']['image'] = (string) $package->image;
Output::i()->metaTags['og:image'] = (string)$package->image;
}
if( $package->reviewable AND $item->averageReviewRating() )
{
\IPS\Output::i()->jsonLd['package']['aggregateRating'] = array(
Output::i()->jsonLd['package']['aggregateRating'] = array(
'@type' => 'AggregateRating',
'ratingValue' => $item->averageReviewRating(),
'ratingCount' => $item->reviews
);
}
if( isset( $length ) )
{
\IPS\Output::i()->jsonLd['package']['depth'] = array( '@type' => 'Distance', 'name' => $length->string() );
\IPS\Output::i()->jsonLd['package']['width'] = array( '@type' => 'Distance', 'name' => $width->string() );
\IPS\Output::i()->jsonLd['package']['height'] = array( '@type' => 'Distance', 'name' => $height->string() );
\IPS\Output::i()->jsonLd['package']['weight'] = array( '@type' => 'QuantitativeValue', 'name' => $weight->string() );
}
}
}
}
return null;
}
/**
* Get form
*
* @param \IPS\nexus\Package $package The package
* @param Package $package The package
* @param array $inCart The number in the cart already for each of the field combinations
* @param bool $verticalForm Whether to output a vertical form (true) or not
* @return string
*/
protected function _getForm( \IPS\nexus\Package $package, $inCart, $verticalForm = FALSE )
protected function _getForm( Package $package, array $inCart, bool $verticalForm = FALSE ) : string
{
/* Is this a subscription package that we've already bought? */
if ( $package->subscription )
{
try
{
$purchase = \IPS\nexus\Purchase::constructFromData( \IPS\Db::i()->select( '*', 'nexus_purchases', array( 'ps_app=? AND ps_type=? AND ps_item_id=? AND ps_cancelled=0 AND ps_member=?', 'nexus', 'package', $package->id, \IPS\Member::loggedIn()->member_id ) )->first() );
return \IPS\Theme::i()->getTemplate( 'store', 'nexus' )->subscriptionPurchase( $purchase );
$purchase = Purchase::constructFromData( Db::i()->select( '*', 'nexus_purchases', array( 'ps_app=? AND ps_type=? AND ps_item_id=? AND ps_cancelled=0 AND ps_member=?', 'nexus', 'package', $package->id, Member::loggedIn()->member_id ) )->first() );
return Theme::i()->getTemplate( 'store', 'nexus' )->subscriptionPurchase( $purchase );
}
catch ( \UnderflowException $e ) {}
catch ( UnderflowException ) {}
}
/* Get member's currency */
$memberCurrency = ( ( isset( \IPS\Request::i()->cookie['currency'] ) and \in_array( \IPS\Request::i()->cookie['currency'], \IPS\nexus\Money::currencies() ) ) ? \IPS\Request::i()->cookie['currency'] : \IPS\nexus\Customer::loggedIn()->defaultCurrency() );
$memberCurrency = ( ( isset( Request::i()->cookie['currency'] ) and in_array( Request::i()->cookie['currency'], Money::currencies() ) ) ? Request::i()->cookie['currency'] : Customer::loggedIn()->defaultCurrency() );
/* Init form */
$form = new \IPS\Helpers\Form( "package_{$package->id}", 'add_to_cart' );
$form = new Form( "package_{$package->id}", 'add_to_cart' );
if ( $verticalForm )
{
$form->class = 'ipsForm_vertical';
$form->class = 'ipsForm--vertical ipsForm--add-to-cart';
}
/* Package-dependant fields */
@@ -333,7 +276,7 @@ class _product extends \IPS\Content\Controller
if ( $package->stock != -1 and $package->stock != -2 and ( $package->stock - array_sum( $inCart ) ) <= 0 )
{
$form->actionButtons = array();
$form->addButton( 'out_of_stock', 'submit', NULL, 'ipsButton ipsButton_primary', array( 'disabled' => 'disabled' ) );
$form->addButton( 'out_of_stock', 'submit', NULL, 'ipsButton ipsButton--primary', array( 'disabled' => 'disabled' ) );
}
/* And is it available for our currency */
@@ -343,28 +286,28 @@ class _product extends \IPS\Content\Controller
{
$price = $package->price();
}
catch ( \OutOfBoundsException $e )
catch ( OutOfBoundsException )
{
$form->actionButtons = array();
$form->addButton( 'currently_unavailable', 'submit', NULL, 'ipsButton ipsButton_primary', array( 'disabled' => 'disabled' ) );
$form->addButton( 'currently_unavailable', 'submit', NULL, 'ipsButton ipsButton--primary', array( 'disabled' => 'disabled' ) );
}
}
/* Associate */
if ( \count( $package->associablePackages() ) )
if ( count( $package->associablePackages() ) )
{
$associableIds = array_keys( $package->associablePackages() );
$associableOptions = array();
foreach ( $_SESSION['cart'] as $k => $item )
{
if ( \in_array( $item->id, $associableIds ) )
if ( in_array( $item->id, $associableIds ) )
{
for ( $i = 0; $i < $item->quantity; $i++ )
{
$name = $item->name;
if ( \count( $item->details ) )
if ( count( $item->details ) )
{
$customFields = \IPS\nexus\Package\CustomField::roots();
$customFields = CustomField::roots();
$stickyFields = array();
foreach ( $item->details as $_k => $v )
{
@@ -373,7 +316,7 @@ class _product extends \IPS\Content\Controller
$stickyFields[] = $v;
}
}
if ( \count( $stickyFields ) )
if ( count( $stickyFields ) )
{
$name .= ' (' . implode( ' &middot; ', $stickyFields ) . ')';
}
@@ -382,7 +325,7 @@ class _product extends \IPS\Content\Controller
}
}
}
foreach ( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'nexus_purchases', array( array( 'ps_member=? AND ps_app=? AND ps_type=?', \IPS\nexus\Customer::loggedIn()->member_id, 'nexus', 'package' ), \IPS\Db::i()->in( 'ps_item_id', $associableIds ) ) ), 'IPS\nexus\Purchase' ) as $purchase )
foreach ( new ActiveRecordIterator( Db::i()->select( '*', 'nexus_purchases', array( array( 'ps_member=? AND ps_app=? AND ps_type=?', Customer::loggedIn()->member_id, 'nexus', 'package' ), Db::i()->in( 'ps_item_id', $associableIds ) ) ), 'IPS\nexus\Purchase' ) as $purchase )
{
$associableOptions['existing_purchases']["1.{$purchase->id}"] = $purchase->name;
}
@@ -393,24 +336,24 @@ class _product extends \IPS\Content\Controller
{
array_unshift( $associableOptions, 'do_not_associate' );
}
$form->add( new \IPS\Helpers\Form\Select( 'associate_with', NULL, $package->force_assoc, array( 'options' => $associableOptions ) ) );
$form->add( new Select( 'associate_with', NULL, $package->force_assoc, array( 'options' => $associableOptions ) ) );
}
elseif ( $package->force_assoc )
{
return \IPS\Member::loggedIn()->language()->addToStack("nexus_package_{$package->id}_assoc");
return Member::loggedIn()->language()->addToStack("nexus_package_{$package->id}_assoc");
}
}
/* Renewal options */
$renewOptions = $package->renew_options ? json_decode( $package->renew_options, TRUE ) : array();
if ( \count( $renewOptions ) > 1 )
if ( count( $renewOptions ) > 1 )
{
$sortedRenewOptions = array();
foreach ( $renewOptions as $k => $option )
{
if ( isset( $renewOptions[ $k ]['cost'][ $memberCurrency ] ) )
if ( isset( $option['cost'][ $memberCurrency ] ) )
{
$sortedRenewOptions[ $k ] = new \IPS\nexus\Purchase\RenewalTerm( new \IPS\nexus\Money( $option['cost'][ $memberCurrency ]['amount'], $memberCurrency ), new \DateInterval( 'P' . $option['term'] . mb_strtoupper( $option['unit'] ) ), $package->tax ? \IPS\nexus\Tax::load( $package->tax ) : NULL, $option['add'], $package->grace_period ? new \DateInterval( 'P' . $package->grace_period . 'D' ) : NULL );
$sortedRenewOptions[ $k ] = new RenewalTerm( new Money( $option['cost'][ $memberCurrency ]['amount'], $memberCurrency ), new DateInterval( 'P' . $option['term'] . mb_strtoupper( $option['unit'] ) ), $package->tax ? Tax::load( $package->tax ) : NULL, $option['add'], $package->grace_period ? new DateInterval( 'P' . $package->grace_period . 'D' ) : NULL );
}
}
uasort( $sortedRenewOptions, function( $a, $b ) {
@@ -422,7 +365,7 @@ class _product extends \IPS\Content\Controller
foreach ( $sortedRenewOptions as $k => $term )
{
$saving = NULL;
if ( \IPS\Settings::i()->nexus_show_renew_option_savings != 'none' )
if ( Settings::i()->nexus_show_renew_option_savings != 'none' )
{
if ( $first === NULL )
{
@@ -430,19 +373,19 @@ class _product extends \IPS\Content\Controller
}
else
{
$saving = $term->diff( $first, \IPS\Settings::i()->nexus_show_renew_option_savings == 'percent' );
$saving = $term->diff( $first, Settings::i()->nexus_show_renew_option_savings == 'percent' );
}
}
if ( $saving and ( ( \IPS\Settings::i()->nexus_show_renew_option_savings == 'percent' and $saving->isGreaterThanZero() ) or ( \IPS\Settings::i()->nexus_show_renew_option_savings == 'amount' and $saving->amount->isGreaterThanZero() ) ) )
if ( $saving and ( ( Settings::i()->nexus_show_renew_option_savings == 'percent' and $saving->isGreaterThanZero() ) or ( Settings::i()->nexus_show_renew_option_savings == 'amount' and $saving->amount->isGreaterThanZero() ) ) )
{
if ( \IPS\Settings::i()->nexus_show_renew_option_savings == 'percent' )
if ( Settings::i()->nexus_show_renew_option_savings == 'percent' )
{
$options[ $k ] = \IPS\Member::loggedIn()->language()->addToStack( 'renewal_amount_with_pc_saving', FALSE, array( 'sprintf' => array( $term->toDisplay(), $saving->round(1) ) ) );
$options[ $k ] = Member::loggedIn()->language()->addToStack( 'renewal_amount_with_pc_saving', FALSE, array( 'sprintf' => array( $term->toDisplay(), $saving->round(1) ) ) );
}
else
{
$options[ $k ] = \IPS\Member::loggedIn()->language()->addToStack( 'renewal_amount_with_cost_saving', FALSE, array( 'sprintf' => array( $term->toDisplay(), $saving ) ) );
$options[ $k ] = Member::loggedIn()->language()->addToStack( 'renewal_amount_with_cost_saving', FALSE, array( 'sprintf' => array( $term->toDisplay(), $saving ) ) );
}
}
else
@@ -453,14 +396,15 @@ class _product extends \IPS\Content\Controller
ksort( $options );
$form->add( new \IPS\Helpers\Form\Radio( 'renewal_term', NULL, TRUE, array( 'options' => $options ) ) );
$form->add( new Radio( 'renewal_term', NULL, TRUE, array( 'options' => $options ) ) );
}
/* Custom Fields */
$customFields = \IPS\nexus\Package\CustomField::roots( NULL, NULL, array( array( 'cf_purchase=1' ), array( \IPS\Db::i()->findInSet( 'cf_packages', array( $package->id ) ) ) ) );
$customFields = CustomField::roots( NULL, NULL, array( array( 'cf_purchase=1' ), array( Db::i()->findInSet( 'cf_packages', array( $package->id ) ) ) ) );
foreach ( $customFields as $field )
{
if( \IPS\Request::i()->isAjax() && isset( \IPS\Request::i()->stockCheck ) )
/* @var CustomField $field */
if( Request::i()->isAjax() && isset( Request::i()->stockCheck ) )
{
$field->required = FALSE; // Otherwise a required text field (for example) can block the price changing when a different radio (for example) value is selected
}
@@ -469,12 +413,12 @@ class _product extends \IPS\Content\Controller
}
/* Is this the validation for the additional page? */
if ( \IPS\Request::i()->isAjax() and isset( \IPS\Request::i()->additionalPageCheck ) )
if ( Request::i()->isAjax() and isset( Request::i()->additionalPageCheck ) )
{
if ( $additionalPage = $package->storeAdditionalPage( $_POST ) )
{
\IPS\Output::i()->httpHeaders['X-IPS-FormNoSubmit'] = "true";
\IPS\Output::i()->json( $additionalPage );
Output::i()->httpHeaders['X-IPS-FormNoSubmit'] = "true";
Output::i()->json( $additionalPage );
}
}
@@ -489,7 +433,7 @@ class _product extends \IPS\Content\Controller
if ( isset( $values[ 'nexus_pfield_' . $field->id ] ) )
{
$class = $field->buildHelper();
if ( $class instanceof \IPS\Helpers\Form\Upload )
if ( $class instanceof Upload )
{
$details[ $field->id ] = (string) $values[ 'nexus_pfield_' . $field->id ];
}
@@ -498,10 +442,10 @@ class _product extends \IPS\Content\Controller
$details[ $field->id ] = $class::stringValue( $values[ 'nexus_pfield_' . $field->id ] );
}
if ( !isset( \IPS\Request::i()->stockCheck ) and $field->type === 'Editor' )
if ( !isset( Request::i()->stockCheck ) and $field->type === 'Editor' )
{
$uploadId = \IPS\Db::i()->insert( 'nexus_cart_uploads', array(
'session_id' => \IPS\Session::i()->id,
$uploadId = Db::i()->insert( 'nexus_cart_uploads', array(
'session_id' => Session::i()->id,
'time' => time()
) );
$field->claimAttachments( $uploadId, 'cart' );
@@ -512,18 +456,18 @@ class _product extends \IPS\Content\Controller
$optionValues = $package->optionValues( $details );
/* Stock check */
$quantity = isset( $values['quantity'] ) ? $values['quantity'] : 1;
$quantity = $values['quantity'] ?? 1;
try
{
$data = $package->optionValuesStockAndPrice( $optionValues, TRUE );
}
catch ( \UnderflowException $e )
catch ( UnderflowException )
{
\IPS\Output::i()->error( 'product_options_price_error', '3X240/2', 500, 'product_options_price_error_admin' );
Output::i()->error( 'product_options_price_error', '3X240/2', 500, 'product_options_price_error_admin' );
}
$inCartForThisFieldCombination = isset( $inCart[ json_encode( $optionValues ) ] ) ? $inCart[ json_encode( $optionValues ) ] : 0;
if ( \IPS\Request::i()->isAjax() && isset( \IPS\Request::i()->stockCheck ) )
if ( Request::i()->isAjax() && isset( Request::i()->stockCheck ) )
{
/* Stock */
if ( $data['stock'] == -1 )
@@ -536,8 +480,8 @@ class _product extends \IPS\Content\Controller
else
{
$return = array(
'stock' => \IPS\Member::loggedIn()->language()->addToStack( 'x_in_stock', FALSE, array( 'pluralize' => array( $data['stock'] - $inCartForThisFieldCombination ) ) ),
'okay' => ( $data['stock'] - $inCartForThisFieldCombination > 0 ) ? true : false,
'stock' => Member::loggedIn()->language()->addToStack( 'x_in_stock', FALSE, array( 'pluralize' => array( $data['stock'] - $inCartForThisFieldCombination ) ) ),
'okay' => ( $data['stock'] - $inCartForThisFieldCombination > 0 ),
);
}
@@ -549,36 +493,36 @@ class _product extends \IPS\Content\Controller
$renewOptions = $package->renew_options ? json_decode( $package->renew_options, TRUE ) : array();
if ( !empty( $renewOptions ) )
{
$term = ( isset( \IPS\Request::i()->renewal_term ) and isset( $renewOptions[ \IPS\Request::i()->renewal_term ] ) ) ? $renewOptions[ \IPS\Request::i()->renewal_term ] : array_shift( $renewOptions );
$term = ( isset( Request::i()->renewal_term ) and isset( $renewOptions[ Request::i()->renewal_term ] ) ) ? $renewOptions[ Request::i()->renewal_term ] : array_shift( $renewOptions );
switch( $term['unit'] )
{
case 'd':
$initialTerm = \IPS\Member::loggedIn()->language()->pluralize( \IPS\Member::loggedIn()->language()->get('renew_days'), array( $term['term'] ) );
$initialTerm = Member::loggedIn()->language()->pluralize( Member::loggedIn()->language()->get('renew_days'), array( $term['term'] ) );
break;
case 'm':
$initialTerm = \IPS\Member::loggedIn()->language()->pluralize( \IPS\Member::loggedIn()->language()->get('renew_months'), array( $term['term'] ) );
$initialTerm = Member::loggedIn()->language()->pluralize( Member::loggedIn()->language()->get('renew_months'), array( $term['term'] ) );
break;
case 'y':
$initialTerm = \IPS\Member::loggedIn()->language()->pluralize( \IPS\Member::loggedIn()->language()->get('renew_years'), array( $term['term'] ) );
$initialTerm = Member::loggedIn()->language()->pluralize( Member::loggedIn()->language()->get('renew_years'), array( $term['term'] ) );
break;
}
$return['initialTerm'] = sprintf( \IPS\Member::loggedIn()->language()->get('package_initial_term_title'), $initialTerm );
$return['initialTerm'] = sprintf( Member::loggedIn()->language()->get('package_initial_term_title'), $initialTerm );
if ( $term['add'] )
{
$data['price']->amount = $data['price']->amount->add( new \IPS\Math\Number( number_format( $term['cost'][ $memberCurrency ]['amount'], \IPS\nexus\Money::numberOfDecimalsForCurrency( $memberCurrency ), '.', '' ) ) );
$normalPrice->amount = $normalPrice->amount->add( new \IPS\Math\Number( number_format( $term['cost'][ $memberCurrency ]['amount'], \IPS\nexus\Money::numberOfDecimalsForCurrency( $memberCurrency ), '.', '' ) ) );
$data['price']->amount = $data['price']->amount->add( new Number( number_format( $term['cost'][ $memberCurrency ]['amount'], Money::numberOfDecimalsForCurrency( $memberCurrency ), '.', '' ) ) );
$normalPrice->amount = $normalPrice->amount->add( new Number( number_format( $term['cost'][ $memberCurrency ]['amount'], Money::numberOfDecimalsForCurrency( $memberCurrency ), '.', '' ) ) );
}
$return['renewal'] = ( new \IPS\nexus\Purchase\RenewalTerm(
new \IPS\nexus\Money(
( new \IPS\Math\Number( number_format( $term['cost'][ $memberCurrency ]['amount'], \IPS\nexus\Money::numberOfDecimalsForCurrency( $memberCurrency ), '.', '' ) ) )
->add( ( new \IPS\Math\Number( number_format( $_data['renewalAdjustment'], \IPS\nexus\Money::numberOfDecimalsForCurrency( $memberCurrency ), '.', '' ) ) ) )
$return['renewal'] = ( new RenewalTerm(
new Money(
( new Number( number_format( $term['cost'][ $memberCurrency ]['amount'], Money::numberOfDecimalsForCurrency( $memberCurrency ), '.', '' ) ) )
->add( ( new Number( number_format( $_data['renewalAdjustment'], Money::numberOfDecimalsForCurrency( $memberCurrency ), '.', '' ) ) ) )
, $memberCurrency ),
new \DateInterval( 'P' . $term['term'] . mb_strtoupper( $term['unit'] ) ),
$package->tax ? \IPS\nexus\Tax::load( $package->tax ) : NULL, $term['add']
new DateInterval( 'P' . $term['term'] . mb_strtoupper( $term['unit'] ) ),
$package->tax ? Tax::load( $package->tax ) : NULL, $term['add']
) )->toDisplay();
}
else
@@ -587,40 +531,40 @@ class _product extends \IPS\Content\Controller
}
/* Include tax? */
if ( \IPS\Settings::i()->nexus_show_tax and $package->tax )
if ( Settings::i()->nexus_show_tax and $package->tax )
{
try
{
$taxRate = new \IPS\Math\Number( \IPS\nexus\Tax::load( $package->tax )->rate( \IPS\nexus\Customer::loggedIn()->estimatedLocation() ) );
$taxRate = new Number( Tax::load( $package->tax )->rate( Customer::loggedIn()->estimatedLocation() ) );
$data['price']->amount = $data['price']->amount->add( $data['price']->amount->multiply( $taxRate ) );
$normalPrice->amount = $normalPrice->amount->add( $normalPrice->amount->multiply( $taxRate ) );
}
catch ( \OutOfRangeException $e ) { }
catch ( OutOfRangeException ) { }
}
/* Format and return */
if ( $data['price']->amount->compare( $normalPrice->amount ) !== 0 )
{
$return['price'] = \IPS\Theme::i()->getTemplate( 'store', 'nexus' )->priceDiscounted( $normalPrice, $data['price'], FALSE, FALSE, NULL );
$return['price'] = Theme::i()->getTemplate( 'store', 'nexus' )->priceDiscounted( $normalPrice, $data['price'], FALSE, FALSE, NULL );
}
else
{
$return['price'] = \IPS\Theme::i()->getTemplate( 'store', 'nexus' )->price( $data['price'], FALSE, FALSE, NULL );
$return['price'] = Theme::i()->getTemplate( 'store', 'nexus' )->price( $data['price'], FALSE, FALSE, NULL );
}
\IPS\Output::i()->json( $return );
Output::i()->json( $return );
}
elseif ( $data['stock'] != -1 and ( $data['stock'] - $inCartForThisFieldCombination ) < $quantity )
{
$form->error = \IPS\Member::loggedIn()->language()->addToStack( 'not_enough_in_stock', FALSE, array( 'sprintf' => array( $data['stock'] - $inCartForThisFieldCombination ) ) );
$form->error = Member::loggedIn()->language()->addToStack( 'not_enough_in_stock', FALSE, array( 'sprintf' => array( $data['stock'] - $inCartForThisFieldCombination ) ) );
return (string) $form;
}
if ( ( !isset( \IPS\Request::i()->additionalPageCheck ) or !\IPS\Request::i()->isAjax() ) and $additionalPage = $package->storeAdditionalPage( $_POST ) )
if ( ( !isset( Request::i()->additionalPageCheck ) or !Request::i()->isAjax() ) and $additionalPage = $package->storeAdditionalPage( $_POST ) )
{
if ( \IPS\Request::i()->isAjax() )
if ( Request::i()->isAjax() )
{
\IPS\Output::i()->json( array( 'dialog' => $additionalPage ) );
Output::i()->json( array( 'dialog' => $additionalPage ) );
}
else
{
@@ -630,9 +574,9 @@ class _product extends \IPS\Content\Controller
/* Work out renewal term */
$renewalTerm = NULL;
if ( \count( $renewOptions ) )
if ( count( $renewOptions ) )
{
if ( \count( $renewOptions ) === 1 )
if ( count( $renewOptions ) === 1 )
{
$chosenRenewOption = array_pop( $renewOptions );
}
@@ -641,7 +585,7 @@ class _product extends \IPS\Content\Controller
$chosenRenewOption = $renewOptions[ $values['renewal_term'] ];
}
$renewalTerm = new \IPS\nexus\Purchase\RenewalTerm( new \IPS\nexus\Money( ( new \IPS\Math\Number( number_format( $chosenRenewOption['cost'][ $memberCurrency ]['amount'], 2, '.', '' ) ) )->add( new \IPS\Math\Number( number_format( $data['renewalAdjustment'], 2, '.', '' ) ) ), $memberCurrency ), new \DateInterval( 'P' . $chosenRenewOption['term'] . mb_strtoupper( $chosenRenewOption['unit'] ) ), $package->tax ? \IPS\nexus\Tax::load( $package->tax ) : NULL, $chosenRenewOption['add'], $package->grace_period ? new \DateInterval( 'P' . $package->grace_period . 'D' ) : NULL );
$renewalTerm = new RenewalTerm( new Money( ( new Number( number_format( $chosenRenewOption['cost'][ $memberCurrency ]['amount'], 2, '.', '' ) ) )->add( new Number( number_format( $data['renewalAdjustment'], 2, '.', '' ) ) ), $memberCurrency ), new DateInterval( 'P' . $chosenRenewOption['term'] . mb_strtoupper( $chosenRenewOption['unit'] ) ), $package->tax ? Tax::load( $package->tax ) : NULL, $chosenRenewOption['add'], $package->grace_period ? new DateInterval( 'P' . $package->grace_period . 'D' ) : NULL );
}
/* Associations */
@@ -651,7 +595,7 @@ class _product extends \IPS\Content\Controller
$exploded = explode( '.', $values['associate_with'] );
if ( $exploded[0] )
{
$parent = \IPS\nexus\Purchase::load( $exploded[1] );
$parent = Purchase::load( $exploded[1] );
}
else
{
@@ -661,20 +605,20 @@ class _product extends \IPS\Content\Controller
/* Actually add to cart */
$cartId = $package->addItemsToCartData( $details, $quantity, $renewalTerm, $parent, $values );
\IPS\Db::i()->update( 'nexus_cart_uploads', array( 'item_id' => $cartId ), \IPS\Db::i()->in( 'id', $editorUploadIds ) );
Db::i()->update( 'nexus_cart_uploads', array( 'item_id' => $cartId ), Db::i()->in( 'id', $editorUploadIds ) );
/* Redirect or AJAX */
if ( \IPS\Request::i()->isAjax() )
if ( Request::i()->isAjax() )
{
/* Upselling? */
$upsell = \IPS\nexus\Package\Item::getItemsWithPermission( array( array( 'p_upsell=1' ), array( \IPS\Db::i()->findInSet( 'p_associable', array( $package->id ) ) ) ), 'p_position' );
$upsell = Item::getItemsWithPermission( array( array( 'p_upsell=1' ), array( Db::i()->findInSet( 'p_associable', array( $package->id ) ) ) ), 'p_position' );
/* Send */
\IPS\Output::i()->json( array( 'dialog' => \IPS\Theme::i()->getTemplate('store')->cartReview( $package, $quantity, $upsell ), 'cart' => \IPS\Theme::i()->getTemplate('store')->cartHeader(), 'css' => \IPS\Output::i()->cssFiles ) );
Output::i()->json( array( 'dialog' => Theme::i()->getTemplate('store')->cartReview( $package, $quantity, $upsell ), 'cart' => Theme::i()->getTemplate('store')->cartHeader(), 'css' => Output::i()->cssFiles ) );
}
else
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=nexus&module=store&controller=cart&added=' . $package->id, 'front', 'store_cart' ) );
Output::i()->redirect( Url::internal( 'app=nexus&module=store&controller=cart&added=' . $package->id, 'front', 'store_cart' ) );
}
}
+137 -120
View File
@@ -12,59 +12,87 @@
namespace IPS\nexus\modules\front\store;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use DateInterval;
use IPS\Content\Filter;
use IPS\DateTime;
use IPS\Db;
use IPS\Dispatcher\Controller;
use IPS\Helpers\Form;
use IPS\Helpers\Form\Number;
use IPS\Http\Url;
use IPS\Login;
use IPS\Member;
use IPS\nexus\Customer;
use IPS\nexus\Money;
use IPS\nexus\Package;
use IPS\nexus\Package\Group;
use IPS\nexus\Package\Item;
use IPS\Output;
use IPS\Patterns\ActiveRecordIterator;
use IPS\Request;
use IPS\Session;
use IPS\Settings;
use IPS\Theme;
use OutOfBoundsException;
use OutofRangeException;
use function count;
use function defined;
use function floatval;
use function in_array;
use function intval;
use function is_array;
use function is_numeric;
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;
}
/**
* Browse Store
*/
class _store extends \IPS\Dispatcher\Controller
class store extends Controller
{
/**
* @brief Products per page
*/
protected static $productsPerPage = 50;
protected static int $productsPerPage = 50;
/**
* @brief Currency
*/
protected $currency;
protected mixed $currency = NULL;
/**
* Execute
*
* @return void
*/
public function execute()
public function execute() : void
{
/* Set CSS */
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'store.css', 'nexus' ) );
if ( \IPS\Theme::i()->settings['responsive'] )
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'store_responsive.css', 'nexus', 'front' ) );
}
Output::i()->cssFiles = array_merge( Output::i()->cssFiles, Theme::i()->css( 'store.css', 'nexus' ) );
/* Work out currency */
if ( isset( \IPS\Request::i()->currency ) and \in_array( \IPS\Request::i()->currency, \IPS\nexus\Money::currencies() ) )
if ( isset( Request::i()->currency ) and in_array( Request::i()->currency, Money::currencies() ) )
{
if ( isset( \IPS\Request::i()->csrfKey ) and \IPS\Login::compareHashes( (string) \IPS\Session::i()->csrfKey, (string) \IPS\Request::i()->csrfKey ) )
if ( isset( Request::i()->csrfKey ) and Login::compareHashes( (string) Session::i()->csrfKey, (string) Request::i()->csrfKey ) )
{
$_SESSION['cart'] = array();
\IPS\Request::i()->setCookie( 'currency', \IPS\Request::i()->currency );
Request::i()->setCookie( 'currency', Request::i()->currency );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=nexus&module=store&controller=store', 'front', 'store' ) );
Output::i()->redirect( Url::internal( 'app=nexus&module=store&controller=store', 'front', 'store' ) );
}
$this->currency = \IPS\Request::i()->currency;
$this->currency = Request::i()->currency;
}
else
{
$this->currency = \IPS\nexus\Customer::loggedIn()->defaultCurrency();
$this->currency = Customer::loggedIn()->defaultCurrency();
}
\IPS\Output::setCacheTime( false );
Output::i()->pageCaching = FALSE;
/* Pass up */
parent::execute();
@@ -75,12 +103,12 @@ class _store extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function manage()
protected function manage() : void
{
/* If we have a category, display it */
if ( isset( \IPS\Request::i()->cat ) )
if ( isset( Request::i()->cat ) )
{
return $this->_categoryView();
$this->_categoryView();
}
/* Otherwise, display the index */
@@ -95,21 +123,21 @@ class _store extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function _categoryView()
protected function _categoryView() : void
{
/* Load category */
try
{
$category = \IPS\nexus\Package\Group::loadAndCheckPerms( \IPS\Request::i()->cat );
$category = Group::loadAndCheckPerms( Request::i()->cat );
}
catch ( \OutofRangeException $e )
catch ( OutofRangeException )
{
\IPS\Output::i()->error( 'node_error', '1X241/1', 404, '' );
Output::i()->error( 'node_error', '1X241/1', 404, '' );
}
$url = $category->url();
/* Set initial stuff for fetching packages */
$currentPage = isset( \IPS\Request::i()->page ) ? \intval( \IPS\Request::i()->page ) : 1;
$currentPage = isset( Request::i()->page ) ? intval( Request::i()->page ) : 1;
if( $currentPage < 1 )
{
$currentPage = 1;
@@ -117,55 +145,55 @@ class _store extends \IPS\Dispatcher\Controller
$where = array(
array( 'p_group=?', $category->id ),
array( 'p_store=1' ),
array( "( p_member_groups='*' OR " . \IPS\Db::i()->findInSet( 'p_member_groups', \IPS\Member::loggedIn()->groups ) . ' )' )
array( "( p_member_groups='*' OR " . Db::i()->findInSet( 'p_member_groups', Member::loggedIn()->groups ) . ' )' )
);
$havePackagesWhichAcceptReviews = (bool) \IPS\Db::i()->select( 'COUNT(*)', 'nexus_packages', array_merge( $where, array( array( 'p_reviewable=1' ) ) ) )->first();
$havePackagesWhichUseStockLevels = (bool) \IPS\Db::i()->select( 'COUNT(*)', 'nexus_packages', array_merge( $where, array( array( 'p_stock<>-1' ) ) ) )->first();
$havePackagesWhichAcceptReviews = (bool) Db::i()->select( 'COUNT(*)', 'nexus_packages', array_merge( $where, array( array( 'p_reviewable=1' ) ) ) )->first();
$havePackagesWhichUseStockLevels = (bool) Db::i()->select( 'COUNT(*)', 'nexus_packages', array_merge( $where, array( array( 'p_stock<>-1' ) ) ) )->first();
$joins = array();
/* Apply Filters */
if ( isset( \IPS\Request::i()->filter ) and \is_array( \IPS\Request::i()->filter ) )
if ( isset( Request::i()->filter ) and is_array( Request::i()->filter ) )
{
$url = $url->setQueryString( 'filter', \IPS\Request::i()->filter );
foreach ( \IPS\Request::i()->filter as $filterId => $allowedValues )
$url = $url->setQueryString( 'filter', Request::i()->filter );
foreach ( Request::i()->filter as $filterId => $allowedValues )
{
$filterId = (int) $filterId;
$where[] = array( \IPS\Db::i()->findInSet( "filter{$filterId}.pfm_values", array_map( 'intval', explode( ',', $allowedValues ) ) ) );
$where[] = array( Db::i()->findInSet( "filter{$filterId}.pfm_values", array_map( 'intval', explode( ',', $allowedValues ) ) ) );
$joins[] = array( 'table' => array( 'nexus_package_filters_map', "filter{$filterId}" ), 'on' => array( "filter{$filterId}.pfm_package=p_id AND filter{$filterId}.pfm_filter=?", $filterId ) );
}
}
foreach ( array( 'minPrice' => '>', 'maxPrice' => '<' ) as $k => $op )
{
if ( isset( \IPS\Request::i()->$k ) and \is_numeric( \IPS\Request::i()->$k ) and \floatval( \IPS\Request::i()->$k ) > 0 )
if ( isset( Request::i()->$k ) and is_numeric( Request::i()->$k ) and floatval( Request::i()->$k ) > 0 )
{
$url = $url->setQueryString( $k, \IPS\Request::i()->$k );
$url = $url->setQueryString( $k, Request::i()->$k );
$joins['nexus_package_base_prices'] = array( 'table' => 'nexus_package_base_prices', 'on' => array( 'id=p_id' ) );
$where[] = array( $this->currency . $op . '=?', \floatval( \IPS\Request::i()->$k ) );
$where[] = array( $this->currency . $op . '=?', floatval( Request::i()->$k ) );
}
}
if ( isset( \IPS\Request::i()->minRating ) and \is_numeric( \IPS\Request::i()->minRating ) and \floatval( \IPS\Request::i()->minRating ) > 0 )
if ( isset( Request::i()->minRating ) and is_numeric( Request::i()->minRating ) and floatval( Request::i()->minRating ) > 0 )
{
$url = $url->setQueryString( 'minRating', \IPS\Request::i()->minRating );
$where[] = array( 'p_rating>=?', \intval( \IPS\Request::i()->minRating ) );
$url = $url->setQueryString( 'minRating', Request::i()->minRating );
$where[] = array( 'p_rating>=?', intval( Request::i()->minRating ) );
}
if ( isset( \IPS\Request::i()->inStock ) )
if ( isset( Request::i()->inStock ) )
{
$url = $url->setQueryString( 'inStock', \IPS\Request::i()->inStock );
$where[] = array( '( p_stock>0 OR ( p_stock=-2 AND (?)>0 ) )', \IPS\Db::i()->select( 'MAX(opt_stock)', 'nexus_product_options', 'opt_package=p_id' ) );
$url = $url->setQueryString( 'inStock', Request::i()->inStock );
$where[] = array( '( p_stock>0 OR ( p_stock=-2 AND (?)>0 ) )', Db::i()->select( 'MAX(opt_stock)', 'nexus_product_options', 'opt_package=p_id' ) );
}
/* Figure out the sorting */
switch ( \IPS\Request::i()->sortby )
switch ( Request::i()->sortby )
{
case 'name':
$joins['core_sys_lang_words'] = array( 'table' => 'core_sys_lang_words', 'on' => array( "word_app='nexus' AND word_key=CONCAT( 'nexus_package_', p_id ) AND lang_id=?", \IPS\Member::loggedIn()->language()->id ) );
$joins['core_sys_lang_words'] = array( 'table' => 'core_sys_lang_words', 'on' => array( "word_app='nexus' AND word_key=CONCAT( 'nexus_package_', p_id ) AND lang_id=?", Member::loggedIn()->language()->id ) );
$sortBy = 'word_custom';
break;
case 'price_low':
case 'price_high':
$joins['nexus_package_base_prices'] = array( 'table' => 'nexus_package_base_prices', 'on' => array( 'id=p_id' ) );
$sortBy = \IPS\Request::i()->sortby == 'price_low' ? $this->currency : ( $this->currency . ' DESC' );
$sortBy = Request::i()->sortby == 'price_low' ? $this->currency : ( $this->currency . ' DESC' );
break;
case 'rating':
@@ -178,15 +206,15 @@ class _store extends \IPS\Dispatcher\Controller
}
/* Fetch the packages */
$select = \IPS\Db::i()->select( '*', 'nexus_packages', $where, $sortBy, array( ( $currentPage - 1 ) * static::$productsPerPage, static::$productsPerPage ) );
$select = Db::i()->select( '*', 'nexus_packages', $where, $sortBy, array( ( $currentPage - 1 ) * static::$productsPerPage, static::$productsPerPage ) );
foreach ( $joins as $join )
{
$select->join( $join['table'], $join['on'] );
}
$packages = new \IPS\Patterns\ActiveRecordIterator( $select, 'IPS\nexus\Package' );
$packages = new ActiveRecordIterator( $select, 'IPS\nexus\Package' );
/* Get packages count */
$select = \IPS\Db::i()->select( 'COUNT(*)', 'nexus_packages', $where );
$select = Db::i()->select( 'COUNT(*)', 'nexus_packages', $where );
foreach ( $joins as $join )
{
$select->join( $join['table'], $join['on'] );
@@ -197,50 +225,41 @@ class _store extends \IPS\Dispatcher\Controller
$totalPages = ceil( $totalCount / static::$productsPerPage );
if ( $totalPages and $currentPage > $totalPages )
{
\IPS\Output::i()->redirect( $category->url()->setPage( 'page', $totalPages ), NULL, 303 );
Output::i()->redirect( $category->url()->setPage( 'page', $totalPages ), NULL, 303 );
}
$pagination = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination( $category->url(), $totalPages, $currentPage, static::$productsPerPage );
$pagination = Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination( $category->url(), $totalPages, $currentPage, static::$productsPerPage );
/* Other stuff we need for the view */
$subcategories = new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'nexus_package_groups', array( 'pg_parent=?', $category->id ), 'pg_position ASC' ), 'IPS\nexus\Package\Group' );
$subcategories = new ActiveRecordIterator( Db::i()->select( '*', 'nexus_package_groups', array( 'pg_parent=?', $category->id ), 'pg_position ASC' ), 'IPS\nexus\Package\Group' );
$packagesWithCustomFields = array();
foreach ( iterator_to_array( \IPS\Db::i()->select( 'cf_packages', 'nexus_package_fields', 'cf_purchase=1' ) ) as $ids )
foreach ( iterator_to_array( Db::i()->select( 'cf_packages', 'nexus_package_fields', 'cf_purchase=1' ) ) as $ids )
{
$packagesWithCustomFields = array_merge( $packagesWithCustomFields, array_filter( explode( ',', $ids ) ) );
}
/* List or grid? */
if ( \IPS\Request::i()->view )
{
\IPS\Session::i()->csrfCheck();
\IPS\Request::i()->setCookie( 'storeView', ( \IPS\Request::i()->view == 'list' ) ? 'list' : 'grid', \IPS\DateTime::ts( time() )->add( new \DateInterval( 'P1Y' ) ) );
\IPS\Request::i()->cookie['storeView'] = ( \IPS\Request::i()->view == 'list' ) ? 'list' : 'grid';
}
/* Output */
if ( \IPS\Request::i()->isAjax() )
if ( Request::i()->isAjax() )
{
\IPS\Output::i()->json( array(
'contents' => \IPS\Theme::i()->getTemplate('store')->categoryContents( $category, $subcategories, $packages, $pagination, $packagesWithCustomFields, $totalCount ),
'sidebar' => \IPS\Theme::i()->getTemplate('store')->categorySidebar( $category, $subcategories, $url, \count( $packages ), $this->currency, $havePackagesWhichAcceptReviews, $havePackagesWhichUseStockLevels )
Output::i()->json( array(
'contents' => Theme::i()->getTemplate('store')->categoryContents( $category, $subcategories, $packages, $pagination, $packagesWithCustomFields, $totalCount ),
'sidebar' => Theme::i()->getTemplate('store')->categorySidebar( $category, $subcategories, $url, count( $packages ), $this->currency, $havePackagesWhichAcceptReviews, $havePackagesWhichUseStockLevels )
)) ;
return;
}
else
{
foreach ( $category->parents() as $parent )
{
\IPS\Output::i()->breadcrumb[] = array( $parent->url(), $parent->_title );
Output::i()->breadcrumb[] = array( $parent->url(), $parent->_title );
}
\IPS\Output::i()->breadcrumb[] = array( $category->url(), $category->_title );
\IPS\Output::i()->title = $category->_title;
\IPS\Output::i()->sidebar['contextual'] = \IPS\Theme::i()->getTemplate('store')->categorySidebar( $category, $subcategories, $url, \count( $packages ), $this->currency, $havePackagesWhichAcceptReviews, $havePackagesWhichUseStockLevels );
Output::i()->breadcrumb[] = array( $category->url(), $category->_title );
Output::i()->title = $category->_title;
Output::i()->sidebar['contextual'] = Theme::i()->getTemplate('store')->categorySidebar( $category, $subcategories, $url, count( $packages ), $this->currency, $havePackagesWhichAcceptReviews, $havePackagesWhichUseStockLevels );
/* Set default search */
\IPS\Output::i()->defaultSearchOption = array( 'nexus_package_item', "nexus_package_item_el" );
Output::i()->defaultSearchOption = array( 'nexus_package_item', "nexus_package_item_el" );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('store')->category( $category, $subcategories, $packages, $pagination, $packagesWithCustomFields, $totalCount );
\IPS\Output::i()->globalControllers[] = 'nexus.front.store.category';
Output::i()->output = Theme::i()->getTemplate('store')->category( $category, $subcategories, $packages, $pagination, $packagesWithCustomFields, $totalCount );
Output::i()->globalControllers[] = 'nexus.front.store.category';
}
/* JSON-LD
@@ -248,13 +267,14 @@ class _store extends \IPS\Dispatcher\Controller
@link https://developers.google.com/search/docs/guides/intro-structured-data#multiple-entities-on-the-same-page */
foreach( $packages as $package )
{
$item = \IPS\nexus\Package\Item::load( $package->id );
/* @var Package $package */
$item = Item::load( $package->id );
try
{
$price = $package->price();
}
catch( \OutOfBoundsException $e )
catch( OutOfBoundsException )
{
$price = NULL;
}
@@ -262,8 +282,8 @@ class _store extends \IPS\Dispatcher\Controller
/* A product MUST have an offer, so if there's no price (i.e. due to currency configuration) don't even output */
if( $price !== NULL )
{
\IPS\Output::i()->jsonLd['package' . $package->id ] = array(
'@context' => "http://schema.org",
Output::i()->jsonLd['package' . $package->id ] = array(
'@context' => "https://schema.org",
'@type' => "Product",
'name' => $package->_title,
'description' => $item->truncated( TRUE, NULL ),
@@ -276,32 +296,29 @@ class _store extends \IPS\Dispatcher\Controller
'priceCurrency' => $price->currency,
'seller' => array(
'@type' => 'Organization',
'name' => \IPS\Settings::i()->board_name
'name' => Settings::i()->board_name
),
),
);
/* Stock levels */
if( $package->physical )
if( $package->stockLevel() === 0 )
{
if( $package->stockLevel() === 0 )
{
\IPS\Output::i()->jsonLd['package' . $package->id ]['offers']['availability'] = 'http://schema.org/OutOfStock';
}
else
{
\IPS\Output::i()->jsonLd['package' . $package->id ]['offers']['availability'] = 'http://schema.org/InStock';
}
Output::i()->jsonLd['package' . $package->id ]['offers']['availability'] = 'https://schema.org/OutOfStock';
}
else
{
Output::i()->jsonLd['package' . $package->id ]['offers']['availability'] = 'https://schema.org/InStock';
}
if( $package->image )
{
\IPS\Output::i()->jsonLd['package' . $package->id ]['image'] = (string) $package->image;
Output::i()->jsonLd['package' . $package->id ]['image'] = (string) $package->image;
}
if( $package->reviewable and $item->averageReviewRating() )
{
\IPS\Output::i()->jsonLd['package' . $package->id ]['aggregateRating'] = array(
Output::i()->jsonLd['package' . $package->id ]['aggregateRating'] = array(
'@type' => 'AggregateRating',
'ratingValue' => $item->averageReviewRating(),
'ratingCount' => $item->reviews
@@ -316,21 +333,21 @@ class _store extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function priceFilter()
protected function priceFilter() : void
{
if ( !isset( \IPS\Request::i()->maxPrice ) )
if ( !isset( Request::i()->maxPrice ) )
{
\IPS\Request::i()->maxPrice = 0;
Request::i()->maxPrice = 0;
}
$form = new \IPS\Helpers\Form( 'price_filter', 'filter' );
$form->class = 'ipsForm_vertical';
$form->add( new \IPS\Helpers\Form\Number( 'minPrice', FALSE, 0, array( 'decimals' => \IPS\nexus\Money::numberOfDecimalsForCurrency( $this->currency ) ), NULL, NULL, $this->currency ) );
$form->add( new \IPS\Helpers\Form\Number( 'maxPrice', FALSE, 0, array( 'decimals' => \IPS\nexus\Money::numberOfDecimalsForCurrency( $this->currency ), 'unlimited' => 0 ), NULL, NULL, $this->currency ) );
$form = new Form( 'price_filter', 'filter' );
$form->class = 'ipsForm--vertical ipsForm--price-filter';
$form->add( new Number( 'minPrice', FALSE, 0, array( 'decimals' => Money::numberOfDecimalsForCurrency( $this->currency ) ), NULL, NULL, $this->currency ) );
$form->add( new Number( 'maxPrice', FALSE, 0, array( 'decimals' => Money::numberOfDecimalsForCurrency( $this->currency ), 'unlimited' => 0 ), NULL, NULL, $this->currency ) );
if ( $values = $form->values() )
{
$url = \IPS\Request::i()->url()->setQueryString( 'do', NULL );
$url = Request::i()->url()->setQueryString( 'do', NULL );
if ( $values['minPrice'] )
{
$url = $url->setQueryString( 'minPrice', $values['minPrice'] );
@@ -347,11 +364,11 @@ class _store extends \IPS\Dispatcher\Controller
{
$url = $url->setQueryString( 'maxPrice', NULL );
}
\IPS\Output::i()->redirect( $url );
Output::i()->redirect( $url );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('price_filter');
\IPS\Output::i()->output = $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
Output::i()->title = Member::loggedIn()->language()->addToStack('price_filter');
Output::i()->output = $form->customTemplate( array( Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
}
/**
@@ -359,38 +376,38 @@ class _store extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function _indexView()
protected function _indexView() : void
{
/* New Products */
$newProducts = array();
$nexus_store_new = explode( ',', \IPS\Settings::i()->nexus_store_new );
$nexus_store_new = explode( ',', Settings::i()->nexus_store_new );
if ( $nexus_store_new[0] )
{
$newProducts = \IPS\nexus\Package\Item::getItemsWithPermission( array( array( 'p_date_added>?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . $nexus_store_new[1] . 'D' ) )->getTimestamp() ) ), 'p_date_added DESC', $nexus_store_new[0] );
$newProducts = Item::getItemsWithPermission( array( array( 'p_date_added>?', DateTime::create()->sub( new DateInterval( 'P' . $nexus_store_new[1] . 'D' ) )->getTimestamp() ) ), 'p_date_added DESC', $nexus_store_new[0] );
}
/* Popular Products */
$popularProducts = array();
$nexus_store_popular = explode( ',', \IPS\Settings::i()->nexus_store_popular );
$nexus_store_popular = explode( ',', Settings::i()->nexus_store_popular );
if ( $nexus_store_popular[0] )
{
$where = array();
$where[] = array( 'ps_app=? AND ps_type=? AND ps_start>?', 'nexus', 'package', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . $nexus_store_popular[1] . 'D' ) )->getTimestamp() );
$where[] = "( p_member_groups='*' OR " . \IPS\Db::i()->findInSet( 'p_member_groups', \IPS\Member::loggedIn()->groups ) . ' )';
$where[] = array( 'ps_app=? AND ps_type=? AND ps_start>?', 'nexus', 'package', DateTime::create()->sub( new DateInterval( 'P' . $nexus_store_popular[1] . 'D' ) )->getTimestamp() );
$where[] = "( p_member_groups='*' OR " . Db::i()->findInSet( 'p_member_groups', Member::loggedIn()->groups ) . ' )';
$where[] = array( 'p_store=?', 1 );
$popularIds = \IPS\Db::i()->select( 'nexus_purchases.ps_item_id', 'nexus_purchases', $where, 'COUNT(ps_item_id) DESC', $nexus_store_popular[0], 'ps_item_id' )->join( 'nexus_packages', 'ps_item_id=p_id' );
if( \count( $popularIds ) )
$popularIds = Db::i()->select( 'nexus_purchases.ps_item_id', 'nexus_purchases', $where, 'COUNT(ps_item_id) DESC', $nexus_store_popular[0], 'ps_item_id' )->join( 'nexus_packages', 'ps_item_id=p_id' );
if( count( $popularIds ) )
{
$popularProducts = new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( 'nexus_packages.*', 'nexus_packages', array( \IPS\Db::i()->in( 'p_id', iterator_to_array( $popularIds ) ) ), 'FIELD(p_id, ' . implode( ',', iterator_to_array($popularIds) ) . ')' ), 'IPS\nexus\Package' );
$popularProducts = new ActiveRecordIterator( Db::i()->select( 'nexus_packages.*', 'nexus_packages', array( Db::i()->in( 'p_id', iterator_to_array( $popularIds ) ) ), 'FIELD(p_id, ' . implode( ',', iterator_to_array($popularIds) ) . ')' ), 'IPS\nexus\Package' );
}
}
/* Display */
\IPS\Output::i()->sidebar['contextual'] = \IPS\Theme::i()->getTemplate('store')->categorySidebar( );
\IPS\Output::i()->linkTags['canonical'] = (string) \IPS\Http\Url::internal( 'app=nexus&module=store&controller=store', 'front', 'store' );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('store')->index( \IPS\nexus\Customer::loggedIn()->cm_credits[ $this->currency ], $newProducts, $popularProducts );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('module__nexus_store');
Output::i()->sidebar['contextual'] = Theme::i()->getTemplate('store')->categorySidebar( );
Output::i()->linkTags['canonical'] = (string) Url::internal( 'app=nexus&module=store&controller=store', 'front', 'store' );
Output::i()->output = Theme::i()->getTemplate('store')->index( Customer::loggedIn()->cm_credits[ $this->currency ], $newProducts, $popularProducts );
Output::i()->title = Member::loggedIn()->language()->addToStack('module__nexus_store');
}
/**
@@ -398,12 +415,12 @@ class _store extends \IPS\Dispatcher\Controller
*
* @return void
*/
public function register()
public function register() : void
{
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('store')->register( \IPS\nexus\Package\Item::getItemsWithPermission( array( array( 'p_reg=1' ) ), 'pg_position, p_position', 10, 'read', \IPS\Content\Hideable::FILTER_AUTOMATIC, 0, NULL, TRUE ) );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('sign_up');
Output::i()->bodyClasses[] = 'ipsLayout_minimal';
Output::i()->sidebar['enabled'] = FALSE;
Output::i()->output = Theme::i()->getTemplate('store')->register( Item::getItemsWithPermission( array( array( 'p_reg=1' ) ), 'pg_position, p_position', 10, 'read', Filter::FILTER_AUTOMATIC, 0, NULL, TRUE ) );
Output::i()->title = Member::loggedIn()->language()->addToStack('sign_up');
}
/**
@@ -411,8 +428,8 @@ class _store extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function cart()
protected function cart() : void
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('store')->cart();
Output::i()->output = Theme::i()->getTemplate('store')->cart();
}
}
@@ -12,40 +12,65 @@
namespace IPS\nexus\modules\front\subscriptions;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use DateInterval;
use Exception;
use IPS\core\Facebook\Pixel;
use IPS\Dispatcher\Controller;
use IPS\Http\Url;
use IPS\Login;
use IPS\Member;
use IPS\nexus\Customer;
use IPS\nexus\extensions\nexus\Item\Subscription;
use IPS\nexus\Invoice;
use IPS\nexus\Money;
use IPS\nexus\Purchase;
use IPS\nexus\Subscription\Package;
use IPS\nexus\Subscription\Table;
use IPS\nexus\Tax;
use IPS\Output;
use IPS\Request;
use IPS\Session;
use IPS\Settings;
use IPS\Theme;
use OutOfRangeException;
use function defined;
use function in_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;
}
/**
* subscriptions
*/
class _subscriptions extends \IPS\Dispatcher\Controller
class subscriptions extends Controller
{
/**
* Execute
*
* @return void
*/
public function execute()
public function execute() : void
{
/* Work out currency */
if ( isset( \IPS\Request::i()->currency ) and \in_array( \IPS\Request::i()->currency, \IPS\nexus\Money::currencies() ) )
if ( isset( Request::i()->currency ) and in_array( Request::i()->currency, Money::currencies() ) )
{
if ( isset( \IPS\Request::i()->csrfKey ) and \IPS\Login::compareHashes( (string) \IPS\Session::i()->csrfKey, (string) \IPS\Request::i()->csrfKey ) )
if ( isset( Request::i()->csrfKey ) and Login::compareHashes( (string) Session::i()->csrfKey, (string) Request::i()->csrfKey ) )
{
$_SESSION['cart'] = array();
\IPS\Request::i()->setCookie( 'currency', \IPS\Request::i()->currency );
Request::i()->setCookie( 'currency', Request::i()->currency );
$url = \IPS\Http\Url::internal( 'app=nexus&module=subscriptions&controller=subscriptions', 'front', 'nexus_subscriptions' );
$url = Url::internal( 'app=nexus&module=subscriptions&controller=subscriptions', 'front', 'nexus_subscriptions' );
if( isset( \IPS\Request::i()->register ) )
if( isset( Request::i()->register ) )
{
$url = $url->setQueryString( 'register', (int) \IPS\Request::i()->register );
$url = $url->setQueryString( 'register', (int) Request::i()->register );
}
\IPS\Output::i()->redirect( $url );
Output::i()->redirect( $url );
}
}
@@ -57,46 +82,45 @@ class _subscriptions extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function manage()
protected function manage() : void
{
if ( ! \IPS\Settings::i()->nexus_subs_enabled )
if ( ! Settings::i()->nexus_subs_enabled )
{
\IPS\Output::i()->error( 'nexus_no_subs', '2X379/1', 404, '' );
Output::i()->error( 'nexus_no_subs', '2X379/1', 404, '' );
}
/* Send no-cache headers for this page, required for guest sign-ups */
\IPS\Output::setCacheTime( false );
Output::i()->pageCaching = FALSE;
/* Create the table */
$table = new \IPS\nexus\Subscription\Table( \IPS\Http\Url::internal( 'app=nexus&module=subscriptions&controller=subscriptions', 'front', 'nexus_subscriptions' ) );
$current = \IPS\nexus\Subscription::loadByMember( \IPS\Member::loggedIn(), FALSE );
$table = new Table( Url::internal( 'app=nexus&module=subscriptions&controller=subscriptions', 'front', 'nexus_subscriptions' ) );
$current = \IPS\nexus\Subscription::loadByMember( Member::loggedIn(), FALSE );
if ( $current )
{
$table->activeSubscription = $current;
}
if ( isset( \IPS\Request::i()->purchased ) and $table->activeSubscription )
if ( isset( Request::i()->purchased ) and $table->activeSubscription )
{
try
{
$invoice = \IPS\nexus\Invoice::load( $table->activeSubscription->invoice_id );
$invoice = Invoice::load( $table->activeSubscription->invoice_id );
/* Fire the pixel event */
\IPS\core\Facebook\Pixel::i()->Purchase = array( 'value' => $invoice->total->amount, 'currency' => $invoice->total->currency );
\IPS\Output::i()->inlineMessage = \IPS\Member::loggedIn()->language()->addToStack( 'nexus_subs_paid_flash_msg');
Pixel::i()->Purchase = array( 'value' => $invoice->total->amount, 'currency' => $invoice->total->currency );
Output::i()->inlineMessage = Member::loggedIn()->language()->addToStack( 'nexus_subs_paid_flash_msg');
}
catch( \Exception $e ) { }
catch( Exception ) { }
}
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_subscriptions.js', 'nexus', 'front' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'subscriptions.css', 'nexus' ) );
Output::i()->jsFiles = array_merge( Output::i()->jsFiles, Output::i()->js( 'front_subscriptions.js', 'nexus', 'front' ) );
\IPS\Output::i()->breadcrumb['module'] = array( \IPS\Http\Url::internal( 'app=nexus&module=subscriptions&controller=subscriptions', 'front', 'nexus_subscriptions' ), \IPS\Member::loggedIn()->language()->addToStack('nexus_front_subscriptions') );
Output::i()->breadcrumb['module'] = array( Url::internal( 'app=nexus&module=subscriptions&controller=subscriptions', 'front', 'nexus_subscriptions' ), Member::loggedIn()->language()->addToStack('nexus_front_subscriptions') );
\IPS\Output::i()->linkTags['canonical'] = (string) \IPS\Http\Url::internal( 'app=nexus&module=subscriptions&controller=subscriptions', 'front', 'nexus_subscriptions' );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('nexus_front_subscriptions');
\IPS\Output::i()->output = $table;
Output::i()->linkTags['canonical'] = (string) Url::internal( 'app=nexus&module=subscriptions&controller=subscriptions', 'front', 'nexus_subscriptions' );
Output::i()->title = Member::loggedIn()->language()->addToStack('nexus_front_subscriptions');
Output::i()->output = $table;
}
/**
@@ -104,40 +128,40 @@ class _subscriptions extends \IPS\Dispatcher\Controller
*
* @return void just like life, it is meaningless and temporary so live in the moment, enjoy each day and eat chocolate unless you have an allergy in which case don't. See your GP before starting any new diet.
*/
protected function change()
protected function change() : void
{
/* CSRF Check */
\IPS\Session::i()->csrfCheck();
Session::i()->csrfCheck();
try
{
$newPackage = \IPS\nexus\Subscription\Package::load( \IPS\Request::i()->id );
$newPackage = Package::load( Request::i()->id );
}
catch( \OutOfRangeException $e )
catch( OutOfRangeException )
{
\IPS\Output::i()->error( 'nexus_no_subs_package', '2X379/2', 404, '' );
Output::i()->error( 'nexus_no_subs_package', '2X379/2', 404, '' );
}
/* Is the subscription purchasable ? */
if ( !$newPackage->enabled )
{
\IPS\Output::i()->error( 'node_error', '2X379/7', 403, '' );
Output::i()->error( 'node_error', '2X379/7', 403, '' );
}
try
{
$subscription = \IPS\nexus\Subscription::loadByMember( \IPS\Member::loggedIn(), FALSE );
$subscription = \IPS\nexus\Subscription::loadByMember( Member::loggedIn(), FALSE );
}
catch( \OutOfRangeException $e )
catch( OutOfRangeException )
{
\IPS\Output::i()->error( 'nexus_no_subs_subs', '2X379/3', 404, '' );
Output::i()->error( 'nexus_no_subs_subs', '2X379/3', 404, '' );
}
/* Fetch purchase */
$purchase = NULL;
if( $subscription )
{
foreach ( \IPS\nexus\extensions\nexus\Item\Subscription::getPurchases( \IPS\nexus\Customer::loggedIn(), $subscription->package->id, TRUE, TRUE ) as $row )
foreach ( Subscription::getPurchases( Customer::loggedIn(), $subscription->package->id, TRUE, TRUE ) as $row )
{
if ( !$row->cancelled OR ( $row->cancelled AND $row->can_reactivate ) )
{
@@ -149,33 +173,34 @@ class _subscriptions extends \IPS\Dispatcher\Controller
if ( $purchase === NULL )
{
\IPS\Output::i()->error( 'nexus_sub_no_purchase', '2X379/4', 404, '' );
Output::i()->error( 'nexus_sub_no_purchase', '2X379/4', 404, '' );
}
/* @var Purchase $purchase */
/* We cannot process changes if an active Billing Agreement is in place */
if( $purchase->billing_agreement and !$purchase->billing_agreement->canceled )
{
\IPS\Output::i()->error( 'nexus_sub_no_change_ba', '2X379/B', 404, '' );
Output::i()->error( 'nexus_sub_no_change_ba', '2X379/B', 404, '' );
}
/* Right, that's all the "I'll tamper with the URLs for a laugh" stuff out of the way... */
$upgradeCost = $newPackage->costToUpgrade( $subscription->package, \IPS\nexus\Customer::loggedIn() );
$upgradeCost = $newPackage->costToUpgrade( $subscription->package, Customer::loggedIn() );
if ( $upgradeCost === NULL )
{
\IPS\Output::i()->error( 'nexus_no_subs_nocost', '2X379/5', 404, '' );
Output::i()->error( 'nexus_no_subs_nocost', '2X379/5', 404, '' );
}
$invoice = $subscription->package->upgradeDowngrade( $purchase, $newPackage );
if ( $invoice )
{
\IPS\Output::i()->redirect( $invoice->checkoutUrl() );
Output::i()->redirect( $invoice->checkoutUrl() );
}
$purchase->member->log( 'subscription', array( 'type' => 'change', 'id' => $purchase->id, 'old' => $purchase->name, 'name' => $newPackage->titleForLog(), 'system' => FALSE ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=nexus&module=subscriptions&controller=subscriptions', 'front', 'nexus_subscriptions' ) );
Output::i()->redirect( Url::internal( 'app=nexus&module=subscriptions&controller=subscriptions', 'front', 'nexus_subscriptions' ) );
}
/**
@@ -183,37 +208,37 @@ class _subscriptions extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function purchase()
protected function purchase() : void
{
/* CSRF Check */
\IPS\Session::i()->csrfCheck();
Session::i()->csrfCheck();
/* Send no-cache headers for this page, required for guest sign-ups */
\IPS\Output::setCacheTime( false );
Output::i()->pageCaching = FALSE;
/* Already purchased a subscription */
if ( $current = \IPS\nexus\Subscription::loadByMember( \IPS\nexus\Customer::loggedIn(), FALSE ) AND ( $current->purchase AND ( !$current->purchase->cancelled OR $current->purchase->can_reactivate ) ) )
if ( $current = \IPS\nexus\Subscription::loadByMember( Customer::loggedIn(), FALSE ) AND ( $current->purchase AND ( !$current->purchase->cancelled OR $current->purchase->can_reactivate ) ) )
{
\IPS\Output::i()->error( 'nexus_subs_already_got_package', '2X379/6', 403, '' );
Output::i()->error( 'nexus_subs_already_got_package', '2X379/6', 403, '' );
}
$package = \IPS\nexus\Subscription\Package::load( \IPS\Request::i()->id );
$package = Package::load( Request::i()->id );
/* Is the subscription purchasable ? */
if ( !$package->enabled )
{
\IPS\Output::i()->error( 'node_error', '2X379/7', 403, '' );
Output::i()->error( 'node_error', '2X379/7', 403, '' );
}
$price = $package->price();
$item = new \IPS\nexus\extensions\nexus\Item\Subscription( \IPS\nexus\Customer::loggedIn()->language()->get( $package->_titleLanguageKey ), $price );
$item = new Subscription( Customer::loggedIn()->language()->get( $package->_titleLanguageKey ), $price );
$item->id = $package->id;
try
{
$item->tax = \IPS\nexus\Tax::load( $package->tax );
$item->tax = Tax::load( $package->tax );
}
catch ( \OutOfRangeException $e ) { }
catch ( OutOfRangeException ) { }
if ( $package->gateways !== '*' )
{
$item->paymentMethodIds = explode( ',', $package->gateways );
@@ -221,19 +246,19 @@ class _subscriptions extends \IPS\Dispatcher\Controller
$item->renewalTerm = $package->renewalTerm( $price->currency );
if ( $package->price and $costs = json_decode( $package->price, TRUE ) and isset( $costs['cost'] ) )
{
$item->initialInterval = new \DateInterval( 'P' . $costs['term'] . mb_strtoupper( $costs['unit'] ) );
$item->initialInterval = new DateInterval( 'P' . $costs['term'] . mb_strtoupper( $costs['unit'] ) );
}
/* Generate the invoice */
$invoice = new \IPS\nexus\Invoice;
$invoice = new Invoice;
$invoice->currency = $price->currency;
$invoice->member = \IPS\nexus\Customer::loggedIn();
$invoice->member = Customer::loggedIn();
$invoice->addItem( $item );
$invoice->return_uri = "app=nexus&module=subscriptions&controller=subscriptions&purchased=1";
$invoice->save();
/* Take them to it */
\IPS\Output::i()->redirect( $invoice->checkoutUrl() );
Output::i()->redirect( $invoice->checkoutUrl() );
}
/**
@@ -241,30 +266,30 @@ class _subscriptions extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function reactivate()
protected function reactivate() : void
{
/* CSRF Check */
\IPS\Session::i()->csrfCheck();
Session::i()->csrfCheck();
/* Get subscription and purchase */
try
{
$package = \IPS\nexus\Subscription\Package::load( \IPS\Request::i()->id );
$package = Package::load( Request::i()->id );
}
catch( \OutOfRangeException $e )
catch( OutOfRangeException )
{
\IPS\Output::i()->error( 'nexus_no_subs_package', '2X379/2', 404, '' );
Output::i()->error( 'nexus_no_subs_package', '2X379/2', 404, '' );
}
try
{
$subscription = \IPS\nexus\Subscription::loadByMemberAndPackage( \IPS\Member::loggedIn(), $package, FALSE );
$subscription = \IPS\nexus\Subscription::loadByMemberAndPackage( Member::loggedIn(), $package, FALSE );
}
catch( \OutOfRangeException $e )
catch( OutOfRangeException )
{
\IPS\Output::i()->error( 'nexus_no_subs_subs', '2X379/8', 404, '' );
Output::i()->error( 'nexus_no_subs_subs', '2X379/8', 404, '' );
}
$purchase = NULL;
foreach ( \IPS\nexus\extensions\nexus\Item\Subscription::getPurchases( \IPS\nexus\Customer::loggedIn(), $subscription->package->id, TRUE, TRUE ) as $row )
foreach ( Subscription::getPurchases( Customer::loggedIn(), $subscription->package->id, TRUE, TRUE ) as $row )
{
if ( $row->can_reactivate )
{
@@ -274,15 +299,16 @@ class _subscriptions extends \IPS\Dispatcher\Controller
}
if ( $purchase === NULL )
{
\IPS\Output::i()->error( 'nexus_sub_no_purchase', '2X379/9', 404, '' );
Output::i()->error( 'nexus_sub_no_purchase', '2X379/9', 404, '' );
}
/* @var Purchase $purchase */
/* Set renewal terms */
try
{
$currency = $purchase->original_invoice->currency;
}
catch ( \Exception $e )
catch ( Exception )
{
$currency = $purchase->member->defaultCurrency();
}
@@ -296,11 +322,11 @@ class _subscriptions extends \IPS\Dispatcher\Controller
if ( !$purchase->active and $cycles = $purchase->canRenewUntil( NULL, TRUE ) AND $cycles !== FALSE )
{
$url = $cycles === 1 ? $purchase->url()->setQueryString( 'do', 'renew' )->csrf() : $purchase->url()->setQueryString( 'do', 'renew' );
\IPS\Output::i()->redirect( $url );
Output::i()->redirect( $url );
}
else
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=nexus&module=subscriptions&controller=subscriptions', 'front', 'nexus_subscriptions' ) );
Output::i()->redirect( Url::internal( 'app=nexus&module=subscriptions&controller=subscriptions', 'front', 'nexus_subscriptions' ) );
}
}
}
@@ -1,63 +0,0 @@
<?php
/**
* @brief Handle actions from emails
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @subpackage Nexus
* @since 17 Nov 2020
*/
namespace IPS\nexus\modules\front\support;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Handle actions from emails
*/
class _email extends \IPS\Dispatcher\Controller
{
/**
* Send or discard reply
*
* @return void
*/
public function sendDiscard()
{
try
{
$reply = \IPS\nexus\Support\Reply::load( \IPS\Request::i()->id );
if ( !\IPS\Login::compareHashes( md5( $reply->item()->email_key . $reply->date ), (string) \IPS\Request::i()->key ) )
{
throw new \OutOfRangeException;
}
}
catch ( \OutOfRangeException $e )
{
\IPS\Output::i()->error( 'node_error', '2X206/1', 404, '' );
}
if ( $reply->type !== \IPS\nexus\Support\Reply::REPLY_PENDING )
{
\IPS\Output::i()->error( 'support_reply_not_pending', '1X206/2', 403, '' );
}
if ( \IPS\Request::i()->send )
{
$reply->sendPending();
}
else
{
$reply->delete();
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( \IPS\Request::i()->send ? 'support_pending_sent' : 'support_pending_discarded' );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'support', 'nexus', 'front' )->pendingDone( \IPS\Request::i()->send ? 'support_pending_sent' : 'support_pending_discarded' );
}
}
@@ -1,90 +0,0 @@
<?php
/**
* @brief Support Index
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @subpackage Nexus
* @since 08 Apr 2014
*/
namespace IPS\nexus\modules\front\support;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Support Index
*/
class _home extends \IPS\Dispatcher\Controller
{
/**
* Execute
*
* @return void
*/
public function execute()
{
if ( !\IPS\Member::loggedIn()->member_id )
{
\IPS\Output::i()->error( 'no_module_permission_guest', '2X265/1', 403, '' );
}
parent::execute();
}
/**
* Index
*
* @return void
*/
protected function manage()
{
$table = new \IPS\Helpers\Table\Content( 'IPS\nexus\Support\Request', \IPS\Http\Url::internal( 'app=nexus&module=support&controller=home', 'front', 'support' ) );
$table->rowsTemplate = array( \IPS\Theme::i()->getTemplate( 'support' ), 'tableRows' );
$table->classes[] = 'ipsDataList_large';
$table->showFilters = FALSE;
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('support');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('support')->requestList( (string) $table );
}
/**
* Create
*
* @return void
*/
protected function create()
{
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('new_request');
\IPS\Output::i()->breadcrumb[] = array( NULL, \IPS\Member::loggedIn()->language()->addToStack( 'new_request' ) );
$accounts = \IPS\nexus\Customer::loggedIn()->parentContacts( array( 'support=1' ) );
if ( \count( $accounts ) and !isset( \IPS\Request::i()->account ) )
{
$options = array();
$options[ \IPS\nexus\Customer::loggedIn()->member_id ] = \IPS\nexus\Customer::loggedIn()->language()->addToStack( 'my_account', FALSE, array( 'sprintf' => array( \IPS\nexus\Customer::loggedIn()->cm_name ) ) );
foreach ( $accounts as $contact )
{
$options[ $contact->main_id->member_id ] = $contact->main_id->cm_name;
}
$form = new \IPS\Helpers\Form( 'account', 'continue' );
$form->class = 'ipsForm_vertical';
$form->add( new \IPS\Helpers\Form\Radio( 'support_account', \IPS\nexus\Customer::loggedIn()->member_id, TRUE, array( 'options' => $options, 'parse' => 'normal' ) ) );
if ( $values = $form->values() )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=nexus&module=support&controller=home&do=create&account={$values['support_account']}", 'front', 'support_create' ) );
}
\IPS\Output::i()->output = $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
}
else
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('support')->create( \IPS\nexus\Support\Request::create() );
}
}
}
Whitespace-only changes.
@@ -1,41 +0,0 @@
<?php
/**
* @brief Legacy Redirector
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @subpackage Commerce
* @since 07 Sep 2016
*/
namespace IPS\nexus\modules\front\support;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Legacy Redirector
*/
class _redirect extends \IPS\Dispatcher\Controller
{
/**
* Redirect
*
* @return void
*/
protected function manage()
{
$url = \IPS\Http\Url::internal( "app=core&module=system&controller=redirect" )->setQueryString( array(
'url' => \IPS\Request::i()->url,
'resource' => ( \IPS\Request::i()->resource ) ? 1 : NULL,
'key' => hash_hmac( "sha256", \IPS\Request::i()->url, \IPS\Settings::i()->site_secret_key . 'r' ),
) );
\IPS\Output::i()->redirect( $url );
}
}
@@ -1,182 +0,0 @@
<?php
/**
* @brief Support Request View
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @subpackage Nexus
* @since 09 Apr 2014
*/
namespace IPS\nexus\modules\front\support;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Support Request View
*/
class _view extends \IPS\Content\Controller
{
/**
* [Content\Controller] Class
*/
protected static $contentModel = 'IPS\nexus\Support\Request';
/**
* Execute
*
* @return void
*/
public function execute()
{
if ( !\IPS\Member::loggedIn()->member_id )
{
\IPS\Output::i()->error( 'no_module_permission_guest', '2X264/1', 403, '' );
}
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_support.js', 'nexus', 'front' ) );
parent::execute();
}
/**
* @brief The current support request (instance of \IPS\nexus\Support\Request)
*/
protected $request;
/**
* View Item
*
* @return void
*/
protected function manage()
{
$this->request = parent::manage();
if ( !$this->request )
{
\IPS\Output::i()->error( 'node_error', '2X204/1', 404, '' );
}
$allowedStatuses = \IPS\nexus\Support\Status::publicSetStatuses( $this->request );
if ( isset( \IPS\Request::i()->setStatus ) and !empty( $allowedStatuses ) and \in_array( \IPS\Request::i()->setStatus, array_keys( $allowedStatuses ) ) )
{
\IPS\Session::i()->csrfCheck();
$newStatus = \IPS\nexus\Support\Status::load( \IPS\Request::i()->setStatus );
$this->request->log( 'status', $this->request->status, $newStatus );
$this->request->status = $newStatus;
$this->request->save();
\IPS\Output::i()->redirect( $this->request->url() );
}
if ( !isset( \IPS\Request::i()->root ) and $purchase = $this->request->purchase and $purchase->childrenCount( NULL ) )
{
\IPS\Request::i()->root = $purchase->id;
\IPS\Request::i()->noshowroot = TRUE;
}
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'support' )->request( $this->request );
}
/**
* Rate Staff Response
*
* @return void
*/
protected function rate()
{
try
{
$reply = \IPS\nexus\Support\Reply::loadAndCheckPerms( \IPS\Request::i()->response );
}
catch ( \OutOfRangeException $e )
{
\IPS\Output::i()->error( 'node_error', '2X209/1', 404, '' );
}
/* If we've rated, do not allow us to rate again */
try
{
\IPS\Db::i()->select( '*', 'nexus_support_ratings', array( 'rating_reply=?', $reply->id ) )->first();
\IPS\Output::i()->error( 'already_rated', '2X204/2', 403, '' );
}
catch ( \UnderflowException $e ) {}
$form = new \IPS\Helpers\Form( 'feedback', 'send_feedback' );
$form->class = 'ipsForm_vertical';
$form->add( new \IPS\Helpers\Form\Rating( 'support_rating_rating', \IPS\Request::i()->rating, TRUE ) );
$form->add( new \IPS\Helpers\Form\TextArea( 'support_rating_feedback', NULL, FALSE ) );
if ( $values = $form->values() )
{
$save = array(
'rating_reply' => $reply->id,
'rating_rating' => $values['support_rating_rating'],
'rating_from' => \IPS\Member::loggedIn()->member_id,
'rating_staff' => $reply->member,
'rating_note' => $values['support_rating_feedback'],
'rating_date' => time()
);
\IPS\Db::i()->insert( 'nexus_support_ratings', $save );
if ( \IPS\Request::i()->isAjax() )
{
$reply->ratingData = $save;
\IPS\Output::i()->json( \IPS\Theme::i()->getTemplate('support')->ratingValue( $reply ) );
}
else
{
\IPS\Output::i()->redirect( $reply->url(), 'thanks_for_your_feedback' );
}
}
\IPS\Output::i()->output = $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
}
/**
* Change Severity
*
* @return void
*/
protected function severity()
{
try
{
$request = \IPS\nexus\Support\Request::loadAndCheckPerms( \IPS\Request::i()->id );
}
catch ( \OutOfRangeException $e )
{
\IPS\Output::i()->error( 'node_error', '2X209/1', 404, '' );
}
if ( !\IPS\Settings::i()->nexus_severities or \IPS\Member::loggedIn()->cm_no_sev )
{
\IPS\Output::i()->error( 'node_error', '2X209/3', 404, '' );
}
$options = array();
foreach ( \IPS\nexus\Support\Severity::roots( NULL, NULL, array( array( 'sev_public=1' ), array( "sev_departments='*' OR " . \IPS\Db::i()->findInSet( 'sev_departments', array( $request->department->id ) ) ) ) ) as $severity )
{
$options[ $severity->id ] = $severity->_title;
}
$form = new \IPS\Helpers\Form;
$form->class = 'ipsForm_vertical';
$form->add( new \IPS\Helpers\Form\Radio( 'support_severity', $request->severity->id, FALSE, array(
'options' => $options
) ) );
if ( $values = $form->values() )
{
$request->severity = \IPS\nexus\Support\Severity::load( $values['support_severity'] );
$request->save();
\IPS\Output::i()->redirect( $request->url() );
}
\IPS\Output::i()->output = $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
}
}