Ejemplo n.º 1
0
        /// <summary>
        /// Factory method to create a new order.
        /// </summary>
        public static Order NewOrder(OrderCreationArgs args, IProcedureNumberBroker procedureNumberBroker, IDicomUidBroker dicomUidBroker)
        {
            // validate required members are set
            Platform.CheckMemberIsSet(args.Patient, "Patient");
            Platform.CheckMemberIsSet(args.Visit, "Visit");
            Platform.CheckMemberIsSet(args.AccessionNumber, "AccessionNumber");
            Platform.CheckMemberIsSet(args.DiagnosticService, "DiagnosticService");
            Platform.CheckMemberIsSet(args.ReasonForStudy, "ReasonForStudy");
            Platform.CheckMemberIsSet(args.OrderingFacility, "OrderingFacility");
            Platform.CheckMemberIsSet(args.OrderingPractitioner, "OrderingPractitioner");


            // create the order
            var order = new Order
            {
                Patient               = args.Patient,
                Visit                 = args.Visit,
                AccessionNumber       = args.AccessionNumber,
                DiagnosticService     = args.DiagnosticService,
                ReasonForStudy        = args.ReasonForStudy,
                OrderingFacility      = args.OrderingFacility,
                OrderingPractitioner  = args.OrderingPractitioner,
                Priority              = args.Priority,
                SchedulingRequestTime = args.SchedulingRequestTime,
                EnteredTime           = args.EnteredTime,
                EnteredBy             = args.EnteredBy,
                EnteredComment        = args.EnteredComment
            };

            if (args.Procedures == null || args.Procedures.Count == 0)
            {
                // create procedures according to the diagnostic service plan
                args.Procedures = CollectionUtils.Map <ProcedureType, Procedure>(
                    args.DiagnosticService.ProcedureTypes,
                    type => new Procedure(type, procedureNumberBroker.GetNext(), dicomUidBroker.GetNewUid())
                {
                    PerformingFacility = args.PerformingFacility ?? args.OrderingFacility
                });
            }


            // associate all procedures with the order
            foreach (var procedure in args.Procedures)
            {
                order.AddProcedure(procedure);
            }

            // add recipients
            if (args.ResultRecipients != null)
            {
                foreach (var recipient in args.ResultRecipients)
                {
                    order.ResultRecipients.Add(recipient);
                }
            }

            var recipientsContainsOrderingPractitioner = CollectionUtils.Contains(
                order.ResultRecipients,
                r => r.PractitionerContactPoint.Practitioner.Equals(args.OrderingPractitioner));

            // if the result recipients collection does not contain the ordering practitioner, add it by force
            if (!recipientsContainsOrderingPractitioner)
            {
                var orderingPractitionerContactPoint =
                    // use the contact point associated to the ordering facility's information authority
                    CollectionUtils.SelectFirst(args.OrderingPractitioner.ContactPoints,
                                                cp => args.OrderingFacility.InformationAuthority.Equals(cp.InformationAuthority) && cp.Deactivated == false)
                    // or, use the default contact point
                    ?? CollectionUtils.SelectFirst(args.OrderingPractitioner.ContactPoints, cp => cp.IsDefaultContactPoint)
                    // or, if no default, use first available active CP (should never happen)
                    ?? CollectionUtils.SelectFirst(args.OrderingPractitioner.ContactPoints, cp => !cp.Deactivated)
                    // or, if no active CPs, use first in the collection (should never happen)
                    ?? CollectionUtils.FirstElement(args.OrderingPractitioner.ContactPoints);

                if (orderingPractitionerContactPoint != null)
                {
                    order.ResultRecipients.Add(new ResultRecipient(orderingPractitionerContactPoint, ResultCommunicationMode.ANY));
                }
            }

            return(order);
        }
Ejemplo n.º 2
0
        /// <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
            });
        }
Ejemplo n.º 3
0
		/// <summary>
		/// Factory method to create a new order.
		/// </summary>
		public static Order NewOrder(OrderCreationArgs args, IProcedureNumberBroker procedureNumberBroker, IDicomUidBroker dicomUidBroker)
		{
			// validate required members are set
			Platform.CheckMemberIsSet(args.Patient, "Patient");
			Platform.CheckMemberIsSet(args.Visit, "Visit");
			Platform.CheckMemberIsSet(args.AccessionNumber, "AccessionNumber");
			Platform.CheckMemberIsSet(args.DiagnosticService, "DiagnosticService");
			Platform.CheckMemberIsSet(args.ReasonForStudy, "ReasonForStudy");
			Platform.CheckMemberIsSet(args.OrderingFacility, "OrderingFacility");
			Platform.CheckMemberIsSet(args.OrderingPractitioner, "OrderingPractitioner");


			// create the order
			var order = new Order
			{
				Patient = args.Patient,
				Visit = args.Visit,
				AccessionNumber = args.AccessionNumber,
				DiagnosticService = args.DiagnosticService,
				ReasonForStudy = args.ReasonForStudy,
				OrderingFacility = args.OrderingFacility,
				OrderingPractitioner = args.OrderingPractitioner,
				Priority = args.Priority,
				SchedulingRequestTime = args.SchedulingRequestTime,
				EnteredTime = args.EnteredTime,
				EnteredBy = args.EnteredBy,
				EnteredComment = args.EnteredComment
			};

			if (args.Procedures == null || args.Procedures.Count == 0)
			{
				// create procedures according to the diagnostic service plan
				args.Procedures = CollectionUtils.Map<ProcedureType, Procedure>(
					args.DiagnosticService.ProcedureTypes,
					type => new Procedure(type, procedureNumberBroker.GetNext(), dicomUidBroker.GetNewUid())
								{
									PerformingFacility = args.PerformingFacility ?? args.OrderingFacility
								});
			}


			// associate all procedures with the order
			foreach (var procedure in args.Procedures)
			{
				order.AddProcedure(procedure);
			}

			// add recipients
			if (args.ResultRecipients != null)
			{
				foreach (var recipient in args.ResultRecipients)
				{
					order.ResultRecipients.Add(recipient);
				}
			}

			var recipientsContainsOrderingPractitioner = CollectionUtils.Contains(
				order.ResultRecipients,
				r => r.PractitionerContactPoint.Practitioner.Equals(args.OrderingPractitioner));

			// if the result recipients collection does not contain the ordering practitioner, add it by force
			if (!recipientsContainsOrderingPractitioner)
			{
				var orderingPractitionerContactPoint =
					// use the contact point associated to the ordering facility's information authority
					CollectionUtils.SelectFirst(args.OrderingPractitioner.ContactPoints,
						cp => args.OrderingFacility.InformationAuthority.Equals(cp.InformationAuthority) && cp.Deactivated == false)
					// or, use the default contact point
					?? CollectionUtils.SelectFirst(args.OrderingPractitioner.ContactPoints, cp => cp.IsDefaultContactPoint)
					// or, if no default, use first available active CP (should never happen)
					?? CollectionUtils.SelectFirst(args.OrderingPractitioner.ContactPoints, cp => !cp.Deactivated)
					// or, if no active CPs, use first in the collection (should never happen)
					?? CollectionUtils.FirstElement(args.OrderingPractitioner.ContactPoints);

				if (orderingPractitionerContactPoint != null)
				{
					order.ResultRecipients.Add(new ResultRecipient(orderingPractitionerContactPoint, ResultCommunicationMode.ANY));
				}
			}

			return order;
		}
Ejemplo n.º 4
0
		private void UpdateProceduresHelper(Order order, IEnumerable<ProcedureRequisition> procedureReqs, ModifyOrderRequest request)
		{
			// do not update the procedures if the order is completed
			if (order.IsTerminated)
				return;

			var assembler = new OrderEntryAssembler();

			// if any procedure is in downtime recovery mode, assume the entire order is a "downtime order"
			var isDowntime = CollectionUtils.Contains(order.Procedures, p => p.DowntimeRecoveryMode);

			// separate the list into additions and updates
			var existingReqs = new List<ProcedureRequisition>();
			var addedReqs = new List<ProcedureRequisition>();

			foreach (var req in procedureReqs)
			{
				if (CollectionUtils.Contains(order.Procedures, x => req.ProcedureNumber == x.Number))
				{
					existingReqs.Add(req);
				}
				else
				{
					addedReqs.Add(req);
				}
			}

			// process the additions first, so that we don't accidentally cancel an order (if all its procedures are cancelled momentarily)
			var procedureNumberBroker = PersistenceContext.GetBroker<IProcedureNumberBroker>();
			var dicomUidBroker = PersistenceContext.GetBroker<IDicomUidBroker>();
			foreach (var req in addedReqs)
			{
				var requestedType = this.PersistenceContext.Load<ProcedureType>(req.ProcedureType.ProcedureTypeRef);

				// create a new procedure for this requisition
				var procedure = new Procedure(requestedType, procedureNumberBroker.GetNext(), dicomUidBroker.GetNewUid()) { DowntimeRecoveryMode = isDowntime };
				order.AddProcedure(procedure);

				// note: need to lock the new procedure now, prior to creating the procedure steps
				// otherwise may get exceptions saying the Procedure is a transient object
				this.PersistenceContext.Lock(procedure, DirtyState.New);

				// create the procedure steps
				procedure.CreateProcedureSteps();

				// apply the requisition information to the actual procedure
				assembler.UpdateProcedureFromRequisition(procedure, req, this.CurrentUserStaff, this.PersistenceContext);

				LogicalHL7Event.ProcedureCreated.EnqueueEvents(procedure);
			}

			// process updates
			foreach (var req in existingReqs)
			{
				var requestedType = this.PersistenceContext.Load<ProcedureType>(req.ProcedureType.ProcedureTypeRef);
				var procedure = CollectionUtils.SelectFirst(order.Procedures, x => req.ProcedureNumber == x.Number);

				// validate that the type has not changed
				if (!procedure.Type.Equals(requestedType))
					throw new RequestValidationException("Order modification must not modify the type of a requested procedure.");

				// If the procedure is already terminated, just move on to the next one since procedures cannot be "un-terminated".
				if (procedure.IsTerminated)
					continue;

				// apply the requisition information to the actual procedure
				assembler.UpdateProcedureFromRequisition(procedure, req, this.CurrentUserStaff, this.PersistenceContext);

				(req.Cancelled ? LogicalHL7Event.ProcedureCancelled : LogicalHL7Event.ProcedureModified).EnqueueEvents(procedure);
			}
		}
Ejemplo n.º 5
0
		/// <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};
		}