From d03c1c7a93093e4eebe56a356343fb96d82d9946 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Fri, 14 Nov 2025 14:16:07 +0700 Subject: [PATCH] feat (therapy-protocol): add verification --- .../main-entities/therapy-protocol/dto.go | 74 +++++++++++-------- .../main-entities/therapy-protocol/entity.go | 4 + .../interface/main-handler/main-handler.go | 19 +++-- .../main-handler/therapy-protocol/handler.go | 46 ++++++++++++ .../main-use-case/therapy-protocol/case.go | 65 ++++++++++++++++ 5 files changed, 167 insertions(+), 41 deletions(-) diff --git a/internal/domain/main-entities/therapy-protocol/dto.go b/internal/domain/main-entities/therapy-protocol/dto.go index 40633b89..a1d311dc 100644 --- a/internal/domain/main-entities/therapy-protocol/dto.go +++ b/internal/domain/main-entities/therapy-protocol/dto.go @@ -4,24 +4,27 @@ import ( ecore "simrs-vx/internal/domain/base-entities/core" ed "simrs-vx/internal/domain/main-entities/doctor" ee "simrs-vx/internal/domain/main-entities/encounter" - "simrs-vx/internal/domain/references/common" + erc "simrs-vx/internal/domain/references/common" + + pa "simrs-vx/internal/lib/auth" ) type CreateDto struct { - Encounter_Id *uint `json:"encounter_id"` - Doctor_Code *string `json:"doctor_code"` - Anamnesis *string `json:"anamnesis" validate:"maxLength=2048"` - MedicalDiagnoses *string `json:"medicalDiagnoses"` - FunctionDiagnoses *string `json:"functionDiagnoses"` - Procedures *string `json:"procedures"` - SupportingExams *string `json:"supportingExams" validate:"maxLength=2048"` - Instruction *string `json:"instruction" validate:"maxLength=2048"` - Evaluation *string `json:"evaluation" validate:"maxLength=2048"` - WorkCauseStatus *string `json:"workCauseStatus"` - Frequency *uint `json:"frequency"` - IntervalUnit_Code *common.TimeUnitCode `json:"intervalUnit_code" validate:"maxLength=10"` - Duration *uint `json:"duration"` - DurationUnit_Code *common.TimeUnitCode `json:"durationUnit_code" validate:"maxLength=10"` + Encounter_Id *uint `json:"encounter_id"` + Doctor_Code *string `json:"doctor_code"` + Anamnesis *string `json:"anamnesis" validate:"maxLength=2048"` + MedicalDiagnoses *string `json:"medicalDiagnoses"` + FunctionDiagnoses *string `json:"functionDiagnoses"` + Procedures *string `json:"procedures"` + SupportingExams *string `json:"supportingExams" validate:"maxLength=2048"` + Instruction *string `json:"instruction" validate:"maxLength=2048"` + Evaluation *string `json:"evaluation" validate:"maxLength=2048"` + WorkCauseStatus *string `json:"workCauseStatus"` + Frequency *uint `json:"frequency"` + IntervalUnit_Code *erc.TimeUnitCode `json:"intervalUnit_code" validate:"maxLength=10"` + Duration *uint `json:"duration"` + DurationUnit_Code *erc.TimeUnitCode `json:"durationUnit_code" validate:"maxLength=10"` + Status_Code *erc.DataVerifiedCode `json:"status_code"` } type ReadListDto struct { @@ -49,6 +52,13 @@ type DeleteDto struct { Id uint `json:"id"` } +type VerifyDto struct { + Id uint `json:"id"` + Status_Code erc.DataVerifiedCode `json:"status_code"` + + pa.AuthInfo +} + type MetaDto struct { PageNumber int `json:"page_number"` PageSize int `json:"page_size"` @@ -57,22 +67,23 @@ type MetaDto struct { type ResponseDto struct { ecore.Main - Encounter_Id *uint `json:"encounter_id"` - Encounter *ee.Encounter `json:"encounter,omitempty"` - Doctor_Code *string `json:"doctor_code"` - Doctor *ed.Doctor `json:"doctor,omitempty"` - Anamnesis *string `json:"anamnesis"` - MedicalDiagnoses *string `json:"medicalDiagnoses"` - FunctionDiagnoses *string `json:"functionDiagnoses"` - Procedures *string `json:"procedures"` - SupportingExams *string `json:"supportingExams"` - Instruction *string `json:"instruction"` - Evaluation *string `json:"evaluation"` - WorkCauseStatus *string `json:"workCauseStatus"` - Frequency *uint `json:"frequency"` - IntervalUnit_Code *common.TimeUnitCode `json:"intervalUnit_code"` - Duration *uint `json:"duration"` - DurationUnit_Code *common.TimeUnitCode `json:"durationUnit_code"` + Encounter_Id *uint `json:"encounter_id"` + Encounter *ee.Encounter `json:"encounter,omitempty"` + Doctor_Code *string `json:"doctor_code"` + Doctor *ed.Doctor `json:"doctor,omitempty"` + Anamnesis *string `json:"anamnesis"` + MedicalDiagnoses *string `json:"medicalDiagnoses"` + FunctionDiagnoses *string `json:"functionDiagnoses"` + Procedures *string `json:"procedures"` + SupportingExams *string `json:"supportingExams"` + Instruction *string `json:"instruction"` + Evaluation *string `json:"evaluation"` + WorkCauseStatus *string `json:"workCauseStatus"` + Frequency *uint `json:"frequency"` + IntervalUnit_Code *erc.TimeUnitCode `json:"intervalUnit_code"` + Duration *uint `json:"duration"` + DurationUnit_Code *erc.TimeUnitCode `json:"durationUnit_code"` + Status_Code *erc.DataVerifiedCode `json:"status_code"` } func (d TherapyProtocol) ToResponse() ResponseDto { @@ -93,6 +104,7 @@ func (d TherapyProtocol) ToResponse() ResponseDto { IntervalUnit_Code: d.IntervalUnit_Code, Duration: d.Duration, DurationUnit_Code: d.DurationUnit_Code, + Status_Code: d.Status_Code, } resp.Main = d.Main return resp diff --git a/internal/domain/main-entities/therapy-protocol/entity.go b/internal/domain/main-entities/therapy-protocol/entity.go index 1378eb25..e7607eea 100644 --- a/internal/domain/main-entities/therapy-protocol/entity.go +++ b/internal/domain/main-entities/therapy-protocol/entity.go @@ -30,3 +30,7 @@ type TherapyProtocol struct { DurationUnit_Code *common.TimeUnitCode `json:"durationUnit_code" gorm:"size:10"` Status_Code *common.DataVerifiedCode `json:"status_code" gorm:"size:10"` } + +func (d TherapyProtocol) IsNew() bool { + return d.Status_Code != nil && *d.Status_Code == common.DVCNew +} diff --git a/internal/interface/main-handler/main-handler.go b/internal/interface/main-handler/main-handler.go index a06c5c18..aa6f76fb 100644 --- a/internal/interface/main-handler/main-handler.go +++ b/internal/interface/main-handler/main-handler.go @@ -152,7 +152,6 @@ func SetRoutes() http.Handler { hc.RegCrud(r, "/v1/prescription-item", prescriptionitem.O) hc.RegCrud(r, "/v1/device-order-item", deviceorderitem.O) hc.RegCrud(r, "/v1/material-order-item", materialorderitem.O) - hk.GroupRoutes("/v1/encounter", r, auth.GuardMW, hk.MapHandlerFunc{ "GET /": encounter.O.GetList, "GET /{id}": encounter.O.GetDetail, @@ -211,7 +210,6 @@ func SetRoutes() http.Handler { "DELETE /{id}": medication.O.Delete, "PATCH /{id}/complete": medication.O.Complete, }) - hk.GroupRoutes("/v1/medication-item", r, auth.GuardMW, hk.MapHandlerFunc{ "GET /": medicationitem.O.GetList, "GET /{id}": medicationitem.O.GetDetail, @@ -220,7 +218,6 @@ func SetRoutes() http.Handler { "DELETE /{id}": medicationitem.O.Delete, "PATCH /{id}/redeem": medicationitem.O.Redeem, }) - hk.GroupRoutes("/v1/medication-item-dist", r, auth.GuardMW, hk.MapHandlerFunc{ "GET /": medicationitemdist.O.GetList, "GET /{id}": medicationitemdist.O.GetDetail, @@ -229,7 +226,6 @@ func SetRoutes() http.Handler { "DELETE /{id}": medicationitemdist.O.Delete, "PATCH /{id}/consume": medicationitemdist.O.Consume, }) - hk.GroupRoutes("/v1/device-order", r, auth.GuardMW, hk.MapHandlerFunc{ "GET /": deviceorder.O.GetList, "GET /{id}": deviceorder.O.GetDetail, @@ -238,7 +234,6 @@ func SetRoutes() http.Handler { "DELETE /{id}": deviceorder.O.Delete, "PATCH /{id}/complete": deviceorder.O.Complete, }) - hk.GroupRoutes("/v1/material-order", r, auth.GuardMW, hk.MapHandlerFunc{ "GET /": materialorder.O.GetList, "GET /{id}": materialorder.O.GetDetail, @@ -247,7 +242,6 @@ func SetRoutes() http.Handler { "DELETE /{id}": materialorder.O.Delete, "PATCH /{id}/complete": materialorder.O.Complete, }) - hk.GroupRoutes("/v1/consultation", r, auth.GuardMW, hk.MapHandlerFunc{ "GET /": consultation.O.GetList, "GET /{id}": consultation.O.GetDetail, @@ -256,7 +250,6 @@ func SetRoutes() http.Handler { "DELETE /{id}": consultation.O.Delete, "PATCH /{id}/reply": consultation.O.Reply, }) - hk.GroupRoutes("/v1/chemo", r, auth.GuardMW, hk.MapHandlerFunc{ "GET /": chemo.O.GetList, "GET /{id}": chemo.O.GetDetail, @@ -266,13 +259,20 @@ func SetRoutes() http.Handler { "PATCH /{id}/verify": chemo.O.Verify, "PATCH /{id}/reject": chemo.O.Reject, }) - hc.RegCrud(r, "/v1/control-letter", controlletter.O) hc.RegCrud(r, "/v1/internal-reference", internalreference.O) hc.RegCrud(r, "/v1/ambulance-transport-req", ambulancetransportrequest.O) hc.RegCrud(r, "/v1/responsible-doctor-hist", responsibledoctorhist.O) hc.RegCrud(r, "/v1/adm-employee-hist", admemployeehist.O) - hc.RegCrud(r, "/v1/therapy-protocol", therapyprotocol.O) + hk.GroupRoutes("/v1/therapy-protocol", r, auth.GuardMW, hk.MapHandlerFunc{ + "GET /": therapyprotocol.O.GetList, + "GET /{id}": therapyprotocol.O.GetDetail, + "POST /": therapyprotocol.O.Create, + "PATCH /{id}": therapyprotocol.O.Update, + "DELETE /{id}": therapyprotocol.O.Delete, + "PATCH /{id}/verify": therapyprotocol.O.Verify, + "PATCH /{id}/reject": therapyprotocol.O.Reject, + }) hc.RegCrud(r, "/v1/chemo-protocol", chemoprotocol.O) hc.RegCrud(r, "/v1/upload", upload.O) hc.RegCrud(r, "/v1/encounter-document", encounterdocument.O) @@ -297,7 +297,6 @@ func SetRoutes() http.Handler { "PATCH /{id}/active": user.O.Active, }) hc.RegCrud(r, "/v1/user-fes", userfes.O) - hk.GroupRoutes("/v1/patient", r, hk.MapHandlerFunc{ "GET /": patient.O.GetList, "GET /{id}": patient.O.GetDetail, diff --git a/internal/interface/main-handler/therapy-protocol/handler.go b/internal/interface/main-handler/therapy-protocol/handler.go index 2d9efc3b..769e5677 100644 --- a/internal/interface/main-handler/therapy-protocol/handler.go +++ b/internal/interface/main-handler/therapy-protocol/handler.go @@ -9,7 +9,12 @@ import ( // ua "github.com/karincake/tumpeng/auth/svc" e "simrs-vx/internal/domain/main-entities/therapy-protocol" + erc "simrs-vx/internal/domain/references/common" u "simrs-vx/internal/use-case/main-use-case/therapy-protocol" + + d "github.com/karincake/dodol" + + pa "simrs-vx/internal/lib/auth" ) type myBase struct{} @@ -71,3 +76,44 @@ func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { res, err := u.Delete(dto) rw.DataResponse(w, res, err) } + +func (obj myBase) Verify(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.VerifyDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + + dto.Id = uint(id) + authInfo, err := pa.GetAuthInfo(r) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) + } + + dto.AuthInfo = *authInfo + dto.Status_Code = erc.DVCVerified + res, err := u.Verify(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Reject(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.VerifyDto{} + dto.Id = uint(id) + authInfo, err := pa.GetAuthInfo(r) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) + } + dto.AuthInfo = *authInfo + dto.Status_Code = erc.DVCRejected + res, err := u.Verify(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/use-case/main-use-case/therapy-protocol/case.go b/internal/use-case/main-use-case/therapy-protocol/case.go index bc65325f..ed4f3a21 100644 --- a/internal/use-case/main-use-case/therapy-protocol/case.go +++ b/internal/use-case/main-use-case/therapy-protocol/case.go @@ -1,6 +1,7 @@ package therapy_protocol import ( + "errors" "strconv" "gorm.io/gorm" @@ -15,6 +16,8 @@ import ( ee "simrs-vx/internal/domain/main-entities/encounter" e "simrs-vx/internal/domain/main-entities/therapy-protocol" + erc "simrs-vx/internal/domain/references/common" + ud "simrs-vx/internal/use-case/main-use-case/doctor" ue "simrs-vx/internal/use-case/main-use-case/encounter" ) @@ -45,6 +48,8 @@ func Create(input e.CreateDto) (*d.Data, error) { return err } + statusNew := erc.DVCNew + input.Status_Code = &statusNew if resData, err := CreateData(input, &event, tx); err != nil { return err } else { @@ -291,6 +296,66 @@ func Delete(input e.DeleteDto) (*d.Data, error) { } +func Verify(input e.VerifyDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.TherapyProtocol + var err error + + event := pl.Event{ + Feature: "Verify", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "verify") + + 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.IsNew() { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-state-mismatch", + Detail: "data is not new", + Raw: errors.New("data is not new"), + } + return pl.SetLogError(&event, input) + } + + data.Status_Code = &input.Status_Code + err = tx.Save(&data).Error + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-update-fail", + Detail: "Database update failed", + Raw: err, + } + return pl.SetLogError(&event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "verify", + }, + Data: data.ToResponse(), + }, nil +} + func validateForeignKey(input e.CreateDto) error { // validate encounter if input.Encounter_Id != nil {