mirror of
https://github.com/hapifhir/hapi-fhir.git
synced 2025-02-16 18:05:19 +00:00
Refactored the meta extensions, so it reuses the existing logic that is
used for encoding and parsing extensions on resources.
This commit is contained in:
parent
46fcceb9c6
commit
f426b0679c
@ -26,7 +26,6 @@ import ca.uhn.fhir.model.api.*;
|
|||||||
import ca.uhn.fhir.model.api.annotation.Child;
|
import ca.uhn.fhir.model.api.annotation.Child;
|
||||||
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
|
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
|
||||||
import ca.uhn.fhir.model.base.composite.BaseContainedDt;
|
import ca.uhn.fhir.model.base.composite.BaseContainedDt;
|
||||||
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
|
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||||
import ca.uhn.fhir.narrative.INarrativeGenerator;
|
import ca.uhn.fhir.narrative.INarrativeGenerator;
|
||||||
@ -34,7 +33,6 @@ import ca.uhn.fhir.parser.json.*;
|
|||||||
import ca.uhn.fhir.parser.json.JsonLikeValue.ScalarType;
|
import ca.uhn.fhir.parser.json.JsonLikeValue.ScalarType;
|
||||||
import ca.uhn.fhir.parser.json.JsonLikeValue.ValueType;
|
import ca.uhn.fhir.parser.json.JsonLikeValue.ValueType;
|
||||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||||
import ca.uhn.fhir.util.BinaryUtil;
|
|
||||||
import ca.uhn.fhir.util.ElementUtil;
|
import ca.uhn.fhir.util.ElementUtil;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
@ -695,7 +693,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||||||
theEventWriter.endArray();
|
theEventWriter.endArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
addExtensionMetadata(extensionMetadataKeys, theEventWriter);
|
addExtensionMetadata(theResDef, theResource, theContainedResource, theSubResource, extensionMetadataKeys, resDef, theEventWriter);
|
||||||
|
|
||||||
theEventWriter.endObject(); // end meta
|
theEventWriter.endObject(); // end meta
|
||||||
}
|
}
|
||||||
@ -706,52 +704,21 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||||||
theEventWriter.endObject();
|
theEventWriter.endObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addExtensionMetadata(List<Map.Entry<ResourceMetadataKeyEnum<?>, Object>> extensionMetadataKeys, JsonLikeWriter theEventWriter) throws IOException {
|
|
||||||
|
private void addExtensionMetadata(RuntimeResourceDefinition theResDef, IBaseResource theResource,
|
||||||
|
boolean theContainedResource, boolean theSubResource,
|
||||||
|
List<Map.Entry<ResourceMetadataKeyEnum<?>, Object>> extensionMetadataKeys,
|
||||||
|
RuntimeResourceDefinition resDef,
|
||||||
|
JsonLikeWriter theEventWriter) throws IOException {
|
||||||
if (extensionMetadataKeys.isEmpty()) {
|
if (extensionMetadataKeys.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Map.Entry<ResourceMetadataKeyEnum<?>, Object>> extensionKeys = new ArrayList<>(extensionMetadataKeys.size());
|
ExtensionDt metaResource = new ExtensionDt();
|
||||||
List<Map.Entry<ResourceMetadataKeyEnum<?>, Object>> modifierExtensionKeys = new ArrayList<>(extensionKeys.size());
|
|
||||||
for (Map.Entry<ResourceMetadataKeyEnum<?>, Object> entry : extensionMetadataKeys) {
|
for (Map.Entry<ResourceMetadataKeyEnum<?>, Object> entry : extensionMetadataKeys) {
|
||||||
if (!((ExtensionDt) entry.getValue()).isModifier()) {
|
metaResource.addUndeclaredExtension((ExtensionDt) entry.getValue());
|
||||||
extensionKeys.add(entry);
|
|
||||||
} else {
|
|
||||||
modifierExtensionKeys.add(entry);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
encodeCompositeElementToStreamWriter(theResDef, theResource, metaResource, theEventWriter, theContainedResource, theSubResource, new CompositeChildElement(resDef, theSubResource));
|
||||||
writeMetadataExtensions(extensionKeys, "extension", theEventWriter);
|
|
||||||
writeMetadataExtensions(modifierExtensionKeys, "modifierExtension", theEventWriter);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeMetadataExtensions(List<Map.Entry<ResourceMetadataKeyEnum<?>, Object>> extensions, String arrayName, JsonLikeWriter theEventWriter) throws IOException {
|
|
||||||
if (extensions.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
beginArray(theEventWriter, arrayName);
|
|
||||||
for (Map.Entry<ResourceMetadataKeyEnum<?>, Object> key : extensions) {
|
|
||||||
ExtensionDt extension = (ExtensionDt) key.getValue();
|
|
||||||
if (!extension.getAllUndeclaredExtensions().isEmpty()) {
|
|
||||||
throw new IllegalArgumentException("Sub-extensions on metadata isn't supported");
|
|
||||||
}
|
|
||||||
theEventWriter.beginObject();
|
|
||||||
writeOptionalTagWithTextNode(theEventWriter, "url", extension.getUrl());
|
|
||||||
RuntimeChildUndeclaredExtensionDefinition runtimeDefinitions = myContext.getRuntimeChildUndeclaredExtensionDefinition();
|
|
||||||
|
|
||||||
String extensionDatatype = runtimeDefinitions.getChildNameByDatatype(extension.getValue().getClass());
|
|
||||||
if (extension.getValue() instanceof IPrimitiveDatatype) {
|
|
||||||
writeOptionalTagWithTextNode(theEventWriter, extensionDatatype, extension.getValueAsPrimitive());
|
|
||||||
} else {
|
|
||||||
if (extension.getValue() instanceof BaseResourceReferenceDt) {
|
|
||||||
writeOptionalTagWithTextNode(theEventWriter, extensionDatatype, ((BaseResourceReferenceDt) extension.getValue()).getReference());
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException("Cannot parse meta extension with type: " + extension.getValue().getClass().getSimpleName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
theEventWriter.endObject();
|
|
||||||
}
|
|
||||||
theEventWriter.endArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -489,8 +489,6 @@ class ParserState<T> {
|
|||||||
}
|
}
|
||||||
} else if ("url".equals(theName) && myInstance instanceof ExtensionDt) {
|
} else if ("url".equals(theName) && myInstance instanceof ExtensionDt) {
|
||||||
((ExtensionDt) myInstance).setUrl(theValue);
|
((ExtensionDt) myInstance).setUrl(theValue);
|
||||||
} else if ("value".equals(theName) && myInstance instanceof BaseResourceReferenceDt) {
|
|
||||||
((BaseResourceReferenceDt) myInstance).setReference(new IdDt(theValue));
|
|
||||||
} else {
|
} else {
|
||||||
if (myJsonMode) {
|
if (myJsonMode) {
|
||||||
myErrorHandler.incorrectJsonType(null, myElementName, ValueType.OBJECT, null, ValueType.SCALAR, ScalarType.STRING);
|
myErrorHandler.incorrectJsonType(null, myElementName, ValueType.OBJECT, null, ValueType.SCALAR, ScalarType.STRING);
|
||||||
|
@ -15,16 +15,14 @@ import static org.junit.Assert.assertThat;
|
|||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.times;
|
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.hamcrest.CoreMatchers;
|
import org.apache.commons.lang3.time.DateUtils;
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
@ -37,7 +35,6 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.ConfigurationException;
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.model.api.*;
|
import ca.uhn.fhir.model.api.*;
|
||||||
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
|
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
|
||||||
@ -1716,41 +1713,67 @@ public class JsonParserDstu2Test {
|
|||||||
public void testEncodeResourceWithExtensionMetadata() throws Exception {
|
public void testEncodeResourceWithExtensionMetadata() throws Exception {
|
||||||
ProcedureRequest procedureRequest = new ProcedureRequest();
|
ProcedureRequest procedureRequest = new ProcedureRequest();
|
||||||
procedureRequest.setStatus(ProcedureRequestStatusEnum.ACCEPTED);
|
procedureRequest.setStatus(ProcedureRequestStatusEnum.ACCEPTED);
|
||||||
addExtensionResourceMetadataKeyToResource(procedureRequest, false, "http://someurl.com", "SomeValue");
|
ExtensionDt timestamp = new ExtensionDt(false, "http://fhir.sjanic.com/timestamp");
|
||||||
addExtensionResourceMetadataKeyToResource(procedureRequest, false, "http://someurl2.com", "SomeValue2");
|
timestamp.addUndeclaredExtension(false, "http://fhir.sjanic.com/timestamp/user", new ResourceReferenceDt("sjanic"));
|
||||||
addExtensionResourceMetadataKeyToResource(procedureRequest, true, "http://someurl.com/modifier", "SomeValue");
|
timestamp.addUndeclaredExtension(false, "http://fhir.sjanic.com/timestamp/instance", new InstantDt("2012-01-01T13:00:00Z"));
|
||||||
addExtensionResourceMetadataKeyToResource(procedureRequest, true, "http://someurl.com/modifier2", "SomeValue2");
|
timestamp.addUndeclaredExtension(false, "http://fhir.sjanic.com/timestamp/organization", new ResourceReferenceDt("sjanic_org"));
|
||||||
|
timestamp.addUndeclaredExtension(false, "http://fhir.sjanic.com/timestamp/role", new CodeableConceptDt().addCoding(new CodingDt("sjanic", "Doctor").setDisplay("Doctorin")));
|
||||||
Organization organization = new Organization();
|
ExtensionDt payment = new ExtensionDt(true, "http://fhir.sjanic.com/procedureRequest/requiresPatientPayment", new BooleanDt(true));
|
||||||
organization.setId(new IdDt("Someorganization"));
|
procedureRequest.getResourceMetadata().put(new ResourceMetadataKeyEnum.ExtensionResourceMetadataKey(timestamp.getUrl()), timestamp);
|
||||||
ExtensionDt extensionDt = new ExtensionDt(false, "http://someurl3.com", new ResourceReferenceDt(organization.getId()));
|
procedureRequest.getResourceMetadata().put(new ResourceMetadataKeyEnum.ExtensionResourceMetadataKey(payment.getUrl()), payment);
|
||||||
procedureRequest.getResourceMetadata()
|
|
||||||
.put(new ResourceMetadataKeyEnum.ExtensionResourceMetadataKey(extensionDt.getUrl()), extensionDt);
|
|
||||||
|
|
||||||
String json = ourCtx.newJsonParser().encodeResourceToString(procedureRequest);
|
String json = ourCtx.newJsonParser().encodeResourceToString(procedureRequest);
|
||||||
|
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
assertThat(json, stringContainsInOrder(
|
assertThat(json, stringContainsInOrder(
|
||||||
"\"meta\":{",
|
"\"meta\":{"+
|
||||||
"\"extension\":[{",
|
"\"extension\":["+
|
||||||
"\"url\":\"http://someurl.com\",",
|
"{"+
|
||||||
"\"valueString\":\"SomeValue\"",
|
"\"url\":\"http://fhir.sjanic.com/timestamp\","+
|
||||||
"},{",
|
"\"extension\":["+
|
||||||
"\"url\":\"http://someurl2.com\",",
|
"{"+
|
||||||
"\"valueString\":\"SomeValue2\"",
|
"\"url\":\"http://fhir.sjanic.com/timestamp/user\","+
|
||||||
"}],",
|
"\"valueReference\":{"+
|
||||||
"\"modifierExtension\":[{",
|
"\"reference\":\"sjanic\""+
|
||||||
"\"url\":\"http://someurl.com/modifier\",",
|
"}"+
|
||||||
"\"valueString\":\"SomeValue\"",
|
"},"+
|
||||||
"},{",
|
"{"+
|
||||||
"\"url\":\"http://someurl.com/modifier2\",",
|
"\"url\":\"http://fhir.sjanic.com/timestamp/instance\","+
|
||||||
"\"valueString\":\"SomeValue2\"",
|
"\"valueInstant\":\"2012-01-01T13:00:00Z\""+
|
||||||
"}]"));
|
"},"+
|
||||||
|
"{"+
|
||||||
|
"\"url\":\"http://fhir.sjanic.com/timestamp/organization\","+
|
||||||
|
"\"valueReference\":{"+
|
||||||
|
"\"reference\":\"sjanic_org\""+
|
||||||
|
"}"+
|
||||||
|
"},"+
|
||||||
|
"{"+
|
||||||
|
"\"url\":\"http://fhir.sjanic.com/timestamp/role\","+
|
||||||
|
"\"valueCodeableConcept\":{"+
|
||||||
|
"\"coding\":["+
|
||||||
|
"{"+
|
||||||
|
"\"system\":\"sjanic\","+
|
||||||
|
"\"code\":\"Doctor\","+
|
||||||
|
"\"display\":\"Doctorin\""+
|
||||||
|
"}"+
|
||||||
|
"]"+
|
||||||
|
"}"+
|
||||||
|
"}"+
|
||||||
|
"]"+
|
||||||
|
"}"+
|
||||||
|
"],"+
|
||||||
|
"\"modifierExtension\":["+
|
||||||
|
"{"+
|
||||||
|
"\"url\":\"http://fhir.sjanic.com/procedureRequest/requiresPatientPayment\","+
|
||||||
|
"\"valueBoolean\":true"+
|
||||||
|
"}"+
|
||||||
|
"]"+
|
||||||
|
"},"));
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParseResourceWithReferenceExtensionMetadata() throws Exception {
|
public void testParseResourceWithExtensionMetadata() throws Exception {
|
||||||
String input = IOUtils.toString(getClass().getResourceAsStream("/procedure-request.json"));
|
String input = IOUtils.toString(getClass().getResourceAsStream("/procedure-request.json"));
|
||||||
IParser parser = ourCtx.newJsonParser();
|
IParser parser = ourCtx.newJsonParser();
|
||||||
IParserErrorHandler peh = mock(IParserErrorHandler.class);
|
IParserErrorHandler peh = mock(IParserErrorHandler.class);
|
||||||
@ -1760,37 +1783,21 @@ public class JsonParserDstu2Test {
|
|||||||
|
|
||||||
ArgumentCaptor<String> capt = ArgumentCaptor.forClass(String.class);
|
ArgumentCaptor<String> capt = ArgumentCaptor.forClass(String.class);
|
||||||
verify(peh, Mockito.never()).unknownElement(Mockito.isNull(IParseLocation.class), capt.capture());
|
verify(peh, Mockito.never()).unknownElement(Mockito.isNull(IParseLocation.class), capt.capture());
|
||||||
assertReferenceExtensionMetadata(p, "http://someurl3.com", false, ResourceReferenceDt.class, "dc0b549a-f852-11e6-bc64-92361f002671");
|
assertParsedResourcesExtensionMetadata(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertReferenceExtensionMetadata(
|
private void assertParsedResourcesExtensionMetadata(ProcedureRequest resource) throws Exception {
|
||||||
BaseResource resource,
|
ExtensionDt payment = (ExtensionDt) resource.getResourceMetadata().get(
|
||||||
String url,
|
new ResourceMetadataKeyEnum.ExtensionResourceMetadataKey("http://fhir.sjanic.com/procedureRequest/requiresPatientPayment"));
|
||||||
boolean isModifier,
|
assertThat(payment.isModifier(), equalTo(true));
|
||||||
Class<?> expectedType,
|
assertThat(((BooleanDt)payment.getValue()).getValue(), equalTo(true));
|
||||||
String expectedValue) {
|
|
||||||
ExtensionDt extension = (ExtensionDt) resource.getResourceMetadata().get(new ResourceMetadataKeyEnum.ExtensionResourceMetadataKey(url));
|
|
||||||
assertThat(extension.getValue(), CoreMatchers.instanceOf(expectedType));
|
|
||||||
assertThat(extension.isModifier(), equalTo(isModifier));
|
|
||||||
assertThat(extension.getValue(), CoreMatchers.instanceOf(BaseResourceReferenceDt.class));
|
|
||||||
assertThat(((BaseResourceReferenceDt)extension.getValue()).getReference().getIdPart(), equalTo(expectedValue));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
TimestampFields timestampFields = new TimestampFields(resource);
|
||||||
public void testCannotEncodeSubextensionsOnMeta() {
|
assertThat(timestampFields.user.getReference().getIdPart(), equalTo("sjanic"));
|
||||||
ProcedureRequest procedureRequest = new ProcedureRequest();
|
assertThat(timestampFields.instance.getValue(), equalTo(new InstantDt("2012-01-01T13:00:00Z").getValue()));
|
||||||
procedureRequest.setStatus(ProcedureRequestStatusEnum.ACCEPTED);
|
assertThat(timestampFields.organization.getReference().getIdPart(), equalTo("sjanic_org"));
|
||||||
ExtensionDt parent = new ExtensionDt(false, "#parent");
|
assertThat(timestampFields.role.getCodingFirstRep().getSystem(), equalTo("sjanic"));
|
||||||
parent.addUndeclaredExtension(new ExtensionDt(false, "#child", new DurationDt().setValue(123)));
|
assertThat(timestampFields.role.getCodingFirstRep().getCode(), equalTo("Doctor"));
|
||||||
procedureRequest.getResourceMetadata().put(new ResourceMetadataKeyEnum.ExtensionResourceMetadataKey(parent.getUrl()), parent);
|
|
||||||
|
|
||||||
String json = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(procedureRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addExtensionResourceMetadataKeyToResource(BaseResource resource, boolean isModifier, String url, String value) {
|
|
||||||
ExtensionDt extensionDt = new ExtensionDt(isModifier, url, new StringDt(value));
|
|
||||||
resource.getResourceMetadata()
|
|
||||||
.put(new ResourceMetadataKeyEnum.ExtensionResourceMetadataKey(extensionDt.getUrl()), extensionDt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -2058,4 +2065,25 @@ public class JsonParserDstu2Test {
|
|||||||
Assert.assertEquals(1, extlst.size());
|
Assert.assertEquals(1, extlst.size());
|
||||||
Assert.assertEquals(refVal, ((ResourceReferenceDt) extlst.get(0).getValue()).getReference().getValue());
|
Assert.assertEquals(refVal, ((ResourceReferenceDt) extlst.get(0).getValue()).getReference().getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final class TimestampFields {
|
||||||
|
ResourceReferenceDt user;
|
||||||
|
InstantDt instance;
|
||||||
|
ResourceReferenceDt organization;
|
||||||
|
CodeableConceptDt role;
|
||||||
|
|
||||||
|
TimestampFields(BaseResource resource) {
|
||||||
|
ExtensionDt timestamp = (ExtensionDt) resource.getResourceMetadata().get(
|
||||||
|
new ResourceMetadataKeyEnum.ExtensionResourceMetadataKey("http://fhir.sjanic.com/timestamp"));
|
||||||
|
|
||||||
|
Map<String, ExtensionDt> timestampFields = new HashMap<>(timestamp.getExtension().size());
|
||||||
|
for (ExtensionDt extensionDt : timestamp.getExtension()) {
|
||||||
|
timestampFields.put(extensionDt.getUrl(), extensionDt);
|
||||||
|
}
|
||||||
|
user = ((ResourceReferenceDt)timestampFields.get("http://fhir.sjanic.com/timestamp/user").getValue());
|
||||||
|
instance = (InstantDt) timestampFields.get("http://fhir.sjanic.com/timestamp/instance").getValue();
|
||||||
|
organization = (ResourceReferenceDt) timestampFields.get("http://fhir.sjanic.com/timestamp/organization").getValue();
|
||||||
|
role = (CodeableConceptDt) timestampFields.get("http://fhir.sjanic.com/timestamp/role").getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,43 @@
|
|||||||
"meta": {
|
"meta": {
|
||||||
"extension": [
|
"extension": [
|
||||||
{
|
{
|
||||||
"url": "http://someurl3.com",
|
"url": "http://fhir.sjanic.com/timestamp",
|
||||||
"valueReference": "Organization/dc0b549a-f852-11e6-bc64-92361f002671"
|
"extension": [
|
||||||
|
{
|
||||||
|
"url": "http://fhir.sjanic.com/timestamp/user",
|
||||||
|
"valueReference": {
|
||||||
|
"reference": "sjanic"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "http://fhir.sjanic.com/timestamp/instance",
|
||||||
|
"valueInstant": "2012-01-01T13:00:00Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "http://fhir.sjanic.com/timestamp/organization",
|
||||||
|
"valueReference": {
|
||||||
|
"reference": "sjanic_org"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "http://fhir.sjanic.com/timestamp/role",
|
||||||
|
"valueCodeableConcept": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "sjanic",
|
||||||
|
"code": "Doctor",
|
||||||
|
"display": "Doctorin"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"modifierExtension": [
|
||||||
|
{
|
||||||
|
"url": "http://fhir.sjanic.com/procedureRequest/requiresPatientPayment",
|
||||||
|
"valueBoolean": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user