Ejemplo n.º 1
0
        public StaffDetail CreateStaffDetail(Staff staff, IPersistenceContext context)
        {
            PersonNameAssembler      assembler          = new PersonNameAssembler();
            StaffGroupAssembler      groupAssembler     = new StaffGroupAssembler();
            EmailAddressAssembler    emailAssembler     = new EmailAddressAssembler();
            TelephoneNumberAssembler telephoneAssembler = new TelephoneNumberAssembler();
            AddressAssembler         addressAssembler   = new AddressAssembler();

            return(new StaffDetail(
                       staff.GetRef(),
                       staff.Id,
                       EnumUtils.GetEnumValueInfo(staff.Type),
                       assembler.CreatePersonNameDetail(staff.Name),
                       EnumUtils.GetEnumValueInfo(staff.Sex, context),
                       staff.Title,
                       staff.LicenseNumber,
                       staff.BillingNumber,
                       CollectionUtils.Map <TelephoneNumber, TelephoneDetail>(
                           staff.TelephoneNumbers,
                           delegate(TelephoneNumber tn) { return telephoneAssembler.CreateTelephoneDetail(tn, context); }),
                       CollectionUtils.Map <Address, AddressDetail>(
                           staff.Addresses,
                           delegate(Address a) { return addressAssembler.CreateAddressDetail(a, context); }),
                       CollectionUtils.Map <EmailAddress, EmailAddressDetail>(
                           staff.EmailAddresses,
                           delegate(EmailAddress ea) { return emailAssembler.CreateEmailAddressDetail(ea, context); }),
                       CollectionUtils.Map <StaffGroup, StaffGroupSummary>(
                           staff.Groups,
                           delegate(StaffGroup group) { return groupAssembler.CreateSummary(group); }),
                       ExtendedPropertyUtils.Copy(staff.ExtendedProperties),
                       staff.Deactivated,
                       staff.UserName));
        }
        protected override ExternalPractitionerData Export(ExternalPractitioner entity, IReadContext context)
        {
            var data = new ExternalPractitionerData
            {
                Deactivated      = entity.Deactivated,
                FamilyName       = entity.Name.FamilyName,
                GivenName        = entity.Name.GivenName,
                MiddleName       = entity.Name.MiddleName,
                LicenseNumber    = entity.LicenseNumber,
                BillingNumber    = entity.BillingNumber,
                IsVerified       = entity.IsVerified,
                LastVerifiedTime = entity.LastVerifiedTime,
                LastEditedTime   = entity.LastEditedTime,
                ContactPoints    = CollectionUtils.Map(entity.ContactPoints,
                                                       (ExternalPractitionerContactPoint cp) => new ExternalPractitionerContactPointData
                {
                    Name = cp.Name,
                    IsDefaultContactPoint            = cp.IsDefaultContactPoint,
                    PreferredResultCommunicationMode = cp.PreferredResultCommunicationMode.ToString(),
                    InformationAuthority             = cp.InformationAuthority == null ? null : cp.InformationAuthority.Code,
                    Description      = cp.Description,
                    Addresses        = CollectionUtils.Map(cp.Addresses, (Address a) => new AddressData(a)),
                    TelephoneNumbers = CollectionUtils.Map(cp.TelephoneNumbers, (TelephoneNumber tn) => new TelephoneNumberData(tn)),
                    EmailAddresses   = CollectionUtils.Map(cp.EmailAddresses, (EmailAddress a) => new EmailAddressData(a))
                }),
                ExtendedProperties = ExtendedPropertyUtils.Copy(entity.ExtendedProperties)
            };

            return(data);
        }
Ejemplo n.º 3
0
        protected override StaffData Export(Staff entity, IReadContext context)
        {
            StaffData data = new StaffData();

            data.Deactivated   = entity.Deactivated;
            data.Id            = entity.Id;
            data.StaffType     = entity.Type.Code;
            data.Title         = entity.Title;
            data.FamilyName    = entity.Name.FamilyName;
            data.GivenName     = entity.Name.GivenName;
            data.MiddleName    = entity.Name.MiddleName;
            data.Sex           = entity.Sex.ToString();
            data.UserName      = entity.UserName;
            data.LicenseNumber = entity.LicenseNumber;
            data.BillingNumber = entity.BillingNumber;

            data.TelephoneNumbers = CollectionUtils.Map <TelephoneNumber, TelephoneNumberData>(entity.TelephoneNumbers,
                                                                                               delegate(TelephoneNumber tn) { return(new TelephoneNumberData(tn)); });
            data.Addresses = CollectionUtils.Map <Address, AddressData>(entity.Addresses,
                                                                        delegate(Address a) { return(new AddressData(a)); });
            data.EmailAddresses = CollectionUtils.Map <EmailAddress, EmailAddressData>(entity.EmailAddresses,
                                                                                       delegate(EmailAddress a) { return(new EmailAddressData(a)); });

            data.ExtendedProperties = ExtendedPropertyUtils.Copy(entity.ExtendedProperties);

            return(data);
        }
        public ModalityPerformedProcedureStepDetail CreateModalityPerformedProcedureStepDetail(ModalityPerformedProcedureStep mpps, IPersistenceContext context)
        {
            var assembler = new ModalityProcedureStepAssembler();

            // include the details of each MPS in the mpps summary
            var mpsDetails = CollectionUtils.Map(mpps.Activities,
                                                 (ProcedureStep mps) => assembler.CreateProcedureStepSummary(mps.As <ModalityProcedureStep>(), context));

            var dicomSeriesAssembler = new DicomSeriesAssembler();
            var dicomSeries          = dicomSeriesAssembler.GetDicomSeriesDetails(mpps.DicomSeries);

            StaffSummary mppsPerformer = null;
            var          performer     = mpps.Performer as ProcedureStepPerformer;

            if (performer != null)
            {
                var staffAssembler = new StaffAssembler();
                mppsPerformer = staffAssembler.CreateStaffSummary(performer.Staff, context);
            }

            return(new ModalityPerformedProcedureStepDetail(
                       mpps.GetRef(),
                       EnumUtils.GetEnumValueInfo(mpps.State, context),
                       mpps.StartTime,
                       mpps.EndTime,
                       mppsPerformer,
                       mpsDetails,
                       dicomSeries,
                       ExtendedPropertyUtils.Copy(mpps.ExtendedProperties)));
        }
        public CompleteModalityPerformedProcedureStepResponse CompleteModalityPerformedProcedureStep(CompleteModalityPerformedProcedureStepRequest request)
        {
            var mpps = this.PersistenceContext.Load <ModalityPerformedProcedureStep>(request.Mpps.ModalityPerformendProcedureStepRef);

            // update extended properties (should this be in an assembler?)
            ExtendedPropertyUtils.Update(mpps.ExtendedProperties, request.Mpps.ExtendedProperties);

            var dicomSeriesAssembler = new DicomSeriesAssembler();

            dicomSeriesAssembler.SynchronizeDicomSeries(mpps, request.Mpps.DicomSeries, this.PersistenceContext);

            var op = new CompleteModalityPerformedProcedureStepOperation();

            op.Execute(mpps, request.CompletedTime, new PersistentWorkflow(PersistenceContext));

            this.PersistenceContext.SynchState();

            // Drill back to order so we can refresh procedure plan
            var onePs = CollectionUtils.FirstElement(mpps.Activities).As <ProcedureStep>();

            var planAssembler = new ProcedurePlanAssembler();
            var stepAssembler = new ModalityPerformedProcedureStepAssembler();

            return(new CompleteModalityPerformedProcedureStepResponse(
                       planAssembler.CreateProcedurePlanSummary(onePs.Procedure.Order, this.PersistenceContext),
                       stepAssembler.CreateModalityPerformedProcedureStepDetail(mpps, this.PersistenceContext)));
        }
Ejemplo n.º 6
0
        public void UpdateVisit(Visit visit, VisitDetail detail, IPersistenceContext context)
        {
            visit.Patient        = context.Load <Patient>(detail.Patient.PatientRef, EntityLoadFlags.Proxy);
            visit.VisitNumber.Id = detail.VisitNumber.Id;
            visit.VisitNumber.AssigningAuthority = EnumUtils.GetEnumValue <InformationAuthorityEnum>(detail.VisitNumber.AssigningAuthority, context);

            visit.AdmissionType = EnumUtils.GetEnumValue <AdmissionTypeEnum>(detail.AdmissionType, context);
            visit.PatientClass  = EnumUtils.GetEnumValue <PatientClassEnum>(detail.PatientClass, context);
            visit.PatientType   = EnumUtils.GetEnumValue <PatientTypeEnum>(detail.PatientType, context);
            visit.Status        = EnumUtils.GetEnumValue <VisitStatus>(detail.Status);

            visit.AdmitTime            = detail.AdmitTime;
            visit.DischargeTime        = detail.DischargeTime;
            visit.DischargeDisposition = detail.DischargeDisposition;
            visit.VipIndicator         = detail.VipIndicator;

            visit.Facility = detail.Facility == null ? null :
                             context.Load <Facility>(detail.Facility.FacilityRef, EntityLoadFlags.Proxy);
            visit.CurrentLocation = detail.CurrentLocation == null ? null :
                                    context.Load <Location>(detail.CurrentLocation.LocationRef, EntityLoadFlags.Proxy);
            visit.CurrentRoom = detail.CurrentRoom;
            visit.CurrentBed  = detail.CurrentBed;

            visit.Locations.Clear();
            foreach (var vlDetail in detail.Locations)
            {
                visit.Locations.Add(new VisitLocation(
                                        context.Load <Location>(vlDetail.Location.LocationRef, EntityLoadFlags.Proxy),
                                        vlDetail.Room,
                                        vlDetail.Bed,
                                        EnumUtils.GetEnumValue <VisitLocationRole>(vlDetail.Role),
                                        vlDetail.StartTime,
                                        vlDetail.EndTime));
            }

            visit.Practitioners.Clear();
            foreach (var vpDetail in detail.Practitioners)
            {
                visit.Practitioners.Add(new VisitPractitioner(
                                            context.Load <ExternalPractitioner>(vpDetail.Practitioner.PractitionerRef, EntityLoadFlags.Proxy),
                                            EnumUtils.GetEnumValue <VisitPractitionerRole>(vpDetail.Role),
                                            vpDetail.StartTime,
                                            vpDetail.EndTime));
            }

            visit.AmbulatoryStatuses.Clear();
            foreach (var ambulatoryStatus in detail.AmbulatoryStatuses)
            {
                visit.AmbulatoryStatuses.Add(EnumUtils.GetEnumValue <AmbulatoryStatusEnum>(ambulatoryStatus, context));
            }

            ExtendedPropertyUtils.Update(visit.ExtendedProperties, detail.ExtendedProperties);
        }
Ejemplo n.º 7
0
        protected override void Import(StaffData data, IUpdateContext context)
        {
            Staff staff = GetStaff(data.Id, context);

            staff.Deactivated     = data.Deactivated;
            staff.Type            = context.GetBroker <IEnumBroker>().Find <StaffTypeEnum>(data.StaffType);
            staff.Title           = data.Title;
            staff.Name.FamilyName = data.FamilyName;
            staff.Name.GivenName  = data.GivenName;
            staff.Name.MiddleName = data.MiddleName;

            staff.Sex = string.IsNullOrEmpty(data.Sex) == false
                                ? (Sex)Enum.Parse(typeof(Sex), data.Sex)
                                : Sex.U;

            staff.UserName      = data.UserName;
            staff.LicenseNumber = data.LicenseNumber;
            staff.BillingNumber = data.BillingNumber;

            if (data.TelephoneNumbers != null)
            {
                staff.TelephoneNumbers.Clear();
                foreach (TelephoneNumberData phoneDetail in data.TelephoneNumbers)
                {
                    staff.TelephoneNumbers.Add(phoneDetail.CreateTelephoneNumber());
                }
            }

            if (data.Addresses != null)
            {
                staff.Addresses.Clear();
                foreach (AddressData address in data.Addresses)
                {
                    staff.Addresses.Add(address.CreateAddress());
                }
            }

            if (data.EmailAddresses != null)
            {
                staff.EmailAddresses.Clear();
                foreach (EmailAddressData addressDetail in data.EmailAddresses)
                {
                    staff.EmailAddresses.Add(addressDetail.CreateEmailAddress());
                }
            }

            ExtendedPropertyUtils.Update(staff.ExtendedProperties, data.ExtendedProperties);
        }
Ejemplo n.º 8
0
        public void UpdateOrderFromRequisition(Order order, OrderRequisition requisition, Staff currentStaff, IPersistenceContext context)
        {
            // only certain properties of an order may be updated from a requisition
            // Patient cannot not be updated
            // DiagnosticService cannot be updated
            // OrderingFacility cannot be updated

            // do not update the individual procedures, as this is done separately - see UpdateProcedureFromRequisition

            // Some properties cannot be updated if the procedure is terminated
            if (!order.IsTerminated)
            {
                order.Visit = context.Load <Visit>(requisition.Visit.VisitRef, EntityLoadFlags.Proxy);

                order.SchedulingRequestTime = requisition.SchedulingRequestTime;
                order.OrderingPractitioner  = context.Load <ExternalPractitioner>(
                    requisition.OrderingPractitioner.PractitionerRef, EntityLoadFlags.Proxy);
                order.ReasonForStudy = requisition.ReasonForStudy;
                order.Priority       = EnumUtils.GetEnumValue <OrderPriority>(requisition.Priority);

                // wipe out and reset the result recipients
                order.ResultRecipients.Clear();

                CollectionUtils.Map <ResultRecipientDetail, ResultRecipient>(
                    requisition.ResultRecipients,
                    s => new ResultRecipient(
                        context.Load <ExternalPractitionerContactPoint>(s.ContactPoint.ContactPointRef, EntityLoadFlags.Proxy),
                        EnumUtils.GetEnumValue <ResultCommunicationMode>(s.PreferredCommunicationMode))).ForEach(r => order.ResultRecipients.Add(r));
            }

            // synchronize Order.Attachments from order requisition
            var attachmentAssembler = new OrderAttachmentAssembler();

            attachmentAssembler.Synchronize(order.Attachments, requisition.Attachments, currentStaff, context);

            // synchronize Order.Notes from order requisition
            var noteAssembler = new OrderNoteAssembler();

            noteAssembler.SynchronizeOrderNotes(order, requisition.Notes, currentStaff, context);

            if (requisition.ExtendedProperties != null)
            {
                ExtendedPropertyUtils.Update(order.ExtendedProperties, requisition.ExtendedProperties);
            }
        }
		public WorkQueueItemDetail CreateWorkQueueItemDetail(WorkQueueItem workQueueItem, IPersistenceContext context)
		{
			WorkQueueItemDetail detail = new WorkQueueItemDetail();

			detail.WorkQueueItemRef = workQueueItem.GetRef();
			detail.CreationTime = workQueueItem.CreationTime;
			detail.ScheduledTime = workQueueItem.ScheduledTime;
			detail.ExpirationTime = workQueueItem.ExpirationTime;
			detail.User = workQueueItem.User;
			detail.Type = workQueueItem.Type;
			detail.Status = EnumUtils.GetEnumValueInfo(workQueueItem.Status, context);
			detail.ProcessedTime = workQueueItem.ProcessedTime;
			detail.FailureCount = workQueueItem.FailureCount;
			detail.FailureDescription = workQueueItem.FailureDescription;
			detail.ExtendedProperties = ExtendedPropertyUtils.Copy(workQueueItem.ExtendedProperties);

			return detail;
		}
Ejemplo n.º 10
0
        public VisitDetail CreateVisitDetail(Visit visit, IPersistenceContext context)
        {
            var patientProfileAssembler = new PatientProfileAssembler();
            var detail = new VisitDetail
            {
                VisitRef             = visit.GetRef(),
                Patient              = patientProfileAssembler.CreatePatientProfileSummary(visit.PatientProfile, context),
                VisitNumber          = CreateVisitNumberDetail(visit.VisitNumber),
                AdmissionType        = EnumUtils.GetEnumValueInfo(visit.AdmissionType),
                PatientClass         = EnumUtils.GetEnumValueInfo(visit.PatientClass),
                PatientType          = EnumUtils.GetEnumValueInfo(visit.PatientType),
                Status               = EnumUtils.GetEnumValueInfo(visit.Status, context),
                AdmitTime            = visit.AdmitTime,
                DischargeTime        = visit.DischargeTime,
                DischargeDisposition = visit.DischargeDisposition,
                Facility             = new FacilityAssembler().CreateFacilitySummary(visit.Facility),
                CurrentLocation      = visit.CurrentLocation == null ? null : new LocationAssembler().CreateLocationSummary(visit.CurrentLocation),
                CurrentRoom          = visit.CurrentRoom,
                CurrentBed           = visit.CurrentBed,
                Locations            = new List <VisitLocationDetail>(),
                PreadmitNumber       = visit.PreadmitNumber,
                VipIndicator         = visit.VipIndicator,
                ExtendedProperties   = ExtendedPropertyUtils.Copy(visit.ExtendedProperties)
            };

            foreach (var vl in visit.Locations)
            {
                detail.Locations.Add(CreateVisitLocationDetail(vl, context));
            }

            detail.Practitioners = new List <VisitPractitionerDetail>();
            foreach (var vp in visit.Practitioners)
            {
                detail.Practitioners.Add(CreateVisitPractitionerDetail(vp, context));
            }

            detail.AmbulatoryStatuses = new List <EnumValueInfo>();
            foreach (var ambulatoryStatus in visit.AmbulatoryStatuses)
            {
                detail.AmbulatoryStatuses.Add(EnumUtils.GetEnumValueInfo(ambulatoryStatus));
            }

            return(detail);
        }
Ejemplo n.º 11
0
        public OrderRequisition CreateOrderRequisition(Order order, IPersistenceContext context)
        {
            var patientProfileAssembler  = new PatientProfileAssembler();
            var visitAssembler           = new VisitAssembler();
            var pracAssembler            = new ExternalPractitionerAssembler();
            var facilityAssembler        = new FacilityAssembler();
            var dsAssembler              = new DiagnosticServiceAssembler();
            var attachmentAssembler      = new OrderAttachmentAssembler();
            var noteAssembler            = new OrderNoteAssembler();
            var resultRecipientAssembler = new ResultRecipientAssembler();

            var requisition = new OrderRequisition
            {
                OrderRef = order.GetRef(),
                Patient  =
                    patientProfileAssembler.CreatePatientProfileSummary(
                        CollectionUtils.FirstElement(order.Procedures).PatientProfile, context),
                Visit                 = visitAssembler.CreateVisitSummary(order.Visit, context),
                DiagnosticService     = dsAssembler.CreateSummary(order.DiagnosticService),
                SchedulingRequestTime = order.SchedulingRequestTime,
                OrderingPractitioner  =
                    pracAssembler.CreateExternalPractitionerSummary(order.OrderingPractitioner, context),
                OrderingFacility = facilityAssembler.CreateFacilitySummary(order.OrderingFacility),
                ReasonForStudy   = order.ReasonForStudy,
                Priority         = EnumUtils.GetEnumValueInfo(order.Priority, context),
                ResultRecipients = CollectionUtils.Map <ResultRecipient, ResultRecipientDetail>(
                    order.ResultRecipients,
                    r => resultRecipientAssembler.CreateResultRecipientDetail(r, context)),
                Procedures = CollectionUtils.Map <Procedure, ProcedureRequisition>(
                    order.Procedures,
                    procedure => CreateProcedureRequisition(procedure, context)),
                Attachments = CollectionUtils.Map <OrderAttachment, AttachmentSummary>(
                    order.Attachments,
                    attachment => attachmentAssembler.CreateOrderAttachmentSummary(attachment, context)),
                Notes = CollectionUtils.Map <OrderNote, OrderNoteDetail>(
                    OrderNote.GetNotesForOrder(order),
                    note => noteAssembler.CreateOrderNoteDetail(note, context)),
                ExtendedProperties = ExtendedPropertyUtils.Copy(order.ExtendedProperties),
                CanModify          = !order.IsTerminated
            };

            return(requisition);
        }
        public SaveOrderDocumentationDataResponse SaveOrderDocumentationData(SaveOrderDocumentationDataRequest request)
        {
            var order = this.PersistenceContext.Load <Order>(request.OrderRef);

            ExtendedPropertyUtils.Update(order.ExtendedProperties, request.OrderExtendedProperties);

            var dicomSeriesAssembler = new DicomSeriesAssembler();

            foreach (var detail in request.ModalityPerformedProcedureSteps)
            {
                var mpps = this.PersistenceContext.Load <ModalityPerformedProcedureStep>(detail.ModalityPerformendProcedureStepRef);
                ExtendedPropertyUtils.Update(mpps.ExtendedProperties, detail.ExtendedProperties);
                dicomSeriesAssembler.SynchronizeDicomSeries(mpps, detail.DicomSeries, this.PersistenceContext);
            }

            // add new order notes
            var noteAssembler = new OrderNoteAssembler();

            noteAssembler.SynchronizeOrderNotes(order, request.OrderNotes, CurrentUserStaff, this.PersistenceContext);

            // assign all procedures for this order to the specified interpreter (or unassign them, if null)
            var interpreter = request.AssignedInterpreter == null
                                ? null
                                : this.PersistenceContext.Load <Staff>(request.AssignedInterpreter.StaffRef, EntityLoadFlags.Proxy);

            foreach (var procedure in order.Procedures)
            {
                if (procedure.IsPerformed)
                {
                    var interpretationStep = GetPendingInterpretationStep(procedure);
                    if (interpretationStep != null)
                    {
                        interpretationStep.Assign(interpreter);
                    }
                }
            }

            this.PersistenceContext.SynchState();

            var planAssembler = new ProcedurePlanAssembler();

            return(new SaveOrderDocumentationDataResponse(planAssembler.CreateProcedurePlanSummary(order, this.PersistenceContext)));
        }
        public LoadOrderDocumentationDataResponse LoadOrderDocumentationData(LoadOrderDocumentationDataRequest request)
        {
            Platform.CheckForNullReference(request, "request");
            Platform.CheckMemberIsSet(request.OrderRef, "OrderRef");

            var order = this.PersistenceContext.Load <Order>(request.OrderRef);

            var noteAssembler = new OrderNoteAssembler();

            return(new LoadOrderDocumentationDataResponse
            {
                OrderRef = order.GetRef(),
                OrderExtendedProperties = ExtendedPropertyUtils.Copy(order.ExtendedProperties),
                OrderNotes = CollectionUtils.Map <OrderNote, OrderNoteDetail>(
                    OrderNote.GetNotesForOrder(order),
                    note => noteAssembler.CreateOrderNoteDetail(note, PersistenceContext)),
                AssignedInterpreter = GetUniqueAssignedInterpreter(order)
            });
        }
        protected override void Import(ExternalPractitionerData data, IUpdateContext context)
        {
            var prac = LoadExternalPractitioner(
                data.LicenseNumber,
                data.BillingNumber,
                context);

            var name = new PersonName(data.FamilyName, data.GivenName, data.MiddleName, null, null, null);

            if (prac == null)
            {
                // Creating a new practitioenr:  Import
                prac = new ExternalPractitioner(name,
                                                data.LicenseNumber,
                                                data.BillingNumber,
                                                data.IsVerified,
                                                data.LastVerifiedTime,
                                                data.LastEditedTime,
                                                new HashedSet <ExternalPractitionerContactPoint>(),
                                                new Dictionary <string, string>(),
                                                null);
                context.Lock(prac, DirtyState.New);
            }
            else
            {
                prac.Name = name;
                prac.MarkEdited();
            }

            prac.MarkDeactivated(data.Deactivated);

            if (data.ContactPoints != null)
            {
                foreach (var cpData in data.ContactPoints)
                {
                    var cp = CollectionUtils.SelectFirst(prac.ContactPoints, p => p.Name == cpData.Name) ?? new ExternalPractitionerContactPoint(prac);
                    UpdateExternalPractitionerContactPoint(cpData, cp, context);
                }
            }

            ExtendedPropertyUtils.Update(prac.ExtendedProperties, data.ExtendedProperties);
        }
        public ExternalPractitionerDetail CreateExternalPractitionerDetail(ExternalPractitioner prac, IPersistenceContext context)
        {
            var assembler = new PersonNameAssembler();

            var sortedContactPoints = CollectionUtils.Sort(prac.ContactPoints, (x, y) =>
            {
                if (ReferenceEquals(x, y))
                {
                    return(0);
                }
                if (x.IsDefaultContactPoint)
                {
                    return(-1);
                }
                if (y.IsDefaultContactPoint)
                {
                    return(1);
                }
                return(string.Compare(x.Name, y.Name));
            });

            var contactPointDetails = CollectionUtils.Map(
                sortedContactPoints,
                (ExternalPractitionerContactPoint cp) => CreateExternalPractitionerContactPointDetail(cp, context));

            var detail = new ExternalPractitionerDetail(
                prac.GetRef(),
                assembler.CreatePersonNameDetail(prac.Name),
                prac.LicenseNumber,
                prac.BillingNumber,
                prac.IsVerified,
                prac.LastVerifiedTime,
                prac.LastEditedTime,
                contactPointDetails,
                ExtendedPropertyUtils.Copy(prac.ExtendedProperties),
                CreateExternalPractitionerSummary(prac.GetUltimateMergeDestination(), context),
                prac.IsMerged,
                prac.Deactivated);

            return(detail);
        }
        public void UpdateExternalPractitioner(ExternalPractitionerDetail detail, ExternalPractitioner prac, IPersistenceContext context)
        {
            // validate that only one contact point is specified as default
            var defaultPoints = CollectionUtils.Select(detail.ContactPoints, cp => cp.IsDefaultContactPoint);

            if (defaultPoints.Count > 1)
            {
                throw new RequestValidationException(SR.ExceptionOneDefaultContactPoint);
            }

            var assembler = new PersonNameAssembler();

            assembler.UpdatePersonName(detail.Name, prac.Name);

            prac.LicenseNumber = detail.LicenseNumber;
            prac.BillingNumber = detail.BillingNumber;
            prac.MarkDeactivated(detail.Deactivated);

            // update contact points collection
            var syncHelper = new CollectionSynchronizeHelper <ExternalPractitionerContactPoint, ExternalPractitionerContactPointDetail>(
                delegate(ExternalPractitionerContactPoint cp, ExternalPractitionerContactPointDetail cpDetail)
            {
                // ignore version in this comparison - deal with this issue in the update delegate
                return(cp.GetRef().Equals(cpDetail.ContactPointRef, true));
            },
                delegate(ExternalPractitionerContactPointDetail cpDetail, ICollection <ExternalPractitionerContactPoint> cps)
            {
                // create a new contact point
                var cp = new ExternalPractitionerContactPoint(prac);
                UpdateExternalPractitionerContactPoint(cpDetail, cp, context);
                cps.Add(cp);
            },
                (cp, cpDetail, cps) => UpdateExternalPractitionerContactPoint(cpDetail, cp, context),
                (cp, cps) => cps.Remove(cp));

            syncHelper.Synchronize(prac.ContactPoints, detail.ContactPoints);

            ExtendedPropertyUtils.Update(prac.ExtendedProperties, detail.ExtendedProperties);
        }
Ejemplo n.º 17
0
        public ReportPartDetail CreateReportPartDetail(ReportPart reportPart, IPersistenceContext context)
        {
            StaffAssembler   staffAssembler = new StaffAssembler();
            ReportPartDetail summary        = new ReportPartDetail(
                reportPart.GetRef(),
                reportPart.Index,
                reportPart.Index > 0,
                EnumUtils.GetEnumValueInfo(reportPart.Status, context),
                reportPart.CreationTime,
                reportPart.PreliminaryTime,
                reportPart.CompletedTime,
                reportPart.CancelledTime,
                reportPart.Supervisor == null ? null : staffAssembler.CreateStaffSummary(reportPart.Supervisor, context),
                reportPart.Interpreter == null ? null : staffAssembler.CreateStaffSummary(reportPart.Interpreter, context),
                reportPart.Transcriber == null ? null : staffAssembler.CreateStaffSummary(reportPart.Transcriber, context),
                reportPart.TranscriptionSupervisor == null ? null : staffAssembler.CreateStaffSummary(reportPart.TranscriptionSupervisor, context),
                reportPart.Verifier == null ? null : staffAssembler.CreateStaffSummary(reportPart.Verifier, context),
                EnumUtils.GetEnumValueInfo(reportPart.TranscriptionRejectReason),
                ExtendedPropertyUtils.Copy(reportPart.ExtendedProperties));

            return(summary);
        }
        public DiscontinueModalityPerformedProcedureStepResponse DiscontinueModalityPerformedProcedureStep(DiscontinueModalityPerformedProcedureStepRequest request)
        {
            var mpps = this.PersistenceContext.Load <ModalityPerformedProcedureStep>(request.Mpps.ModalityPerformendProcedureStepRef);

            // update extended properties (should this be in an assembler?)
            ExtendedPropertyUtils.Update(mpps.ExtendedProperties, request.Mpps.ExtendedProperties);

            var dicomSeriesAssembler = new DicomSeriesAssembler();

            dicomSeriesAssembler.SynchronizeDicomSeries(mpps, request.Mpps.DicomSeries, this.PersistenceContext);

            var op = new DiscontinueModalityPerformedProcedureStepOperation();

            op.Execute(mpps, request.DiscontinuedTime, new PersistentWorkflow(PersistenceContext));

            this.PersistenceContext.SynchState();

            // If discontinuing the MPPS caused any associated procedures to be discontinued,
            // create an HL7 event.
            foreach (var activity in mpps.Activities)
            {
                var procedure = activity.As <ProcedureStep>().Procedure;
                if (procedure.IsTerminated)
                {
                    LogicalHL7Event.ProcedureCancelled.EnqueueEvents(procedure);
                }
            }

            // Drill back to order so we can refresh procedure plan
            var order = CollectionUtils.FirstElement(mpps.Activities).As <ProcedureStep>().Procedure.Order;

            var planAssembler = new ProcedurePlanAssembler();
            var stepAssembler = new ModalityPerformedProcedureStepAssembler();

            return(new DiscontinueModalityPerformedProcedureStepResponse(
                       planAssembler.CreateProcedurePlanSummary(order, this.PersistenceContext),
                       stepAssembler.CreateModalityPerformedProcedureStepDetail(mpps, this.PersistenceContext)));
        }
Ejemplo n.º 19
0
        public virtual void CopyFrom(Visit v)
        {
            this.VisitNumber.Id = v.VisitNumber.Id;
            this.VisitNumber.AssigningAuthority = v.VisitNumber.AssigningAuthority;
            this.Status               = v.Status;
            this.AdmitTime            = v.AdmitTime;
            this.PatientClass         = v.PatientClass;
            this.PatientType          = v.PatientType;
            this.AdmissionType        = v.AdmissionType;
            this.Facility             = v.Facility;
            this.DischargeTime        = v.DischargeTime;
            this.DischargeDisposition = v.DischargeDisposition;
            this.VipIndicator         = v.VipIndicator;
            //this.AmbulatoryStatus = v.AmbulatoryStatus;
            this.PreadmitNumber = v.PreadmitNumber;

            foreach (AmbulatoryStatusEnum a in v.AmbulatoryStatuses)
            {
                this.AmbulatoryStatuses.Add(a);
            }

            foreach (VisitPractitioner vp in v.Practitioners)
            {
                VisitPractitioner practitioner = new VisitPractitioner();
                practitioner.CopyFrom(vp);
                this.Practitioners.Add(practitioner);
            }

            foreach (VisitLocation vl in v.Locations)
            {
                VisitLocation location = new VisitLocation();
                location.CopyFrom(vl);
                this.Locations.Add(location);
            }

            ExtendedPropertyUtils.Update(this.ExtendedProperties, v.ExtendedProperties);
        }
Ejemplo n.º 20
0
        private Order PlaceOrderHelper(OrderRequisition requisition)
        {
            // get appropriate A# for this order
            var accNum = GetAccessionNumberForOrder(requisition);

            var patient           = this.PersistenceContext.Load <Patient>(requisition.Patient.PatientRef, EntityLoadFlags.Proxy);
            var orderingFacility  = this.PersistenceContext.Load <Facility>(requisition.OrderingFacility.FacilityRef, EntityLoadFlags.Proxy);
            var visit             = FindOrCreateVisit(requisition, patient, orderingFacility, accNum);
            var orderingPhysician = this.PersistenceContext.Load <ExternalPractitioner>(requisition.OrderingPractitioner.PractitionerRef, EntityLoadFlags.Proxy);
            var diagnosticService = this.PersistenceContext.Load <DiagnosticService>(requisition.DiagnosticService.DiagnosticServiceRef);
            var priority          = EnumUtils.GetEnumValue <OrderPriority>(requisition.Priority);


            var resultRecipients = CollectionUtils.Map(
                requisition.ResultRecipients ?? new List <ResultRecipientDetail>(),
                (ResultRecipientDetail s) => new ResultRecipient(
                    this.PersistenceContext.Load <ExternalPractitionerContactPoint>(s.ContactPoint.ContactPointRef, EntityLoadFlags.Proxy),
                    EnumUtils.GetEnumValue <ResultCommunicationMode>(s.PreferredCommunicationMode)));

            // generate set of procedures
            // create a temp map from procedure back to its requisition, this will be needed later
            var orderAssembler        = new OrderEntryAssembler();
            var mapProcToReq          = new Dictionary <Procedure, ProcedureRequisition>();
            var procedureNumberBroker = PersistenceContext.GetBroker <IProcedureNumberBroker>();
            var dicomUidBroker        = PersistenceContext.GetBroker <IDicomUidBroker>();
            var procedures            = CollectionUtils.Map(
                requisition.Procedures ?? new List <ProcedureRequisition>(),
                delegate(ProcedureRequisition req)
            {
                var rpt = this.PersistenceContext.Load <ProcedureType>(req.ProcedureType.ProcedureTypeRef);
                var rp  = new Procedure(rpt, procedureNumberBroker.GetNext(), dicomUidBroker.GetNewUid());
                mapProcToReq.Add(rp, req);

                // important to set this flag prior to creating the procedure steps, because it may affect
                // which procedure steps are created
                rp.DowntimeRecoveryMode = requisition.IsDowntimeOrder;
                return(rp);
            });


            // generate a new order with the default set of procedures
            var order = Order.NewOrder(
                new OrderCreationArgs(
                    Platform.Time,
                    this.CurrentUserStaff,
                    null,
                    accNum,
                    patient,
                    visit,
                    diagnosticService,
                    requisition.ReasonForStudy,
                    priority,
                    orderingFacility,
                    requisition.SchedulingRequestTime,
                    orderingPhysician,
                    resultRecipients,
                    procedures),
                procedureNumberBroker,
                dicomUidBroker);

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

            // create procedure steps and update from requisition
            foreach (var procedure in order.Procedures)
            {
                procedure.CreateProcedureSteps();
                if (mapProcToReq.ContainsKey(procedure))
                {
                    orderAssembler.UpdateProcedureFromRequisition(procedure, mapProcToReq[procedure], this.CurrentUserStaff, this.PersistenceContext);
                }
            }

            // add order notes
            if (requisition.Notes != null)
            {
                var noteAssembler = new OrderNoteAssembler();
                noteAssembler.SynchronizeOrderNotes(order, requisition.Notes, this.CurrentUserStaff, this.PersistenceContext);
            }

            // add attachments
            if (requisition.Attachments != null)
            {
                var attachmentAssembler = new OrderAttachmentAssembler();
                attachmentAssembler.Synchronize(order.Attachments, requisition.Attachments, this.CurrentUserStaff, this.PersistenceContext);
            }

            if (requisition.ExtendedProperties != null)
            {
                ExtendedPropertyUtils.Update(order.ExtendedProperties, requisition.ExtendedProperties);
            }

            return(order);
        }
 public void Execute(TranscriptionStep step, Dictionary <string, string> reportPartExtendedProperties)
 {
     ExtendedPropertyUtils.Update(step.ReportPart.ExtendedProperties, reportPartExtendedProperties);
 }
Ejemplo n.º 22
0
        public void UpdateStaff(StaffDetail detail, Staff staff, bool updateElectiveGroups, bool updateNonElectiveGroups, IPersistenceContext context)
        {
            PersonNameAssembler      assembler          = new PersonNameAssembler();
            EmailAddressAssembler    emailAssembler     = new EmailAddressAssembler();
            TelephoneNumberAssembler telephoneAssembler = new TelephoneNumberAssembler();
            AddressAssembler         addressAssembler   = new AddressAssembler();

            staff.Id   = detail.StaffId;
            staff.Type = EnumUtils.GetEnumValue <StaffTypeEnum>(detail.StaffType, context);
            assembler.UpdatePersonName(detail.Name, staff.Name);
            staff.Sex           = EnumUtils.GetEnumValue <Sex>(detail.Sex);
            staff.Title         = detail.Title;
            staff.LicenseNumber = detail.LicenseNumber;
            staff.BillingNumber = detail.BillingNumber;
            staff.Deactivated   = detail.Deactivated;
            staff.UserName      = detail.UserName;

            staff.TelephoneNumbers.Clear();
            if (detail.TelephoneNumbers != null)
            {
                foreach (TelephoneDetail phoneDetail in detail.TelephoneNumbers)
                {
                    staff.TelephoneNumbers.Add(telephoneAssembler.CreateTelephoneNumber(phoneDetail));
                }
            }

            staff.Addresses.Clear();
            if (detail.Addresses != null)
            {
                foreach (AddressDetail addressDetail in detail.Addresses)
                {
                    staff.Addresses.Add(addressAssembler.CreateAddress(addressDetail));
                }
            }

            staff.EmailAddresses.Clear();
            if (detail.EmailAddresses != null)
            {
                foreach (EmailAddressDetail emailAddressDetail in detail.EmailAddresses)
                {
                    staff.EmailAddresses.Add(emailAssembler.CreateEmailAddress(emailAddressDetail));
                }
            }

            ExtendedPropertyUtils.Update(staff.ExtendedProperties, detail.ExtendedProperties);

            if (updateElectiveGroups)
            {
                // update elective groups
                UpdateStaffGroups(detail, staff,
                                  delegate(StaffGroupSummary summary) { return(summary.IsElective); },
                                  delegate(StaffGroup group) { return(group.Elective); },
                                  context);
            }

            if (updateNonElectiveGroups)
            {
                // update non-elective groups
                UpdateStaffGroups(detail, staff,
                                  delegate(StaffGroupSummary summary) { return(!summary.IsElective); },
                                  delegate(StaffGroup group) { return(!group.Elective); },
                                  context);
            }
        }
Ejemplo n.º 23
0
        /// <summary>
        /// Creates order detail document including only specified parts.
        /// </summary>
        public OrderDetail CreateOrderDetail(Order order, CreateOrderDetailOptions options, IPersistenceContext context)
        {
            var orderDetail = new OrderDetail();

            var practitionerAssembler = new ExternalPractitionerAssembler();
            var facilityAssembler     = new FacilityAssembler();
            var dsAssembler           = new DiagnosticServiceAssembler();
            var procedureAssembler    = new ProcedureAssembler();
            var staffAssembler        = new StaffAssembler();

            orderDetail.OrderRef   = order.GetRef();
            orderDetail.PatientRef = order.Patient.GetRef();

            if (options.IncludeVisit)
            {
                var visitAssembler = new VisitAssembler();
                orderDetail.Visit = visitAssembler.CreateVisitDetail(order.Visit, context);
            }

            orderDetail.PlacerNumber      = order.PlacerNumber;
            orderDetail.AccessionNumber   = order.AccessionNumber;
            orderDetail.DiagnosticService = dsAssembler.CreateSummary(order.DiagnosticService);

            orderDetail.EnteredTime = order.EnteredTime;
            orderDetail.EnteredBy   = order.EnteredBy == null ? null :
                                      staffAssembler.CreateStaffSummary(order.EnteredBy, context);
            orderDetail.EnteredComment = order.EnteredComment;

            orderDetail.SchedulingRequestTime = order.SchedulingRequestTime;
            orderDetail.OrderingPractitioner  = practitionerAssembler.CreateExternalPractitionerSummary(order.OrderingPractitioner, context);
            orderDetail.OrderingFacility      = facilityAssembler.CreateFacilitySummary(order.OrderingFacility);
            orderDetail.ReasonForStudy        = order.ReasonForStudy;
            orderDetail.OrderPriority         = EnumUtils.GetEnumValueInfo(order.Priority, context);

            if (order.CancelInfo != null)
            {
                orderDetail.CancelReason = order.CancelInfo.Reason == null ? null : EnumUtils.GetEnumValueInfo(order.CancelInfo.Reason);
                orderDetail.CancelledBy  = order.CancelInfo.CancelledBy == null ? null :
                                           staffAssembler.CreateStaffSummary(order.CancelInfo.CancelledBy, context);
                orderDetail.CancelComment = order.CancelInfo.Comment;
            }

            if (options.IncludeProcedures)
            {
                orderDetail.Procedures = CollectionUtils.Map(order.Procedures,
                                                             (Procedure p) => procedureAssembler.CreateProcedureDetail(p, context));
            }

            if (options.IncludeNotes)
            {
                var orderNoteAssembler = new OrderNoteAssembler();
                var orderNotes         = new List <OrderNote>(OrderNote.GetNotesForOrder(order, options.NoteCategoriesFilter, options.IncludeVirtualNotes));

                // sort notes by post-time (guaranteed non-null because only "posted" notes are in this collection)
                orderNotes.Sort((x, y) => x.PostTime.Value.CompareTo(y.PostTime.Value));

                // Put most recent notes first
                orderNotes.Reverse();

                orderDetail.Notes = CollectionUtils.Map <OrderNote, OrderNoteSummary>(
                    orderNotes,
                    note => orderNoteAssembler.CreateOrderNoteSummary(note, context));
            }

            if (options.IncludeAttachments)
            {
                var orderAttachmentAssembler = new OrderAttachmentAssembler();
                var attachments = new List <OrderAttachment>(order.Attachments);

                orderDetail.Attachments = CollectionUtils.Map <OrderAttachment, AttachmentSummary>(
                    attachments,
                    a => orderAttachmentAssembler.CreateOrderAttachmentSummary(a, context));
            }

            if (options.IncludeResultRecipients)
            {
                var resultRecipientAssembler = new ResultRecipientAssembler();
                var resultRecipients         = new List <ResultRecipient>(order.ResultRecipients);

                orderDetail.ResultRecipients = CollectionUtils.Map <ResultRecipient, ResultRecipientDetail>(
                    resultRecipients,
                    r => resultRecipientAssembler.CreateResultRecipientDetail(r, context));
            }

            if (options.IncludeExtendedProperties)
            {
                orderDetail.ExtendedProperties = ExtendedPropertyUtils.Copy(order.ExtendedProperties);
            }

            return(orderDetail);
        }
Ejemplo n.º 24
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
            });
        }
        /// <summary>
        /// Creates a new practitioner that is the result of merging the two specified practitioners.
        /// </summary>
        /// <param name="right"></param>
        /// <param name="left"></param>
        /// <param name="name"></param>
        /// <param name="licenseNumber"></param>
        /// <param name="billingNumber"></param>
        /// <param name="extendedProperties"></param>
        /// <param name="defaultContactPoint"></param>
        /// <param name="deactivatedContactPoints"></param>
        /// <param name="contactPointReplacements"></param>
        /// <returns></returns>
        public static ExternalPractitioner MergePractitioners(
            ExternalPractitioner right,
            ExternalPractitioner left,
            PersonName name,
            string licenseNumber,
            string billingNumber,
            IDictionary <string, string> extendedProperties,
            ExternalPractitionerContactPoint defaultContactPoint,
            ICollection <ExternalPractitionerContactPoint> deactivatedContactPoints,
            IDictionary <ExternalPractitionerContactPoint, ExternalPractitionerContactPoint> contactPointReplacements)
        {
            // sanity check
            if (Equals(right, left))
            {
                throw new WorkflowException("Cannot merge a practitioner with itself.");
            }
            if (right.Deactivated || left.Deactivated)
            {
                throw new WorkflowException("Cannot merge a practitioner that is de-activated.");
            }
            if (right.IsMerged || left.IsMerged)
            {
                throw new WorkflowException("Cannot merge a practitioner that has already been merged.");
            }
            if (defaultContactPoint != null && defaultContactPoint.IsMerged)
            {
                throw new WorkflowException("Cannot assigned a merged contact point as default");
            }

            // update properties on result record
            var result = new ExternalPractitioner {
                Name = name, LicenseNumber = licenseNumber, BillingNumber = billingNumber
            };

            ExtendedPropertyUtils.Update(result.ExtendedProperties, extendedProperties);

            // construct the set of retained contact points
            var retainedContactPoints = new HashedSet <ExternalPractitionerContactPoint>();

            retainedContactPoints.AddAll(contactPointReplacements.Values);

            // some of the replacement contact points are merged.  This should not be allowed.
            if (CollectionUtils.Contains(contactPointReplacements.Values, cp => cp.IsMerged))
            {
                throw new WorkflowException("Cannot replace a contact point with another that has already been merged.");
            }

            // add any existing contact point that was not in the replacement list (because it is implicitly being retained)
            foreach (var contactPoint in CollectionUtils.Concat(right.ContactPoints, left.ContactPoints))
            {
                // No need to retain a merged contact point.  Because its replacement would already be retained.
                if (!contactPointReplacements.ContainsKey(contactPoint) && !contactPoint.IsMerged)
                {
                    retainedContactPoints.Add(contactPoint);
                }
            }

            // for all retained contact points, create a copy attached to the result practitioner,
            // and mark the original as having been merged into the copy
            foreach (var original in retainedContactPoints)
            {
                var copy = original.CreateCopy(result);
                result.ContactPoints.Add(copy);

                copy.IsDefaultContactPoint = original.Equals(defaultContactPoint);
                copy.MarkDeactivated(original.Deactivated || deactivatedContactPoints.Contains(original));
                original.SetMergedInto(copy);
            }

            // for all replaced contact points, mark the original as being merged into the
            // copy of the replacement
            foreach (var kvp in contactPointReplacements)
            {
                kvp.Key.SetMergedInto(kvp.Value.MergedInto);
            }

            // mark both left and right as edited and merged
            foreach (var practitioner in new[] { right, left })
            {
                practitioner.MarkEdited();
                practitioner.SetMergedInto(result);
            }

            // mark the result as being edited
            result.MarkEdited();
            return(result);
        }