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); }
public ReservationState GetUnstartedReservationState(ReservationStateArgs args) { bool isInLab = false; bool isReserver = false; bool isInvited = false; bool isAuthorized = false; bool isBeforeMinCancelTime = args.IsBeforeMinCancelTime(Now); bool isStartable = args.IsStartable(Now); if (!args.IsToolEngineer) { isInLab = args.IsInLab; isReserver = args.IsReserver; isInvited = args.IsInvited; isAuthorized = args.IsAuthorized; } var subStateValue = GetSubStateVal(isInLab, isReserver, isInvited, isAuthorized, isBeforeMinCancelTime, isStartable); var result = (args.IsToolEngineer) ? TruthTableTE[subStateValue] : TruthTable[subStateValue]; bool throwErrorOnUndefined = false; if (throwErrorOnUndefined && result == ReservationState.Undefined) { var errmsg = "Unstarted reservation state is undefined." + " ReservationID: {0}, IsToolEngineer: {1}, IsInLab: {2}, IsReserver: {3}, IsInvited: {4}, IsAuthorized: {5}, IsBeforeMinCancelTime: {6}, IsStartable: {7}, SubStateValue: {8}"; throw new Exception(string.Format(errmsg, args.ReservationID, args.IsToolEngineer ? "Yes" : "No", isInLab ? "Yes" : "No", isReserver ? "Yes" : "No", isInvited ? "Yes" : "No", isAuthorized ? "Yes" : "No", isBeforeMinCancelTime ? "Yes" : "No", isStartable ? "Yes" : "No", subStateValue)); } return(result); }
// This is the truth table for non tool engineer // note that having both R and I true is meaningless // L - IsInLab // R - IsReserver // I - IsInvited // A - IsAuth // M - Before MCT // S - In Start Per // L R I A M S // 0 0 0 0 0 0 ReservationState.Other [00] // 0 0 0 0 0 1 ReservationState.Other [01] // 0 0 0 0 1 0 ReservationState.Other [02] // 0 0 0 0 1 1 ReservationState.Other [03] // 0 0 0 1 0 0 ReservationState.Other [04] // 0 0 0 1 0 1 ReservationState.Other [05] // 0 0 0 1 1 0 ReservationState.Other [06] // 0 0 0 1 1 1 ReservationState.Other [07] // 0 0 1 0 0 0 ReservationState.Invited [08] // 0 0 1 0 0 1 ReservationState.Invited [09] // 0 0 1 0 1 0 ReservationState.Invited [10] // 0 0 1 0 1 1 ReservationState.Invited [11] // 0 0 1 1 0 0 ReservationState.Invited [12] // 0 0 1 1 0 1 ReservationState.NotInLab [13] // 0 0 1 1 1 0 ReservationState.Invited [14] // 0 0 1 1 1 1 ReservationState.NotInLab [15] // 0 1 0 0 0 0 ReservationState.Undefined [16] // 0 1 0 0 0 1 ReservationState.UnAuthToStart [17] // 0 1 0 0 1 0 ReservationState.Editable [18] // 0 1 0 0 1 1 ReservationState.Editable [19] // 0 1 0 1 0 0 ReservationState.Undefined [20] // 0 1 0 1 0 1 ReservationState.NotInLab [21] // 0 1 0 1 1 0 ReservationState.Editable [22] // 0 1 0 1 1 1 ReservationState.Editable [23] // 0 1 1 0 0 0 ReservationState.Undefined [24] // 0 1 1 0 0 1 ReservationState.Undefined [25] // 0 1 1 0 1 0 ReservationState.Undefined [26] // 0 1 1 0 1 1 ReservationState.Undefined [27] // 0 1 1 1 0 0 ReservationState.Undefined [28] // 0 1 1 1 0 1 ReservationState.Undefined [29] // 0 1 1 1 1 0 ReservationState.Undefined [30] // 0 1 1 1 1 1 ReservationState.Undefined [31] // 1 0 0 0 0 0 ReservationState.Other [32] // 1 0 0 0 0 1 ReservationState.Other [33] // 1 0 0 0 1 0 ReservationState.Other [34] // 1 0 0 0 1 1 ReservationState.Other [35] // 1 0 0 1 0 0 ReservationState.Other [36] // 1 0 0 1 0 1 ReservationState.Other [37] // 1 0 0 1 1 0 ReservationState.Other [38] // 1 0 0 1 1 1 ReservationState.Other [39] // 1 0 1 0 0 0 ReservationState.Invited [40] // 1 0 1 0 0 1 ReservationState.Invited [41] // 1 0 1 0 1 0 ReservationState.Invited [42] // 1 0 1 0 1 1 ReservationState.Invited [43] // 1 0 1 1 0 0 ReservationState.Invited [44] // 1 0 1 1 0 1 ReservationState.StartOnly [45] // 1 0 1 1 1 0 ReservationState.Invited [46] // 1 0 1 1 1 1 ReservationState.StartOrDelete [47] [2020-10-08 jg] changed from StartOnly to StartOrDelete so invitee can cancel reservation // 1 1 0 0 0 0 ReservationState.Undefined [48] // 1 1 0 0 0 1 ReservationState.UnAuthToStart [49] // 1 1 0 0 1 0 ReservationState.Editable [50] // 1 1 0 0 1 1 ReservationState.Editable [51] // 1 1 0 1 0 0 ReservationState.Undefined [52] // 1 1 0 1 0 1 ReservationState.StartOnly [53] // 1 1 0 1 1 0 ReservationState.Editable [54] // 1 1 0 1 1 1 ReservationState.StartOrDelete [55] // 1 1 1 0 0 0 ReservationState.Undefined [56] // 1 1 1 0 0 1 ReservationState.Undefined [57] // 1 1 1 0 1 0 ReservationState.Undefined [58] // 1 1 1 0 1 1 ReservationState.Undefined [59] // 1 1 1 1 0 0 ReservationState.Undefined [60] // 1 1 1 1 0 1 ReservationState.Undefined [61] // 1 1 1 1 1 0 ReservationState.Undefined [62] // 1 1 1 1 1 1 ReservationState.Undefined [63] // L R I A M S // The truth table for tool engineers is simply this // for TE, MCT=0, so both M and S cannot both be false // L R I A M S // x x x x 0 0 ReservationState.Undefined // x x x x 0 1 ReservationState.StartOnly // x x x x 1 0 ReservationState.Editable // x x x x 1 1 ReservationState.StartOrDelete // Note that the four cases in which the res can be started are modified by IsInLab. // if this is false, the state changes as shown above #endregion public ReservationState GetReservationState(ReservationStateArgs args) { // Repair Reservations, returns immediately // 2008-08-15 temp (return Meeting if ReservationID is -1) if (args.IsRepair) { return(args.ReservationID == -1 ? ReservationState.Meeting : ReservationState.Repair); } if (args.ActualBeginDateTime == null && args.ActualEndDateTime == null) { // reservations that have not yet been started if (args.EndDateTime <= Now) // should never occur - if in the past, the actuals should exist { if (args.IsReserver) { return(ReservationState.PastSelf); } else { return(ReservationState.PastOther); } } // redefine min cancel time (MCT) for tool engineers - can edit up until scheduled start time return(GetUnstartedReservationState(args)); } else if (args.ActualBeginDateTime != null && args.ActualEndDateTime == null) { // reservations that have been started if (args.IsReserver || args.IsToolEngineer) { return(ReservationState.Endable); } else if (args.IsInvited) { if (args.UserAuth != ClientAuthLevel.UnauthorizedUser && args.UserAuth != ClientAuthLevel.RemoteUser) { //2008-06-26 Sandrine requested that invitee should be able to end the reservation return(ReservationState.Endable); } else { return(ReservationState.Invited); } } else { return(ReservationState.ActiveNotEndable); } } else if (args.ActualBeginDateTime != null && args.ActualEndDateTime != null) { // at this point actualEndDateTime must not be null, and // we don't care if actualBeginDateTime is null or not // reservations in the past OR it's Facility Down Time reservation if (args.IsFacilityDownTime) { // Facility Down Time, it must be editable if it's not started yet if (args.ActualEndDateTime.HasValue && args.ActualEndDateTime.Value < Now && args.IsToolEngineer) { return(ReservationState.PastSelf); // FDT reservation that has already ended } else if (args.BeginDateTime > Now && args.IsToolEngineer) { return(ReservationState.Editable); // FDT reservation that has not started yet } else if (args.EndDateTime > Now && args.IsToolEngineer) { return(ReservationState.Endable); //it's endable only if it's not ended yet } else { return(ReservationState.Other); } } if (args.IsReserver) { return(ReservationState.PastSelf); } else { return(ReservationState.PastOther); } } else //if (actualBeginDateTime == null && actualEndDateTime != null) { // a reservation cannot have ended if it never began throw new InvalidOperationException("ActualBeginDateTime cannot be null if ActualEndDateTime is not null."); } }
/// <summary> /// Starts a reservation, and turns on Interlock. /// </summary> /// <param name="item">The reservation to start</param> /// <param name="client">The current user starting the reservation</param> public void Start(IReservationItem item, ReservationClient client, int?modifiedByClientId) { if (item == null) { throw new ArgumentNullException("item", "A null ReservationItem object is not allowed."); } if (item.IsStarted) { return; } var args = ReservationStateArgs.Create(item, client, Now); ReservationState state = ReservationStateUtility.Create(Now).GetReservationState(args); if (state != ReservationState.StartOnly && state != ReservationState.StartOrDelete) { if (!args.IsInLab) { throw new Exception($"Reservation #{item.ReservationID} is not startable at this time. You must be inside the lab to start reservations."); } else if (!args.IsAuthorized) { throw new Exception($"Reservation #{item.ReservationID} is not startable at this time. You are not authorized to start reservations on this tool."); } else { throw new Exception($"Reservation #{item.ReservationID} is not startable at this time. State: {state}."); } } // End Previous un-ended reservations var endableQuery = Provider.Scheduler.Reservation.SelectEndableReservations(item.ResourceID); foreach (var endable in endableQuery) { // no need to disable interlock or send open slot notifications for each of these // so calling IReservationManager.EndReservation directly instead of ReservationUtility.End Provider.Scheduler.Reservation.EndReservation(new EndReservationArgs { ReservationID = endable.ReservationID, ActualEndDateTime = Now, EndedByClientID = modifiedByClientId.GetValueOrDefault(-1) }); } // Start Reservation Provider.Scheduler.Reservation.StartReservation(item.ReservationID, modifiedByClientId); // If Resource authorization type is rolling and the reserver is a regular user for the resource then reset reserver's expiration date int authLevel = 0, resourceClientId = 0; var resourceClients = Provider.Scheduler.Resource.GetResourceClients(item.ResourceID, clientId: client.ClientID); if (resourceClients.Any()) { var rc = resourceClients.First(); authLevel = Convert.ToInt32(rc.AuthLevel); resourceClientId = rc.ResourceClientID; } if (item.AuthState && (authLevel == (int)ClientAuthLevel.AuthorizedUser)) { DateTime expiration = Now.AddMonths(item.AuthDuration); Provider.Scheduler.Resource.UpdateExpiration(resourceClientId, expiration); } // Turn Interlock On if (CacheManager.Current.WagoEnabled) { uint duration = OnTheFlyUtility.GetStateDuration(item.ResourceID); bool hasInterlock = WagoInterlock.ToggleInterlock(item.ResourceID, true, duration); if (hasInterlock) { bool interlockState = WagoInterlock.GetPointState(item.ResourceID); if (!interlockState) { throw new InvalidOperationException($"Failed to start interlock for ResourceID {item.ResourceID}."); } } } }