示例#1
0
        public static ReservationStateArgs Create(IReservationItem rsv, ReservationClient client, DateTime now)
        {
            var isAuthorized = client.IsAuthorized(rsv);
            var args         = new ReservationStateArgs(rsv.ReservationID, client.InLab, client.IsReserver, client.IsInvited, isAuthorized, !rsv.Editable, rsv.IsFacilityDownTime, rsv.MinCancelTime, rsv.MinReservTime, rsv.BeginDateTime, rsv.EndDateTime, rsv.ActualBeginDateTime, rsv.ActualEndDateTime, client.UserAuth);

            return(args);
        }
示例#2
0
        public bool HandlePracticeReservation(IReservationItem rsv, IEnumerable <Invitee> invitees, int modifiedByClientId)
        {
            // 2009-09-16 Practice reservation : we must also check if tool engineers want to receive the notify email
            if (IsPracticeActivity(rsv.ActivityID))
            {
                Invitee invitee = null;

                if (invitees != null)
                {
                    invitee = invitees.FirstOrDefault();
                }

                if (invitee == null)
                {
                    throw new InvalidOperationException("A practice reservation must have at least one invitee.");
                }

                Provider.Scheduler.Email.EmailOnPracticeRes(rsv.ReservationID, invitee.DisplayName, modifiedByClientId);

                return(true);
            }
            else
            {
                return(false);
            }
        }
示例#3
0
        public ReservationClient GetReservationClient(IReservationItem rsv, IClient client, IEnumerable <IResourceClient> resourceClients, IEnumerable <IReservationInviteeItem> invitees)
        {
            var physicalAccessUtil = GetPhysicalAccessUtility();
            var inlab = physicalAccessUtil.ClientInLab(client.ClientID, rsv.LabID);

            return(ReservationClient.Create(rsv, client, resourceClients, invitees, inlab));
        }
示例#4
0
        public bool HandleFacilityDowntimeReservation(IReservationItem rsv, int modifiedByClientId)
        {
            // 2009-06-21 If it's Facility downtime, we must delete the reservations that has been made during that period
            if (IsFacilityDownTimeActivity(rsv.ActivityID))
            {
                // Find and Remove any un-started reservations made during time of repair
                var query = Provider.Scheduler.Reservation.SelectByResource(rsv.ResourceID, rsv.BeginDateTime, rsv.EndDateTime, false);

                foreach (var existing in query)
                {
                    // Only if the reservation has not begun
                    if (existing.ActualBeginDateTime == null)
                    {
                        Provider.Scheduler.Reservation.CancelAndForgive(existing.ReservationID, "Cancelled and forgiven for facility down time.", modifiedByClientId);
                        Provider.Scheduler.Email.EmailOnCanceledByRepair(existing.ReservationID, true, $"{SendEmail.CompanyName} Facility Down", "Facility is down, thus we have to disable the tool.", rsv.EndDateTime, modifiedByClientId);
                    }
                    else
                    {
                        // We have to disable all those reservations that have been activated by setting IsActive to 0.
                        // The catch here is that we must compare the "Actual" usage time with the repair time because if the user ends the reservation before the repair starts, we still
                        // have to charge the user for that reservation
                    }
                }

                return(true);
            }
            else
            {
                return(false);
            }
        }
        public ReservationModel(SchedulerContextHelper helper, DateTime now)
        {
            Helper = helper;
            Now    = now;

            int reservationId = helper.GetReservationID();

            if (reservationId > 0)
            {
                IReservationItem rsv = helper.Provider.Scheduler.Reservation.GetReservation(reservationId);
                var res = helper.Provider.Scheduler.Resource.GetResource(rsv.ResourceID);

                Reservation  = rsv;
                ActivityID   = rsv.ActivityID;
                AccountID    = rsv.AccountID;
                RecurrenceID = rsv.RecurrenceID;
                Notes        = rsv.Notes;
                AutoEnd      = rsv.ReservationAutoEnd;
                KeepAlive    = rsv.KeepAlive;
                Resource     = res;
            }

            if (Resource == null)
            {
                var resourceId = helper.Context.Request.SelectedPath().ResourceID;
                Resource = helper.Provider.Scheduler.Resource.GetResource(resourceId);
            }
        }
        public bool IsBeforeForgiveCutoff(IReservationItem rsv, DateTime now, int maxForgivenDay, IEnumerable <IHoliday> holidays)
        {
            // Normal lab users cannot forgive reservations
            // Staff can forgive a reservation on the same day it ended, and during the following 3 three business days
            // Admins can always forgive reservations

            DateTime maxDay = rsv.ActualBeginDateTime.GetValueOrDefault(rsv.EndDateTime);

            return(IsBeforeForgiveCutoff(now, maxDay, maxForgivenDay, rsv.Editable, holidays));
        }
        public bool ReservationNotesCanBeChanged(IClient client, IReservationItem rsv)
        {
            // staff can always change notes
            if (client.HasPriv(ClientPrivilege.Staff | ClientPrivilege.Administrator | ClientPrivilege.Developer))
            {
                return(true);
            }

            // otherwise notes can be changed by the reserver
            return(client.ClientID == rsv.ClientID);
        }
示例#8
0
 public static bool CreateForModification(IReservationItem rsv, ReservationDuration rd)
 {
     // if Time And Duration modified create new reservation else change existing
     if (rsv.BeginDateTime != rd.BeginDateTime || rsv.Duration != rd.Duration.TotalMinutes)
     {
         return(true);
     }
     else
     {
         return(false);
     }
 }
示例#9
0
        public void End(IReservationItem rsv, DateTime actualEndDateTime, int?endedByClientId)
        {
            if (rsv == null)
            {
                throw new ArgumentNullException($"The argument rsv cannot be null.");
            }

            // Make sure this reservation hasn't already been ended some how
            // [2016-01-21 jg] Allow FacilityDownTime because they already have ActualEndDateTime set
            if (rsv.ActualEndDateTime != null && !rsv.IsFacilityDownTime)
            {
                return;
            }

            // must set these for future use
            rsv.ActualEndDateTime = actualEndDateTime;
            rsv.ClientIDEnd       = endedByClientId.GetValueOrDefault(-1);

            // End reservation
            Provider.Scheduler.Reservation.EndReservation(new EndReservationArgs
            {
                ReservationID     = rsv.ReservationID,
                ActualEndDateTime = actualEndDateTime,
                EndedByClientID   = endedByClientId.GetValueOrDefault(-1)
            });

            // Turn Interlock Off
            if (CacheManager.Current.WagoEnabled)
            {
                WagoInterlock.ToggleInterlock(rsv.ResourceID, false, 0);
            }

            // Check for other open reservation slots between now and the reservation fence
            DateTime?nextBeginDateTime = OpenResSlot(rsv.ResourceID, TimeSpan.FromMinutes(rsv.ReservFence), TimeSpan.FromMinutes(rsv.MinReservTime), rsv.EndDateTime);

            if (nextBeginDateTime == null)
            {
                return;
            }

            // Get the next reservation start time
            DateTime currentEndDateTime = rsv.GetNextGranularity(actualEndDateTime, GranularityDirection.Previous);

            // Send email notifications to all clients who want to be notified of open reservation slots
            Provider.Scheduler.Email.EmailOnOpenSlot(rsv.ReservationID, currentEndDateTime, nextBeginDateTime.Value, EmailNotify.Always, endedByClientId.GetValueOrDefault(-1));


            if (nextBeginDateTime.Value.Subtract(currentEndDateTime).TotalMinutes >= rsv.MinReservTime)
            {
                Provider.Scheduler.Email.EmailOnOpenSlot(rsv.ReservationID, currentEndDateTime, nextBeginDateTime.Value, EmailNotify.OnOpening, endedByClientId.GetValueOrDefault(-1));
            }
        }
        private ReservationStateArgs GetReservationStateArgs(IReservationItem rsv, int currentUserClientId, int inviteeClientId, bool inlab, DateTime now)
        {
            IClient client = Provider.Data.Client.GetClient(currentUserClientId);
            IEnumerable <IResourceClient>         resourceClients = Provider.Scheduler.Resource.GetResourceClients(rsv.ResourceID);
            IEnumerable <IReservationInviteeItem> invitees        = new[] { GetMockReservationInvitee(inviteeClientId, rsv.ReservationID) };

            ReservationClient rc = Helper.GetReservationClient(rsv, client, resourceClients, invitees);

            rc.InLab = inlab;
            ReservationStateArgs result = ReservationStateArgs.Create(rsv, rc, now);

            return(result);
        }
        public bool IsBeforeChangeAccountCutoff(IReservationItem rsv, DateTime now, IEnumerable <IHoliday> holidays)
        {
            // Normal lab users can modify their own reservation's account on the same day it ended through 3 business days after the 1st of the following month
            // Staff can modify any reservation's account on the same day it ended through 3 business days after the 1st of the following month
            // Admins can always modify a reservation's account

            DateTime maxDay = rsv.ActualBeginDateTime.GetValueOrDefault(rsv.EndDateTime);

            // need to see if current date is between maxDay and next period business day cutoff
            var      d      = maxDay.AddMonths(1).FirstOfMonth();
            DateTime cutoff = Utility.NextBusinessDay(d, holidays);

            return(now >= maxDay && now < cutoff && rsv.Editable);
        }
        public bool ReservationCanBeForgiven(IClient client, IReservationItem rsv, DateTime now, int maxForgivenDay, IEnumerable <IHoliday> holidays)
        {
            // first, only admins and staff can possibly forgive
            if (!client.HasPriv(ClientPrivilege.Administrator | ClientPrivilege.Staff | ClientPrivilege.Developer))
            {
                return(false);
            }

            // always let admins forgive even after business day cutoff
            if (client.HasPriv(ClientPrivilege.Administrator | ClientPrivilege.Developer))
            {
                return(true);
            }

            return(IsBeforeForgiveCutoff(rsv, now, maxForgivenDay, holidays));
        }
        public bool ReservationAccountCanBeChanged(IClient client, IReservationItem rsv, DateTime now, IEnumerable <IHoliday> holidays)
        {
            // admins can always change the account
            if (client.HasPriv(ClientPrivilege.Administrator | ClientPrivilege.Developer))
            {
                return(true);
            }

            // reserver and staff can before 3rd business day of next period
            if (client.HasPriv(ClientPrivilege.Staff) || client.ClientID == rsv.ClientID)
            {
                return(IsBeforeChangeAccountCutoff(rsv, now, holidays));
            }

            return(false);
        }
示例#14
0
        public IReservationItem ModifyReservation(IReservationItem rsv, ReservationData data)
        {
            IReservationItem result;
            bool             insert = false;

            if (IsFacilityDownTimeActivity(rsv.ActivityID))
            {
                result = Provider.Scheduler.Reservation.UpdateFacilityDownTime(rsv.ReservationID, data.Duration.BeginDateTime, data.Duration.EndDateTime, data.ClientID);
                HandleFacilityDowntimeReservation(result, data.ClientID);
            }
            else
            {
                if (CreateForModification(rsv, data.Duration))
                {
                    var args = GetInsertReservationArgs(data, rsv.ReservationID);
                    Provider.Scheduler.Reservation.CancelReservation(rsv.ReservationID, string.Empty, args.ModifiedByClientID);
                    result = Provider.Scheduler.Reservation.InsertForModification(args);
                    Provider.Scheduler.Reservation.AppendNotes(rsv.ReservationID, $"Cancelled for modification. New ReservationID: {result.ReservationID}");
                    insert = true;
                }
                else
                {
                    // at this point data does not Contain
                    var args = GetUpdateReservationArgs(data, rsv.ReservationID);
                    result = Provider.Scheduler.Reservation.UpdateReservation(args);
                }

                HandlePracticeReservation(result, data.Invitees, data.ClientID);
            }

            if (insert)
            {
                InsertReservationInvitees(result.ReservationID, data.Invitees);
                InsertReservationProcessInfos(result.ReservationID, data.ProcessInfos);
            }
            else
            {
                UpdateReservationInvitees(data.Invitees);
                UpdateReservationProcessInfos(data.ProcessInfos);
            }

            Provider.Scheduler.Email.EmailOnUserUpdate(result.ReservationID, data.ClientID);
            Provider.Scheduler.Email.EmailOnInvited(result.ReservationID, data.Invitees, data.ClientID, ReservationModificationType.Modified);
            Provider.Scheduler.Email.EmailOnUninvited(rsv.ReservationID, data.Invitees, data.ClientID);

            return(result);
        }
示例#15
0
        public ReservationClient GetReservationClient(IReservationItem rsv, IEnumerable <IReservationInviteeItem> invitees, IClient client)
        {
            var resourceClients = Provider.Scheduler.Reservation.GetResourceClients(rsv.ResourceID);
            var userAuth        = Reservations.GetAuthLevel(resourceClients, client);

            var result = new ReservationClient
            {
                ClientID      = client.ClientID,
                ReservationID = rsv.ReservationID,
                ResourceID    = rsv.ResourceID,
                IsReserver    = rsv.ClientID == client.ClientID,
                IsInvited     = invitees.Any(x => x.InviteeID == client.ClientID),
                InLab         = ClientInLab(rsv.LabID),
                UserAuth      = userAuth
            };

            return(result);
        }
示例#16
0
        public static ReservationClient Create(IReservationItem rsv, IClient client, IEnumerable <IResourceClient> resourceClients, IEnumerable <IReservationInviteeItem> invitees, bool inlab)
        {
            var userAuth   = Reservations.GetAuthLevel(resourceClients, client);
            var isReserver = rsv.ClientID == client.ClientID;
            var isInvited  = invitees.Any(x => x.InviteeID == client.ClientID);

            var result = new ReservationClient
            {
                ClientID      = client.ClientID,
                ReservationID = rsv.ReservationID,
                ResourceID    = rsv.ResourceID,
                IsReserver    = isReserver,
                IsInvited     = isInvited,
                InLab         = inlab,
                UserAuth      = userAuth
            };

            return(result);
        }
        private void ReservationStateTester(int resourceId, int reserverClientId, int currentClientId, int inviteeClientId, int activityId, DateTime beginDateTime, int duration, bool inlab, bool canDelete, bool canModify)
        {
            var now = DateTime.Now;

            DateTime endDateTime = beginDateTime.AddMinutes(duration);

            IReservationItem rsv = GetMockReservation(123456, resourceId, reserverClientId, activityId, beginDateTime, endDateTime, null, null);

            ReservationStateArgs args  = GetReservationStateArgs(rsv, currentClientId, inviteeClientId, inlab, now);
            ReservationState     state = ReservationStateUtility.Create(now).GetReservationState(args);

            bool actual;

            actual = SchedulerUtility.CanDeleteReservation(state, args, now);
            Assert.AreEqual(canDelete, actual);

            actual = SchedulerUtility.CanModifyReservation(state, args, now);
            Assert.AreEqual(canModify, actual);
        }
示例#18
0
        private static ReservationDateRangeItem CreateReservation(IReservationItem rsv, IEnumerable <ICost> costs)
        {
            var           filtered = costs.Where(c => (c.RecordID == rsv.ResourceID || c.RecordID == 0) && c.ChargeTypeID == rsv.ChargeTypeID).ToList();
            IResourceCost rc       = ResourceCost.CreateResourceCosts(filtered).FirstOrDefault();

            if (rc == null)
            {
                throw new Exception($"Cannot determine cost for Resource: [{rsv.ResourceID}] {rsv.ResourceName}");
            }

            return(new ReservationDateRangeItem()
            {
                ReservationID = rsv.ReservationID,
                ResourceID = rsv.ResourceID,
                ResourceName = rsv.ResourceName,
                ProcessTechID = rsv.ProcessTechID,
                ProcessTechName = rsv.ProcessTechName,
                ClientID = rsv.ClientID,
                UserName = rsv.UserName,
                LName = rsv.LName,
                FName = rsv.FName,
                ActivityID = rsv.ActivityID,
                ActivityName = rsv.ActivityName,
                AccountID = rsv.AccountID,
                AccountName = rsv.AccountName,
                ShortCode = rsv.ShortCode,
                ChargeTypeID = rsv.ChargeTypeID,
                IsActive = rsv.IsActive,
                IsStarted = rsv.IsStarted,
                BeginDateTime = rsv.BeginDateTime,
                EndDateTime = rsv.EndDateTime,
                ActualBeginDateTime = rsv.ActualBeginDateTime,
                ActualEndDateTime = rsv.ActualEndDateTime,
                ChargeBeginDateTime = rsv.ChargeBeginDateTime,
                ChargeEndDateTime = rsv.ChargeEndDateTime,
                LastModifiedOn = rsv.LastModifiedOn,
                IsCancelledBeforeCutoff = rsv.IsCancelledBeforeCutoff,
                ChargeMultiplier = rsv.ChargeMultiplier,
                Cost = rc
            });
        }
示例#19
0
        public void Delete(IReservationItem rsv, int?modifiedByClientId)
        {
            Provider.Scheduler.Reservation.CancelReservation(rsv.ReservationID, string.Empty, modifiedByClientId);

            // Send email to reserver and invitees
            var invitees = ReservationInvitees.Create(Provider).SelectInvitees(rsv.ReservationID);

            Provider.Scheduler.Email.EmailOnUserDelete(rsv.ReservationID, modifiedByClientId.GetValueOrDefault());
            Provider.Scheduler.Email.EmailOnUninvited(rsv.ReservationID, invitees, modifiedByClientId.GetValueOrDefault());

            // Send email notifications to all clients want to be notified of open reservation slots
            Provider.Scheduler.Email.EmailOnOpenSlot(rsv.ReservationID, rsv.BeginDateTime, rsv.EndDateTime, EmailNotify.Always, modifiedByClientId.GetValueOrDefault());

            // Check for other open reservation slots between now and the reservation fence and Get the next reservation start time
            DateTime?nextBeginDateTime = OpenResSlot(rsv.ResourceID, TimeSpan.FromMinutes(rsv.ReservFence), TimeSpan.FromMinutes(rsv.MinReservTime), rsv.EndDateTime);

            if (nextBeginDateTime.HasValue)
            {
                Provider.Scheduler.Email.EmailOnOpenSlot(rsv.ReservationID, rsv.BeginDateTime, nextBeginDateTime.Value, EmailNotify.OnOpening, modifiedByClientId.GetValueOrDefault());
            }
        }
示例#20
0
        /// <summary>
        /// Checks for all reservations affected by the repair and either cancels or deletes them (depending of if they are started or not), and then forgives them.
        /// </summary>
        /// <param name="repair">The repair reservation.</param>
        private bool UpdateAffectedReservations(IReservationItem repair)
        {
            // Might be null when resource state is Limited
            if (repair == null)
            {
                return(false);
            }

            // Find and end reservations that are in progress (Endable) for this resource
            var endableReservations = Provider.Scheduler.Reservation.SelectEndableReservations(repair.ResourceID);

            foreach (var endable in endableReservations.Where(x => x.ReservationID != repair.ReservationID))
            {
                Provider.Scheduler.Reservation.EndAndForgiveForRepair(endable.ReservationID, "Ended and forgiven for repair.", CurrentUser.ClientID, CurrentUser.ClientID);
                Provider.Scheduler.Email.EmailOnCanceledByRepair(endable.ReservationID, false, "Offline", repair.Notes, repair.EndDateTime, CurrentUser.ClientID);
                Provider.Scheduler.Email.EmailOnForgiveCharge(endable.ReservationID, 100, true, CurrentUser.ClientID);
            }

            // Find and remove any unstarted reservations made during time of repair
            var unstartedReservations = Provider.Scheduler.Reservation.SelectUnstarted(repair.ResourceID, repair.BeginDateTime, repair.EndDateTime);

            foreach (var unstarted in unstartedReservations)
            {
                Provider.Scheduler.Reservation.CancelReservation(unstarted.ReservationID, "Cancelled and forgiven for repair.", CurrentUser.ClientID);
                Provider.Scheduler.Email.EmailOnCanceledByRepair(unstarted.ReservationID, true, "Offline", repair.Notes, repair.EndDateTime, CurrentUser.ClientID);
                // Don't send forgiveness email yet, this will happen below...
            }

            // 2009-05-21 Make the old reservations that were covered by the repair to be forgiven
            // Get all the past active reservations that were covered by this specific repair period

            // [2013-05-20 jg] We also need cancelled reservations so booking fee is forgiven

            // [2017-08-24 jg] Changing to beginDateTime and endDateTime so that any existing reservations in the entire repair range are forgiven.
            //      The previous date range only covered reservations scheduled to start between the actualBeginDateTime (the time the repair began
            //      without going to the previous granularity) and the current time. The range is now between the repair begin (to previous granularity)
            //      to repair end (to next granularity).


            // [2018-08-31 jg] This is now just a catch all. Nothing will happen if the reservation is already 100% forgiven.
            //      Overlapping reservations (started and unstarted) are forgiven above and an email is sent. This will catch
            //      unstarted overlapping reservations where IsActive == true and ActualBeginDateTime.HasValue == true, or
            //      IsActive == false since these are skipped above.
            var query = Provider.Scheduler.Reservation.SelectHistoryToForgiveForRepair(repair.ResourceID, repair.BeginDateTime, repair.EndDateTime);

            var result = false;

            foreach (var rsv in query)
            {
                // Avoid resending the email if the reservation was already forgiven
                if (rsv.ChargeMultiplier > 0)
                {
                    // Set charge multiplier to zero, notes have already been appended
                    Provider.Scheduler.Reservation.UpdateCharges(rsv.ReservationID, string.Empty, 0, true, CurrentUser.ClientID);

                    // Email User after everything is done.
                    Provider.Scheduler.Email.EmailOnForgiveCharge(rsv.ReservationID, 100, true, CurrentUser.ClientID);

                    // The session variable is set now and then checked for on the next page load.
                    result = true;
                }
            }

            // Update forgiven charge on FinOps. Enqueue an UpdateBilling request. This will
            // return immediately and the update will process in the background using OnlineServicesWorker.
            DateTime sd = repair.BeginDateTime.FirstOfMonth();

            Provider.Worker.Execute(new UpdateBillingWorkerRequest(sd, 0, new[] { "tool", "room" }));

            return(result);
        }
示例#21
0
        public ReservationClient GetReservationClient(IReservationItem rsv, IClient client, IEnumerable <IResourceClient> resourceClients)
        {
            var invitees = Provider.Scheduler.Reservation.GetInvitees(rsv.ReservationID);

            return(GetReservationClient(rsv, client, resourceClients, invitees));
        }
示例#22
0
        public ReservationClient GetReservationClient(IReservationItem rsv, IClient client)
        {
            var resourceClients = Provider.Scheduler.Reservation.GetResourceClients(rsv.ResourceID);

            return(GetReservationClient(rsv, client, resourceClients));
        }
示例#23
0
 public ReservationClient GetReservationClient(IReservationItem rsv) => GetReservationClient(rsv, CurrentUser());
示例#24
0
 public bool IsAuthorized(IReservationItem rsv) => (UserAuth & rsv.StartEndAuth) > 0;
示例#25
0
 public ReservationClient GetReservationClient(IReservationItem rsv, IEnumerable <IReservationInviteeItem> invitees) => GetReservationClient(rsv, CurrentUser());
 public SaveReservationHistoryResult SaveReservationHistory(IReservationItem rsv, int accountId, double?forgivenPct, string notes, bool emailClient, int modifiedByClientId)
 {
     throw new NotImplementedException();
 }
示例#27
0
 public static bool IsRunning(this IReservationItem item)
 {
     return(item.ActualBeginDateTime != null && item.ActualEndDateTime == null);
 }
示例#28
0
 public IEnumerable <IClientAccount> AvailableAccounts(IReservationItem rsv)
 {
     throw new NotImplementedException();
 }
示例#29
0
 public IAutoEndLog AddAutoEndLog(IReservationItem rsv, string action)
 {
     throw new NotImplementedException();
 }
        public static StartReservationItem CreateStartReservationItem(HttpContextBase context, IProvider provider, IReservationItem rsv)
        {
            var now = DateTime.Now;

            var item = new StartReservationItem
            {
                ReservationID        = rsv.ReservationID,
                ResourceID           = rsv.ResourceID,
                ResourceName         = rsv.ResourceName,
                ReservedByClientID   = rsv.ClientID,
                ReservedByClientName = string.Format("{0} {1}", rsv.FName, rsv.LName)
            };

            var currentUser = context.CurrentUser(provider);

            if (rsv.ClientIDBegin.HasValue)
            {
                if (rsv.ClientIDBegin.Value > 0)
                {
                    IClient startedBy = provider.Data.Client.GetClient(rsv.ClientIDBegin.Value);
                    item.StartedByClientID   = startedBy.ClientID;
                    item.StartedByClientName = string.Format("{0} {1}", startedBy.FName, startedBy.LName);
                }
                else
                {
                    item.StartedByClientID   = 0;
                    item.StartedByClientName = string.Empty;
                }
            }
            else
            {
                item.StartedByClientID = currentUser.ClientID;

                item.StartedByClientName = string.Format("{0} {1}", currentUser.FName, currentUser.LName);
            }

            var reservationItem    = provider.Scheduler.Reservation.GetReservationWithInvitees(rsv.ReservationID);
            var helper             = new SchedulerContextHelper(context, provider);
            var args               = ReservationStateArgs.Create(reservationItem, helper.GetReservationClient(reservationItem), now);
            var stateUtil          = ReservationStateUtility.Create(now);
            ReservationState state = stateUtil.GetReservationState(args);

            item.Startable           = stateUtil.IsStartable(state);
            item.NotStartableMessage = GetNotStartableMessage(state);

            var inst = ActionInstances.Find(ActionType.Interlock, rsv.ResourceID);

            item.HasInterlock = inst != null;

            var res = provider.Scheduler.Resource.GetResource(rsv.ResourceID);

            item.ReturnUrl = GetResourceUrl(context, res);

            return(item);
        }