penambahan All case Satu sehat
This commit is contained in:
@@ -1,19 +1,27 @@
|
||||
package immunization
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"time"
|
||||
|
||||
"service/internal/satusehat/common"
|
||||
)
|
||||
|
||||
type ImmunizationRequest struct {
|
||||
PatientID string `json:"patient_id" binding:"required"`
|
||||
PatientName string `json:"patient_name" binding:"required"`
|
||||
EncounterID string `json:"encounter_id" binding:"required"`
|
||||
Status string `json:"status" binding:"required,oneof=completed entered-in-error not-done"`
|
||||
VaccineCode string `json:"vaccine_code" binding:"required"` // KFA Code for Vaccine
|
||||
VaccineDisplay string `json:"vaccine_display" binding:"required"`
|
||||
OccurrenceDateTime time.Time `json:"occurrence_date_time" binding:"required"`
|
||||
PrimarySource bool `json:"primary_source"`
|
||||
LotNumber string `json:"lot_number,omitempty"`
|
||||
PractitionerID string `json:"practitioner_id" binding:"required"`
|
||||
PractitionerName string `json:"practitioner_name" binding:"required"`
|
||||
OrganizationID string `json:"organization_id,omitempty"`
|
||||
ImmunizationID string `json:"immunization_id,omitempty"`
|
||||
Status string `json:"status" binding:"required,oneof=completed entered-in-error not-done"`
|
||||
VaccineCode *common.CodeableConceptDTO `json:"vaccine_code" binding:"required"`
|
||||
PatientID string `json:"patient_id" binding:"required"`
|
||||
PatientName string `json:"patient_name,omitempty"`
|
||||
EncounterID string `json:"encounter_id" binding:"required"`
|
||||
EncounterDisplay string `json:"encounter_display,omitempty"`
|
||||
OccurrenceDateTime *time.Time `json:"occurrence_date_time,omitempty"`
|
||||
PrimarySource *bool `json:"primary_source,omitempty"`
|
||||
LotNumber string `json:"lot_number,omitempty"`
|
||||
Performer []common.ReferenceDTO `json:"performer,omitempty"`
|
||||
Location *common.ReferenceDTO `json:"location,omitempty"`
|
||||
DoseQuantity *common.QuantityDTO `json:"dose_quantity,omitempty"`
|
||||
Route *common.CodeableConceptDTO `json:"route,omitempty"`
|
||||
}
|
||||
|
||||
type ImmunizationPatchRequest []map[string]interface{}
|
||||
|
||||
@@ -1,33 +1,126 @@
|
||||
package immunization
|
||||
|
||||
import (
|
||||
"service/internal/interfaces/satusehat"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"service/internal/interfaces/satusehat"
|
||||
)
|
||||
|
||||
func MapRequestToFHIR(req ImmunizationRequest) satusehat.FHIRPayload {
|
||||
payload := satusehat.NewFHIRPayload("Immunization").
|
||||
Set("status", req.Status).
|
||||
Set("vaccineCode", map[string]interface{}{
|
||||
"coding": []map[string]interface{}{
|
||||
{"system": "http://sys-ids.kemkes.go.id/kfa", "code": req.VaccineCode, "display": req.VaccineDisplay},
|
||||
},
|
||||
}).
|
||||
Set("patient", map[string]interface{}{"reference": "Patient/" + req.PatientID, "display": req.PatientName}).
|
||||
Set("encounter", map[string]interface{}{"reference": "Encounter/" + req.EncounterID}).
|
||||
Set("occurrenceDateTime", req.OccurrenceDateTime.Format(time.RFC3339)).
|
||||
Set("primarySource", req.PrimarySource).
|
||||
Set("performer", []map[string]interface{}{
|
||||
payload := satusehat.NewFHIRPayload("Immunization")
|
||||
|
||||
orgID := os.Getenv("SATUSEHAT_ORG_ID")
|
||||
if orgID == "" {
|
||||
orgID = req.OrganizationID
|
||||
}
|
||||
|
||||
if orgID != "" && req.ImmunizationID != "" {
|
||||
payload.Set("identifier", []map[string]interface{}{
|
||||
{
|
||||
"actor": map[string]interface{}{
|
||||
"reference": "Practitioner/" + req.PractitionerID,
|
||||
"display": req.PractitionerName,
|
||||
},
|
||||
"system": "http://sys-ids.kemkes.go.id/immunization/" + orgID,
|
||||
"use": "official",
|
||||
"value": req.ImmunizationID,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if req.Status != "" {
|
||||
payload.Set("status", req.Status)
|
||||
}
|
||||
|
||||
if req.VaccineCode != nil {
|
||||
sys := req.VaccineCode.System
|
||||
if sys == "" {
|
||||
sys = "http://sys-ids.kemkes.go.id/kfa"
|
||||
}
|
||||
coding := map[string]interface{}{"system": sys, "code": req.VaccineCode.Code}
|
||||
if req.VaccineCode.Display != "" {
|
||||
coding["display"] = req.VaccineCode.Display
|
||||
}
|
||||
vaccineConcept := map[string]interface{}{"coding": []map[string]interface{}{coding}}
|
||||
if req.VaccineCode.Text != "" {
|
||||
vaccineConcept["text"] = req.VaccineCode.Text
|
||||
}
|
||||
payload.Set("vaccineCode", vaccineConcept)
|
||||
}
|
||||
|
||||
if req.PatientID != "" {
|
||||
subj := map[string]interface{}{"reference": "Patient/" + req.PatientID}
|
||||
if req.PatientName != "" {
|
||||
subj["display"] = req.PatientName
|
||||
}
|
||||
payload.Set("patient", subj)
|
||||
}
|
||||
|
||||
if req.EncounterID != "" {
|
||||
enc := map[string]interface{}{"reference": "Encounter/" + req.EncounterID}
|
||||
if req.EncounterDisplay != "" {
|
||||
enc["display"] = req.EncounterDisplay
|
||||
}
|
||||
payload.Set("encounter", enc)
|
||||
}
|
||||
|
||||
if req.OccurrenceDateTime != nil && !req.OccurrenceDateTime.IsZero() {
|
||||
payload.Set("occurrenceDateTime", req.OccurrenceDateTime.Format(time.RFC3339))
|
||||
}
|
||||
|
||||
if req.PrimarySource != nil {
|
||||
payload.Set("primarySource", *req.PrimarySource)
|
||||
}
|
||||
|
||||
if req.Location != nil {
|
||||
loc := map[string]interface{}{"reference": req.Location.Reference}
|
||||
if req.Location.Display != "" {
|
||||
loc["display"] = req.Location.Display
|
||||
}
|
||||
payload.Set("location", loc)
|
||||
}
|
||||
|
||||
if req.LotNumber != "" {
|
||||
payload.Set("lotNumber", req.LotNumber)
|
||||
}
|
||||
|
||||
if len(req.Performer) > 0 {
|
||||
var performers []map[string]interface{}
|
||||
for _, p := range req.Performer {
|
||||
actor := map[string]interface{}{"reference": p.Reference}
|
||||
if p.Display != "" {
|
||||
actor["display"] = p.Display
|
||||
}
|
||||
performers = append(performers, map[string]interface{}{"actor": actor})
|
||||
}
|
||||
payload.Set("performer", performers)
|
||||
}
|
||||
|
||||
if req.DoseQuantity != nil {
|
||||
sys := req.DoseQuantity.System
|
||||
if sys == "" {
|
||||
sys = "http://terminology.hl7.org/CodeSystem/v3-orderableDrugForm"
|
||||
}
|
||||
payload.Set("doseQuantity", map[string]interface{}{
|
||||
"value": req.DoseQuantity.Value,
|
||||
"unit": req.DoseQuantity.Unit,
|
||||
"system": sys,
|
||||
"code": req.DoseQuantity.Code,
|
||||
})
|
||||
}
|
||||
|
||||
if req.Route != nil {
|
||||
sys := req.Route.System
|
||||
if sys == "" {
|
||||
sys = "http://www.whocc.no/atc"
|
||||
}
|
||||
coding := map[string]interface{}{"system": sys, "code": req.Route.Code}
|
||||
if req.Route.Display != "" {
|
||||
coding["display"] = req.Route.Display
|
||||
}
|
||||
routeConcept := map[string]interface{}{"coding": []map[string]interface{}{coding}}
|
||||
if req.Route.Text != "" {
|
||||
routeConcept["text"] = req.Route.Text
|
||||
}
|
||||
payload.Set("route", routeConcept)
|
||||
}
|
||||
|
||||
return payload
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"service/internal/interfaces/satusehat"
|
||||
"service/pkg/errors"
|
||||
)
|
||||
|
||||
type Repository interface {
|
||||
@@ -19,14 +20,21 @@ type repository struct{ client satusehat.SatuSehatClient }
|
||||
|
||||
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
|
||||
if id, ok := result["id"].(string); ok {
|
||||
|
||||
@@ -24,12 +24,23 @@ func (s *service) Update(ctx context.Context, id string, req ImmunizationRequest
|
||||
if id == "" {
|
||||
return nil, errors.NewValidationError().Message("ID is required").Build()
|
||||
}
|
||||
return s.repo.Update(ctx, id, MapRequestToFHIR(req).Set("id", id))
|
||||
payload := MapRequestToFHIR(req)
|
||||
payload.Set("id", id)
|
||||
return s.repo.Update(ctx, id, payload)
|
||||
}
|
||||
func (s *service) Patch(ctx context.Context, id string, req ImmunizationPatchRequest) (*satusehat.FHIRResponse, error) {
|
||||
if id == "" {
|
||||
return nil, errors.NewValidationError().Message("ID is required").Build()
|
||||
}
|
||||
if len(req) == 0 {
|
||||
return nil, errors.NewValidationError().Message("Patch payload cannot be empty").Build()
|
||||
}
|
||||
return s.repo.Patch(ctx, id, req)
|
||||
}
|
||||
func (s *service) GetByID(ctx context.Context, id string) (*satusehat.FHIRResponse, error) {
|
||||
if id == "" {
|
||||
return nil, errors.NewValidationError().Message("ID is required").Build()
|
||||
}
|
||||
return s.repo.GetByID(ctx, id)
|
||||
}
|
||||
func (s *service) Search(ctx context.Context, queryParams url.Values) (*satusehat.FHIRResponse, error) {
|
||||
|
||||
Reference in New Issue
Block a user