penambahan All case Satu sehat
This commit is contained in:
No files matched your search
@@ -1,14 +1,36 @@
|
||||
package episodeofcare
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"time"
|
||||
|
||||
"service/internal/satusehat/common"
|
||||
)
|
||||
|
||||
type EpisodeOfCareRequest struct {
|
||||
PatientID string `json:"patient_id" binding:"required"`
|
||||
PatientName string `json:"patient_name" binding:"required"`
|
||||
OrganizationID string `json:"organization_id" binding:"required"`
|
||||
Status string `json:"status" binding:"required,oneof=planned waitlist active onhold finished cancelled entered-in-error"` // planned, waitlist, active, onhold, finished, cancelled, entered-in-error
|
||||
PeriodStart time.Time `json:"period_start" binding:"required"`
|
||||
PeriodEnd *time.Time `json:"period_end,omitempty"`
|
||||
OrganizationID string `json:"organization_id,omitempty"`
|
||||
EpisodeOfCareID string `json:"episode_of_care_id,omitempty"` // cth: "EOC12345"
|
||||
Status string `json:"status" binding:"required,oneof=planned waitlist active onhold finished cancelled entered-in-error"`
|
||||
StatusHistory []StatusHistoryDTO `json:"status_history,omitempty"`
|
||||
Type []*common.CodeableConceptDTO `json:"type,omitempty"`
|
||||
Diagnosis []DiagnosisDTO `json:"diagnosis,omitempty"`
|
||||
PatientID string `json:"patient_id" binding:"required"`
|
||||
PatientName string `json:"patient_name,omitempty"`
|
||||
ManagingOrganization string `json:"managing_organization,omitempty"`
|
||||
PeriodStart *time.Time `json:"period_start,omitempty"`
|
||||
PeriodEnd *time.Time `json:"period_end,omitempty"`
|
||||
CareManager *common.ReferenceDTO `json:"care_manager,omitempty"`
|
||||
}
|
||||
|
||||
type StatusHistoryDTO struct {
|
||||
Status string `json:"status,omitempty"`
|
||||
PeriodStart *time.Time `json:"period_start,omitempty"`
|
||||
PeriodEnd *time.Time `json:"period_end,omitempty"`
|
||||
}
|
||||
|
||||
type DiagnosisDTO struct {
|
||||
Condition *common.ReferenceDTO `json:"condition,omitempty"`
|
||||
Role *common.CodeableConceptDTO `json:"role,omitempty"`
|
||||
Rank int `json:"rank,omitempty"`
|
||||
}
|
||||
|
||||
type EpisodeOfCarePatchRequest []map[string]interface{}
|
||||
@@ -1,30 +1,141 @@
|
||||
package episodeofcare
|
||||
|
||||
import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"service/internal/interfaces/satusehat"
|
||||
)
|
||||
|
||||
func MapRequestToFHIR(req EpisodeOfCareRequest) satusehat.FHIRPayload {
|
||||
payload := satusehat.NewFHIRPayload("EpisodeOfCare").
|
||||
Set("status", req.Status).
|
||||
Set("patient", map[string]interface{}{
|
||||
"reference": "Patient/" + req.PatientID,
|
||||
"display": req.PatientName,
|
||||
})
|
||||
payload := satusehat.NewFHIRPayload("EpisodeOfCare")
|
||||
|
||||
if req.OrganizationID != "" {
|
||||
orgID := os.Getenv("SATUSEHAT_ORG_ID")
|
||||
if orgID == "" {
|
||||
orgID = req.OrganizationID
|
||||
}
|
||||
|
||||
if orgID != "" && req.EpisodeOfCareID != "" {
|
||||
payload.Set("identifier", []map[string]interface{}{
|
||||
{
|
||||
"system": "http://sys-ids.kemkes.go.id/episode-of-care/" + orgID,
|
||||
"value": req.EpisodeOfCareID,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if req.Status != "" {
|
||||
payload.Set("status", req.Status)
|
||||
}
|
||||
|
||||
if len(req.StatusHistory) > 0 {
|
||||
var statusHistory []map[string]interface{}
|
||||
for _, sh := range req.StatusHistory {
|
||||
historyItem := map[string]interface{}{"status": sh.Status}
|
||||
period := map[string]interface{}{}
|
||||
if sh.PeriodStart != nil && !sh.PeriodStart.IsZero() {
|
||||
period["start"] = sh.PeriodStart.Format(time.RFC3339)
|
||||
}
|
||||
if sh.PeriodEnd != nil && !sh.PeriodEnd.IsZero() {
|
||||
period["end"] = sh.PeriodEnd.Format(time.RFC3339)
|
||||
}
|
||||
if len(period) > 0 {
|
||||
historyItem["period"] = period
|
||||
}
|
||||
statusHistory = append(statusHistory, historyItem)
|
||||
}
|
||||
payload.Set("statusHistory", statusHistory)
|
||||
}
|
||||
|
||||
if len(req.Type) > 0 {
|
||||
var types []map[string]interface{}
|
||||
for _, t := range req.Type {
|
||||
if t != nil {
|
||||
sys := t.System
|
||||
if sys == "" {
|
||||
sys = "http://terminology.kemkes.go.id/CodeSystem/episodeofcare-type"
|
||||
}
|
||||
coding := map[string]interface{}{"system": sys, "code": t.Code}
|
||||
if t.Display != "" {
|
||||
coding["display"] = t.Display
|
||||
}
|
||||
typeConcept := map[string]interface{}{"coding": []map[string]interface{}{coding}}
|
||||
if t.Text != "" {
|
||||
typeConcept["text"] = t.Text
|
||||
}
|
||||
types = append(types, typeConcept)
|
||||
}
|
||||
}
|
||||
payload.Set("type", types)
|
||||
}
|
||||
|
||||
if len(req.Diagnosis) > 0 {
|
||||
var diagnoses []map[string]interface{}
|
||||
for _, d := range req.Diagnosis {
|
||||
diagnosisItem := map[string]interface{}{}
|
||||
|
||||
if d.Condition != nil {
|
||||
condition := map[string]interface{}{"reference": d.Condition.Reference}
|
||||
if d.Condition.Display != "" {
|
||||
condition["display"] = d.Condition.Display
|
||||
}
|
||||
diagnosisItem["condition"] = condition
|
||||
}
|
||||
|
||||
if d.Role != nil {
|
||||
sys := d.Role.System
|
||||
if sys == "" {
|
||||
sys = "http://terminology.hl7.org/CodeSystem/diagnosis-role"
|
||||
}
|
||||
coding := map[string]interface{}{"system": sys, "code": d.Role.Code}
|
||||
if d.Role.Display != "" {
|
||||
coding["display"] = d.Role.Display
|
||||
}
|
||||
diagnosisItem["role"] = map[string]interface{}{"coding": []map[string]interface{}{coding}}
|
||||
}
|
||||
|
||||
if d.Rank > 0 {
|
||||
diagnosisItem["rank"] = d.Rank
|
||||
}
|
||||
|
||||
diagnoses = append(diagnoses, diagnosisItem)
|
||||
}
|
||||
payload.Set("diagnosis", diagnoses)
|
||||
}
|
||||
|
||||
if req.PatientID != "" {
|
||||
subject := map[string]interface{}{"reference": "Patient/" + req.PatientID}
|
||||
if req.PatientName != "" {
|
||||
subject["display"] = req.PatientName
|
||||
}
|
||||
payload.Set("patient", subject)
|
||||
}
|
||||
|
||||
manageOrg := orgID
|
||||
if req.ManagingOrganization != "" {
|
||||
manageOrg = req.ManagingOrganization
|
||||
}
|
||||
if manageOrg != "" {
|
||||
payload.Set("managingOrganization", map[string]interface{}{
|
||||
"reference": "Organization/" + req.OrganizationID,
|
||||
"reference": "Organization/" + manageOrg,
|
||||
})
|
||||
}
|
||||
|
||||
period := map[string]interface{}{"start": req.PeriodStart.Format(time.RFC3339)}
|
||||
if req.PeriodEnd != nil {
|
||||
period["end"] = req.PeriodEnd.Format(time.RFC3339)
|
||||
if req.PeriodStart != nil && !req.PeriodStart.IsZero() {
|
||||
period := map[string]interface{}{"start": req.PeriodStart.Format(time.RFC3339)}
|
||||
if req.PeriodEnd != nil && !req.PeriodEnd.IsZero() {
|
||||
period["end"] = req.PeriodEnd.Format(time.RFC3339)
|
||||
}
|
||||
payload.Set("period", period)
|
||||
}
|
||||
|
||||
if req.CareManager != nil {
|
||||
cm := map[string]interface{}{"reference": req.CareManager.Reference}
|
||||
if req.CareManager.Display != "" {
|
||||
cm["display"] = req.CareManager.Display
|
||||
}
|
||||
payload.Set("careManager", cm)
|
||||
}
|
||||
payload.Set("period", period)
|
||||
|
||||
return payload
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"service/internal/interfaces/satusehat"
|
||||
"service/pkg/errors"
|
||||
)
|
||||
|
||||
// Repository mendefinisikan kontrak untuk operasi penyimpanan data EpisodeOfCare.
|
||||
@@ -26,15 +27,22 @@ func NewRepository(client satusehat.SatuSehatClient) Repository {
|
||||
return &repository{client: client}
|
||||
}
|
||||
|
||||
type hiddenCtx struct {
|
||||
context.Context
|
||||
}
|
||||
|
||||
func (r *repository) executeRequest(ctx context.Context, method, endpoint string, req interface{}) (*satusehat.FHIRResponse, error) {
|
||||
resp, err := r.client.DoRequest(ctx, method, endpoint, req)
|
||||
resp, err := r.client.DoRequest(hiddenCtx{ctx}, method, endpoint, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.InternalError().Message("Failed to execute request to SatuSehat").Cause(err).Build()
|
||||
}
|
||||
|
||||
var result map[string]interface{}
|
||||
if err := json.Unmarshal(resp, &result); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
|
||||
return nil, errors.InternalError().Message("Failed to parse SatuSehat response").Cause(err).Metadata("raw_response", string(resp)).Build()
|
||||
}
|
||||
if resourceType, ok := result["resourceType"].(string); ok && resourceType == "OperationOutcome" {
|
||||
return nil, errors.ParseSatuSehatError(result)
|
||||
}
|
||||
|
||||
var resourceID string
|
||||
@@ -42,11 +50,7 @@ func (r *repository) executeRequest(ctx context.Context, method, endpoint string
|
||||
resourceID = id
|
||||
}
|
||||
|
||||
return &satusehat.FHIRResponse{
|
||||
ID: resourceID,
|
||||
FullResponse: result,
|
||||
RawResponse: resp,
|
||||
}, nil
|
||||
return &satusehat.FHIRResponse{ID: resourceID, FullResponse: result, RawResponse: resp}, nil
|
||||
}
|
||||
|
||||
func (r *repository) Create(ctx context.Context, payload interface{}) (*satusehat.FHIRResponse, error) {
|
||||
|
||||
@@ -26,19 +26,16 @@ func NewService(repo Repository) Service {
|
||||
}
|
||||
|
||||
func (s *service) Create(ctx context.Context, req EpisodeOfCareRequest) (*satusehat.FHIRResponse, error) {
|
||||
fhirPayload := MapRequestToFHIR(req)
|
||||
return s.repo.Create(ctx, fhirPayload)
|
||||
return s.repo.Create(ctx, MapRequestToFHIR(req))
|
||||
}
|
||||
|
||||
func (s *service) Update(ctx context.Context, id string, req EpisodeOfCareRequest) (*satusehat.FHIRResponse, error) {
|
||||
if id == "" {
|
||||
return nil, errors.NewValidationError().Message("EpisodeOfCare ID is required").Build()
|
||||
}
|
||||
|
||||
fhirPayload := MapRequestToFHIR(req)
|
||||
fhirPayload.Set("id", id)
|
||||
|
||||
return s.repo.Update(ctx, id, fhirPayload)
|
||||
payload := MapRequestToFHIR(req)
|
||||
payload.Set("id", id)
|
||||
return s.repo.Update(ctx, id, payload)
|
||||
}
|
||||
|
||||
func (s *service) Patch(ctx context.Context, id string, req EpisodeOfCarePatchRequest) (*satusehat.FHIRResponse, error) {
|
||||
|
||||
Reference in New Issue
Block a user