package encounter import ( "context" "encoding/json" "fmt" "net/url" "os" "service/internal/interfaces/satusehat" "service/pkg/errors" ) type Service interface { Create(ctx context.Context, req EncounterRequest) (*satusehat.FHIRResponse, error) Update(ctx context.Context, id string, req EncounterRequest) (*satusehat.FHIRResponse, error) Patch(ctx context.Context, id string, req EncounterPatchRequest) (*satusehat.FHIRResponse, error) GetByID(ctx context.Context, id string) (*satusehat.FHIRResponse, error) Search(ctx context.Context, queryParams url.Values) (*satusehat.FHIRResponse, error) SyncFromSIMRS(ctx context.Context, idxdaftar int64) (*satusehat.FHIRResponse, error) } type service struct { repo Repository } func NewService(repo Repository) Service { return &service{repo: repo} } func (s *service) Create(ctx context.Context, req EncounterRequest) (*satusehat.FHIRResponse, error) { fhirPayload := MapRequestToFHIR(req) return s.repo.Create(ctx, fhirPayload) } func (s *service) Update(ctx context.Context, id string, req EncounterRequest) (*satusehat.FHIRResponse, error) { if id == "" { return nil, errors.NewValidationError().Message("Encounter ID is required").Build() } fhirPayload := MapRequestToFHIR(req) fhirPayload.Set("id", id) // Untuk Update (PUT), parameter ID di payload diwajibkan oleh standar API Kemenkes return s.repo.Update(ctx, id, fhirPayload) } func (s *service) Patch(ctx context.Context, id string, req EncounterPatchRequest) (*satusehat.FHIRResponse, error) { if id == "" { return nil, errors.NewValidationError().Message("Encounter 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("Encounter ID is required").Build() } return s.repo.GetByID(ctx, id) } func (s *service) Search(ctx context.Context, queryParams url.Values) (*satusehat.FHIRResponse, error) { // Bisa ditambahkan validasi query params wajib di sini jika perlu return s.repo.Search(ctx, queryParams) } func (s *service) SyncFromSIMRS(ctx context.Context, idxdaftar int64) (*satusehat.FHIRResponse, error) { // 1. Ambil data dari database SIMRS pendaftaran, err := s.repo.GetPendaftaranByID(ctx, idxdaftar) if err != nil { return nil, fmt.Errorf("gagal mengambil data pendaftaran: %w", err) } // 2. Ambil Organization ID RS Anda (Bisa dari environment variable atau parameter config) orgID := os.Getenv("SATUSEHAT_ORGANIZATION_ID") // Sesuaikan bila ada package config terpisah // 3. Persiapkan Patient ID (IHS) dengan fallback pencarian ke NIK patientIHS := pendaftaran.PatientIHS.String if patientIHS == "" && pendaftaran.PasienNIK.Valid && pendaftaran.PasienNIK.String != "" { resp, err := s.repo.SearchPatientByNIK(ctx, pendaftaran.PasienNIK.String) if err == nil && resp != nil { patientIHS = extractIDFromBundle(resp.RawResponse) } } if patientIHS == "" { // Fallback terakhir (jaga-jaga agar mapping tak panic) patientIHS = pendaftaran.NoMR.String } // 4. Persiapkan Practitioner ID (IHS) dengan fallback pencarian ke NIK practitionerIHS := pendaftaran.PractitionerIHS.String if practitionerIHS == "" && pendaftaran.DokterNIK.Valid && pendaftaran.DokterNIK.String != "" { resp, err := s.repo.SearchPractitionerByNIK(ctx, pendaftaran.DokterNIK.String) if err == nil && resp != nil { practitionerIHS = extractIDFromBundle(resp.RawResponse) } } if practitionerIHS == "" { // Fallback terakhir practitionerIHS = pendaftaran.DokterIDHFIS.String } // 5. Mapping data database ke struktur Request Encounter API req := MapPendaftaranToRequest(*pendaftaran, orgID, patientIHS, practitionerIHS) // 6. Proses Create/Kirim ke Satu Sehat menggunakan fungsi Create yang sudah ada return s.Create(ctx, req) } // extractIDFromBundle mem-parsing raw response FHIR Bundle untuk mengambil ID resource pertama func extractIDFromBundle(data []byte) string { var bundle struct { Entry []struct { Resource struct { ID string `json:"id"` } `json:"resource"` } `json:"entry"` } if err := json.Unmarshal(data, &bundle); err == nil && len(bundle.Entry) > 0 { return bundle.Entry[0].Resource.ID } return "" }