When you change an Obs value and then save the Obs by saving the parent Encounter via the API (ie calling saveEncounter, not saveObs), instead of voiding the Obs and creating a new one, it simply updates the Obs.
See attached test case.
- Encounter.obs in the mapping file shouldn't cascade any operation to the Obs and let the API do it explicitly, same for ConceptProposal.obs
- Add Obs.dirty field which is non persistent and defaults to false, update every setter in Obs class to set the dirty field to true if the old and new field values are not the same
- When updating an Obs, the API should check if Obs.dirty is set true, voids it and creates a new Obs to replace it
- EncounterService.saveEncounter should loop over all the Obs an encounter contains and call saveObs for each after saving the encounter.
- Obs are immutable except for voided, voidedBy, voidReason and dateVoided fields, register a subclass of ImmutableEntityInterceptor for Obs just like we did for orders to fail when an updated obs is flushed. See ImmutableOrderInterceptor for an example.
- It would be nice to include a test in ObsTest that reflectively fetches all fields in Obs, loops over all of them to ensure that if a given setter is called with a new value, the Obs gets marked dirty, this will be future-proofing the class in case new fields get added later