# Class ObservationService

Namespace
  adas_core.Application.Services

Assembly
  adas-core.Application.dll

Provides the concrete implementation of the IObservationService contract, encapsulating the business logic required to manage and expose observation-related operations.

    public class ObservationService : IObservationService, IApiRequestService

Inheritance
  object
  ObservationService

Implements
  IObservationService
  IApiRequestService

Inherited Members
  object.Equals(object)
  object.Equals(object, object)
  object.GetHashCode()
  object.GetType()
  object.MemberwiseClone()
  object.ReferenceEquals(object, object)
  object.ToString()

Extension Methods
  NumberUtils.IsNumber(object)
  NumberUtils.ToDouble(object)
  ObjectUtils.ToStr(object?)

## Constructors

### ObservationService(IPatientService, IConfigObservationService, IObservationRepository, IObservationArchiveRepository, IConfigUnitsService, IDiagnosisService, IOptions<ApiSettings>, IOptions<CacheSettings>, ILightBeaconService, IRelayService, IRecordingService, ILogger<ObservationService>, IGroupedObservationService, IAlarmService, IClientMessageService, ISubscribersService, ISubscriberGroupedService, Lazy<ICalculatedObservationsService>, IHttpContextAccessor, ILocalAuditService, IPointOfCareService, ICacheService)

    public ObservationService(IPatientService patientService, IConfigObservationService configObservationService, IObservationRepository observationRepository, IObservationArchiveRepository observationArchiveRepository, IConfigUnitsService configUnitsService, IDiagnosisService diagnosisService, IOptions<ApiSettings> apiSettings, IOptions<CacheSettings> cacheSettings, ILightBeaconService lightBeaconService, IRelayService relayService, IRecordingService recordingService, ILogger<ObservationService> logger, IGroupedObservationService groupedObservationService, IAlarmService alarmService, IClientMessageService clientMessageService, ISubscribersService subscribersService, ISubscriberGroupedService subscriberGroupedService, Lazy<ICalculatedObservationsService> calculatedObservationsService, IHttpContextAccessor httpContextAccessor, ILocalAuditService auditService, IPointOfCareService pointOfCareService, ICacheService cacheService)

#### Parameters

`patientService` IPatientService
`configObservationService` IConfigObservationService
`observationRepository` IObservationRepository
`observationArchiveRepository` IObservationArchiveRepository
`configUnitsService` IConfigUnitsService
`diagnosisService` IDiagnosisService
`apiSettings` IOptions<ApiSettings>
`cacheSettings` IOptions<CacheSettings>
`lightBeaconService` ILightBeaconService
`relayService` IRelayService
`recordingService` IRecordingService
`logger` ILogger<ObservationService>
`groupedObservationService` IGroupedObservationService
`alarmService` IAlarmService
`clientMessageService` IClientMessageService
`subscribersService` ISubscribersService
`subscriberGroupedService` ISubscriberGroupedService
`calculatedObservationsService` Lazy<ICalculatedObservationsService>
`httpContextAccessor` IHttpContextAccessor
`auditService` ILocalAuditService
`pointOfCareService` IPointOfCareService
`cacheService` ICacheService

## Methods

### Archive(Patient)

Archives the specified patient by delegating to the archive operation keyed by the patient's identifier.

    public Task Archive(Patient patient)

#### Parameters

`patient` Patient

  The patient to be archived. Its identifier is used to locate and archive the corresponding record.

#### Returns

Task

### Archive(PatientObservation)

Archives a patient observation by persisting it to the archive repository, removing it from the active observations, and invalidating the related cache entries for the patient's latest observations.

    public Task Archive(PatientObservation observation)

#### Parameters

`observation` PatientObservation

  The patient observation to be archived.

#### Returns

Task

### ArchiveByPatientId(ObjectId)

Archives all observations associated with the specified patient by copying them into the archive repository with newly generated identifiers, then removes the originals and invalidates the related cache entries.

    public Task ArchiveByPatientId(ObjectId id)

#### Parameters

`id` ObjectId

  The unique identifier of the patient whose observations should be archived.

#### Returns

Task

### CheckAndExpireObservations()

Retrieve all observations with expire time from configObservation service Check all of this observations in patient_observations and expire them if (obs.time + config.expires) smaller than current time mark as expired in bd.

    public Task CheckAndExpireObservations()

#### Returns

Task

### DeleteByPatientId(ObjectId)

Deletes all observations associated with the specified patient identifier, clears the related cache entries, and records an audit log. If no observations exist for the given patient, the method returns without performing any deletion, cache invalidation, or audit logging. Any exception encountered during the process is logged and swallowed without being rethrown.

    public Task DeleteByPatientId(ObjectId id)

#### Parameters

`id` ObjectId

  The unique identifier of the patient whose observations should be deleted.

#### Returns

Task

### ExpireAlertsAndPowerOffAsync()

Asynchronously processes alert expiration and powers off beacon LEDs for points of care that are not currently in use. Skips patients located in virtual/moved/deleted/pushed/unknown locations and ignores emulated beacons and configurations with disabled alarms.

    public Task ExpireAlertsAndPowerOffAsync()

#### Returns

Task

### ExpireObservations()

Retrieves all observation configurations and expires those whose `Expires` value is set to a positive number, ignoring configurations with a null or non-positive expiry.

    public Task ExpireObservations()

#### Returns

Task

### ExpireObservationsAndRecalculateAsync()

Expires patient observations that should no longer be active and recalculates the latest observation values per configured field. Sets a global flag while running to signal that expiration is in progress, processes expirations in batches of 1000 to limit memory usage, and clears the patient observations cache once finished; any error is logged and swallowed without rethrowing.

    public Task ExpireObservationsAndRecalculateAsync()

#### Returns

Task

### FindAllAfterDate(ObjectId, DateTime, List<string>?)

Retrieves all patient observations recorded after the specified date, optionally filtered by a list of observation types.

    public Task<List<PatientObservation>> FindAllAfterDate(ObjectId patientId, DateTime date, List<string>? filterObservations = null)

#### Parameters

`patientId` ObjectId

  The unique identifier of the patient whose observations are being retrieved.

`date` DateTime

  The cutoff date; only observations recorded after this date will be returned.

`filterObservations` List<string>

  An optional list of observation identifiers used to narrow the returned results.

#### Returns

Task<List<PatientObservation>>

  A task that represents the asynchronous operation, containing a list of patient observations matching the criteria.

#### Exceptions

NotImplementedException

  Thrown when the method is invoked, as the implementation has not yet been provided.

### FindAllBeforeDate(ObjectId, DateTime, List<string>?)

Retrieves all patient observations recorded before the specified date by delegating to the observation repository.

    public Task<List<PatientObservation>> FindAllBeforeDate(ObjectId patientId, DateTime date, List<string>? filterObservations = null)

#### Parameters

`patientId` ObjectId

  The unique identifier of the patient whose observations are being queried.

`date` DateTime

  The cutoff date; observations recorded before this date will be returned.

`filterObservations` List<string>

  An optional list of observation identifiers to filter the results.

#### Returns

Task<List<PatientObservation>>

  A task representing the asynchronous operation, containing a list of PatientObservation entries found before the specified date.

### FindAllBetweenDates(ObjectId, DateTime?, DateTime?, List<string>?, bool, PaginationFilter?)

Retrieves a paginated list of patient observations for a specific patient within an optional date range, optionally filtering by observation names and supporting both active and archived collections.

    public Task<List<PatientObservation>> FindAllBetweenDates(ObjectId patientId, DateTime? startDate = null, DateTime? endDate = null, List<string>? filterObservations = null, bool fromArchived = false, PaginationFilter? filter = null)

#### Parameters

`patientId` ObjectId

  The unique identifier of the patient whose observations are being queried.

`startDate` DateTime?

  The inclusive lower bound of the observation time range. Falls back to MinValue when null.

`endDate` DateTime?

  The exclusive upper bound of the observation time range. Falls back to MaxValue when null.

`filterObservations` List<string>

  Optional list of observation names to restrict the results to. When null or empty, no name-based filter is applied.

`fromArchived` bool

  When true, queries the archived observation collection; otherwise, queries the active observation collection.

`filter` PaginationFilter

  Optional pagination settings controlling the page number and page size of the returned results.

#### Returns

Task<List<PatientObservation>>

  A task that resolves to the list of PatientObservation records matching the specified criteria.

### FindAllLastPatientObservationTime()

Retrieves the most recent observation time for all patients by delegating to the observation repository.

    public Task<Dictionary<ObjectId, DateTime>> FindAllLastPatientObservationTime()

#### Returns

Task<Dictionary<ObjectId, DateTime>>

  A task that represents the asynchronous operation, containing a dictionary mapping patient MongoDB.Bson.ObjectId values to their last observation DateTime.

### FindAnyWithSameDate(ObjectId, DateTime, string?)

Asynchronously retrieves any patient observations matching the specified patient, date, and optional observation name by delegating to the underlying observation repository. Returns null when no matching observations are found for the given criteria.

    public Task<List<PatientObservation>?> FindAnyWithSameDate(ObjectId patientId, DateTime date, string? obsName)

#### Parameters

`patientId` ObjectId

  The unique identifier of the patient whose observations are being queried.

`date` DateTime

  The date used to find observations recorded on the same day.

`obsName` string

  The optional name of the observation to filter by; when null, observations of any name on the given date are considered.

#### Returns

Task<List<PatientObservation>>

  A task that resolves to a list of matching PatientObservation instances, or null if no observations match the specified criteria.

### FindByPatientIdAndCodingSystemAsync(ObjectId, string, string)

Asynchronously retrieves patient observations filtered by the specified patient identifier, coding system, and name.

    public Task<IAsyncCursor<PatientObservation>> FindByPatientIdAndCodingSystemAsync(ObjectId patientId, string codingSystem, string name)

#### Parameters

`patientId` ObjectId

  The unique identifier of the patient whose observations are being queried.

`codingSystem` string

  The coding system used to classify the observations.

`name` string

  The name associated with the observations to filter by.

#### Returns

Task<IAsyncCursor<PatientObservation>>

  An asynchronous cursor over the matching PatientObservation documents.

### FindByPatientIdAsync(ObjectId)

Retrieves all PatientObservation records associated with the specified patient by delegating to the observation repository.

    public Task<IAsyncCursor<PatientObservation>> FindByPatientIdAsync(ObjectId patientId)

#### Parameters

`patientId` ObjectId

  The unique identifier of the patient whose observations are being queried.

#### Returns

Task<IAsyncCursor<PatientObservation>>

  An MongoDB.Driver.IAsyncCursor<TDocument> that iterates over the matching patient observations.

### FindLastBeforeDate(ObjectId, DateTime, string?)

Retrieves the most recent patient observation recorded before the specified date, optionally filtered by observation name. Returns `null` when no matching observation exists.

    public Task<PatientObservation?> FindLastBeforeDate(ObjectId patientId, DateTime date, string? obsName)

#### Parameters

`patientId` ObjectId

  The unique identifier of the patient whose observation history is being queried.

`date` DateTime

  The upper bound date; only observations recorded prior to this date are considered.

`obsName` string

  The optional name of the observation to filter by. When `null`, observations of any name are considered.

#### Returns

Task<PatientObservation>

  The latest PatientObservation recorded before the specified date, or `null` if none was found.

### FindLastIntravenousLinesObservationByLocation(ObjectId)

Retrieves the most recent active intravenous lines observations for a patient, aggregated by location.

    public Task<List<PatientObservation?>> FindLastIntravenousLinesObservationByLocation(ObjectId patientId)

#### Parameters

`patientId` ObjectId

  The unique identifier of the patient whose intravenous lines observations are being queried.

#### Returns

Task<List<PatientObservation>>

  A task that represents the asynchronous operation. The task result contains a list of PatientObservation objects, which may include null entries, representing the latest active intravenous lines observations grouped by location.

### FindLastNotExpiredObservatonsByPatient(ObjectId, string, int?, int?)

Retrieves the most recent non-expired patient observations matching the specified name, optionally filtered by an end-after threshold and limited in count.

    public Task<IEnumerable<PatientObservation>> FindLastNotExpiredObservatonsByPatient(ObjectId patientId, string name, int? endAfter = null, int? num = null)

#### Parameters

`patientId` ObjectId

  The identifier of the patient whose observations are being queried.

`name` string

  The name of the observation to filter by.

`endAfter` int?

  Optional threshold used to restrict which observations are considered; if null, no end-after filter is applied.

`num` int?

  Optional maximum number of observations to return; if null, all matching observations are returned.

#### Returns

Task<IEnumerable<PatientObservation>>

  A task that represents the asynchronous operation, containing an enumerable collection of matching PatientObservation instances.

### FindLastObservations(ObjectId, int, List<string>?)

Retrieves the most recent observations for a specified patient by delegating to the observation repository's aggregation pipeline.

    public Task<List<PatientObservation>> FindLastObservations(ObjectId patientId, int num = 2, List<string>? filterObservations = null)

#### Parameters

`patientId` ObjectId

  The unique identifier of the patient whose observations are being queried.

`num` int

  The maximum number of recent observations to return. Defaults to 2.

`filterObservations` List<string>

  An optional list of observation codes/names used to narrow down which observations are considered.

#### Returns

Task<List<PatientObservation>>

  A task that represents the asynchronous operation, containing a list of the patient's most recent PatientObservation entries.

### FindLastObservationsByField(ObjectId, List<Field>?, bool, CancellationToken)

Retrieves the most recent observations for a patient from the aggregated cache, optionally filtered by specific fields, and optionally enriched through a name-based mapping. When `mapped` is `false`, the raw cached observations are returned directly; otherwise each observation is individually mapped and those that yield no result are excluded from the output.

    public Task<List<PatientObservation>> FindLastObservationsByField(ObjectId patientId, List<Field>? filterObservations = null, bool mapped = true, CancellationToken ct = default)

#### Parameters

`patientId` ObjectId

  The identifier of the patient whose latest observations are being queried.

`filterObservations` List<Field>

  Optional list of fields used to restrict which observations are retrieved from the cache.

`mapped` bool

  When `true` (default), applies a name-based mapping to each observation; when `false`, returns the raw results as they come from the cache.

`ct` CancellationToken

  Cancellation token to cancel the asynchronous operation.

#### Returns

Task<List<PatientObservation>>

  A task containing the list of patient observations, either as raw cached entries or as mapped values depending on `mapped`.

### FindLatestUniqueValuesByName(ObjectId, string, int?)

Retrieves the latest unique observation values for a specified patient and observation name, delegating the lookup to the underlying observation repository.

    public Task<List<PatientObservation>> FindLatestUniqueValuesByName(ObjectId patientId, string name, int? expires)

#### Parameters

`patientId` ObjectId

  The unique identifier of the patient whose observations are being queried.

`name` string

  The name of the observation to search for.

`expires` int?

  An optional expiration value (in seconds) applied to the query.

#### Returns

Task<List<PatientObservation>>

  A task that represents the asynchronous operation, containing a list of the latest unique PatientObservation values.

### FindNotExpiredObservationsShouldBeExpired()

Retrieves observations that are currently marked as not expired but should be expired based on their configured expiration thresholds. For each candidate observation, the patient is validated; missing patients trigger cleanup of their observations and cached entries. Observations with missing names or unparsable expiration values are skipped, and only those whose expected expiration time (observation time plus configured minutes) has passed are yielded.

    public IAsyncEnumerable<PatientObservation> FindNotExpiredObservationsShouldBeExpired()

#### Returns

IAsyncEnumerable<PatientObservation>

  An asynchronous stream of PatientObservation instances that are not expired in storage but whose effective expiration time has elapsed.

### GetPaginatedObservations(PaginationFilter)

Retrieves a paginated collection of patient observations from the repository, returning both the requested page of data and the total document count to support client-side pagination.

    public Task<PaginationResponse<PatientObservation>> GetPaginatedObservations(PaginationFilter filter)

#### Parameters

`filter` PaginationFilter

  The pagination filter that specifies the page number and page size used to compute the skip/limit range.

#### Returns

Task<PaginationResponse<PatientObservation>>

  A PaginationResponse<T> containing the page of patient observations along with pagination metadata.

### InsertIfChanged(string, PatientObservation, bool, bool)

Inserts a new patient observation only when its value differs from the most recent observation recorded for the same observation name; otherwise the existing record is kept and no insertion is performed.

    public Task<bool> InsertIfChanged(string name, PatientObservation observation, bool persistObs = true, bool mapObs = true)

#### Parameters

`name` string

  The name of the observation used to look up the latest existing value for the patient.

`observation` PatientObservation

  The patient observation to compare against the most recent value and to insert when a change is detected.

`persistObs` bool

  Indicates whether the new observation should be persisted when inserted.

`mapObs` bool

  Indicates whether the new observation should be mapped when inserted.

#### Returns

Task<bool>

  A task that resolves to `true` if the observation was inserted because the value changed, or `false` if the most recent observation already has the same value and no insertion was made.

### InsertNurseObservation(PatientObservation)

Inserts a nurse observation by mapping it, persisting it via the observation repository, updating the latest-observations cache, broadcasting the change, and creating an audit log entry. If mapping returns a null result or an observation with a null name, the method logs the error and returns without inserting. Any exception thrown during the operation is caught and logged.

    public Task InsertNurseObservation(PatientObservation obs)

#### Parameters

`obs` PatientObservation

  The patient observation provided by the nurse to be mapped, persisted, cached, broadcast, and audited.

#### Returns

Task

### InsertObservation(PatientObservation, bool, bool)

Inserts a new observation if needed

    public Task InsertObservation(PatientObservation obs, bool persistObs = true, bool mapObs = true)

#### Parameters

`obs` PatientObservation

  Observation

`persistObs` bool
`mapObs` bool

  True if it needs to be inserted

#### Returns

Task

### InsertSimpleObservation(PatientObservation)

Inserts a simple patient observation into the repository and records an audit log entry for the operation using the current HTTP context user.

    public Task InsertSimpleObservation(PatientObservation observation)

#### Parameters

`observation` PatientObservation

  The patient observation to insert.

#### Returns

Task

### MapObservation(PatientObservation, bool)

Maps a PatientObservation through a sequence of configuration, units, and calculated observations services to produce a fully mapped observation, returning `null` if any mapping step yields no result or if an error occurs.

    public Task<PatientObservation?> MapObservation(PatientObservation obs, bool onlyByName = false)

#### Parameters

`obs` PatientObservation

  The patient observation to be mapped.

`onlyByName` bool

  When `true`, restricts the mapping to name-based lookups only.

#### Returns

Task<PatientObservation>

  A task containing the mapped PatientObservation, or `null` if the observation is ignored, not found, or an exception is raised during processing.

### MapObservationsByName(PatientObservation)

Maps the specified patient observation by name by delegating to the configuration observation service using the by-name mapping mode.

    public Task<PatientObservation?> MapObservationsByName(PatientObservation obs)

#### Parameters

`obs` PatientObservation

  The patient observation to be mapped.

#### Returns

Task<PatientObservation>

  A task that represents the asynchronous operation. The task result contains the mapped PatientObservation, or null if no matching mapping is found.

### ProcessObservations(List<PatientObservation>, Patient, DateTime, ObservationData?)

Processes a batch of patient observations by attaching patient, parent data, and message metadata, then persists them asynchronously through the calculated observations mapping service. Missing observation or message timestamps default to UtcNow, and any errors during processing are logged without being rethrown.

    public void ProcessObservations(List<PatientObservation> observations, Patient patient, DateTime messageTime, ObservationData? observationData = null)

#### Parameters

`observations` List<PatientObservation>

  The list of patient observations to be processed and inserted.

`patient` Patient

  The patient to whom the observations belong.

`messageTime` DateTime

  The timestamp associated with the source message.

`observationData` ObservationData

  Optional parent observation metadata used to populate the parent data of each observation.

### SaveRequest(ApiRequest)

Processes and persists an inbound medical API request (HL7), routing `ORU_R40` alerts to the alarm service and `ORU_R01` observations to the appropriate handler (intravenous lines, allergies, drainage, isolation, position, diagnosis, or generic observations) based on the observation code. Throws when both patient and location are missing or when the request type is not supported, and silently returns when no matching patient is found.

    public Task SaveRequest(ApiRequest apiRequest)

#### Parameters

`apiRequest` ApiRequest

  The incoming API request containing patient/location identifiers, message type, and observation data.

#### Returns

Task

#### Exceptions

ApiRequestException

  Thrown when both the patient number and location are null or empty, or when the request type is not valid for observations.

### SaveRequestAsync(ApiRequest)

Asynchronously saves the provided API request by executing the save operation on a background thread.

    public Task SaveRequestAsync(ApiRequest apiRequest)

#### Parameters

`apiRequest` ApiRequest

  The API request to be saved.

#### Returns

Task

  A task that represents the asynchronous save operation.

### SaveRequestNurseObs(ApiRequest)

Saves manual nurse observations following the logic opposite to that of observations received from the census.

    public Task SaveRequestNurseObs(ApiRequest apiRequest)

#### Parameters

`apiRequest` ApiRequest

  The API request containing the data required to locate the patient and the observations to be saved.

#### Returns

Task

  A task that represents the asynchronous save operation.

#### Exceptions

ArgumentNullException

  Thrown when `apiRequest` is null.

### SaveRequestNurseObsAsync(ApiRequest)

Asynchronously saves nurse observations from the provided API request by executing the save operation on a background thread.

    public Task SaveRequestNurseObsAsync(ApiRequest request)

#### Parameters

`request` ApiRequest

  The API request containing the nurse observation data to be persisted.

#### Returns

Task

  A task that represents the asynchronous nurse observation save operation.

### SendObsBroadcast(List<PatientObservation>, ObjectId)

Broadcasts a list of patient observations to all display subscribers whose location identifiers match the specified point of care identifier. Subscribers with null or empty location identifiers are excluded, and each observation is dispatched asynchronously to every matching subscriber.

    public Task SendObsBroadcast(List<PatientObservation> obsList, ObjectId pocId)

#### Parameters

`obsList` List<PatientObservation>

  The collection of patient observations to be sent to the matched subscribers.

`pocId` ObjectId

  The point of care identifier used to filter the subscribers by their configured location identifiers.

#### Returns

Task

### SendObsBroadcast(List<PatientObservation>, PatientLocation)

Broadcasts a list of patient observations to all display subscribers whose registered locations match the specified patient location by unit name, bed, and room. Subscribers without any registered locations are excluded from the broadcast.

    public Task SendObsBroadcast(List<PatientObservation> obsList, PatientLocation location)

#### Parameters

`obsList` List<PatientObservation>

  The list of patient observations to send to matching subscribers.

`location` PatientLocation

  The patient location used to identify subscribers to notify.

#### Returns

Task

### SendObsBroadcast(BasePatientObservation)

Broadcasts a patient observation to all display subscribers whose location matches the patient's point of care. The method skips the broadcast if the observation has no name, and falls back to looking up the patient by id when it is not included in the observation.

    public Task SendObsBroadcast(BasePatientObservation obs)

#### Parameters

`obs` BasePatientObservation

  The patient observation to broadcast. May include the patient or require a lookup via PatientId.

#### Returns

Task

### UpdateExpiredObservations(List<PatientObservation>)

Updates the repository to mark a list of patient observations as expired, invalidates the corresponding cache entries, and creates audit log entries capturing the pre-update state of each observation.

    public Task UpdateExpiredObservations(List<PatientObservation> patientObservations)

#### Parameters

`patientObservations` List<PatientObservation>

  The list of patient observations to be marked as expired.

#### Returns

Task

### UpdateManyObjectId(string, ObjectId, ObjectId)

Updates multiple observation records by replacing the specified old object identifier with a new one for the given name identifier.

    public Task UpdateManyObjectId(string nameId, ObjectId id, ObjectId oldId)

#### Parameters

`nameId` string

  The name identifier of the field whose value should be updated across matching records.

`id` ObjectId

  The new MongoDB.Bson.ObjectId value to assign to the matching records.

`oldId` ObjectId

  The existing MongoDB.Bson.ObjectId value to be replaced.

#### Returns

Task

### UpdateObservation(PatientObservation)

Updates an existing patient observation if it exists in the repository, invalidates the related cache entries, and records an audit log of the change. If no observation with the specified identifier is found, the method performs no action.

    public Task UpdateObservation(PatientObservation observation)

#### Parameters

`observation` PatientObservation

  The patient observation containing the updated data to be persisted.

#### Returns

Task