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

+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();
}
}