package encounter import ( "context" "fmt" "service/internal/infrastructure/database" "service/pkg/utils/query" ) // Repository mendefinisikan kontrak akses database untuk worker encounter type Repository interface { GetNextPendaftaran(ctx context.Context, lastID int64) (*PendaftaranDB, error) SaveSatuSehatID(ctx context.Context, idxdaftar int64, encounterID string) error SaveSyncLog(ctx context.Context, logData EncounterSyncLog) error } type repository struct { dbManager database.Service } func NewRepository(dbManager database.Service) Repository { return &repository{dbManager: dbManager} } func (r *repository) GetNextPendaftaran(ctx context.Context, lastID int64) (*PendaftaranDB, error) { var p PendaftaranDB // 1. Ambil koneksi database SQLX SIMRS (PostgreSQL) simrsDB, err := r.dbManager.GetSQLXDB("simrs") if err != nil { return nil, err } // Inisiasi Query Builder (Disable security check untuk penggunaan internal & static) qb := query.NewSQLQueryBuilder(query.DBTypePostgreSQL).SetSecurityOptions(false, 0).SetQueryLogging(false) // 2. Ambil data Pendaftaran Utama dari SIMRS menggunakan Query Builder qSimrs := query.DynamicQuery{ From: "public.t_pendaftaran", Aliases: "p", // Alias untuk tabel pendaftaran Fields: []query.SelectField{ {Expression: "p.idxdaftar"}, {Expression: "p.nomr"}, {Expression: "p.tglreg"}, {Expression: "p.kddokter"}, {Expression: "p.kdpoly"}, {Expression: "p.kdcarabayar"}, {Expression: "p.status"}, {Expression: "p.batal"}, {Expression: "p.jamreg"}, {Expression: "p.masukpoly"}, {Expression: "p.keluarpoly"}, {Expression: "m.nama"}, {Expression: "COALESCE(NULLIF(m.noktp_baru, ''), m.noktp) AS nik"}, }, Joins: []query.Join{ { Type: "LEFT", Table: "public.m_pasien", Alias: "m", // Alias untuk tabel master pasien OnConditions: query.FilterGroup{ Filters: []query.DynamicFilter{ // Relasi antar kolom: p.nomr = m.nomr query.CreateEqualFilter("p.nomr", "m.nomr"), }, }, }, }, Filters: []query.FilterGroup{ { Filters: []query.DynamicFilter{ query.CreateFilter("p.idxdaftar", query.OpGreaterThan, lastID), }, }, }, Sort: []query.SortField{ query.CreateAscSort("p.idxdaftar"), }, Limit: 1, } err = qb.ExecuteQueryRow(ctx, simrsDB, qSimrs, &p) if err != nil { return nil, err } // 3. Lengkapi referensi IHS Number dari tabel master SATUDATA menggunakan Query Builder satuDataDB, err := r.dbManager.GetSQLXDB("satudata") if err != nil { return nil, fmt.Errorf("gagal koneksi ke database satudata: %w", err) } if p.NoMR.Valid && p.NoMR.String != "" { qPasien := query.DynamicQuery{ From: "public.data_pasien", Fields: []query.SelectField{{Expression: "\"Nomor_satusehat\""}}, Filters: []query.FilterGroup{{Filters: []query.DynamicFilter{query.CreateEqualFilter("\"Nomor_rekamedik\"", p.NoMR.String)}}}, Limit: 1, } _ = qb.ExecuteQueryRow(ctx, satuDataDB, qPasien, &p.PatientIHS) } if p.KdDokter.Valid { qDokter := query.DynamicQuery{ From: "public.data_pegawai", Fields: []query.SelectField{ {Expression: "\"Kode_satusehat\"", Alias: "practitioner_ihs"}, {Expression: "nik", Alias: "practitioner_nik"}, // Sesuaikan "nik" jika nama kolom di DB Anda menggunakan huruf besar "\"NIK\"" }, Filters: []query.FilterGroup{{Filters: []query.DynamicFilter{query.CreateEqualFilter("\"Kode_DPJP\"", fmt.Sprintf("%d", p.KdDokter.Int64))}}}, Limit: 1, } _ = qb.ExecuteQueryRow(ctx, satuDataDB, qDokter, &p) } if p.KdPoly.Valid { qPoly := query.DynamicQuery{ From: "public.daftar_lokasi_ruang", Fields: []query.SelectField{{Expression: "\"Kode_satusehat\""}}, Filters: []query.FilterGroup{{Filters: []query.DynamicFilter{query.CreateEqualFilter("\"ID_ruang_simgos\"", fmt.Sprintf("%d", p.KdPoly.Int64))}}}, Limit: 1, } _ = qb.ExecuteQueryRow(ctx, satuDataDB, qPoly, &p.LocationIHS) } return &p, nil } func (r *repository) SaveSatuSehatID(ctx context.Context, idxdaftar int64, encounterID string) error { simrsDB, err := r.dbManager.GetSQLXDB("simrs") if err != nil { return err } // Menggunakan transaksi DB tx, err := simrsDB.BeginTxx(ctx, nil) if err != nil { return err } defer tx.Rollback() // Otomatis rollback bila gagal (atau tidak di-commit) qb := query.NewSQLQueryBuilder(query.DBTypePostgreSQL).SetSecurityOptions(false, 0).SetQueryLogging(false) updateData := query.UpdateData{ Columns: []string{"status_bridging"}, Values: []interface{}{encounterID}, } filters := []query.FilterGroup{ query.CreateAndFilterGroup([]query.DynamicFilter{query.CreateEqualFilter("idxdaftar", idxdaftar)}), } // Eksekusi Update via Query Builder (melempar tx, bukan db, agar terbawa ke transaksi) _, err = qb.ExecuteUpdate(ctx, tx, "public.t_pendaftaran", updateData, filters) if err != nil { return err } // Terapkan data return tx.Commit() } // SaveSyncLog menyimpan histori pengiriman (Request & Response) ke tabel log func (r *repository) SaveSyncLog(ctx context.Context, logData EncounterSyncLog) error { simrsDB, err := r.dbManager.GetSQLXDB("simrs") if err != nil { return err } qb := query.NewSQLQueryBuilder(query.DBTypePostgreSQL).SetSecurityOptions(false, 0).SetQueryLogging(false) insertData := query.InsertData{ Columns: []string{"idxdaftar", "encounter_id", "request_payload", "response_payload", "status", "error_message"}, Values: []interface{}{ logData.IdxDaftar, logData.EncounterID, logData.RequestPayload, logData.ResponsePayload, logData.Status, logData.ErrorMessage, }, } // Menggunakan UPSERT (ON CONFLICT) agar jika kita mengirim ulang (resend), log otomatis diperbarui conflictCols := []string{"idxdaftar"} updateCols := []string{"encounter_id", "request_payload", "response_payload", "status", "error_message"} _, err = qb.ExecuteUpsert(ctx, simrsDB, "public.log_satusehat_encounter", insertData, conflictCols, updateCols) return err }