Version 4.3.0

This commit is contained in:
Neo committed 2025-12-19 05:47:12 -08:00
1 parent 96997ddd8e
commit fe1acf984a
1349 files changed
+116159 -67711

No files matched your search

@@ -108,7 +108,10 @@ class _purchases extends \IPS\Dispatcher\Controller
{
try
{
$customFields[ $k ] = \IPS\nexus\Package\CustomField::load( $k )->displayValue( $v, TRUE );
if ( $displayValue = trim( \IPS\nexus\Package\CustomField::load( $k )->displayValue( $v, TRUE ) ) )
{
$customFields[ $k ] = $displayValue;
}
}
catch ( \OutOfRangeException $e ) { }
}
@@ -218,7 +221,14 @@ class _purchases extends \IPS\Dispatcher\Controller
{
/* Transfer */
$previousOwner = $this->purchase->member;
$this->purchase->transfer( $values['ps_member'] );
try
{
$this->purchase->transfer( $values['ps_member'] );
}
catch ( \DomainException $e )
{
\IPS\Output::i()->error( $e->getMessage(), '2X195/8', 403 );
}
/* Log */
$previousOwner->log( 'purchase', array( 'type' => 'transfer_from', 'id' => $this->purchase->id, 'name' => $this->purchase->name, 'to' => $values['ps_member']->member_id ) );
@@ -119,7 +119,7 @@ class _search extends \IPS\Dispatcher\Controller
'view' => array(
'icon' => 'search',
'title' => 'view',
'link' => \IPS\Http\Url::internal("app=nexus&module=customers&controller=view&id={$row['member_id']}"),
'link' => \IPS\Http\Url::internal("app=core&module=members&controller=members&do=view&tab=nexus_Main&id={$row['member_id']}"),
),
);
};
@@ -40,6 +40,10 @@ class _view extends \IPS\Dispatcher\Controller
try
{
$this->member = \IPS\nexus\Customer::load( \IPS\Request::i()->id );
if ( !$this->member->member_id )
{
throw new \OutOfRangeException;
}
}
catch ( \OutOfRangeException $e )
{
@@ -64,653 +68,59 @@ class _view extends \IPS\Dispatcher\Controller
* View Customer
*
* @return void
* @deprecated
*/
protected function manage()
{
$member = $this->member;
/* Notes */
$notes = NULL;
$noteCount = 0;
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'nexus', 'customers', 'customer_notes_view' ) )
{
$noteCount = \IPS\Db::i()->select( 'COUNT(*)', 'nexus_notes', array( 'note_member=?', $this->member->member_id ) )->first();
$notes = new \IPS\Helpers\Table\Db( 'nexus_notes', $this->member->acpUrl()->setQueryString( array( 'view' => 'notes', 'support' => isset( \IPS\Request::i()->support ) ? \IPS\Request::i()->support : 0 ) ), array( 'note_member=?', $this->member->member_id ) );
$notes->tableTemplate = array( \IPS\Theme::i()->getTemplate('customers'), 'notes' );
$notes->sortBy = 'note_date';
$notes->parsers = array(
'note_member' => function( $val )
{
return \IPS\Member::load( $val );
},
'note_text' => function( $val )
{
return $val;
}
);
$notes->rowButtons = function( $row ) use ( $member )
{
$return = array();
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'nexus', 'customers', 'customer_notes_edit' ) )
{
if ( !isset( \IPS\Request::i()->support ) or !\IPS\Request::i()->support )
{
$return['edit'] = array(
'link' => $member->acpUrl()->setQueryString( array( 'do' => 'noteForm', 'note_id' => $row['note_id'], 'support' => isset( \IPS\Request::i()->support ) ? \IPS\Request::i()->support : 0 ) ),
'title' => 'edit',
'icon' => 'pencil',
'data' => array( 'ipsDialog' => true, 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('edit_note') )
);
}
else
{
$return['edit'] = array(
'link' => $member->acpUrl()->setQueryString( array( 'do' => 'noteForm', 'note_id' => $row['note_id'], 'support' => isset( \IPS\Request::i()->support ) ? \IPS\Request::i()->support : 0 ) ),
'title' => 'edit',
'icon' => 'pencil',
);
}
}
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'nexus', 'customers', 'customer_notes_delete' ) )
{
$return['delete'] = array(
'link' => $member->acpUrl()->setQueryString( array( 'do' => 'deleteNote', 'note_id' => $row['note_id'], 'support' => isset( \IPS\Request::i()->support ) ? \IPS\Request::i()->support : 0 ) ),
'title' => 'delete',
'icon' => 'times-circle',
'data' => array( 'delete' => '' )
);
}
return $return;
};
if ( ( !isset( \IPS\Request::i()->support ) or !\IPS\Request::i()->support ) and \IPS\Member::loggedIn()->hasAcpRestriction( 'nexus', 'customers', 'customer_notes_add' ) )
{
$notes->rootButtons = array(
'add' => array(
'link' => $this->member->acpUrl()->setQueryString( array( 'do' => 'noteForm', 'support' => isset( \IPS\Request::i()->support ) ? \IPS\Request::i()->support : 0 ) ),
'title' => 'add',
'icon' => 'plus',
'data' => array( 'ipsDialog' => true, 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('add_note') )
)
);
}
if ( \IPS\Request::i()->view === 'notes' )
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('customers')->customerPopup( $notes );
return;
}
else
{
$notes->limit = 2;
$notes->tableTemplate = array( \IPS\Theme::i()->getTemplate('customers'), 'notesOverview' );
$notes->rowsTemplate = array( \IPS\Theme::i()->getTemplate('customers'), 'notesOverviewRows' );
}
}
/* Purchases */
$purchaseCount = \IPS\Db::i()->select( 'COUNT(*)', 'nexus_purchases', array( 'ps_member=? AND ps_show=1', $this->member->member_id ) )->first();
$purchaseRootCount = \IPS\Db::i()->select( 'COUNT(*)', 'nexus_purchases', array( 'ps_member=? AND ps_show=1 AND ps_parent=0', $this->member->member_id ) )->first();
$purchases = \IPS\nexus\Purchase::tree( $this->member->acpUrl()->setQueryString( 'tab', 'purchases' ), array( array( 'ps_member=?', $this->member->member_id ) ) );
$purchases->rootsPerPage = 15;
$purchases->getTotalRoots = function()
{
return NULL;
};
if ( \IPS\Request::i()->isAjax() and \IPS\Request::i()->tab === 'purchases' )
{
\IPS\Output::i()->output = $purchases;
return;
}
/* Invoices */
$invoiceCount = \IPS\Db::i()->select( 'COUNT(*)', 'nexus_invoices', array( 'i_member=?', $this->member->member_id ) )->first();
$invoices = \IPS\nexus\Invoice::table( array( 'i_member=?', $this->member->member_id ), $this->member->acpUrl()->setQueryString( 'tab', 'invoices' ), 'c' );
$invoices->limit = 15;
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'nexus', 'payments', 'invoices_add' ) )
{
$invoices->rootButtons = array(
'add' => array(
'link' => \IPS\Http\Url::internal( "app=nexus&module=payments&controller=invoices&do=generate&member={$this->member->member_id}" ),
'title' => 'add',
'icon' => 'plus',
)
);
}
$invoices->tableTemplate = array( \IPS\Theme::i()->getTemplate('customers'), 'invoicesTable' );
$invoices->rowsTemplate = array( \IPS\Theme::i()->getTemplate('customers'), 'invoicesTableRows' );
/*if ( \IPS\Request::i()->isAjax() and \IPS\Request::i()->tab === 'invoices' )
{
\IPS\Output::i()->output = $invoices;
return;
}*/
/* Addresses */
if ( \IPS\Request::i()->view === 'addresses' )
{
$addresses = new \IPS\Helpers\Table\Db( 'nexus_customer_addresses', $this->member->acpUrl()->setQueryString( 'view', 'addresses' ), array( 'member=?', $this->member->member_id ) );
$addresses->sortBy = 'primary_billing, primary_shipping, added';
$addresses->include = array( 'address', 'primary_billing', 'primary_shipping' );
$addresses->parsers = array( 'address' => function( $val )
{
return \IPS\GeoLocation::buildFromJson( $val )->toString( '<br>' );
} );
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'nexus', 'customers', 'customers_edit_details' ) )
{
$addresses->rootButtons = array(
'add' => array(
'link' => $this->member->acpUrl()->setQueryString( 'do', 'addressForm' ),
'title' => 'add',
'icon' => 'plus',
'data' => array( 'ipsDialog' => true, 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('add_address') )
)
);
$addresses->rowButtons = function( $row ) use ( $member )
{
return array(
'edit' => array(
'link' => $member->acpUrl()->setQueryString( array( 'do' => 'addressForm', 'address_id' => $row['id'] ) ),
'title' => 'edit',
'icon' => 'pencil',
'data' => array( 'ipsDialog' => true, 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('edit_address') )
),
'delete' => array(
'link' => $member->acpUrl()->setQueryString( array( 'do' => 'deleteAddress', 'address_id' => $row['id'] ) ),
'title' => 'delete',
'icon' => 'times-circle',
'data' => array( 'delete' => '' )
)
);
};
}
$addresses->tableTemplate = array( \IPS\Theme::i()->getTemplate('customers'), 'addressTable' );
$addresses->rowsTemplate = array( \IPS\Theme::i()->getTemplate('customers'), 'addressTableRows' );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('customers')->customerPopup( $addresses );
return;
}
else
{
$primaryBillingAddress = NULL;
try
{
$primaryBillingAddress = \IPS\nexus\Customer\Address::constructFromData( \IPS\Db::i()->select( '*', 'nexus_customer_addresses', array( 'member=? AND primary_billing=1', $this->member->member_id ) )->first() )->address;
}
catch ( \UnderflowException $e ) { }
}
$addressCount = \IPS\Db::i()->select( 'COUNT(*)', 'nexus_customer_addresses', array( 'member=?', $this->member->member_id ) )->first();
/* Credit Cards */
$cards = '';
$cardCount = 0;
if ( count( \IPS\nexus\Gateway::cardStorageGateways() ) and \IPS\Member::loggedIn()->hasAcpRestriction( 'nexus', 'customers', 'customers_edit_cards' ) )
{
$cardCount = \IPS\Db::i()->select( 'COUNT(*)', 'nexus_customer_cards', array( 'card_member=?', $this->member->member_id ) )->first();
$cards = array();
foreach ( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'nexus_customer_cards', array( 'card_member=?', $this->member->member_id ), NULL, \IPS\Request::i()->view === 'cards' ? NULL : 2 ), 'IPS\nexus\Customer\CreditCard' ) as $card )
{
try
{
$cardData = $card->card;
$cards[ $card->id ] = array(
'id' => $card->id,
'card_type' => $cardData->type,
'card_member' => $card->member->member_id,
'card_number' => $cardData->lastFour,
'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 ) { }
}
$cards = new \IPS\Helpers\Table\Custom( $cards, $this->member->acpUrl()->setQueryString( 'view', 'cards' ) );
$cards->rootButtons = array(
'add' => array(
'link' => $this->member->acpUrl()->setQueryString( 'do', 'addCard' ),
'title' => 'add',
'icon' => 'plus',
'data' => array( 'ipsDialog' => true, 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('add_card') )
)
);
$cards->rowButtons = function( $row ) use ( $member )
{
return array(
'delete' => array(
'link' => $member->acpUrl()->setQueryString( array( 'do' => 'deleteCard', 'card_id' => $row['id'] ) ),
'title' => 'delete',
'icon' => 'times-circle',
'data' => array( 'delete' => '' )
)
);
};
if ( \IPS\Request::i()->view === 'cards' )
{
$cards->tableTemplate = array( \IPS\Theme::i()->getTemplate('customers'), 'cardsTable' );
$cards->rowsTemplate = array( \IPS\Theme::i()->getTemplate('customers'), 'cardsTableRows' );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('customers')->customerPopup( $cards );
return;
}
else
{
$cards->tableTemplate = array( \IPS\Theme::i()->getTemplate('customers'), 'cardsOverview' );
$cards->rowsTemplate = array( \IPS\Theme::i()->getTemplate('customers'), 'cardsOverviewRows' );
}
}
/* Billing Agreements */
$billingAgreements = '';
$billingAgreementCount = 0;
if ( count( \IPS\nexus\Gateway::billingAgreementGateways() ) and \IPS\Member::loggedIn()->hasAcpRestriction( 'nexus', 'payments', 'billingagreements_view' ) )
{
$billingAgreementCount = \IPS\Db::i()->select( 'COUNT(*)', 'nexus_billing_agreements', array( 'ba_member=? AND ba_canceled=0', $this->member->member_id ) )->first();
$billingAgreements = array();
foreach ( \IPS\Db::i()->select( '*', 'nexus_billing_agreements', array( 'ba_member=? AND ba_canceled=0', $this->member->member_id ), NULL, \IPS\Request::i()->view === 'billingagreements' ? NULL : 2 ) as $billingAgreement )
{
$billingAgreements[ $billingAgreement['ba_id'] ] = array(
'id' => $billingAgreement['ba_id'],
'gw_id' => $billingAgreement['ba_gw_id'],
'started' => $billingAgreement['ba_started'],
'next_cycle' => $billingAgreement['ba_next_cycle'],
);
}
$billingAgreements = new \IPS\Helpers\Table\Custom( $billingAgreements, $this->member->acpUrl()->setQueryString( 'view', 'billingagreements' ) );
$billingAgreements->parsers = array(
'started' => function( $val ) {
return $val ? \IPS\DateTime::ts( $val )->relative() : null;
},
'next_cycle' => function( $val ) {
return $val ? \IPS\DateTime::ts( $val )->relative() : null;
},
);
$billingAgreements->rowButtons = function( $row, $id )
{
return array(
'view' => array(
'link' => \IPS\Http\Url::internal("app=nexus&module=payments&controller=billingagreements&id={$id}"),
'title' => 'view',
'icon' => 'search',
)
);
};
if ( \IPS\Request::i()->view === 'billingagreements' )
{
$billingAgreements->exclude = array( 'id', 'last_transaction_currency' );
$billingAgreements->langPrefix = 'ba_';
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('customers')->customerPopup( $billingAgreements );
return;
}
else
{
$billingAgreements->tableTemplate = array( \IPS\Theme::i()->getTemplate('customers'), 'billingAgreementsOverview' );
$billingAgreements->rowsTemplate = array( \IPS\Theme::i()->getTemplate('customers'), 'billingAgreementsOverviewRows' );
}
}
/* Alternative Contacts */
$altContactCount = \IPS\Db::i()->select( 'COUNT(*)', 'nexus_alternate_contacts', array( 'main_id=?', $this->member->member_id ) )->first();
$alternativeContacts = new \IPS\Helpers\Table\Db( 'nexus_alternate_contacts', $this->member->acpUrl()->setQueryString( 'view', 'alternatives' ), array( 'main_id=?', $this->member->member_id ) );
$alternativeContacts->langPrefix = 'altcontactTable_';
$alternativeContacts->include = array( 'alt_id', 'purchases', 'billing', 'support' );
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'nexus', 'customers', 'customers_edit_details' ) )
{
$alternativeContacts->parsers = array(
'alt_id' => function( $val )
{
return "<a href='" . \IPS\nexus\Customer::load( $val )->acpUrl() . "'>" . \IPS\nexus\Customer::load( $val )->name . "</a>";
},
'email' => function ( $val, $row )
{
return \IPS\nexus\Customer::load( $row['alt_id'] )->email;
},
'purchases' => function( $val )
{
return implode( '<br>', array_map( function( $id )
{
try
{
return \IPS\Theme::i()->getTemplate('purchases')->link( \IPS\nexus\Purchase::load( $id ) );
}
catch ( \OutOfRangeException $e )
{
return '';
}
}, explode( ',', $val ) ) );
},
'billing' => function( $val )
{
return $val ? "<i class='fa fa-check'></i>" : "<i class='fa fa-times'></i>";
},
'support' => function( $val )
{
return $val ? "<i class='fa fa-check'></i>" : "<i class='fa fa-times'></i>";
}
);
$alternativeContacts->rootButtons = array(
'add' => array(
'link' => $this->member->acpUrl()->setQueryString( 'do', 'alternativeContactForm' ),
'title' => 'add',
'icon' => 'plus',
'data' => array( 'ipsDialog' => true, 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('altcontact_add') )
)
);
$alternativeContacts->rowButtons = function( $row ) use ( $member )
{
return array(
'view' => array(
'link' => $member->acpUrl(),
'title' => 'view',
'icon' => 'search'
),
'edit' => array(
'link' => $member->acpUrl()->setQueryString( array( 'do' => 'alternativeContactForm', 'alt_id' => $row['alt_id'] ) ),
'title' => 'edit',
'icon' => 'pencil',
'data' => array( 'ipsDialog' => true )
),
'delete' => array(
'link' => $member->acpUrl()->setQueryString( array( 'do' => 'deleteAlternativeContact', 'alt_id' => $row['alt_id'] ) ),
'title' => 'delete',
'icon' => 'times-circle',
'data' => array( 'delete' => '' )
)
);
};
}
if ( \IPS\Request::i()->view === 'alternatives' )
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('customers')->customerPopup( $alternativeContacts );
return;
}
else
{
$alternativeContacts->include[] = 'email';
$alternativeContacts->limit = 2;
$alternativeContacts->tableTemplate = array( \IPS\Theme::i()->getTemplate('customers'), 'altContactsOverview' );
$alternativeContacts->rowsTemplate = array( \IPS\Theme::i()->getTemplate('customers'), 'altContactsOverviewRows' );
}
/* Parent Alternative Contacts */
$parents = array();
foreach ( \IPS\Db::i()->select( 'main_id', 'nexus_alternate_contacts', array( 'alt_id=?', $this->member->member_id ) ) as $row )
{
$parents[] = \IPS\nexus\Customer::load( $row );
}
/* Referrals */
try
{
$referredBy = \IPS\nexus\Customer::load( \IPS\Db::i()->select( 'referred_by', 'nexus_referrals', array( 'member_id=?', $this->member->member_id ) )->first() );
}
catch ( \UnderflowException $e )
{
$referredBy = NULL;
}
$referCount = \IPS\Db::i()->select( 'COUNT(*)', 'nexus_referrals', array( 'referred_by=?', $this->member->member_id ) )->first();
$referrals = new \IPS\Helpers\Table\Db( 'nexus_referrals', $this->member->acpUrl()->setQueryString( 'view', 'referrals' ), array( 'referred_by=?', $this->member->member_id ) );
$referrals->langPrefix = 'ref_';
$referrals->include = array( 'member_id', 'amount' );
$referrals->sortBy = $referrals->sortBy ?: 'member_id';
$referrals->parsers = array(
'member_id' => function( $v )
{
try
{
return \IPS\nexus\Customer::load( $v )->link();
}
catch ( \OutOfRangeException $e )
{
return \IPS\Member::loggedIn()->language()->addToStack('deleted_member');
}
},
'email' => function( $v, $row )
{
try
{
return \IPS\nexus\Customer::load( $row['member_id'] )->email;
}
catch ( \OutOfRangeException $e )
{
return \IPS\Member::loggedIn()->language()->addToStack('deleted_member');
}
},
'amount' => function( $v ) use ( $member )
{
$return = array();
if ( $v )
{
foreach ( json_decode( $v, TRUE ) as $currency => $amount )
{
$return[] = new \IPS\nexus\Money( $amount, $currency );
}
}
else
{
$return[] = new \IPS\nexus\Money( 0, $member->defaultCurrency() );
}
return implode( '<br>', $return );
}
);
if ( \IPS\Request::i()->isAjax() and \IPS\Request::i()->view === 'referrals' )
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('customers')->customerPopup( $referrals );
return;
}
else
{
$referrals->include[] = 'email';
$referrals->limit = 2;
$referrals->tableTemplate = array( \IPS\Theme::i()->getTemplate('customers'), 'referralsOverview' );
$referrals->rowsTemplate = array( \IPS\Theme::i()->getTemplate('customers'), 'referralsOverviewRows' );
}
/* Sparkline */
$rows = array();
$oneYearAgo = \IPS\DateTime::create()->sub( new \DateInterval('P1Y') );
$date = clone $oneYearAgo;
$endOfLastMonth = mktime( 23, 59, 59, date('n') - 1, date('t'), date('Y') );
while ( $date->getTimestamp() < $endOfLastMonth )
{
foreach ( \IPS\nexus\Money::currencies() as $currency )
{
$rows[ $date->format( 'n Y' ) ][ $currency ] = 0;
}
$date->add( new \DateInterval( 'P1M' ) );
}
$sparkline = new \IPS\Helpers\Chart;
foreach( \IPS\Db::i()->select( 'DATE_FORMAT( FROM_UNIXTIME(t_date), \'%c %Y\' ) AS time, SUM(t_amount)-SUM(t_partial_refund) AS amount, t_currency', 'nexus_transactions', array( array( "t_member=? AND ( t_status=? OR t_status=? ) AND t_date>? AND t_date<?", $this->member->member_id, \IPS\nexus\Transaction::STATUS_PAID, \IPS\nexus\Transaction::STATUS_PART_REFUNDED, $oneYearAgo->getTimestamp(), time() ) ), NULL, NULL, array( 'time', 't_currency' ) ) as $row )
{
if ( isset( $rows[ $row['time'] ][ $row['t_currency'] ] ) ) // Currency may no longer exist
{
$rows[ $row['time'] ][ $row['t_currency'] ] += $row['amount'];
}
}
$sparkline->addHeader( \IPS\Member::loggedIn()->language()->addToStack('date'), 'date' );
foreach ( \IPS\nexus\Money::currencies() as $currency )
{
$sparkline->addHeader( $currency, 'number' );
}
foreach ( $rows as $time => $row )
{
$datetime = new \IPS\DateTime;
$datetime->setTime( 0, 0, 0 );
$exploded = explode( ' ', $time );
$datetime->setDate( $exploded[1], $exploded[0], 1 );
foreach( $row as $currency => $value )
{
$row[ $currency ] = number_format( $value, 2, '.', '' );
}
$sparkline->addRow( array_merge( array( $datetime ), $row ) );
}
$sparkline = $sparkline->render( 'AreaChart', array(
'areaOpacity' => 0.4,
'backgroundColor' => '#fff',
'colors' => array( '#10967e' ),
'chartArea' => array(
'left' => 0,
'top' => 0,
'width' => '100%',
'height' => '100%',
),
'hAxis' => array(
'baselineColor' => '#F3F3F3',
'gridlines' => array(
'count' => 0,
)
),
'height' => 60,
'legend' => array(
'position' => 'none',
),
'lineWidth' => 1,
'vAxis' => array(
'baselineColor' => '#F3F3F3',
'gridlines' => array(
'count' => 0,
)
),
) );
/* Support Requests */
$customerStream = \IPS\nexus\Support\Stream::customer( $this->member );
$supportCount = $customerStream->count( \IPS\Member::loggedIn() );
$results = $customerStream->results( \IPS\Member::loggedIn(), 'r_started DESC', 1, 15 );
$supportRequestsInView = array_keys( iterator_to_array( $results ) );
$tracked = iterator_to_array( \IPS\Db::i()->select( array( 'request_id', 'notify' ), 'nexus_support_tracker', array( array( 'member_id=?', \IPS\Member::loggedIn()->member_id ), array( \IPS\Db::i()->in( 'request_id', $supportRequestsInView ) ) ) )->setKeyField( 'request_id' )->setValueField( 'notify' ) );
$participatedIn = iterator_to_array( \IPS\Db::i()->select( 'DISTINCT reply_request', 'nexus_support_replies', array( array( 'reply_member=?', \IPS\Member::loggedIn()->member_id ), array( \IPS\Db::i()->in( 'reply_request', $supportRequestsInView ) ) ) ) );
$support = \IPS\Theme::i()->getTemplate('support')->requestsTableResults( $results, NULL, FALSE, $tracked, $participatedIn, FALSE );
/* History */
$extraHistoryTypes = array( 'email_change', 'password_change', 'display_name', 'mfa', 'merged' ); // define history types from other applications to include in commerce user history, i.e. changing MFA
$memberUrl = \IPS\Member::load( $this->member->member_id )->acpUrl();
$history = new \IPS\Member\History( $memberUrl->setQueryString( array( 'do' => 'history', 'nexus_return' => 1 ) ), array( array( 'log_member=? AND ( log_app=? OR ' . \IPS\Db::i()->in( 'log_type', $extraHistoryTypes ) . ' )', $this->member->member_id, 'nexus' ) ), TRUE, FALSE, TRUE );
$history->tableTemplate = array( \IPS\Theme::i()->getTemplate( 'customers', 'nexus' ), 'historyTable' );
$history->rowsTemplate = array( \IPS\Theme::i()->getTemplate( 'customers', 'nexus' ), 'historyRows' );
$history->limit = 16;
/* Display */
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'nexus', 'customers', 'customers_void' ) )
{
\IPS\Output::i()->sidebar['actions']['void'] = array(
'title' => 'void_account',
'icon' => 'times',
'link' => $member->acpUrl()->setQueryString( 'do', 'void' ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('void_account') )
);
}
\IPS\Output::i()->customHeader = \IPS\Theme::i()->getTemplate( 'customers' )->viewHeader( $member );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('customers')->view( $member, (string) $notes, $noteCount, $primaryBillingAddress, (string) $cards, $cardCount, $parents, (string) $alternativeContacts, $altContactCount, $purchases, $purchaseCount, $invoices, $invoiceCount, $history, $referredBy, $referrals, $referCount, $support, $supportCount, $sparkline, $purchaseRootCount, $billingAgreements, $billingAgreementCount, $addressCount );
\IPS\Output::i()->redirect( $this->member->acpUrl() );
}
/**
* Standing Data
* View Addresses
*
* @return void
*/
protected function standing()
protected function addresses()
{
$standing = array();
$time = time();
foreach ( \IPS\nexus\Money::currencies() as $currency )
$addresses = new \IPS\Helpers\Table\Db( 'nexus_customer_addresses', \IPS\Http\Url::internal("app=nexus&module=customers&controller=view&id={$this->member->member_id}")->setQueryString( 'view', 'addresses' ), array( 'member=?', $this->member->member_id ) );
$addresses->sortBy = 'primary_billing, primary_shipping, added';
$addresses->include = array( 'address', 'primary_billing', 'primary_shipping' );
$addresses->parsers = array( 'address' => function( $val )
{
/* Total spent */
$comparisons = \IPS\Db::i()->select( 'AVG(xval) AS avg, MAX(xval) AS max, MIN(xval) AS min', \IPS\Db::i()->select( "(SUM(t_amount)-SUM(t_partial_refund)) as xval", 'nexus_transactions', array( '( t_status=? OR t_status=? ) AND t_currency=? AND t_member<>0', \IPS\nexus\Transaction::STATUS_PAID, \IPS\nexus\Transaction::STATUS_PART_REFUNDED, $currency ), NULL, NULL, 't_member' ), 'xval>0' )->first();
$val = \IPS\Db::i()->select( 'SUM(t_amount)-SUM(t_partial_refund)', 'nexus_transactions', array( 't_member=? AND ( t_status=? OR t_status=? ) AND t_currency=?', $this->member->member_id, \IPS\nexus\Transaction::STATUS_PAID, \IPS\nexus\Transaction::STATUS_PART_REFUNDED, $currency ) )->first();
$standing[ \IPS\Member::loggedIn()->language()->addToStack( 'total_spent_currency', FALSE, array( 'sprintf' => array( $currency ) ) ) ] = array(
'value' => new \IPS\nexus\Money( $val ?: '0', $currency ),
'avg' => new \IPS\nexus\Money( $comparisons['avg'], $currency ),
'highest' => new \IPS\nexus\Money( $comparisons['max'], $currency ),
'lowest' => new \IPS\nexus\Money( $comparisons['min'], $currency ),
'lowval' => $comparisons['min'],
'highval' => $comparisons['max'],
'avgval' => $comparisons['avg'],
'thisval' => $val,
'avgpct' => $comparisons['max'] ? round( ( ( $comparisons['avg'] - $comparisons['min'] ) / $comparisons['max'] ) * 100, 1 ) : 0,
'thispct' => $comparisons['max'] ? round( ( ( $val - $comparisons['min'] ) / $comparisons['max'] ) * 100, 1 ) : 0,
'type' => 'totalspent'
return \IPS\GeoLocation::buildFromJson( $val )->toString( '<br>' );
} );
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'nexus', 'customers', 'customers_edit_details' ) )
{
$addresses->rootButtons = array(
'add' => array(
'link' => \IPS\Http\Url::internal("app=nexus&module=customers&controller=view&id={$this->member->member_id}")->setQueryString( 'do', 'addressForm' ),
'title' => 'add',
'icon' => 'plus',
'data' => array( 'ipsDialog' => true, 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('add_address') )
)
);
/* Average monthly spend */
$sum = "( SUM(t_amount) / ( ( {$time} - core_members.joined ) / 2592000 ) )";
$where = array( array( "( t_status=? OR t_status=? ) AND ({$time} - core_members.joined > 2592000) AND t_currency=?", \IPS\nexus\Transaction::STATUS_PAID, \IPS\nexus\Transaction::STATUS_PART_REFUNDED, $currency ) );
try
$addresses->rowButtons = function( $row )
{
$val = \IPS\Db::i()->select( "{$sum} as sum", 'nexus_transactions', array_merge( $where, array( array( 't_member=?', $this->member->member_id ) ) ), 'joined', NULL, 'joined' )->join( 'core_members', 'member_id=t_member' )->first();
}
catch( \UnderflowException $e )
{
$val = 0;
}
$comparisons = \IPS\Db::i()->select( 'AVG(xval) AS avg, MAX(xval) AS max, MIN(xval) AS min', \IPS\Db::i()->select( "{$sum} as xval", 'nexus_transactions', array_merge( $where, array( array( 't_member<>0' ) ) ), NULL, NULL, array( 't_member', 'joined' ) ), 'xval>0' )->join( 'core_members', 'member_id=t_member' )->first();
$standing[ \IPS\Member::loggedIn()->language()->addToStack( 'average_spend_currency', FALSE, array( 'sprintf' => array( $currency ) ) ) ] = array(
'value' => new \IPS\nexus\Money( $val, $currency ),
'avg' => new \IPS\nexus\Money( $comparisons['avg'], $currency ),
'highest' => new \IPS\nexus\Money( $comparisons['max'], $currency ),
'lowest' => new \IPS\nexus\Money( $comparisons['min'], $currency ),
'lowval' => $comparisons['min'],
'highval' => $comparisons['max'],
'avgval' => $comparisons['avg'],
'thisval' => $val,
'avgpct' => $comparisons['max'] ? round( ( ( $comparisons['avg'] - $comparisons['min'] ) / $comparisons['max'] ) * 100, 1 ) : 0,
'thispct' => $comparisons['max'] ? round( ( ( $val - $comparisons['min'] ) / $comparisons['max'] ) * 100, 1 ) : 0,
'type' => 'avgspent'
);
return array(
'edit' => array(
'link' => \IPS\Http\Url::internal("app=nexus&module=customers&controller=view&id={$this->member->member_id}")->setQueryString( array( 'do' => 'addressForm', 'address_id' => $row['id'] ) ),
'title' => 'edit',
'icon' => 'pencil',
'data' => array( 'ipsDialog' => true, 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('edit_address') )
),
'delete' => array(
'link' => \IPS\Http\Url::internal("app=nexus&module=customers&controller=view&id={$this->member->member_id}")->setQueryString( array( 'do' => 'deleteAddress', 'address_id' => $row['id'] ) ),
'title' => 'delete',
'icon' => 'times-circle',
'data' => array( 'delete' => '' )
)
);
};
}
$sum = "ROUND( ( AVG( i_paid - i_date ) / 86400 ), 2 )";
$where = array( array( "i_status=? AND i_date>0 AND i_paid>0", \IPS\nexus\Invoice::STATUS_PAID ) );
$val = \IPS\Db::i()->select( "{$sum} as sum", 'nexus_invoices', array_merge( $where, array( array( 'i_member=?', $this->member->member_id ) ) ) )->join( 'core_members', 'member_id=i_member' )->first();
$comparisons = \IPS\Db::i()->select( 'AVG(xval) AS avg, MAX(xval) AS max, MIN(xval) AS min', \IPS\Db::i()->select( "{$sum} as xval", 'nexus_invoices', array_merge( $where, array( array( 'i_member<>0' ) ) ), NULL, NULL, array( 'i_member', 'joined' ) ), 'xval>0' )->join( 'core_members', 'member_id=i_member' )->first();
$standing[ \IPS\Member::loggedIn()->language()->addToStack( 'average_time_to_pay' ) ] = array(
'value' => \IPS\Member::loggedIn()->language()->formatNumber( $val, 2 ) . ' ' . \IPS\Member::loggedIn()->language()->addToStack('days'),
'avg' => \IPS\Member::loggedIn()->language()->formatNumber( $comparisons['avg'], 2 ) . ' ' . \IPS\Member::loggedIn()->language()->addToStack('days'),
'highest' => \IPS\Member::loggedIn()->language()->formatNumber( $comparisons['max'], 2 ) . ' ' . \IPS\Member::loggedIn()->language()->addToStack('days'),
'lowest' => \IPS\Member::loggedIn()->language()->formatNumber( $comparisons['min'], 2 ) . ' ' . \IPS\Member::loggedIn()->language()->addToStack('days'),
'lowval' => $comparisons['min'],
'highval' => $comparisons['max'],
'avgval' => $comparisons['avg'],
'thisval' => $val,
'avgpct' => floatval( $comparisons['max'] ) ? round( ( ( $comparisons['avg'] - $comparisons['min'] ) / $comparisons['max'] ) * 100, 1 ) : 0,
'thispct' => floatval( $comparisons['max'] ) ? round( ( ( $val - $comparisons['min'] ) / $comparisons['max'] ) * 100, 1 ) : 0,
'type' => 'timetopay'
);
$sum = "LEAST( ( COUNT(*) / ( ( {$time} - core_members.joined ) / 2592000 ) ), COUNT(*) )";
try
{
$val = \IPS\Db::i()->select( "{$sum} as sum", 'nexus_support_requests', array( 'r_member=?', $this->member->member_id ), 'joined', NULL, 'joined' )->join( 'core_members', 'member_id=r_member' )->first();
}
catch( \UnderflowException $e )
{
$val = 0;
}
$comparisons = \IPS\Db::i()->select( 'AVG(xval) AS avg, MAX(xval) AS max, MIN(xval) AS min', \IPS\Db::i()->select( "{$sum} as xval", 'nexus_support_requests', 'r_member<>0', NULL, NULL, 'joined' ) )->join( 'core_members', 'member_id=r_member' )->first();
$standing[ \IPS\Member::loggedIn()->language()->addToStack( 'average_monthly_support_requests' ) ] = array(
'value' => \IPS\Member::loggedIn()->language()->formatNumber( $val, 2 ),
'avg' => \IPS\Member::loggedIn()->language()->formatNumber( $comparisons['avg'], 2 ),
'highest' => \IPS\Member::loggedIn()->language()->formatNumber( $comparisons['max'], 2 ),
'lowest' => \IPS\Member::loggedIn()->language()->formatNumber( $comparisons['min'], 2 ),
'lowval' => $comparisons['min'],
'highval' => $comparisons['max'],
'avgval' => $comparisons['avg'],
'thisval' => $val,
'avgpct' => $comparisons['max'] ? round( ( ( $comparisons['avg'] - $comparisons['min'] ) / $comparisons['max'] ) * 100, 1 ) : 0,
'thispct' => $comparisons['max'] ? round( ( ( $val - $comparisons['min'] ) / $comparisons['max'] ) * 100, 1 ) : 0,
'type' => 'support'
);
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate('customers')->standing( $standing ) );
$addresses->tableTemplate = array( \IPS\Theme::i()->getTemplate('customers'), 'addressTable' );
$addresses->rowsTemplate = array( \IPS\Theme::i()->getTemplate('customers'), 'addressTableRows' );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('customers')->customerPopup( $addresses );
}
/**
@@ -720,7 +130,7 @@ class _view extends \IPS\Dispatcher\Controller
*/
protected function purchaseList()
{
$purchases = \IPS\nexus\Purchase::tree( $this->member->acpUrl()->setQueryString( 'do', 'purchaseList' ), array( array( 'ps_member=?', $this->member->member_id ) ) );
$purchases = \IPS\nexus\Purchase::tree( \IPS\Http\Url::internal("app=nexus&module=customers&controller=view&id={$this->member->member_id}")->setQueryString( 'do', 'purchaseList' ), array( array( 'ps_member=?', $this->member->member_id ) ) );
$purchases->rootsPerPage = 25;
$purchases->getTotalRoots = function()
{
@@ -824,7 +234,7 @@ class _view extends \IPS\Dispatcher\Controller
\IPS\Output::i()->redirect( $this->member->acpUrl() );
}
\IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core', 'front' ) ), 'popupTemplate' ) );
\IPS\Output::i()->output = (string) $form;
}
/**
@@ -1138,16 +548,21 @@ class _view extends \IPS\Dispatcher\Controller
if ( isset( \IPS\Request::i()->process ) )
{
$values = array(
'void_refund_transactions' => \IPS\Request::i()->trans,
'void_cancel_purchases' => \IPS\Request::i()->purch,
'void_refund_transactions' => \IPS\Request::i()->trans,
'void_cancel_billing_agreements' => \IPS\Request::i()->ba,
'void_cancel_purchases' => \IPS\Request::i()->purch,
);
}
else
{
$form = new \IPS\Helpers\Form( 'void_account', 'void_account' );
$form->ajaxOutput = TRUE;
$form->addMessage( 'void_account_warning', 'ipsMessage ipsMessage_warning' );
$form->addMessage( 'void_account_warning' );
$form->add( new \IPS\Helpers\Form\YesNo( 'void_refund_transactions', TRUE ) );
if ( \IPS\nexus\Gateway::billingAgreementGateways() )
{
$form->add( new \IPS\Helpers\Form\YesNo( 'void_cancel_billing_agreements', TRUE ) );
}
$form->add( new \IPS\Helpers\Form\YesNo( 'void_cancel_purchases', TRUE ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'void_cancel_invoices', TRUE ) );
$form->add( new \IPS\Helpers\Form\Node( 'void_resolve_support', \IPS\Settings::i()->nexus_autoresolve_status, FALSE, array( 'class' => 'IPS\nexus\Support\Status', 'zeroVal' => 'do_not_change' ) ) );
@@ -1189,7 +604,7 @@ class _view extends \IPS\Dispatcher\Controller
\IPS\File::claimAttachments( "nexus-note-{$this->member->member_id}-new", $this->member->id, $noteId, 'note' );
}
if ( !$values['void_refund_transactions'] and !$values['void_cancel_purchases'] )
if ( !$values['void_refund_transactions'] and !$values['void_cancel_purchases'] and !$values['void_cancel_billing_agreements'] )
{
\IPS\Output::i()->redirect( $this->member->acpUrl() );
}
@@ -1199,17 +614,18 @@ class _view extends \IPS\Dispatcher\Controller
if ( $values )
{
$member = $this->member;
\IPS\Output::i()->output = new \IPS\Helpers\MultipleRedirect( $this->member->acpUrl()->setQueryString( array(
\IPS\Output::i()->output = new \IPS\Helpers\MultipleRedirect( \IPS\Http\Url::internal("app=nexus&module=customers&controller=view&id={$this->member->member_id}")->setQueryString( array(
'do' => 'void',
'process' => 1,
'trans' => $values['void_refund_transactions'],
'ba' => $values['void_cancel_billing_agreements'],
'purch' => $values['void_cancel_purchases'],
) ), function( $data ) use ( $member )
{
if ( !is_array( $data ) )
{
$data = array( 'trans' => 0, 'purch' => 0, 'fail' => array() );
$data = array( 'trans' => 0, 'ba' => 0, 'purch' => 0, 'fail' => array() );
}
$done = 0;
@@ -1253,6 +669,25 @@ class _view extends \IPS\Dispatcher\Controller
}
}
if ( \IPS\Request::i()->ba )
{
foreach ( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'nexus_billing_agreements', array( 'ba_member=?', $member->member_id ), 'ba_id', array( $data['ba'], 10 ) ), 'IPS\nexus\Customer\BillingAgreement' ) as $billingAgreement )
{
try
{
$billingAgreement->cancel();
}
catch ( \Exception $e ) { }
$data['ba']++;
$done++;
if ( $done >= 10 )
{
return array( $data, \IPS\Member::loggedIn()->language()->addToStack('processing') );
}
}
}
if ( \IPS\Request::i()->purch )
{
foreach ( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'nexus_purchases', array( 'ps_member=?', $member->member_id ), 'ps_id', array( $data['purch'], 10 ) ), 'IPS\nexus\Purchase' ) as $purchase )
@@ -478,7 +478,7 @@ class _servers extends \IPS\Node\Controller
if( isset( \IPS\Request::i()->server_type ) and in_array( \IPS\Request::i()->server_type, $availableTypes ) )
{
$this->nodeClass = "IPS\\nexus\\Hosting\\" . ucfirst( \IPS\Request::i()->server_type ) . "\\Server";
$this->nodeClass = "IPS\\nexus\\Hosting\\" . mb_ucfirst( \IPS\Request::i()->server_type ) . "\\Server";
}
parent::form();
@@ -55,24 +55,15 @@ class _checkoutsettings extends \IPS\Dispatcher\Controller
{
$requireBillingOptions['domain'] = 'nexus_require_billing_domain';
}
if ( \IPS\Settings::i()->nexus_subs_enabled and \IPS\Db::i()->select( 'COUNT(*)', 'nexus_member_subscription_packages' )->first() )
{
$requireBillingOptions['subscriptions'] = 'nexus_require_billing_subscriptions';
}
$requireBillingOptions['other'] = 'nexus_require_billing_other';
$form = new \IPS\Helpers\Form;
$form->addHeader( 'checkout_settings' );
$form->add( new \IPS\Helpers\Form\YesNo( 'nexus_https', \IPS\Settings::i()->nexus_https, FALSE, array(), function( $val )
{
if ( $val )
{
try
{
\IPS\Http\Url::internal( '', 'front', NULL, array(), TRUE )->request()->get();
}
catch ( \IPS\Http\Request\Exception $e )
{
throw new \DomainException('nexus_https_err');
}
}
} ) );
$form->add( new \IPS\Helpers\Form\CheckboxSet( 'nexus_require_billing', explode( ',', \IPS\Settings::i()->nexus_require_billing ), FALSE, array( 'options' => $requireBillingOptions ) ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'nexus_split_payments_on', \IPS\Settings::i()->nexus_split_payments != -1, FALSE, array( 'togglesOn' => array( 'nexus_split_payments' ) ) ) );
$form->add( new \IPS\nexus\Form\Money( 'nexus_split_payments', \IPS\Settings::i()->nexus_split_payments ?: '*', FALSE, array( 'unlimitedLang' => 'no_restriction' ), NULL, NULL, NULL, 'nexus_split_payments' ) );
@@ -80,7 +80,7 @@ class _currencies extends \IPS\Dispatcher\Controller
'default' => $defaults
);
if ( !in_array( $code, array( 'AED', 'AFN', 'ALL', 'AMD', 'ANG', 'AOA', 'ARS', 'AUD', 'AWG', 'AZN', 'BAM', 'BBD', 'BDT', 'BGN', 'BHD', 'BIF', 'BMD', 'BND', 'BOB', 'BRL', 'BSD', 'BTN', 'BWP', 'BYN', 'BYR', 'BZD', 'CAD', 'CDF', 'CHF', 'CLP', 'CNY', 'COP', 'CRC', 'CUC', 'CUP', 'CVE', 'CZK', 'DJF', 'DKK', 'DOP', 'DZD', 'EGP', 'ERN', 'ETB', 'EUR', 'FJD', 'FKP', 'GBP', 'GEL', 'GGP', 'GHS', 'GIP', 'GMD', 'GNF', 'GTQ', 'GYD', 'HKD', 'HNL', 'HRK', 'HTG', 'HUF', 'IDR', 'ILS', 'IMP', 'INR', 'IQD', 'IRR', 'ISK', 'JEP', 'JMD', 'JOD', 'JPY', 'KES', 'KGS', 'KHR', 'KMF', 'KPW', 'KRW', 'KWD', 'KYD', 'KZT', 'LAK', 'LBP', 'LKR', 'LRD', 'LSL', 'LYD', 'MAD', 'MDL', 'MGA', 'MKD', 'MMK', 'MNT', 'MOP', 'MRO', 'MUR', 'MVR', 'MWK', 'MXN', 'MYR', 'MZN', 'NAD', 'NGN', 'NIO', 'NOK', 'NPR', 'NZD', 'OMR', 'PAB', 'PEN', 'PGK', 'PHP', 'PKR', 'PLN', 'PYG', 'QAR', 'RON', 'RSD', 'RUB', 'RWF', 'SAR', 'SBD', 'SCR', 'SDG', 'SEK', 'SGD', 'SHP', 'SLL', 'SOS', 'SPL*', 'SRD', 'STD', 'SVC', 'SYP', 'SZL', 'THB', 'TJS', 'TMT', 'TND', 'TOP', 'TRY', 'TTD', 'TVD', 'TWD', 'TZS', 'UAH', 'UGX', 'USD', 'UYU', 'UZS', 'VEF', 'VND', 'VUV', 'WST', 'XAF', 'XCD', 'XDR', 'XOF', 'XPF', 'YER', 'ZAR', 'ZMW', 'ZWD' ) ) )
if ( !in_array( $code, array( 'AED', 'AFN', 'ALL', 'AMD', 'ANG', 'AOA', 'ARS', 'AUD', 'AWG', 'AZN', 'BAM', 'BBD', 'BDT', 'BGN', 'BHD', 'BIF', 'BMD', 'BND', 'BOB', 'BRL', 'BSD', 'BTN', 'BWP', 'BYN', 'BYR', 'BZD', 'CAD', 'CDF', 'CHF', 'CLF', 'CLP', 'CNY', 'COP', 'CRC', 'CUC', 'CUP', 'CVE', 'CZK', 'DJF', 'DKK', 'DOP', 'DZD', 'EGP', 'ERN', 'ETB', 'EUR', 'FJD', 'FKP', 'GBP', 'GEL', 'GGP', 'GHS', 'GIP', 'GMD', 'GNF', 'GTQ', 'GYD', 'HKD', 'HNL', 'HRK', 'HTG', 'HUF', 'IDR', 'ILS', 'IMP', 'INR', 'IQD', 'IRR', 'ISK', 'JEP', 'JMD', 'JOD', 'JPY', 'KES', 'KGS', 'KHR', 'KMF', 'KPW', 'KRW', 'KWD', 'KYD', 'KZT', 'LAK', 'LBP', 'LKR', 'LRD', 'LSL', 'LYD', 'MAD', 'MDL', 'MGA', 'MKD', 'MMK', 'MNT', 'MOP', 'MRO', 'MUR', 'MVR', 'MWK', 'MXN', 'MYR', 'MZN', 'NAD', 'NGN', 'NIO', 'NOK', 'NPR', 'NZD', 'OMR', 'PAB', 'PEN', 'PGK', 'PHP', 'PKR', 'PLN', 'PYG', 'QAR', 'RON', 'RSD', 'RUB', 'RWF', 'SAR', 'SBD', 'SCR', 'SDG', 'SEK', 'SGD', 'SHP', 'SLL', 'SOS', 'SPL*', 'SRD', 'STD', 'SVC', 'SYP', 'SZL', 'THB', 'TJS', 'TMT', 'TND', 'TOP', 'TRY', 'TTD', 'TVD', 'TWD', 'TZS', 'UAH', 'UGX', 'USD', 'UYU', 'UZS', 'VEF', 'VND', 'VUV', 'WST', 'XAF', 'XCD', 'XDR', 'XOF', 'XPF', 'YER', 'ZAR', 'ZMW', 'ZWD' ) ) )
{
$warnings .= \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->message( \IPS\Member::loggedIn()->language()->addToStack( 'currency_code_invalid', FALSE, array( 'sprintf' => array( $code ) ) ), 'warning' );
}
@@ -106,9 +106,7 @@ class _currencies extends \IPS\Dispatcher\Controller
}
}
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => json_encode( $save ) ), array( 'conf_key=?', 'nexus_currency' ) );
\IPS\Settings::i()->nexus_currency = json_encode( $save );
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'nexus_currency' => json_encode( $save ) ) );
$definition = \IPS\Db::i()->getTableDefinition( 'nexus_package_base_prices' );
@@ -33,6 +33,11 @@ class _fraud extends \IPS\Node\Controller
*/
public $_descriptionHtml = TRUE;
/**
* Show the "add" button in the page root rather than the table root
*/
protected $_addButtonInRoot = FALSE;
/**
* Execute
*
@@ -51,17 +56,7 @@ class _fraud extends \IPS\Node\Controller
*/
public function manage()
{
foreach ( \IPS\nexus\Fraud\Rule::roots() as $rule )
{
foreach ( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'nexus_fraud_rules', array( 'f_order>?', $rule->order ) ), 'IPS\nexus\Fraud\Rule' ) as $otherRule )
{
if ( $rule->isSubsetOf( $otherRule ) )
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core' )->message( \IPS\Member::loggedIn()->language()->addToStack('fraud_rule_conflict', FALSE, array( 'sprintf' => array( $rule->name, $otherRule->name ) ) ), 'warning', NULL, FALSE );
break 2;
}
}
}
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'forms', 'core' )->blurb( 'fraud_rule_blurb', TRUE, TRUE );
parent::manage();
}
@@ -584,12 +584,18 @@ class _invoices extends \IPS\Dispatcher\Controller
$method = $transaction->method;
$refundMethods = array();
$refundMethodToggles = array( 'credit' => array( $transaction->id . '_refund_amount' ) );
$refundReasons = array();
if ( $method and $method::SUPPORTS_REFUNDS )
{
$refundMethods['gateway'] = $method->_title;
$refundMethodToggles['gateway'] = array();
if ( $method::SUPPORTS_PARTIAL_REFUNDS )
{
$refundMethodToggles['gateway'] = array( $transaction->id . '_refund_amount' );
$refundMethodToggles['gateway'][] = $transaction->id . '_refund_amount';
}
if ( $refundReasons = $method::refundReasons() )
{
$refundMethodToggles['gateway'][] = $transaction->id . '_refund_reason';
}
}
$refundMethods['credit'] = 'refund_method_credit';
@@ -599,6 +605,12 @@ class _invoices extends \IPS\Dispatcher\Controller
$field = new \IPS\Helpers\Form\Radio( $transaction->id . '_refund_method', 'none', TRUE, array( 'options' => $refundMethods, 'toggles' => $refundMethodToggles ) );
$field->label = count( $transactions ) === 1 ? \IPS\Member::loggedIn()->language()->addToStack( 'refund_method' ) : \IPS\Member::loggedIn()->language()->addToStack( 'trans_refund_method', FALSE, array( 'sprintf' => array( $transaction->id ) ) );
$form->add( $field );
if ( $refundReasons )
{
$field = new \IPS\Helpers\Form\Radio( $transaction->id . '_refund_reason', NULL, FALSE, array( 'options' => $refundReasons ), NULL, NULL, NULL, $transaction->id . '_refund_reason' );
$field->label = count( $transactions ) === 1 ? \IPS\Member::loggedIn()->language()->addToStack( 'refund_reason' ) : \IPS\Member::loggedIn()->language()->addToStack( 'trans_refund_reason', FALSE, array( 'sprintf' => array( $transaction->id ) ) );
$form->add( $field );
}
/* Partial refund? */
$field = new \IPS\Helpers\Form\Number( $transaction->id . '_refund_amount', ( $transaction->status === \IPS\nexus\Transaction::STATUS_PART_REFUNDED ? (string) $transaction->amount->amount->subtract( $transaction->partial_refund->amount ) : 0 ), TRUE, array( 'unlimited' => 0, 'unlimitedLang' => \IPS\Member::loggedIn()->language()->addToStack( 'refund_full', FALSE, array( 'sprintf' => array( $transaction->amount ) ) ), 'max' => (string) $transaction->amount->amount->subtract( $transaction->partial_refund->amount ), 'decimals' => TRUE ), NULL, NULL, $transaction->amount->currency, $transaction->id . '_refund_amount' );
@@ -645,7 +657,7 @@ class _invoices extends \IPS\Dispatcher\Controller
{
try
{
$transaction->refund( $values[ $transaction->id . '_refund_method' ], $values[ $transaction->id . '_refund_amount' ] );
$transaction->refund( $values[ $transaction->id . '_refund_method' ], $values[ $transaction->id . '_refund_amount' ], isset( $values[ $transaction->id . '_refund_reason' ] ) ? $values[ $transaction->id . '_refund_reason' ] : NULL );
}
catch ( \LogicException $e )
{
@@ -764,7 +776,7 @@ class _invoices extends \IPS\Dispatcher\Controller
$invoice->delete();
/* Redirect */
$this->_redirect( $invoice );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=nexus&module=payments&controller=invoices') );
}
/**
@@ -276,7 +276,7 @@ class _payouts extends \IPS\Dispatcher\Controller
{
if ( !$field->htmlId )
{
$field->htmlId = md5(uniqid());
$field->htmlId = md5(mt_rand());
}
$fields[] = $field;
@@ -45,7 +45,7 @@ class _transactions extends \IPS\Dispatcher\Controller
/* Create Table */
$table = \IPS\nexus\Transaction::table( array( array( 't_status<>?', \IPS\nexus\Transaction::STATUS_PENDING ) ), \IPS\Http\Url::internal( 'app=nexus&module=payments&controller=transactions' ), 't' );
$table->filters = array(
'tstatus_hold' => array( '( t_status=? OR t_status=? )', \IPS\nexus\Transaction::STATUS_HELD, \IPS\nexus\Transaction::STATUS_REVIEW ),
'trans_attention_required' => array( '( t_status=? OR t_status=? OR t_status=? )', \IPS\nexus\Transaction::STATUS_HELD, \IPS\nexus\Transaction::STATUS_REVIEW, \IPS\nexus\Transaction::STATUS_DISPUTED ),
);
$table->advancedSearch = array(
't_id' => \IPS\Helpers\Table\SEARCH_CONTAINS_TEXT,
@@ -58,6 +58,10 @@ class _transactions extends \IPS\Dispatcher\Controller
$table->quickSearch = 't_id';
/* Display */
if ( isset( \IPS\Request::i()->attn ) and \IPS\Db::i()->select( 'COUNT(*)', 'nexus_transactions', array( '( t_status=? OR t_status=? OR t_status=? )', \IPS\nexus\Transaction::STATUS_HELD, \IPS\nexus\Transaction::STATUS_REVIEW, \IPS\nexus\Transaction::STATUS_DISPUTED ) ) )
{
$table->filter = 'trans_attention_required';
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__nexus_payments_transactions');
\IPS\Output::i()->output = (string) $table;
}
@@ -105,7 +109,7 @@ class _transactions extends \IPS\Dispatcher\Controller
$method = $transaction->method;
/* Can we approve it? */
if ( !in_array( $transaction->status, array( \IPS\nexus\Transaction::STATUS_PENDING, \IPS\nexus\Transaction::STATUS_WAITING, \IPS\nexus\Transaction::STATUS_HELD, \IPS\nexus\Transaction::STATUS_REVIEW, \IPS\nexus\Transaction::STATUS_GATEWAY_PENDING ) ) )
if ( !in_array( $transaction->status, array( \IPS\nexus\Transaction::STATUS_WAITING, \IPS\nexus\Transaction::STATUS_HELD, \IPS\nexus\Transaction::STATUS_REVIEW, \IPS\nexus\Transaction::STATUS_GATEWAY_PENDING ) ) )
{
\IPS\Output::i()->error( 'transaction_status_err', '2X186/A', 403, '' );
}
@@ -163,7 +167,7 @@ class _transactions extends \IPS\Dispatcher\Controller
$method = $transaction->method;
/* Can we flag it? */
if ( !in_array( $transaction->status, array( \IPS\nexus\Transaction::STATUS_PENDING, \IPS\nexus\Transaction::STATUS_WAITING, \IPS\nexus\Transaction::STATUS_HELD ) ) )
if ( !in_array( $transaction->status, array( \IPS\nexus\Transaction::STATUS_WAITING, \IPS\nexus\Transaction::STATUS_HELD ) ) )
{
\IPS\Output::i()->error( 'transaction_status_err', '2X186/B', 403, '' );
}
@@ -176,11 +180,14 @@ class _transactions extends \IPS\Dispatcher\Controller
$transaction->save();
/* Log it */
$transaction->member->log( 'transaction', array(
'type' => 'status',
'status' => \IPS\nexus\Transaction::STATUS_REVIEW,
'id' => $transaction->id
) );
if( $transaction->member )
{
$transaction->member->log( 'transaction', array(
'type' => 'status',
'status' => \IPS\nexus\Transaction::STATUS_REVIEW,
'id' => $transaction->id
) );
}
/* Create a support request? */
if ( \IPS\Settings::i()->nexus_revw_sa != -1 )
@@ -248,7 +255,7 @@ class _transactions extends \IPS\Dispatcher\Controller
$method = $transaction->method;
/* Can we void it? */
if ( !in_array( $transaction->status, array( \IPS\nexus\Transaction::STATUS_PENDING, \IPS\nexus\Transaction::STATUS_WAITING, \IPS\nexus\Transaction::STATUS_GATEWAY_PENDING ) ) and ( !$transaction->auth or !in_array( $transaction->status, array( \IPS\nexus\Transaction::STATUS_HELD, \IPS\nexus\Transaction::STATUS_REVIEW ) ) ) )
if ( !in_array( $transaction->status, array( \IPS\nexus\Transaction::STATUS_WAITING, \IPS\nexus\Transaction::STATUS_GATEWAY_PENDING ) ) and ( !$transaction->auth or !in_array( $transaction->status, array( \IPS\nexus\Transaction::STATUS_HELD, \IPS\nexus\Transaction::STATUS_REVIEW ) ) ) )
{
\IPS\Output::i()->error( 'transaction_status_err', '2X186/5', 403, '' );
}
@@ -302,12 +309,18 @@ class _transactions extends \IPS\Dispatcher\Controller
/* What are the refund methods? */
$refundMethods = array();
$refundMethodToggles = array( 'credit' => array( 'refund_amount' ) );
$refundReasons = array();
if ( $method and $method::SUPPORTS_REFUNDS )
{
$refundMethods['gateway'] = $method->_title;
$refundMethodToggles['gateway'] = array();
if ( $method::SUPPORTS_PARTIAL_REFUNDS )
{
$refundMethodToggles['gateway'] = array( 'refund_amount' );
$refundMethodToggles['gateway'][] = 'refund_amount';
}
if ( $refundReasons = $method::refundReasons() )
{
$refundMethodToggles['gateway'][] = 'refund_reason';
}
}
$refundMethods['credit'] = 'refund_method_credit';
@@ -316,7 +329,20 @@ class _transactions extends \IPS\Dispatcher\Controller
/* Build form */
$form = new \IPS\Helpers\Form;
$form->add( new \IPS\Helpers\Form\Radio( 'refund_method', ( $method and $method::SUPPORTS_REFUNDS ) ? 'gateway' : 'credit', TRUE, array( 'options' => $refundMethods, 'toggles' => $refundMethodToggles ) ) );
$form->add( new \IPS\Helpers\Form\Number( 'refund_amount', ( $transaction->status === \IPS\nexus\Transaction::STATUS_PART_REFUNDED ? $transaction->amount->amount->subtract( $transaction->partial_refund->amount ) : 0 ), TRUE, array( 'unlimited' => 0, 'unlimitedLang' => \IPS\Member::loggedIn()->language()->addToStack( 'refund_full', FALSE, array( 'sprintf' => array( $transaction->amount ) ) ), 'max' => (string) $transaction->amount->amount->subtract( $transaction->partial_refund->amount ), 'decimals' => TRUE ), NULL, NULL, $transaction->amount->currency, 'refund_amount' ) );
if ( $refundReasons )
{
$form->add( new \IPS\Helpers\Form\Radio( 'refund_reason', NULL, FALSE, array( 'options' => $refundReasons ), NULL, NULL, NULL, 'refund_reason' ) );
}
$form->add( new \IPS\Helpers\Form\Number( 'refund_amount', 0, TRUE, array(
'unlimited' => 0,
'unlimitedLang' => (
$transaction->status === \IPS\nexus\Transaction::STATUS_PART_REFUNDED
? \IPS\Member::loggedIn()->language()->addToStack( 'refund_full_remaining', FALSE, array( 'sprintf' => array( new \IPS\nexus\Money( $transaction->amount->amount->subtract( $transaction->partial_refund->amount ), $transaction->currency ) ) ) )
: \IPS\Member::loggedIn()->language()->addToStack( 'refund_full', FALSE, array( 'sprintf' => array( $transaction->amount ) ) )
),
'max' => (string) $transaction->amount->amount->subtract( $transaction->partial_refund->amount ),
'decimals' => TRUE
), NULL, NULL, $transaction->amount->currency, 'refund_amount' ) );
if ( $transaction->invoice !== NULL and $transaction->invoice->status === \IPS\nexus\Invoice::STATUS_PAID )
{
$field = new \IPS\Helpers\Form\Radio( 'refund_invoice_status', \IPS\nexus\Invoice::STATUS_PENDING, TRUE, array(
@@ -340,7 +366,7 @@ class _transactions extends \IPS\Dispatcher\Controller
/* Refund */
try
{
$transaction->refund( $values['refund_method'], $values['refund_amount'] );
$transaction->refund( $values['refund_method'], $values['refund_amount'], isset( $values['refund_reason'] ) ? $values['refund_reason'] : NULL );
}
catch ( \LogicException $e )
{
@@ -358,12 +384,15 @@ class _transactions extends \IPS\Dispatcher\Controller
{
$transaction->invoice->markUnpaid( $values['refund_invoice_status'] );
$transaction->invoice->member->log( 'invoice', array(
'type' => 'status',
'new' => $values['refund_invoice_status'],
'id' => $transaction->invoice->id,
'title' => $transaction->invoice->title
) );
if( $transaction->invoice->member )
{
$transaction->invoice->member->log( 'invoice', array(
'type' => 'status',
'new' => $values['refund_invoice_status'],
'id' => $transaction->invoice->id,
'title' => $transaction->invoice->title
) );
}
}
/* Send Email */
@@ -406,11 +435,14 @@ class _transactions extends \IPS\Dispatcher\Controller
/* Log it */
try
{
$transaction->member->log( 'transaction', array(
'type' => 'delete',
'id' => $transaction->id,
'method' => $transaction->method->id
) );
if( $transaction->member )
{
$transaction->member->log( 'transaction', array(
'type' => 'delete',
'id' => $transaction->id,
'method' => $transaction->method->id
) );
}
}
catch ( \OutOfRangeException $e )
{
@@ -41,14 +41,29 @@ class _income extends \IPS\Dispatcher\Controller
*/
protected function manage()
{
$tabs['totals'] = 'nexus_report_income_totals';
foreach ( \IPS\nexus\Money::currencies() as $currency )
$currencies = \IPS\nexus\Money::currencies();
$tabs = array( 'totals' => 'nexus_report_income_totals' );
if( count( $currencies ) == 1 )
{
$tabs['members'] = 'nexus_report_income_members';
}
else
{
foreach ( $currencies as $currency )
{
$tabs[ 'members_' . $currency ] = \IPS\Member::loggedIn()->language()->addToStack( 'nexus_report_income_by_member', NULL, array( 'sprintf' => array( $currency ) ) );
}
}
foreach ( $currencies as $currency )
{
$tabs[ $currency ] = \IPS\Member::loggedIn()->language()->addToStack( 'nexus_report_income_by_method', NULL, array( 'sprintf' => array( $currency ) ) );
}
$activeTab = ( isset( \IPS\Request::i()->tab ) and array_key_exists( \IPS\Request::i()->tab, $tabs ) ) ? \IPS\Request::i()->tab : 'totals';
$chart = new \IPS\Helpers\Chart\Database(
\IPS\Http\Url::internal( 'app=nexus&module=reports&controller=income&tab=' . $activeTab ),
'nexus_transactions',
@@ -61,7 +76,7 @@ class _income extends \IPS\Dispatcher\Controller
'lineWidth' => 1,
'areaOpacity' => 0.4,
),
'AreaChart',
( \IPS\Request::i()->tab == 'members' ) ? 'PieChart' : 'AreaChart',
'monthly',
array( 'start' => 0, 'end' => 0 ),
array(),
@@ -73,11 +88,30 @@ class _income extends \IPS\Dispatcher\Controller
{
$chart->groupBy = 't_currency';
foreach ( \IPS\nexus\Money::currencies() as $currency )
foreach ( $currencies as $currency )
{
$chart->addSeries( $currency, 'number', 'SUM(t_amount)-SUM(t_partial_refund)', TRUE, $currency );
}
}
elseif( mb_strpos( $activeTab, 'members' ) === 0 )
{
$chart->groupBy = 't_member';
if( count( $currencies ) === 1 )
{
$chart->format = array_pop( $currencies );
}
else
{
$chart->format = mb_substr( $activeTab, 8 );
$chart->where[] = array( 't_currency=?', $chart->format );
}
foreach ( \IPS\Db::i()->select( 't_member, SUM(t_amount)-SUM(t_partial_refund) as _amount', 'nexus_transactions', $chart->where, '_amount DESC', array( 0, 20 ), 't_member' ) as $member )
{
$chart->addSeries( \IPS\Member::load( $member['t_member'] )->name, 'number', 'SUM(t_amount)-SUM(t_partial_refund)', TRUE, $member['t_member'] );
}
}
else
{
$chart->where[] = array( 't_currency=?', $activeTab );
@@ -89,6 +123,48 @@ class _income extends \IPS\Dispatcher\Controller
$chart->addSeries( $gateway->_title, 'number', 'SUM(t_amount)-SUM(t_partial_refund)', TRUE, $gateway->id );
}
}
$chart->tableInclude = array( 't_id', 't_member', 't_invoice', 't_method', 't_amount', 't_date' );
$chart->tableParsers = array(
't_member' => function( $val ) {
return \IPS\Theme::i()->getTemplate('global', 'nexus')->userLink( \IPS\Member::load( $val ) );
},
't_method' => function( $val ) {
if ( $val )
{
try
{
return \IPS\nexus\Gateway::load( $val )->_title;
}
catch ( \OutOfRangeException $e )
{
return '';
}
}
else
{
return \IPS\Member::loggedIn()->language()->addToStack('account_credit');
}
},
't_amount' => function( $val, $row )
{
return (string) new \IPS\nexus\Money( $val, $row['t_currency'] );
},
't_invoice' => function( $val )
{
try
{
return \IPS\Theme::i()->getTemplate('invoices', 'nexus')->link( \IPS\nexus\Invoice::load( $val ) );
}
catch ( \OutOfRangeException $e )
{
return '';
}
},
't_date' => function( $val ) {
return \IPS\DateTime::ts( $val );
}
);
if ( \IPS\Request::i()->isAjax() )
{
@@ -56,7 +56,7 @@ class _markets extends \IPS\Dispatcher\Controller
'',
array(
'backgroundColor' => '#ffffff',
'colors' => array( '#10967e', '#ea7963', '#de6470', '#6b9dde', '#b09be4', '#eec766', '#9fc973', '#e291bf', '#55c1a6', '#5fb9da' ),
'colors' => array( '#c9e2de', '#10967e' ),
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
'lineWidth' => 1,
'areaOpacity' => 0.4,
@@ -56,6 +56,18 @@ class _purchases extends \IPS\Dispatcher\Controller
);
$chart->where[] = array( 'ps_app=? AND ps_type=?', 'nexus', 'package' );
$chart->groupBy = 'ps_item_id';
$chart->tableInclude = array( 'ps_id', 'ps_member', 'ps_name', 'ps_start', 'ps_expire' );
$chart->tableParsers = array(
'ps_member' => function( $val ) {
return \IPS\Theme::i()->getTemplate('global', 'nexus')->userLink( \IPS\Member::load( $val ) );
},
'ps_start' => function( $val ) {
return \IPS\DateTime::ts( $val );
},
'ps_expire' => function( $val ) {
return $val ? \IPS\DateTime::ts( $val ) : '';
}
);
$packages = array();
foreach ( \IPS\Db::i()->select( 'p_id', 'nexus_packages' ) as $packageId )
@@ -38,6 +38,7 @@ class _packages extends \IPS\Node\Controller
\IPS\Dispatcher::i()->checkAcpPermission( 'packages_manage' );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'admin_store.js', 'nexus', 'admin' ) );
parent::execute();
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__nexus_store_packages');
}
/**
@@ -127,10 +128,10 @@ class _packages extends \IPS\Node\Controller
}
$changes = json_decode( \IPS\Request::i()->changes, TRUE );
if ( !isset( \IPS\Request::i()->processing ) )
{
if ( isset( $changes['renew_options'] ) and $changes['renew_options'] )
if ( isset( $changes['renew_options'] ) )
{
$matrix = new \IPS\Helpers\Form\Matrix( 'matrix', 'continue' );
$matrix->manageable = FALSE;
@@ -180,28 +181,31 @@ class _packages extends \IPS\Node\Controller
},
);
foreach ( json_decode( $changes['renew_options'], TRUE ) as $k => $oldOption )
if ( $changes['renew_options'] )
{
$costs = array();
foreach ( $oldOption['cost'] as $data )
foreach ( json_decode( $changes['renew_options'], TRUE ) as $k => $oldOption )
{
$costs[] = new \IPS\nexus\Money( $data['amount'], $data['currency'] );
$costs = array();
foreach ( $oldOption['cost'] as $data )
{
$costs[] = new \IPS\nexus\Money( $data['amount'], $data['currency'] );
}
switch ( $oldOption['unit'] )
{
case 'd':
$term = \IPS\Member::loggedIn()->language()->addToStack('renew_days', FALSE, array( 'pluralize' => array( $oldOption['term'] ) ) );
break;
case 'm':
$term = \IPS\Member::loggedIn()->language()->addToStack('renew_months', FALSE, array( 'pluralize' => array( $oldOption['term'] ) ) );
break;
case 'y':
$term = \IPS\Member::loggedIn()->language()->addToStack('renew_years', FALSE, array( 'pluralize' => array( $oldOption['term'] ) ) );
break;
}
$matrix->rows[ $k ] = array( \IPS\Member::loggedIn()->language()->addToStack( 'renew_option', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->formatList( $costs, \IPS\Member::loggedIn()->language()->get('or_list_format') ), $term ) ) ), "o{$k}" );
}
switch ( $oldOption['unit'] )
{
case 'd':
$term = \IPS\Member::loggedIn()->language()->addToStack('renew_days', FALSE, array( 'pluralize' => array( $oldOption['term'] ) ) );
break;
case 'm':
$term = \IPS\Member::loggedIn()->language()->addToStack('renew_months', FALSE, array( 'pluralize' => array( $oldOption['term'] ) ) );
break;
case 'y':
$term = \IPS\Member::loggedIn()->language()->addToStack('renew_years', FALSE, array( 'pluralize' => array( $oldOption['term'] ) ) );
break;
}
$matrix->rows[ $k ] = array( \IPS\Member::loggedIn()->language()->addToStack( 'renew_option', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->formatList( $costs, \IPS\Member::loggedIn()->language()->get('or_list_format') ), $term ) ) ), "o{$k}" );
}
$matrix->rows['x'] = array( 'any_other_amount', '-' );
@@ -226,7 +230,7 @@ class _packages extends \IPS\Node\Controller
}
}
}
if ( isset( $changes['renew_options'] ) and !isset( \IPS\Request::i()->ba ) )
{
$needBaPrompt = FALSE;
@@ -403,7 +407,7 @@ class _packages extends \IPS\Node\Controller
'ps_member' => function( $val ) {
try
{
return \IPS\nexus\Customer::load( $val )->link();
return \IPS\Theme::i()->getTemplate('global', 'nexus')->userLink( \IPS\Member::load( $val ) );
}
catch ( \OutOfRangeException $e )
{
@@ -454,4 +458,34 @@ class _packages extends \IPS\Node\Controller
\IPS\Output::i()->title = $package->_title;
\IPS\Output::i()->output = $table;
}
/**
* Show Email Preview
*
* @return void
*/
public function emailPreview()
{
$functionName = 'emailPreview_' . mt_rand();
\IPS\Theme::makeProcessFunction( \IPS\Request::i()->value, $functionName, '$purchase' );
$dummyPurchase = new \IPS\nexus\Purchase;
$dummyPurchase->name = \IPS\Member::loggedIn()->language()->addToStack('p_email_preview_example');
$dummyPurchase->member = \IPS\Member::loggedIn();
$dummyPurchase->expires = \IPS\DateTime::create()->add( new \DateInterval('P1M') );
$dummyPurchase->renewals = new \IPS\nexus\Purchase\RenewalTerm( new \IPS\nexus\Money( 10, \IPS\nexus\Customer::loggedIn()->defaultCurrency() ), new \DateInterval('P1M') );
$dummyPurchase->custom_fields = array_fill( 0, \IPS\Db::i()->select( 'MAX(cf_id)', 'nexus_package_fields' )->first(), \IPS\Member::loggedIn()->language()->addToStack('p_email_preview_example') );
$dummyPurchase->licenseKey = new \IPS\nexus\Purchase\LicenseKey\Standard;
$dummyPurchase->licenseKey->key = 'XXXX-XXXX-XXXX-XXXX';
try
{
$output = \IPS\Email::buildFromContent( 'Test', call_user_func( 'IPS\\Theme\\'.$functionName, $dummyPurchase ) )->compileContent( 'html', \IPS\Member::loggedIn() );
}
catch ( \Exception $e )
{
$output = \IPS\Theme::i()->getTemplate( 'global', 'core' )->message( $e->getMessage(), 'error', $e->getMessage(), TRUE, TRUE );
}
\IPS\Output::i()->sendOutput( $output );
}
}
@@ -0,0 +1,184 @@
<?php
/**
* @brief Subscribers
* @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 14 Feb 2018
*/
namespace IPS\nexus\modules\admin\subscriptions;
/* 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;
}
/**
* Subscribers
*/
class _subscribers extends \IPS\Dispatcher\Controller
{
/**
* Execute
*
* @return void
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'subscribers_manage' );
parent::execute();
}
/**
* Manage
*
* @return void
*/
protected function manage()
{
/* Create the table */
$table = new \IPS\Helpers\Table\Db( 'nexus_member_subscriptions', \IPS\Http\Url::internal( 'app=nexus&module=subscriptions&controller=subscribers' ) );
$table->joins = array(
array(
'select' => 'core_members.*',
'from' => 'core_members',
'where' => 'core_members.member_id=nexus_member_subscriptions.sub_member_id'
),
array(
'select' => 'nexus_customers.cm_first_name, nexus_customers.cm_last_name',
'from' => 'nexus_customers',
'where' => 'core_members.member_id=nexus_customers.member_id'
)
);
$table->include = array( 'photo', 'sub_member_id', 'cm_last_name', 'cm_first_name', 'email', 'sub_package_id', 'sub_active', 'sub_start', 'sub_expire');
$table->noSort = array( 'photo');
$table->sortBy = $table->sortBy ?: 'sub_start';
$table->sortDirection = $table->sortDirection ?: 'desc';
$table->langPrefix = 'nexus_';
$table->quickSearch = 'email';
$table->parsers = array(
'photo' => function( $val, $row )
{
return \IPS\Theme::i()->getTemplate('customers')->rowPhoto( \IPS\Member::constructFromData( $row ) );
},
'sub_member_id' => function( $val ) {
return \IPS\Theme::i()->getTemplate('global', 'nexus')->userLink( \IPS\Member::load( $val ) );
},
'sub_package_id' => function( $val ) {
try
{
return \IPS\Theme::i()->getTemplate('subscription', 'nexus')->packageLink( \IPS\nexus\Subscription\Package::load( $val ) );
}
catch( \OutOfRangeException $e ) { }
},
'sub_start' => function( $val ) {
return \IPS\DateTime::ts( $val );
},
'sub_expire' => function( $val ) {
return $val ? \IPS\DateTime::ts( $val ) : '';
},
'sub_active' => function( $val ) {
return \IPS\Theme::i()->getTemplate('subscription', 'nexus')->status( $val );
}
);
$table->rowButtons = function( $row ) {
$return = array();
if ( $row['sub_purchase_id'] )
{
$return['purchase'] = array(
'title' => 'nexus_subs_view_purchase',
'icon' => 'search',
'link' => \IPS\Http\Url::internal( "app=nexus&module=subscriptions&controller=subscribers&do=findPurchase&id=" . $row['sub_id'] )
);
}
return $return;
};
$table->filters = array(
'nexus_subs_filter_active' => array( 'sub_active=1' ),
'nexus_subs_filter_inactive' => array( 'sub_active=0' ),
'nexus_subs_filter_renews' => array( 'sub_active=1 and sub_renews=1' )
);
$table->advancedSearch = array(
'cm_first_name' => \IPS\Helpers\Table\SEARCH_CONTAINS_TEXT,
'cm_last_name' => \IPS\Helpers\Table\SEARCH_CONTAINS_TEXT,
'email' => \IPS\Helpers\Table\SEARCH_CONTAINS_TEXT,
'name' => \IPS\Helpers\Table\SEARCH_CONTAINS_TEXT,
'sub_expire' => \IPS\Helpers\Table\SEARCH_DATE_RANGE,
'sub_start' => \IPS\Helpers\Table\SEARCH_DATE_RANGE,
'sub_package_id' => array( \IPS\Helpers\Table\SEARCH_NODE, array(
'class' => '\IPS\nexus\Subscription\Package',
'zeroVal' => 'any'
) ),
);
/* Breadcrumb? */
if ( isset( \IPS\Request::i()->nexus_sub_package_id ) )
{
try
{
$package = \IPS\nexus\Subscription\Package::load( \IPS\Request::i()->nexus_sub_package_id );
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( "app=nexus&module=subscriptions&controller=subscriptions&id=" . $package->id ), $package->_title );
}
catch( \OutOfRangeException $e ) { }
}
/* Display */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('r__subscribers');
\IPS\Output::i()->output = (string) $table;
}
/**
* Remove a manually added member
*
* @return void
*/
protected function remove()
{
try
{
$sub = \IPS\nexus\Subscription::load( \IPS\Request::i()->id );
$package = \IPS\nexus\Subscription\Package::load( $sub->package_id );
$customer = \IPS\nexus\Customer::load( $sub->member_id );
$package->removeMember( $customer );
\IPS\Output::i()->redirect( $customer->acpUrl(), 'nexus_sub_member_removed' );
}
catch( \OutOfRangeException $e )
{
\IPS\Output::i()->error( 'nexus_sub_no_invoice', '2X378/1', 404, '' );
}
}
/**
* Find an purchase and redirect to it.
*
* @return void
*/
protected function findPurchase()
{
try
{
$sub = \IPS\nexus\Subscription::load( \IPS\Request::i()->id );
$purchase = \IPS\nexus\Purchase::load( $sub->purchase_id );
\IPS\Output::i()->redirect( $purchase->acpUrl() );
}
catch( \OutOfRangeException $e )
{
\IPS\Output::i()->error( 'nexus_sub_no_purchase', '2X378/2', 404, '' );
}
}
}
@@ -0,0 +1,317 @@
<?php
/**
* @brief subscriptions
* @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 09 Feb 2018
*/
namespace IPS\nexus\modules\admin\subscriptions;
/* 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;
}
/**
* subscriptions
*/
class _subscriptions extends \IPS\Node\Controller
{
/**
* Node Class
*/
protected $nodeClass = 'IPS\nexus\Subscription\Package';
/**
* Fetch any additional HTML for this row
*
* @param object $node Node returned from $nodeClass::load()
* @return NULL|string
*/
public function _getRowHtml( $node )
{
$active = \IPS\Db::i()->select( 'COUNT(*)', 'nexus_member_subscriptions', array( 'sub_package_id=? and sub_active=1', $node->id ) )->first();
$inactive = \IPS\Db::i()->select( 'COUNT(*)', 'nexus_member_subscriptions', array( 'sub_package_id=? and sub_active=0', $node->id ) )->first();
return \IPS\Theme::i()->getTemplate( 'subscription', 'nexus' )->rowHtml( $node, $node->priceBlurb(), $active, $inactive );
}
/**
* Execute
*
* @return void
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'subscriptions_manage' );
parent::execute();
}
/**
* Manage
*
* @return void
*/
public function manage()
{
if ( \IPS\Settings::i()->nexus_subs_enabled )
{
\IPS\Output::i()->sidebar['actions']['settings'] = array(
'primary' => false,
'title' => 'settings',
'icon' => 'cog',
'link' => \IPS\Http\Url::internal('app=nexus&module=subscriptions&controller=subscriptions&do=settings')
);
parent::manage();
}
else
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'subscription' )->disabled();
}
}
/**
* Convert a package to a subscription
*
* @return void
*/
public function convertToSubscription()
{
try
{
$package = \IPS\nexus\Package::load( \IPS\Request::i()->id );
}
catch( \OutOfRangeException $ex )
{
}
$renewOptions = array();
if ( $package->renew_options and $_renewOptions = json_decode( $package->renew_options, TRUE ) and is_array( $_renewOptions ) )
{
foreach ( $_renewOptions as $option )
{
$costs = array();
foreach ( $option['cost'] as $cost )
{
$costs[ $cost['currency'] ] = new \IPS\nexus\Money( $cost['amount'], $cost['currency'] );
}
/* Catch any invalid renewal terms, these can occasionally appear from legacy IP.Subscriptions */
try
{
$renewOptions[] = new \IPS\nexus\Purchase\RenewalTerm( $costs, new \DateInterval( "P{$option['term']}" . mb_strtoupper( $option['unit'] ) ), NULL, $option['add'] );
}
catch( \Exception $ex) {}
}
}
$useRenewals = array_pop( $renewOptions );
$form = new \IPS\Helpers\Form;
$form->addHeader('nexus_subs_review_pricing');
$form->add( new \IPS\nexus\Form\Money( 'sp_price', $package->base_price, TRUE ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'sp_renews', !empty( $useRenewals ), FALSE, array( 'togglesOn' => array( 'sp_renew_options' ) ), NULL, NULL, NULL, 'sp_renews' ) );
$form->add( new \IPS\nexus\Form\RenewalTerm( 'sp_renew_options', $useRenewals, NULL, array( 'allCurrencies' => TRUE ), NULL, NULL, NULL, 'sp_renew_options' ) );
$form->add( new \IPS\Helpers\Form\Node( 'sp_tax', (int) $package->tax, FALSE, array( 'class' => 'IPS\nexus\Tax', 'zeroVal' => 'do_not_tax' ) ) );
$form->addHeader('nexus_subs_after_conversion');
$form->add( new \IPS\Helpers\Form\YesNo( 'sp_after_conversion_delete', FALSE, FALSE ) );
if ( $values = $form->values() )
{
$sub = new \IPS\nexus\Subscription\Package;
$sub->enabled = 1;
$sub->tax = $values['sp_tax'] ? $values['p_tax']->id : 0;
$sub->gateways = ( isset( $values['sp_gateways'] ) and is_array( $values['sp_gateways'] ) ) ? implode( ',', array_keys( $values['sp_gateways'] ) ) : '*';
$sub->price = json_encode( $values['sp_price'] );
foreach( array( 'primary_group', 'secondary_group') as $thingsWotAreTheSame )
{
$sub->$thingsWotAreTheSame = $package->$thingsWotAreTheSame;
}
/* Renewal options */
if ( $values['sp_renews'] )
{
$renewOptions = array();
$option = $values['sp_renew_options'];
$term = $option->getTerm();
$sub->renew_options = json_encode( array(
'cost' => $option->cost,
'term' => $term['term'],
'unit' => $term['unit']
) );
}
else
{
$sub->renew_options = '';
}
$sub->save();
/* Language stuffs */
\IPS\Lang::copyCustom( 'nexus', "nexus_package_{$package->id}", "nexus_subs_{$sub->id}" );
\IPS\Lang::copyCustom( 'nexus', "nexus_package_{$package->id}_desc", "nexus_subs_{$sub->id}_desc" );
/* Purchases */
foreach( \IPS\Db::i()->select( '*', 'nexus_purchases', array( 'ps_app=? and ps_type=? and ps_active=1 and ps_cancelled=0 and ps_item_id=?', 'nexus', 'package', $package->id ) ) as $purchase )
{
try
{
$customer = \IPS\nexus\Customer::load( $purchase['ps_member'] );
\IPS\Db::i()->update( 'nexus_purchases', array( 'ps_type' => 'subscription', 'ps_item_id' => $sub->id ), array( 'ps_id=?', $purchase['ps_id'] ) );
$subscription = $sub->addMember( $customer );
$subscription->purchase_id = $purchase['ps_id'];
$subscription->invoice_id = $purchase['ps_original_invoice'];
$subscription->expire = $purchase['ps_expire'];
$subscription->start = $purchase['ps_start'];
$subscription->save();
}
catch( \Exception $e ) { }
}
/* Delete original product */
if ( $values['sp_after_conversion_delete'] )
{
$package->delete();
}
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=nexus&module=subscriptions&controller=subscriptions'), 'nexus_package_converted_lovely' );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('nexus_subs_convert');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'subscription', 'nexus' )->convert( $form, $package );
}
/**
* Enable
*
* @return void
*/
public function enable()
{
\IPS\Settings::i()->changeValues( array( 'nexus_subs_enabled' => true ) );
\IPS\Session::i()->log( 'acplog__subscription_settings' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=nexus&module=subscriptions&controller=subscriptions') );
}
/**
* Add a member for free!
*
* @return void
*/
protected function addMember()
{
$form = new \IPS\Helpers\Form;
$form->add( new \IPS\Helpers\Form\Member( 'nexus_subs_member_to_add', NULL, TRUE, array(), function( $val )
{
if ( $val instanceof \IPS\Member )
{
try
{
$package = \IPS\nexus\Subscription\Package::load( \IPS\Request::i()->id );
$sub = \IPS\nexus\Subscription::loadByMemberAndPackage( $val, $package, TRUE );
/* We have cannot have duplicate active subscriptions, so error out */
throw new \InvalidArgumentException('nexus_subs_add_member_already_subscribed');
}
catch( \OutOfRangeException $e )
{
/* Nothing found, so that's all lovely and good */
}
}
}, NULL, NULL, 'nexus_subs_member_to_add' ) );
if ( $values = $form->values() )
{
$sub = \IPS\nexus\Subscription\Package::load( \IPS\Request::i()->id )->addMember( $values['nexus_subs_member_to_add'] );
$sub->added_manually = 1;
$sub->save();
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=nexus&module=subscriptions&controller=subscriptions'), 'nexus_sub_member_added' );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('nexus_subs_add_member');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'subscription', 'nexus' )->addMemberMessage( $form );
}
/**
* Manage Settings
*
* @return void
*/
protected function settings()
{
$groups = array();
foreach ( \IPS\Member\Group::groups( FALSE, FALSE ) as $group )
{
$groups[ $group->g_id ] = $group->name;
}
$form = new \IPS\Helpers\Form;
$form->addHeader('subscription_basic_settings');
$form->add( new \IPS\Helpers\Form\YesNo( 'nexus_subs_enabled', \IPS\Settings::i()->nexus_subs_enabled, FALSE, array(), NULL, NULL, NULL, 'nexus_subs_enabled' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'nexus_subs_register', \IPS\Settings::i()->nexus_subs_register, FALSE, array(), NULL, NULL, NULL, 'nexus_subs_register' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'nexus_subs_show_public', \IPS\Settings::i()->nexus_subs_show_public, FALSE, array(), NULL, NULL, NULL, 'nexus_subs_show_public' ) );
$form->add( new \IPS\Helpers\Form\Number( 'nexus_subs_invoice_grace', \IPS\Settings::i()->nexus_subs_invoice_grace, FALSE, array( ), NULL, NULL, \IPS\Member::loggedIn()->language()->addToStack('days'), 'nexus_subs_invoice_grace' ) );
$form->add( new \IPS\Helpers\Form\Select( 'nexus_subs_exclude_groups', explode( ',', \IPS\Settings::i()->nexus_subs_exclude_groups ), FALSE, array( 'options' => $groups, 'multiple' => TRUE ) ) );
$form->addHeader('package_upgrade_downgrade');
$form->add( new \IPS\Helpers\Form\YesNo( 'nexus_subs_upgrade_toggle', \IPS\Settings::i()->nexus_subs_upgrade > -1, FALSE, array( 'togglesOn' => array( 'nexus_subs_upgrade' ) ) ) );
$form->add( new \IPS\Helpers\Form\Radio( 'nexus_subs_upgrade', \IPS\Settings::i()->nexus_subs_upgrade, FALSE, array( 'options' => array(
0 => 'p_upgrade_charge_none',
1 => 'p_upgrade_charge_full',
2 => 'p_upgrade_charge_prorate'
) ), NULL, NULL, NULL, 'nexus_subs_upgrade' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'nexus_subs_downgrade_toggle', \IPS\Settings::i()->nexus_subs_downgrade > -1, FALSE, array( 'togglesOn' => array( 'nexus_subs_downgrade' ) ) ) );
$form->add( new \IPS\Helpers\Form\Radio( 'nexus_subs_downgrade', \IPS\Settings::i()->nexus_subs_downgrade, FALSE, array( 'options' => array(
0 => 'p_downgrade_refund_none',
1 => 'p_downgrade_refund_full',
2 => 'p_downgrade_refund_prorate'
)), NULL, NULL, NULL, 'nexus_subs_downgrade' ) );
if ( $values = $form->values() )
{
if ( ! $values['nexus_subs_upgrade_toggle'] )
{
$values['nexus_subs_upgrade'] = -1;
}
if ( ! $values['nexus_subs_downgrade_toggle'] )
{
$values['nexus_subs_downgrade'] = -1;
}
foreach( array( 'nexus_subs_upgrade_toggle', 'nexus_subs_downgrade_toggle' ) as $field )
{
unset( $values[ $field ] );
}
$values['nexus_subs_exclude_groups'] = implode( ',', $values['nexus_subs_exclude_groups'] );
$form->saveAsSettings( $values );
\IPS\Session::i()->log( 'acplog__nexus_subs_settings' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=nexus&module=subscriptions&controller=subscriptions') );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('settings');
\IPS\Output::i()->output = $form;
}
}
@@ -130,13 +130,7 @@ class _incomingemail extends \IPS\Dispatcher\Controller
*/
protected function disablePop3()
{
foreach ( array( 'pop3_server', 'pop3_port', 'pop3_user', 'pop3_password' ) as $k )
{
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => '' ), array( 'conf_key=?', $k ) );
\IPS\Settings::i()->$k = '';
}
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'pop3_server' => '', 'pop3_port' => '', 'pop3_user' => '', 'pop3_password' => '' ) );
\IPS\Session::i()->log( 'acplogs__pop3_settings' );
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => 0 ), array( 'app=? AND `key`=?', 'core', 'pop' ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=nexus&module=support&controller=settings&tab=incomingemail') );
@@ -896,7 +896,7 @@ class _request extends \IPS\nexus\modules\front\support\view
}
$options[ $request->author()->member_id ] = $request->author()->name;
$toggles[ $request->author()->member_id ] = array( 'associated_purchase_' . $request->author()->member_id );
$form->add( new \IPS\Helpers\Form\Radio( 'support_account', $request->author()->member_id, TRUE, array( 'options' => $options, 'toggles' => $toggles, 'parse' => 'none' ) ) );
$form->add( new \IPS\Helpers\Form\Radio( 'support_account', $request->author()->member_id, TRUE, array( 'options' => $options, 'toggles' => $toggles, 'parse' => 'normal' ) ) );
foreach ( $options as $memberId => $memberName )
{
$field = new \IPS\Helpers\Form\Node( 'associated_purchase_' . $memberId, $memberId == $request->author()->member_id ? $request->purchase : NULL, TRUE, array( 'class' => 'IPS\nexus\Purchase', 'forceOwner' => \IPS\Member::load( $memberId ), 'zeroVal' => 'none' ), NULL, NULL, NULL, 'associated_purchase_' . $memberId );
@@ -1002,7 +1002,7 @@ class _request extends \IPS\nexus\modules\front\support\view
$form->add( new \IPS\Helpers\Form\Node( 'support_department', $request->department, TRUE, array( 'class' => 'IPS\nexus\Support\Department', 'url' => $url ) ) );
$form->add( new \IPS\Helpers\Form\Node( 'r_status', $request->status, TRUE, array( 'class' => 'IPS\nexus\Support\Status', 'url' => $url ) ) );
$form->add( new \IPS\Helpers\Form\Node( 'support_severity', $request->severity, TRUE, array( 'class' => 'IPS\nexus\Support\Severity', 'url' => $url ) ) );
$form->add( new \IPS\Helpers\Form\Select( 'r_staff', $request->staff ? $request->staff->member_id : 0, FALSE, array( 'options' => array( 0 => 'unassigned' ) + \IPS\nexus\Support\Request::staff() ) ) );
$form->add( new \IPS\Helpers\Form\Select( 'r_staff', $request->staff ? $request->staff->member_id : 0, FALSE, array( 'parse' => 'normal', 'options' => array( 0 => \IPS\Member::loggedIn()->language()->addToStack('unassigned') ) + \IPS\nexus\Support\Request::staff() ) ) );
if ( $values = $form->values() )
{
@@ -138,7 +138,8 @@ class _requests extends \IPS\Dispatcher\Controller
$order = array();
if ( $groupByDepartment )
{
$order[] = 'dpt_position';
$order[] = 'nexus_support_staff_dpt_order.dpt_position';
$order[] = 'nexus_support_departments.dpt_position'; // This is to prevent an issue if two departments have the same position (which may be the case if new departments have been created since the user set their preferred order)
}
$honorSeverities = ( !isset( \IPS\Request::i()->cookie['support_honor_severities'] ) or \IPS\Request::i()->cookie['support_honor_severities'] );
if ( $honorSeverities )
@@ -525,19 +526,26 @@ class _requests extends \IPS\Dispatcher\Controller
/* Init */
\IPS\Dispatcher::i()->checkAcpPermission( 'requests_create' );
$steps = array();
$url = \IPS\Http\Url::internal('app=nexus&module=support&controller=requests&do=create');
$initialData = NULL;
if ( isset( \IPS\Request::i()->member ) )
{
$initialData = array( 'member' => \IPS\Request::i()->member );
$url = $url->setQueryString( 'member', \IPS\Request::i()->member );
}
/* Owner */
if ( !isset( \IPS\Request::i()->member ) )
{
$steps['request_owner'] = function( $data )
$steps['request_owner'] = function( $data ) use ( $url )
{
$form = new \IPS\Helpers\Form( 'owner', 'continue' );
$form->add( new \IPS\Helpers\Form\Radio( 'request_owner_type', 'member', TRUE, array(
$form = new \IPS\Helpers\Form( 'owner', 'continue', $url->setQueryString( '_step', 'request_owner' ) );
$form->add( new \IPS\Helpers\Form\Radio( 'request_owner_type', isset( $data['email'] ) ? 'email' : 'member', TRUE, array(
'options' => array( 'member' => 'request_owner_member', 'email' => 'request_owner_email' ),
'toggles' => array( 'member' => array( 'request_owner_member' ), 'email' => array( 'request_owner_email' ) )
) ) );
$form->add( new \IPS\Helpers\Form\Member( 'request_owner_member', isset( \IPS\Request::i()->member ) ? \IPS\Member::load( \IPS\Request::i()->member ) : NULL, FALSE, array(), NULL, NULL, NULL, 'request_owner_member' ) );
$form->add( new \IPS\Helpers\Form\Email( 'request_owner_email', NULL, FALSE, array(), NULL, NULL, NULL, 'request_owner_email' ) );
$form->add( new \IPS\Helpers\Form\Member( 'request_owner_member', isset( $data['member'] ) ? \IPS\Member::load( $data['member'] ) : ( isset( \IPS\Request::i()->member ) ? \IPS\Member::load( \IPS\Request::i()->member ) : NULL ), FALSE, array(), NULL, NULL, NULL, 'request_owner_member' ) );
$form->add( new \IPS\Helpers\Form\Email( 'request_owner_email', isset( $data['email'] ) ? $data['email'] : NULL, FALSE, array(), NULL, NULL, NULL, 'request_owner_email' ) );
if ( $values = $form->values() )
{
if ( $values['request_owner_type'] === 'member' )
@@ -579,7 +587,7 @@ class _requests extends \IPS\Dispatcher\Controller
$stockActions = \IPS\nexus\Support\StockAction::roots();
if ( count( $stockActions ) )
{
$steps['stock_action'] = function( $data ) use ( $stockActions )
$steps['stock_action'] = function( $data ) use ( $stockActions, $url )
{
$options = array( 0 => 'none' );
foreach ( $stockActions as $action )
@@ -587,8 +595,8 @@ class _requests extends \IPS\Dispatcher\Controller
$options[ $action->id ] = $action->_title;
}
$form = new \IPS\Helpers\Form( 'stock_action', 'continue' );
$form->add( new \IPS\Helpers\Form\Radio( 'stock_action', 0, FALSE, array(
$form = new \IPS\Helpers\Form( 'stock_action', 'continue', $url->setQueryString( '_step', 'stock_action' ) );
$form->add( new \IPS\Helpers\Form\Radio( 'stock_action', isset( $data['stock_action'] ) ? $data['stock_action'] : 0, FALSE, array(
'options' => $options
) ) );
if ( $values = $form->values() )
@@ -602,7 +610,7 @@ class _requests extends \IPS\Dispatcher\Controller
}
/* Request Details */
$steps['request_details'] = function( $data ) use ( $stockActions )
$steps['request_details'] = function( $data ) use ( $stockActions, $url )
{
if ( !isset( $data['member'] ) AND isset( \IPS\Request::i()->member ) )
{
@@ -615,16 +623,16 @@ class _requests extends \IPS\Dispatcher\Controller
$stockAction = $stockActions[ $data['stock_action'] ];
}
$form = new \IPS\Helpers\Form( 'request_details', 'continue' );
$form->add( new \IPS\Helpers\Form\Text( 'support_title', NULL, TRUE ) );
$form->add( new \IPS\Helpers\Form\Node( 'support_department', $stockAction ? $stockAction->department : NULL, TRUE, array( 'class' => 'IPS\nexus\Support\Department' ) ) );
$form = new \IPS\Helpers\Form( 'request_details', 'continue', $url->setQueryString( '_step', 'request_details' ) );
$form->add( new \IPS\Helpers\Form\Text( 'support_title', isset( $data['title'] ) ? $data['title'] : NULL, TRUE ) );
$form->add( new \IPS\Helpers\Form\Node( 'support_department', isset( $data['department'] ) ? $data['department'] : ( $stockAction ? $stockAction->department : NULL ), TRUE, array( 'class' => 'IPS\nexus\Support\Department' ) ) );
if ( isset( $data['member'] ) )
{
$form->add( new \IPS\Helpers\Form\Node( 'support_purchase', 0, FALSE, array( 'class' => 'IPS\nexus\Purchase', 'forceOwner' => \IPS\Member::load( $data['member'] ), 'zeroVal' => 'none' ) ) );
$form->add( new \IPS\Helpers\Form\Node( 'support_purchase', isset( $data['purchase'] ) ? $data['purchase'] : 0, FALSE, array( 'class' => 'IPS\nexus\Purchase', 'forceOwner' => \IPS\Member::load( $data['member'] ), 'zeroVal' => 'none' ) ) );
}
$form->add( new \IPS\Helpers\Form\Node( 'r_status', $stockAction ? $stockAction->status : \IPS\nexus\Support\Status::load( TRUE, 'status_default_staff' ), TRUE, array( 'class' => 'IPS\nexus\Support\Status' ) ) );
$form->add( new \IPS\Helpers\Form\Node( 'support_severity', \IPS\nexus\Support\Severity::load( TRUE, 'sev_default' ), TRUE, array( 'class' => 'IPS\nexus\Support\Severity' ) ) );
$form->add( new \IPS\Helpers\Form\Select( 'r_staff', 0, FALSE, array( 'options' => array( 0 => 'unassigned' ) + \IPS\nexus\Support\Request::staff() ) ) );
$form->add( new \IPS\Helpers\Form\Node( 'r_status', isset( $data['status'] ) ? $data['status'] : ( $stockAction ? $stockAction->status : \IPS\nexus\Support\Status::load( TRUE, 'status_default_staff' ) ), TRUE, array( 'class' => 'IPS\nexus\Support\Status' ) ) );
$form->add( new \IPS\Helpers\Form\Node( 'support_severity', isset( $data['severity'] ) ? $data['severity'] : \IPS\nexus\Support\Severity::load( TRUE, 'sev_default' ), TRUE, array( 'class' => 'IPS\nexus\Support\Severity' ) ) );
$form->add( new \IPS\Helpers\Form\Select( 'r_staff', isset( $data['staff'] ) ? $data['staff'] : 0, FALSE, array( 'parse' => 'normal', 'options' => array( 0 => \IPS\Member::loggedIn()->language()->addToStack('unassigned') ) + \IPS\nexus\Support\Request::staff() ) ) );
if ( $values = $form->values() )
{
$data['title'] = $values['support_title'];
@@ -645,15 +653,15 @@ class _requests extends \IPS\Dispatcher\Controller
$customFields = \IPS\nexus\Support\CustomField::roots();
if ( count( $customFields ) )
{
$steps['custom_support_fields'] = function( $data )
$steps['custom_support_fields'] = function( $data ) use ( $url )
{
$customFields = \IPS\nexus\Support\CustomField::roots( NULL, NULL, array( "sf_departments='*' OR " . \IPS\Db::i()->findInSet( 'sf_departments', array( $data['department'] ) ) ) );
if ( count( $customFields ) )
{
$form = new \IPS\Helpers\Form( 'custom_fields', 'continue' );
$form = new \IPS\Helpers\Form( 'custom_fields', 'continue', $url->setQueryString( '_step', 'custom_support_fields' ) );
foreach ( $customFields as $field )
{
$form->add( $field->buildHelper() );
$form->add( $field->buildHelper( isset( $data['custom_fields']["nexus_cfield_{$field->id}"] ) ? $data['custom_fields']["nexus_cfield_{$field->id}"] : NULL ) );
}
if ( $values = $form->values() )
{
@@ -670,7 +678,7 @@ class _requests extends \IPS\Dispatcher\Controller
}
/* Your Message */
$steps['your_message'] = function( $data ) use ( $stockActions )
$steps['your_message'] = function( $data ) use ( $stockActions, $url )
{
$stockAction = NULL;
if ( isset( $data['stock_action'] ) and isset( $stockActions[ $data['stock_action'] ] ) )
@@ -701,7 +709,7 @@ class _requests extends \IPS\Dispatcher\Controller
$defaultContent = NULL;
}
$form = new \IPS\Helpers\Form( 'your_message' );
$form = new \IPS\Helpers\Form( 'your_message', 'save', $url->setQueryString( '_step', 'your_message' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'support_email_customer', TRUE, TRUE, array( 'togglesOn' => array( 'support_create_to', 'support_create_cc', 'support_create_bcc' ) ) ) );
$form->add( new \IPS\Helpers\Form\Email( 'to', isset( $data['member'] ) ? \IPS\Member::load( $data['member'] )->email : $data['email'], NULL, array(), NULL, NULL, NULL, 'support_create_to' ) );
$form->add( new \IPS\Helpers\Form\Text( 'cc', array(), FALSE, array( 'autocomplete' => array( 'unique' => TRUE, 'forceLower' => TRUE ) ), array( 'IPS\nexus\Support\Request', '_validateEmail' ), NULL, NULL, 'support_create_cc' ) );
@@ -845,16 +853,7 @@ class _requests extends \IPS\Dispatcher\Controller
return $form;
};
/* Set member */
$url = \IPS\Http\Url::internal('app=nexus&module=support&controller=requests&do=create');
$initialData = NULL;
if ( isset( \IPS\Request::i()->member ) )
{
$initialData = array( 'member' => \IPS\Request::i()->member );
$url = $url->setQueryString( 'member', \IPS\Request::i()->member );
}
/* Display */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('create_support_request');
\IPS\Output::i()->output = new \IPS\Helpers\Wizard( $steps, $url, TRUE, $initialData );
@@ -50,9 +50,7 @@ class _severities extends \IPS\Node\Controller
if ( isset( \IPS\Request::i()->nexus_severities ) )
{
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => \IPS\Request::i()->nexus_severities ), array( 'conf_key=?', 'nexus_severities' ) );
\IPS\Settings::i()->nexus_severities = \IPS\Request::i()->nexus_severities;
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'nexus_severities' => \IPS\Request::i()->nexus_severities ) );
\IPS\Session::i()->log( 'acplogs__severity_settings' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=nexus&module=support&controller=settings&tab=severities') );
}
@@ -58,6 +58,26 @@ class _volume extends \IPS\Dispatcher\Controller
$chart->addSeries( $department->_title, 'number', 'COUNT(*)', TRUE, $department->id );
}
$chart->tableInclude = array( 'r_id', 'r_title', 'r_member', 'r_department', 'r_status', 'r_started', 'r_last_reply', 'r_replies' );
$chart->tableParsers = array(
'r_member' => function( $val ) {
return \IPS\Theme::i()->getTemplate('global', 'nexus')->userLink( \IPS\Member::load( $val ) );
},
'r_department' => function( $val ) {
return \IPS\Member::loggedIn()->language()->addToStack( 'nexus_department_' . $val );
},
'r_status' => function( $val, $row )
{
return \IPS\Member::loggedIn()->language()->addToStack( 'nexus_status_' . $val . '_admin' );
},
'r_started' => function( $val ) {
return \IPS\DateTime::ts( $val );
},
'r_last_reply' => function( $val ) {
return \IPS\DateTime::ts( $val );
}
);
\IPS\Output::i()->output = (string) $chart;
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__nexus_support_volume');
}