diff --git a/internal/interface/main-handler/encounter/request-validation.go b/internal/interface/main-handler/encounter/request-validation.go index d3a7afe4..b7d31e71 100644 --- a/internal/interface/main-handler/encounter/request-validation.go +++ b/internal/interface/main-handler/encounter/request-validation.go @@ -68,7 +68,7 @@ func validateRequestCreate(w http.ResponseWriter, i e.CreateDto) (valid bool) { switch { case i.Class_Code == ere.ECAmbulatory: // field allocatedVisitCount required if ambulatory visitMode_Code is adm - if ere.AmbulatoryClassCode(*i.SubClass_Code) == ere.ACCRme && *i.VisitMode_Code == ere.VMCAdm { + if ere.AmbulatoryClassCode(*i.SubClass_Code) == ere.ACCRehab && *i.VisitMode_Code == ere.VMCAdm { if *i.AllocatedVisitCount == 0 { rw.DataResponse(w, nil, d.FieldError{ Code: dataValidationFail, diff --git a/internal/use-case/main-use-case/encounter/case.go b/internal/use-case/main-use-case/encounter/case.go index fa55f222..ef70d9c2 100644 --- a/internal/use-case/main-use-case/encounter/case.go +++ b/internal/use-case/main-use-case/encounter/case.go @@ -38,7 +38,6 @@ import ( uem "simrs-vx/internal/use-case/main-use-case/employee" ui "simrs-vx/internal/use-case/main-use-case/inpatient" ur "simrs-vx/internal/use-case/main-use-case/rehab" - urdh "simrs-vx/internal/use-case/main-use-case/responsible-doctor-hist" us "simrs-vx/internal/use-case/main-use-case/soapi" ) @@ -66,7 +65,7 @@ func Create(input e.CreateDto) (*d.Data, error) { } // verify whether the allocated visit count has not exceeded the limit - if input.Class_Code == ere.ECAmbulatory && subCode.(ere.AmbulatoryClassCode) == ere.ACCRme && + if input.Class_Code == ere.ECAmbulatory && subCode.(ere.AmbulatoryClassCode) == ere.ACCRehab && *input.VisitMode_Code == ere.VMCSeries { dataEncounter, valid, err := verifyAllocatedVisitCount(input, &event) @@ -150,7 +149,7 @@ func Create(input e.CreateDto) (*d.Data, error) { } } - if subCodeAmbulatory == ere.ACCRme && *input.VisitMode_Code == ere.VMCAdm { + if subCodeAmbulatory == ere.ACCRehab && *input.VisitMode_Code == ere.VMCAdm { // create data rehab if _, err = ur.CreateData(er.CreateDto{ Encounter_Id: &data.Id, @@ -158,7 +157,7 @@ func Create(input e.CreateDto) (*d.Data, error) { AllocatedVisitCount: input.AllocatedVisitCount}, &event, tx); err != nil { return err } - } else if subCodeAmbulatory == ere.ACCRme && *input.VisitMode_Code == ere.VMCSeries { + } else if subCodeAmbulatory == ere.ACCRehab && *input.VisitMode_Code == ere.VMCSeries { // Insert Soapi if err = us.CreateBulkData(createSoapi, data.Id, &event, tx); err != nil { return err @@ -442,7 +441,7 @@ func Delete(input e.DeleteDto) (*d.Data, error) { } func CheckOut(input e.DischargeDto) (*d.Data, error) { - rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + rdDto := e.ReadDetailDto{Id: uint16(input.Id), Includes: "Ambulatory"} var data *e.Encounter var err error @@ -470,13 +469,14 @@ func CheckOut(input e.DischargeDto) (*d.Data, error) { return pl.SetLogError(&event, input) } - if data.Class_Code == ere.ECAmbulatory { + if data.Ambulatory != nil && (data.Ambulatory.Class_Code == ere.ACCReg || data.Ambulatory.Class_Code == ere.ACCRehab) { // validate if soapi exist - err = getSoapiByTypeCode(input.Id, &event, "check-out") + err = getSoapiByTypeCode(input.Id, *data.Ambulatory, &event, "check-out") if err != nil { return err } } else { + // chemo TBC if err := checkSoapiByDocExists(data.Id, &event, tx); err != nil { return err } @@ -605,7 +605,7 @@ func UpdateStatusCode(input e.UpdateStatusDto) (*d.Data, error) { } func CheckIn(input e.CheckinDto) (*d.Data, error) { - rdDto := e.ReadDetailDto{Id: uint16(input.Id), Includes: "Rehab"} + rdDto := e.ReadDetailDto{Id: uint16(input.Id), Includes: "Rehab,Ambulatory"} var data *e.Encounter var err error @@ -627,12 +627,6 @@ func CheckIn(input e.CheckinDto) (*d.Data, error) { input.StartedAt = &now } - // validate if soapi exist - err = getSoapiByTypeCode(input.Id, &event, "check-in") - if err != nil { - return nil, err - } - err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") if data, err = ReadDetailData(rdDto, &event, tx); err != nil { @@ -649,34 +643,34 @@ func CheckIn(input e.CheckinDto) (*d.Data, error) { return pl.SetLogError(&event, input) } - // Insert responsible_doctor_hist if responsible_doctor_id has changed && update latest history - if data.Responsible_Doctor_Id == nil || *input.Responsible_Doctor_Id != *data.Responsible_Doctor_Id { - // update finishedAt in latest responsible_doctor_hist - if err = updateLatestResponsibleDoctorHist(input, &event, tx); err != nil { + // validate if soapi exist + if data.Ambulatory != nil && (data.Ambulatory.Class_Code == ere.ACCReg || data.Ambulatory.Class_Code == ere.ACCRehab) { + err = getSoapiByTypeCode(input.Id, *data.Ambulatory, &event, "check-in") + if err != nil { return err } + } - //insert responsible_doctor_hist - if _, err = urdh.CreateData(erdh.CreateDto{ - Encounter_Id: &input.Id, + // Insert responsible_doctor_hist if responsible_doctor_id has changed && update latest history + if data.Responsible_Doctor_Id == nil || *input.Responsible_Doctor_Id != *data.Responsible_Doctor_Id { + // upsert responsibleDoctorHist + if err = upsertResponsibleDoctorHist(erdh.CreateDto{ + Encounter_Id: &data.Id, Doctor_Id: input.Responsible_Doctor_Id, - StartedAt: input.StartedAt}, &event, tx); err != nil { + StartedAt: input.StartedAt, + }, &event, tx); err != nil { return err } } // Insert adm_employee_hist if adm_employee_id has changed && update latest history if input.Adm_Employee_Id != nil && *input.Adm_Employee_Id != *data.Adm_Employee_Id { - // update finishedAt in latest adm_employee_hist - if err = updateLatestAdmEmployeeHist(input, &event, tx); err != nil { - return err - } - - // insert responsible_doctor_hist - if _, err = uaeh.CreateData(eaeh.CreateDto{ - Encounter_Id: &input.Id, + // upsert admEmployeeHist + if err = upsertAdmEmployeeHist(eaeh.CreateDto{ + Encounter_Id: &data.Id, Employee_Id: input.Adm_Employee_Id, - StartedAt: input.StartedAt}, &event, tx); err != nil { + StartedAt: input.StartedAt, + }, &event, tx); err != nil { return err } } @@ -686,13 +680,13 @@ func CheckIn(input e.CheckinDto) (*d.Data, error) { return err } - if err := updateRehabDoctor(er.UpdateDto{ - CreateDto: er.CreateDto{ + if data.Ambulatory.Class_Code == ere.ACCRehab { + if err := updateRehabDoctor(er.UpdateDto{CreateDto: er.CreateDto{ Encounter_Id: &data.Id, Doctor_Id: input.Responsible_Doctor_Id, - }, - }, &event, tx); err != nil { - return err + }}, &event, tx); err != nil { + return err + } } pl.SetLogInfo(&event, nil, "complete") diff --git a/internal/use-case/main-use-case/encounter/helper.go b/internal/use-case/main-use-case/encounter/helper.go index c5eb155e..4bf7be60 100644 --- a/internal/use-case/main-use-case/encounter/helper.go +++ b/internal/use-case/main-use-case/encounter/helper.go @@ -7,17 +7,25 @@ package encounter import ( "errors" "fmt" - uir "simrs-vx/internal/use-case/main-use-case/internal-reference" "strings" "time" + dg "github.com/karincake/apem/db-gorm-pg" "gorm.io/gorm" pl "simrs-vx/pkg/logger" pu "simrs-vx/pkg/use-case-helper" + ercl "simrs-vx/internal/domain/references/clinical" + erc "simrs-vx/internal/domain/references/common" + ere "simrs-vx/internal/domain/references/encounter" + erg "simrs-vx/internal/domain/references/organization" + + eaeh "simrs-vx/internal/domain/main-entities/adm-employee-hist" + ea "simrs-vx/internal/domain/main-entities/ambulatory" edo "simrs-vx/internal/domain/main-entities/device-order" ed "simrs-vx/internal/domain/main-entities/doctor" + e "simrs-vx/internal/domain/main-entities/encounter" emo "simrs-vx/internal/domain/main-entities/material-order" emco "simrs-vx/internal/domain/main-entities/mcu-order" em "simrs-vx/internal/domain/main-entities/medication" @@ -26,20 +34,21 @@ import ( emmi "simrs-vx/internal/domain/main-entities/medicine-mix-item" ep "simrs-vx/internal/domain/main-entities/prescription" epi "simrs-vx/internal/domain/main-entities/prescription-item" + er "simrs-vx/internal/domain/main-entities/rehab" + erdh "simrs-vx/internal/domain/main-entities/responsible-doctor-hist" eu "simrs-vx/internal/domain/main-entities/unit" // udo "simrs-vx/internal/use-case/main-use-case/device-order" es "simrs-vx/internal/domain/main-entities/soapi" + uaeh "simrs-vx/internal/use-case/main-use-case/adm-employee-hist" + uir "simrs-vx/internal/use-case/main-use-case/internal-reference" um "simrs-vx/internal/use-case/main-use-case/medication" umei "simrs-vx/internal/use-case/main-use-case/medication-item" umi "simrs-vx/internal/use-case/main-use-case/medicine-mix" ummi "simrs-vx/internal/use-case/main-use-case/medicine-mix-item" up "simrs-vx/internal/use-case/main-use-case/prescription" upi "simrs-vx/internal/use-case/main-use-case/prescription-item" - - e "simrs-vx/internal/domain/main-entities/encounter" - erc "simrs-vx/internal/domain/references/common" - erg "simrs-vx/internal/domain/references/organization" + urdh "simrs-vx/internal/use-case/main-use-case/responsible-doctor-hist" ) func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Encounter) { @@ -432,3 +441,371 @@ func getDoctors(doctorIds []uint, event *pl.Event, tx *gorm.DB) ([]ed.Doctor, er } return doctors, nil } + +func upsertResponsibleDoctorHist(input erdh.CreateDto, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + var latest erdh.ResponsibleDoctorHist + err := tx. + Where("\"Encounter_Id\" = ?", input.Encounter_Id). + Order("\"CreatedAt\" DESC"). + Limit(1). + First(&latest).Error + + switch { + case errors.Is(err, gorm.ErrRecordNotFound): + // Insert + if _, err = urdh.CreateData(input, event, tx); err != nil { + return err + } + case err != nil: + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "read-fail", + Detail: "Failed to read responsible doctor history", + Raw: err, + } + return pl.SetLogError(event, input) + default: + // Update + if err := tx.Model(&latest).Updates(map[string]interface{}{ + "Doctor_Id": input.Doctor_Id, + "StartedAt": input.StartedAt, + "UpdatedAt": time.Now(), + }).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "update-fail", + Detail: "Failed to update responsible doctor history", + Raw: err, + } + return pl.SetLogError(event, input) + } + } + pl.SetLogInfo(event, input, "complete") + return nil +} + +func upsertAdmEmployeeHist(input eaeh.CreateDto, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + var latest eaeh.AdmEmployeeHist + err := tx. + Where("\"Encounter_Id\" = ?", input.Encounter_Id). + Order("\"CreatedAt\" DESC"). + Limit(1). + First(&latest).Error + + switch { + case errors.Is(err, gorm.ErrRecordNotFound): + // Insert + if _, err = uaeh.CreateData(input, event, tx); err != nil { + return err + } + case err != nil: + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "read-fail", + Detail: "Failed to read responsible doctor history", + Raw: err, + } + return pl.SetLogError(event, input) + + default: + // Update + if err := tx.Model(&latest).Updates(map[string]interface{}{ + "Employee_Id": input.Employee_Id, + "StartedAt": input.StartedAt, + "UpdatedAt": time.Now(), + }).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "update-fail", + Detail: "Failed to update responsible doctor history", + Raw: err, + } + return pl.SetLogError(event, input) + } + } + pl.SetLogInfo(event, input, "complete") + + return nil +} + +func updateLatestResponsibleDoctorHist(input e.CheckinDto, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, "started", "DBUpdate") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + subQuery := tx. + Select("\"Id\""). + Model(&erdh.ResponsibleDoctorHist{}). + Where("\"Encounter_Id\" = ?", input.Id). + Order("\"CreatedAt\" DESC"). + Limit(1) + + result := tx. + Model(&erdh.ResponsibleDoctorHist{}). + Where("\"Id\" = (?)", subQuery). + Update("\"FinishedAt\"", input.StartedAt) + + if result.Error != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-update-fail", + Detail: "Database update failed", + Raw: result.Error, + } + return pl.SetLogError(event, input) + } + + if result.RowsAffected == 0 { + pl.SetLogInfo(event, input, "no previous data found to update") + return nil + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} + +func updateLatestAdmEmployeeHist(input e.CheckinDto, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, "started", "DBUpdate") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + subQuery := tx. + Select("\"Id\""). + Model(&eaeh.AdmEmployeeHist{}). + Where("\"Encounter_Id\" = ?", input.Id). + Order("\"CreatedAt\" DESC"). + Limit(1) + + result := tx. + Model(&eaeh.AdmEmployeeHist{}). + Where("\"Id\" = (?)", subQuery). + Update("\"FinishedAt\"", input.StartedAt) + + if result.Error != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-update-fail", + Detail: "Database update failed", + Raw: result.Error, + } + return pl.SetLogError(event, input) + } + + if result.RowsAffected == 0 { + pl.SetLogInfo(event, input, "no previous data found to update") + return nil + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} + +func getSoapiEncounterAdm(enc e.Encounter, event *pl.Event) (dataSoapi []es.CreateDto, err error) { + var data []es.Soapi + + pl.SetLogInfo(event, enc, "started", "DBReadList") + + if enc.Responsible_Doctor == nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "no responsible-doctor found", + Detail: "Encounter does not have responsible-doctor", + } + } + + err = dg.I.Debug(). + Model(&es.Soapi{}). + Joins("JOIN \"Employee\" ON \"Employee\".\"Id\" = \"Soapi\".\"Employee_Id\""). + Where("\"Encounter_Id\" = ?", enc.Id). + Where("\"Employee\".\"Position_Code\" = ?", erg.EPCDoc). + Where("\"Soapi\".\"TypeCode\" IN ?", []ercl.SoapiTypeCode{ercl.STCEEarlyMedic, ercl.STCFunc}). + Where("\"Soapi\".\"Employee_Id\" = ?", *enc.Responsible_Doctor.Employee_Id). + Find(&data).Error + + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Raw: err, + } + + if errors.Is(err, gorm.ErrRecordNotFound) { + event.ErrInfo.Code = "data-not-found" + event.ErrInfo.Detail = "Data not found" + return nil, pl.SetLogError(event, enc) + } + + event.ErrInfo.Code = "read-fail" + event.ErrInfo.Detail = "Database read failed" + return nil, pl.SetLogError(event, enc) + } + + pl.SetLogInfo(event, nil, "complete") + + for _, s := range data { + // set data soapi for copy + dataSoapi = append(dataSoapi, es.CreateDto{ + Employee_Id: s.Employee_Id, + Time: s.Time, + TypeCode: s.TypeCode, + Value: s.Value, + }) + } + + if len(dataSoapi) < 2 { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "missing-soapi", + Detail: fmt.Sprintf("Missing required Soapi types"), + } + return nil, pl.SetLogError(event, enc) + } + return +} + +func getSoapiByTypeCode(encounterId uint, dataAmbulatory ea.Ambulatory, event *pl.Event, mode string) (err error) { + pl.SetLogInfo(event, encounterId, "started", "DBReadList") + + var ( + dataSoapi []es.Soapi + ) + + // Set Query for get data Soapi + tx := dg.I. + Model(&es.Soapi{}). + Joins("JOIN \"Employee\" ON \"Employee\".\"Id\" = \"Soapi\".\"Employee_Id\""). + Where("\"Encounter_Id\" = ?", encounterId). + Where("\"Employee\".\"Position_Code\" = ?", erg.EPCDoc) + + // Set Case + switch { + case dataAmbulatory.Class_Code == ere.ACCReg: + tx = tx.Where("\"Soapi\".\"TypeCode\" = ?", ercl.STCEEarlyMedic) + case dataAmbulatory.Class_Code == ere.ACCRehab && dataAmbulatory.VisitMode_Code == ere.VMCAdm: + tx = tx.Where("\"Soapi\".\"TypeCode\" IN ?", []ercl.SoapiTypeCode{ercl.STCEEarlyMedic, ercl.STCFunc, ercl.STCEarlyRehab}) + case dataAmbulatory.Class_Code == ere.ACCRehab && dataAmbulatory.VisitMode_Code == ere.VMCSeries: + tx = tx.Where("\"Soapi\".\"TypeCode\" = ?", ercl.STCEarlyRehab) + } + + if err = tx.Find(&dataSoapi).Error; err != nil { + return setDBError(event, err, encounterId) + } + + pl.SetLogInfo(event, nil, "complete") + return validateExistedSoapi(dataSoapi, &dataAmbulatory, event, mode) +} + +func validateExistedSoapi(dataSoapi []es.Soapi, dataAmbulatory *ea.Ambulatory, event *pl.Event, mode string) error { + typeExist := make(map[ercl.SoapiTypeCode]bool) + for _, s := range dataSoapi { + typeExist[s.TypeCode] = true + } + + required := []ercl.SoapiTypeCode{} + + switch { + case dataAmbulatory.Class_Code == ere.ACCReg: + required = []ercl.SoapiTypeCode{ercl.STCEEarlyMedic} + case dataAmbulatory.Class_Code == ere.ACCRehab && dataAmbulatory.VisitMode_Code == ere.VMCAdm: + required = []ercl.SoapiTypeCode{ercl.STCEEarlyMedic, ercl.STCFunc, ercl.STCEarlyRehab} + case dataAmbulatory.Class_Code == ere.ACCRehab && dataAmbulatory.VisitMode_Code == ere.VMCSeries: + required = []ercl.SoapiTypeCode{ercl.STCEarlyRehab} + } + + var missing, existing []string + for _, code := range required { + if typeExist[code] { + existing = append(existing, string(code)) + } else { + missing = append(missing, string(code)) + } + } + + switch mode { + case "check-in": + if len(existing) > 0 { + return setSoapiError(event, fmt.Sprintf("Soapi type(s) %s exist, can't check-in", strings.Join(existing, ", "))) + } + case "check-out": + if len(missing) > 0 { + return setSoapiError(event, fmt.Sprintf("Soapi type(s) %s not found, can't check-out", strings.Join(missing, ", "))) + } + } + + return nil +} + +func setSoapiError(event *pl.Event, detail string) error { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "invalid-soapi-state", + Detail: detail, + } + return pl.SetLogError(event, detail) +} + +func setDBError(event *pl.Event, err error, ctx any) error { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Raw: err, + Code: "read-fail", + Detail: "Database read failed", + } + return pl.SetLogError(event, ctx) +} + +func updateRehabDoctor(input er.UpdateDto, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, "started", "DBUpdate") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + result := tx. + Model(&er.Rehab{}). + Where("\"Encounter_Id\" = (?)", input.Encounter_Id). + Update("\"Doctor_Id\"", input.Doctor_Id) + + if result.Error != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-update-fail", + Detail: "Database update failed", + Raw: result.Error, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/main-use-case/encounter/lib.go b/internal/use-case/main-use-case/encounter/lib.go index b840f6e1..d80fd513 100644 --- a/internal/use-case/main-use-case/encounter/lib.go +++ b/internal/use-case/main-use-case/encounter/lib.go @@ -3,29 +3,17 @@ package encounter import ( // std "errors" - "fmt" - erc "simrs-vx/internal/domain/references/clinical" ere "simrs-vx/internal/domain/references/encounter" - ero "simrs-vx/internal/domain/references/organization" - "strings" - // external dg "github.com/karincake/apem/db-gorm-pg" gh "github.com/karincake/getuk" "gorm.io/gorm" - // pkg plh "simrs-vx/pkg/lib-helper" pl "simrs-vx/pkg/logger" pu "simrs-vx/pkg/use-case-helper" - // internal - eaeh "simrs-vx/internal/domain/main-entities/adm-employee-hist" - ea "simrs-vx/internal/domain/main-entities/ambulatory" e "simrs-vx/internal/domain/main-entities/encounter" - er "simrs-vx/internal/domain/main-entities/rehab" - erdh "simrs-vx/internal/domain/main-entities/responsible-doctor-hist" - es "simrs-vx/internal/domain/main-entities/soapi" ) func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Encounter, error) { @@ -261,88 +249,6 @@ func updateCheckInData(input e.CheckinDto, data *e.Encounter, event *pl.Event, d return nil } -func updateLatestResponsibleDoctorHist(input e.CheckinDto, event *pl.Event, dbx ...*gorm.DB) error { - pl.SetLogInfo(event, "started", "DBUpdate") - - var tx *gorm.DB - if len(dbx) > 0 { - tx = dbx[0] - } else { - tx = dg.I - } - - subQuery := tx. - Select("\"Id\""). - Model(&erdh.ResponsibleDoctorHist{}). - Where("\"Encounter_Id\" = ?", input.Id). - Order("\"CreatedAt\" DESC"). - Limit(1) - - result := tx. - Model(&erdh.ResponsibleDoctorHist{}). - Where("\"Id\" = (?)", subQuery). - Update("\"FinishedAt\"", input.StartedAt) - - if result.Error != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-update-fail", - Detail: "Database update failed", - Raw: result.Error, - } - return pl.SetLogError(event, input) - } - - if result.RowsAffected == 0 { - pl.SetLogInfo(event, input, "no previous data found to update") - return nil - } - - pl.SetLogInfo(event, nil, "complete") - return nil -} - -func updateLatestAdmEmployeeHist(input e.CheckinDto, event *pl.Event, dbx ...*gorm.DB) error { - pl.SetLogInfo(event, "started", "DBUpdate") - - var tx *gorm.DB - if len(dbx) > 0 { - tx = dbx[0] - } else { - tx = dg.I - } - - subQuery := tx. - Select("\"Id\""). - Model(&eaeh.AdmEmployeeHist{}). - Where("\"Encounter_Id\" = ?", input.Id). - Order("\"CreatedAt\" DESC"). - Limit(1) - - result := tx. - Model(&eaeh.AdmEmployeeHist{}). - Where("\"Id\" = (?)", subQuery). - Update("\"FinishedAt\"", input.StartedAt) - - if result.Error != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-update-fail", - Detail: "Database update failed", - Raw: result.Error, - } - return pl.SetLogError(event, input) - } - - if result.RowsAffected == 0 { - pl.SetLogInfo(event, input, "no previous data found to update") - return nil - } - - pl.SetLogInfo(event, nil, "complete") - return nil -} - func verifyAllocatedVisitCount(i e.CreateDto, event *pl.Event) (e.Encounter, bool, error) { pl.SetLogInfo(event, nil, "started", "DBGetRecentEncounterAdm") @@ -356,7 +262,7 @@ func verifyAllocatedVisitCount(i e.CreateDto, event *pl.Event) (e.Encounter, boo Scopes(gh.Preload("Rehab,Responsible_Doctor")). Joins("JOIN \"Ambulatory\" ON \"Ambulatory\".\"Encounter_Id\" = \"Encounter\".\"Id\""). Where("\"Patient_Id\" = ?", i.Patient_Id). - Where("\"Ambulatory\".\"Class_Code\" = ? AND \"Ambulatory\".\"VisitMode_Code\" = ?", ere.ACCRme, ere.VMCAdm). + Where("\"Ambulatory\".\"Class_Code\" = ? AND \"Ambulatory\".\"VisitMode_Code\" = ?", ere.ACCRehab, ere.VMCAdm). Order("\"CreatedAt\" DESC"). First(&recentEncounterAdm).Error if err != nil { @@ -374,7 +280,7 @@ func verifyAllocatedVisitCount(i e.CreateDto, event *pl.Event) (e.Encounter, boo Model(&e.Encounter{}). Joins("JOIN \"Ambulatory\" ON \"Ambulatory\".\"Encounter_Id\" = \"Encounter\".\"Id\""). Where("\"Patient_Id\" = ?", i.Patient_Id). - Where("\"Ambulatory\".\"Class_Code\" = ? AND \"Ambulatory\".\"VisitMode_Code\" = ?", ere.ACCRme, ere.VMCSeries). + Where("\"Ambulatory\".\"Class_Code\" = ? AND \"Ambulatory\".\"VisitMode_Code\" = ?", ere.ACCRehab, ere.VMCSeries). Where("\"Encounter\".\"CreatedAt\" > ?", recentEncounterAdm.CreatedAt). Count(&countEncounterSeries).Error if err != nil { @@ -389,193 +295,3 @@ func verifyAllocatedVisitCount(i e.CreateDto, event *pl.Event) (e.Encounter, boo return recentEncounterAdm, countEncounterSeries < int64(*recentEncounterAdm.Rehab.AllocatedVisitCount), nil } - -func getSoapiEncounterAdm(enc e.Encounter, event *pl.Event) (dataSoapi []es.CreateDto, err error) { - var data []es.Soapi - - pl.SetLogInfo(event, enc, "started", "DBReadList") - - if enc.Responsible_Doctor == nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "no responsible-doctor found", - Detail: "Encounter does not have responsible-doctor", - } - } - - err = dg.I.Debug(). - Model(&es.Soapi{}). - Joins("JOIN \"Employee\" ON \"Employee\".\"Id\" = \"Soapi\".\"Employee_Id\""). - Where("\"Encounter_Id\" = ?", enc.Id). - Where("\"Employee\".\"Position_Code\" = ?", ero.EPCDoc). - Where("\"Soapi\".\"TypeCode\" IN ?", []erc.SoapiTypeCode{erc.STCEEarlyMedic, erc.STCFunc}). - Where("\"Soapi\".\"Employee_Id\" = ?", *enc.Responsible_Doctor.Employee_Id). - Find(&data).Error - - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Raw: err, - } - - if errors.Is(err, gorm.ErrRecordNotFound) { - event.ErrInfo.Code = "data-not-found" - event.ErrInfo.Detail = "Data not found" - return nil, pl.SetLogError(event, enc) - } - - event.ErrInfo.Code = "read-fail" - event.ErrInfo.Detail = "Database read failed" - return nil, pl.SetLogError(event, enc) - } - - pl.SetLogInfo(event, nil, "complete") - - for _, s := range data { - // set data soapi for copy - dataSoapi = append(dataSoapi, es.CreateDto{ - Employee_Id: s.Employee_Id, - Time: s.Time, - TypeCode: s.TypeCode, - Value: s.Value, - }) - } - - if len(dataSoapi) < 2 { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "missing-soapi", - Detail: fmt.Sprintf("Missing required Soapi types"), - } - return nil, pl.SetLogError(event, enc) - } - return -} - -func getSoapiByTypeCode(encounterId uint, event *pl.Event, mode string) (err error) { - pl.SetLogInfo(event, encounterId, "started", "DBReadList") - - var ( - dataAmbulatory ea.Ambulatory - dataSoapi []es.Soapi - ) - - // Get Data Ambulatory - if err = dg.I. - Where("\"Encounter_Id\" = ?", encounterId). - First(&dataAmbulatory).Error; err != nil { - return setDBError(event, err, encounterId) - } - - // Set Query for get data Soapi - tx := dg.I. - Model(&es.Soapi{}). - Joins("JOIN \"Employee\" ON \"Employee\".\"Id\" = \"Soapi\".\"Employee_Id\""). - Where("\"Encounter_Id\" = ?", encounterId). - Where("\"Employee\".\"Position_Code\" = ?", ero.EPCDoc) - - // Set Case - switch { - case dataAmbulatory.Class_Code == ere.ACCReg: - tx = tx.Where("\"Soapi\".\"TypeCode\" = ?", erc.STCEEarlyMedic) - case dataAmbulatory.Class_Code == ere.ACCRme && dataAmbulatory.VisitMode_Code == ere.VMCAdm: - tx = tx.Where("\"Soapi\".\"TypeCode\" IN ?", []erc.SoapiTypeCode{erc.STCEEarlyMedic, erc.STCFunc, erc.STCEarlyRehab}) - case dataAmbulatory.Class_Code == ere.ACCRme && dataAmbulatory.VisitMode_Code == ere.VMCSeries: - tx = tx.Where("\"Soapi\".\"TypeCode\" = ?", erc.STCEarlyRehab) - } - - if err = tx.Find(&dataSoapi).Error; err != nil { - return setDBError(event, err, encounterId) - } - - pl.SetLogInfo(event, nil, "complete") - return validateExistedSoapi(dataSoapi, &dataAmbulatory, event, mode) -} - -func validateExistedSoapi(dataSoapi []es.Soapi, dataAmbulatory *ea.Ambulatory, event *pl.Event, mode string) error { - typeExist := make(map[erc.SoapiTypeCode]bool) - for _, s := range dataSoapi { - typeExist[s.TypeCode] = true - } - - required := []erc.SoapiTypeCode{} - - switch { - case dataAmbulatory.Class_Code == ere.ACCReg: - required = []erc.SoapiTypeCode{erc.STCEEarlyMedic} - case dataAmbulatory.Class_Code == ere.ACCRme && dataAmbulatory.VisitMode_Code == ere.VMCAdm: - required = []erc.SoapiTypeCode{erc.STCEEarlyMedic, erc.STCFunc, erc.STCEarlyRehab} - case dataAmbulatory.Class_Code == ere.ACCRme && dataAmbulatory.VisitMode_Code == ere.VMCSeries: - required = []erc.SoapiTypeCode{erc.STCEarlyRehab} - } - - var missing, existing []string - for _, code := range required { - if typeExist[code] { - existing = append(existing, string(code)) - } else { - missing = append(missing, string(code)) - } - } - - switch mode { - case "check-in": - if len(existing) > 0 { - return setSoapiError(event, fmt.Sprintf("Soapi type(s) %s exist, can't check-in", strings.Join(existing, ", "))) - } - case "check-out": - if len(missing) > 0 { - return setSoapiError(event, fmt.Sprintf("Soapi type(s) %s not found, can't check-out", strings.Join(missing, ", "))) - } - } - - return nil -} - -func setSoapiError(event *pl.Event, detail string) error { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "invalid-soapi-state", - Detail: detail, - } - return pl.SetLogError(event, detail) -} - -func setDBError(event *pl.Event, err error, ctx any) error { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Raw: err, - Code: "read-fail", - Detail: "Database read failed", - } - return pl.SetLogError(event, ctx) -} - -func updateRehabDoctor(input er.UpdateDto, event *pl.Event, dbx ...*gorm.DB) error { - pl.SetLogInfo(event, "started", "DBUpdate") - - var tx *gorm.DB - if len(dbx) > 0 { - tx = dbx[0] - } else { - tx = dg.I - } - - result := tx. - Model(&er.Rehab{}). - Where("\"Encounter_Id\" = (?)", input.Encounter_Id). - Update("\"Doctor_Id\"", input.Doctor_Id) - - if result.Error != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-update-fail", - Detail: "Database update failed", - Raw: result.Error, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(event, nil, "complete") - return nil -}