package integration import ( "bytes" "encoding/json" "errors" "fmt" "net/http" "os" "satusehat-rssa/internal/constant" "satusehat-rssa/internal/model" "satusehat-rssa/pkg/httputil" ) type EpisodeOfCareInterface interface { // Define methods for EpisodeOfCareInterface CreateEpisodeOfCare(req model.EpisodeOfCareRequest) (map[string]interface{}, error) GetEpisodeOfCareByPatient(id string) (map[string]interface{}, error) HandleCheckEpisodeOfCare(id string) ([]string, bool, error) UpdateEpisodeOfCare(req model.EpisodeOfCareRequest) (map[string]interface{}, error) } type EpisodeOfCareRepository struct { akses *model.Akses } // CreateEpisodeOfCare implements EpisodeOfCareInterface. func (e *EpisodeOfCareRepository) CreateEpisodeOfCare(req model.EpisodeOfCareRequest) (map[string]interface{}, error) { var data map[string]interface{} req.ResourceType = constant.EpisodeOfCareResourceType req.Identifier = []model.Identifier{ { System: "http://sys-ids.kemkes.go.id/episode-of-care/" + os.Getenv("ORGANIZATION_ID"), Value: os.Getenv("ORGANIZATION_ID"), }, } // Setup Patient var patient string if req.Patient.Reference != "" { patientInterface := NewPatientRepo(e.akses) var err error patient, err = patientInterface.HandleCheckPatient(req.Patient.Reference) if err != nil { return nil, err } if patient != "" { req.Patient.Reference = "Patient/" + patient } } // Setup Organization req.ManagingOrganization.Reference = "Organization/" + os.Getenv("ORGANIZATION_ID") req.ManagingOrganization.Display = os.Getenv("ORGANIZATION_NAME") var conditionReference model.Reference condition := e.setupCondition(patient) if condition != "" { conditionReference = model.Reference{ Reference: "Condition/" + condition, } } else { return nil, errors.New("condition not found for the patient") } req.Diagnosis = append(req.Diagnosis, model.Diagnosis{ Condition: conditionReference, }) // Setup CareManager // if req.CareManager.Reference != "" { // careManagerInterface := NewPracticionerRepo(e.akses) // careManagerId, _, err := careManagerInterface.HandleCheckPartitioner(req.CareManager.Reference) // if err != nil { // return nil, err // } // req.CareManager.Reference = "Practitioner/" + careManagerId // } // Setup Type url := e.akses.BaseUrl + "/EpisodeOfCare" method := "POST" jsonData, err := json.Marshal(req) if err != nil { return nil, err } client := &http.Client{} request, err := http.NewRequest(method, url, bytes.NewBuffer(jsonData)) if err != nil { return nil, err } oauth := model.OauthRequest{ ClientId: e.akses.ClientId, ClientSecret: e.akses.ClientSecret, } OauthInterface := NewOauthRequestRepo(e.akses) token, err := OauthInterface.GenerateToken(oauth) if err != nil { return nil, err } request.Header.Set("Authorization", "Bearer "+token.AccessToken) request.Header.Set("Content-Type", "application/json") response, err := client.Do(request) if err != nil { return nil, err } defer response.Body.Close() if err := json.NewDecoder(response.Body).Decode(&data); err != nil { return nil, err } if !hasOperationOutcomeIssue(data) { // Setup Encounter if patient != "" { encounterInterface := NewEncounterRepo(e.akses) encounterId, encounterExist, err := encounterInterface.HandleCheckEncounter(patient) if err != nil { return nil, err } if encounterExist { data["encounter"] = map[string]interface{}{ "reference": "Encounter/" + encounterId, } } else { return nil, errors.New("encounter not found") } } } return data, nil } // GetEpisodeOfCareByPatient implements EpisodeOfCareInterface. func (e *EpisodeOfCareRepository) GetEpisodeOfCareByPatient(id string) (map[string]interface{}, error) { var data map[string]interface{} // Validate the patient ID if id == "" { return nil, errors.New("patient ID cannot be empty") } // Construct the URL with query parameters url := e.akses.BaseUrl + "/EpisodeOfCare?patient=" + id method := "GET" client := &http.Client{} request, err := http.NewRequest(method, url, nil) if err != nil { return nil, err } oauth := model.OauthRequest{ ClientId: e.akses.ClientId, ClientSecret: e.akses.ClientSecret, } OauthInterface := NewOauthRequestRepo(e.akses) token, err := OauthInterface.GenerateToken(oauth) if err != nil { return nil, err } request.Header.Set("Authorization", "Bearer "+token.AccessToken) response, err := client.Do(request) if err != nil { return nil, err } defer response.Body.Close() if err := json.NewDecoder(response.Body).Decode(&data); err != nil { return nil, err } return data, nil } // HandleCheckEpisodeOfCare implements EpisodeOfCareInterface. func (e *EpisodeOfCareRepository) HandleCheckEpisodeOfCare(id string) ([]string, bool, error) { eoc, err := e.GetEpisodeOfCareByPatient(id) if err != nil { return nil, false, err } // You can process 'eoc' here if needed var ids []string if entries, ok := eoc["entry"].([]interface{}); ok && len(entries) != 0 { if entries, ok := (eoc)["entry"].([]interface{}); ok && len(entries) > 0 { if entryMap, ok := entries[0].(map[string]interface{}); ok { if resource, ok := entryMap["resource"].(map[string]interface{}); ok { if id, ok := resource["id"].(string); ok { //fmt.Println("resource.id:", id) ids = append(ids, id) return ids, true, nil } } } } return nil, true, nil } return nil, false, nil } func (e *EpisodeOfCareRepository) UpdateEpisodeOfCare(req model.EpisodeOfCareRequest) (map[string]interface{}, error) { req.ResourceType = constant.EpisodeOfCareResourceType // Setup Patient var patient string if req.Patient.Reference != "" { patientInterface := NewPatientRepo(e.akses) var err error patient, err = patientInterface.HandleCheckPatient(req.Patient.Reference) if err != nil { return nil, err } if patient != "" { req.Patient.Reference = "Patient/" + patient } } // Setup Organization if req.ManagingOrganization.Reference != "" { orgInterface := NewOrganizationRepo(e.akses) orgName, _, err := orgInterface.HandleCheckOrganization(req.ManagingOrganization.Reference) if err != nil { return nil, err } req.ManagingOrganization.Reference = "Organization/" + req.ManagingOrganization.Reference req.ManagingOrganization.Display = orgName } // Get id existing EpisodeOfCare data, err := e.setupPutEpisodeOfCare(&req, patient) if err != nil { return nil, err } if len(data["entry"].([]interface{})) == 0 { return nil, errors.New("episode of care not found") } // Setup CareManager // if req.CareManager.Reference != "" { // careManagerInterface := NewPracticionerRepo(e.akses) // careManagerId, _, err := careManagerInterface.HandleCheckPartitioner(req.CareManager.Reference) // if err != nil { // return nil, err // } // req.CareManager.Reference = "Practitioner/" + careManagerId // } // Setup Type oauth := model.OauthRequest{ ClientId: e.akses.ClientId, ClientSecret: e.akses.ClientSecret, } token, err := NewOauthRequestRepo(e.akses).GenerateToken(oauth) if err != nil { return nil, err } if token == nil { return nil, errors.New(constant.ErrGenerateToken) } url := e.akses.BaseUrl + fmt.Sprintf("/EpisodeOfCare/%s", req.Id) return httputil.DoRequest(httputil.RequestOption{ Method: "PUT", URL: url, Body: req, BearerToken: token.AccessToken, }) } func (e *EpisodeOfCareRepository) setupCondition(patient string) string { if patient == "" { return "" } conditionInterface := NewConditionRepo(e.akses) conditionId, conditionExist, err := conditionInterface.HandleCheckCondition(patient) if err != nil { return "" } if conditionExist { return conditionId } return "" } func (e *EpisodeOfCareRepository) setupPutEpisodeOfCare(req *model.EpisodeOfCareRequest, patient string) (map[string]interface{}, error) { data, err := e.GetEpisodeOfCareByPatient(patient) if err != nil { return nil, err } if entries, ok := data["entry"].([]interface{}); ok && len(entries) != 0 { if entries, ok := (data)["entry"].([]interface{}); ok && len(entries) > 0 { if entryMap, ok := entries[0].(map[string]interface{}); ok { if resource, ok := entryMap["resource"].(map[string]interface{}); ok { if id, ok := resource["id"].(string); ok { req.Id = id } } } } } return data, nil } // hasOperationOutcomeIssue returns true when the response is an OperationOutcome // with at least one issue that includes diagnostics or details.text. func hasOperationOutcomeIssue(resp map[string]interface{}) bool { if resp == nil { return false } rt, ok := resp["resourceType"].(string) if !ok || rt != "OperationOutcome" { return false } issues, ok := resp["issue"].([]interface{}) if !ok || len(issues) == 0 { return false } for _, it := range issues { m, ok := it.(map[string]interface{}) if !ok { continue } if diag, _ := m["diagnostics"].(string); diag != "" { return true } if details, ok := m["details"].(map[string]interface{}); ok { if txt, _ := details["text"].(string); txt != "" { return true } } } return false } func NewEpisodeOfCareRepo(akses *model.Akses) EpisodeOfCareInterface { return &EpisodeOfCareRepository{ akses: akses, } }