package integration import ( "errors" "os" "satusehat-rssa/internal/constant" "satusehat-rssa/internal/model" "satusehat-rssa/pkg/httputil" ) type CompositionInterface interface { CreateComposition(req model.CompositionRequest) (map[string]interface{}, error) UpdateComposition(req model.CompositionRequest) (map[string]interface{}, error) GetCompositionByID(id string) (map[string]interface{}, error) } type CompositionRepository struct { akses *model.Akses } // CreateComposition implements CompositionInterface. func (c *CompositionRepository) CreateComposition(req model.CompositionRequest) (map[string]interface{}, error) { req.ResourceType = "Composition" req.Identifier = model.Identifier{ Use: "official", System: "http://sys-ids.kemkes.go.id/composition/" + os.Getenv("ORGANIZATION_ID"), Value: os.Getenv("ORGANIZATION_ID"), } patient, err := c.setupPatient(&req) if err != nil { return nil, err } err = c.setupEncounter(&req, patient) if err != nil { return nil, err } err = c.setupOrganization(&req) if err != nil { return nil, err } // section setup if req.Anamnesis == "" { req.Anamnesis = "default anamnesis" } if req.PemeriksaanFisik == "" { req.PemeriksaanFisik = "default pemeriksaan fisik" } if req.PemeriksaanPenunjang == "" { req.PemeriksaanPenunjang = "default pemeriksaan penunjang" } if req.Medikamentosa == "" { req.Medikamentosa = "default medikamentosa" } if req.LanjutanPenatalaksanaan == "" { req.LanjutanPenatalaksanaan = "default lanjutan penatalaksanaan" } req.Section = append(req.Section, model.SectionRequest{ Title: "Anamnesis", Code: model.CodeableConcept{ Coding: []model.Coding{ { System: "http://terminology.kemkes.go.id", Code: "TK000003", Display: "Anamnesis", }, }, }, Text: &model.SectionText{ Status: "additional", Div: req.Anamnesis, }, }) allergyId := c.setupAllergyIntollerance(patient) section := model.SectionRequest{ Title: "Riwayat Alergi", Code: model.CodeableConcept{ Coding: []model.Coding{ { System: "http://loinc.org", Code: "18776-5", Display: "Riwayat Alergi", }, }, }, } if allergyId != "" { section.Entry = []model.Reference{ {Reference: "AllergyIntolerance/" + allergyId}, } } req.Section = append(req.Section, section) /* Observation disabled for Now req.Section = append(req.Section, model.SectionRequest{ Title: "Pemeriksaan Fisik", Code: model.CodeableConcept{ Coding: []model.Coding{ { System: "http://terminology.kemkes.go.id", Code: "TK000007", Display: "Pemeriksaan Fisik", }, }, }, Section: []model.SectionRequest{ { Title: "Tanda Vital", Code: model.CodeableConcept{ Coding: []model.Coding{ { System: "http://loinc.org", Code: "8716-3", Display: "Vital signs", }, }, }, Entry: c.setupObservation(patient), }, { Title: "Hasil Pemeriksaan", Code: model.CodeableConcept{ Coding: []model.Coding{ { System: "http://terminology.kemkes.go.id", Code: "TK000007", Display: "Pemeriksaan Fisik", }, }, }, Text: &model.SectionText{ Status: "additional", Div: req.PemeriksaanFisik, }, }, }, }) */ var entry []model.Reference clinicalId := c.setupClinicalImpression(patient) goalId := c.setupGoal(patient) carePlanId := c.setupCarePlan(patient) if clinicalId != "" { entry = append(entry, model.Reference{Reference: "ClinicalImpression/" + clinicalId}) } if goalId != "" { entry = append(entry, model.Reference{Reference: "Goal/" + goalId}) } if carePlanId != "" { entry = append(entry, model.Reference{Reference: "CarePlan/" + carePlanId}) } req.Section = append(req.Section, model.SectionRequest{ Title: "Perencanaan Perawatan", Code: model.CodeableConcept{ Coding: []model.Coding{ { System: "http://loinc.org", Code: "18776-5", Display: "Plan of care note", }, }, }, Entry: entry, }) var entryLab, entryRad []model.Reference serviceRequestIdLab := c.setupServiceRequestCategory(patient, "LAB") specimenIdLab := c.setupSpecimenCategory(patient) diagnosticReportIdLab := c.setupDiagnosticCategory(patient, "LAB") observationIdLab := c.setupObservationCategory(patient, "LAB") serviceRequestIdRad := c.setupServiceRequestCategory(patient, "RAD") imagingStudyRad := c.setupImagingStudy(patient) diagnosticReportIdRad := c.setupDiagnosticCategory(patient, "RAD") observationIdRad := c.setupObservationCategory(patient, "RAD") if serviceRequestIdLab != "" { entryLab = append(entryLab, model.Reference{Reference: "ServiceRequest/" + serviceRequestIdLab}) } if specimenIdLab != "" { entryLab = append(entryLab, model.Reference{Reference: "Specimen/" + specimenIdLab}) } if diagnosticReportIdLab != "" { entryLab = append(entryLab, model.Reference{Reference: "DiagnosticReport/" + diagnosticReportIdLab}) } if observationIdLab != "" { entryLab = append(entryLab, model.Reference{Reference: "Observation/" + observationIdLab}) } if serviceRequestIdRad != "" { entryRad = append(entryRad, model.Reference{Reference: "ServiceRequest/" + serviceRequestIdRad}) } if imagingStudyRad != "" { entryRad = append(entryRad, model.Reference{Reference: "ImagingStudy/" + imagingStudyRad}) } if diagnosticReportIdRad != "" { entryRad = append(entryRad, model.Reference{Reference: "DiagnosticReport/" + diagnosticReportIdRad}) } if observationIdRad != "" { entryRad = append(entryRad, model.Reference{Reference: "Observation/" + observationIdRad}) } if len(entryLab) != 0 && len(entryRad) != 0 { req.Section = append(req.Section, model.SectionRequest{ Title: "Pemeriksaan Penunjang", Code: model.CodeableConcept{ Coding: []model.Coding{ { System: "http://terminology.kemkes.go.id", Code: "TK000009", Display: "Hasil Pemeriksaan Penunjang", }, }, }, Text: &model.SectionText{ Status: "additional", Div: req.PemeriksaanPenunjang, }, Section: []model.SectionRequest{ { Title: "Hasil Pemeriksaan Laboratorium", Code: model.CodeableConcept{ Coding: []model.Coding{ { System: "http://loinc.org", Code: "11502-2", Display: "Laboratory report", }, }, }, Entry: entryLab, }, { Title: "Hasil Pemeriksaan Radiologi", Code: model.CodeableConcept{ Coding: []model.Coding{ { System: "http://loinc.org", Code: "18782-3", Display: "Radiology Study observation (narrative)", }, }, }, Entry: entryRad, }, }, }) } else if len(entryLab) != 0 && len(entryRad) == 0 { req.Section = append(req.Section, model.SectionRequest{ Title: "Pemeriksaan Penunjang", Code: model.CodeableConcept{ Coding: []model.Coding{ { System: "http://terminology.kemkes.go.id", Code: "TK000009", Display: "Hasil Pemeriksaan Penunjang", }, }, }, Text: &model.SectionText{ Status: "additional", Div: req.PemeriksaanPenunjang, }, Section: []model.SectionRequest{ { Title: "Hasil Pemeriksaan Laboratorium", Code: model.CodeableConcept{ Coding: []model.Coding{ { System: "http://loinc.org", Code: "11502-2", Display: "Laboratory report", }, }, }, Entry: entryLab, }, }, }) } else if len(entryLab) == 0 && len(entryRad) != 0 { req.Section = append(req.Section, model.SectionRequest{ Title: "Pemeriksaan Penunjang", Code: model.CodeableConcept{ Coding: []model.Coding{ { System: "http://terminology.kemkes.go.id", Code: "TK000009", Display: "Hasil Pemeriksaan Penunjang", }, }, }, Text: &model.SectionText{ Status: "additional", Div: req.PemeriksaanPenunjang, }, Section: []model.SectionRequest{ { Title: "Hasil Pemeriksaan Radiologi", Code: model.CodeableConcept{ Coding: []model.Coding{ { System: "http://loinc.org", Code: "18782-3", Display: "Radiology Study observation (narrative)", }, }, }, Entry: entryRad, }, }, }) } var entryCondition []model.Reference conditionId := c.setupCondition(patient) if conditionId != "" { entryCondition = append(entryCondition, model.Reference{Reference: "Condition/" + conditionId}) } req.Section = append(req.Section, model.SectionRequest{ Title: "Diagnosa", Code: model.CodeableConcept{ Coding: []model.Coding{ { System: "http://terminology.kemkes.go.id", Code: "TK000004", Display: "Diagnosis", }, }, }, Section: []model.SectionRequest{ { Title: "Diagnosa Utama", Code: model.CodeableConcept{ Coding: []model.Coding{ { System: "http://loinc.org", Code: "78375-3", Display: "Discharge diagnosis Narrative", }, }, }, Entry: entryCondition, }, }, }) var entryProcedure []model.Reference procedureId := c.setupProcedure(patient) if procedureId != "" { entryProcedure = append(entryProcedure, model.Reference{Reference: "Procedure/" + procedureId}) } req.Section = append(req.Section, model.SectionRequest{ Title: "Tindakan Operatif/Non Operatif Utama", Code: model.CodeableConcept{ Coding: []model.Coding{ { System: "http://terminology.kemkes.go.id", Code: "TK000005", Display: "Tindakan/Prosedur Medis", }, }, }, Entry: entryProcedure, }) var medication []model.Reference medicationRequestId := c.setupMedicationRequest(patient) if medicationRequestId != "" { medication = append(medication, model.Reference{Reference: "MedicationRequest/" + medicationRequestId}) } medicationDispenseId := c.setupMedicationDispense(patient) if medicationDispenseId != "" { medication = append(medication, model.Reference{Reference: "MedicationDispense/" + medicationDispenseId}) } /* Farmasi section disabled for Now req.Section = append(req.Section, model.SectionRequest{ Title: "Farmasi", Code: model.CodeableConcept{ Coding: []model.Coding{ { System: "http://terminology.kemkes.go.id", Code: "TK000013", Display: "Obat", }, }, }, Section: []model.SectionRequest{ /*{ Title: "Obat Saat Kunjungan", Code: model.CodeableConcept{ Coding: []model.Coding{ { System: "http://loinc.org", Code: "42346-7", Display: "Medications on admission (narrative)", }, }, }, Entry: []model.Reference{ {Reference: "MedicationAdministration/"}, {Reference: "MedicationRequest/"}, {Reference: "MedicationDispense/"}, }, },*/ /* { Title: "Obat Pulang", Code: model.CodeableConcept{ Coding: []model.Coding{ { System: "http://loinc.org", Code: "75311-1", Display: "Discharge medications Narrative", }, }, }, Entry: medication, }, }, }) */ req.Section = append(req.Section, model.SectionRequest{ Title: "Medikamentosa", Code: model.CodeableConcept{ Coding: []model.Coding{ { System: "http://loinc.org", Code: "18776-5", Display: "Plan of treatment (narrative)", }, }, }, Text: &model.SectionText{ Status: "additional", Div: req.Medikamentosa, }, }) req.Section = append(req.Section, model.SectionRequest{ Title: "Lanjutan Penatalaksanaan", Code: model.CodeableConcept{ Coding: []model.Coding{ { System: "http://loinc.org", Code: "8653-8", Display: "Hospital Discharge instructions", }, }, }, Text: &model.SectionText{ Status: "additional", Div: req.LanjutanPenatalaksanaan, }, }) //remove field unused req.Anamnesis = "" req.PemeriksaanFisik = "" req.PemeriksaanPenunjang = "" req.Medikamentosa = "" req.LanjutanPenatalaksanaan = "" oauth := model.OauthRequest{ ClientId: c.akses.ClientId, ClientSecret: c.akses.ClientSecret, } token, err := NewOauthRequestRepo(c.akses).GenerateToken(oauth) if err != nil { return nil, err } if token == nil { return nil, errors.New(constant.ErrGenerateToken) } // b, err := json.MarshalIndent(req, "", " ") // if err != nil { // log.Println("error marshal:", err) // } else { // log.Println(string(b)) // } url := c.akses.BaseUrl + "/Composition" return httputil.DoRequest(httputil.RequestOption{ Method: "POST", URL: url, Body: req, BearerToken: token.AccessToken, }) } // GetCompositionByID implements CompositionInterface. func (c *CompositionRepository) GetCompositionByID(id string) (map[string]interface{}, error) { panic("unimplemented") } // UpdateComposition implements CompositionInterface. func (c *CompositionRepository) UpdateComposition(req model.CompositionRequest) (map[string]interface{}, error) { req.ResourceType = "Composition" patient, err := c.setupPatient(&req) if err != nil { return nil, err } err = c.setupEncounter(&req, patient) if err != nil { return nil, err } err = c.setupOrganization(&req) if err != nil { return nil, err } oauth := model.OauthRequest{ ClientId: c.akses.ClientId, ClientSecret: c.akses.ClientSecret, } token, err := NewOauthRequestRepo(c.akses).GenerateToken(oauth) if err != nil { return nil, err } if token == nil { return nil, errors.New(constant.ErrGenerateToken) } url := c.akses.BaseUrl + "/Composition/" + req.Id return httputil.DoRequest(httputil.RequestOption{ Method: "PUT", URL: url, Body: req, BearerToken: token.AccessToken, }) } func (c *CompositionRepository) setupPatient(req *model.CompositionRequest) (string, error) { if req.Subject.Reference == "" { return "", nil } patientInterface := NewPatientRepo(c.akses) patient, err := patientInterface.HandleCheckPatient(req.Subject.Reference) if err != nil { return "", err } if patient != "" { req.Subject.Reference = "Patient/" + patient } return patient, nil } // setupEncounter extracts encounter setup logic from CreateDiagnosisReport. func (c *CompositionRepository) setupEncounter(req *model.CompositionRequest, patient string) error { if patient == "" { return nil } encounterInterface := NewEncounterRepo(c.akses) encounterId, encounterExist, err := encounterInterface.HandleCheckEncounter(patient) if err != nil { return err } if encounterExist { req.Encounter.Reference = "Encounter/" + encounterId } else { //Buat dulu encounter } return nil } func (c *CompositionRepository) setupOrganization(req *model.CompositionRequest) error { req.Custodian.Reference = "Organization/" + os.Getenv("ORGANIZATION_ID") return nil } func (c *CompositionRepository) setupPractitioner(req *model.CompositionRequest) error { if len(req.Author) == 0 { return nil } practicionerInterface := NewPracticionerRepo(c.akses) ref, display, err := practicionerInterface.HandleCheckPartitioner(req.Author[0].Reference) if err != nil { return err } if ref != "" { req.Author[0].Reference = "Practitioner/" + ref req.Author[0].Display = display } return nil } func (c *CompositionRepository) setupAllergyIntollerance(patient string) string { if patient == "" { return "" } allergyInterface := NewAllergancyToleranRepo(c.akses) allergyId, allergyExist, err := allergyInterface.HandleCheckAllergancyToleran(patient) if err != nil { return "" } if allergyExist { return allergyId[0] } return "" } func (c *CompositionRepository) setupObservation(patient string) []model.Reference { if patient == "" { return nil } observationInterface := NewObservationRepo(c.akses) observationId, observationExist, err := observationInterface.HandleCheckObservation(patient) if err != nil { return nil } if observationExist { var references []model.Reference for _, id := range observationId { references = append(references, model.Reference{Reference: "Observation/" + id}) } return references } return nil } func (c *CompositionRepository) setupClinicalImpression(patient string) string { if patient == "" { return "" } clinicalInterface := NewClinicalImpressionRepo(c.akses) clinicalId, clinicalExist, err := clinicalInterface.HandleCheckClinicalImpression(patient) if err != nil { return "" } if clinicalExist { return clinicalId[0] } return "" } func (c *CompositionRepository) setupGoal(patient string) string { if patient == "" { return "" } goalInterface := NewGoalRepo(c.akses) goalId, goalExist, err := goalInterface.HandleCheckGoal(patient) if err != nil { return "" } if goalExist { return goalId[0] } return "" } func (c *CompositionRepository) setupCarePlan(patient string) string { if patient == "" { return "" } careplanInterface := NewCarePlanRepo(c.akses) careplanId, careplanExist, err := careplanInterface.HandleCheckCarePlan(patient) if err != nil { return "" } if careplanExist { return careplanId[0] } return "" } func (c *CompositionRepository) setupServiceRequestCategory(patient string, category string) string { if patient == "" { return "" } if category == "LAB" { category = "108252007" } else if category == "RAD" { category = "363679005" } serviceRequestInterface := NewServiceRequestRepository(c.akses) serviceRequestId, serviceRequestExist, err := serviceRequestInterface.HandleCheckServiceRequestByCategory(patient, category) if err != nil { return "" } if serviceRequestExist { return serviceRequestId[0] } return "" } func (c *CompositionRepository) setupSpecimenCategory(patient string) string { if patient == "" { return "" } specimenInterface := NewSpecimenRepository(c.akses) specimenId, specimenExist, err := specimenInterface.HandleCheckSpecimen(patient) if err != nil { return "" } if specimenExist { return specimenId[0] } return "" } func (c *CompositionRepository) setupImagingStudy(patient string) string { if patient == "" { return "" } imagingInterface := NewImagingStudyRepo(c.akses) imagingId, imagingExist, err := imagingInterface.HandleCheckImagingStudy(patient) if err != nil { return "" } if imagingExist { return imagingId[0] } return "" } func (c *CompositionRepository) setupObservationCategory(patient string, category string) string { if patient == "" { return "" } if category == "LAB" { category = "laboratory" } else if category == "RAD" { category = "imaging" } observationInterface := NewObservationRepo(c.akses) observationId, observationExist, err := observationInterface.HandleCheckObservationCategory(patient, category) if err != nil { return "" } if observationExist { return observationId[0] } return "" } func (c *CompositionRepository) setupDiagnosticCategory(patient string, category string) string { if patient == "" { return "" } if category == "LAB" { category = "LAB" } else if category == "RAD" { category = "RAD" } observationInterface := NewObservationRepo(c.akses) observationId, observationExist, err := observationInterface.HandleCheckObservationCategory(patient, category) if err != nil { return "" } if observationExist { return observationId[0] } return "" } func (c *CompositionRepository) setupCondition(patient string) string { if patient == "" { return "" } conditionInterface := NewConditionRepo(c.akses) conditionId, conditionExist, err := conditionInterface.HandleCheckCondition(patient) if err != nil { return "" } if conditionExist { return conditionId } return "" } func (c *CompositionRepository) setupProcedure(patient string) string { if patient == "" { return "" } procedureInterface := NewProcedureRepo(c.akses) procedureId, procedureExist, err := procedureInterface.HandleCheckProcedure(patient) if err != nil { return "" } if procedureExist { return procedureId[0] } return "" } func (c *CompositionRepository) setupMedicationRequest(patient string) string { if patient == "" { return "" } medicationRequestInterface := NewMedicationRequestRepo(c.akses) medicationRequestId, medicationRequestExist, err := medicationRequestInterface.HandleCheckMedicationRequest(patient, "") if err != nil { return "" } if medicationRequestExist { return medicationRequestId[0] } return "" } func (c *CompositionRepository) setupMedicationDispense(patient string) string { if patient == "" { return "" } medicationDispenseInterface := NewMedicationDispenseRepo(c.akses) medicationDispenseId, medicationDispenseExist, err := medicationDispenseInterface.HandleCheckMedicationDispense(patient, "") if err != nil { return "" } if medicationDispenseExist { return medicationDispenseId[0] } return "" } func NewCompositionRepo(akses *model.Akses) CompositionInterface { return &CompositionRepository{ akses: akses, } }