diff --git a/internal/domain/simgos-entities/m-pasien/dto.go b/internal/domain/simgos-entities/m-pasien/dto.go new file mode 100644 index 00000000..8d2c3368 --- /dev/null +++ b/internal/domain/simgos-entities/m-pasien/dto.go @@ -0,0 +1,273 @@ +package m_pasien + +import ( + "fmt" + ecore "simrs-vx/internal/domain/base-entities/core" + e "simrs-vx/internal/domain/main-entities/patient" + pr "simrs-vx/internal/domain/main-entities/person" + pa "simrs-vx/internal/domain/main-entities/person-address" + pab "simrs-vx/internal/domain/main-entities/person-address/base" + pc "simrs-vx/internal/domain/main-entities/person-contact" + rf "simrs-vx/internal/domain/references/person" + + "time" +) + +type MPasienDto struct { + Id uint `json:"id" gorm:"primaryKey;autoIncrement;column:id"` + Nomr string `json:"nomr" gorm:"uniqueIndex;column:nomr"` + Title string `json:"title" gorm:"column:title"` + Nama string `json:"nama" gorm:"column:nama"` + Tempat string `json:"tempat" gorm:"column:tempat"` + Tgllahir string `json:"tgllahir" gorm:"column:tgllahir"` + Jeniskelamin string `json:"jeniskelamin" gorm:"column:jeniskelamin"` + Alamat string `json:"alamat" gorm:"column:alamat"` + Kelurahan uint64 `json:"kelurahan" gorm:"column:kelurahan"` + Kdkecamatan uint `json:"kdkecamatan" gorm:"column:kdkecamatan"` + Kota uint `json:"kota" gorm:"column:kota"` + Kdprovinsi uint `json:"kdprovinsi" gorm:"column:kdprovinsi"` + Notelp string `json:"notelp" gorm:"column:notelp"` + Noktp string `json:"noktp" gorm:"column:noktp"` + SuamiOrtu *string `json:"suami_ortu" gorm:"column:suami_ortu"` + Pekerjaan string `json:"pekerjaan" gorm:"column:pekerjaan"` + Status uint `json:"status" gorm:"column:status"` + Agama uint `json:"agama" gorm:"column:agama"` + Pendidikan uint `json:"pendidikan" gorm:"column:pendidikan"` + Kdcarabayar *uint `json:"kdcarabayar" gorm:"column:kdcarabayar"` + Nip *string `json:"nip" gorm:"column:nip"` + Tgldaftar string `json:"tgldaftar" gorm:"column:tgldaftar"` + AlamatKtp string `json:"alamat_ktp" gorm:"column:alamat_ktp"` + ParentNomr *string `json:"parent_nomr" gorm:"column:parent_nomr"` + Kepercayaan string `json:"kepercayaan" gorm:"column:kepercayaan"` + PenanggungjawabNama string `json:"penanggungjawab_nama" gorm:"column:penanggungjawab_nama"` + PenanggungjawabHubungan string `json:"penanggungjawab_hubungan" gorm:"column:penanggungjawab_hubungan"` + PenanggungjawabAlamat string `json:"penanggungjawab_alamat" gorm:"column:penanggungjawab_alamat"` + PenanggungjawabPhone string `json:"penanggungjawab_phone" gorm:"column:penanggungjawab_phone"` + NoKartu string `json:"no_kartu" gorm:"column:no_kartu"` + JnsPasien string `json:"jns_pasien" gorm:"column:jns_pasien"` + Nk *string `json:"nk" gorm:"column:nk"` + Kdprovider *string `json:"kdprovider" gorm:"column:kdprovider"` + Nmprovider *string `json:"nmprovider" gorm:"column:nmprovider"` + Kelas *uint `json:"kelas" gorm:"column:kelas"` + Sim *string `json:"sim" gorm:"column:sim"` + Paspor *string `json:"paspor" gorm:"column:paspor"` + Disabilitas *string `json:"disabilitas" gorm:"column:disabilitas"` + Bahasa string `json:"bahasa" gorm:"column:bahasa"` + HambatanKomunikasi string `json:"hambatan_komunikasi" gorm:"column:hambatan_komunikasi"` + Kebangsaan string `json:"kebangsaan" gorm:"column:kebangsaan"` + Notelprumah1 string `json:"notelprumah1" gorm:"column:notelprumah1"` + Notelprumah2 *string `json:"notelprumah2" gorm:"column:notelprumah2"` + Notelpkantor string `json:"notelpkantor" gorm:"column:notelpkantor"` + NoHp *string `json:"no_hp" gorm:"column:no_hp"` + AsalMasuk *string `json:"asal_masuk" gorm:"column:asal_masuk"` + Diagnosa *string `json:"diagnosa" gorm:"column:diagnosa"` + DiagnosaUtama *string `json:"diagnosa_utama" gorm:"column:diagnosa_utama"` + Suku string `json:"suku" gorm:"column:suku"` + AgamaLain string `json:"agama_lain" gorm:"column:agama_lain"` + StDisabilitas uint `json:"stDisabilitas" gorm:"column:st_disabilitas"` + TxtKelurahan string `json:"txt_kelurahan" gorm:"column:txt_kelurahan"` + TxtKecamatan string `json:"txt_kecamatan" gorm:"column:txt_kecamatan"` + TxtKota string `json:"txt_kota" gorm:"column:txt_kota"` + TxtProvinsi string `json:"txt_provinsi" gorm:"column:txt_provinsi"` + TxtStatus string `json:"txt_status" gorm:"column:txt_status"` + TxtAgama string `json:"txt_agama" gorm:"column:txt_agama"` + TxtPendidikan string `json:"txt_pendidikan" gorm:"column:txt_pendidikan"` + NamaAyah string `json:"nama_ayah" gorm:"column:nama_ayah"` + NamaIbu string `json:"nama_ibu" gorm:"column:nama_ibu"` + PendidikanAyah string `json:"pendidikan_ayah" gorm:"column:pendidikan_ayah"` + PendidikanIbu string `json:"pendidikan_ibu" gorm:"column:pendidikan_ibu"` + StIdentitasOrtu int `json:"st_identitas_ortu" gorm:"column:st_identitas_ortu"` + NomrBaru *string `json:"nomr_baru" gorm:"column:nomr_baru"` + KtpFile *string `json:"ktp_file" gorm:"column:ktp_file"` + KkFile *string `json:"kk_file" gorm:"column:kk_file"` + CreatedAt *time.Time `json:"created_at" gorm:"column:created_at"` + UpdatedAt *time.Time `json:"updated_at" gorm:"column:updated_at"` + NoKk *string `json:"no_kk" gorm:"column:no_kk"` + NoktpBaru string `json:"noktp_baru" gorm:"column:noktp_baru"` +} + +func (mp MPasienDto) ToPatient() e.Patient { + + patient := e.Patient{ + Main: ecore.Main{ + Id: mp.Id, + }, + NewBornStatus: mp.ParentNomr != nil, + RegisteredAt: parseTimeDateOnly(mp.Tgldaftar), + RegisteredBy_User_Name: mp.Nip, + Number: &mp.Nomr, + Parent_Number: mp.ParentNomr, + // Status_Code: getActiveStatus(mp.Status), + // mp.Status is marital status + // Parent + } + + // person + gc := getGender(mp.Jeniskelamin) + rc := getReligion(mp.Agama) + ec := getEducation(mp.Pendidikan) + mc := getMaritalStatus(mp.Status) + bc := getBirthRegencyCode(mp.Tempat) + et := getEthnicCode(mp.Suku) + lc := getLanguageCode(mp.Bahasa) + + person := pr.Person{ + Name: mp.Nama, + FrontTitle: &mp.Title, + BirthDate: parseTimeDateOnly(mp.Tgllahir), + BirthRegency_Code: &bc, + Gender_Code: &gc, + ResidentIdentityNumber: nilEmptyString(&mp.Noktp), + PassportNumber: nilEmptyString(mp.Paspor), + DrivingLicenseNumber: nilEmptyString(mp.Sim), + Religion_Code: &rc, + Education_Code: &ec, + Ocupation_Name: &mp.Pekerjaan, + MaritalStatus_Code: &mc, + Nationality: &mp.Kebangsaan, + Ethnic_Code: &et, + Language_Code: &lc, + CommunicationIssueStatus: mp.HambatanKomunikasi == "Y", + Disability: mp.Disabilitas, + ResidentIdentityFileUrl: mp.KtpFile, + FamilyIdentityFileUrl: mp.KkFile, + // EndTitle + // Confidence + // Ocupation_Code + } + var addresses []pa.PersonAddress + if mp.Alamat != "" { + vc := fmt.Sprintf("%d", mp.Kelurahan) + addresses = append(addresses, pa.PersonAddress{ + PersonAddress: pab.PersonAddress{ + Address: mp.Alamat, + LocationType_Code: rf.ALTCDom, + Village_Code: &vc, + }, + }) + } + if mp.AlamatKtp != "" { + addresses = append(addresses, pa.PersonAddress{ + PersonAddress: pab.PersonAddress{ + Address: mp.AlamatKtp, + LocationType_Code: rf.ALTCIdn, + }, + }) + } + + var contacts []pc.PersonContact + + if mp.NoHp != nil { + + } + + person.Addresses = &addresses + person.Contacts = &contacts + patient.Person = &person + return patient +} + +func nilEmptyString(s *string) *string { + if s == nil { + return nil + } + return s +} + +func getGender(g string) rf.GenderCode { + if g == "L" { + return rf.GCMale + } else if g == "P" { + return rf.GCFemale + } + return rf.GCUnknown + +} + +func getReligion(r uint) rf.ReligionCode { + switch r { + case 1: + return rf.RCIslam + case 2: + return rf.RCProtestan + case 3: + return rf.RCKatolik + case 4: + return rf.RCHindu + case 5: + return rf.RCBudha + case 6: + return rf.RCKonghucu + default: + // 9 "Lainnya" + // 0 "Tidak diketahui" + return "" + } +} + +func getEducation(e uint) rf.EducationCode { + switch e { + case 0: + return rf.ECTS + case 1: + return rf.ECSD + case 2: + return rf.ECSLTP + case 3: + return rf.ECSLTA + case 4: + return rf.ECD3 + case 5: + return rf.ECS1 + case 6: + return rf.ECOther + case 7: + return rf.ECUnkown + default: + return rf.ECUnkown + } +} + +func getMaritalStatus(m uint) rf.MaritalStatusCode { + switch m { + case 1: + return rf.MaritalStatusSingle // S + case 2: + return rf.MaritalStatusMarried // M + case 3: + return rf.MaritalStatusWidowed // W + case 4: + return rf.MaritalStatusDivorced // D + default: + return "" // unknown + } +} + +func getBirthRegencyCode(r string) string { + if r != "" { + // TODO get from database + } + return "3574" +} + +func getEthnicCode(s string) string { + if s != "" { + // TODO check database + } + return "jawa" +} + +func getLanguageCode(s string) string { + if s != "" { + // TODO check database + } + return "jawa" +} + +func parseTimeDateOnly(d string) *time.Time { + do, err := time.Parse("2006-01-02", d) + if err == nil { + return &do + } + return nil +} diff --git a/internal/interface/simgos-sync-handler/old/patient/handler.go b/internal/interface/simgos-sync-handler/old/patient/handler.go new file mode 100644 index 00000000..4c697fd4 --- /dev/null +++ b/internal/interface/simgos-sync-handler/old/patient/handler.go @@ -0,0 +1,48 @@ +package patient + +import ( + "net/http" + + p "simrs-vx/internal/domain/simgos-entities/m-pasien" + uo "simrs-vx/internal/use-case/simgos-sync-use-case/old/patient" + + rw "github.com/karincake/risoles" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := p.MPasienDto{} + if !rw.ValidateStructByIOR(w, r.Body, &dto) { + return + } + + // mapping m_patient to patient + patient := dto.ToPatient() + res, err := uo.Create(patient) + rw.DataResponse(w, res, err) + +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + + dto := p.MPasienDto{} + if !rw.ValidateStructByIOR(w, r.Body, &dto) { + return + } + patient := dto.ToPatient() + res, err := uo.Update(patient) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + dto := p.MPasienDto{} + if !rw.ValidateStructByIOR(w, r.Body, &dto) { + return + } + patient := dto.ToPatient() + res, err := uo.Delete(patient) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/simgos-sync-handler/simgos-sync-handler.go b/internal/interface/simgos-sync-handler/simgos-sync-handler.go index 62e3e615..a47b38d4 100644 --- a/internal/interface/simgos-sync-handler/simgos-sync-handler.go +++ b/internal/interface/simgos-sync-handler/simgos-sync-handler.go @@ -30,6 +30,8 @@ import ( "simrs-vx/internal/interface/simgos-sync-handler/new/subspecialist" "simrs-vx/internal/interface/simgos-sync-handler/new/unit" + oldpatient "simrs-vx/internal/interface/simgos-sync-handler/old/patient" + oauth "simrs-vx/internal/interface/simgos-sync-handler/old/authentication" // just a reminder, an openauth ) @@ -76,7 +78,10 @@ func SetRoutes() http.Handler { /******************** SvcToNew ******************/ prefixold := "/old-to-new" - hk.GroupRoutes(prefixold+"/v1/patient", r, oauth.OldGuardMW, hk.MapHandlerFunc{}) // FINISH THIS - + hk.GroupRoutes(prefixold+"/v1/patient", r, oauth.OldGuardMW, hk.MapHandlerFunc{ + "POST /": oldpatient.O.Create, + "PATCH /{id}": oldpatient.O.Update, + "DELETE /{id}": oldpatient.O.Delete, + }) // FINISH THIS return cmw.SetCors(handlerlogger.SetLog(r)) } diff --git a/internal/use-case/simgos-sync-use-case/old/patient/case.go b/internal/use-case/simgos-sync-use-case/old/patient/case.go new file mode 100644 index 00000000..09afa2bd --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/old/patient/case.go @@ -0,0 +1,165 @@ +package patient + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + + cfg "simrs-vx/internal/infra/sync-cfg" + pl "simrs-vx/pkg/logger" + + e "simrs-vx/internal/domain/main-entities/patient" + un "simrs-vx/internal/use-case/simgos-sync-use-case/new/patient" + + d "github.com/karincake/dodol" +) + +const source = "old-to-new-patient" + +var path = "patient" + +func Create(input e.Patient) (*d.Data, error) { + evt := pl.Event{ + Feature: "Create", + Source: source, + } + + pl.SetLogInfo(&evt, input, "started", "create") + + // create request body + jsonPatient, err := json.Marshal(input) + if err != nil { + return nil, pl.SetLogError(&evt, input) + } + reqBody := bytes.NewBuffer(jsonPatient) + // send data to main-api + resp, err := send(http.MethodPost, path, reqBody, *input.RegisteredBy_User_Name) + if err != nil { + return nil, pl.SetLogError(&evt, input) + } + // getting response + var data MainApiResp + err = json.Unmarshal(resp, &data) + if err != nil { + return nil, pl.SetLogError(&evt, string(resp)) + } + // create PatientLink + un.CreateLinkData(data.Data.Id, input.Id, &evt) + pl.SetLogInfo(&evt, nil, "complete") + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + Data: input.ToResponse(), + }, nil +} + +func Update(input e.Patient) (*d.Data, error) { + evt := pl.Event{ + Feature: "Update", + Source: source, + } + pl.SetLogInfo(&evt, input, "started", "update") + + // get patient link from database + patientLink, err := ReadDetailLinkData(input.Id) + if err != nil { + return nil, pl.SetLogError(&evt, input) + } + + // get data patient from main-api + resp, err := send(http.MethodGet, fmt.Sprintf("%s%v", "patient/", patientLink.Simx_Id), nil, *input.RegisteredBy_User_Name) + if err != nil { + return nil, pl.SetLogError(&evt, input) + } + // unpack data from resp + var respData MainApiResp + err = json.Unmarshal(resp, &respData) + if err != nil { + return nil, pl.SetLogError(&evt, input) + } + + // copy data from simgos m_patient to simx Patient + preserve := map[string]bool{ + "Main.Id": true, + "Person.Id": true, + } + simxPatient := respData.Data + SetPatient(&simxPatient, &input, preserve) + + jsonPatient, err := json.Marshal(simxPatient) + if err != nil { + return nil, pl.SetLogError(&evt, input) + } + + // send data to main api + url := fmt.Sprintf("%s%v", "patient/", simxPatient.Id) + reqBody := bytes.NewBuffer(jsonPatient) + _, err = send(http.MethodPatch, url, reqBody, *input.RegisteredBy_User_Name) + if err != nil { + return nil, pl.SetLogError(&evt, input) + } + + pl.SetLogInfo(&evt, nil, "complete") + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + Data: input.ToResponse(), + }, nil +} + +func Delete(input e.Patient) (*d.Data, error) { + evt := pl.Event{ + Feature: "Delete", + Source: source, + } + pl.SetLogInfo(&evt, input, "started", "delete") + + // get patient link from database + patientLink, err := ReadDetailLinkData(input.Id) + if err != nil { + return nil, err + } + _, err = send(http.MethodDelete, fmt.Sprintf("%s%v", "patient/", patientLink.Simx_Id), nil, *input.RegisteredBy_User_Name) + if err != nil { + return nil, err + } + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + Data: input.ToResponse(), + }, nil +} + +func send(method string, endpoint string, body *bytes.Buffer, username string) ([]byte, error) { + var url string = cfg.O.NewHost + endpoint + var reader io.Reader = nil + if body != nil { + reader = body + } + req, err := http.NewRequest(method, url, reader) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/json") + req.Header.Set("X-Sync-Source", cfg.O.OldSource) + req.Header.Set("X-Sync-SecretKey", cfg.O.NewSecretKey) + req.Header.Set("X-Sync-UserName", username) + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + respBody, _ := io.ReadAll(resp.Body) + return respBody, nil +} diff --git a/internal/use-case/simgos-sync-use-case/old/patient/helper.go b/internal/use-case/simgos-sync-use-case/old/patient/helper.go new file mode 100644 index 00000000..2d89bff9 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/old/patient/helper.go @@ -0,0 +1,69 @@ +package patient + +import ( + "reflect" + "strings" +) + +func SetPatient(dst, src interface{}, preserve map[string]bool) { + dv := reflect.ValueOf(dst).Elem() + sv := reflect.ValueOf(src).Elem() + + for i := 0; i < dv.NumField(); i++ { + f := dv.Type().Field(i) + fieldName := f.Name + + // skip preserved fields + if preserve[fieldName] { + continue + } + + df := dv.Field(i) + sf := sv.Field(i) + if !df.CanSet() { + // skip unexported skip + continue + } + + switch df.Kind() { + + case reflect.Struct: + nestedPreserve := map[string]bool{} + + for key := range preserve { + if strings.HasPrefix(key, fieldName+".") { + nestedPreserve[strings.TrimPrefix(key, fieldName+".")] = true + } + } + + SetPatient(df.Addr().Interface(), sf.Addr().Interface(), nestedPreserve) + case reflect.Pointer: + // Check if pointer points to a struct + if df.Type().Elem().Kind() == reflect.Struct { + if sf.IsNil() { + break + } + + // If dest pointer is nil, allocate it + if df.IsNil() { + df.Set(reflect.New(df.Type().Elem())) + } + + // Recurse into struct via Elem() + nestedPreserve := map[string]bool{} + for key := range preserve { + if strings.HasPrefix(key, fieldName+".") { + nestedPreserve[strings.TrimPrefix(key, fieldName+".")] = true + } + } + + SetPatient(df.Elem().Addr().Interface(), sf.Elem().Addr().Interface(), nestedPreserve) + } + default: + // Overwrite only when src has non-zero value + if !sf.IsZero() { + df.Set(sf) + } + } + } +} diff --git a/internal/use-case/simgos-sync-use-case/old/patient/lib.go b/internal/use-case/simgos-sync-use-case/old/patient/lib.go new file mode 100644 index 00000000..d6b5f470 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/old/patient/lib.go @@ -0,0 +1,19 @@ +package patient + +import ( + esync "simrs-vx/internal/domain/sync-entities/patient" + + dg "github.com/karincake/apem/db-gorm-pg" +) + +func ReadDetailLinkData(simgosId uint) (*esync.PatientLink, error) { + // log event + var data esync.PatientLink + var tx = dg.I + + if err := tx.Where("\"Simgos_Id\" = ?", simgosId).First(&data).Error; err != nil { + return nil, err + } + // log end event + return &data, nil +} diff --git a/internal/use-case/simgos-sync-use-case/old/patient/tycovar.go b/internal/use-case/simgos-sync-use-case/old/patient/tycovar.go new file mode 100644 index 00000000..15d99d0f --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/old/patient/tycovar.go @@ -0,0 +1,14 @@ +package patient + +import e "simrs-vx/internal/domain/main-entities/patient" + +type MainApiResp struct { + Meta MetaData `json:"meta"` + Data e.Patient `json:"data"` +} + +type MetaData struct { + Source string `json:"source"` + Status string `json:"status"` + Structure string `json:"structure"` +}