diff --git a/internal/use-case/main-use-case/chemo-plan/case.go b/internal/use-case/main-use-case/chemo-plan/case.go index 6a4c426e..7f74b6f7 100644 --- a/internal/use-case/main-use-case/chemo-plan/case.go +++ b/internal/use-case/main-use-case/chemo-plan/case.go @@ -1,17 +1,17 @@ package chemo_plan import ( - erc "simrs-vx/internal/domain/references/common" + ere "simrs-vx/internal/domain/references/encounter" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" "strconv" dg "github.com/karincake/apem/db-gorm-pg" d "github.com/karincake/dodol" - - pl "simrs-vx/pkg/logger" - pu "simrs-vx/pkg/use-case-helper" - "gorm.io/gorm" + erc "simrs-vx/internal/domain/references/common" + e "simrs-vx/internal/domain/main-entities/chemo-plan" ep "simrs-vx/internal/domain/main-entities/chemo-protocol" ) @@ -266,12 +266,33 @@ func Fail(input e.FailDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "update") - err = dg.I.Transaction(func(tx *gorm.DB) error { - pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") - if data, err = ReadDetailData(rdDto, &event, tx); err != nil { - return err - } + if data, err = ReadDetailData(rdDto, &event); err != nil { + return nil, err + } + dataSoapi, err := getSoapiByEncounterId(*data.Encounter_Id, &event) + if err != nil { + return nil, err + } + + if dataSoapi != nil && len(*dataSoapi) > 0 { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "soapi-exist", + Detail: "cancel soapi to proceed", + } + return nil, pl.SetLogError(&event, data) + } + + if data.Status != ere.SPCPlanned { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "invalid-chemo-status", + Detail: "only chemo plans with status 'planned' can be deleted.", + } + } + + err = dg.I.Transaction(func(tx *gorm.DB) error { if err := UpdateData(data, &event, tx); err != nil { return err } diff --git a/internal/use-case/main-use-case/chemo-plan/helper.go b/internal/use-case/main-use-case/chemo-plan/helper.go index f1b6179d..5cf7ffd5 100644 --- a/internal/use-case/main-use-case/chemo-plan/helper.go +++ b/internal/use-case/main-use-case/chemo-plan/helper.go @@ -6,12 +6,21 @@ package chemo_plan import ( "encoding/json" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + "time" + + dg "github.com/karincake/apem/db-gorm-pg" + + ere "simrs-vx/internal/domain/references/encounter" + e "simrs-vx/internal/domain/main-entities/chemo-plan" ep "simrs-vx/internal/domain/main-entities/chemo-protocol" - ere "simrs-vx/internal/domain/references/encounter" - "time" + es "simrs-vx/internal/domain/main-entities/soapi" ) +var now = time.Now() + func setDataCreate(input *ep.CreateDto) (data []e.ChemoPlan) { for _, c := range *input.ChemoPlans { data = append(data, e.ChemoPlan{ @@ -22,14 +31,10 @@ func setDataCreate(input *ep.CreateDto) (data []e.ChemoPlan) { PlanDate: c.PlanDate, }) } - - status := ere.SPCPlanned - data[0].Status = status return } func setDataUpdate(data *e.ChemoPlan) { - now := time.Now() data.RealizationDate = &now status := ere.SPCComplete @@ -42,5 +47,36 @@ func setDatafail(input e.FailDto, data *e.ChemoPlan) { var reasons []e.FailReason - _ := json.Unmarshal(data.Re) + if data.Reasons != nil { + json.Unmarshal([]byte(*data.Reasons), &reasons) + } + + reasons = append(reasons, e.FailReason{ + FailReason: input.Reasons, + Date: &now, + }) + + if b, err := json.Marshal(reasons); err == nil { + jsonStr := string(b) + data.Reasons = &jsonStr + } +} + +func getSoapiByEncounterId(encounterId uint, event *pl.Event) (*[]es.Soapi, error) { + pl.SetLogInfo(event, encounterId, "started", "DBReadDetail") + var data []es.Soapi + + var tx = dg.I + + if err := tx. + Model(&es.Soapi{}). + Where(`"Encounter_Id" = ?`, encounterId). + Find(&data).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, encounterId, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil } diff --git a/internal/use-case/main-use-case/encounter/helper.go b/internal/use-case/main-use-case/encounter/helper.go index 6fc28632..a4632296 100644 --- a/internal/use-case/main-use-case/encounter/helper.go +++ b/internal/use-case/main-use-case/encounter/helper.go @@ -7,7 +7,6 @@ package encounter import ( "errors" "fmt" - "strings" "time" @@ -27,6 +26,7 @@ import ( ea "simrs-vx/internal/domain/main-entities/ambulatory" ec "simrs-vx/internal/domain/main-entities/chemo" ecpl "simrs-vx/internal/domain/main-entities/chemo-plan" + ecp "simrs-vx/internal/domain/main-entities/chemo-protocol" edo "simrs-vx/internal/domain/main-entities/device-order" ed "simrs-vx/internal/domain/main-entities/doctor" ee "simrs-vx/internal/domain/main-entities/emergency" @@ -663,6 +663,20 @@ func insertDataSubClassAmbulatory(input e.CreateDto, soapiData []es.CreateDto, e switch { case subCode == ere.ACCChemo: + // validate if encounter Chemo valid + chemoProtoc, err := validateChemoAdm(*input.Patient_Id, event) + if err != nil { + return err + } + + if chemoProtoc == nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-not-found", + Detail: "chemo plan not found", + } + } + chemoCreate := ec.CreateDto{ Encounter_Id: &input.Id, Status_Code: erc.DVCVerified, @@ -677,7 +691,7 @@ func insertDataSubClassAmbulatory(input e.CreateDto, soapiData []es.CreateDto, e } // set chemo-plan to planned - _, err = updateChemoPlan(*input.Patient_Id, event, tx) + err = updateChemoPlan(chemoProtoc, event, tx) if err != nil { return err } @@ -875,10 +889,8 @@ func validateDoctorCodes(doctorCodes map[string]struct{}, event *pl.Event) error return nil } -func updateChemoPlan(patientId uint, event *pl.Event, dbx ...*gorm.DB) (*ecpl.ChemoPlan, error) { +func updateChemoPlan(data *ecpl.ChemoPlan, event *pl.Event, dbx ...*gorm.DB) error { pl.SetLogInfo(event, nil, "started", "getChemoFromEncounter") - data := ecpl.ChemoPlan{} - var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] @@ -886,20 +898,65 @@ func updateChemoPlan(patientId uint, event *pl.Event, dbx ...*gorm.DB) (*ecpl.Ch tx = dg.I } - tx = tx.Model(&ecpl.ChemoPlan{}). - Joins(`"ChemoProtocol" cp ON cp."Id" = "ChemoPlan"."Protocol_Id"`). - Where(`cp."Patient_Id" = ? AND ("ChemoPlan"."Status" IS NULL OR "ChemoPlan"."Status" = ?)`, patientId, ere.SPCSchedule). - Order(`"Id" ASC`). - Limit(1).First(&data) - - if err := tx.Error; err != nil { - return nil, err + if err := tx.Model(&data).Update(`"Status"`, ere.SPCPlanned).Error; err != nil { + return err } - if err := tx.Model(&data).Update(`"Status"`, ere.SPCPlanned).Error; err != nil { + pl.SetLogInfo(event, nil, "complete") + return nil +} + +func getChemoProtocol(patientId uint, event *pl.Event) (*ecp.ChemoProtocol, error) { + pl.SetLogInfo(event, nil, "started", "getChemoProtocol") + data := ecp.ChemoProtocol{} + + var tx = dg.I + + tx = tx.Model(&ecp.ChemoProtocol{}). + Joins(`"ChemoPlan" cp ON cp."Protocol_Id" = "ChemoProtocol"."Id"`). + Where(`"Patient.Id" = ? AND cp."Status" IS NULL`, patientId). + Preload("ChemoPlans", func(db *gorm.DB) *gorm.DB { + return tx.Order(`"Id" ASC`).Limit(1) + }). + First(&data) + + if err := tx.Error; err != nil { return nil, err } pl.SetLogInfo(event, nil, "complete") return &data, nil } + +func validateChemoAdm(patientId uint, event *pl.Event) (*ecpl.ChemoPlan, error) { + // get chemo protocol + chemo, err := getChemoProtocol(patientId, event) + if err != nil { + return nil, err + } + + if chemo.Status_Code != erc.DVCVerified { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-not-match", + Detail: fmt.Sprintf("protocol chemo not yet verified"), + } + return nil, pl.SetLogError(event, chemo) + } + + if now.Before(*chemo.StartDate) || now.After(*chemo.EndDate) { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "invalid-date-range", + Detail: "chemo cannot be performed because the current date is outside the allowed treatment window.", + } + return nil, pl.SetLogError(event, chemo) + } + + if chemo.ChemoPlans == nil || len(*chemo.ChemoPlans) == 0 { + return nil, nil + } + + // Return the first chemo plan + return &(*chemo.ChemoPlans)[0], nil +} diff --git a/internal/use-case/main-use-case/soapi/helper.go b/internal/use-case/main-use-case/soapi/helper.go index 7d5e7825..24f87465 100644 --- a/internal/use-case/main-use-case/soapi/helper.go +++ b/internal/use-case/main-use-case/soapi/helper.go @@ -77,20 +77,10 @@ func validateIfEncounterIsChemo(encounterId uint, event *pl.Event) (*ecpl.ChemoP return nil, pl.SetLogError(event, nil) } - if chemo.Status_Code != erc.DVCVerified { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-not-match", - Detail: fmt.Sprintf("protocol chemo not yet verified"), - } + if err = chemoProtocoValidation(chemo, event); err != nil { + } - now := time.Now() - if now.Before(*chemo.StartDate) || now.After(*chemo.EndDate) { - return nil, nil - } - - // --- 3. Must have at least one ChemoPlan --- if chemo.ChemoPlans == nil || len(*chemo.ChemoPlans) == 0 { return nil, nil } @@ -99,6 +89,31 @@ func validateIfEncounterIsChemo(encounterId uint, event *pl.Event) (*ecpl.ChemoP return &(*chemo.ChemoPlans)[0], nil } +func chemoProtocoValidation(chemo *ecp.ChemoProtocol, event *pl.Event) error { + if chemo.Status_Code != erc.DVCVerified { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-not-match", + Detail: fmt.Sprintf("protocol chemo not yet verified"), + } + + return pl.SetLogError(event, chemo) + } + + now := time.Now() + if now.Before(*chemo.StartDate) || now.After(*chemo.EndDate) { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "invalid-date-range", + Detail: "chemo cannot be performed because the current date is outside the allowed treatment window.", + } + + return pl.SetLogError(event, chemo) + } + + return nil +} + func getEncounter(encounterId uint, event *pl.Event) (*ee.Encounter, error) { pl.SetLogInfo(event, nil, "started", "getEncounter") data := ee.Encounter{}