/// <summary> /// Cancels the order. /// </summary> /// <param name="cancelInfo"></param> public virtual void Cancel(OrderCancelInfo cancelInfo) { if (this.Status != OrderStatus.SC) { throw new WorkflowException("Only orders in the SC status can be canceled"); } _cancelInfo = cancelInfo; // cancel/discontinue all procedures foreach (var procedure in _procedures) { // given that the order is still in SC, all procedures must be either // SC or CA - and only those in SC need to be cancelled if (procedure.Status == ProcedureStatus.SC) { procedure.Cancel(); } } // if the order was replaced, change the status to RP if (cancelInfo.ReplacementOrder != null) { SetStatus(OrderStatus.RP); } // need to update the end-time again, after cacnelling procedures UpdateEndTime(); }
/// <summary> /// Discontinues the order. /// </summary> public virtual void Discontinue(OrderCancelInfo cancelInfo) { if (this.Status != OrderStatus.IP) { throw new WorkflowException("Only orders in the IP status can be discontinued"); } _cancelInfo = cancelInfo; // update the status prior to cancelling the procedures // (otherwise cancelling the procedures will cause them to try and update the order status) SetStatus(OrderStatus.DC); // cancel or discontinue any non-terminated procedures foreach (var procedure in _procedures) { if (procedure.Status == ProcedureStatus.SC) { procedure.Cancel(); } else if (procedure.Status == ProcedureStatus.IP) { procedure.Discontinue(); } } // need to update the end-time again, after discontinuing procedures UpdateEndTime(); }
/// <summary> /// Gets a value indicating whether this order can be unmerged from its merge destination. /// </summary> /// <param name="cancelInfo"></param> /// <param name="failureReason"></param> /// <returns></returns> public virtual bool CanUnmerge(OrderCancelInfo cancelInfo, out string failureReason) { var destOrder = _mergeInfo.MergeDestinationOrder; failureReason = null; if (_status != OrderStatus.MG || destOrder == null) { failureReason = "Only orders in the MG status can be unmerged."; } else if (destOrder.Status != OrderStatus.SC) { failureReason = "Cannot unmerge because the merge target order has already been started."; } else if (CollectionUtils.Contains(destOrder.Procedures, p => p.Status == ProcedureStatus.CA)) { failureReason = "Cannot unmerge because the merge target order has cancelled procedures."; } else if (cancelInfo.Reason == null) { failureReason = "A reason must be provided to unmerge."; } else if (CollectionUtils.Contains(this.Procedures, p => p.DowntimeRecoveryMode) || CollectionUtils.Contains(destOrder.Procedures, p => p.DowntimeRecoveryMode)) { failureReason = "Downtime orders cannot be unmerged."; } return(string.IsNullOrEmpty(failureReason)); }
/// <summary> /// Gets a value indicating whether this order can be unmerged from its merge destination. /// </summary> /// <param name="cancelInfo"></param> /// <param name="failureReason"></param> /// <returns></returns> public virtual bool CanUnmerge(OrderCancelInfo cancelInfo, out string failureReason) { // Bug #12488 - unmerging orders as it exists currently will leave ghost procedures around, which can eventually corrupt the order state after repeated merge-unmerge cycles failureReason = "Not Supported"; return(false); //var destOrder = _mergeInfo.MergeDestinationOrder; //failureReason = null; //if (_status != OrderStatus.MG || destOrder == null) // failureReason = "Only orders in the MG status can be unmerged."; //else if (destOrder.Status != OrderStatus.SC) // failureReason = "Cannot unmerge because the merge target order has already been started."; //else if(CollectionUtils.Contains(destOrder.Procedures, p => p.Status == ProcedureStatus.CA)) // failureReason = "Cannot unmerge because the merge target order has cancelled procedures."; //else if (cancelInfo.Reason == null) // failureReason = "A reason must be provided to unmerge."; //else if (CollectionUtils.Contains(this.Procedures, p => p.DowntimeRecoveryMode) // || CollectionUtils.Contains(destOrder.Procedures, p => p.DowntimeRecoveryMode)) // failureReason = "Downtime orders cannot be unmerged."; //return string.IsNullOrEmpty(failureReason); }
/// <summary> /// Un-merges this order from its merge destination, returning a new order with the specified accession #, /// and marking this order as Replaced by the new order. /// </summary> /// <param name="cancelInfo"></param> /// <param name="newAccessionNumber"></param> /// <returns></returns> public virtual UnmergeResult Unmerge(OrderCancelInfo cancelInfo, string newAccessionNumber) { string failureReason; if (!CanUnmerge(cancelInfo, out failureReason)) { throw new WorkflowException(failureReason); } var destOrder = _mergeInfo.MergeDestinationOrder; // create replacement order var newOrder = new Order( _patient, _visit, null, // do not copy placer-number newAccessionNumber, // assign new acc # _diagnosticService, _enteredTime, _enteredBy, _enteredComment, _schedulingRequestTime, null, // will be set by call to UpdateScheduling() null, null, _orderingPractitioner, _orderingFacility, new HashedSet <Procedure>(), // will be added later new HashedSet <Procedure>(), // ghosts CollectionUtils.Map(_resultRecipients, (ResultRecipient rr) => (ResultRecipient)rr.Clone()), new List <OrderAttachment>(), _reasonForStudy, _priority, (int)_priority, OrderStatus.SC, null, null, new HashedSet <Order>(), ExtendedPropertyUtils.Copy(_extendedProperties) ); // reclaim order notes var notes = OrderNote.GetNotesForOrder(this); var reclaimNotes = CollectionUtils.Map( CollectionUtils.Select(notes, n => n.GhostOf != null), (OrderNote n) => n.GhostOf.Downcast <OrderNote>()); foreach (var note in reclaimNotes) { note.Order = newOrder; } // reclaim attachments var reclaimAttachments = CollectionUtils.Map(_attachments, (OrderAttachment a) => CollectionUtils.SelectFirst(destOrder.Attachments, b => Equals(a.Document.GhostOf, b.Document))); foreach (var attachment in reclaimAttachments) { destOrder.Attachments.Remove(attachment); newOrder.Attachments.Add(attachment); } // reclaim procedures // need to create new ghost copies on the dest order, so that HL7 can cancel them var reclaimProcedures = CollectionUtils.Map(_ghostProcedures, (Procedure p) => p.GhostOf); var ghostProcedures = CollectionUtils.Map(reclaimProcedures, (Procedure p) => p.CreateGhostCopy()); foreach (var procedure in reclaimProcedures) { newOrder.AddProcedure(procedure); } destOrder.Procedures.AddAll(ghostProcedures); // note: procedure Indexes are already set correctly // update scheduling/status information newOrder.UpdateScheduling(); newOrder.UpdateStatus(); // any orders that were merged into this order must be redirected to the new order, // in order to support recursive unmerge foreach (var sourceOrder in _mergeSourceOrders) { sourceOrder.MergeInfo.MergeDestinationOrder = newOrder; newOrder.MergeSourceOrders.Add(sourceOrder); } _mergeSourceOrders.Clear(); // change status of this order to RP, and set cancel info _cancelInfo = (OrderCancelInfo)cancelInfo.Clone(); _cancelInfo.ReplacementOrder = newOrder; // clear merge info on this order, since it is no longer considered merged _mergeInfo = null; // set status of this order to RP, and set end time manually SetStatus(OrderStatus.RP); _endTime = Platform.Time; return(new UnmergeResult { ReplacementOrder = newOrder, GhostProcedures = ghostProcedures }); }
private void UnmergeHelper(IEnumerable<Order> sourceOrders, OrderCancelInfo cancelInfo, IAccessionNumberBroker accBroker) { foreach (var order in sourceOrders) { string failureReason; if (!order.CanUnmerge(cancelInfo, out failureReason)) throw new RequestValidationException(failureReason); var result = order.Unmerge(cancelInfo, accBroker.GetNext()); var replacementOrder = result.ReplacementOrder; PersistenceContext.Lock(replacementOrder, DirtyState.New); // sync state so that ghost procedures get OIDs, prior to queuing ghost HL7 events PersistenceContext.SynchState(); // notify HL7 of cancelled procedures (now existing as ghosts on dest order) foreach (var procedure in result.GhostProcedures) { LogicalHL7Event.ProcedureCancelled.EnqueueEvents(procedure); } // if the replacement order is not terminated if (!replacementOrder.IsTerminated) { // notify HL7 of replacement LogicalHL7Event.OrderCreated.EnqueueEvents(replacementOrder); // recur on items that were merged into this order UnmergeHelper(replacementOrder.MergeSourceOrders, cancelInfo, accBroker); } } }
public UnmergeOrderResponse UnmergeOrder(UnmergeOrderRequest request) { Platform.CheckForNullReference(request, "request"); Platform.CheckMemberIsSet(request.OrderRef, "OrderRef"); // reason is not required for dry run, but otherwise it is if (!request.DryRun && request.UnmergeReason == null) throw new ArgumentNullException("UnmergeReason"); DryRunHelper(request.DryRun, delegate { var destinationOrder = this.PersistenceContext.Load<Order>(request.OrderRef); var sourceOrders = destinationOrder.MergeSourceOrders; if (sourceOrders.Count == 0) throw new RequestValidationException("This order does not have any orders to un-merge."); // load the reason; if reason is null (eg dry run), just get the first available reason var reason = request.UnmergeReason == null ? CollectionUtils.FirstElement(PersistenceContext.GetBroker<IEnumBroker>().Load<OrderCancelReasonEnum>(false)) : EnumUtils.GetEnumValue<OrderCancelReasonEnum>(request.UnmergeReason, PersistenceContext); var cancelInfo = new OrderCancelInfo(reason, this.CurrentUserStaff, "Un-merged"); var accBroker = PersistenceContext.GetBroker<IAccessionNumberBroker>(); // do unmerge UnmergeHelper(sourceOrders, cancelInfo, accBroker); }); return new UnmergeOrderResponse(); }
private static void CancelOrderHelper(Order order, OrderCancelInfo info) { var operation = new CancelOrDiscontinueOrderOperation(); operation.Execute(order, info); }
/// <summary> /// Discontinues the order. /// </summary> public virtual void Discontinue(OrderCancelInfo cancelInfo) { if (this.Status != OrderStatus.IP) throw new WorkflowException("Only orders in the IP status can be discontinued"); _cancelInfo = cancelInfo; // update the status prior to cancelling the procedures // (otherwise cancelling the procedures will cause them to try and update the order status) SetStatus(OrderStatus.DC); // cancel or discontinue any non-terminated procedures foreach (var procedure in _procedures) { if (procedure.Status == ProcedureStatus.SC) procedure.Cancel(); else if (procedure.Status == ProcedureStatus.IP) procedure.Discontinue(); } // need to update the end-time again, after discontinuing procedures UpdateEndTime(); }
/// <summary> /// Cancels the order. /// </summary> /// <param name="cancelInfo"></param> public virtual void Cancel(OrderCancelInfo cancelInfo) { if (this.Status != OrderStatus.SC) throw new WorkflowException("Only orders in the SC status can be canceled"); _cancelInfo = cancelInfo; // cancel/discontinue all procedures foreach (var procedure in _procedures) { // given that the order is still in SC, all procedures must be either // SC or CA - and only those in SC need to be cancelled if (procedure.Status == ProcedureStatus.SC) procedure.Cancel(); } // if the order was replaced, change the status to RP if (cancelInfo.ReplacementOrder != null) SetStatus(OrderStatus.RP); // need to update the end-time again, after cacnelling procedures UpdateEndTime(); }
/// <summary> /// Un-merges this order from its merge destination, returning a new order with the specified accession #, /// and marking this order as Replaced by the new order. /// </summary> /// <param name="cancelInfo"></param> /// <param name="newAccessionNumber"></param> /// <returns></returns> public virtual UnmergeResult Unmerge(OrderCancelInfo cancelInfo, string newAccessionNumber) { string failureReason; if (!CanUnmerge(cancelInfo, out failureReason)) throw new WorkflowException(failureReason); var destOrder = _mergeInfo.MergeDestinationOrder; // create replacement order var newOrder = new Order( _patient, _visit, null, // do not copy placer-number newAccessionNumber, // assign new acc # _diagnosticService, _enteredTime, _enteredBy, _enteredComment, _schedulingRequestTime, null, // will be set by call to UpdateScheduling() null, null, _orderingPractitioner, _orderingFacility, new HashedSet<Procedure>(), // will be added later new HashedSet<Procedure>(), // ghosts CollectionUtils.Map(_resultRecipients, (ResultRecipient rr) => (ResultRecipient)rr.Clone()), new List<OrderAttachment>(), _reasonForStudy, _priority, (int)_priority, OrderStatus.SC, null, null, new HashedSet<Order>(), ExtendedPropertyUtils.Copy(_extendedProperties) ); // reclaim order notes var notes = OrderNote.GetNotesForOrder(this); var reclaimNotes = CollectionUtils.Map( CollectionUtils.Select(notes, n => n.GhostOf != null), (OrderNote n) => n.GhostOf.Downcast<OrderNote>()); foreach (var note in reclaimNotes) { note.Order = newOrder; } // reclaim attachments var reclaimAttachments = CollectionUtils.Map(_attachments, (OrderAttachment a) => CollectionUtils.SelectFirst(destOrder.Attachments, b => Equals(a.Document.GhostOf, b.Document))); foreach (var attachment in reclaimAttachments) { destOrder.Attachments.Remove(attachment); newOrder.Attachments.Add(attachment); } // reclaim procedures // need to create new ghost copies on the dest order, so that HL7 can cancel them var reclaimProcedures = CollectionUtils.Map(_ghostProcedures, (Procedure p) => p.GhostOf); var ghostProcedures = CollectionUtils.Map(reclaimProcedures, (Procedure p) => p.CreateGhostCopy()); foreach (var procedure in reclaimProcedures) { newOrder.AddProcedure(procedure); } destOrder.Procedures.AddAll(ghostProcedures); // note: procedure Indexes are already set correctly // update scheduling/status information newOrder.UpdateScheduling(); newOrder.UpdateStatus(); // any orders that were merged into this order must be redirected to the new order, // in order to support recursive unmerge foreach (var sourceOrder in _mergeSourceOrders) { sourceOrder.MergeInfo.MergeDestinationOrder = newOrder; newOrder.MergeSourceOrders.Add(sourceOrder); } _mergeSourceOrders.Clear(); // change status of this order to RP, and set cancel info _cancelInfo = (OrderCancelInfo)cancelInfo.Clone(); _cancelInfo.ReplacementOrder = newOrder; // clear merge info on this order, since it is no longer considered merged _mergeInfo = null; // set status of this order to RP, and set end time manually SetStatus(OrderStatus.RP); _endTime = Platform.Time; return new UnmergeResult {ReplacementOrder = newOrder, GhostProcedures = ghostProcedures}; }
/// <summary> /// Gets a value indicating whether this order can be unmerged from its merge destination. /// </summary> /// <param name="cancelInfo"></param> /// <param name="failureReason"></param> /// <returns></returns> public virtual bool CanUnmerge(OrderCancelInfo cancelInfo, out string failureReason) { // Bug #12488 - unmerging orders as it exists currently will leave ghost procedures around, which can eventually corrupt the order state after repeated merge-unmerge cycles failureReason = "Not Supported"; return false; //var destOrder = _mergeInfo.MergeDestinationOrder; //failureReason = null; //if (_status != OrderStatus.MG || destOrder == null) // failureReason = "Only orders in the MG status can be unmerged."; //else if (destOrder.Status != OrderStatus.SC) // failureReason = "Cannot unmerge because the merge target order has already been started."; //else if(CollectionUtils.Contains(destOrder.Procedures, p => p.Status == ProcedureStatus.CA)) // failureReason = "Cannot unmerge because the merge target order has cancelled procedures."; //else if (cancelInfo.Reason == null) // failureReason = "A reason must be provided to unmerge."; //else if (CollectionUtils.Contains(this.Procedures, p => p.DowntimeRecoveryMode) // || CollectionUtils.Contains(destOrder.Procedures, p => p.DowntimeRecoveryMode)) // failureReason = "Downtime orders cannot be unmerged."; //return string.IsNullOrEmpty(failureReason); }
/// <summary> /// Gets a value indicating whether this order can be unmerged from its merge destination. /// </summary> /// <param name="cancelInfo"></param> /// <param name="failureReason"></param> /// <returns></returns> public virtual bool CanUnmerge(OrderCancelInfo cancelInfo, out string failureReason) { var destOrder = _mergeInfo.MergeDestinationOrder; failureReason = null; if (_status != OrderStatus.MG || destOrder == null) failureReason = "Only orders in the MG status can be unmerged."; else if (destOrder.Status != OrderStatus.SC) failureReason = "Cannot unmerge because the merge target order has already been started."; else if(CollectionUtils.Contains(destOrder.Procedures, p => p.Status == ProcedureStatus.CA)) failureReason = "Cannot unmerge because the merge target order has cancelled procedures."; else if (cancelInfo.Reason == null) failureReason = "A reason must be provided to unmerge."; else if (CollectionUtils.Contains(this.Procedures, p => p.DowntimeRecoveryMode) || CollectionUtils.Contains(destOrder.Procedures, p => p.DowntimeRecoveryMode)) failureReason = "Downtime orders cannot be unmerged."; return string.IsNullOrEmpty(failureReason); }