diff --git a/code/controllers/EventRegisterController.php b/code/controllers/EventRegisterController.php index 3271b95..823911b 100644 --- a/code/controllers/EventRegisterController.php +++ b/code/controllers/EventRegisterController.php @@ -5,151 +5,157 @@ * * @package silverstripe-eventmanagement */ -class EventRegisterController extends Page_Controller { - - public static $url_handlers = array( - '' => 'index' - ); - - public static $allowed_actions = array( - 'RegisterForm', - 'confirm' - ); - - protected $parent; - protected $datetime; - - /** - * Constructs a new controller for creating a registration. - * - * @param ContentController $parent - * @param RegistrableDateTime $datetime - */ - public function __construct($parent, $datetime) { - $this->parent = $parent; - $this->datetime = $datetime; - - parent::__construct($parent->data()); - } - - public function init() { - parent::init(); - - if ($this->datetime->Event()->RequireLoggedIn && !Member::currentUserID()) { - return Security::permissionFailure($this, array( - 'default' => 'Please log in to register for this event.' - )); - } - - $form = $this->RegisterForm(); - $expiry = $form->getExpiryDateTime(); - - if ($expiry && $expiry->InPast()) { - $form->getSession()->Registration()->delete(); - $form->getSession()->delete(); - - $message = _t('EventManagement.REGSESSIONEXPIRED', 'Your' - . ' registration expired before it was completed. Please' - . ' try ordering your tickets again.'); - - $form->sessionMessage($message, 'bad'); - - $this->redirect($this->Link()); - } - else { - $form->clearMessage(); - } - } - - public function index() { - $datetime = $this->datetime; - $exclude = null; - - // If we have a current multiform ID, then exclude the linked - // registration from the capacity calculation. - if (isset($_GET['MultiFormSessionID'])) { - $exclude = $this->RegisterForm()->getSession()->RegistrationID; - } - - if ($datetime->getStartDateTime()->getTimestamp() < time()) { - $data = array( - 'Title' => $datetime->Event()->Title . ' Has Already Happened', - 'Content' => '
You can no longer register for this event.
' - ); - } elseif ($datetime->getRemainingCapacity($exclude)) { - $data = array( - 'Title' => 'Register For ' . $datetime->Event()->Title, - 'Form' => $this->RegisterForm() - ); - } else { - $data = array( - 'Title' => $datetime->Event()->Title . ' Is Full', - 'Content' => 'There are no more places available at this event.
' - ); - } - - return $this->getViewer('index')->process($this->customise($data)); - } - - /** - * Handles a user clicking on a registration confirmation link in an email. - */ - public function confirm($request) { - $id = $request->param('ID'); - $token = $request->getVar('token'); - - if (!$rego = DataObject::get_by_id('EventRegistration', $id)) { - return $this->httpError(404); - } - - if ($rego->Token != $token) { - return $this->httpError(403); - } - - if ($rego->Status != 'Unconfirmed') { - return $this->redirect($rego->Link()); - } - - try { - $rego->Status = 'Valid'; - $rego->write(); - - EventRegistrationDetailsEmail::factory($rego)->send(); - } catch (ValidationException $e) { - return array( - 'Title' => 'Could Not Confirm Registration', - 'Content' => '' . $e->getResult()->message() . '
' - ); - } - - return array( - 'Title' => $this->datetime->Event()->AfterConfirmTitle, - 'Content' => $this->datetime->Event()->obj('AfterConfirmContent') - ); - } - - /** - * @return RegistrableDateTime - */ - public function getDateTime() { - return $this->datetime; - } - - /** - * @return EventRegisterForm - */ - public function RegisterForm() { - return new EventRegisterForm($this, 'RegisterForm'); - } - - /** - * @param string $action - * @return string - */ - public function Link($action = null) { - return Controller::join_links( - $this->parent->Link(), 'register', $action - ); - } - +class EventRegisterController extends Page_Controller +{ + + public static $url_handlers = array( + '' => 'index' + ); + + public static $allowed_actions = array( + 'RegisterForm', + 'confirm' + ); + + protected $parent; + protected $datetime; + + /** + * Constructs a new controller for creating a registration. + * + * @param ContentController $parent + * @param RegistrableDateTime $datetime + */ + public function __construct($parent, $datetime) + { + $this->parent = $parent; + $this->datetime = $datetime; + + parent::__construct($parent->data()); + } + + public function init() + { + parent::init(); + + if ($this->datetime->Event()->RequireLoggedIn && !Member::currentUserID()) { + return Security::permissionFailure($this, array( + 'default' => 'Please log in to register for this event.' + )); + } + + $form = $this->RegisterForm(); + $expiry = $form->getExpiryDateTime(); + + if ($expiry && $expiry->InPast()) { + $form->getSession()->Registration()->delete(); + $form->getSession()->delete(); + + $message = _t('EventManagement.REGSESSIONEXPIRED', 'Your' + . ' registration expired before it was completed. Please' + . ' try ordering your tickets again.'); + + $form->sessionMessage($message, 'bad'); + + $this->redirect($this->Link()); + } else { + $form->clearMessage(); + } + } + + public function index() + { + $datetime = $this->datetime; + $exclude = null; + + // If we have a current multiform ID, then exclude the linked + // registration from the capacity calculation. + if (isset($_GET['MultiFormSessionID'])) { + $exclude = $this->RegisterForm()->getSession()->RegistrationID; + } + + if ($datetime->getStartDateTime()->getTimestamp() < time()) { + $data = array( + 'Title' => $datetime->Event()->Title . ' Has Already Happened', + 'Content' => 'You can no longer register for this event.
' + ); + } elseif ($datetime->getRemainingCapacity($exclude)) { + $data = array( + 'Title' => 'Register For ' . $datetime->Event()->Title, + 'Form' => $this->RegisterForm() + ); + } else { + $data = array( + 'Title' => $datetime->Event()->Title . ' Is Full', + 'Content' => 'There are no more places available at this event.
' + ); + } + + return $this->getViewer('index')->process($this->customise($data)); + } + + /** + * Handles a user clicking on a registration confirmation link in an email. + */ + public function confirm($request) + { + $id = $request->param('ID'); + $token = $request->getVar('token'); + + if (!$rego = DataObject::get_by_id('EventRegistration', $id)) { + return $this->httpError(404); + } + + if ($rego->Token != $token) { + return $this->httpError(403); + } + + if ($rego->Status != 'Unconfirmed') { + return $this->redirect($rego->Link()); + } + + try { + $rego->Status = 'Valid'; + $rego->write(); + + EventRegistrationDetailsEmail::factory($rego)->send(); + } catch (ValidationException $e) { + return array( + 'Title' => 'Could Not Confirm Registration', + 'Content' => '' . $e->getResult()->message() . '
' + ); + } + + return array( + 'Title' => $this->datetime->Event()->AfterConfirmTitle, + 'Content' => $this->datetime->Event()->obj('AfterConfirmContent') + ); + } + + /** + * @return RegistrableDateTime + */ + public function getDateTime() + { + return $this->datetime; + } + + /** + * @return EventRegisterForm + */ + public function RegisterForm() + { + return new EventRegisterForm($this, 'RegisterForm'); + } + + /** + * @param string $action + * @return string + */ + public function Link($action = null) + { + return Controller::join_links( + $this->parent->Link(), 'register', $action + ); + } } diff --git a/code/controllers/EventRegistrationDetailsController.php b/code/controllers/EventRegistrationDetailsController.php index 200dc35..127b4e1 100644 --- a/code/controllers/EventRegistrationDetailsController.php +++ b/code/controllers/EventRegistrationDetailsController.php @@ -5,133 +5,143 @@ * * @package silverstripe-eventmanagement */ -class EventRegistrationDetailsController extends Page_Controller { - - public static $url_handlers = array( - '' => 'index' - ); - - public static $allowed_actions = array( - 'ticketfile' - ); - - protected $parent; - protected $registration; - protected $message; - - public function __construct($parent, $registration) { - $this->parent = $parent; - $this->registration = $registration; - - parent::__construct($parent->data()->customise(array( - 'Title' => $this->Title() - ))); - } - - public function init() { - parent::init(); - - $request = $this->request; - $rego = $this->registration; - - $hasToken = $request->getVar('token') == $rego->Token; - $hasMemb = $rego->MemberID && Member::currentUserID() == $rego->MemberID; - - if (!$hasToken && !$hasMemb) { - return Security::permissionFailure($this); - } - - // If the registration has passed the confirmation expiry date, then - // cancel it. - if ($time = $this->registration->ConfirmTimeLimit()) { - if ($time->InPast()) { - $this->registration->Status = 'Canceled'; - $this->registration->write(); - } - } - - $message = "EventRegistration.{$rego->ID}.message"; - $this->message = Session::get($message); - Session::clear($message); - } - - public function index() { - return $this->getViewer('index')->process($this); - } - - public function ticketfile() { - if (!$this->HasTicketFile() || $this->registration->Status != 'Valid') { - $this->httpError(404); - } - - $generator = $this->registration->Time()->Event()->TicketGenerator; - $generator = new $generator(); - - $path = $generator->generateTicketFileFor($this->registration); - $path = Director::getAbsFile($path); - $name = $generator->getTicketFilenameFor($this->registration); - $mime = $generator->getTicketMimeTypeFor($this->registration); - - if (!$path || !file_exists($path)) { - $this->httpError(404, 'The ticket file could not be generated.'); - } - - return SS_HTTPRequest::send_file(file_get_contents($path), $name, $mime); - } - - /** - * @return EventRegistration - */ - public function Registration() { - return $this->registration; - } - - /** - * @return string - */ - public function Title() { - return 'Registration Details for ' . $this->registration->Time()->Event()->Title; - } - - /** - * @return string - */ - public function Message() { - return $this->message; - } - - /** - * @return EventRegistrationTicketsTableField - */ - public function TicketsTable() { - $rego = $this->registration; - $table = new EventRegistrationTicketsTableField('Tickets', $rego->Time()); - - $table->setReadonly(true); - $table->setShowUnavailableTickets(false); - $table->setShowUnselectedTickets(false); - $table->setForceTotalRow(true); - $table->setValue($rego->Tickets()); - $table->setTotal($rego->Total); - - return $table; - } - - /** - * @return bool - */ - public function HasTicketFile() { - return (bool) $this->registration->Time()->Event()->TicketGenerator; - } - - /** - * @return string - */ - public function Link($action = null) { - return Controller::join_links( - $this->parent->Link(), 'registration', $this->registration->ID, $action, - '?token='. $this->registration->Token - ); - } - -} \ No newline at end of file +class EventRegistrationDetailsController extends Page_Controller +{ + + public static $url_handlers = array( + '' => 'index' + ); + + public static $allowed_actions = array( + 'ticketfile' + ); + + protected $parent; + protected $registration; + protected $message; + + public function __construct($parent, $registration) + { + $this->parent = $parent; + $this->registration = $registration; + + parent::__construct($parent->data()->customise(array( + 'Title' => $this->Title() + ))); + } + + public function init() + { + parent::init(); + + $request = $this->request; + $rego = $this->registration; + + $hasToken = $request->getVar('token') == $rego->Token; + $hasMemb = $rego->MemberID && Member::currentUserID() == $rego->MemberID; + + if (!$hasToken && !$hasMemb) { + return Security::permissionFailure($this); + } + + // If the registration has passed the confirmation expiry date, then + // cancel it. + if ($time = $this->registration->ConfirmTimeLimit()) { + if ($time->InPast()) { + $this->registration->Status = 'Canceled'; + $this->registration->write(); + } + } + + $message = "EventRegistration.{$rego->ID}.message"; + $this->message = Session::get($message); + Session::clear($message); + } + + public function index() + { + return $this->getViewer('index')->process($this); + } + + public function ticketfile() + { + if (!$this->HasTicketFile() || $this->registration->Status != 'Valid') { + $this->httpError(404); + } + + $generator = $this->registration->Time()->Event()->TicketGenerator; + $generator = new $generator(); + + $path = $generator->generateTicketFileFor($this->registration); + $path = Director::getAbsFile($path); + $name = $generator->getTicketFilenameFor($this->registration); + $mime = $generator->getTicketMimeTypeFor($this->registration); + + if (!$path || !file_exists($path)) { + $this->httpError(404, 'The ticket file could not be generated.'); + } + + return SS_HTTPRequest::send_file(file_get_contents($path), $name, $mime); + } + + /** + * @return EventRegistration + */ + public function Registration() + { + return $this->registration; + } + + /** + * @return string + */ + public function Title() + { + return 'Registration Details for ' . $this->registration->Time()->Event()->Title; + } + + /** + * @return string + */ + public function Message() + { + return $this->message; + } + + /** + * @return EventRegistrationTicketsTableField + */ + public function TicketsTable() + { + $rego = $this->registration; + $table = new EventRegistrationTicketsTableField('Tickets', $rego->Time()); + + $table->setReadonly(true); + $table->setShowUnavailableTickets(false); + $table->setShowUnselectedTickets(false); + $table->setForceTotalRow(true); + $table->setValue($rego->Tickets()); + $table->setTotal($rego->Total); + + return $table; + } + + /** + * @return bool + */ + public function HasTicketFile() + { + return (bool) $this->registration->Time()->Event()->TicketGenerator; + } + + /** + * @return string + */ + public function Link($action = null) + { + return Controller::join_links( + $this->parent->Link(), 'registration', $this->registration->ID, $action, + '?token='. $this->registration->Token + ); + } +} diff --git a/code/controllers/EventTimeDetailsController.php b/code/controllers/EventTimeDetailsController.php index 0554b42..7a6c8d2 100644 --- a/code/controllers/EventTimeDetailsController.php +++ b/code/controllers/EventTimeDetailsController.php @@ -5,90 +5,100 @@ * * @package silverstripe-eventmanagement */ -class EventTimeDetailsController extends Page_Controller { +class EventTimeDetailsController extends Page_Controller +{ - public static $url_handlers = array( - '' => 'index' - ); + public static $url_handlers = array( + '' => 'index' + ); - public static $allowed_actions = array( - 'register', - 'unregister' - ); + public static $allowed_actions = array( + 'register', + 'unregister' + ); - protected $parent; - protected $time; + protected $parent; + protected $time; - public function __construct($parent, $time) { - $this->parent = $parent; - $this->time = $time; + public function __construct($parent, $time) + { + $this->parent = $parent; + $this->time = $time; - parent::__construct($parent->data()->customise(array( - 'Title' => $this->Title() - ))); - } + parent::__construct($parent->data()->customise(array( + 'Title' => $this->Title() + ))); + } - public function index() { - return $this->getViewer('index')->process($this); - } + public function index() + { + return $this->getViewer('index')->process($this); + } - /** - * @return EventRegisterController - */ - public function register() { - return new EventRegisterController($this, $this->time); - } + /** + * @return EventRegisterController + */ + public function register() + { + return new EventRegisterController($this, $this->time); + } - /** - * @return EventUnregisterController - */ - public function unregister() { - return new EventUnregisterController($this, $this->time); - } + /** + * @return EventUnregisterController + */ + public function unregister() + { + return new EventUnregisterController($this, $this->time); + } - /** - * @return RegistrableDateTime - */ - public function DateTime() { - return $this->time; - } + /** + * @return RegistrableDateTime + */ + public function DateTime() + { + return $this->time; + } - /** - * @return string - */ - public function Title() { - return $this->DateTime()->Event()->Title; - } + /** + * @return string + */ + public function Title() + { + return $this->DateTime()->Event()->Title; + } - /** - * @return bool - */ - public function EventInFuture() { - return time() < $this->DateTime()->getStartDateTime()->getTimestamp(); - } + /** + * @return bool + */ + public function EventInFuture() + { + return time() < $this->DateTime()->getStartDateTime()->getTimestamp(); + } - /** - * @return bool - */ - public function EventIsFull() { - return !$this->DateTime()->getRemainingCapacity(); - } + /** + * @return bool + */ + public function EventIsFull() + { + return !$this->DateTime()->getRemainingCapacity(); + } - /** - * @return Form - */ - public function UnregisterForm() { - return $this->unregister()->UnregisterForm(); - } + /** + * @return Form + */ + public function UnregisterForm() + { + return $this->unregister()->UnregisterForm(); + } - /** - * @param string $action - * @return string - */ - public function Link($action = null) { - return Controller::join_links( - $this->parent->Link(), 'details', $this->time->ID, $action - ); - } - -} \ No newline at end of file + /** + * @param string $action + * @return string + */ + public function Link($action = null) + { + return Controller::join_links( + $this->parent->Link(), 'details', $this->time->ID, $action + ); + } +} diff --git a/code/controllers/EventUnregisterController.php b/code/controllers/EventUnregisterController.php index 89c2a8a..3b231d3 100644 --- a/code/controllers/EventUnregisterController.php +++ b/code/controllers/EventUnregisterController.php @@ -4,145 +4,151 @@ * * @package silverstripe-eventmanagement */ -class EventUnregisterController extends Page_Controller { - - public static $allowed_actions = array( - 'UnregisterForm', - 'afterunregistration', - 'confirm' - ); - - protected $parent; - protected $time; - - /** - * Constructs a new controller for deleting a registration. - * - * @param Controller $parent - * @param RegistrableDateTiem $time - */ - public function __construct($parent, $time) { - $this->parent = $parent; - $this->time = $time; - - parent::__construct($parent->data()); - } - - /** - * @return Form - */ - public function UnregisterForm() { - return new Form( - $this, - 'UnregisterForm', - new FieldList(new EmailField( - 'Email', _t('EventManagement.EMAIL_ADDRESS', 'Email address') - )), - new FieldList(new FormAction( - 'doUnregister', _t('EventManagement.UN_REGISTER', 'Un-register') - )), - new RequiredFields('Email') - ); - } - - /** - * @param array $data - * @param Form $form - */ - public function doUnregister($data, $form) { - $regos = $this->time->Registrations()->filter('Email', $data['Email']); - - if (!$regos || !count($regos)) { - $form->sessionMessage(_t( - 'EventManager.NOREGFOREMAIL', - 'No registrations for the email you entered could be found.'), - 'bad'); - return $this->redirectBack(); - } - - if ($this->time->Event()->UnRegEmailConfirm) { - $addr = $data['Email']; - $email = new Email(); - $registration = $regos->First(); - - $email->setTo($addr); - $email->setSubject(sprintf( - _t('EventManagement.CONFIRMUNREGFOR', 'Confirm Un-Registration For %s (%s)'), - $this->time->Event()->Title, SiteConfig::current_site_config()->Title)); - - $email->setTemplate('EventUnregistrationConfirmationEmail'); - $email->populateTemplate(array( - 'Registration' => $registration, - 'Time' => $this->time, - 'SiteConfig' => SiteConfig::current_site_config(), - 'ConfirmLink' => Director::absoluteURL(Controller::join_links( - $this->Link(), 'confirm', - '?email=' . urlencode($addr), '?token=' . $registration->Token)) - )); - - $email->send(); - } else { - foreach ($regos as $rego) { - $rego->Status = 'Canceled'; - $rego->write(); - } - } - - $this->redirect($this->Link('afterunregistration')); - } - - /** - * @return array - */ - public function afterunregistration() { - return array( - 'Title' => $this->time->Event()->AfterUnregTitle, - 'Content' => $this->time->Event()->obj('AfterUnregContent') - ); - } - - /** - * @return array - */ - public function confirm($request) { - $email = $request->getVar('email'); - $token = $request->getVar('token'); - - // Attempt to get at least one registration with the email and token, - // and if we do then delete all the other ones as well. - $first = DataObject::get_one('EventRegistration', sprintf( - '"Email" = \'%s\' AND "Token" = \'%s\'', - Convert::raw2sql($email), Convert::raw2sql($token) - )); - - if (!$first) { - return $this->httpError(404); - } - - // Now delete all registrations with the same email. - $regos = DataObject::get('EventRegistration', sprintf( - '"Email" = \'%s\'', Convert::raw2sql($email) - )); - - foreach ($regos as $rego) { - $rego->Status = 'Canceled'; - $rego->write(); - } - - return array( - 'Title' => $this->time->Event()->AfterConfUnregTitle, - 'Content' => $this->time->Event()->obj('AfterConfUnregContent') - ); - } - - /** - * @param string $action - * @return string - */ - public function Link($action = null) { - return Controller::join_links( - $this->parent->Link(), 'unregister', $action - ); - } - -} \ No newline at end of file +class EventUnregisterController extends Page_Controller +{ + + public static $allowed_actions = array( + 'UnregisterForm', + 'afterunregistration', + 'confirm' + ); + + protected $parent; + protected $time; + + /** + * Constructs a new controller for deleting a registration. + * + * @param Controller $parent + * @param RegistrableDateTiem $time + */ + public function __construct($parent, $time) + { + $this->parent = $parent; + $this->time = $time; + + parent::__construct($parent->data()); + } + + /** + * @return Form + */ + public function UnregisterForm() + { + return new Form( + $this, + 'UnregisterForm', + new FieldList(new EmailField( + 'Email', _t('EventManagement.EMAIL_ADDRESS', 'Email address') + )), + new FieldList(new FormAction( + 'doUnregister', _t('EventManagement.UN_REGISTER', 'Un-register') + )), + new RequiredFields('Email') + ); + } + + /** + * @param array $data + * @param Form $form + */ + public function doUnregister($data, $form) + { + $regos = $this->time->Registrations()->filter('Email', $data['Email']); + + if (!$regos || !count($regos)) { + $form->sessionMessage(_t( + 'EventManager.NOREGFOREMAIL', + 'No registrations for the email you entered could be found.'), + 'bad'); + return $this->redirectBack(); + } + + if ($this->time->Event()->UnRegEmailConfirm) { + $addr = $data['Email']; + $email = new Email(); + $registration = $regos->First(); + + $email->setTo($addr); + $email->setSubject(sprintf( + _t('EventManagement.CONFIRMUNREGFOR', 'Confirm Un-Registration For %s (%s)'), + $this->time->Event()->Title, SiteConfig::current_site_config()->Title)); + + $email->setTemplate('EventUnregistrationConfirmationEmail'); + $email->populateTemplate(array( + 'Registration' => $registration, + 'Time' => $this->time, + 'SiteConfig' => SiteConfig::current_site_config(), + 'ConfirmLink' => Director::absoluteURL(Controller::join_links( + $this->Link(), 'confirm', + '?email=' . urlencode($addr), '?token=' . $registration->Token)) + )); + + $email->send(); + } else { + foreach ($regos as $rego) { + $rego->Status = 'Canceled'; + $rego->write(); + } + } + + $this->redirect($this->Link('afterunregistration')); + } + + /** + * @return array + */ + public function afterunregistration() + { + return array( + 'Title' => $this->time->Event()->AfterUnregTitle, + 'Content' => $this->time->Event()->obj('AfterUnregContent') + ); + } + + /** + * @return array + */ + public function confirm($request) + { + $email = $request->getVar('email'); + $token = $request->getVar('token'); + + // Attempt to get at least one registration with the email and token, + // and if we do then delete all the other ones as well. + $first = DataObject::get_one('EventRegistration', sprintf( + '"Email" = \'%s\' AND "Token" = \'%s\'', + Convert::raw2sql($email), Convert::raw2sql($token) + )); + + if (!$first) { + return $this->httpError(404); + } + + // Now delete all registrations with the same email. + $regos = DataObject::get('EventRegistration', sprintf( + '"Email" = \'%s\'', Convert::raw2sql($email) + )); + + foreach ($regos as $rego) { + $rego->Status = 'Canceled'; + $rego->write(); + } + + return array( + 'Title' => $this->time->Event()->AfterConfUnregTitle, + 'Content' => $this->time->Event()->obj('AfterConfUnregContent') + ); + } + + /** + * @param string $action + * @return string + */ + public function Link($action = null) + { + return Controller::join_links( + $this->parent->Link(), 'unregister', $action + ); + } +} diff --git a/code/dataobjects/EventInvitation.php b/code/dataobjects/EventInvitation.php index a670592..c784db7 100644 --- a/code/dataobjects/EventInvitation.php +++ b/code/dataobjects/EventInvitation.php @@ -4,51 +4,55 @@ * * @package silverstripe-eventmanagement */ -class EventInvitation extends DataObject { - - private static $db = array( - 'Name' => 'Varchar(255)', - 'Email' => 'Varchar(255)' - ); - - private static $has_one = array( - 'Event' => 'RegistrableEvent', - 'Time' => 'RegistrableDateTime' - ); - - private static $summary_fields = array( - 'Name' => 'Name', - 'Email' => 'Email', - 'Registered' => 'Registered', - 'EventTitle' => 'Event', - 'TimeSummary' => 'Time(s)' - ); - - public function Registered() { - $rego = DataObject::get_one('EventRegistration', sprintf( - '"Email" = \'%s\' AND "TimeID" = %d', - Convert::raw2sql($this->Email), $this->TimeID - )); - - return $rego ? _t('EventRegistration.YES', 'Yes') : _t('EventRegistration.NO', 'No'); - } - - public function EventTitle() { - return $this->Time()->EventTitle(); - } - - public function TimeSummary() { - return $this->Time()->Summary(); - } - - /** - * @return string - */ - public function RegisterLink() { - return Director::absoluteURL(Controller::join_links( - $this->Event()->Link(), 'register', $this->TimeID, - '?name=' . urlencode($this->Name), '?email=' . urlencode($this->Email) - )); - } - -} \ No newline at end of file +class EventInvitation extends DataObject +{ + + private static $db = array( + 'Name' => 'Varchar(255)', + 'Email' => 'Varchar(255)' + ); + + private static $has_one = array( + 'Event' => 'RegistrableEvent', + 'Time' => 'RegistrableDateTime' + ); + + private static $summary_fields = array( + 'Name' => 'Name', + 'Email' => 'Email', + 'Registered' => 'Registered', + 'EventTitle' => 'Event', + 'TimeSummary' => 'Time(s)' + ); + + public function Registered() + { + $rego = DataObject::get_one('EventRegistration', sprintf( + '"Email" = \'%s\' AND "TimeID" = %d', + Convert::raw2sql($this->Email), $this->TimeID + )); + + return $rego ? _t('EventRegistration.YES', 'Yes') : _t('EventRegistration.NO', 'No'); + } + + public function EventTitle() + { + return $this->Time()->EventTitle(); + } + + public function TimeSummary() + { + return $this->Time()->Summary(); + } + + /** + * @return string + */ + public function RegisterLink() + { + return Director::absoluteURL(Controller::join_links( + $this->Event()->Link(), 'register', $this->TimeID, + '?name=' . urlencode($this->Name), '?email=' . urlencode($this->Email) + )); + } +} diff --git a/code/dataobjects/EventRegistration.php b/code/dataobjects/EventRegistration.php index d7206b7..73db20c 100644 --- a/code/dataobjects/EventRegistration.php +++ b/code/dataobjects/EventRegistration.php @@ -4,129 +4,139 @@ * * @package silverstripe-eventmanagement */ -class EventRegistration extends DataObject { - - private static $db = array( - 'Name' => 'Varchar(255)', - 'Email' => 'Varchar(255)', - 'Status' => 'Enum("Unsubmitted, Unconfirmed, Valid, Canceled")', - 'Total' => 'Money', - 'Token' => 'Varchar(40)' - ); - - private static $has_one = array( - 'Time' => 'RegistrableDateTime', - 'Member' => 'Member' - ); - - private static $many_many = array( - 'Tickets' => 'EventTicket' - ); - - private static $many_many_extraFields = array( - 'Tickets' => array('Quantity' => 'Int') - ); - - private static $summary_fields = array( - 'Name' => 'Name', - 'Email' => 'Email', - 'Time.Title' => 'Event', - 'TotalQuantity' => 'Places' - ); - - protected function onBeforeWrite() { - if (!$this->isInDB()) { - $generator = new RandomGenerator(); - $this->Token = $generator->randomToken(); - } - - parent::onBeforeWrite(); - } - - public function getCMSFields() { - $fields = parent::getCMSFields(); - - $fields->removeByName('Tickets'); - $fields->removeByName('Total'); - $fields->removeByName('Token'); - $fields->removeByName('TimeID'); - - $config = GridFieldConfig_RelationEditor::create(); - $config->getComponentByType('GridFieldDataColumns')->setDisplayFields(array( - 'Title' => 'Ticket Title', - 'PriceSummary' => 'Price', - 'Quantity' => 'Quantity' - )); - $ticketsGridField = GridField::create( - 'Tickets', - 'EventTicket', - $this->Tickets(), - $config - ); - $fields->addFieldToTab('Root.Tickets', $ticketsGridField); - - if (class_exists('Payment')) { - $fields->addFieldToTab('Root.Tickets', new ReadonlyField( - 'TotalNice', 'Total', $this->Total->Nice() - )); - } - - return $fields; - } - - /** - * @see EventRegistration::EventTitle() - */ - public function getTitle() { - return $this->Time()->Title; - } - - /** - * @return int - */ - public function TotalQuantity() { - return $this->Tickets()->sum('Quantity'); - } - - /** - * @return SS_Datetime - */ - public function ConfirmTimeLimit() { - $unconfirmed = $this->Status == 'Unconfirmed'; - $limit = $this->Time()->Event()->ConfirmTimeLimit; - - if ($unconfirmed && $limit) { - return DBField::create_field('SS_Datetime', strtotime($this->Created) + $limit); - } - } - - /** - * @return string - */ - public function Link() { - return Controller::join_links( - $this->Time()->Event()->Link(), 'registration', $this->ID, '?token=' . $this->Token - ); - } - - public function canView($member = null) { - return $this->Time()->canView($member) - && Permission::check("CMS_ACCESS_CMSMain", 'any', $member); - } - - public function canEdit($member = null) { - return $this->Time()->canEdit($member) - && Permission::check("CMS_ACCESS_CMSMain", 'any', $member); - } - - public function canDelete($member = null) { - return $this->Time()->canDelete($member) - && Permission::check("CMS_ACCESS_CMSMain", 'any', $member); - } - - public function canCreate($member = null) { - return $this->Time()->canCreate($member) - && Permission::check("CMS_ACCESS_CMSMain", 'any', $member); - } - +class EventRegistration extends DataObject +{ + + private static $db = array( + 'Name' => 'Varchar(255)', + 'Email' => 'Varchar(255)', + 'Status' => 'Enum("Unsubmitted, Unconfirmed, Valid, Canceled")', + 'Total' => 'Money', + 'Token' => 'Varchar(40)' + ); + + private static $has_one = array( + 'Time' => 'RegistrableDateTime', + 'Member' => 'Member' + ); + + private static $many_many = array( + 'Tickets' => 'EventTicket' + ); + + private static $many_many_extraFields = array( + 'Tickets' => array('Quantity' => 'Int') + ); + + private static $summary_fields = array( + 'Name' => 'Name', + 'Email' => 'Email', + 'Time.Title' => 'Event', + 'TotalQuantity' => 'Places' + ); + + protected function onBeforeWrite() + { + if (!$this->isInDB()) { + $generator = new RandomGenerator(); + $this->Token = $generator->randomToken(); + } + + parent::onBeforeWrite(); + } + + public function getCMSFields() + { + $fields = parent::getCMSFields(); + + $fields->removeByName('Tickets'); + $fields->removeByName('Total'); + $fields->removeByName('Token'); + $fields->removeByName('TimeID'); + + $config = GridFieldConfig_RelationEditor::create(); + $config->getComponentByType('GridFieldDataColumns')->setDisplayFields(array( + 'Title' => 'Ticket Title', + 'PriceSummary' => 'Price', + 'Quantity' => 'Quantity' + )); + $ticketsGridField = GridField::create( + 'Tickets', + 'EventTicket', + $this->Tickets(), + $config + ); + $fields->addFieldToTab('Root.Tickets', $ticketsGridField); + + if (class_exists('Payment')) { + $fields->addFieldToTab('Root.Tickets', new ReadonlyField( + 'TotalNice', 'Total', $this->Total->Nice() + )); + } + + return $fields; + } + + /** + * @see EventRegistration::EventTitle() + */ + public function getTitle() + { + return $this->Time()->Title; + } + + /** + * @return int + */ + public function TotalQuantity() + { + return $this->Tickets()->sum('Quantity'); + } + + /** + * @return SS_Datetime + */ + public function ConfirmTimeLimit() + { + $unconfirmed = $this->Status == 'Unconfirmed'; + $limit = $this->Time()->Event()->ConfirmTimeLimit; + + if ($unconfirmed && $limit) { + return DBField::create_field('SS_Datetime', strtotime($this->Created) + $limit); + } + } + + /** + * @return string + */ + public function Link() + { + return Controller::join_links( + $this->Time()->Event()->Link(), 'registration', $this->ID, '?token=' . $this->Token + ); + } + + public function canView($member = null) + { + return $this->Time()->canView($member) + && Permission::check("CMS_ACCESS_CMSMain", 'any', $member); + } + + public function canEdit($member = null) + { + return $this->Time()->canEdit($member) + && Permission::check("CMS_ACCESS_CMSMain", 'any', $member); + } + + public function canDelete($member = null) + { + return $this->Time()->canDelete($member) + && Permission::check("CMS_ACCESS_CMSMain", 'any', $member); + } + + public function canCreate($member = null) + { + return $this->Time()->canCreate($member) + && Permission::check("CMS_ACCESS_CMSMain", 'any', $member); + } } diff --git a/code/dataobjects/EventTicket.php b/code/dataobjects/EventTicket.php index b0e893e..806bfa4 100644 --- a/code/dataobjects/EventTicket.php +++ b/code/dataobjects/EventTicket.php @@ -5,288 +5,305 @@ * * @package silverstripe-eventmanagement */ -class EventTicket extends DataObject { - - private static $db = array( - 'Title' => 'Varchar(255)', - 'Type' => 'Enum("Free, Price")', - 'Price' => 'Money', - 'Description' => 'Text', - 'StartType' => 'Enum("Date, TimeBefore")', - 'StartDate' => 'SS_Datetime', - 'StartDays' => 'Int', - 'StartHours' => 'Int', - 'StartMins' => 'Int', - 'EndType' => 'Enum("Date, TimeBefore")', - 'EndDate' => 'SS_Datetime', - 'EndDays' => 'Int', - 'EndHours' => 'Int', - 'EndMins' => 'Int', - 'MinTickets' => 'Int', - 'MaxTickets' => 'Int' - ); - - private static $has_one = array( - 'Event' => 'RegistrableEvent' - ); - - private static $defaults = array( - 'MinTickets' => 1, - 'StartType' => 'Date', - 'EndType' => 'TimeBefore', - 'EndDays' => 0, - 'EndHours' => 0, - 'EndMins' => 0 - ); - - private static $summary_fields = array( - 'Title' => 'Title', - 'StartSummary' => 'Sales Start', - 'PriceSummary' => 'Price' - ); - - private static $searchable_fields = array( - 'Title', - 'Type' - ); - - public function getCMSFields() { - $fields = parent::getCMSFields(); - - Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.js'); - Requirements::javascript('eventmanagement/javascript/event-ticket-cms.js'); - - $fields->removeByName('EventID'); - $fields->removeByName('StartType'); - $fields->removeByName('StartDate'); - $fields->removeByName('StartDays'); - $fields->removeByName('StartHours'); - $fields->removeByName('StartMins'); - $fields->removeByName('EndType'); - $fields->removeByName('EndDate'); - $fields->removeByName('EndDays'); - $fields->removeByName('EndHours'); - $fields->removeByName('EndMins'); - - if (class_exists('Payment')) { - $fields->insertBefore( - new OptionSetField('Type', 'Ticket type', array( - 'Free' => 'Free ticket', - 'Price' => 'Fixed price ticket' - )), - 'Price' - ); - } else { - $fields->removeByName('Type'); - $fields->removeByName('Price'); - } - - foreach (array('Start', 'End') as $type) { - $fields->addFieldsToTab('Root.Main', array( - new OptionSetField("{$type}Type", "$type sales at", array( - 'Date' => 'A specific date and time', - 'TimeBefore' => 'A time before the event starts' - )), - $dateTime = new DatetimeField("{$type}Date", ''), - $before = new FieldGroup( - "{$type}Offset", - new NumericField("{$type}Days", 'Days'), - new NumericField("{$type}Hours", 'Hours'), - new NumericField("{$type}Mins", 'Minutes') - ) - )); - - $before->setName("{$type}Offset"); - $before->setTitle(' '); - - $dateTime->getDateField()->setConfig('showcalendar', true); - $dateTime->getTimeField()->setConfig('showdropdown', true); - } - - $fields->addFieldsToTab('Root.Advanced', array( - new TextareaField('Description', 'Description'), - new NumericField('MinTickets', 'Minimum tickets per order'), - new NumericField('MaxTickets', 'Maximum tickets per order') - )); - - return $fields; - } - - public function validate() { - $result = parent::validate(); - - if ($this->Type == 'Price' && !$this->Price->exists()) { - $result->error('You must enter a currency and price for fixed price tickets'); - } - - if ($this->StartType == 'Date') { - if (!$this->StartDate) $result->error('You must enter a start date'); - } else { - if (!$this->StartDays && !$this->StartHours && !$this->StartMins) { - $result->error('You must enter a time before the event to start the ticket sales'); - } - } - - if ($this->EndType == 'Date' && !$this->EndDate) { - $result->error('You must enter an end date'); - } - - return $result; - } - - public function populateDefaults() { - $this->StartDate = date('Y-m-d H:i:s'); - parent::populateDefaults(); - } - - protected function onBeforeWrite() { - if (!class_exists('Payment')) { - $this->Type = 'Free'; - } - - parent::onBeforeWrite(); - } - - /** - * @return RequiredFields - */ - public function getValidator() { - return new RequiredFields('Title', 'Type', 'StartType', 'EndType'); - } - - /** - * Returns the number of tickets available for an event time. - * - * @param RegistrableDateTime $time - * @param int $excludeId A registration ID to exclude from calculations. - * @return array - */ - public function getAvailableForDateTime(RegistrableDateTime $time, $excludeId = null) { - if ($this->StartType == 'Date') { - $start = strtotime($this->StartDate); - } else { - $start = $time->getStartDateTime()->getTimestamp(); - $start = sfTime::subtract($start, $this->StartDays, sfTime::DAY); - $start = sfTime::subtract($start, $this->StartHours, sfTime::HOUR); - $start = sfTime::subtract($start, $this->StartMins, sfTime::MINUTE); - } - - if ($start >= time()) { - return array( - 'available' => false, - 'reason' => 'Tickets are not yet available.', - 'available_at' => $start); - } - - if ($this->EndType == 'Date') { - $end = strtotime($this->EndDate); - } else { - $end = $time->getStartDateTime()->getTimestamp(); - $end = sfTime::subtract($end, $this->EndDays, sfTime::DAY); - $end = sfTime::subtract($end, $this->EndHours, sfTime::HOUR); - $end = sfTime::subtract($end, $this->EndMins, sfTime::MINUTE); - } - - if (time() >= $end) { - return array( - 'available' => false, - 'reason' => 'Tickets are no longer available.'); - } - - if (!$quantity = $this->Available) { - return array('available' => true); - } - - $booked = new SQLQuery(); - $booked->setSelect('SUM("Quantity")'); - $booked->setFrom('"EventRegistration_Tickets"'); - $booked->addLeftJoin('EventRegistration', '"EventRegistration"."ID" = "EventRegistrationID"'); - - if ($excludeId) { - $booked->addWhere('"EventRegistration"."ID" <>' . (int)$excludeId); - } - - $booked->addWhere('"Status" <> \'Canceled\''); - $booked->addWhere('"EventTicketID" = ' . (int)$this->ID); - $booked->addWhere('"EventRegistration"."TimeID" =' . (int)$time->ID); - - $booked = $booked->execute()->value(); - - if ($booked < $quantity) { - return array('available' => $quantity - $booked); - } else { - return array( - 'available' => false, - 'reason' => 'All tickets have been booked.'); - } - } - - /** - * Calculates the timestamp for when this ticket stops going on sale for an - * event date time. - * - * @param RegistrableDateTime $datetime - * @return int - */ - public function getSaleEndForDateTime(RegistrableDateTime $datetime) { - if ($this->EndType == 'Date') { - return strtotime($this->EndDate); - } - - $time = $datetime->getStartDateTime()->getTimestamp(); - $time = sfTime::subtract($time, $this->EndDays, sfTime::DAY); - $time = sfTime::subtract($time, $this->EndHours, sfTime::HOUR); - $time = sfTime::subtract($time, $this->EndMins, sfTime::MINUTE); - - return $time; - } - - /** - * @return string - */ - public function StartSummary() { - if ($this->StartType == 'Date') { - return $this->obj('StartDate')->Nice(); - } else { - return sprintf( - '%d days, %d hours and %d minutes before event', - $this->StartDays, - $this->StartHours, - $this->StartMins); - } - } - - /** - * @return string - */ - public function PriceSummary() { - switch ($this->Type) { - case 'Free': return 'Free'; - case 'Price': return $this->obj('Price')->Nice(); - } - } - - /** - * @return string - */ - public function Summary() { - $summary = "{$this->Title} ({$this->PriceSummary()})"; - return $summary . ($this->Available ? " ($this->Available available)" : ''); - } - - public function canEdit($member = null) { - return $this->Event()->canEdit($member); - } - - public function canCreate($member = null) { - return $this->Event()->canCreate($member); - } - - public function canDelete($member = null) { - return $this->Event()->canDelete($member); - } - - public function canView($member = null) { - return $this->Event()->canView($member); - } +class EventTicket extends DataObject +{ + + private static $db = array( + 'Title' => 'Varchar(255)', + 'Type' => 'Enum("Free, Price")', + 'Price' => 'Money', + 'Description' => 'Text', + 'StartType' => 'Enum("Date, TimeBefore")', + 'StartDate' => 'SS_Datetime', + 'StartDays' => 'Int', + 'StartHours' => 'Int', + 'StartMins' => 'Int', + 'EndType' => 'Enum("Date, TimeBefore")', + 'EndDate' => 'SS_Datetime', + 'EndDays' => 'Int', + 'EndHours' => 'Int', + 'EndMins' => 'Int', + 'MinTickets' => 'Int', + 'MaxTickets' => 'Int' + ); + + private static $has_one = array( + 'Event' => 'RegistrableEvent' + ); + + private static $defaults = array( + 'MinTickets' => 1, + 'StartType' => 'Date', + 'EndType' => 'TimeBefore', + 'EndDays' => 0, + 'EndHours' => 0, + 'EndMins' => 0 + ); + + private static $summary_fields = array( + 'Title' => 'Title', + 'StartSummary' => 'Sales Start', + 'PriceSummary' => 'Price' + ); + + private static $searchable_fields = array( + 'Title', + 'Type' + ); + + public function getCMSFields() + { + $fields = parent::getCMSFields(); + + Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.js'); + Requirements::javascript('eventmanagement/javascript/event-ticket-cms.js'); + + $fields->removeByName('EventID'); + $fields->removeByName('StartType'); + $fields->removeByName('StartDate'); + $fields->removeByName('StartDays'); + $fields->removeByName('StartHours'); + $fields->removeByName('StartMins'); + $fields->removeByName('EndType'); + $fields->removeByName('EndDate'); + $fields->removeByName('EndDays'); + $fields->removeByName('EndHours'); + $fields->removeByName('EndMins'); + + if (class_exists('Payment')) { + $fields->insertBefore( + new OptionSetField('Type', 'Ticket type', array( + 'Free' => 'Free ticket', + 'Price' => 'Fixed price ticket' + )), + 'Price' + ); + } else { + $fields->removeByName('Type'); + $fields->removeByName('Price'); + } + + foreach (array('Start', 'End') as $type) { + $fields->addFieldsToTab('Root.Main', array( + new OptionSetField("{$type}Type", "$type sales at", array( + 'Date' => 'A specific date and time', + 'TimeBefore' => 'A time before the event starts' + )), + $dateTime = new DatetimeField("{$type}Date", ''), + $before = new FieldGroup( + "{$type}Offset", + new NumericField("{$type}Days", 'Days'), + new NumericField("{$type}Hours", 'Hours'), + new NumericField("{$type}Mins", 'Minutes') + ) + )); + + $before->setName("{$type}Offset"); + $before->setTitle(' '); + + $dateTime->getDateField()->setConfig('showcalendar', true); + $dateTime->getTimeField()->setConfig('showdropdown', true); + } + + $fields->addFieldsToTab('Root.Advanced', array( + new TextareaField('Description', 'Description'), + new NumericField('MinTickets', 'Minimum tickets per order'), + new NumericField('MaxTickets', 'Maximum tickets per order') + )); + + return $fields; + } + + public function validate() + { + $result = parent::validate(); + + if ($this->Type == 'Price' && !$this->Price->exists()) { + $result->error('You must enter a currency and price for fixed price tickets'); + } + + if ($this->StartType == 'Date') { + if (!$this->StartDate) { + $result->error('You must enter a start date'); + } + } else { + if (!$this->StartDays && !$this->StartHours && !$this->StartMins) { + $result->error('You must enter a time before the event to start the ticket sales'); + } + } + + if ($this->EndType == 'Date' && !$this->EndDate) { + $result->error('You must enter an end date'); + } + + return $result; + } + + public function populateDefaults() + { + $this->StartDate = date('Y-m-d H:i:s'); + parent::populateDefaults(); + } + + protected function onBeforeWrite() + { + if (!class_exists('Payment')) { + $this->Type = 'Free'; + } + + parent::onBeforeWrite(); + } + + /** + * @return RequiredFields + */ + public function getValidator() + { + return new RequiredFields('Title', 'Type', 'StartType', 'EndType'); + } + + /** + * Returns the number of tickets available for an event time. + * + * @param RegistrableDateTime $time + * @param int $excludeId A registration ID to exclude from calculations. + * @return array + */ + public function getAvailableForDateTime(RegistrableDateTime $time, $excludeId = null) + { + if ($this->StartType == 'Date') { + $start = strtotime($this->StartDate); + } else { + $start = $time->getStartDateTime()->getTimestamp(); + $start = sfTime::subtract($start, $this->StartDays, sfTime::DAY); + $start = sfTime::subtract($start, $this->StartHours, sfTime::HOUR); + $start = sfTime::subtract($start, $this->StartMins, sfTime::MINUTE); + } + + if ($start >= time()) { + return array( + 'available' => false, + 'reason' => 'Tickets are not yet available.', + 'available_at' => $start); + } + + if ($this->EndType == 'Date') { + $end = strtotime($this->EndDate); + } else { + $end = $time->getStartDateTime()->getTimestamp(); + $end = sfTime::subtract($end, $this->EndDays, sfTime::DAY); + $end = sfTime::subtract($end, $this->EndHours, sfTime::HOUR); + $end = sfTime::subtract($end, $this->EndMins, sfTime::MINUTE); + } + + if (time() >= $end) { + return array( + 'available' => false, + 'reason' => 'Tickets are no longer available.'); + } + + if (!$quantity = $this->Available) { + return array('available' => true); + } + + $booked = new SQLQuery(); + $booked->setSelect('SUM("Quantity")'); + $booked->setFrom('"EventRegistration_Tickets"'); + $booked->addLeftJoin('EventRegistration', '"EventRegistration"."ID" = "EventRegistrationID"'); + + if ($excludeId) { + $booked->addWhere('"EventRegistration"."ID" <>' . (int)$excludeId); + } + + $booked->addWhere('"Status" <> \'Canceled\''); + $booked->addWhere('"EventTicketID" = ' . (int)$this->ID); + $booked->addWhere('"EventRegistration"."TimeID" =' . (int)$time->ID); + + $booked = $booked->execute()->value(); + + if ($booked < $quantity) { + return array('available' => $quantity - $booked); + } else { + return array( + 'available' => false, + 'reason' => 'All tickets have been booked.'); + } + } + + /** + * Calculates the timestamp for when this ticket stops going on sale for an + * event date time. + * + * @param RegistrableDateTime $datetime + * @return int + */ + public function getSaleEndForDateTime(RegistrableDateTime $datetime) + { + if ($this->EndType == 'Date') { + return strtotime($this->EndDate); + } + + $time = $datetime->getStartDateTime()->getTimestamp(); + $time = sfTime::subtract($time, $this->EndDays, sfTime::DAY); + $time = sfTime::subtract($time, $this->EndHours, sfTime::HOUR); + $time = sfTime::subtract($time, $this->EndMins, sfTime::MINUTE); + + return $time; + } + + /** + * @return string + */ + public function StartSummary() + { + if ($this->StartType == 'Date') { + return $this->obj('StartDate')->Nice(); + } else { + return sprintf( + '%d days, %d hours and %d minutes before event', + $this->StartDays, + $this->StartHours, + $this->StartMins); + } + } + + /** + * @return string + */ + public function PriceSummary() + { + switch ($this->Type) { + case 'Free': return 'Free'; + case 'Price': return $this->obj('Price')->Nice(); + } + } + + /** + * @return string + */ + public function Summary() + { + $summary = "{$this->Title} ({$this->PriceSummary()})"; + return $summary . ($this->Available ? " ($this->Available available)" : ''); + } + + public function canEdit($member = null) + { + return $this->Event()->canEdit($member); + } + + public function canCreate($member = null) + { + return $this->Event()->canCreate($member); + } + + public function canDelete($member = null) + { + return $this->Event()->canDelete($member); + } + + public function canView($member = null) + { + return $this->Event()->canView($member); + } } diff --git a/code/dataobjects/RegistrableDateTime.php b/code/dataobjects/RegistrableDateTime.php index 8555f70..9123424 100644 --- a/code/dataobjects/RegistrableDateTime.php +++ b/code/dataobjects/RegistrableDateTime.php @@ -2,297 +2,316 @@ /** * An instance of an event that a person can register to attend. */ -class RegistrableDateTime extends CalendarDateTime { - - private static $db = array( - 'Capacity' => 'Int', - 'EmailReminder' => 'Boolean', - 'RemindDays' => 'Int' - ); - - private static $has_many = array( - 'Registrations' => 'EventRegistration' - ); - - private static $many_many = array( - 'Tickets' => 'EventTicket' - ); - - private static $many_many_extraFields = array( - 'Tickets' => array('Available' => 'Int', 'Sort' => 'Int') - ); - - public function getCMSFields() { - $fields = parent::getCMSFields(); - - $fields->removeByName('Capacity'); - $fields->removeByName('Registrations'); - $fields->removeByName('Tickets'); - $fields->removeByName('EmailReminder'); - $fields->removeByName('RemindDays'); - $fields->removeByName('PaymentID'); - $fields->removeByName('ReminderJobID'); - - if (!$this->isInDB()) { - $fields->push(new LiteralField( - 'RegistrationNote', 'You can configure registration once ' . - 'you save for the first time.
' - )); - - return $fields; - } - - - $fields->push( - new GridField( - 'Tickets', - _t('EventManagement.AVAILABLE_TICKETS', 'Available Tickets'), - $this->Tickets(), - GridFieldConfig::create() - ->addComponent(new GridFieldButtonRow('before')) - ->addComponent(new GridFieldToolbarHeader()) - ->addComponent($add = new GridFieldAddExistingSearchButton()) - ->addComponent(new GridFieldTitleHeader()) - ->addComponent(new GridFieldOrderableRows('Sort')) - ->addComponent($editable = new GridFieldEditableColumns()) - ->addComponent(new GridFieldDeleteAction(true)) - ) - ); - - $fields->push( - $capacity = new NumericField('Capacity', _t('EventManagement.CAPACITY', 'Capacity')) - ); - - $editable->setDisplayFields(array( - 'Title' => array('title' => 'Title', 'field' => 'ReadonlyField'), - 'StartSummary' => 'Sales Start', - 'PriceSummary' => 'Price', - 'Available' => array('field' => 'NumericField') - )); - - $add->setTitle(_t('EventManagement.ADD_TICKET_TYPE', 'Add Ticket Type')); - $capacity->setDescription('Set to 0 for unlimited capacity.'); - - if (class_exists('AbstractQueuedJob')) { - if ($this->ReminderJobID && $this->ReminderJob()->StepsProcessed) { - $fields->push(new LiteralField( - 'RemindersAlreadySent', - 'Reminder emails have already been sent out.
' - )); - } else { - $fields->push(new CheckboxField( - 'EmailReminder', - _t('EventManagement.SEND_REMINDER_EMAIL', 'Send the registered attendees a reminder email?') - ) - ); - - $fields->push( - $remindDays = new NumericField( - 'RemindDays', - _t('EventManagement.SEND_REMINDER', 'Send reminder') - ) - ); - - $remindDays->setDescription(_t('EventManagement.DAYS_BEFORE_EVENT', 'Days before the event starts.')); - } - } - - return $fields; - } - - public function validate() { - $result = parent::validate(); - $currency = null; - - // Ensure that if we are sending a reminder email it has an interval - // to send at. - if ($this->EmailReminder && !$this->RemindDays) { - $result->error('You must enter a time to send the reminder at.'); - } - - // Ensure that we only have tickets in one currency, since you can't - // make a payment across currencies. - foreach ($this->Tickets() as $ticket) { - if ($ticket->Type == 'Price') { - $ticketCurr = $ticket->Price->getCurrency(); - - if ($ticketCurr && $currency && $ticketCurr != $currency) { - $result->error(sprintf( - 'You cannot attach tickets with different currencies ' - . 'to one event. You have tickets in both "%s" and "%s".', - $currency, $ticketCurr)); - return $result; - } - - $currency = $ticketCurr; - } - } - - return $result; - } - - /** - * If an email reminder is set, then this registers it in the queue. - */ - protected function onBeforeWrite() { - parent::onBeforeWrite(); - - // If an email reminder has been set then register it with the queued - // jobs module. - if (class_exists('AbstractQueuedJob') && $this->EmailReminder) { - $hasJob = $this->ReminderJobID; - $changedStart = $this->isChanged('RemindDays'); - - if ($hasJob) { - if (!$changedStart) { - return; - } else { - $this->ReminderJob()->delete(); - } - } - - $start = $this->getStartDateTime()->getTimestamp(); - $start = sfTime::subtract($start, $this->RemindDays, sfTime::DAY); - - $job = new EventReminderEmailJob($this); - $srv = singleton('QueuedJobService'); - $this->ReminderJobID = $srv->queueJob($job, date('Y-m-d H:i:s', $start)); - } - } - - /** - * Notifies the users of any changes made to the event. - */ - protected function onAfterWrite() { - parent::onAfterWrite(); - - // If any details have changed and the system is configured to send out - // a notification email then do so. - $email = $this->Event()->EmailNotifyChanges; - $changed = $this->getChangedFields(false, 2); - $notify = explode(',', $this->Event()->NotifyChangeFields); - $notify = array_intersect_key($changed, array_flip($notify)); - - if (!$email || !$changed || !$notify) return; - - $emails = DB::query(sprintf( - 'SELECT "Email", "Name" FROM "EventRegistration" WHERE "TimeID" = %d ' - . 'AND "Status" = \'Valid\' GROUP BY "Email"', - $this->ID - )); - if (!$emails = $emails->map()) return; - - $changed = new DataObjectSet(); - foreach ($notify as $field => $data) { - $changed->push(new ArrayData(array( - 'Label' => singleton('EventRegistration')->fieldLabel($field), - 'Before' => $data['before'], - 'After' => $data['after'] - ))); - } - - $email = new Email(); - $email->setSubject( - sprintf('Event Details Changed For %s (%s)', - $this->EventTitle(), - SiteConfig::current_site_config()->Title)); - - $email->setTemplate('EventRegistrationChangeEmail'); - $email->populateTemplate(array( - 'Time' => $this, - 'SiteConfig' => SiteConfig::current_site_config(), - 'Changed' => $changed, - 'Link' => $this->Link() - )); - - // We need to send the email for each registration individually. - foreach ($emails as $address => $name) { - $_email = clone $email; - $_email->setTo($address); - $_email->populateTemplate(array( - 'Name' => $name - )); - - $_email->send(); - } - } - - /** - * Returns the overall number of places remaining at this event, TRUE if - * there are unlimited places or FALSE if they are all taken. - * - * @param int $excludeId A registration ID to exclude from calculations. - * @return int|bool - */ - public function getRemainingCapacity($excludeId = null) { - if (!$this->Capacity) return true; - - $taken = new SQLQuery(); - $taken->setSelect('SUM("Quantity")'); - $taken->setFrom('EventRegistration_Tickets'); - $taken->addLeftJoin('EventRegistration', '"EventRegistration"."ID" = "EventRegistrationID"'); - - if ($excludeId) { - $taken->addWhere('"EventRegistration"."ID" <>'. (int)$excludeId); - } - - $taken->addWhere('"Status" <> \'Canceled\''); - $taken->addWhere('"EventRegistration"."TimeID" ='. (int)$this->ID); - $taken = $taken->execute()->value(); - - return ($this->Capacity >= $taken) ? $this->Capacity - $taken : false; - } - - /** - * @return boolean - */ - public function isSoldOut() { - return (!$this->getRemainingCapacity()); - } - - /** - * @return string - */ - public function getTitle() { - $parts = CalendarUtil::get_date_string($this->StartDate, $this->EndDate); - if ($parts) { - $date = implode(' ', $parts); - }else { - $date = 'No date'; - } - - if ($this->AllDay) { - return sprintf(_t('EventManagement.DATEALLDAY', '%s (all day)'), $date); - } - - if (!$this->StartTime) return $date; - - $time = $this->obj('StartTime')->Nice(); - if ($this->EndTime) $time .= ' - ' . $this->obj('EndTime')->Nice(); - - return "$date $time"; - } - - /** - * @return DateTime - */ - public function getStartDateTime() { - $dt = new DateTime($this->StartDate); - - if(!$this->AllDay) { - if($this->StartTime) { - $dt->modify($this->StartTime); - } - } - - return $dt; - } - - /** - * @return string - */ - public function Link() { - return Controller::join_links($this->Event()->Link(), 'details', $this->ID); - } - +class RegistrableDateTime extends CalendarDateTime +{ + + private static $db = array( + 'Capacity' => 'Int', + 'EmailReminder' => 'Boolean', + 'RemindDays' => 'Int' + ); + + private static $has_many = array( + 'Registrations' => 'EventRegistration' + ); + + private static $many_many = array( + 'Tickets' => 'EventTicket' + ); + + private static $many_many_extraFields = array( + 'Tickets' => array('Available' => 'Int', 'Sort' => 'Int') + ); + + public function getCMSFields() + { + $fields = parent::getCMSFields(); + + $fields->removeByName('Capacity'); + $fields->removeByName('Registrations'); + $fields->removeByName('Tickets'); + $fields->removeByName('EmailReminder'); + $fields->removeByName('RemindDays'); + $fields->removeByName('PaymentID'); + $fields->removeByName('ReminderJobID'); + + if (!$this->isInDB()) { + $fields->push(new LiteralField( + 'RegistrationNote', 'You can configure registration once ' . + 'you save for the first time.
' + )); + + return $fields; + } + + + $fields->push( + new GridField( + 'Tickets', + _t('EventManagement.AVAILABLE_TICKETS', 'Available Tickets'), + $this->Tickets(), + GridFieldConfig::create() + ->addComponent(new GridFieldButtonRow('before')) + ->addComponent(new GridFieldToolbarHeader()) + ->addComponent($add = new GridFieldAddExistingSearchButton()) + ->addComponent(new GridFieldTitleHeader()) + ->addComponent(new GridFieldOrderableRows('Sort')) + ->addComponent($editable = new GridFieldEditableColumns()) + ->addComponent(new GridFieldDeleteAction(true)) + ) + ); + + $fields->push( + $capacity = new NumericField('Capacity', _t('EventManagement.CAPACITY', 'Capacity')) + ); + + $editable->setDisplayFields(array( + 'Title' => array('title' => 'Title', 'field' => 'ReadonlyField'), + 'StartSummary' => 'Sales Start', + 'PriceSummary' => 'Price', + 'Available' => array('field' => 'NumericField') + )); + + $add->setTitle(_t('EventManagement.ADD_TICKET_TYPE', 'Add Ticket Type')); + $capacity->setDescription('Set to 0 for unlimited capacity.'); + + if (class_exists('AbstractQueuedJob')) { + if ($this->ReminderJobID && $this->ReminderJob()->StepsProcessed) { + $fields->push(new LiteralField( + 'RemindersAlreadySent', + 'Reminder emails have already been sent out.
' + )); + } else { + $fields->push(new CheckboxField( + 'EmailReminder', + _t('EventManagement.SEND_REMINDER_EMAIL', 'Send the registered attendees a reminder email?') + ) + ); + + $fields->push( + $remindDays = new NumericField( + 'RemindDays', + _t('EventManagement.SEND_REMINDER', 'Send reminder') + ) + ); + + $remindDays->setDescription(_t('EventManagement.DAYS_BEFORE_EVENT', 'Days before the event starts.')); + } + } + + return $fields; + } + + public function validate() + { + $result = parent::validate(); + $currency = null; + + // Ensure that if we are sending a reminder email it has an interval + // to send at. + if ($this->EmailReminder && !$this->RemindDays) { + $result->error('You must enter a time to send the reminder at.'); + } + + // Ensure that we only have tickets in one currency, since you can't + // make a payment across currencies. + foreach ($this->Tickets() as $ticket) { + if ($ticket->Type == 'Price') { + $ticketCurr = $ticket->Price->getCurrency(); + + if ($ticketCurr && $currency && $ticketCurr != $currency) { + $result->error(sprintf( + 'You cannot attach tickets with different currencies ' + . 'to one event. You have tickets in both "%s" and "%s".', + $currency, $ticketCurr)); + return $result; + } + + $currency = $ticketCurr; + } + } + + return $result; + } + + /** + * If an email reminder is set, then this registers it in the queue. + */ + protected function onBeforeWrite() + { + parent::onBeforeWrite(); + + // If an email reminder has been set then register it with the queued + // jobs module. + if (class_exists('AbstractQueuedJob') && $this->EmailReminder) { + $hasJob = $this->ReminderJobID; + $changedStart = $this->isChanged('RemindDays'); + + if ($hasJob) { + if (!$changedStart) { + return; + } else { + $this->ReminderJob()->delete(); + } + } + + $start = $this->getStartDateTime()->getTimestamp(); + $start = sfTime::subtract($start, $this->RemindDays, sfTime::DAY); + + $job = new EventReminderEmailJob($this); + $srv = singleton('QueuedJobService'); + $this->ReminderJobID = $srv->queueJob($job, date('Y-m-d H:i:s', $start)); + } + } + + /** + * Notifies the users of any changes made to the event. + */ + protected function onAfterWrite() + { + parent::onAfterWrite(); + + // If any details have changed and the system is configured to send out + // a notification email then do so. + $email = $this->Event()->EmailNotifyChanges; + $changed = $this->getChangedFields(false, 2); + $notify = explode(',', $this->Event()->NotifyChangeFields); + $notify = array_intersect_key($changed, array_flip($notify)); + + if (!$email || !$changed || !$notify) { + return; + } + + $emails = DB::query(sprintf( + 'SELECT "Email", "Name" FROM "EventRegistration" WHERE "TimeID" = %d ' + . 'AND "Status" = \'Valid\' GROUP BY "Email"', + $this->ID + )); + if (!$emails = $emails->map()) { + return; + } + + $changed = new DataObjectSet(); + foreach ($notify as $field => $data) { + $changed->push(new ArrayData(array( + 'Label' => singleton('EventRegistration')->fieldLabel($field), + 'Before' => $data['before'], + 'After' => $data['after'] + ))); + } + + $email = new Email(); + $email->setSubject( + sprintf('Event Details Changed For %s (%s)', + $this->EventTitle(), + SiteConfig::current_site_config()->Title)); + + $email->setTemplate('EventRegistrationChangeEmail'); + $email->populateTemplate(array( + 'Time' => $this, + 'SiteConfig' => SiteConfig::current_site_config(), + 'Changed' => $changed, + 'Link' => $this->Link() + )); + + // We need to send the email for each registration individually. + foreach ($emails as $address => $name) { + $_email = clone $email; + $_email->setTo($address); + $_email->populateTemplate(array( + 'Name' => $name + )); + + $_email->send(); + } + } + + /** + * Returns the overall number of places remaining at this event, TRUE if + * there are unlimited places or FALSE if they are all taken. + * + * @param int $excludeId A registration ID to exclude from calculations. + * @return int|bool + */ + public function getRemainingCapacity($excludeId = null) + { + if (!$this->Capacity) { + return true; + } + + $taken = new SQLQuery(); + $taken->setSelect('SUM("Quantity")'); + $taken->setFrom('EventRegistration_Tickets'); + $taken->addLeftJoin('EventRegistration', '"EventRegistration"."ID" = "EventRegistrationID"'); + + if ($excludeId) { + $taken->addWhere('"EventRegistration"."ID" <>'. (int)$excludeId); + } + + $taken->addWhere('"Status" <> \'Canceled\''); + $taken->addWhere('"EventRegistration"."TimeID" ='. (int)$this->ID); + $taken = $taken->execute()->value(); + + return ($this->Capacity >= $taken) ? $this->Capacity - $taken : false; + } + + /** + * @return boolean + */ + public function isSoldOut() + { + return (!$this->getRemainingCapacity()); + } + + /** + * @return string + */ + public function getTitle() + { + $parts = CalendarUtil::get_date_string($this->StartDate, $this->EndDate); + if ($parts) { + $date = implode(' ', $parts); + } else { + $date = 'No date'; + } + + if ($this->AllDay) { + return sprintf(_t('EventManagement.DATEALLDAY', '%s (all day)'), $date); + } + + if (!$this->StartTime) { + return $date; + } + + $time = $this->obj('StartTime')->Nice(); + if ($this->EndTime) { + $time .= ' - ' . $this->obj('EndTime')->Nice(); + } + + return "$date $time"; + } + + /** + * @return DateTime + */ + public function getStartDateTime() + { + $dt = new DateTime($this->StartDate); + + if (!$this->AllDay) { + if ($this->StartTime) { + $dt->modify($this->StartTime); + } + } + + return $dt; + } + + /** + * @return string + */ + public function Link() + { + return Controller::join_links($this->Event()->Link(), 'details', $this->ID); + } } diff --git a/code/emails/EventRegistrationDetailsEmail.php b/code/emails/EventRegistrationDetailsEmail.php index c482b1d..bb0b8c8 100644 --- a/code/emails/EventRegistrationDetailsEmail.php +++ b/code/emails/EventRegistrationDetailsEmail.php @@ -4,45 +4,46 @@ * * @package silverstripe-eventmanagement */ -class EventRegistrationDetailsEmail extends Email { - - protected $ss_template = 'EventRegistrationDetailsEmail'; - - /** - * Creates an email instance from a registration object. - * - * @param EventRegistration $registration - * @return EventRegistrationDetailsEmail - */ - public static function factory(EventRegistration $registration) { - $email = new self(); - $siteconfig = SiteConfig::current_site_config(); - - $email->setTo($registration->Email); - $email->setSubject(sprintf( - 'Registration Details For %s (%s)', - $registration->Time()->Event()->Title, - $siteconfig->Title)); - - $email->populateTemplate(array( - 'Registration' => $registration, - 'SiteConfig' => $siteconfig - )); - - if ($generator = $registration->Time()->Event()->TicketGenerator) { - $generator = new $generator(); - - $path = $generator->generateTicketFileFor($registration); - $name = $generator->getTicketFilenameFor($registration); - $mime = $generator->getTicketMimeTypeFor($registration); - - if ($path) { - $email->attachFile($path, $name, $mime); - } - } - - singleton(get_class())->extend('updateEmail', $email, $registration); - return $email; - } - -} \ No newline at end of file +class EventRegistrationDetailsEmail extends Email +{ + + protected $ss_template = 'EventRegistrationDetailsEmail'; + + /** + * Creates an email instance from a registration object. + * + * @param EventRegistration $registration + * @return EventRegistrationDetailsEmail + */ + public static function factory(EventRegistration $registration) + { + $email = new self(); + $siteconfig = SiteConfig::current_site_config(); + + $email->setTo($registration->Email); + $email->setSubject(sprintf( + 'Registration Details For %s (%s)', + $registration->Time()->Event()->Title, + $siteconfig->Title)); + + $email->populateTemplate(array( + 'Registration' => $registration, + 'SiteConfig' => $siteconfig + )); + + if ($generator = $registration->Time()->Event()->TicketGenerator) { + $generator = new $generator(); + + $path = $generator->generateTicketFileFor($registration); + $name = $generator->getTicketFilenameFor($registration); + $mime = $generator->getTicketMimeTypeFor($registration); + + if ($path) { + $email->attachFile($path, $name, $mime); + } + } + + singleton(get_class())->extend('updateEmail', $email, $registration); + return $email; + } +} diff --git a/code/extensions/EventRegistrationPaymentExtension.php b/code/extensions/EventRegistrationPaymentExtension.php index 9bc78d0..47c98b3 100644 --- a/code/extensions/EventRegistrationPaymentExtension.php +++ b/code/extensions/EventRegistrationPaymentExtension.php @@ -4,10 +4,10 @@ * * @package silverstripe-eventmanagement */ -class EventRegistrationPaymentExtension extends DataExtension { +class EventRegistrationPaymentExtension extends DataExtension +{ - private static $has_one = array( - 'Payment' => 'Payment' - ); - -} \ No newline at end of file + private static $has_one = array( + 'Payment' => 'Payment' + ); +} diff --git a/code/extensions/RegistrableDateTimeReminderExtension.php b/code/extensions/RegistrableDateTimeReminderExtension.php index 782d34c..75963ae 100644 --- a/code/extensions/RegistrableDateTimeReminderExtension.php +++ b/code/extensions/RegistrableDateTimeReminderExtension.php @@ -3,10 +3,10 @@ * Adds a relationship between an event date/time and the job that is used to * send out reminder emails. */ -class RegistrableDateTimeReminderExtension extends DataExtension { - - private static $has_one = array( - 'ReminderJob' => 'QueuedJobDescriptor' - ); +class RegistrableDateTimeReminderExtension extends DataExtension +{ + private static $has_one = array( + 'ReminderJob' => 'QueuedJobDescriptor' + ); } diff --git a/code/formfields/EventRegistrationTicketsTableField.php b/code/formfields/EventRegistrationTicketsTableField.php index 4aed051..2cbb5d2 100644 --- a/code/formfields/EventRegistrationTicketsTableField.php +++ b/code/formfields/EventRegistrationTicketsTableField.php @@ -5,176 +5,191 @@ * * @package silverstripe-eventmanagement */ -class EventRegistrationTicketsTableField extends FormField { - - protected $datetime; - protected $excludedRegistrationId; - protected $showUnavailableTickets = true; - protected $showUnselectedTickets = true; - protected $forceTotalRow; - protected $total; - - public function __construct($name, $datetime, $value = array()) { - $this->datetime = $datetime; - parent::__construct($name, '', $value); - } - - public function Field($properties = array()) { - return $this->renderWith('EventRegistrationTicketsTableField', $properties); - } - - /** - * @return array - */ - public function dataValue() { - return (array) $this->value; - } - - /** - * @param array|object $value - */ - public function setValue($value) { - if (is_object($value)) { - $value = $value->map('ID', 'Quantity'); - } - - parent::setValue($value); - } - - /** - * Sets a registration ID to exclude from any availibility calculations. - * - * @param int $id - */ - public function setExcludedRegistrationId($id) { - $this->excludedRegistrationId = $id; - } - - /** - * @param bool $bool - */ - public function setShowUnavailableTickets($bool) { - $this->showUnavailableTickets = $bool; - } - - /** - * @param bool $bool - */ - public function setShowUnselectedTickets($bool) { - $this->showUnselectedTickets = $bool; - } - - /** - * @param bool $bool - */ - public function setForceTotalRow($bool) { - $this->forceTotalRow = $bool; - } - - /** - * @param Money $money - */ - public function setTotal(Money $money) { - $this->total = $money; - } - - /** - * @return EventRegistrationTicketsTableField - */ - public function performReadonlyTransformation() { - $table = clone $this; - $table->setReadonly(true); - return $table; - } - - public function Tickets() { - $result = new ArrayList(); - $tickets = $this->datetime->Tickets('', '"RegistrableDateTime_Tickets"."Sort"'); - - foreach ($tickets as $ticket) { - $available = $ticket->getAvailableForDateTime( - $this->datetime, $this->excludedRegistrationId - ); - $endTime = $ticket->getSaleEndForDateTime($this->datetime); - - if ($avail = $available['available']) { - $name = "{$this->name}[{$ticket->ID}]"; - $min = $ticket->MinTickets; - $max = $ticket->MaxTickets; - - $val = array_key_exists($ticket->ID, $this->value) - ? $this->value[$ticket->ID] : null; - - if (!$val && !$this->showUnselectedTickets) { - continue; - } - - if ($this->readonly) { - $field = $val ? $val : '0'; - } elseif ($max) { - $field = new DropdownField( - $name, '', - ArrayLib::valuekey(range($min, min($available, $max))), - $val, null); - $field->setHasEmptyDefault(true); - } else { - $field = new NumericField($name, '', $val); - } - - $result->push(new ArrayData(array( - 'Title' => $ticket->Title, - 'Description' => $ticket->Description, - 'Available' => $avail === true ? 'Unlimited' : $avail, - 'Price' => $ticket->PriceSummary(), - 'End' => DBField::create_field('SS_Datetime', $endTime), - 'Quantity' => $field - ))); - } elseif ($this->showUnavailableTickets) { - $availableAt = null; - - if (array_key_exists('available_at', $available)) { - $availableAt = DBField::create_field('SS_Datetime', $available['available_at']); - } - - $result->push(new ArrayData(array( - 'Title' => $ticket->Title, - 'Description' => $ticket->Description, - 'Available' => false, - 'Reason' => $available['reason'], - 'AvailableAt' => $availableAt - ))); - } - } - - return $result; - } - - /** - * @return int - */ - public function RemainingCapacity() { - return $this->datetime->getRemainingCapacity($this->excludedRegistrationId); - } - - /** - * @return bool - */ - public function ShowTotalRow() { - return $this->forceTotalRow || ($this->readonly && $this->Total() && $this->Total()->exists()); - } - - /** - * @return Money - */ - public function Total() { - return $this->total; - } - - /** - * @return RegistrableDateTime - */ - public function DateTime() { - return $this->datetime; - } - +class EventRegistrationTicketsTableField extends FormField +{ + + protected $datetime; + protected $excludedRegistrationId; + protected $showUnavailableTickets = true; + protected $showUnselectedTickets = true; + protected $forceTotalRow; + protected $total; + + public function __construct($name, $datetime, $value = array()) + { + $this->datetime = $datetime; + parent::__construct($name, '', $value); + } + + public function Field($properties = array()) + { + return $this->renderWith('EventRegistrationTicketsTableField', $properties); + } + + /** + * @return array + */ + public function dataValue() + { + return (array) $this->value; + } + + /** + * @param array|object $value + */ + public function setValue($value) + { + if (is_object($value)) { + $value = $value->map('ID', 'Quantity'); + } + + parent::setValue($value); + } + + /** + * Sets a registration ID to exclude from any availibility calculations. + * + * @param int $id + */ + public function setExcludedRegistrationId($id) + { + $this->excludedRegistrationId = $id; + } + + /** + * @param bool $bool + */ + public function setShowUnavailableTickets($bool) + { + $this->showUnavailableTickets = $bool; + } + + /** + * @param bool $bool + */ + public function setShowUnselectedTickets($bool) + { + $this->showUnselectedTickets = $bool; + } + + /** + * @param bool $bool + */ + public function setForceTotalRow($bool) + { + $this->forceTotalRow = $bool; + } + + /** + * @param Money $money + */ + public function setTotal(Money $money) + { + $this->total = $money; + } + + /** + * @return EventRegistrationTicketsTableField + */ + public function performReadonlyTransformation() + { + $table = clone $this; + $table->setReadonly(true); + return $table; + } + + public function Tickets() + { + $result = new ArrayList(); + $tickets = $this->datetime->Tickets('', '"RegistrableDateTime_Tickets"."Sort"'); + + foreach ($tickets as $ticket) { + $available = $ticket->getAvailableForDateTime( + $this->datetime, $this->excludedRegistrationId + ); + $endTime = $ticket->getSaleEndForDateTime($this->datetime); + + if ($avail = $available['available']) { + $name = "{$this->name}[{$ticket->ID}]"; + $min = $ticket->MinTickets; + $max = $ticket->MaxTickets; + + $val = array_key_exists($ticket->ID, $this->value) + ? $this->value[$ticket->ID] : null; + + if (!$val && !$this->showUnselectedTickets) { + continue; + } + + if ($this->readonly) { + $field = $val ? $val : '0'; + } elseif ($max) { + $field = new DropdownField( + $name, '', + ArrayLib::valuekey(range($min, min($available, $max))), + $val, null); + $field->setHasEmptyDefault(true); + } else { + $field = new NumericField($name, '', $val); + } + + $result->push(new ArrayData(array( + 'Title' => $ticket->Title, + 'Description' => $ticket->Description, + 'Available' => $avail === true ? 'Unlimited' : $avail, + 'Price' => $ticket->PriceSummary(), + 'End' => DBField::create_field('SS_Datetime', $endTime), + 'Quantity' => $field + ))); + } elseif ($this->showUnavailableTickets) { + $availableAt = null; + + if (array_key_exists('available_at', $available)) { + $availableAt = DBField::create_field('SS_Datetime', $available['available_at']); + } + + $result->push(new ArrayData(array( + 'Title' => $ticket->Title, + 'Description' => $ticket->Description, + 'Available' => false, + 'Reason' => $available['reason'], + 'AvailableAt' => $availableAt + ))); + } + } + + return $result; + } + + /** + * @return int + */ + public function RemainingCapacity() + { + return $this->datetime->getRemainingCapacity($this->excludedRegistrationId); + } + + /** + * @return bool + */ + public function ShowTotalRow() + { + return $this->forceTotalRow || ($this->readonly && $this->Total() && $this->Total()->exists()); + } + + /** + * @return Money + */ + public function Total() + { + return $this->total; + } + + /** + * @return RegistrableDateTime + */ + public function DateTime() + { + return $this->datetime; + } } diff --git a/code/formfields/EventSendInvitationsButton.php b/code/formfields/EventSendInvitationsButton.php index 58005a8..83c7e13 100644 --- a/code/formfields/EventSendInvitationsButton.php +++ b/code/formfields/EventSendInvitationsButton.php @@ -2,27 +2,30 @@ /** * */ -class EventSendInvitationsButton extends RequestHandler implements GridField_HTMLProvider, GridField_URLHandler { +class EventSendInvitationsButton extends RequestHandler implements GridField_HTMLProvider, GridField_URLHandler +{ - public function sendinvitations($grid) { - return new EventSendInvitationsHandler($grid, $this); - } + public function sendinvitations($grid) + { + return new EventSendInvitationsHandler($grid, $this); + } - public function getHTMLFragments($grid) { - $data = new ArrayData(array( - 'Title' => _t('EventManagement.SEND_INVITATIONS', 'Send Invitations'), - 'Link' => $grid->Link('send-invitations') - )); + public function getHTMLFragments($grid) + { + $data = new ArrayData(array( + 'Title' => _t('EventManagement.SEND_INVITATIONS', 'Send Invitations'), + 'Link' => $grid->Link('send-invitations') + )); - return array( - 'buttons-before-left' => $data->renderWith('EventSendInvitationsButton') - ); - } - - public function getURLHandlers($grid) { - return array( - 'send-invitations' => 'sendinvitations' - ); - } + return array( + 'buttons-before-left' => $data->renderWith('EventSendInvitationsButton') + ); + } + public function getURLHandlers($grid) + { + return array( + 'send-invitations' => 'sendinvitations' + ); + } } diff --git a/code/forms/EventRegisterForm.php b/code/forms/EventRegisterForm.php index 3236d99..ca02322 100644 --- a/code/forms/EventRegisterForm.php +++ b/code/forms/EventRegisterForm.php @@ -6,220 +6,227 @@ * * @package silverstripe-eventmanagement */ -class EventRegisterForm extends MultiForm { - - public static $start_step = 'EventRegisterTicketsStep'; - - public function __construct($controller, $name) { - $this->controller = $controller; - $this->name = $name; - - parent::__construct($controller, $name); - - if ($expires = $this->getExpiryDateTime()) { - Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.js'); - Requirements::add_i18n_javascript('eventmanagement/javascript/lang'); - Requirements::javascript('eventmanagement/javascript/EventRegisterForm.js'); - - $message = _t('EventManagement.PLEASECOMPLETEREGWITHIN', - 'Please complete your registration within %s. If you do not,' - . ' the places that are on hold for you will be released to' - . ' others. You have %s remaining'); - - $remain = strtotime($expires->getValue()) - time(); - $hours = floor($remain / 3600); - $mins = floor(($remain - $hours * 3600) / 60); - $secs = $remain - $hours * 3600 - $mins * 60; - - $remaining = sprintf( - '%s:%s:%s', - str_pad($hours, 2, '0', STR_PAD_LEFT), - str_pad($mins, 2, '0', STR_PAD_LEFT), - str_pad($secs, 2, '0', STR_PAD_LEFT) - ); - - $field = new LiteralField('CompleteRegistrationWithin', sprintf( - "$message
", - $expires->TimeDiff(), $remaining)); - - $this->fields->insertAfter($field, 'Tickets'); - } - } - - /** - * @return SS_Datetime - */ - public function getExpiryDateTime() { - if ($this->getSession()->RegistrationID) { - $created = strtotime($this->getSession()->Registration()->Created); - $limit = $this->controller->getDateTime()->Event()->RegistrationTimeLimit; - - if ($limit) return DBField::create_field('SS_Datetime', $created + $limit); - } - } - - /** - * Handles validating the final step and writing the tickets data to the - * registration object. - */ - public function finish($data, $form) { - $step = $this->getCurrentStep(); - $datetime = $this->getController()->getDateTime(); - $registration = $this->session->getRegistration(); - $ticketsStep = $this->getSavedStepByClass('EventRegisterTicketsStep'); - $tickets = $ticketsStep->loadData(); - - // Check that the requested tickets are still available. - if (!$this->validateTickets($tickets['Tickets'], $form)) { - Session::set("FormInfo.{$form->FormName()}.data", $form->getData()); - $this->controller->redirectBack(); - return false; - } - - $success = parent::finish($data, $form); - if ($success === false) { - return false; - } - - // see whether we've been redirected by the step (most typically with Payment steps) - $controller = Controller::curr(); - /* @var $controller Controller */ - if ($controller->redirectedTo()) { - return; - } - - $this->session->delete(); - - // If the registrations is already valid, then send a details email. - if ($registration->Status == 'Valid') { - EventRegistrationDetailsEmail::factory($registration)->send(); - } - - $this->extend('onRegistrationComplete', $registration); - - $this->controller->redirect(Controller::join_links( - $datetime->Event()->Link(), - 'registration', - $registration->ID, - '?token=' . $registration->Token - )); - } - - /** - * Validates that the tickets requested are available and valid. - * - * @param array $tickets A map of ticket ID to quantity. - * @param Form $form - * @return bool - */ - public function validateTickets($tickets, $form) { - $datetime = $this->controller->getDateTime(); - $session = $this->getSession(); - - // First check we have at least one ticket. - if (!array_sum($tickets)) { - $form->addErrorMessage( - 'Tickets', - 'Please select at least one ticket to purchase.', - 'required'); - return false; - } - - // Loop through each ticket and check that the data entered is valid - // and they are available. - foreach ($tickets as $id => $quantity) { - if (!$quantity) { - continue; - } - - if (!is_int($quantity) && !ctype_digit($quantity)) { - $form->addErrorMessage( - 'Tickets', - 'Please only enter numerical amounts for ticket quantities.', - 'required'); - return false; - } - - $ticket = $datetime->Tickets('"EventTicket"."ID" = ' . (int) $id); - - if (!$ticket = $ticket->First()) { - $form->addErrorMessage( - 'Tickets', 'An invalid ticket ID was entered.', 'required'); - return false; - } - - $avail = $ticket->getAvailableForDateTime($datetime, $session->RegistrationID); - $avail = $avail['available']; - - if (!$avail) { - $form->addErrorMessage( - 'Tickets', - sprintf('%s is currently not available.', $ticket->Title), - 'required'); - return false; - } - - if (is_int($avail) && $avail < $quantity) { - $form->addErrorMessage( - 'Tickets', - sprintf('There are only %d of "%s" available.', $avail, $ticket->Title), - 'required'); - return false; - } - - if ($ticket->MinTickets && $quantity < $ticket->MinTickets) { - $form->addErrorMessage('Tickets',sprintf( - 'You must purchase at least %d of "%s".', - $ticket->MinTickets, $ticket->Title), 'required'); - return false; - } - - if ($ticket->MaxTickets && $quantity > $ticket->MaxTickets) { - $form->addErrorMessage('Tickets', sprintf( - 'You can only purchase at most %d of "%s".', - $ticket->MaxTickets, $ticket->Title), 'required'); - return false; - } - } - - // Then check the sum of the quantities does not exceed the overall - // event capacity. - if ($datetime->Capacity) { - $avail = $datetime->getRemainingCapacity($session->RegistrationID); - $request = array_sum($tickets); - - if ($request > $avail) { - $message = sprintf( - 'The event only has %d overall places remaining, but you ' - . 'have requested a total of %d places. Please select a ' - . 'lower number.', - $avail, $request - ); - $form->addErrorMessage('Tickets', $message, 'required'); - return false; - } - } - - return true; - } - - protected function setSession() { - $this->session = $this->getCurrentSession(); - - // If there was no session found, create a new one instead - if(!$this->session) { - $this->session = new EventRegisterFormSession(); - $this->session->setForm($this); - $this->session->write(); - } else { - $this->session->setForm($this); - } - - // Create encrypted identification to the session instance if it doesn't exist - if(!$this->session->Hash) { - $this->session->Hash = sha1($this->session->ID . '-' . microtime()); - $this->session->write(); - } - } - +class EventRegisterForm extends MultiForm +{ + + public static $start_step = 'EventRegisterTicketsStep'; + + public function __construct($controller, $name) + { + $this->controller = $controller; + $this->name = $name; + + parent::__construct($controller, $name); + + if ($expires = $this->getExpiryDateTime()) { + Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.js'); + Requirements::add_i18n_javascript('eventmanagement/javascript/lang'); + Requirements::javascript('eventmanagement/javascript/EventRegisterForm.js'); + + $message = _t('EventManagement.PLEASECOMPLETEREGWITHIN', + 'Please complete your registration within %s. If you do not,' + . ' the places that are on hold for you will be released to' + . ' others. You have %s remaining'); + + $remain = strtotime($expires->getValue()) - time(); + $hours = floor($remain / 3600); + $mins = floor(($remain - $hours * 3600) / 60); + $secs = $remain - $hours * 3600 - $mins * 60; + + $remaining = sprintf( + '%s:%s:%s', + str_pad($hours, 2, '0', STR_PAD_LEFT), + str_pad($mins, 2, '0', STR_PAD_LEFT), + str_pad($secs, 2, '0', STR_PAD_LEFT) + ); + + $field = new LiteralField('CompleteRegistrationWithin', sprintf( + "$message
", + $expires->TimeDiff(), $remaining)); + + $this->fields->insertAfter($field, 'Tickets'); + } + } + + /** + * @return SS_Datetime + */ + public function getExpiryDateTime() + { + if ($this->getSession()->RegistrationID) { + $created = strtotime($this->getSession()->Registration()->Created); + $limit = $this->controller->getDateTime()->Event()->RegistrationTimeLimit; + + if ($limit) { + return DBField::create_field('SS_Datetime', $created + $limit); + } + } + } + + /** + * Handles validating the final step and writing the tickets data to the + * registration object. + */ + public function finish($data, $form) + { + $step = $this->getCurrentStep(); + $datetime = $this->getController()->getDateTime(); + $registration = $this->session->getRegistration(); + $ticketsStep = $this->getSavedStepByClass('EventRegisterTicketsStep'); + $tickets = $ticketsStep->loadData(); + + // Check that the requested tickets are still available. + if (!$this->validateTickets($tickets['Tickets'], $form)) { + Session::set("FormInfo.{$form->FormName()}.data", $form->getData()); + $this->controller->redirectBack(); + return false; + } + + $success = parent::finish($data, $form); + if ($success === false) { + return false; + } + + // see whether we've been redirected by the step (most typically with Payment steps) + $controller = Controller::curr(); + /* @var $controller Controller */ + if ($controller->redirectedTo()) { + return; + } + + $this->session->delete(); + + // If the registrations is already valid, then send a details email. + if ($registration->Status == 'Valid') { + EventRegistrationDetailsEmail::factory($registration)->send(); + } + + $this->extend('onRegistrationComplete', $registration); + + $this->controller->redirect(Controller::join_links( + $datetime->Event()->Link(), + 'registration', + $registration->ID, + '?token=' . $registration->Token + )); + } + + /** + * Validates that the tickets requested are available and valid. + * + * @param array $tickets A map of ticket ID to quantity. + * @param Form $form + * @return bool + */ + public function validateTickets($tickets, $form) + { + $datetime = $this->controller->getDateTime(); + $session = $this->getSession(); + + // First check we have at least one ticket. + if (!array_sum($tickets)) { + $form->addErrorMessage( + 'Tickets', + 'Please select at least one ticket to purchase.', + 'required'); + return false; + } + + // Loop through each ticket and check that the data entered is valid + // and they are available. + foreach ($tickets as $id => $quantity) { + if (!$quantity) { + continue; + } + + if (!is_int($quantity) && !ctype_digit($quantity)) { + $form->addErrorMessage( + 'Tickets', + 'Please only enter numerical amounts for ticket quantities.', + 'required'); + return false; + } + + $ticket = $datetime->Tickets('"EventTicket"."ID" = ' . (int) $id); + + if (!$ticket = $ticket->First()) { + $form->addErrorMessage( + 'Tickets', 'An invalid ticket ID was entered.', 'required'); + return false; + } + + $avail = $ticket->getAvailableForDateTime($datetime, $session->RegistrationID); + $avail = $avail['available']; + + if (!$avail) { + $form->addErrorMessage( + 'Tickets', + sprintf('%s is currently not available.', $ticket->Title), + 'required'); + return false; + } + + if (is_int($avail) && $avail < $quantity) { + $form->addErrorMessage( + 'Tickets', + sprintf('There are only %d of "%s" available.', $avail, $ticket->Title), + 'required'); + return false; + } + + if ($ticket->MinTickets && $quantity < $ticket->MinTickets) { + $form->addErrorMessage('Tickets', sprintf( + 'You must purchase at least %d of "%s".', + $ticket->MinTickets, $ticket->Title), 'required'); + return false; + } + + if ($ticket->MaxTickets && $quantity > $ticket->MaxTickets) { + $form->addErrorMessage('Tickets', sprintf( + 'You can only purchase at most %d of "%s".', + $ticket->MaxTickets, $ticket->Title), 'required'); + return false; + } + } + + // Then check the sum of the quantities does not exceed the overall + // event capacity. + if ($datetime->Capacity) { + $avail = $datetime->getRemainingCapacity($session->RegistrationID); + $request = array_sum($tickets); + + if ($request > $avail) { + $message = sprintf( + 'The event only has %d overall places remaining, but you ' + . 'have requested a total of %d places. Please select a ' + . 'lower number.', + $avail, $request + ); + $form->addErrorMessage('Tickets', $message, 'required'); + return false; + } + } + + return true; + } + + protected function setSession() + { + $this->session = $this->getCurrentSession(); + + // If there was no session found, create a new one instead + if (!$this->session) { + $this->session = new EventRegisterFormSession(); + $this->session->setForm($this); + $this->session->write(); + } else { + $this->session->setForm($this); + } + + // Create encrypted identification to the session instance if it doesn't exist + if (!$this->session->Hash) { + $this->session->Hash = sha1($this->session->ID . '-' . microtime()); + $this->session->write(); + } + } } diff --git a/code/forms/EventRegisterFormSession.php b/code/forms/EventRegisterFormSession.php index 1f56c6f..1e4ba2b 100644 --- a/code/forms/EventRegisterFormSession.php +++ b/code/forms/EventRegisterFormSession.php @@ -6,56 +6,59 @@ * * @package silverstripe-eventmanagement */ -class EventRegisterFormSession extends MultiFormSession { - - public static $has_one = array( - 'Registration' => 'EventRegistration' - ); - - protected $form; - protected $registration; - - /** - * @param EventRegisterForm $form - */ - public function setForm(EventRegisterForm $form) { - $this->form = $form; - } - - /** - * @return EventRegistration - */ - public function getRegistration() { - if ($this->registration) { - return $this->registration; - } - - if ($this->RegistrationID) { - return $this->registration = $this->Registration(); - } else { - $this->registration = new EventRegistration(); - $this->registration->TimeID = $this->form->getController()->getDateTime()->ID; - $this->registration->Status = 'Unsubmitted'; - - return $this->registration; - } - } - - public function onBeforeWrite() { - parent::onBeforeWrite(); - - if (!$this->form->getController()->getDateTime()->Event()->RegistrationTimeLimit) { - return; - } - - $isInDb = $this->getRegistration()->isInDB(); - $hasTickets = (bool) count($this->getRegistration()->Tickets()); - - if ($isInDb || $hasTickets) { - $this->getRegistration()->write(); - } - - $this->RegistrationID = $this->getRegistration()->ID; - } - -} \ No newline at end of file +class EventRegisterFormSession extends MultiFormSession +{ + + public static $has_one = array( + 'Registration' => 'EventRegistration' + ); + + protected $form; + protected $registration; + + /** + * @param EventRegisterForm $form + */ + public function setForm(EventRegisterForm $form) + { + $this->form = $form; + } + + /** + * @return EventRegistration + */ + public function getRegistration() + { + if ($this->registration) { + return $this->registration; + } + + if ($this->RegistrationID) { + return $this->registration = $this->Registration(); + } else { + $this->registration = new EventRegistration(); + $this->registration->TimeID = $this->form->getController()->getDateTime()->ID; + $this->registration->Status = 'Unsubmitted'; + + return $this->registration; + } + } + + public function onBeforeWrite() + { + parent::onBeforeWrite(); + + if (!$this->form->getController()->getDateTime()->Event()->RegistrationTimeLimit) { + return; + } + + $isInDb = $this->getRegistration()->isInDB(); + $hasTickets = (bool) count($this->getRegistration()->Tickets()); + + if ($isInDb || $hasTickets) { + $this->getRegistration()->write(); + } + + $this->RegistrationID = $this->getRegistration()->ID; + } +} diff --git a/code/forms/EventRegisterFreeConfirmationStep.php b/code/forms/EventRegisterFreeConfirmationStep.php index 37f4f51..bbe3049 100644 --- a/code/forms/EventRegisterFreeConfirmationStep.php +++ b/code/forms/EventRegisterFreeConfirmationStep.php @@ -5,127 +5,132 @@ * * @package silverstripe-eventmanagement */ -class EventRegisterFreeConfirmationStep extends MultiFormStep { - - public static $is_final_step = true; - - public function getTitle() { - return 'Confirmation'; - } - - /** - * Returns this step's data merged with the tickets from the previous step. - * - * @return array - */ - public function loadData() { - $data = parent::loadData(); - $tickets = $this->getForm()->getSavedStepByClass('EventRegisterTicketsStep'); - - $tickets = $tickets->loadData(); - $data['Tickets'] = $tickets['Tickets']; - - return $data; - } - - public function getFields() { - $datetime = $this->getForm()->getController()->getDateTime(); - $session = $this->getForm()->getSession(); - $tickets = $this->getForm()->getSavedStepByClass('EventRegisterTicketsStep'); - $total = $tickets->getTotal(); - - $table = new EventRegistrationTicketsTableField('Tickets', $datetime); - $table->setReadonly(true); - $table->setExcludedRegistrationId($session->RegistrationID); - $table->setShowUnavailableTickets(false); - $table->setShowUnselectedTickets(false); - $table->setForceTotalRow(true); - $table->setTotal($total); - - $fields = new FieldList( - new LiteralField('ConfirmTicketsNote', - 'Please confirm the tickets you wish to register for:
'), - $table - ); - - $this->extend('updateFields', $fields); - return $fields; - } - - public function getValidator() { - $validator = new RequiredFields(); - $this->extend('updateValidator', $validator); - return $validator; - } - - /** - * This does not actually perform any validation, but just creates the - * initial registration object. - */ - public function validateStep($data, $form) { - $form = $this->getForm(); - $datetime = $form->getController()->getDateTime(); - $confirmation = $datetime->Event()->RegEmailConfirm; - $registration = $this->getForm()->getSession()->getRegistration(); - - // If we require email validation for free registrations, then send - // out the email and mark the registration. Otherwise immediately - // mark it as valid. - if ($confirmation) { - $email = new Email(); - $config = SiteConfig::current_site_config(); - - $registration->TimeID = $datetime->ID; - $registration->Status = 'Unconfirmed'; - $registration->write(); - - if (Member::currentUserID()) { - $details = array( - 'Name' => Member::currentUser()->getName(), - 'Email' => Member::currentUser()->Email - ); - } else { - $details = $form->getSavedStepByClass('EventRegisterTicketsStep'); - $details = $details->loadData(); - } - - $link = Controller::join_links( - $this->getForm()->getController()->Link(), - 'confirm', $registration->ID, '?token=' . $registration->Token - ); - - $regLink = Controller::join_links( - $datetime->Event()->Link(), 'registration', $registration->ID, - '?token=' . $registration->Token - ); - - $email->setTo($details['Email']); - $email->setSubject(sprintf( - 'Confirm Registration For %s (%s)', $datetime->EventTitle(), $config->Title - )); - - $email->setTemplate('EventRegistrationConfirmationEmail'); - $email->populateTemplate(array( - 'Name' => $details['Name'], - 'Registration' => $registration, - 'RegLink' => $regLink, - 'Time' => $datetime, - 'SiteConfig' => $config, - 'ConfirmLink' => Director::absoluteURL($link) - )); - - $email->send(); - - Session::set( - "EventRegistration.{$registration->ID}.message", - $datetime->Event()->EmailConfirmMessage - ); - } else { - $registration->Status = 'Valid'; - $registration->write(); - } - - return true; - } - -} \ No newline at end of file +class EventRegisterFreeConfirmationStep extends MultiFormStep +{ + + public static $is_final_step = true; + + public function getTitle() + { + return 'Confirmation'; + } + + /** + * Returns this step's data merged with the tickets from the previous step. + * + * @return array + */ + public function loadData() + { + $data = parent::loadData(); + $tickets = $this->getForm()->getSavedStepByClass('EventRegisterTicketsStep'); + + $tickets = $tickets->loadData(); + $data['Tickets'] = $tickets['Tickets']; + + return $data; + } + + public function getFields() + { + $datetime = $this->getForm()->getController()->getDateTime(); + $session = $this->getForm()->getSession(); + $tickets = $this->getForm()->getSavedStepByClass('EventRegisterTicketsStep'); + $total = $tickets->getTotal(); + + $table = new EventRegistrationTicketsTableField('Tickets', $datetime); + $table->setReadonly(true); + $table->setExcludedRegistrationId($session->RegistrationID); + $table->setShowUnavailableTickets(false); + $table->setShowUnselectedTickets(false); + $table->setForceTotalRow(true); + $table->setTotal($total); + + $fields = new FieldList( + new LiteralField('ConfirmTicketsNote', + 'Please confirm the tickets you wish to register for:
'), + $table + ); + + $this->extend('updateFields', $fields); + return $fields; + } + + public function getValidator() + { + $validator = new RequiredFields(); + $this->extend('updateValidator', $validator); + return $validator; + } + + /** + * This does not actually perform any validation, but just creates the + * initial registration object. + */ + public function validateStep($data, $form) + { + $form = $this->getForm(); + $datetime = $form->getController()->getDateTime(); + $confirmation = $datetime->Event()->RegEmailConfirm; + $registration = $this->getForm()->getSession()->getRegistration(); + + // If we require email validation for free registrations, then send + // out the email and mark the registration. Otherwise immediately + // mark it as valid. + if ($confirmation) { + $email = new Email(); + $config = SiteConfig::current_site_config(); + + $registration->TimeID = $datetime->ID; + $registration->Status = 'Unconfirmed'; + $registration->write(); + + if (Member::currentUserID()) { + $details = array( + 'Name' => Member::currentUser()->getName(), + 'Email' => Member::currentUser()->Email + ); + } else { + $details = $form->getSavedStepByClass('EventRegisterTicketsStep'); + $details = $details->loadData(); + } + + $link = Controller::join_links( + $this->getForm()->getController()->Link(), + 'confirm', $registration->ID, '?token=' . $registration->Token + ); + + $regLink = Controller::join_links( + $datetime->Event()->Link(), 'registration', $registration->ID, + '?token=' . $registration->Token + ); + + $email->setTo($details['Email']); + $email->setSubject(sprintf( + 'Confirm Registration For %s (%s)', $datetime->EventTitle(), $config->Title + )); + + $email->setTemplate('EventRegistrationConfirmationEmail'); + $email->populateTemplate(array( + 'Name' => $details['Name'], + 'Registration' => $registration, + 'RegLink' => $regLink, + 'Time' => $datetime, + 'SiteConfig' => $config, + 'ConfirmLink' => Director::absoluteURL($link) + )); + + $email->send(); + + Session::set( + "EventRegistration.{$registration->ID}.message", + $datetime->Event()->EmailConfirmMessage + ); + } else { + $registration->Status = 'Valid'; + $registration->write(); + } + + return true; + } +} diff --git a/code/forms/EventRegisterPaymentStep.php b/code/forms/EventRegisterPaymentStep.php index 485258e..ee19213 100644 --- a/code/forms/EventRegisterPaymentStep.php +++ b/code/forms/EventRegisterPaymentStep.php @@ -5,166 +5,175 @@ * * @package silverstripe-eventmanagement */ -class EventRegisterPaymentStep extends MultiFormStep { - - public static $is_final_step = true; - - public function getTitle() { - return 'Payment'; - } - - /** - * Returns this step's data merged with the tickets from the previous step. - * - * @return array - */ - public function loadData() { - $data = parent::loadData(); - - - $tickets = $this->getForm()->getSavedStepByClass('EventRegisterTicketsStep'); - $tickets = $tickets->loadData(); - - $data['Tickets'] = $tickets['Tickets']; - - // let's see if we're loading immediately after a payment, in which - // case we want to redirect straight out. - $registration = $this->form->getSession()->getRegistration(); - $paymentID = Session::get('PaymentID'); - - if ($registration && $paymentID) { - $payment = Payment::get()->byID($paymentID); - if ($this->checkPayment($registration, $payment)) { - Controller::curr()->redirect($registration->Link()); - } - } - - return $data; - } - - public function getFields() { - if (!class_exists('Payment')) throw new Exception( - 'Please install the Payment module to accept event payments.' - ); - - $datetime = $this->getForm()->getController()->getDateTime(); - $session = $this->getForm()->getSession(); - $tickets = $this->getForm()->getSavedStepByClass('EventRegisterTicketsStep'); - $total = $tickets->getTotal(); - - $table = new EventRegistrationTicketsTableField('Tickets', $datetime); - $table->setReadonly(true); - $table->setExcludedRegistrationId($session->RegistrationID); - $table->setShowUnavailableTickets(false); - $table->setShowUnselectedTickets(false); - $table->setTotal($total); - - // the following 2 methods are not in the updated payment module - // so ignore them as we will be handling this in the extension anyway - //Requirements::customScript(Payment::combined_form_requirements()); - - // add the payment field via the extension - //$payment = Payment::combined_form_fields($total->Nice()); - - // we will replace this field in the extension - $fields = new FieldList( - new LiteralField('ConfirmTicketsNote', - 'Please confirm the tickets you wish to purchase:
'), - $table - ); - - $this->extend('updateFields', $fields); - return $fields; - } - - public function getValidator() { - $validator = new RequiredFields('PaymentMethod'); - $this->extend('updateValidator', $validator); - return $validator; - } - - public function validateStep($data, $form) { - Session::set("FormInfo.{$form->FormName()}.data", $form->getData()); - - $payment = $data['PaymentMethod']; - $tickets = $this->getForm()->getSavedStepByClass('EventRegisterTicketsStep'); - $total = $tickets->getTotal(); - - $registration = $this->form->getSession()->getRegistration(); - - $data['Currency'] = $total->Currency; - $data['Amount'] = $total->Amount; - - $processor = PaymentFactory::factory($payment); - - try { - $link = $registration->Link(); - $link = $this->Link(); - // Set the url to redirect to after the payment is completed, e.g. - $processor->setRedirectURL(Director::absoluteURL($link)); - // Process the payment - $processor->capture($data); - } catch (Exception $e) { - // Most likely due to connection cannot be extablished or validation fails - return false; - } - - $result = $processor->gateway->getValidationResult(); - $controller = Controller::curr(); - /* @var $controller Controller */ - if ($controller->redirectedTo()) { - return true; - } - - if (!$result->valid()) { - $form->sessionMessage($result->message(), 'required'); - return false; - } - - $this->checkPayment($registration); - // Write an empty registration object so we have an ID to reference the - // payment against. This will be populated in the form's finish() method. - $registration->Status = 'Valid'; - $registration->write(); - - Session::set( - "EventRegistration.{$registration->ID}.message", - strip_tags($payment->Message) - ); - - return true; - } - - /** - * Check whether payment for the given registration succeeded. Returns true if so - * - * @param type $registration - */ - public function checkPayment($registration, $payment = null) { - if (!$payment) { - $paymentID = Session::get('PaymentID'); - if ($paymentID) { - $payment = Payment::get()->byID($paymentID); - } - } - - $paid = false; - if ($payment) { - $payment->PaidForClass = 'EventRegistration'; - $payment->PaidForID = $registration->ID; - $payment->PaidBy = Member::currentUserID(); - $payment->write(); - - $registration->PaymentID = $payment->ID; - if ($payment->Status == PaymentGateway_Result::SUCCESS) { - $registration->Status = 'Valid'; - $paid = true; - $registration->extend('onPaymentConfirmed', $payment->Status); - Session::clear('PaymentID'); - } - $registration->write(); - } - - return $paid; - } +class EventRegisterPaymentStep extends MultiFormStep +{ + + public static $is_final_step = true; + + public function getTitle() + { + return 'Payment'; + } + + /** + * Returns this step's data merged with the tickets from the previous step. + * + * @return array + */ + public function loadData() + { + $data = parent::loadData(); + + + $tickets = $this->getForm()->getSavedStepByClass('EventRegisterTicketsStep'); + $tickets = $tickets->loadData(); + + $data['Tickets'] = $tickets['Tickets']; + + // let's see if we're loading immediately after a payment, in which + // case we want to redirect straight out. + $registration = $this->form->getSession()->getRegistration(); + $paymentID = Session::get('PaymentID'); + + if ($registration && $paymentID) { + $payment = Payment::get()->byID($paymentID); + if ($this->checkPayment($registration, $payment)) { + Controller::curr()->redirect($registration->Link()); + } + } + + return $data; + } + + public function getFields() + { + if (!class_exists('Payment')) { + throw new Exception( + 'Please install the Payment module to accept event payments.' + ); + } + + $datetime = $this->getForm()->getController()->getDateTime(); + $session = $this->getForm()->getSession(); + $tickets = $this->getForm()->getSavedStepByClass('EventRegisterTicketsStep'); + $total = $tickets->getTotal(); + + $table = new EventRegistrationTicketsTableField('Tickets', $datetime); + $table->setReadonly(true); + $table->setExcludedRegistrationId($session->RegistrationID); + $table->setShowUnavailableTickets(false); + $table->setShowUnselectedTickets(false); + $table->setTotal($total); + + // the following 2 methods are not in the updated payment module + // so ignore them as we will be handling this in the extension anyway + //Requirements::customScript(Payment::combined_form_requirements()); + + // add the payment field via the extension + //$payment = Payment::combined_form_fields($total->Nice()); + + // we will replace this field in the extension + $fields = new FieldList( + new LiteralField('ConfirmTicketsNote', + 'Please confirm the tickets you wish to purchase:
'), + $table + ); + + $this->extend('updateFields', $fields); + return $fields; + } + + public function getValidator() + { + $validator = new RequiredFields('PaymentMethod'); + $this->extend('updateValidator', $validator); + return $validator; + } + + public function validateStep($data, $form) + { + Session::set("FormInfo.{$form->FormName()}.data", $form->getData()); + + $payment = $data['PaymentMethod']; + $tickets = $this->getForm()->getSavedStepByClass('EventRegisterTicketsStep'); + $total = $tickets->getTotal(); + + $registration = $this->form->getSession()->getRegistration(); + + $data['Currency'] = $total->Currency; + $data['Amount'] = $total->Amount; + + $processor = PaymentFactory::factory($payment); + + try { + $link = $registration->Link(); + $link = $this->Link(); + // Set the url to redirect to after the payment is completed, e.g. + $processor->setRedirectURL(Director::absoluteURL($link)); + // Process the payment + $processor->capture($data); + } catch (Exception $e) { + // Most likely due to connection cannot be extablished or validation fails + return false; + } + + $result = $processor->gateway->getValidationResult(); + $controller = Controller::curr(); + /* @var $controller Controller */ + if ($controller->redirectedTo()) { + return true; + } + + if (!$result->valid()) { + $form->sessionMessage($result->message(), 'required'); + return false; + } + + $this->checkPayment($registration); + // Write an empty registration object so we have an ID to reference the + // payment against. This will be populated in the form's finish() method. + $registration->Status = 'Valid'; + $registration->write(); + + Session::set( + "EventRegistration.{$registration->ID}.message", + strip_tags($payment->Message) + ); + + return true; + } + + /** + * Check whether payment for the given registration succeeded. Returns true if so + * + * @param type $registration + */ + public function checkPayment($registration, $payment = null) + { + if (!$payment) { + $paymentID = Session::get('PaymentID'); + if ($paymentID) { + $payment = Payment::get()->byID($paymentID); + } + } + + $paid = false; + if ($payment) { + $payment->PaidForClass = 'EventRegistration'; + $payment->PaidForID = $registration->ID; + $payment->PaidBy = Member::currentUserID(); + $payment->write(); + + $registration->PaymentID = $payment->ID; + if ($payment->Status == PaymentGateway_Result::SUCCESS) { + $registration->Status = 'Valid'; + $paid = true; + $registration->extend('onPaymentConfirmed', $payment->Status); + Session::clear('PaymentID'); + } + $registration->write(); + } + + return $paid; + } } diff --git a/code/forms/EventRegisterTicketsStep.php b/code/forms/EventRegisterTicketsStep.php index 079120b..0b153a0 100644 --- a/code/forms/EventRegisterTicketsStep.php +++ b/code/forms/EventRegisterTicketsStep.php @@ -5,159 +5,166 @@ * * @package silverstripe-eventmanagement */ -class EventRegisterTicketsStep extends MultiFormStep { - - public function getTitle() { - return 'Event Tickets'; - } - - /** - * @return string - */ - public function getNextStep() { - if ($this->getTotal()->getAmount() > 0) { - return 'EventRegisterPaymentStep'; - } else { - return 'EventRegisterFreeConfirmationStep'; - } - } - - public function loadData() { - $data = parent::loadData(); - if ($member = Member::currentUser()) { - $data['Name'] = $member->Name; - $data['Email'] = $member->Email; - } - - return $data; - } - - /** - * Returns the total sum of all the tickets the user is purchasing. - * - * @return Money - */ - public function getTotal() { - $amount = 0; - $currency = null; - $data = $this->loadData(); - - if (isset($data['Tickets'])) { - foreach ($data['Tickets'] as $id => $quantity) { - $ticket = DataObject::get_by_id('EventTicket', $id); - $price = $ticket->obj('Price'); - - if ($ticket->Type == 'Free' || !$quantity) { - continue; - } - - $amount += $price->getAmount() * $quantity; - $currency = $price->getCurrency(); - } - } - - return DBField::create_field('Money', array( - 'Amount' => $amount, - 'Currency' => $currency - )); - } - - public function getFields() { - $datetime = $this->getForm()->getController()->getDateTime(); - $session = $this->getForm()->getSession(); - - $fields = new FieldList( - $tickets = new EventRegistrationTicketsTableField('Tickets', $datetime) - ); - $tickets->setExcludedRegistrationId($session->RegistrationID); - - if ($member = Member::currentUser()) { - $fields->push(new ReadonlyField('Name', 'Your name')); - $fields->push(new ReadonlyField('Email', 'Email address')); - } else { - $fields->push(new TextField('Name', 'Your name')); - $fields->push(new EmailField('Email', 'Email address')); - } - - - $this->extend('updateFields', $fields); - - return $fields; - } - - public function getValidator() { - if ($member = Member::currentUser()) { - $validator = new RequiredFields(); - } else { - $validator = new RequiredFields('Name', 'Email'); - } - - $this->extend('updateValidator', $validator); - - return $validator; - } - - public function validateStep($data, $form) { - Session::set("FormInfo.{$form->FormName()}.data", $form->getData()); - - $datetime = $this->getForm()->getController()->getDateTime(); - $data = $form->getData(); - - if ($datetime->Event()->OneRegPerEmail) { - if (Member::currentUserID()) { - $email = Member::currentUser()->Email; - } else { - $email = $data['Email']; - } - - $existing = DataObject::get_one('EventRegistration', sprintf( - '"Email" = \'%s\' AND "Status" <> \'Canceled\' AND "TimeID" = %d', - Convert::raw2sql($email), $datetime->ID - )); - - if ($existing) { - $form->addErrorMessage( - 'Email', - 'A registration for this email address already exists', - 'required'); - return false; - } - } - - // Ensure that the entered ticket data is valid. - if (!$this->form->validateTickets($data['Tickets'], $form)) { - return false; - } - - // Finally add the tickets to the actual registration. - $registration = $this->form->getSession()->getRegistration(); - $form->saveInto($registration); - - if ($member = Member::currentUser()) { - $registration->Name = $member->getName(); - $registration->Email = $member->Email; - } else { - $registration->Name = $data['Name']; - $registration->Email = $data['Email']; - } - - $registration->TimeID = $datetime->ID; - $registration->MemberID = Member::currentUserID(); - - $total = $this->getTotal(); - $registration->Total->setCurrency($total->getCurrency()); - $registration->Total->setAmount($total->getAmount()); - $registration->write(); - - $registration->Tickets()->removeAll(); - - foreach ($data['Tickets'] as $id => $quantity) { - if ($quantity) { - $registration->Tickets()->add($id, array('Quantity' => $quantity)); - } - } - - return true; - } - -} \ No newline at end of file +class EventRegisterTicketsStep extends MultiFormStep +{ + + public function getTitle() + { + return 'Event Tickets'; + } + + /** + * @return string + */ + public function getNextStep() + { + if ($this->getTotal()->getAmount() > 0) { + return 'EventRegisterPaymentStep'; + } else { + return 'EventRegisterFreeConfirmationStep'; + } + } + + public function loadData() + { + $data = parent::loadData(); + if ($member = Member::currentUser()) { + $data['Name'] = $member->Name; + $data['Email'] = $member->Email; + } + + return $data; + } + + /** + * Returns the total sum of all the tickets the user is purchasing. + * + * @return Money + */ + public function getTotal() + { + $amount = 0; + $currency = null; + $data = $this->loadData(); + + if (isset($data['Tickets'])) { + foreach ($data['Tickets'] as $id => $quantity) { + $ticket = DataObject::get_by_id('EventTicket', $id); + $price = $ticket->obj('Price'); + + if ($ticket->Type == 'Free' || !$quantity) { + continue; + } + + $amount += $price->getAmount() * $quantity; + $currency = $price->getCurrency(); + } + } + + return DBField::create_field('Money', array( + 'Amount' => $amount, + 'Currency' => $currency + )); + } + + public function getFields() + { + $datetime = $this->getForm()->getController()->getDateTime(); + $session = $this->getForm()->getSession(); + + $fields = new FieldList( + $tickets = new EventRegistrationTicketsTableField('Tickets', $datetime) + ); + $tickets->setExcludedRegistrationId($session->RegistrationID); + + if ($member = Member::currentUser()) { + $fields->push(new ReadonlyField('Name', 'Your name')); + $fields->push(new ReadonlyField('Email', 'Email address')); + } else { + $fields->push(new TextField('Name', 'Your name')); + $fields->push(new EmailField('Email', 'Email address')); + } + + + $this->extend('updateFields', $fields); + + return $fields; + } + + public function getValidator() + { + if ($member = Member::currentUser()) { + $validator = new RequiredFields(); + } else { + $validator = new RequiredFields('Name', 'Email'); + } + + $this->extend('updateValidator', $validator); + + return $validator; + } + + public function validateStep($data, $form) + { + Session::set("FormInfo.{$form->FormName()}.data", $form->getData()); + + $datetime = $this->getForm()->getController()->getDateTime(); + $data = $form->getData(); + + if ($datetime->Event()->OneRegPerEmail) { + if (Member::currentUserID()) { + $email = Member::currentUser()->Email; + } else { + $email = $data['Email']; + } + + $existing = DataObject::get_one('EventRegistration', sprintf( + '"Email" = \'%s\' AND "Status" <> \'Canceled\' AND "TimeID" = %d', + Convert::raw2sql($email), $datetime->ID + )); + + if ($existing) { + $form->addErrorMessage( + 'Email', + 'A registration for this email address already exists', + 'required'); + return false; + } + } + + // Ensure that the entered ticket data is valid. + if (!$this->form->validateTickets($data['Tickets'], $form)) { + return false; + } + + // Finally add the tickets to the actual registration. + $registration = $this->form->getSession()->getRegistration(); + $form->saveInto($registration); + + if ($member = Member::currentUser()) { + $registration->Name = $member->getName(); + $registration->Email = $member->Email; + } else { + $registration->Name = $data['Name']; + $registration->Email = $data['Email']; + } + + $registration->TimeID = $datetime->ID; + $registration->MemberID = Member::currentUserID(); + + $total = $this->getTotal(); + $registration->Total->setCurrency($total->getCurrency()); + $registration->Total->setAmount($total->getAmount()); + $registration->write(); + + $registration->Tickets()->removeAll(); + + foreach ($data['Tickets'] as $id => $quantity) { + if ($quantity) { + $registration->Tickets()->add($id, array('Quantity' => $quantity)); + } + } + + return true; + } +} diff --git a/code/jobs/EventReminderEmailJob.php b/code/jobs/EventReminderEmailJob.php index cde3117..a4d8cf6 100644 --- a/code/jobs/EventReminderEmailJob.php +++ b/code/jobs/EventReminderEmailJob.php @@ -4,71 +4,76 @@ * * @package silverstripe-eventmanagement */ -class EventReminderEmailJob extends AbstractQueuedJob { +class EventReminderEmailJob extends AbstractQueuedJob +{ - public function __construct($datetime = null) { - if ($datetime) { - $this->datetimeID = $datetime->ID; - $registrations = $datetime->Registrations('"Status" = \'Valid\''); - $this->emails = $registrations->map('Email', 'Name'); - $this->totalSteps = count($this->emails); - } - } + public function __construct($datetime = null) + { + if ($datetime) { + $this->datetimeID = $datetime->ID; + $registrations = $datetime->Registrations('"Status" = \'Valid\''); + $this->emails = $registrations->map('Email', 'Name'); + $this->totalSteps = count($this->emails); + } + } - public function getTitle() { - return 'Event Registration Reminder Email Job'; - } + public function getTitle() + { + return 'Event Registration Reminder Email Job'; + } - /** - * @return RegistrableDateTime - */ - public function getDatetime() { - return DataObject::get_by_id('RegisterbleDateTime', $this->datetimeID); - } - public function setup() { - parent::setup(); - $datetime = $this->getDatetime(); - $registrations = $datetime->Registrations('"Status" = \'Valid\''); - $this->emails = $registrations->map('Email', 'Name'); - $this->totalSteps = count($this->emails); - } - public function process() { - $config = SiteConfig::current_site_config(); - $datetime = $this->getDatetime(); - $emails = $this->emails; + /** + * @return RegistrableDateTime + */ + public function getDatetime() + { + return DataObject::get_by_id('RegisterbleDateTime', $this->datetimeID); + } + public function setup() + { + parent::setup(); + $datetime = $this->getDatetime(); + $registrations = $datetime->Registrations('"Status" = \'Valid\''); + $this->emails = $registrations->map('Email', 'Name'); + $this->totalSteps = count($this->emails); + } + public function process() + { + $config = SiteConfig::current_site_config(); + $datetime = $this->getDatetime(); + $emails = $this->emails; - if (!count($emails)) { - $this->isComplete = true; - return; - } + if (!count($emails)) { + $this->isComplete = true; + return; + } - $email = new Email(); - $email->setSubject(sprintf( - _t('EventManagement.EVENTREMINDERSUBJECT', 'Event Reminder For %s (%s)'), - $datetime->EventTitle(), $config->Title - )); + $email = new Email(); + $email->setSubject(sprintf( + _t('EventManagement.EVENTREMINDERSUBJECT', 'Event Reminder For %s (%s)'), + $datetime->EventTitle(), $config->Title + )); - $email->setTemplate('EventReminderEmail'); - $email->populateTemplate(array( - 'SiteConfig' => $config, - 'Datetime' => $datetime - )); + $email->setTemplate('EventReminderEmail'); + $email->populateTemplate(array( + 'SiteConfig' => $config, + 'Datetime' => $datetime + )); - foreach ($emails as $addr => $name) { - $_email = clone $email; + foreach ($emails as $addr => $name) { + $_email = clone $email; - $_email->setTo($addr); - $_email->populateTemplate(array('Name' => $name)); - $_email->send(); + $_email->setTo($addr); + $_email->populateTemplate(array('Name' => $name)); + $_email->send(); - unset($emails[$addr]); - $this->emails = $emails; - ++$this->currentStep; - } + unset($emails[$addr]); + $this->emails = $emails; + ++$this->currentStep; + } - if (!count($emails)) { - $this->isComplete = true; - } - } - -} \ No newline at end of file + if (!count($emails)) { + $this->isComplete = true; + } + } +} diff --git a/code/pages/RegistrableEvent.php b/code/pages/RegistrableEvent.php index 5c8fc7d..3ca27ab 100644 --- a/code/pages/RegistrableEvent.php +++ b/code/pages/RegistrableEvent.php @@ -2,307 +2,311 @@ /** * A calendar event that can people can register to attend. */ -class RegistrableEvent extends CalendarEvent { - - private static $db = array( - 'TicketGenerator' => 'Varchar(255)', - 'OneRegPerEmail' => 'Boolean', - 'RequireLoggedIn' => 'Boolean', - 'RegistrationTimeLimit' => 'Int', - 'RegEmailConfirm' => 'Boolean', - 'EmailConfirmMessage' => 'Varchar(255)', - 'ConfirmTimeLimit' => 'Int', - 'AfterConfirmTitle' => 'Varchar(255)', - 'AfterConfirmContent' => 'HTMLText', - 'UnRegEmailConfirm' => 'Boolean', - 'AfterConfUnregTitle' => 'Varchar(255)', - 'AfterConfUnregContent' => 'HTMLText', - 'EmailNotifyChanges' => 'Boolean', - 'NotifyChangeFields' => 'Text', - 'AfterRegTitle' => 'Varchar(255)', - 'AfterRegContent' => 'HTMLText', - 'AfterUnregTitle' => 'Varchar(255)', - 'AfterUnregContent' => 'HTMLText' - ); - - private static $has_many = array( - 'Tickets' => 'EventTicket', - 'DateTimes' => 'RegistrableDateTime', - 'Invitations' => 'EventInvitation' - ); - - private static $defaults = array( - 'RegistrationTimeLimit' => 900, - 'AfterRegTitle' => 'Thanks For Registering', - 'AfterRegContent' => 'Thanks for registering! We look forward to seeing you.
', - 'EmailConfirmMessage' => 'Important: You must check your emails and confirm your registration before it is valid.', - 'ConfirmTimeLimit' => 21600, - 'AfterConfirmTitle' => 'Registration Confirmed', - 'AfterConfirmContent' => 'Thanks! Your registration has been confirmed
', - 'AfterUnregTitle' => 'Registration Canceled', - 'AfterUnregContent' => 'Your registration has been canceled.
', - 'AfterConfUnregTitle' => 'Un-Registration Confirmed', - 'AfterConfUnregContent' => 'Your registration has been canceled.
', - 'NotifyChangeFields' => 'StartDate,EndDate,StartTime,EndTime' - ); - - private static $icon = "eventmanagement/images/date_edit.png"; - - private static $description = "An event that can be registered for."; - - public function getCMSFields() { - $fields = parent::getCMSFields(); - - $fields->insertAfter( - new ToggleCompositeField( - 'AfterRegistrationContent', - _t('EventRegistration.AFTER_REG_CONTENT', 'After Registration Content'), - array( - new TextField('AfterRegTitle', _t('EventRegistration.TITLE', 'Title')), - new HtmlEditorField('AfterRegContent', _t('EventRegistration.CONTENT', 'Content')) - ) - ), - 'Content' - ); - - $fields->insertAfter( - new ToggleCompositeField( - 'AfterUnRegistrationContent', - _t('EventRegistration.AFTER_UNREG_CONTENT', 'After Un-Registration Content'), - array( - new TextField('AfterUnregTitle', _t('EventRegistration.TITLE', 'Title')), - new HtmlEditorField('AfterUnregContent', _t('EventRegistration.CONTENT', 'Content')) - ) - ), - 'AfterRegistrationContent' - ); - - if ($this->RegEmailConfirm) { - $fields->addFieldToTab('Root.Main', new ToggleCompositeField( - 'AfterRegistrationConfirmation', - _t('EventRegistration.AFTER_REG_CONFIRM_CONTENT', 'After Registration Confirmation Content'), - array( - new TextField('AfterConfirmTitle', _t('EventRegistration.TITLE', 'Title')), - new HtmlEditorField('AfterConfirmContent', _t('EventRegistration.CONTENT', 'Content')) - ) - )); - } - - if ($this->UnRegEmailConfirm) { - $fields->addFieldToTab('Root.Main', new ToggleCompositeField( - 'AfterUnRegistrationConfirmation', - _t('EventRegistration.AFTER_UNREG_CONFIRM_CONTENT', 'After Un-Registration Confirmation Content'), - array( - new TextField('AfterConfUnregTitle', _t('EventRegistration.TITLE', 'Title')), - new HtmlEditorField('AfterConfUnregContent', _t('EventRegistration.CONTENT', 'Content')) - ) - )); - } - - $fields->addFieldToTab('Root.Tickets', new GridField( - 'Tickets', - 'Ticket Types', - $this->Tickets(), - GridFieldConfig_RecordEditor::create() - )); - - $generators = ClassInfo::implementorsOf('EventRegistrationTicketGenerator'); - - if ($generators) { - foreach ($generators as $generator) { - $instance = new $generator(); - $generators[$generator] = $instance->getGeneratorTitle(); - } - - $generator = new DropdownField( - 'TicketGenerator', - _t('EventRegistration.TICKET_GENERATOR', 'Ticket generator'), - $generators - ); - - $generator->setEmptyString(_t('EventManagement.NONE', '(None)')); - $generator->setDescription(_t( - 'EventManagement.TICKET_GENERATOR_NOTE', - 'The ticket generator is used to generate a ticket file for the user to download.' - )); - - $fields->addFieldToTab('Root.Tickets', $generator); - } - - $regGridFieldConfig = GridFieldConfig_Base::create() - ->removeComponentsByType('GridFieldAddNewButton') - ->removeComponentsByType('GridFieldDeleteAction') - ->addComponents( - new GridFieldButtonRow('after'), - new GridFieldPrintButton('buttons-after-left'), - new GridFieldExportButton('buttons-after-left') - ); - - $fields->addFieldsToTab('Root.Registrations', array( - new GridField( - 'Registrations', - _t('EventManagement.REGISTRATIONS', 'Registrations'), - $this->DateTimes()->relation('Registrations')->filter('Status', 'Valid'), - $regGridFieldConfig - ), - new GridField( - 'CanceledRegistrations', - _t('EventManagement.CANCELLATIONS', 'Cancellations'), - $this->DateTimes()->relation('Registrations')->filter('Status', 'Canceled'), - $regGridFieldConfig - ) - )); - - if ($this->RegEmailConfirm) { - $fields->addFieldToTab('Root.Registrations', new ToggleCompositeField( - 'UnconfirmedRegistrations', - _t('EventManagement.UNCONFIRMED_REGISTRATIONS', 'Unconfirmed Registrations'), - array( - new GridField( - 'UnconfirmedRegistrations', - '', - $this->DateTimes()->relation('Registrations')->filter('Status', 'Unconfirmed') - ) - ) - )); - } - - $fields->addFieldToTab('Root.Invitations', new GridField( - 'Invitations', - _t('EventManagement.INVITATIONS', 'Invitations'), - $this->Invitations(), - GridFieldConfig_RecordViewer::create() - ->addComponent(new GridFieldButtonRow('before')) - ->addComponent(new EventSendInvitationsButton($this)) - )); - - return $fields; - } - - public function getSettingsFields() { - $fields = parent::getSettingsFields(); - - Requirements::javascript('eventmanagement/javascript/cms.js'); - - $fields->addFieldsToTab('Root.Registration', array( - new CheckboxField( - 'OneRegPerEmail', - _t('EventManagement.ONE_REG_PER_EMAIL', 'Limit to one registration per email address?') - ), - new CheckboxField( - 'RequireLoggedIn', - _t('EventManagement.REQUIRE_LOGGED_IN', 'Require users to be logged in to register?') - ), - $limit = new NumericField( - 'RegistrationTimeLimit', - _t('EventManagement.REG_TIME_LIMIT', 'Registration time limit') - ), - )); - - $limit->setDescription(_t( - 'EventManagement.REG_TIME_LIMIT_NOTE', - 'The time limit to complete registration, in seconds. Set to 0 to disable place holding.' - )); - - $fields->addFieldsToTab('Root.Email', array( - new CheckboxField( - 'RegEmailConfirm', - _t('EventManagement.REQ_EMAIL_CONFIRM', 'Require email confirmation to complete free registrations?') - ), - $info = new TextField( - 'EmailConfirmMessage', - _t('EventManagement.EMAIL_CONFIRM_INFO', 'Email confirmation information') - ), - $limit = new NumericField( - 'ConfirmTimeLimit', - _t('EventManagement.EMAIL_CONFIRM_TIME_LIMIT', 'Email confirmation time limit') - ), - new CheckboxField( - 'UnRegEmailConfirm', - _t('EventManagement.REQ_UN_REG_EMAIL_CONFIRM', 'Require email confirmation to un-register?') - ), - new CheckboxField( - 'EmailNotifyChanges', - _t('EventManagement.EMAIL_NOTIFY_CHANGES', 'Notify registered users of event changes via email?') - ), - new CheckboxSetField( - 'NotifyChangeFields', - _t('EventManagement.NOTIFY_CHANGE_IN', 'Notify of changes in'), - singleton('RegistrableDateTime')->fieldLabels(false) - ) - )); - - $info->setDescription(_t( - 'EventManagement.EMAIL_CONFIRM_INFO_NOTE', - 'This message is displayed to users to let them know they need to confirm their registration.' - )); - - $limit->setDescription(_t( - 'EventManagement.CONFIRM_TIME_LIMIT_NOTE', - 'The time limit to conform registration, in seconds. Set to 0 for no limit.' - )); - - return $fields; - } - +class RegistrableEvent extends CalendarEvent +{ + + private static $db = array( + 'TicketGenerator' => 'Varchar(255)', + 'OneRegPerEmail' => 'Boolean', + 'RequireLoggedIn' => 'Boolean', + 'RegistrationTimeLimit' => 'Int', + 'RegEmailConfirm' => 'Boolean', + 'EmailConfirmMessage' => 'Varchar(255)', + 'ConfirmTimeLimit' => 'Int', + 'AfterConfirmTitle' => 'Varchar(255)', + 'AfterConfirmContent' => 'HTMLText', + 'UnRegEmailConfirm' => 'Boolean', + 'AfterConfUnregTitle' => 'Varchar(255)', + 'AfterConfUnregContent' => 'HTMLText', + 'EmailNotifyChanges' => 'Boolean', + 'NotifyChangeFields' => 'Text', + 'AfterRegTitle' => 'Varchar(255)', + 'AfterRegContent' => 'HTMLText', + 'AfterUnregTitle' => 'Varchar(255)', + 'AfterUnregContent' => 'HTMLText' + ); + + private static $has_many = array( + 'Tickets' => 'EventTicket', + 'DateTimes' => 'RegistrableDateTime', + 'Invitations' => 'EventInvitation' + ); + + private static $defaults = array( + 'RegistrationTimeLimit' => 900, + 'AfterRegTitle' => 'Thanks For Registering', + 'AfterRegContent' => 'Thanks for registering! We look forward to seeing you.
', + 'EmailConfirmMessage' => 'Important: You must check your emails and confirm your registration before it is valid.', + 'ConfirmTimeLimit' => 21600, + 'AfterConfirmTitle' => 'Registration Confirmed', + 'AfterConfirmContent' => 'Thanks! Your registration has been confirmed
', + 'AfterUnregTitle' => 'Registration Canceled', + 'AfterUnregContent' => 'Your registration has been canceled.
', + 'AfterConfUnregTitle' => 'Un-Registration Confirmed', + 'AfterConfUnregContent' => 'Your registration has been canceled.
', + 'NotifyChangeFields' => 'StartDate,EndDate,StartTime,EndTime' + ); + + private static $icon = "eventmanagement/images/date_edit.png"; + + private static $description = "An event that can be registered for."; + + public function getCMSFields() + { + $fields = parent::getCMSFields(); + + $fields->insertAfter( + new ToggleCompositeField( + 'AfterRegistrationContent', + _t('EventRegistration.AFTER_REG_CONTENT', 'After Registration Content'), + array( + new TextField('AfterRegTitle', _t('EventRegistration.TITLE', 'Title')), + new HtmlEditorField('AfterRegContent', _t('EventRegistration.CONTENT', 'Content')) + ) + ), + 'Content' + ); + + $fields->insertAfter( + new ToggleCompositeField( + 'AfterUnRegistrationContent', + _t('EventRegistration.AFTER_UNREG_CONTENT', 'After Un-Registration Content'), + array( + new TextField('AfterUnregTitle', _t('EventRegistration.TITLE', 'Title')), + new HtmlEditorField('AfterUnregContent', _t('EventRegistration.CONTENT', 'Content')) + ) + ), + 'AfterRegistrationContent' + ); + + if ($this->RegEmailConfirm) { + $fields->addFieldToTab('Root.Main', new ToggleCompositeField( + 'AfterRegistrationConfirmation', + _t('EventRegistration.AFTER_REG_CONFIRM_CONTENT', 'After Registration Confirmation Content'), + array( + new TextField('AfterConfirmTitle', _t('EventRegistration.TITLE', 'Title')), + new HtmlEditorField('AfterConfirmContent', _t('EventRegistration.CONTENT', 'Content')) + ) + )); + } + + if ($this->UnRegEmailConfirm) { + $fields->addFieldToTab('Root.Main', new ToggleCompositeField( + 'AfterUnRegistrationConfirmation', + _t('EventRegistration.AFTER_UNREG_CONFIRM_CONTENT', 'After Un-Registration Confirmation Content'), + array( + new TextField('AfterConfUnregTitle', _t('EventRegistration.TITLE', 'Title')), + new HtmlEditorField('AfterConfUnregContent', _t('EventRegistration.CONTENT', 'Content')) + ) + )); + } + + $fields->addFieldToTab('Root.Tickets', new GridField( + 'Tickets', + 'Ticket Types', + $this->Tickets(), + GridFieldConfig_RecordEditor::create() + )); + + $generators = ClassInfo::implementorsOf('EventRegistrationTicketGenerator'); + + if ($generators) { + foreach ($generators as $generator) { + $instance = new $generator(); + $generators[$generator] = $instance->getGeneratorTitle(); + } + + $generator = new DropdownField( + 'TicketGenerator', + _t('EventRegistration.TICKET_GENERATOR', 'Ticket generator'), + $generators + ); + + $generator->setEmptyString(_t('EventManagement.NONE', '(None)')); + $generator->setDescription(_t( + 'EventManagement.TICKET_GENERATOR_NOTE', + 'The ticket generator is used to generate a ticket file for the user to download.' + )); + + $fields->addFieldToTab('Root.Tickets', $generator); + } + + $regGridFieldConfig = GridFieldConfig_Base::create() + ->removeComponentsByType('GridFieldAddNewButton') + ->removeComponentsByType('GridFieldDeleteAction') + ->addComponents( + new GridFieldButtonRow('after'), + new GridFieldPrintButton('buttons-after-left'), + new GridFieldExportButton('buttons-after-left') + ); + + $fields->addFieldsToTab('Root.Registrations', array( + new GridField( + 'Registrations', + _t('EventManagement.REGISTRATIONS', 'Registrations'), + $this->DateTimes()->relation('Registrations')->filter('Status', 'Valid'), + $regGridFieldConfig + ), + new GridField( + 'CanceledRegistrations', + _t('EventManagement.CANCELLATIONS', 'Cancellations'), + $this->DateTimes()->relation('Registrations')->filter('Status', 'Canceled'), + $regGridFieldConfig + ) + )); + + if ($this->RegEmailConfirm) { + $fields->addFieldToTab('Root.Registrations', new ToggleCompositeField( + 'UnconfirmedRegistrations', + _t('EventManagement.UNCONFIRMED_REGISTRATIONS', 'Unconfirmed Registrations'), + array( + new GridField( + 'UnconfirmedRegistrations', + '', + $this->DateTimes()->relation('Registrations')->filter('Status', 'Unconfirmed') + ) + ) + )); + } + + $fields->addFieldToTab('Root.Invitations', new GridField( + 'Invitations', + _t('EventManagement.INVITATIONS', 'Invitations'), + $this->Invitations(), + GridFieldConfig_RecordViewer::create() + ->addComponent(new GridFieldButtonRow('before')) + ->addComponent(new EventSendInvitationsButton($this)) + )); + + return $fields; + } + + public function getSettingsFields() + { + $fields = parent::getSettingsFields(); + + Requirements::javascript('eventmanagement/javascript/cms.js'); + + $fields->addFieldsToTab('Root.Registration', array( + new CheckboxField( + 'OneRegPerEmail', + _t('EventManagement.ONE_REG_PER_EMAIL', 'Limit to one registration per email address?') + ), + new CheckboxField( + 'RequireLoggedIn', + _t('EventManagement.REQUIRE_LOGGED_IN', 'Require users to be logged in to register?') + ), + $limit = new NumericField( + 'RegistrationTimeLimit', + _t('EventManagement.REG_TIME_LIMIT', 'Registration time limit') + ), + )); + + $limit->setDescription(_t( + 'EventManagement.REG_TIME_LIMIT_NOTE', + 'The time limit to complete registration, in seconds. Set to 0 to disable place holding.' + )); + + $fields->addFieldsToTab('Root.Email', array( + new CheckboxField( + 'RegEmailConfirm', + _t('EventManagement.REQ_EMAIL_CONFIRM', 'Require email confirmation to complete free registrations?') + ), + $info = new TextField( + 'EmailConfirmMessage', + _t('EventManagement.EMAIL_CONFIRM_INFO', 'Email confirmation information') + ), + $limit = new NumericField( + 'ConfirmTimeLimit', + _t('EventManagement.EMAIL_CONFIRM_TIME_LIMIT', 'Email confirmation time limit') + ), + new CheckboxField( + 'UnRegEmailConfirm', + _t('EventManagement.REQ_UN_REG_EMAIL_CONFIRM', 'Require email confirmation to un-register?') + ), + new CheckboxField( + 'EmailNotifyChanges', + _t('EventManagement.EMAIL_NOTIFY_CHANGES', 'Notify registered users of event changes via email?') + ), + new CheckboxSetField( + 'NotifyChangeFields', + _t('EventManagement.NOTIFY_CHANGE_IN', 'Notify of changes in'), + singleton('RegistrableDateTime')->fieldLabels(false) + ) + )); + + $info->setDescription(_t( + 'EventManagement.EMAIL_CONFIRM_INFO_NOTE', + 'This message is displayed to users to let them know they need to confirm their registration.' + )); + + $limit->setDescription(_t( + 'EventManagement.CONFIRM_TIME_LIMIT_NOTE', + 'The time limit to conform registration, in seconds. Set to 0 for no limit.' + )); + + return $fields; + } } -class RegistrableEvent_Controller extends CalendarEvent_Controller { - - public static $allowed_actions = array( - 'details', - 'registration' - ); - - /** - * Shows details for an individual event date time, as well as forms for - * registering and un-registering. - * - * @param SS_HTTPRequest $request - * @return array - */ - public function details($request) { - $id = $request->param('ID'); - - if (!ctype_digit($id)) { - $this->httpError(404); - } - - $time = RegistrableDateTime::get()->byID($id); - - if (!$time || $time->EventID != $this->ID) { - $this->httpError(404); - } - - $request->shift(); - $request->shiftAllParams(); - - return new EventTimeDetailsController($this, $time); - } - - /** - * Allows a user to view the details of their registration. - * - * @param SS_HTTPRequest $request - * @return EventRegistrationDetailsController - */ - public function registration($request) { - $id = $request->param('ID'); - - if (!ctype_digit($id)) { - $this->httpError(404); - } - - $rego = EventRegistration::get()->byID($id); - - if (!$rego || $rego->Time()->EventID != $this->ID) { - $this->httpError(404); - } - - $request->shift(); - $request->shiftAllParams(); - - return new EventRegistrationDetailsController($this, $rego); - } - +class RegistrableEvent_Controller extends CalendarEvent_Controller +{ + + public static $allowed_actions = array( + 'details', + 'registration' + ); + + /** + * Shows details for an individual event date time, as well as forms for + * registering and un-registering. + * + * @param SS_HTTPRequest $request + * @return array + */ + public function details($request) + { + $id = $request->param('ID'); + + if (!ctype_digit($id)) { + $this->httpError(404); + } + + $time = RegistrableDateTime::get()->byID($id); + + if (!$time || $time->EventID != $this->ID) { + $this->httpError(404); + } + + $request->shift(); + $request->shiftAllParams(); + + return new EventTimeDetailsController($this, $time); + } + + /** + * Allows a user to view the details of their registration. + * + * @param SS_HTTPRequest $request + * @return EventRegistrationDetailsController + */ + public function registration($request) + { + $id = $request->param('ID'); + + if (!ctype_digit($id)) { + $this->httpError(404); + } + + $rego = EventRegistration::get()->byID($id); + + if (!$rego || $rego->Time()->EventID != $this->ID) { + $this->httpError(404); + } + + $request->shift(); + $request->shiftAllParams(); + + return new EventRegistrationDetailsController($this, $rego); + } } diff --git a/code/tasks/EventRegistrationPurgeTask.php b/code/tasks/EventRegistrationPurgeTask.php index 1afb99b..f22c542 100644 --- a/code/tasks/EventRegistrationPurgeTask.php +++ b/code/tasks/EventRegistrationPurgeTask.php @@ -5,80 +5,85 @@ * * @package silverstripe-eventmanagement */ -class EventRegistrationPurgeTask extends BuildTask { - - public function getTitle() { - return 'Event Registration Purge Task'; - } - - public function getDescription() { - return 'Cancels unconfirmed and unsubmitted registrations older than ' - . 'the cut-off date to free up the places.'; - } - - public function run($request) { - $this->purgeUnsubmittedRegistrations(); - $this->purgeUnconfirmedRegistrations(); - } - - protected function purgeUnsubmittedRegistrations() { - $conn = DB::getConn(); - $created = $conn->formattedDatetimeClause('"EventRegistration"."Created"', '%U'); - - $items = DataObject::get( - 'EventRegistration', - '"Status" = \'Unsubmitted\'' - . " AND $created + \"Registrable\".\"RegistrationTimeLimit\" < " . time(), - null, - 'INNER JOIN "CalendarDateTime" AS "DateTime" ON "TimeID" = "DateTime"."ID"' - . ' INNER JOIN "CalendarEvent" AS "Event" ON "DateTime"."EventID" = "Event"."ID"' - . ' INNER JOIN "RegistrableEvent" AS "Registrable" ON "Event"."ID" = "Registrable"."ID"' - ); - - if ($items) { - $count = count($items); - - foreach ($items as $registration) { - $registration->delete(); - } - } else { - $count = 0; - } - - echo "$count unsubmitted registrations were permantently deleted.\n"; - } - - protected function purgeUnconfirmedRegistrations() { - $query = new SQLQuery(); - $conn = DB::getConn(); - - $query->select('"EventRegistration"."ID"'); - $query->from('"EventRegistration"'); - - $query->innerJoin('CalendarDateTime', '"TimeID" = "DateTime"."ID"', 'DateTime'); - $query->innerJoin('CalendarEvent', '"DateTime"."EventID" = "Event"."ID"', 'Event'); - $query->innerJoin('RegistrableEvent', '"Event"."ID" = "Registrable"."ID"', 'Registrable'); - - $query->where('"Registrable"."ConfirmTimeLimit" > 0'); - $query->where('"Status"', 'Unconfirmed'); - - $created = $conn->formattedDatetimeClause('"EventRegistration"."Created"', '%U'); - $query->where(sprintf( - '%s < %s', $created . ' + "Registrable"."ConfirmTimeLimit"', time() - )); - - if ($ids = $query->execute()->column()) { - $count = count($ids); - - DB::query(sprintf( - 'UPDATE "EventRegistration" SET "Status" = \'Canceled\' WHERE "ID" IN (%s)', - implode(', ', $ids) - )); - } else { - $count = 0; - } - - echo "$count unconfirmed registrations were canceled.\n"; - } - -} \ No newline at end of file +class EventRegistrationPurgeTask extends BuildTask +{ + + public function getTitle() + { + return 'Event Registration Purge Task'; + } + + public function getDescription() + { + return 'Cancels unconfirmed and unsubmitted registrations older than ' + . 'the cut-off date to free up the places.'; + } + + public function run($request) + { + $this->purgeUnsubmittedRegistrations(); + $this->purgeUnconfirmedRegistrations(); + } + + protected function purgeUnsubmittedRegistrations() + { + $conn = DB::getConn(); + $created = $conn->formattedDatetimeClause('"EventRegistration"."Created"', '%U'); + + $items = DataObject::get( + 'EventRegistration', + '"Status" = \'Unsubmitted\'' + . " AND $created + \"Registrable\".\"RegistrationTimeLimit\" < " . time(), + null, + 'INNER JOIN "CalendarDateTime" AS "DateTime" ON "TimeID" = "DateTime"."ID"' + . ' INNER JOIN "CalendarEvent" AS "Event" ON "DateTime"."EventID" = "Event"."ID"' + . ' INNER JOIN "RegistrableEvent" AS "Registrable" ON "Event"."ID" = "Registrable"."ID"' + ); + + if ($items) { + $count = count($items); + + foreach ($items as $registration) { + $registration->delete(); + } + } else { + $count = 0; + } + + echo "$count unsubmitted registrations were permantently deleted.\n"; + } + + protected function purgeUnconfirmedRegistrations() + { + $query = new SQLQuery(); + $conn = DB::getConn(); + + $query->select('"EventRegistration"."ID"'); + $query->from('"EventRegistration"'); + + $query->innerJoin('CalendarDateTime', '"TimeID" = "DateTime"."ID"', 'DateTime'); + $query->innerJoin('CalendarEvent', '"DateTime"."EventID" = "Event"."ID"', 'Event'); + $query->innerJoin('RegistrableEvent', '"Event"."ID" = "Registrable"."ID"', 'Registrable'); + + $query->where('"Registrable"."ConfirmTimeLimit" > 0'); + $query->where('"Status"', 'Unconfirmed'); + + $created = $conn->formattedDatetimeClause('"EventRegistration"."Created"', '%U'); + $query->where(sprintf( + '%s < %s', $created . ' + "Registrable"."ConfirmTimeLimit"', time() + )); + + if ($ids = $query->execute()->column()) { + $count = count($ids); + + DB::query(sprintf( + 'UPDATE "EventRegistration" SET "Status" = \'Canceled\' WHERE "ID" IN (%s)', + implode(', ', $ids) + )); + } else { + $count = 0; + } + + echo "$count unconfirmed registrations were canceled.\n"; + } +} diff --git a/code/tickets/EventRegistrationTicketGenerator.php b/code/tickets/EventRegistrationTicketGenerator.php index 359cdd8..b40544a 100644 --- a/code/tickets/EventRegistrationTicketGenerator.php +++ b/code/tickets/EventRegistrationTicketGenerator.php @@ -5,41 +5,41 @@ * * @package silverstripe-eventmanagement */ -interface EventRegistrationTicketGenerator { +interface EventRegistrationTicketGenerator +{ - /** - * Returns a human-readable name for the ticket generator. - * - * @return string - */ - public function getGeneratorTitle(); + /** + * Returns a human-readable name for the ticket generator. + * + * @return string + */ + public function getGeneratorTitle(); - /** - * Returns the file name the generated ticket file should have. - * - * @param EventRegistration $registration - * @return string - */ - public function getTicketFilenameFor(EventRegistration $registration); + /** + * Returns the file name the generated ticket file should have. + * + * @param EventRegistration $registration + * @return string + */ + public function getTicketFilenameFor(EventRegistration $registration); - /** - * Returns the mime type that the generated ticket file for a registration - * should have. - * - * @param EventRegistration $registration - * @return string - */ - public function getTicketMimeTypeFor(EventRegistration $registration); + /** + * Returns the mime type that the generated ticket file for a registration + * should have. + * + * @param EventRegistration $registration + * @return string + */ + public function getTicketMimeTypeFor(EventRegistration $registration); - /** - * Generates a ticket file for a registration, and returns the path to the - * ticket. - * - * NOTE: The ticket generator is responsible for caching the result. - * - * @param EventRegistration $registration - * @return string The path to the generated file. - */ - public function generateTicketFileFor(EventRegistration $registration); - -} \ No newline at end of file + /** + * Generates a ticket file for a registration, and returns the path to the + * ticket. + * + * NOTE: The ticket generator is responsible for caching the result. + * + * @param EventRegistration $registration + * @return string The path to the generated file. + */ + public function generateTicketFileFor(EventRegistration $registration); +} diff --git a/tests/EventInvitationFieldTest.php b/tests/EventInvitationFieldTest.php index 6fe0dd7..764b893 100644 --- a/tests/EventInvitationFieldTest.php +++ b/tests/EventInvitationFieldTest.php @@ -5,103 +5,108 @@ * @package silverstripe-eventmanagement * @subpackage tests */ -class EventInvitationFieldTest extends SapphireTest { - - public static $fixture_file = 'eventmanagement/tests/EventInvitationFieldTest.yml'; - - /** - * @covers EventInvitationField::doInvite() - */ - public function testDoInvite() { - $event = new RegistrableEvent(); - $event->write(); - - $datetime = new RegistrableDateTime(); - $datetime->StartDate = date('Y-m-d'); - $datetime->EventID = $event->ID; - $datetime->write(); - - $field = new EventInvitationField($datetime, 'Invitations'); - $form = new Form( - new EventInvitationFieldTest_Controller(), - 'Form', - new FieldList($field), - new FieldList()); - $form->loadDataFrom($event); - - $invite = $field->InviteForm(); - $invite->dataFieldByName('Emails')->setValue(array('new' => array( - 'Name' => array('First Test', 'Second Test'), - 'Email' => array('first@example.com', 'second@example.com') - ))); - $invite->dataFieldByName('TimeID')->setValue($datetime->ID); - - $field->doInvite(array(), $invite); - $this->assertEmailSent('first@example.com'); - $this->assertEmailSent('second@example.com'); - - $this->clearEmails(); - - $invite->dataFieldByName('Emails')->setValue(array('new' => array( - 'Name' => array('First Test', 'Second Test', 'Third Test'), - 'Email' => array('first@example.com', 'second@example.com', 'third@example.com') - ))); - - $field->doInvite(array(), $invite); - $this->assertNull($this->findEmail('first@example.com')); - $this->assertNull($this->findEmail('second@example.com')); - $this->assertEmailSent('third@example.com'); - } - - /** - * @covers EventInvitationField::loadfromgroup() - */ - public function testLoadFromGroup() { - $request = new SS_HTTPRequest('GET', null, array( - 'GroupID' => $this->idFromFixture('Group', 'group') - )); - - $field = new EventInvitationField(new RegistrableEvent(), 'Invitations'); - $response = $field->loadfromgroup($request); - $data = Convert::json2array($response->getBody()); - - $expect = array( - (object) array('name' => 'First Member', 'email' => 'first@example.com'), - (object) array('name' => 'Second Member', 'email' => 'second@example.com') - ); - - $this->assertEquals(200, $response->getStatusCode()); - $this->assertEquals($expect, $data); - } - - /** - * @covers EventInvitationField::loadfromtime() - */ - public function testLoadFromDatetime() { - $request = new SS_HTTPRequest('GET', null, array( - 'PastTimeID' => $this->idFromFixture('Group', 'group') - )); - - $field = new EventInvitationField(new RegistrableEvent(), 'Invitations'); - $response = $field->loadfromtime($request); - $data = Convert::json2array($response->getBody()); - - $expect = array( - (object) array('name' => 'First Registration', 'email' => 'first@example.com'), - (object) array('name' => 'Second Registration', 'email' => 'second@example.com') - ); - - $this->assertEquals(200, $response->getStatusCode()); - $this->assertEquals($expect, $data); - } - +class EventInvitationFieldTest extends SapphireTest +{ + + public static $fixture_file = 'eventmanagement/tests/EventInvitationFieldTest.yml'; + + /** + * @covers EventInvitationField::doInvite() + */ + public function testDoInvite() + { + $event = new RegistrableEvent(); + $event->write(); + + $datetime = new RegistrableDateTime(); + $datetime->StartDate = date('Y-m-d'); + $datetime->EventID = $event->ID; + $datetime->write(); + + $field = new EventInvitationField($datetime, 'Invitations'); + $form = new Form( + new EventInvitationFieldTest_Controller(), + 'Form', + new FieldList($field), + new FieldList()); + $form->loadDataFrom($event); + + $invite = $field->InviteForm(); + $invite->dataFieldByName('Emails')->setValue(array('new' => array( + 'Name' => array('First Test', 'Second Test'), + 'Email' => array('first@example.com', 'second@example.com') + ))); + $invite->dataFieldByName('TimeID')->setValue($datetime->ID); + + $field->doInvite(array(), $invite); + $this->assertEmailSent('first@example.com'); + $this->assertEmailSent('second@example.com'); + + $this->clearEmails(); + + $invite->dataFieldByName('Emails')->setValue(array('new' => array( + 'Name' => array('First Test', 'Second Test', 'Third Test'), + 'Email' => array('first@example.com', 'second@example.com', 'third@example.com') + ))); + + $field->doInvite(array(), $invite); + $this->assertNull($this->findEmail('first@example.com')); + $this->assertNull($this->findEmail('second@example.com')); + $this->assertEmailSent('third@example.com'); + } + + /** + * @covers EventInvitationField::loadfromgroup() + */ + public function testLoadFromGroup() + { + $request = new SS_HTTPRequest('GET', null, array( + 'GroupID' => $this->idFromFixture('Group', 'group') + )); + + $field = new EventInvitationField(new RegistrableEvent(), 'Invitations'); + $response = $field->loadfromgroup($request); + $data = Convert::json2array($response->getBody()); + + $expect = array( + (object) array('name' => 'First Member', 'email' => 'first@example.com'), + (object) array('name' => 'Second Member', 'email' => 'second@example.com') + ); + + $this->assertEquals(200, $response->getStatusCode()); + $this->assertEquals($expect, $data); + } + + /** + * @covers EventInvitationField::loadfromtime() + */ + public function testLoadFromDatetime() + { + $request = new SS_HTTPRequest('GET', null, array( + 'PastTimeID' => $this->idFromFixture('Group', 'group') + )); + + $field = new EventInvitationField(new RegistrableEvent(), 'Invitations'); + $response = $field->loadfromtime($request); + $data = Convert::json2array($response->getBody()); + + $expect = array( + (object) array('name' => 'First Registration', 'email' => 'first@example.com'), + (object) array('name' => 'Second Registration', 'email' => 'second@example.com') + ); + + $this->assertEquals(200, $response->getStatusCode()); + $this->assertEquals($expect, $data); + } } /** * @ignore */ -class EventInvitationFieldTest_Controller extends RequestHandler { - - public function Link() { /* nothing */ } +class EventInvitationFieldTest_Controller extends RequestHandler +{ + public function Link() + { /* nothing */ + } } diff --git a/tests/EventRegisterFormTest.php b/tests/EventRegisterFormTest.php index 1ae4665..635f0da 100644 --- a/tests/EventRegisterFormTest.php +++ b/tests/EventRegisterFormTest.php @@ -5,117 +5,125 @@ * @package silverstripe-eventmanagement * @subpackage tests */ -class EventRegisterFormTest extends SapphireTest { - - public static $fixture_file = 'eventmanagement/tests/EventRegisterFormTest.yml'; - - public function testValidateTickets() { - $controller = new EventRegisterFormTest_Controller(); - $datetime = $this->objFromFixture('RegistrableDateTime', 'datetime'); - $controller->datetime = $datetime; - - $form = new EventRegisterForm($controller, 'Form'); - $ended = $this->idFromFixture('EventTicket', 'ended'); - $minmax = $this->idFromFixture('EventTicket', 'minmax'); - $quantity = $this->idFromFixture('EventTicket', 'quantity'); - $unlimited = $this->idFromFixture('EventTicket', 'unlimited'); - - $datetime->Tickets()->add($quantity, array('Available' => 10)); - - // Check it validates we enter at least one ticket. - $this->assertFalse($form->validateTickets(array(), $form)); - $this->assertEquals('no_tickets', $this->getTicketsError($form)); - Session::clear("FormInfo.{$form->FormName()}"); - - // Check that at least one ticket quantity is valid. - $this->assertFalse($form->validateTickets(array(1 => 'a', 2 => 1), $form)); - $this->assertEquals('non_numeric', $this->getTicketsError($form)); - Session::clear("FormInfo.{$form->FormName()}"); - - // Check only valid ticket IDs are allowed. - $this->assertFalse($form->validateTickets(array(-1 => 1), $form)); - $this->assertEquals('invalid_id', $this->getTicketsError($form)); - Session::clear("FormInfo.{$form->FormName()}"); - - // Check expired tickets cannot be registered - $this->assertFalse($form->validateTickets(array($ended => 1), $form)); - $this->assertEquals('not_available', $this->getTicketsError($form)); - Session::clear("FormInfo.{$form->FormName()}"); - - $form->validateTickets(array($quantity => 1), $form); - echo $this->getTicketsError($form); - - // Check we cannot book over the available quantity of tickets. - $this->assertTrue($form->validateTickets(array($quantity => 1), $form)); - $this->assertFalse($form->validateTickets(array($quantity => 11), $form)); - $this->assertEquals('over_quantity', $this->getTicketsError($form)); - Session::clear("FormInfo.{$form->FormName()}"); - - // Check the number of tickets booked must be within the allowed range. - $this->assertTrue($form->validateTickets(array($minmax => 8), $form)); - - $this->assertFalse($form->validateTickets(array($minmax => 4), $form)); - $this->assertEquals('too_few', $this->getTicketsError($form)); - Session::clear("FormInfo.{$form->FormName()}"); - - $this->assertFalse($form->validateTickets(array($minmax => 11), $form)); - $this->assertEquals('too_many', $this->getTicketsError($form)); - Session::clear("FormInfo.{$form->FormName()}"); - - // Check we cannot exceed the overall event capacity. - $this->assertTrue($form->validateTickets(array($unlimited => 1000), $form)); - $this->assertFalse($form->validateTickets(array($unlimited => 1001), $form)); - $this->assertEquals('over_capacity', $this->getTicketsError($form)); - Session::clear("FormInfo.{$form->FormName()}"); - } - - protected function getTicketsError(Form $form) { - $errors = Session::get("FormInfo.{$form->FormName()}.errors"); - - if ($errors) foreach ($errors as $error) { - if ($error['fieldName'] == 'Tickets') { - return $this->getErrorTypeForMessage($error['message']); - } - } - } - - protected function getErrorTypeForMessage($message) { - $static = array( - 'no_tickets' => 'Please select at least one ticket to purchase.', - 'non_numeric' => 'Please only enter numerical amounts for ticket quantities.', - 'invalid_id' => 'An invalid ticket ID was entered.'); - - $static = array_flip($static); - if (array_key_exists($message, $static)) { - return $static[$message]; - } - - $regex = array( - 'not_available' => '/.+? is currently not available./', - 'over_quantity' => '/There are only [0-9]+ of "[^"]+" available./', - 'too_few' => '/You must purchase at least [0-9]+ of "[^"]+"./', - 'too_many' => '/You can only purchase at most [0-9]+ of "[^"]+"./'); - - foreach ($regex as $name => $pattern) { - if (preg_match($pattern, $message)) return $name; - } - - if (strpos($message, 'The event only has') === 0) { - return 'over_capacity'; - } - } - +class EventRegisterFormTest extends SapphireTest +{ + + public static $fixture_file = 'eventmanagement/tests/EventRegisterFormTest.yml'; + + public function testValidateTickets() + { + $controller = new EventRegisterFormTest_Controller(); + $datetime = $this->objFromFixture('RegistrableDateTime', 'datetime'); + $controller->datetime = $datetime; + + $form = new EventRegisterForm($controller, 'Form'); + $ended = $this->idFromFixture('EventTicket', 'ended'); + $minmax = $this->idFromFixture('EventTicket', 'minmax'); + $quantity = $this->idFromFixture('EventTicket', 'quantity'); + $unlimited = $this->idFromFixture('EventTicket', 'unlimited'); + + $datetime->Tickets()->add($quantity, array('Available' => 10)); + + // Check it validates we enter at least one ticket. + $this->assertFalse($form->validateTickets(array(), $form)); + $this->assertEquals('no_tickets', $this->getTicketsError($form)); + Session::clear("FormInfo.{$form->FormName()}"); + + // Check that at least one ticket quantity is valid. + $this->assertFalse($form->validateTickets(array(1 => 'a', 2 => 1), $form)); + $this->assertEquals('non_numeric', $this->getTicketsError($form)); + Session::clear("FormInfo.{$form->FormName()}"); + + // Check only valid ticket IDs are allowed. + $this->assertFalse($form->validateTickets(array(-1 => 1), $form)); + $this->assertEquals('invalid_id', $this->getTicketsError($form)); + Session::clear("FormInfo.{$form->FormName()}"); + + // Check expired tickets cannot be registered + $this->assertFalse($form->validateTickets(array($ended => 1), $form)); + $this->assertEquals('not_available', $this->getTicketsError($form)); + Session::clear("FormInfo.{$form->FormName()}"); + + $form->validateTickets(array($quantity => 1), $form); + echo $this->getTicketsError($form); + + // Check we cannot book over the available quantity of tickets. + $this->assertTrue($form->validateTickets(array($quantity => 1), $form)); + $this->assertFalse($form->validateTickets(array($quantity => 11), $form)); + $this->assertEquals('over_quantity', $this->getTicketsError($form)); + Session::clear("FormInfo.{$form->FormName()}"); + + // Check the number of tickets booked must be within the allowed range. + $this->assertTrue($form->validateTickets(array($minmax => 8), $form)); + + $this->assertFalse($form->validateTickets(array($minmax => 4), $form)); + $this->assertEquals('too_few', $this->getTicketsError($form)); + Session::clear("FormInfo.{$form->FormName()}"); + + $this->assertFalse($form->validateTickets(array($minmax => 11), $form)); + $this->assertEquals('too_many', $this->getTicketsError($form)); + Session::clear("FormInfo.{$form->FormName()}"); + + // Check we cannot exceed the overall event capacity. + $this->assertTrue($form->validateTickets(array($unlimited => 1000), $form)); + $this->assertFalse($form->validateTickets(array($unlimited => 1001), $form)); + $this->assertEquals('over_capacity', $this->getTicketsError($form)); + Session::clear("FormInfo.{$form->FormName()}"); + } + + protected function getTicketsError(Form $form) + { + $errors = Session::get("FormInfo.{$form->FormName()}.errors"); + + if ($errors) { + foreach ($errors as $error) { + if ($error['fieldName'] == 'Tickets') { + return $this->getErrorTypeForMessage($error['message']); + } + } + } + } + + protected function getErrorTypeForMessage($message) + { + $static = array( + 'no_tickets' => 'Please select at least one ticket to purchase.', + 'non_numeric' => 'Please only enter numerical amounts for ticket quantities.', + 'invalid_id' => 'An invalid ticket ID was entered.'); + + $static = array_flip($static); + if (array_key_exists($message, $static)) { + return $static[$message]; + } + + $regex = array( + 'not_available' => '/.+? is currently not available./', + 'over_quantity' => '/There are only [0-9]+ of "[^"]+" available./', + 'too_few' => '/You must purchase at least [0-9]+ of "[^"]+"./', + 'too_many' => '/You can only purchase at most [0-9]+ of "[^"]+"./'); + + foreach ($regex as $name => $pattern) { + if (preg_match($pattern, $message)) { + return $name; + } + } + + if (strpos($message, 'The event only has') === 0) { + return 'over_capacity'; + } + } } /** * @ignore */ -class EventRegisterFormTest_Controller { - - public $datetime; +class EventRegisterFormTest_Controller +{ - public function getDateTime() { - return $this->datetime; - } + public $datetime; -} \ No newline at end of file + public function getDateTime() + { + return $this->datetime; + } +} diff --git a/tests/EventRegistrationPurgeTaskTest.php b/tests/EventRegistrationPurgeTaskTest.php index ed7962a..c5fdf73 100644 --- a/tests/EventRegistrationPurgeTaskTest.php +++ b/tests/EventRegistrationPurgeTaskTest.php @@ -5,115 +5,117 @@ * @package silverstripe-eventmanagement * @subpackage tests */ -class EventRegistrationPurgeTaskTest extends SapphireTest { - - public static $fixture_file = 'eventmanagement/tests/EventRegistrationPurgeTaskTest.yml'; - - /** - * @covers EventRegistrationPurgeTask::purgeUnsubmittedRegistrations - */ - public function testPurgeTaskDeletesUnsubmittedRegistrations() { - $task = new EventRegistrationPurgeTask(); - $unsubmitted1 = $this->objFromFixture('EventRegistration', 'unsubmitted_1'); - $unsubmitted2 = $this->objFromFixture('EventRegistration', 'unsubmitted_2'); - - $count = 'SELECT COUNT(*) FROM "EventRegistration" WHERE "Status" = \'Unsubmitted\''; - $update = 'UPDATE "EventRegistration" SET "Created" = \'%s\' WHERE "ID" = %d'; - - ob_start(); - - $task->run(null); - $this->assertEquals(2, DB::query($count)->value()); - - // Update the first registration to be 10 minutes ago, it shouldn't get - // deleted. - DB::query(sprintf( - $update, - date('Y-m-d H:i:s', sfTime::subtract(time(), 15, sfTime::MINUTE)), - $unsubmitted1->ID)); - - $task->run(null); - $this->assertEquals(2, DB::query($count)->value()); - - // Now update it to 20 minutes ago, one should be deleted. - DB::query(sprintf( - $update, - date('Y-m-d H:i:s', sfTime::subtract(time(), 20, sfTime::MINUTE)), - $unsubmitted1->ID)); - - $task->run(null); - $this->assertEquals(1, DB::query($count)->value()); - - // Now push the second one way into the past. - $created = sfTime::subtract(time(), 1000, sfTime::DAY); - DB::query(sprintf( - $update, - date('Y-m-d H:i:s', $created), - $unsubmitted2->ID)); - - $task->run(null); - $this->assertEquals(0, DB::query($count)->value()); - - // Ensure the confirmed event is still there. - $confirmed = DB::query( - 'SELECT COUNT(*) FROM "EventRegistration" WHERE "Status" = \'Confirmed\'' - ); - $this->assertEquals(1, $confirmed->value()); - - ob_end_clean(); - } - - /** - * @covers EventRegistrationPurgeTask::purgeUnconfirmedRegistrations - */ - public function testPurgeTaskCancelsUnconfirmedRegistrations() { - $task = new EventRegistrationPurgeTask(); - $unconfirmed1 = $this->objFromFixture('EventRegistration', 'unconfirmed_1'); - $unconfirmed2 = $this->objFromFixture('EventRegistration', 'unconfirmed_2'); - - $canceled = 'SELECT COUNT(*) FROM "EventRegistration" WHERE "Status" = \'Canceled\''; - $update = 'UPDATE "EventRegistration" SET "Created" = \'%s\' WHERE "ID" = %d'; - - ob_start(); - - $task->run(null); - $this->assertEquals(0, DB::query($canceled)->value()); - - // Update the first task to be just shy of six hours less than the - // created date. - $created = strtotime($unconfirmed1->Created); - $created = sfTime::subtract($created, 5, sfTime::HOUR); - DB::query(sprintf($update, date('Y-m-d H:i:s', $created), $unconfirmed1->ID)); - - $task->run(null); - $this->assertEquals(0, DB::query($canceled)->value()); - - // Now push it beyond six hours - DB::query(sprintf( - $update, - date('Y-m-d H:i:s', sfTime::subtract($created, 1, sfTime::HOUR)), - $unconfirmed1->ID)); - - $task->run(null); - $this->assertEquals(1, DB::query($canceled)->value()); - - // Now push the second one way back, and check it's also canceled - $created = sfTime::subtract(time(), 1000, sfTime::DAY); - DB::query(sprintf( - $update, - date('Y-m-d H:i:s', $created), - $unconfirmed2->ID)); - - $task->run(null); - $this->assertEquals(2, DB::query($canceled)->value()); - - // Ensure the confirmed event is still there. - $confirmed = DB::query( - 'SELECT COUNT(*) FROM "EventRegistration" WHERE "Status" = \'Confirmed\'' - ); - $this->assertEquals(1, $confirmed->value()); - - ob_end_clean(); - } - -} \ No newline at end of file +class EventRegistrationPurgeTaskTest extends SapphireTest +{ + + public static $fixture_file = 'eventmanagement/tests/EventRegistrationPurgeTaskTest.yml'; + + /** + * @covers EventRegistrationPurgeTask::purgeUnsubmittedRegistrations + */ + public function testPurgeTaskDeletesUnsubmittedRegistrations() + { + $task = new EventRegistrationPurgeTask(); + $unsubmitted1 = $this->objFromFixture('EventRegistration', 'unsubmitted_1'); + $unsubmitted2 = $this->objFromFixture('EventRegistration', 'unsubmitted_2'); + + $count = 'SELECT COUNT(*) FROM "EventRegistration" WHERE "Status" = \'Unsubmitted\''; + $update = 'UPDATE "EventRegistration" SET "Created" = \'%s\' WHERE "ID" = %d'; + + ob_start(); + + $task->run(null); + $this->assertEquals(2, DB::query($count)->value()); + + // Update the first registration to be 10 minutes ago, it shouldn't get + // deleted. + DB::query(sprintf( + $update, + date('Y-m-d H:i:s', sfTime::subtract(time(), 15, sfTime::MINUTE)), + $unsubmitted1->ID)); + + $task->run(null); + $this->assertEquals(2, DB::query($count)->value()); + + // Now update it to 20 minutes ago, one should be deleted. + DB::query(sprintf( + $update, + date('Y-m-d H:i:s', sfTime::subtract(time(), 20, sfTime::MINUTE)), + $unsubmitted1->ID)); + + $task->run(null); + $this->assertEquals(1, DB::query($count)->value()); + + // Now push the second one way into the past. + $created = sfTime::subtract(time(), 1000, sfTime::DAY); + DB::query(sprintf( + $update, + date('Y-m-d H:i:s', $created), + $unsubmitted2->ID)); + + $task->run(null); + $this->assertEquals(0, DB::query($count)->value()); + + // Ensure the confirmed event is still there. + $confirmed = DB::query( + 'SELECT COUNT(*) FROM "EventRegistration" WHERE "Status" = \'Confirmed\'' + ); + $this->assertEquals(1, $confirmed->value()); + + ob_end_clean(); + } + + /** + * @covers EventRegistrationPurgeTask::purgeUnconfirmedRegistrations + */ + public function testPurgeTaskCancelsUnconfirmedRegistrations() + { + $task = new EventRegistrationPurgeTask(); + $unconfirmed1 = $this->objFromFixture('EventRegistration', 'unconfirmed_1'); + $unconfirmed2 = $this->objFromFixture('EventRegistration', 'unconfirmed_2'); + + $canceled = 'SELECT COUNT(*) FROM "EventRegistration" WHERE "Status" = \'Canceled\''; + $update = 'UPDATE "EventRegistration" SET "Created" = \'%s\' WHERE "ID" = %d'; + + ob_start(); + + $task->run(null); + $this->assertEquals(0, DB::query($canceled)->value()); + + // Update the first task to be just shy of six hours less than the + // created date. + $created = strtotime($unconfirmed1->Created); + $created = sfTime::subtract($created, 5, sfTime::HOUR); + DB::query(sprintf($update, date('Y-m-d H:i:s', $created), $unconfirmed1->ID)); + + $task->run(null); + $this->assertEquals(0, DB::query($canceled)->value()); + + // Now push it beyond six hours + DB::query(sprintf( + $update, + date('Y-m-d H:i:s', sfTime::subtract($created, 1, sfTime::HOUR)), + $unconfirmed1->ID)); + + $task->run(null); + $this->assertEquals(1, DB::query($canceled)->value()); + + // Now push the second one way back, and check it's also canceled + $created = sfTime::subtract(time(), 1000, sfTime::DAY); + DB::query(sprintf( + $update, + date('Y-m-d H:i:s', $created), + $unconfirmed2->ID)); + + $task->run(null); + $this->assertEquals(2, DB::query($canceled)->value()); + + // Ensure the confirmed event is still there. + $confirmed = DB::query( + 'SELECT COUNT(*) FROM "EventRegistration" WHERE "Status" = \'Confirmed\'' + ); + $this->assertEquals(1, $confirmed->value()); + + ob_end_clean(); + } +} diff --git a/tests/EventTicketTest.php b/tests/EventTicketTest.php index ceda51c..a758ad9 100644 --- a/tests/EventTicketTest.php +++ b/tests/EventTicketTest.php @@ -5,127 +5,130 @@ * @package silverstripe-eventmanagement * @subpackage tests */ -class EventTicketTest extends SapphireTest { - - /** - * @covers EventTicket::getAvailableForDateTime() - */ - public function testGetAvailableForDatetimeWithDates() { - $ticket = new EventTicket(); - $time = new RegistrableDateTime(); - - // First test making the ticket unavailable with a fixed start date in - // the past. - $ticket->StartType = 'Date'; - $ticket->StartDate = $startDate = date('Y-m-d H:i:s', time() + 60); - $avail = $ticket->getAvailableForDateTime($time); - - $this->assertFalse($avail['available']); - $this->assertEquals(strtotime($startDate), $avail['available_at']); - - // Then test making it unavailable with a date to start set relative - // to the datetime start date. - $ticket->StartType = 'TimeBefore'; - $ticket->StartDays = 2; - $time->StartDate = date('Y-m-d', time() + 3 * 3600 * 24); - $time->StartTime = date('H:i:s', time()); - $avail = $ticket->getAvailableForDateTime($time); - - $this->assertFalse($avail['available']); - $this->assertEquals(time() + 1 * 3600 * 24, $avail['available_at']); - - // Then set it to a valid time and check it's valid. - $time->StartDate = date('Y-m-d', time() + 1 * 3600 * 24); - $avail = $ticket->getAvailableForDateTime($time); - $this->assertTrue($avail['available']); - - // Make it beyond the end date. - $ticket->EndType = 'Date'; - $ticket->EndDate = date('Y-m-d H:i:s'); - $avail = $ticket->getAvailableForDateTime($time); - $this->assertFalse($avail['available']); - - // Then set the end date to be relative. - $ticket->EndType = 'TimeBefore'; - $ticket->EndDays = 1; - $avail = $ticket->getAvailableForDateTime($time); - $this->assertFalse($avail['available']); - - // Then make it valid and check it works. - $ticket->EndDays = 0; - $ticket->EndHours = 6; - $avail = $ticket->getAvailableForDateTime($time); - $this->assertTrue($avail['available']); - } - - /** - * @covers EventTicket::getAvailableForDateTime() - */ - public function testGetAvailableForDatetimeWithQuantity() { - $ticket = new EventTicket(); - $ticket->StartType = 'Date'; - $ticket->StartDate = date('Y-m-d', time() - 3600 * 24); - $ticket->EndType = 'Date'; - $ticket->EndDate = date('Y-m-d', time() + 3600 * 24); - $ticket->write(); - - $time = new RegistrableDateTime(); - $time->write(); - - $ticket->Available = 50; - $avail = $ticket->getAvailableForDateTime($time); - $this->assertEquals(50, $avail['available']); - - // Create a registration that consumes some of the tickets. - $rego = new EventRegistration(); - $rego->Status = 'Valid'; - $rego->TimeID = $time->ID; - $rego->write(); - $rego->Tickets()->add($ticket, array('Quantity' => 49)); - - $avail = $ticket->getAvailableForDateTime($time); - $this->assertEquals(1, $avail['available']); - - // Then check we can exclude it. - $avail = $ticket->getAvailableForDateTime($time, $rego->ID); - $this->assertEquals(50, $avail['available']); - - // Then bump up the quantity so there are no more available. - $rego->Tickets()->remove($ticket); - $rego->Tickets()->add($ticket, array('Quantity' => 50)); - - $avail = $ticket->getAvailableForDateTime($time); - $this->assertFalse($avail['available']); - } - - /** - * @covers EventTicket::getSaleEndForDateTime() - */ - public function testGetSaleEndForDateTime() { - $ticket = new EventTicket(); - $time = new RegistrableDateTime(); - $now = time(); - - $ticket->EndType = 'Date'; - $ticket->EndDate = date('Y-m-d H:i:s', $now); - $this->assertEquals( - $now, - $ticket->getSaleEndForDateTime($time), - 'The correct end time is returned with a fixed date.' - ); - - $ticket->EndType = 'TimeBefore'; - $ticket->EndDays = 1; - $ticket->EndHours = 12; - - $time->StartDate = date('Y-m-d', $now); - $time->StartTime = date('H:i:s', $now); - - $this->assertEquals( - $now - 1.5 * 3600 * 24, - $ticket->getSaleEndForDateTime($time), - 'The correct end time is returned with a relative end date.' - ); - } - -} \ No newline at end of file +class EventTicketTest extends SapphireTest +{ + + /** + * @covers EventTicket::getAvailableForDateTime() + */ + public function testGetAvailableForDatetimeWithDates() + { + $ticket = new EventTicket(); + $time = new RegistrableDateTime(); + + // First test making the ticket unavailable with a fixed start date in + // the past. + $ticket->StartType = 'Date'; + $ticket->StartDate = $startDate = date('Y-m-d H:i:s', time() + 60); + $avail = $ticket->getAvailableForDateTime($time); + + $this->assertFalse($avail['available']); + $this->assertEquals(strtotime($startDate), $avail['available_at']); + + // Then test making it unavailable with a date to start set relative + // to the datetime start date. + $ticket->StartType = 'TimeBefore'; + $ticket->StartDays = 2; + $time->StartDate = date('Y-m-d', time() + 3 * 3600 * 24); + $time->StartTime = date('H:i:s', time()); + $avail = $ticket->getAvailableForDateTime($time); + + $this->assertFalse($avail['available']); + $this->assertEquals(time() + 1 * 3600 * 24, $avail['available_at']); + + // Then set it to a valid time and check it's valid. + $time->StartDate = date('Y-m-d', time() + 1 * 3600 * 24); + $avail = $ticket->getAvailableForDateTime($time); + $this->assertTrue($avail['available']); + + // Make it beyond the end date. + $ticket->EndType = 'Date'; + $ticket->EndDate = date('Y-m-d H:i:s'); + $avail = $ticket->getAvailableForDateTime($time); + $this->assertFalse($avail['available']); + + // Then set the end date to be relative. + $ticket->EndType = 'TimeBefore'; + $ticket->EndDays = 1; + $avail = $ticket->getAvailableForDateTime($time); + $this->assertFalse($avail['available']); + + // Then make it valid and check it works. + $ticket->EndDays = 0; + $ticket->EndHours = 6; + $avail = $ticket->getAvailableForDateTime($time); + $this->assertTrue($avail['available']); + } + + /** + * @covers EventTicket::getAvailableForDateTime() + */ + public function testGetAvailableForDatetimeWithQuantity() + { + $ticket = new EventTicket(); + $ticket->StartType = 'Date'; + $ticket->StartDate = date('Y-m-d', time() - 3600 * 24); + $ticket->EndType = 'Date'; + $ticket->EndDate = date('Y-m-d', time() + 3600 * 24); + $ticket->write(); + + $time = new RegistrableDateTime(); + $time->write(); + + $ticket->Available = 50; + $avail = $ticket->getAvailableForDateTime($time); + $this->assertEquals(50, $avail['available']); + + // Create a registration that consumes some of the tickets. + $rego = new EventRegistration(); + $rego->Status = 'Valid'; + $rego->TimeID = $time->ID; + $rego->write(); + $rego->Tickets()->add($ticket, array('Quantity' => 49)); + + $avail = $ticket->getAvailableForDateTime($time); + $this->assertEquals(1, $avail['available']); + + // Then check we can exclude it. + $avail = $ticket->getAvailableForDateTime($time, $rego->ID); + $this->assertEquals(50, $avail['available']); + + // Then bump up the quantity so there are no more available. + $rego->Tickets()->remove($ticket); + $rego->Tickets()->add($ticket, array('Quantity' => 50)); + + $avail = $ticket->getAvailableForDateTime($time); + $this->assertFalse($avail['available']); + } + + /** + * @covers EventTicket::getSaleEndForDateTime() + */ + public function testGetSaleEndForDateTime() + { + $ticket = new EventTicket(); + $time = new RegistrableDateTime(); + $now = time(); + + $ticket->EndType = 'Date'; + $ticket->EndDate = date('Y-m-d H:i:s', $now); + $this->assertEquals( + $now, + $ticket->getSaleEndForDateTime($time), + 'The correct end time is returned with a fixed date.' + ); + + $ticket->EndType = 'TimeBefore'; + $ticket->EndDays = 1; + $ticket->EndHours = 12; + + $time->StartDate = date('Y-m-d', $now); + $time->StartTime = date('H:i:s', $now); + + $this->assertEquals( + $now - 1.5 * 3600 * 24, + $ticket->getSaleEndForDateTime($time), + 'The correct end time is returned with a relative end date.' + ); + } +} diff --git a/tests/RegistrableDateTimeTest.php b/tests/RegistrableDateTimeTest.php index 91232a5..2a45cf5 100644 --- a/tests/RegistrableDateTimeTest.php +++ b/tests/RegistrableDateTimeTest.php @@ -5,81 +5,82 @@ * @package silverstripe-eventmanagement * @subpackage tests */ -class RegistrableDateTimeTest extends SapphireTest { - - public static $fixture_file = 'eventmanagement/tests/RegistrableDateTimeTest.yml'; - - /** - * @covers RegistrableDateTime::onBeforeWrite() - */ - public function testEventDetailsChangedNotificationEmail() { - $event = $this->objFromFixture('RegistrableEvent', 'event'); - $datetime = $this->objFromFixture('RegistrableDateTime', 'datetime'); - - // First test that no emails are sent out for trivial changes. - $datetime->StartTime = 0; - $datetime->write(); - $this->assertNull($this->findEmail('test@example.com')); - $this->assertNull($this->findEmail('canceled@example.com')); - - // Now do a non-emailed change and check they're still not send. - $datetime->EndTime = '12:00:00'; - $datetime->write(); - $this->assertNull($this->findEmail('test@example.com')); - $this->assertNull($this->findEmail('canceled@example.com')); - - // Now change a property that users are notified of a change in and - // check an email is sent. - $datetime->StartDate = '2011-01-02'; - $datetime->write(); - $this->assertEmailSent('test@example.com'); - $this->assertNull($this->findEmail('canceled@example.com')); - $this->clearEmails(); - - // Now disable notification and do the same and check no emails are - // sent. - $event->EmailNotifyChanges = false; - $event->write(); - - $datetime->StartDate = '2011-01-03'; - $datetime->flushCache(); - - $datetime = DataObject::get_by_id('RegistrableDateTime', $datetime->ID); - $datetime->write(); - - $this->assertNull($this->findEmail('test@example.com')); - $this->assertNull($this->findEmail('canceled@example.com')); - } - - /** - * @covers RegistrableDateTime::getRemainingCapacity() - */ - public function testGetRemainingCapacity() { - $event = $this->objFromFixture('RegistrableEvent', 'event'); - $datetime = $this->objFromFixture('RegistrableDateTime', 'datetime'); - $ticket = $this->objFromFixture('EventTicket', 'ticket'); - - $datetime->Capacity = 0; - $datetime->write(); - $this->assertEquals(true, $datetime->getRemainingCapacity()); - - $datetime->Capacity = 50; - $datetime->write(); - $this->assertEquals(50, $datetime->getRemainingCapacity()); - - $rego = new EventRegistration(); - $rego->TimeID = $datetime->ID; - $rego->write(); - $rego->Tickets()->add($ticket, array('Quantity' => 49)); - - $this->assertEquals(1, $datetime->getRemainingCapacity()); - $this->assertEquals(50, $datetime->getRemainingCapacity($rego->ID)); - - $rego->Tickets()->remove($ticket); - $rego->Tickets()->add($ticket, array('Quantity' => 50)); - $this->assertFalse(!!$datetime->getRemainingCapacity()); - $this->assertEquals(50, $datetime->getRemainingCapacity($rego->ID)); - } - - -} \ No newline at end of file +class RegistrableDateTimeTest extends SapphireTest +{ + + public static $fixture_file = 'eventmanagement/tests/RegistrableDateTimeTest.yml'; + + /** + * @covers RegistrableDateTime::onBeforeWrite() + */ + public function testEventDetailsChangedNotificationEmail() + { + $event = $this->objFromFixture('RegistrableEvent', 'event'); + $datetime = $this->objFromFixture('RegistrableDateTime', 'datetime'); + + // First test that no emails are sent out for trivial changes. + $datetime->StartTime = 0; + $datetime->write(); + $this->assertNull($this->findEmail('test@example.com')); + $this->assertNull($this->findEmail('canceled@example.com')); + + // Now do a non-emailed change and check they're still not send. + $datetime->EndTime = '12:00:00'; + $datetime->write(); + $this->assertNull($this->findEmail('test@example.com')); + $this->assertNull($this->findEmail('canceled@example.com')); + + // Now change a property that users are notified of a change in and + // check an email is sent. + $datetime->StartDate = '2011-01-02'; + $datetime->write(); + $this->assertEmailSent('test@example.com'); + $this->assertNull($this->findEmail('canceled@example.com')); + $this->clearEmails(); + + // Now disable notification and do the same and check no emails are + // sent. + $event->EmailNotifyChanges = false; + $event->write(); + + $datetime->StartDate = '2011-01-03'; + $datetime->flushCache(); + + $datetime = DataObject::get_by_id('RegistrableDateTime', $datetime->ID); + $datetime->write(); + + $this->assertNull($this->findEmail('test@example.com')); + $this->assertNull($this->findEmail('canceled@example.com')); + } + + /** + * @covers RegistrableDateTime::getRemainingCapacity() + */ + public function testGetRemainingCapacity() + { + $event = $this->objFromFixture('RegistrableEvent', 'event'); + $datetime = $this->objFromFixture('RegistrableDateTime', 'datetime'); + $ticket = $this->objFromFixture('EventTicket', 'ticket'); + + $datetime->Capacity = 0; + $datetime->write(); + $this->assertEquals(true, $datetime->getRemainingCapacity()); + + $datetime->Capacity = 50; + $datetime->write(); + $this->assertEquals(50, $datetime->getRemainingCapacity()); + + $rego = new EventRegistration(); + $rego->TimeID = $datetime->ID; + $rego->write(); + $rego->Tickets()->add($ticket, array('Quantity' => 49)); + + $this->assertEquals(1, $datetime->getRemainingCapacity()); + $this->assertEquals(50, $datetime->getRemainingCapacity($rego->ID)); + + $rego->Tickets()->remove($ticket); + $rego->Tickets()->add($ticket, array('Quantity' => 50)); + $this->assertFalse(!!$datetime->getRemainingCapacity()); + $this->assertEquals(50, $datetime->getRemainingCapacity($rego->ID)); + } +}