Merge branch 'fix/anything-moko' of github.com:dikstub-rssa/simrs-be into fix/anything-moko

This commit is contained in:
dpurbosakti
2025-11-10 08:52:12 +07:00
24 changed files with 973 additions and 507 deletions
+9 -9
View File
@@ -1,9 +1,9 @@
package main
import (
m "simrs-vx/internal/interface/migration"
)
func main() {
m.Migrate(m.Main)
}
package main
import (
m "simrs-vx/internal/interface/migration"
)
func main() {
m.Migrate(m.Main)
}
@@ -0,0 +1,6 @@
-- Modify "Ambulatory" table
ALTER TABLE "public"."Ambulatory" DROP COLUMN "VisitMode_Code";
-- Modify "InternalReference" table
ALTER TABLE "public"."InternalReference" ADD COLUMN "Status_Code" text NULL;
-- Modify "Rehab" table
ALTER TABLE "public"."Rehab" ADD COLUMN "Parent_Encounter_Id" bigint NULL, ADD COLUMN "ExpiredAt" timestamptz NULL, ADD COLUMN "VisitMode_Code" text NULL, ADD COLUMN "Status_Code" text NULL;
@@ -0,0 +1,2 @@
-- Modify "Rehab" table
ALTER TABLE "public"."Rehab" DROP COLUMN "Doctor_Id";
+13 -11
View File
@@ -1,4 +1,4 @@
h1:6umIsneejLUg0V9wUaB2HuCvEHD+2v/dwbxg+y23+wo=
h1:VjwYayb6y4kUl9K9WTTwmXExlHijchOCRwnUYcRlhRI=
20250904105930.sql h1:MEM6blCgke9DzWQSTnLzasbPIrcHssNNrJqZpSkEo6k=
20250904141448.sql h1:J8cmYNk4ZrG9fhfbi2Z1IWz7YkfvhFqTzrLFo58BPY0=
20250908062237.sql h1:Pu23yEW/aKkwozHoOuROvHS/GK4ngARJGdO7FB7HZuI=
@@ -85,13 +85,15 @@ h1:6umIsneejLUg0V9wUaB2HuCvEHD+2v/dwbxg+y23+wo=
20251106090021.sql h1:4JwdKgO8T46YhyWVJUxpRIwudBDlG8QN1brSOYmgQ20=
20251106144745.sql h1:nqnQCzGrVJaq8ilOEOGXeRUL1dolj+OPWKuP8A92FRA=
20251107012049.sql h1:Pff4UqltGS3clSlGr0qq8CQM56L29wyxY0FC/N/YAhU=
20251107064812.sql h1:jjpcAi0B/geEOKWmmR6+1UhWMhjstWhWQcz9lUWrtTY=
20251107064937.sql h1:1nPu0THBf+YquFIJSE4pc1dA7r3EydH92cpp26ozysw=
20251107071420.sql h1:Q+e+OqjdiuK/sghDQ5NxjU+u2zYl+vh/eRBlUz9Idhg=
20251107074318.sql h1:VbOWMw2rClEWgMnDSejXPqXkFoQ4odVsHn3/UAEiCYA=
20251107075050.sql h1:ZZaKJEWXIJ94/0/2Gzzz+HXjmebEs5eP8iUIot26/c8=
20251107080604.sql h1:aq+tINa0ULCZlJcUK2jaeGh6rRH4jJz3e2NrK47m0Ec=
20251107081830.sql h1:Bl9kniyLWeMqd3nrvgCgiUpdcJWp8qX1F41JAM1WbiE=
20251107091033.sql h1:ETTCaAHBT6wipXrEGXIepxLMdD2LNzprPAp99+jnW0w=
20251107091209.sql h1:BUI9JlTzZxCdVHsrRbOye7m47AJEvXNhCaCVv/HzILs=
20251107091541.sql h1:/tW2uXv/o0Q2E4lQzlYNgEftvDqjf3c2AQpZ83Vb6zc=
20251107064812.sql h1:GB9a0ZfMYTIoGNmKUG+XcYUsTnRMFfT4/dAD71uCPc4=
20251107064937.sql h1:IC5pw1Ifj30hiE6dr5NMHXaSHoQI+vRd40N5ABgBHRI=
20251107071420.sql h1:9NO3iyLEXEtWa2kSRjM/8LyzuVIk6pdFL2SuheWjB08=
20251107074318.sql h1:7fHbSRrdjOmHh/xwnjCLwoiB5cW5zeH+uxLV0vZbkIA=
20251107075050.sql h1:np+3uTOnU9QNtK7Knaw8eRMhkyB9AwrtSNHphOBxbHY=
20251107080604.sql h1:cXDBLPJDVWLTG6yEJqkJsOQ7p7VYxLM2SY+mwO8qSHo=
20251107081830.sql h1:/S7OQZo4ZnK80t28g/JyiOTZtmWG/dP5Wg2zXNMQ/iE=
20251107091033.sql h1:/cbkF1nO/IjNSIfDJJx456KJtQ9rWFXOBFAkR/M2xiE=
20251107091209.sql h1:jrLQOUeV8ji2fg0pnEcs1bw4ANUxzTSMXC/rrHLIY+M=
20251107091541.sql h1:6UqbhQQRmzA2+eKu5lIvkwOkk+lH70QLZC8Pjpjcq68=
20251110012217.sql h1:+4ZcAtlZobLY/iTU1hwVEuqCCYtbiDs2N75jTBz1eQM=
20251110012306.sql h1:w3ZvpG2IaS4sZ9WxKcaMAjmy1JhsOPg8zmwjDv4tv7Y=
@@ -6,9 +6,8 @@ import (
)
type CreateDto struct {
Encounter_Id *uint `json:"encounter_id"`
Class_Code ere.AmbulatoryClassCode `json:"class_code" validate:"maxLength=10"`
VisitMode_Code ere.VisitModeCode `json:"visitMode_code"`
Encounter_Id *uint `json:"encounter_id"`
Class_Code ere.AmbulatoryClassCode `json:"class_code" validate:"maxLength=10"`
}
type ReadListDto struct {
@@ -50,9 +49,8 @@ type ResponseDto struct {
func (d Ambulatory) ToResponse() ResponseDto {
resp := ResponseDto{
Encounter_Id: d.Encounter_Id,
Class_Code: d.Class_Code,
VisitMode_Code: d.VisitMode_Code,
Encounter_Id: d.Encounter_Id,
Class_Code: d.Class_Code,
}
resp.Main = d.Main
return resp
@@ -6,8 +6,7 @@ import (
)
type Ambulatory struct {
ecore.Main // adjust this according to the needs
Encounter_Id *uint `json:"encounter_id"`
Class_Code ere.AmbulatoryClassCode `json:"class_code" gorm:"size:10"`
VisitMode_Code ere.VisitModeCode `json:"visitMode_code"`
ecore.Main // adjust this according to the needs
Encounter_Id *uint `json:"encounter_id"`
Class_Code ere.AmbulatoryClassCode `json:"class_code" gorm:"size:10"`
}
+43 -4
View File
@@ -1,6 +1,13 @@
package encounter
import (
eam "simrs-vx/internal/domain/main-entities/ambulatory"
edc "simrs-vx/internal/domain/main-entities/death-cause"
eem "simrs-vx/internal/domain/main-entities/emergency"
eip "simrs-vx/internal/domain/main-entities/inpatient"
eir "simrs-vx/internal/domain/main-entities/internal-reference"
er "simrs-vx/internal/domain/main-entities/rehab/base"
// std
"time"
@@ -19,7 +26,6 @@ import (
ea "simrs-vx/internal/domain/main-entities/appointment"
ed "simrs-vx/internal/domain/main-entities/doctor"
ee "simrs-vx/internal/domain/main-entities/employee"
eir "simrs-vx/internal/domain/main-entities/internal-reference"
ep "simrs-vx/internal/domain/main-entities/patient"
es "simrs-vx/internal/domain/main-entities/specialist"
ess "simrs-vx/internal/domain/main-entities/subspecialist"
@@ -48,8 +54,10 @@ type CreateDto struct {
Appointment_Id *uint `json:"appointment_id"`
RefTypeCode ere.RefTypeCode `json:"refTypeCode"`
NewStatus bool `json:"newStatus"`
VisitMode_Code *ere.VisitModeCode `json:"visitMode_code"` // if subClass_Code is rehab
AllocatedVisitCount *int `json:"allocatedVisitCount"` // if subClass_Code is rehab and VisitMode_Code is "adm"
Id uint `json:"-"`
RecentEncounterAdm *Encounter `json:"-"` // if subClass_Code is rehab
VisitMode_Code ere.VisitModeCode `json:"-"` // if subClass_Code is rehab
pa.AuthInfo
}
@@ -114,7 +122,6 @@ type DischargeDto struct {
AdmDischargeEducation *string `json:"admDischargeEducation"`
DischargeReason *string `json:"dischargeReason"`
DeathCause *string `json:"deathCause"`
InternalReferences *[]eir.CreateDto `json:"internalReferences,omitempty"`
}
type CheckinDto struct {
@@ -125,6 +132,17 @@ type CheckinDto struct {
FinishedAt *time.Time `json:"finishedAt"`
}
type SwitchUnitDto struct {
Id uint `json:"id"`
PolySwitchCode *ere.PolySwitchCode `json:"polySwitchCode"`
InternalReferences *[]eir.CreateDto `json:"internalReferences" validate:"required"`
}
type ApproveUnitDto struct {
Id uint `json:"id"`
InternalReferences_Id uint16 `json:"internalReferences_id" validate:"required"`
}
type ResponseDto struct {
ecore.Main
Patient_Id *uint `json:"patient_id"`
@@ -159,6 +177,17 @@ type ResponseDto struct {
DischargeReason *string `json:"dischargeReason"`
Status_Code erc.DataStatusCode `json:"status_code"`
VclaimSep *evs.VclaimSep `json:"vclaimSep,omitempty"`
StartedAt *time.Time `json:"startedAt"`
FinishedAt *time.Time `json:"finishedAt"`
Discharge_Date *time.Time `json:"discharge_date"`
InternalReferences *[]eir.InternalReference `json:"internalReferences,omitempty"`
DeathCause *edc.DeathCause `json:"deathCause,omitempty"`
NewStatus bool `json:"newStatus"`
Ambulatory *eam.Ambulatory `json:"ambulatory,omitempty"`
Emergency *eem.Emergency `json:"emergency,omitempty"`
Inpatient *eip.Inpatient `json:"inpatient,omitempty"`
Rehab *er.Basic `json:"rehab,omitempty"`
RehabChildren *[]er.Basic `json:"rehabChildren,omitempty"`
}
func (d Encounter) ToResponse() ResponseDto {
@@ -195,6 +224,16 @@ func (d Encounter) ToResponse() ResponseDto {
DischargeReason: d.DischargeReason,
Status_Code: d.Status_Code,
VclaimSep: d.VclaimSep,
StartedAt: d.StartedAt,
FinishedAt: d.FinishedAt,
Discharge_Date: d.Discharge_Date,
InternalReferences: d.InternalReferences,
DeathCause: d.DeathCause,
NewStatus: d.NewStatus,
Emergency: d.Emergency,
Inpatient: d.Inpatient,
Rehab: d.Rehab,
RehabChildren: d.RehabChildren,
}
resp.Main = d.Main
return resp
@@ -69,6 +69,7 @@ type Encounter struct {
Emergency *eem.Emergency `json:"emergency,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"`
Inpatient *eip.Inpatient `json:"inpatient,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"`
Rehab *er.Basic `json:"rehab,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"`
RehabChildren *[]er.Basic `json:"rehabChildren,omitempty" gorm:"foreignKey:Parent_Encounter_Id;references:Id"`
}
func (d Encounter) IsDone() bool {
@@ -1,15 +1,18 @@
package internal_reference
import (
erc "simrs-vx/internal/domain/references/common"
ecore "simrs-vx/internal/domain/base-entities/core"
ed "simrs-vx/internal/domain/main-entities/doctor"
eu "simrs-vx/internal/domain/main-entities/unit"
)
type CreateDto struct {
Encounter_Id *uint `json:"-"`
Unit_Id *uint16 `json:"unit_id"`
Doctor_Id *uint `json:"doctor_Id"`
Encounter_Id *uint `json:"-"`
Unit_Id *uint16 `json:"unit_id"`
Doctor_Id *uint `json:"doctor_Id"`
Status_Code erc.DataApprovalCode `json:"status_code"`
}
type ReadListDto struct {
@@ -19,9 +22,10 @@ type ReadListDto struct {
}
type FilterDto struct {
Encounter_Id *uint `json:"encounter-id"`
Unit_Id *uint `json:"unit-id"`
Doctor_Id *uint `json:"doctor-id"`
Encounter_Id *uint `json:"encounter-id"`
Unit_Id *uint `json:"unit-id"`
Doctor_Id *uint `json:"doctor-id"`
Status_Code erc.DataApprovalCode `json:"status-code"`
}
type ReadDetailDto struct {
@@ -46,11 +50,12 @@ type MetaDto struct {
type ResponseDto struct {
ecore.Main
Encounter_Id *uint `json:"encounter_id"`
Unit_Id *uint16 `json:"unit_id"`
Unit *eu.Unit `json:"unit,omitempty"`
Doctor_Id *uint `json:"doctor_id"`
Doctor *ed.Doctor `json:"doctor,omitempty"`
Encounter_Id *uint `json:"encounter_id"`
Unit_Id *uint16 `json:"unit_id"`
Unit *eu.Unit `json:"unit,omitempty"`
Doctor_Id *uint `json:"doctor_id"`
Doctor *ed.Doctor `json:"doctor,omitempty"`
Status_Code *erc.DataApprovalCode `json:"status_code"`
}
func (d InternalReference) ToResponse() ResponseDto {
@@ -60,6 +65,7 @@ func (d InternalReference) ToResponse() ResponseDto {
Unit: d.Unit,
Doctor_Id: d.Doctor_Id,
Doctor: d.Doctor,
Status_Code: d.Status_Code,
}
resp.Main = d.Main
return resp
@@ -1,6 +1,8 @@
package internal_reference
import (
erc "simrs-vx/internal/domain/references/common"
ecore "simrs-vx/internal/domain/base-entities/core"
ed "simrs-vx/internal/domain/main-entities/doctor"
eu "simrs-vx/internal/domain/main-entities/unit"
@@ -8,9 +10,10 @@ import (
type InternalReference struct {
ecore.Main
Encounter_Id *uint `json:"encounter_id"`
Unit_Id *uint16 `json:"unit_id"`
Unit *eu.Unit `json:"unit,omitempty" gorm:"foreignKey:Unit_Id;references:Id"`
Doctor_Id *uint `json:"doctor_id"`
Doctor *ed.Doctor `json:"doctor,omitempty" gorm:"foreignKey:Doctor_Id;references:Id"`
Encounter_Id *uint `json:"encounter_id"`
Unit_Id *uint16 `json:"unit_id"`
Unit *eu.Unit `json:"unit,omitempty" gorm:"foreignKey:Unit_Id;references:Id"`
Doctor_Id *uint `json:"doctor_id"`
Doctor *ed.Doctor `json:"doctor,omitempty" gorm:"foreignKey:Doctor_Id;references:Id"`
Status_Code *erc.DataApprovalCode `json:"status_code"`
}
@@ -1,16 +1,21 @@
package base
import (
erc "simrs-vx/internal/domain/references/common"
ere "simrs-vx/internal/domain/references/encounter"
"time"
ecore "simrs-vx/internal/domain/base-entities/core"
ed "simrs-vx/internal/domain/main-entities/doctor"
)
type Basic struct {
ecore.Main // adjust this according to the needs
Encounter_Id *uint `json:"encounter_id"`
Doctor_Id *uint `json:"doctor_id"`
Doctor *ed.Doctor `json:"doctor,omitempty" gorm:"foreignKey:Doctor_Id;references:Id"`
AllocatedVisitCount *int `json:"allocatedVisitCount"`
ecore.Main // adjust this according to the needs
Parent_Encounter_Id *uint `json:"parent_encounter_id"`
Encounter_Id *uint `json:"encounter_id"`
AllocatedVisitCount *int `json:"allocatedVisitCount"`
ExpiredAt *time.Time `json:"expiredAt"`
VisitMode_Code *ere.VisitModeCode `json:"visitMode_code"`
Status_Code *erc.DataStatusCode `json:"status_code"`
}
func (Basic) TableName() string {
+23 -12
View File
@@ -1,14 +1,20 @@
package rehab
import (
erc "simrs-vx/internal/domain/references/common"
ere "simrs-vx/internal/domain/references/encounter"
ecore "simrs-vx/internal/domain/base-entities/core"
ed "simrs-vx/internal/domain/main-entities/doctor"
"time"
)
type CreateDto struct {
Encounter_Id *uint `json:"encounter_id"`
Doctor_Id *uint `json:"doctor_id"`
AllocatedVisitCount *int `json:"allocatedVisitCount"`
Encounter_Id *uint `json:"encounter_id"`
Parent_Encounter_Id *uint `json:"parent_encounter_id"`
AllocatedVisitCount *int `json:"allocatedVisitCount"`
ExpiredAt *time.Time `json:"expiredAt"`
VisitMode_Code ere.VisitModeCode `json:"visitMode_code"`
Status_Code erc.DataStatusCode `json:"status_code"`
}
type ReadListDto struct {
@@ -18,8 +24,9 @@ type ReadListDto struct {
}
type FilterDto struct {
Encounter_Id *uint `json:"encounter-id"`
Doctor_Id *uint `json:"doctor-id"`
Encounter_Id *uint `json:"encounter-id"`
Parent_Encounter_Id *uint `json:"parent-encounter-id"`
VisitMode_Code ere.VisitModeCode `json:"visitMode-code"`
}
type ReadDetailDto struct {
@@ -44,18 +51,22 @@ type MetaDto struct {
type ResponseDto struct {
ecore.Main
Encounter_Id *uint `json:"encounter_id"`
Doctor_Id *uint `json:"doctor_id"`
Doctor *ed.Doctor `json:"doctor,omitempty"`
AllocatedVisitCount *int `json:"allocatedVisitCount"`
Encounter_Id *uint `json:"encounter_id"`
Parent_Encounter_Id *uint `json:"parent_encounter_id"`
AllocatedVisitCount *int `json:"allocatedVisitCount"`
ExpiredAt *time.Time `json:"expiredAt"`
VisitMode_Code *ere.VisitModeCode `json:"visitMode_code"`
Status_Code *erc.DataStatusCode `json:"status_code"`
}
func (d Rehab) ToResponse() ResponseDto {
resp := ResponseDto{
Encounter_Id: d.Encounter_Id,
Doctor_Id: d.Doctor_Id,
Doctor: d.Doctor,
Parent_Encounter_Id: d.Parent_Encounter_Id,
AllocatedVisitCount: d.AllocatedVisitCount,
ExpiredAt: d.ExpiredAt,
VisitMode_Code: d.VisitMode_Code,
Status_Code: d.Status_Code,
}
resp.Main = d.Main
return resp
+25 -25
View File
@@ -2,26 +2,26 @@
package clinical
type (
SubjectCode string
ObjectCode string
AssessmentCode string
PlanCode string
InstructionCode string
HeadToToeCode string
McuUrgencyLevelCode string
McuScopeCode string
SoapiTypeCode string
MedicalAction string
VehicleTypeCode string
GeneralEduCode string
SpecialEduCode string
EduAssessmentCode string
AbilityCode string
WillCode string
MedObstacleCode string
LearnMethodCode string
LangClassCode string
TranslatorSrcCode string
SubjectCode string
ObjectCode string
AssessmentCode string
PlanCode string
InstructionCode string
HeadToToeCode string
McuUrgencyLevelCode string
McuScopeCode string
SoapiTypeCode string
MedicalActionTypeCode string
VehicleTypeCode string
GeneralEduCode string
SpecialEduCode string
EduAssessmentCode string
AbilityCode string
WillCode string
MedObstacleCode string
LearnMethodCode string
LangClassCode string
TranslatorSrcCode string
)
const (
@@ -124,11 +124,11 @@ const (
STCProgress SoapiTypeCode = "progress" // CPPT
STCDevRecord SoapiTypeCode = "dev-record" // Catatan Perkembangan
MAChemo MedicalAction = "chemo"
MAHemo MedicalAction = "hemo"
MAThalasemia MedicalAction = "thalasemia"
MAEchocardio MedicalAction = "echocardio"
MASpirometry MedicalAction = "spirometry"
MATCChemo MedicalActionTypeCode = "chemo"
MATCHemo MedicalActionTypeCode = "hemo"
MATCThalasemia MedicalActionTypeCode = "thalasemia"
MATCEchocardio MedicalActionTypeCode = "echocardio"
MATCSpirometry MedicalActionTypeCode = "spirometry"
VTCAmbulance VehicleTypeCode = "ambulance" // Ambulans
VTCTransport VehicleTypeCode = "transport" // Transport
@@ -15,6 +15,7 @@ type (
DataAvailabilityCode string
DataVerifiedCode string
CrudCode string
DataApprovalCode string
)
const (
@@ -96,6 +97,10 @@ const (
CCRead CrudCode = "r" // Read
CCUpdate CrudCode = "u" // Update
CCDelete CrudCode = "d" // Delete
DACNew DataApprovalCode = "new"
DACApproved DataApprovalCode = "approved"
DACRejected DataApprovalCode = "rejected"
)
func GetDayCodes() map[DayCode]string {
@@ -18,6 +18,7 @@ type (
AllPaymentMethodCode string
SEPRefTypeCode string
VisitModeCode string
PolySwitchCode string
)
const (
@@ -107,6 +108,9 @@ const (
VMCAdm VisitModeCode = "adm"
VMCSeries VisitModeCode = "series"
PSCConsulPoly PolySwitchCode = "consul-poly" // Konsultasi Poliklinik Lain
PSCConsulExecutive PolySwitchCode = "consul-executive" // Konsultasi Antar Dokter Eksekutif
)
func (ec EncounterClassCode) Code() string {
@@ -3,18 +3,17 @@ package encounter
import (
"net/http"
pa "simrs-vx/internal/lib/auth"
d "github.com/karincake/dodol"
rw "github.com/karincake/risoles"
sf "github.com/karincake/semprit"
// ua "github.com/karincake/tumpeng/auth/svc"
erc "simrs-vx/internal/domain/references/common"
e "simrs-vx/internal/domain/main-entities/encounter"
u "simrs-vx/internal/use-case/main-use-case/encounter"
erc "simrs-vx/internal/domain/references/common"
pa "simrs-vx/internal/lib/auth"
d "github.com/karincake/dodol"
)
type myBase struct{}
@@ -31,7 +30,13 @@ func (obj myBase) Create(w http.ResponseWriter, r *http.Request) {
if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res {
return
}
if valid := validateRequestCreate(w, dto); !valid {
// validate SubClass
if err := verifyClassCode(dto); err != nil {
rw.DataResponse(w, nil, d.FieldError{
Code: dataValidationFail,
Message: err.Error(),
})
return
}
@@ -192,3 +197,40 @@ func (obj myBase) Skip(w http.ResponseWriter, r *http.Request) {
res, err := u.UpdateStatusCode(dto)
rw.DataResponse(w, res, err)
}
func (obj myBase) RequestSwitchUnit(w http.ResponseWriter, r *http.Request) {
dto := e.SwitchUnitDto{}
id := rw.ValidateInt(w, "id", r.PathValue("id"))
if id <= 0 {
return
}
if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res {
return
}
// validate request body
if valid := validateRequestSwitchUnit(w, dto); !valid {
return
}
dto.Id = uint(id)
res, err := u.RequestSwitchUnit(dto)
rw.DataResponse(w, res, err)
}
func (obj myBase) ApproveSwitchUnit(w http.ResponseWriter, r *http.Request) {
dto := e.ApproveUnitDto{}
id := rw.ValidateInt(w, "id", r.PathValue("id"))
if id <= 0 {
return
}
if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res {
return
}
dto.Id = uint(id)
res, err := u.ApproveSwitchUnit(dto)
rw.DataResponse(w, res, err)
}
@@ -1,10 +1,14 @@
package encounter
import (
"errors"
"fmt"
"net/http"
e "simrs-vx/internal/domain/main-entities/encounter"
ere "simrs-vx/internal/domain/references/encounter"
ua "simrs-vx/internal/use-case/main-use-case/ambulatory"
ue "simrs-vx/internal/use-case/main-use-case/emergency"
ui "simrs-vx/internal/use-case/main-use-case/inpatient"
d "github.com/karincake/dodol"
rw "github.com/karincake/risoles"
@@ -12,42 +16,32 @@ import (
const dataValidationFail = "data-validation-fail"
func verifyClassCode(input e.CreateDto) (err error) {
switch input.Class_Code {
case ere.ECAmbulatory:
_, err = ua.CheckClassCode(input.SubClass_Code)
case ere.ECEmergency:
_, err = ue.CheckClassCode(input.SubClass_Code)
case ere.ECInpatient:
_, err = ui.CheckClassCode(input.SubClass_Code)
default:
return errors.New("invalid encounter class code")
}
if err != nil {
return
}
return nil
}
func validateRequestCheckout(w http.ResponseWriter, i e.DischargeDto) (valid bool) {
switch *i.Discharge_Method_Code {
case ere.DMCDeath:
if i.DeathCause == nil {
rw.DataResponse(w, nil, d.FieldError{
Code: dataValidationFail,
Message: "deathCause required if discharge_method_code is death",
})
return
}
case ere.DMCConsulPoly, ere.DMCConsulExecutive:
if i.InternalReferences == nil {
rw.DataResponse(w, nil, d.FieldError{
Code: dataValidationFail,
Message: fmt.Sprintf("internalReferences required if discharge_method_code is %s", *i.Discharge_Method_Code),
})
return
}
for _, v := range *i.InternalReferences {
if v.Unit_Id == nil {
rw.DataResponse(w, nil, d.FieldError{
Code: dataValidationFail,
Message: "internalReferences.unit_id required",
})
return
}
if v.Doctor_Id == nil {
rw.DataResponse(w, nil, d.FieldError{
Code: dataValidationFail,
Message: "internalReferences.doctor_id required",
})
return
}
}
if *i.Discharge_Method_Code == ere.DMCDeath && i.DeathCause == nil {
rw.DataResponse(w, nil, d.FieldError{
Code: dataValidationFail,
Message: "deathCause required if discharge_method_code is death",
})
return
}
return true
}
@@ -64,18 +58,30 @@ func validateRequestCheckIn(w http.ResponseWriter, i e.CheckinDto) (valid bool)
return true
}
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.ACCRehab && *i.VisitMode_Code == ere.VMCAdm {
if *i.AllocatedVisitCount == 0 {
rw.DataResponse(w, nil, d.FieldError{
Code: dataValidationFail,
Message: "allocatedVisitCount required",
})
return
}
func validateRequestSwitchUnit(w http.ResponseWriter, i e.SwitchUnitDto) (valid bool) {
if i.InternalReferences == nil {
rw.DataResponse(w, nil, d.FieldError{
Code: dataValidationFail,
Message: fmt.Sprintf("internalReferences required"),
})
return
}
for _, v := range *i.InternalReferences {
if v.Unit_Id == nil {
rw.DataResponse(w, nil, d.FieldError{
Code: dataValidationFail,
Message: "internalReferences.unit_id required",
})
return
}
if v.Doctor_Id == nil {
rw.DataResponse(w, nil, d.FieldError{
Code: dataValidationFail,
Message: "internalReferences.doctor_id required",
})
return
}
}
+13 -11
View File
@@ -145,17 +145,19 @@ func SetRoutes() http.Handler {
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,
"POST /": encounter.O.Create,
"PATCH /{id}": encounter.O.Update,
"DELETE /{id}": encounter.O.Delete,
"PATCH /{id}/check-out": encounter.O.CheckOut,
"PATCH /{id}/check-in": encounter.O.CheckIn,
"PATCH /{id}/proccess": encounter.O.Process,
"PATCH /{id}/cancel": encounter.O.Cancel,
"PATCH /{id}/reject": encounter.O.Reject,
"PATCH /{id}/skip": encounter.O.Skip,
"GET /": encounter.O.GetList,
"GET /{id}": encounter.O.GetDetail,
"POST /": encounter.O.Create,
"PATCH /{id}": encounter.O.Update,
"DELETE /{id}": encounter.O.Delete,
"PATCH /{id}/check-out": encounter.O.CheckOut,
"PATCH /{id}/check-in": encounter.O.CheckIn,
"PATCH /{id}/proccess": encounter.O.Process,
"PATCH /{id}/cancel": encounter.O.Cancel,
"PATCH /{id}/reject": encounter.O.Reject,
"PATCH /{id}/skip": encounter.O.Skip,
"PATCH /{id}/req-switch-unit": encounter.O.RequestSwitchUnit,
"PATCH /{id}/approve-switch-unit": encounter.O.ApproveSwitchUnit,
})
hk.GroupRoutes("/v1/mcu-order", r, auth.GuardMW, hk.MapHandlerFunc{
"GET /": mcuorder.O.GetList,
@@ -22,7 +22,6 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Ambulatory) {
data.Encounter_Id = inputSrc.Encounter_Id
data.Class_Code = inputSrc.Class_Code
data.VisitMode_Code = inputSrc.VisitMode_Code
}
func CheckClassCode(input *string) (ere.AmbulatoryClassCode, error) {
+241 -166
View File
@@ -2,7 +2,7 @@ package encounter
import (
"errors"
authhelper "simrs-vx/internal/lib/auth"
"fmt"
"strconv"
"time"
@@ -17,28 +17,18 @@ import (
ere "simrs-vx/internal/domain/references/encounter"
eaeh "simrs-vx/internal/domain/main-entities/adm-employee-hist"
ea "simrs-vx/internal/domain/main-entities/ambulatory"
ec "simrs-vx/internal/domain/main-entities/chemo"
edc "simrs-vx/internal/domain/main-entities/death-cause"
ed "simrs-vx/internal/domain/main-entities/doctor"
ee "simrs-vx/internal/domain/main-entities/emergency"
eem "simrs-vx/internal/domain/main-entities/employee"
e "simrs-vx/internal/domain/main-entities/encounter"
ei "simrs-vx/internal/domain/main-entities/inpatient"
er "simrs-vx/internal/domain/main-entities/rehab"
eir "simrs-vx/internal/domain/main-entities/internal-reference"
erdh "simrs-vx/internal/domain/main-entities/responsible-doctor-hist"
es "simrs-vx/internal/domain/main-entities/soapi"
uaeh "simrs-vx/internal/use-case/main-use-case/adm-employee-hist"
ua "simrs-vx/internal/use-case/main-use-case/ambulatory"
uc "simrs-vx/internal/use-case/main-use-case/chemo"
udc "simrs-vx/internal/use-case/main-use-case/death-cause"
ud "simrs-vx/internal/use-case/main-use-case/doctor"
ue "simrs-vx/internal/use-case/main-use-case/emergency"
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"
us "simrs-vx/internal/use-case/main-use-case/soapi"
uir "simrs-vx/internal/use-case/main-use-case/internal-reference"
urdh "simrs-vx/internal/use-case/main-use-case/responsible-doctor-hist"
)
const source = "encounter"
@@ -46,8 +36,11 @@ const source = "encounter"
var now = time.Now()
func Create(input e.CreateDto) (*d.Data, error) {
data := e.Encounter{}
createSoapi := []es.CreateDto{}
var (
data e.Encounter
recentSoapiDataforCopy []es.CreateDto
err error
)
event := pl.Event{
Feature: "Create",
@@ -57,51 +50,36 @@ func Create(input e.CreateDto) (*d.Data, error) {
// Start log
pl.SetLogInfo(&event, input, "started", "create")
// validate SubClass
var subCode interface{}
subCode, err := verifyClassCode(input)
if err != nil {
return nil, err
}
// verify whether the allocated visit count has not exceeded the limit
if input.Class_Code == ere.ECAmbulatory && subCode.(ere.AmbulatoryClassCode) == ere.ACCRehab &&
*input.VisitMode_Code == ere.VMCSeries {
dataEncounter, valid, err := verifyAllocatedVisitCount(input, &event)
// validate rehab bpjs
if input.RefTypeCode == ere.RTCBpjs && input.Class_Code == ere.ECAmbulatory && ere.AmbulatoryClassCode(*input.SubClass_Code) == ere.ACCRehab {
// get latest rehab data
recentRehabData, err := getLatestRehabData(input, &event)
if err != nil {
return nil, err
}
if !valid {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "visit-limit-exceeded",
Detail: "Encounter has exceeded the allowed number of visits",
Raw: errors.New("visit count exceeds allowed limit"),
if recentRehabData != nil {
// determine VisitModeCode
input.VisitMode_Code, input.RecentEncounterAdm, err = determineVisitMode(recentRehabData, input, &event)
if err != nil {
return nil, err
}
return nil, pl.SetLogError(&event, input)
} else {
input.VisitMode_Code = ere.VMCAdm
}
// get data soapi
createSoapi, err = getSoapiEncounterAdm(dataEncounter, &event)
if err != nil {
return nil, err
// if visitMode_Code is series, then get data soapi for copy
if input.VisitMode_Code == ere.VMCSeries {
// get data soapi
recentSoapiDataforCopy, err = getSoapiEncounterAdm(*input.RecentEncounterAdm, &event)
if err != nil {
return nil, err
}
}
}
// check if patient is new in the hospital
dataPatient, err := ReadList(e.ReadListDto{
FilterDto: e.FilterDto{Patient_Id: input.Patient_Id},
AuthInfo: authhelper.AuthInfo{User_Id: input.User_Id}})
if err != nil {
return nil, err
}
if list, ok := dataPatient.Data.([]e.ResponseDto); ok {
if len(list) < 1 {
input.NewStatus = true
}
}
input.NewStatus, err = identifyPatientStatus(input)
err = dg.I.Transaction(func(tx *gorm.DB) error {
mwRunner := newMiddlewareRunner(&event, tx)
@@ -122,74 +100,18 @@ func Create(input e.CreateDto) (*d.Data, error) {
return err
} else {
data = *resData
input.Id = data.Id
}
switch input.Class_Code {
case ere.ECAmbulatory:
subCodeAmbulatory := subCode.(ere.AmbulatoryClassCode)
ambCreate := ea.CreateDto{
Encounter_Id: &data.Id,
Class_Code: subCodeAmbulatory,
VisitMode_Code: *input.VisitMode_Code,
}
_, err = ua.CreateData(ambCreate, &event, tx)
if err != nil {
return err
}
if subCodeAmbulatory == ere.ACCChemo {
chemoCreate := ec.CreateDto{
Encounter_Id: &data.Id,
Status_Code: erc.DVCNew,
SrcUnit_Id: input.Unit_Id,
}
_, err = uc.CreateData(chemoCreate, &event, tx)
if err != nil {
return err
}
}
if subCodeAmbulatory == ere.ACCRehab && *input.VisitMode_Code == ere.VMCAdm {
// create data rehab
if _, err = ur.CreateData(er.CreateDto{
Encounter_Id: &data.Id,
Doctor_Id: input.Appointment_Doctor_Id,
AllocatedVisitCount: input.AllocatedVisitCount}, &event, tx); err != nil {
return err
}
} 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
}
}
case ere.ECEmergency:
emerCreate := ee.CreateDto{
Encounter_Id: &data.Id,
Class_Code: subCode.(ere.EmergencyClassCode),
}
_, err = ue.CreateData(emerCreate, &event, tx)
if err != nil {
return err
}
case ere.ECInpatient:
inpCreate := ei.CreateDto{
Encounter_Id: &data.Id,
Class_Code: subCode.(ere.InpatientClassCode),
Infra_Id: input.Infra_Id,
}
_, err = ui.CreateData(inpCreate, &event, tx)
if err != nil {
return err
}
default:
return errors.New("invalid encounter class code")
// insert ambulatory/emergency/inpatient
err = insertdataClassCode(input, recentSoapiDataforCopy, &event, tx)
if err != nil {
return err
}
// insert adm_employee_hist
if _, err := uaeh.CreateData(eaeh.CreateDto{
Encounter_Id: &data.Main.Id,
Encounter_Id: &data.Id,
Employee_Id: data.Adm_Employee_Id,
StartedAt: &now}, &event, tx); err != nil {
return err
@@ -441,7 +363,7 @@ func Delete(input e.DeleteDto) (*d.Data, error) {
}
func CheckOut(input e.DischargeDto) (*d.Data, error) {
rdDto := e.ReadDetailDto{Id: uint16(input.Id), Includes: "Ambulatory"}
rdDto := e.ReadDetailDto{Id: uint16(input.Id), Includes: "Ambulatory,Rehab"}
var data *e.Encounter
var err error
@@ -471,10 +393,16 @@ func CheckOut(input e.DischargeDto) (*d.Data, error) {
if data.Ambulatory != nil && (data.Ambulatory.Class_Code == ere.ACCReg || data.Ambulatory.Class_Code == ere.ACCRehab) {
// validate if soapi exist
err = getSoapiByTypeCode(input.Id, *data.Ambulatory, &event, "check-out")
if err != nil {
if err = getSoapiByTypeCode(data, &event, "check-out"); err != nil {
return err
}
if data.Ambulatory.Class_Code == ere.ACCRehab {
// verify and update rehabData if visit count has reached the allowed limit
if err = verifyRehabLimit(data, &event, tx); err != nil {
return err
}
}
} else {
// chemo TBC
if err := checkSoapiByDocExists(data.Id, &event, tx); err != nil {
@@ -497,26 +425,20 @@ func CheckOut(input e.DischargeDto) (*d.Data, error) {
}
// update finishedAt in latest responsible_doctor_hist
if err = updateLatestResponsibleDoctorHist(e.CheckinDto{Id: input.Id, StartedAt: &now}, &event, tx); err != nil {
if err = updateLatestResponsibleDoctorHist(e.CheckinDto{Id: input.Id, FinishedAt: &now}, &event, tx); err != nil {
return err
}
// update finishedAt in latest adm_employee_hist
if err = updateLatestAdmEmployeeHist(e.CheckinDto{Id: input.Id, StartedAt: &now}, &event, tx); err != nil {
if err = updateLatestAdmEmployeeHist(e.CheckinDto{Id: input.Id, FinishedAt: &now}, &event, tx); err != nil {
return err
}
switch *input.Discharge_Method_Code {
case ere.DMCDeath:
// insert data death-cause
// insert data death-cause
if *input.Discharge_Method_Code == ere.DMCDeath {
if _, err = udc.CreateData(edc.CreateDto{Encounter_Id: &input.Id, Value: input.DeathCause}, &event, tx); err != nil {
return err
}
case ere.DMCConsulPoly, ere.DMCConsulExecutive:
// bulk insert internal-references
if err = createInternalReferences(input, &event, tx); err != nil {
return err
}
}
pl.SetLogInfo(&event, nil, "complete")
@@ -645,13 +567,13 @@ func CheckIn(input e.CheckinDto) (*d.Data, error) {
// 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")
err = getSoapiByTypeCode(data, &event, "check-in")
if err != nil {
return err
}
}
// Insert responsible_doctor_hist if responsible_doctor_id has changed && update latest history
// Upsert responsible_doctor_hist if responsible_doctor_id has changed
if data.Responsible_Doctor_Id == nil || *input.Responsible_Doctor_Id != *data.Responsible_Doctor_Id {
// upsert responsibleDoctorHist
if err = upsertResponsibleDoctorHist(erdh.CreateDto{
@@ -663,7 +585,7 @@ func CheckIn(input e.CheckinDto) (*d.Data, error) {
}
}
// Insert adm_employee_hist if adm_employee_id has changed && update latest history
// Upsert adm_employee_hist if adm_employee_id has changed
if input.Adm_Employee_Id != nil && *input.Adm_Employee_Id != *data.Adm_Employee_Id {
// upsert admEmployeeHist
if err = upsertAdmEmployeeHist(eaeh.CreateDto{
@@ -680,15 +602,6 @@ func CheckIn(input e.CheckinDto) (*d.Data, error) {
return err
}
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
}
}
pl.SetLogInfo(&event, nil, "complete")
return nil
@@ -708,43 +621,205 @@ func CheckIn(input e.CheckinDto) (*d.Data, error) {
}, nil
}
func validateForeignKey(input e.CheckinDto) error {
// validate employee_Id
if input.Adm_Employee_Id != nil {
if _, err := uem.ReadDetail(eem.ReadDetailDto{Id: uint16(*input.Adm_Employee_Id)}); err != nil {
func RequestSwitchUnit(input e.SwitchUnitDto) (*d.Data, error) {
rdDto := e.ReadDetailDto{Id: uint16(input.Id), Includes: "Responsible_Doctor"}
var data *e.Encounter
var err error
event := pl.Event{
Feature: "RequestSwitchUnit",
Source: source,
}
// Start log
pl.SetLogInfo(&event, input, "started", "checkOut")
unitIDs := make(map[uint16]struct{})
doctorIDs := make(map[uint]struct{})
for _, ref := range *input.InternalReferences {
if ref.Unit_Id != nil {
unitIDs[*ref.Unit_Id] = struct{}{}
}
if ref.Doctor_Id != nil {
doctorIDs[*ref.Doctor_Id] = struct{}{}
}
}
// validate unit
if err = validateUnitIds(unitIDs, &event); err != nil {
return nil, err
}
// validate doctor
if err = validateDoctorIds(doctorIDs, &event); 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 {
return err
}
}
// validate doctor_id
if input.Responsible_Doctor_Id != nil {
if _, err := ud.ReadDetail(ed.ReadDetailDto{Id: uint16(*input.Responsible_Doctor_Id)}); err != nil {
//if data.IsDone() {
// event.Status = "failed"
// event.ErrInfo = pl.ErrorInfo{
// Code: "data-state-mismatch",
// Detail: "encounter is done",
// Raw: errors.New("encounter is done"),
// }
// return pl.SetLogError(&event, input)
//}
// verify Soapi exist for current responsible doctor
dataSoapi, err := getSoapiByResponsibleDoctor(*data, &event)
if err != nil {
return err
}
if len(dataSoapi) < 1 {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "missing-soapi",
Detail: fmt.Sprintf("Missing soapi from latest responsible doctor"),
}
return pl.SetLogError(&event, input)
}
// bulk internal references
if err := uir.CreateBulkData(*input.InternalReferences, input.Id, &event, tx); err != nil {
return err
}
pl.SetLogInfo(&event, nil, "complete")
return nil
})
if err != nil {
return nil, err
}
return nil
return &d.Data{
Meta: d.IS{
"source": source,
"structure": "single-data",
"status": "requestSwitchUnit",
},
Data: data.ToResponse(),
}, nil
}
func verifyClassCode(input e.CreateDto) (subCode interface{}, err error) {
switch input.Class_Code {
case ere.ECAmbulatory:
subCode, err = ua.CheckClassCode(input.SubClass_Code)
if err != nil {
return nil, err
}
case ere.ECEmergency:
subCode, err = ue.CheckClassCode(input.SubClass_Code)
if err != nil {
return nil, err
}
case ere.ECInpatient:
subCode, err = ui.CheckClassCode(input.SubClass_Code)
if err != nil {
return nil, err
}
default:
return nil, errors.New("invalid encounter class code")
func ApproveSwitchUnit(input e.ApproveUnitDto) (*d.Data, error) {
rdDto := e.ReadDetailDto{Id: uint16(input.Id), Includes: "Responsible_Doctor"}
var data *e.Encounter
var err error
event := pl.Event{
Feature: "ApproveSwitchUnit",
Source: source,
}
return
// Start log
pl.SetLogInfo(&event, input, "started", "approveSwitchUnit")
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
}
// get internal reference
irData, err := uir.ReadDetailData(eir.ReadDetailDto{
Id: input.InternalReferences_Id, Includes: "Doctor"}, &event, tx)
if err != nil {
return err
}
if *irData.Status_Code != erc.DACNew {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-state-mismatch",
Detail: "internal references is approve",
Raw: errors.New("internal references is approve"),
}
return pl.SetLogError(&event, input)
}
//if data.IsDone() {
// event.Status = "failed"
// event.ErrInfo = pl.ErrorInfo{
// Code: "data-state-mismatch",
// Detail: "encounter is done",
// Raw: errors.New("encounter is done"),
// }
// return pl.SetLogError(&event, input)
//}
// verify Soapi exist for current responsible doctor
dataSoapi, err := getSoapiByResponsibleDoctor(*data, &event)
if err != nil {
return err
}
if len(dataSoapi) < 1 {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "missing-soapi",
Detail: fmt.Sprintf("Missing soapi from latest responsible doctor"),
}
return pl.SetLogError(&event, input)
}
// update internal reference
if err = uir.UpdateData(eir.UpdateDto{
Id: input.InternalReferences_Id,
CreateDto: eir.CreateDto{
Encounter_Id: &input.Id,
Doctor_Id: irData.Doctor_Id,
Unit_Id: irData.Unit_Id,
Status_Code: erc.DACApproved,
}}, irData, &event, tx); err != nil {
return err
}
// update encounter
if err = updateEncounterApproveSwitchUnit(*irData, &event, tx); err != nil {
return err
}
// update latest responsible doctor hist
if err = updateLatestResponsibleDoctorHist(e.CheckinDto{Id: input.Id, FinishedAt: &now}, &event, tx); err != nil {
return err
}
// create responsible doctor based on internal reference data
if _, err = urdh.CreateData(erdh.CreateDto{
Encounter_Id: &input.Id,
Doctor_Id: irData.Doctor_Id,
StartedAt: &now,
}, &event, tx); err != nil {
return err
}
// update data response
data.Responsible_Doctor_Id = irData.Doctor_Id
data.Unit = irData.Unit
data.Specialist_Id = irData.Doctor.Specialist_Id
data.Subspecialist_Id = irData.Doctor.Subspecialist_Id
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": "updated",
},
Data: data.ToResponse(),
}, nil
}
@@ -10,6 +10,8 @@ import (
"strings"
"time"
authhelper "simrs-vx/internal/lib/auth"
dg "github.com/karincake/apem/db-gorm-pg"
"gorm.io/gorm"
@@ -23,9 +25,13 @@ import (
eaeh "simrs-vx/internal/domain/main-entities/adm-employee-hist"
ea "simrs-vx/internal/domain/main-entities/ambulatory"
ec "simrs-vx/internal/domain/main-entities/chemo"
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"
eem "simrs-vx/internal/domain/main-entities/employee"
e "simrs-vx/internal/domain/main-entities/encounter"
ei "simrs-vx/internal/domain/main-entities/inpatient"
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"
@@ -36,19 +42,26 @@ import (
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"
es "simrs-vx/internal/domain/main-entities/soapi"
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"
ua "simrs-vx/internal/use-case/main-use-case/ambulatory"
uc "simrs-vx/internal/use-case/main-use-case/chemo"
ud "simrs-vx/internal/use-case/main-use-case/doctor"
ue "simrs-vx/internal/use-case/main-use-case/emergency"
uem "simrs-vx/internal/use-case/main-use-case/employee"
ui "simrs-vx/internal/use-case/main-use-case/inpatient"
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"
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"
)
func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Encounter) {
@@ -104,6 +117,19 @@ func setDataDischarge(src e.DischargeDto, dst *e.Encounter) {
dst.FinishedAt = &now
}
func setDataUpdateStatus(src e.UpdateStatusDto, dst *e.Encounter) {
dst.Status_Code = src.StatusCode
}
func setDataCheckIn(src e.CheckinDto, dst *e.Encounter) {
if src.Adm_Employee_Id != nil {
dst.Adm_Employee_Id = src.Adm_Employee_Id
}
dst.Responsible_Doctor_Id = src.Responsible_Doctor_Id
dst.StartedAt = src.StartedAt
}
func checkSoapiByDocExists(encounter_id uint, event *pl.Event, tx *gorm.DB) error {
pl.SetLogInfo(event, nil, "started", "checkSoapiByDocExists")
var soapies []es.Soapi
@@ -335,113 +361,6 @@ func getMcuOrders(encounter_id uint, event *pl.Event, tx *gorm.DB) error {
return nil
}
func setDataUpdateStatus(src e.UpdateStatusDto, dst *e.Encounter) {
dst.Status_Code = src.StatusCode
}
func setDataCheckIn(src e.CheckinDto, dst *e.Encounter) {
if src.Adm_Employee_Id != nil {
dst.Adm_Employee_Id = src.Adm_Employee_Id
}
dst.Responsible_Doctor_Id = src.Responsible_Doctor_Id
dst.StartedAt = src.StartedAt
}
func createInternalReferences(input e.DischargeDto, event *pl.Event, tx *gorm.DB) error {
unitIDs := make(map[uint16]struct{})
doctorIDs := make(map[uint]struct{})
for _, ref := range *input.InternalReferences {
if ref.Unit_Id != nil {
unitIDs[*ref.Unit_Id] = struct{}{}
}
if ref.Doctor_Id != nil {
doctorIDs[*ref.Doctor_Id] = struct{}{}
}
}
// validate unitIds
if len(unitIDs) > 0 {
var ids []uint16
for id := range unitIDs {
ids = append(ids, id)
}
units, err := getUnits(ids, event, tx)
if err != nil {
return fmt.Errorf("failed to fetch units: %w", err)
}
if len(units) != len(ids) {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-validation-fail",
Detail: "unit_id not found",
}
return pl.SetLogError(event, nil)
}
}
// validate doctorIds
if len(doctorIDs) > 0 {
var ids []uint
for id := range doctorIDs {
ids = append(ids, id)
}
doctors, err := getDoctors(ids, event, tx)
if err != nil {
return fmt.Errorf("failed to fetch doctors: %w", err)
}
if len(doctors) != len(ids) {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-validation-fail",
Detail: "doctor_id not found",
}
return pl.SetLogError(event, nil)
}
}
if err := uir.CreateBulkData(*input.InternalReferences, input.Id, event, tx); err != nil {
return err
}
return nil
}
func getUnits(unitIds []uint16, event *pl.Event, tx *gorm.DB) ([]eu.Unit, error) {
pl.SetLogInfo(event, nil, "started", "getUnits")
var units []eu.Unit
err := tx.Where("\"Id\" IN ?", unitIds).Find(&units).Error
if err != nil {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-get-fail",
Detail: "get units",
Raw: err,
}
return nil, pl.SetLogError(event, nil)
}
return units, nil
}
func getDoctors(doctorIds []uint, event *pl.Event, tx *gorm.DB) ([]ed.Doctor, error) {
pl.SetLogInfo(event, nil, "started", "getDoctors")
var doctors []ed.Doctor
err := tx.Where("\"Id\" IN ?", doctorIds).Find(&doctors).Error
if err != nil {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-get-fail",
Detail: "get doctors",
Raw: err,
}
return nil, pl.SetLogError(event, nil)
}
return doctors, nil
}
func upsertResponsibleDoctorHist(input erdh.CreateDto, event *pl.Event, dbx ...*gorm.DB) error {
pl.SetLogInfo(event, nil, "started", "DBCreate")
@@ -566,7 +485,7 @@ func updateLatestResponsibleDoctorHist(input e.CheckinDto, event *pl.Event, dbx
result := tx.
Model(&erdh.ResponsibleDoctorHist{}).
Where("\"Id\" = (?)", subQuery).
Update("\"FinishedAt\"", input.StartedAt)
Update("\"FinishedAt\"", input.FinishedAt)
if result.Error != nil {
event.Status = "failed"
@@ -607,7 +526,7 @@ func updateLatestAdmEmployeeHist(input e.CheckinDto, event *pl.Event, dbx ...*go
result := tx.
Model(&eaeh.AdmEmployeeHist{}).
Where("\"Id\" = (?)", subQuery).
Update("\"FinishedAt\"", input.StartedAt)
Update("\"FinishedAt\"", input.FinishedAt)
if result.Error != nil {
event.Status = "failed"
@@ -628,9 +547,7 @@ func updateLatestAdmEmployeeHist(input e.CheckinDto, event *pl.Event, dbx ...*go
return nil
}
func getSoapiEncounterAdm(enc e.Encounter, event *pl.Event) (dataSoapi []es.CreateDto, err error) {
var data []es.Soapi
func getSoapiByResponsibleDoctor(enc e.Encounter, event *pl.Event) (data []es.Soapi, err error) {
pl.SetLogInfo(event, enc, "started", "DBReadList")
if enc.Responsible_Doctor == nil {
@@ -642,6 +559,7 @@ func getSoapiEncounterAdm(enc e.Encounter, event *pl.Event) (dataSoapi []es.Crea
}
err = dg.I.
Debug().
Model(&es.Soapi{}).
Joins("JOIN \"Employee\" ON \"Employee\".\"Id\" = \"Soapi\".\"Employee_Id\"").
Where("\"Encounter_Id\" = ?", enc.Id).
@@ -653,21 +571,22 @@ func getSoapiEncounterAdm(enc e.Encounter, event *pl.Event) (dataSoapi []es.Crea
if err != nil {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Raw: err,
Raw: err,
Code: "read-fail",
Detail: "Database read failed",
}
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")
return
}
func getSoapiEncounterAdm(enc e.Encounter, event *pl.Event) (dataSoapi []es.CreateDto, err error) {
data, err := getSoapiByResponsibleDoctor(enc, event)
if err != nil {
return nil, err
}
for _, s := range data {
// set data soapi for copy
@@ -690,39 +609,46 @@ func getSoapiEncounterAdm(enc e.Encounter, event *pl.Event) (dataSoapi []es.Crea
return
}
func getSoapiByTypeCode(encounterId uint, dataAmbulatory ea.Ambulatory, event *pl.Event, mode string) (err error) {
pl.SetLogInfo(event, encounterId, "started", "DBReadList")
func getSoapiByTypeCode(encounter *e.Encounter, event *pl.Event, mode string) (err error) {
pl.SetLogInfo(event, encounter, "started", "DBReadList")
var (
dataSoapi []es.Soapi
amb = encounter.Ambulatory
rehab = encounter.Rehab
)
// 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("\"Encounter_Id\" = ?", encounter.Id).
Where("\"Employee\".\"Position_Code\" = ?", erg.EPCDoc)
// Set Case
switch {
case dataAmbulatory.Class_Code == ere.ACCReg:
case amb.Class_Code == ere.ACCReg:
tx = tx.Where("\"Soapi\".\"TypeCode\" = ?", ercl.STCEEarlyMedic)
case dataAmbulatory.Class_Code == ere.ACCRehab && dataAmbulatory.VisitMode_Code == ere.VMCAdm:
case amb.Class_Code == ere.ACCRehab && *rehab.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:
case amb.Class_Code == ere.ACCRehab && *rehab.VisitMode_Code == ere.VMCSeries:
tx = tx.Where("\"Soapi\".\"TypeCode\" = ?", ercl.STCEarlyRehab)
}
if err = tx.Find(&dataSoapi).Error; err != nil {
return setDBError(event, err, encounterId)
return setDBError(event, err, encounter)
}
pl.SetLogInfo(event, nil, "complete")
return validateExistedSoapi(dataSoapi, &dataAmbulatory, event, mode)
return validateExistedSoapi(dataSoapi, encounter, event, mode)
}
func validateExistedSoapi(dataSoapi []es.Soapi, dataAmbulatory *ea.Ambulatory, event *pl.Event, mode string) error {
func validateExistedSoapi(dataSoapi []es.Soapi, dataEncounter *e.Encounter, event *pl.Event, mode string) error {
var (
amb = dataEncounter.Ambulatory
rehab = dataEncounter.Rehab
)
typeExist := make(map[ercl.SoapiTypeCode]bool)
for _, s := range dataSoapi {
typeExist[s.TypeCode] = true
@@ -731,11 +657,11 @@ func validateExistedSoapi(dataSoapi []es.Soapi, dataAmbulatory *ea.Ambulatory, e
required := []ercl.SoapiTypeCode{}
switch {
case dataAmbulatory.Class_Code == ere.ACCReg:
case amb.Class_Code == ere.ACCReg:
required = []ercl.SoapiTypeCode{ercl.STCEEarlyMedic}
case dataAmbulatory.Class_Code == ere.ACCRehab && dataAmbulatory.VisitMode_Code == ere.VMCAdm:
case amb.Class_Code == ere.ACCRehab && *rehab.VisitMode_Code == ere.VMCAdm:
required = []ercl.SoapiTypeCode{ercl.STCEEarlyMedic, ercl.STCFunc, ercl.STCEarlyRehab}
case dataAmbulatory.Class_Code == ere.ACCRehab && dataAmbulatory.VisitMode_Code == ere.VMCSeries:
case amb.Class_Code == ere.ACCRehab && *rehab.VisitMode_Code == ere.VMCSeries:
required = []ercl.SoapiTypeCode{ercl.STCEarlyRehab}
}
@@ -762,6 +688,231 @@ func validateExistedSoapi(dataSoapi []es.Soapi, dataAmbulatory *ea.Ambulatory, e
return nil
}
func identifyPatientStatus(input e.CreateDto) (isNewPatient bool, err error) {
dataPatient, err := ReadList(e.ReadListDto{
FilterDto: e.FilterDto{Patient_Id: input.Patient_Id},
AuthInfo: authhelper.AuthInfo{User_Id: input.User_Id}})
if err != nil {
return
}
if list, ok := dataPatient.Data.([]e.ResponseDto); ok {
if len(list) < 1 {
isNewPatient = true
}
}
return
}
func determineVisitMode(recentRehabData *er.Rehab, input e.CreateDto, event *pl.Event) (ere.VisitModeCode, *e.Encounter, error) {
var (
visitModeCode ere.VisitModeCode
recentAdmEncounterData e.Encounter
isQuotaValid bool
err error
)
switch *recentRehabData.Status_Code {
case erc.DSCProcess:
visitModeCode = ere.VMCSeries
// verify whether the allocated visit count has not exceeded the limit
recentAdmEncounterData, isQuotaValid, err = verifyAllocatedVisitCount(input, event)
if err != nil {
return "", nil, err
}
if !isQuotaValid || recentRehabData.ExpiredAt.Before(*pu.GetTimeNow()) {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "visit-limit-exceeded",
Detail: "Encounter has exceeded the allowed number of visits or expired",
Raw: errors.New("visit count exceeds allowed limit"),
}
return "", nil, pl.SetLogError(event, input)
}
case erc.DSCDone:
visitModeCode = ere.VMCAdm
default:
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "invalid-status",
Detail: fmt.Sprintf("Unknown rehab status: %v", *recentRehabData.Status_Code),
Raw: errors.New("unsupported rehab status"),
}
return "", nil, pl.SetLogError(event, input)
}
return visitModeCode, &recentAdmEncounterData, nil
}
func insertdataClassCode(input e.CreateDto, soapiData []es.CreateDto, event *pl.Event, tx *gorm.DB) (err error) {
switch input.Class_Code {
case ere.ECAmbulatory:
subCode := ere.AmbulatoryClassCode(*input.SubClass_Code)
ambCreate := ea.CreateDto{
Encounter_Id: &input.Id,
Class_Code: subCode,
}
// create data Ambulatory
_, err = ua.CreateData(ambCreate, event, tx)
if err != nil {
return err
}
// insert chemo/rehab
err = insertDataSubClassAmbulatory(input, soapiData, event, tx)
if err != nil {
return err
}
case ere.ECEmergency:
subCode := ere.EmergencyClassCode(*input.SubClass_Code)
emerCreate := ee.CreateDto{
Encounter_Id: &input.Id,
Class_Code: subCode,
}
// create data emergency
_, err = ue.CreateData(emerCreate, event, tx)
if err != nil {
return err
}
case ere.ECInpatient:
subCode := ere.InpatientClassCode(*input.SubClass_Code)
inpCreate := ei.CreateDto{
Encounter_Id: &input.Id,
Class_Code: subCode,
Infra_Id: input.Infra_Id,
}
// create data inpatient
_, err = ui.CreateData(inpCreate, event, tx)
if err != nil {
return err
}
default:
return errors.New("invalid encounter class code")
}
return
}
func insertDataSubClassAmbulatory(input e.CreateDto, soapiData []es.CreateDto, event *pl.Event, tx *gorm.DB) (err error) {
subCode := ere.AmbulatoryClassCode(*input.SubClass_Code)
switch {
case subCode == ere.ACCChemo:
chemoCreate := ec.CreateDto{
Encounter_Id: &input.Id,
Status_Code: erc.DVCNew,
SrcUnit_Id: input.Unit_Id,
}
// create data chemo
_, err = uc.CreateData(chemoCreate, event, tx)
if err != nil {
return err
}
case subCode == ere.ACCRehab:
rehabData := er.CreateDto{
Encounter_Id: &input.Id,
VisitMode_Code: input.VisitMode_Code,
Status_Code: erc.DSCProcess,
}
// if visitMode_code is series, then bulk insert soapi
if input.VisitMode_Code == ere.VMCSeries {
rehabData.Parent_Encounter_Id = &input.RecentEncounterAdm.Id
// Insert Soapi
if err = us.CreateBulkData(soapiData, input.Id, event, tx); err != nil {
return err
}
}
// create rehab
if _, err = ur.CreateData(rehabData, event, tx); err != nil {
return err
}
}
return
}
func verifyRehabLimit(data *e.Encounter, event *pl.Event, tx *gorm.DB) error {
// get data encounter adm
encounterAdmData, _, err := verifyAllocatedVisitCount(e.CreateDto{Patient_Id: data.Patient_Id}, event)
if err != nil {
return err
}
// Check if the visit count has reached the allowed limit
// Mark latest rehab status as 'done' if exceeded.
if len(*encounterAdmData.RehabChildren) >= *encounterAdmData.Rehab.AllocatedVisitCount {
err = updateRehabStatus(er.UpdateDto{
Id: uint16(data.Rehab.Id),
CreateDto: er.CreateDto{Status_Code: erc.DSCDone}}, event, tx)
if err != nil {
return err
}
}
return nil
}
func updateRehabStatus(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("\"Id\" = (?)", input.Id).
Update("\"Status_Code\"", input.Status_Code)
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
}
func validateForeignKey(input e.CheckinDto) error {
// validate employee_Id
if input.Adm_Employee_Id != nil {
if _, err := uem.ReadDetail(eem.ReadDetailDto{Id: uint16(*input.Adm_Employee_Id)}); err != nil {
return err
}
}
// validate doctor_id
if input.Responsible_Doctor_Id != nil {
if _, err := ud.ReadDetail(ed.ReadDetailDto{Id: uint16(*input.Responsible_Doctor_Id)}); err != nil {
return err
}
}
return nil
}
func setSoapiError(event *pl.Event, detail string) error {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
@@ -781,31 +932,82 @@ func setDBError(event *pl.Event, err error, ctx any) error {
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 {
func getUnits(unitIds []uint16, event *pl.Event) ([]eu.Unit, error) {
pl.SetLogInfo(event, nil, "started", "getUnits")
var units []eu.Unit
err := dg.I.Where("\"Id\" IN ?", unitIds).Find(&units).Error
if err != nil {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-update-fail",
Detail: "Database update failed",
Raw: result.Error,
Code: "data-get-fail",
Detail: "get units",
Raw: err,
}
return nil, pl.SetLogError(event, nil)
}
return units, nil
}
func getDoctors(doctorIds []uint, event *pl.Event) ([]ed.Doctor, error) {
pl.SetLogInfo(event, nil, "started", "getDoctors")
var doctors []ed.Doctor
err := dg.I.Where("\"Id\" IN ?", doctorIds).Find(&doctors).Error
if err != nil {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-get-fail",
Detail: "get doctors",
Raw: err,
}
return nil, pl.SetLogError(event, nil)
}
return doctors, nil
}
func validateUnitIds(unitIDs map[uint16]struct{}, event *pl.Event) error {
if len(unitIDs) > 0 {
var ids []uint16
for id := range unitIDs {
ids = append(ids, id)
}
units, err := getUnits(ids, event)
if err != nil {
return fmt.Errorf("failed to fetch units: %w", err)
}
if len(units) != len(ids) {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-validation-fail",
Detail: "unit_id not found",
}
return pl.SetLogError(event, nil)
}
}
return nil
}
func validateDoctorIds(doctorIDs map[uint]struct{}, event *pl.Event) error {
if len(doctorIDs) > 0 {
var ids []uint
for id := range doctorIDs {
ids = append(ids, id)
}
doctors, err := getDoctors(ids, event)
if err != nil {
return fmt.Errorf("failed to fetch doctors: %w", err)
}
if len(doctors) != len(ids) {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-validation-fail",
Detail: "doctor_id not found",
}
return pl.SetLogError(event, nil)
}
return pl.SetLogError(event, input)
}
pl.SetLogInfo(event, nil, "complete")
return nil
}
@@ -3,8 +3,7 @@ package encounter
import (
// std
"errors"
ere "simrs-vx/internal/domain/references/encounter"
eir "simrs-vx/internal/domain/main-entities/internal-reference"
// external
dg "github.com/karincake/apem/db-gorm-pg"
gh "github.com/karincake/getuk"
@@ -15,9 +14,14 @@ import (
pl "simrs-vx/pkg/logger"
pu "simrs-vx/pkg/use-case-helper"
ere "simrs-vx/internal/domain/references/encounter"
e "simrs-vx/internal/domain/main-entities/encounter"
er "simrs-vx/internal/domain/main-entities/rehab"
)
const ErrorReadFailed = "Database read failed"
func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Encounter, error) {
pl.SetLogInfo(event, nil, "started", "DBCreate")
@@ -251,20 +255,49 @@ func updateCheckInData(input e.CheckinDto, data *e.Encounter, event *pl.Event, d
return nil
}
func getLatestRehabData(i e.CreateDto, event *pl.Event) (recentRehabData *er.Rehab, err error) {
pl.SetLogInfo(event, nil, "started", "DBGetLatestRehab")
var (
tx = dg.I
)
err = tx.
Joins("JOIN \"Encounter\" ON \"Encounter\".\"Id\" = \"Rehab\".\"Encounter_Id\"").
Where("\"Encounter\".\"Patient_Id\" = ?", i.Patient_Id).
Order("\"CreatedAt\" DESC").
First(&recentRehabData).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "read-recentRehab-fail",
Detail: ErrorReadFailed,
Raw: err,
}
return nil, pl.SetLogError(event, i)
}
return
}
func verifyAllocatedVisitCount(i e.CreateDto, event *pl.Event) (e.Encounter, bool, error) {
pl.SetLogInfo(event, nil, "started", "DBGetRecentEncounterAdm")
var (
tx = dg.I
recentEncounterAdm e.Encounter
countEncounterSeries int64
tx = dg.I
recentEncounterAdm e.Encounter
valid = true
)
err := tx.
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.ACCRehab, ere.VMCAdm).
Scopes(gh.Preload("RehabChildren,Rehab,Responsible_Doctor")).
Joins("JOIN \"Rehab\" ON \"Rehab\".\"Encounter_Id\" = \"Encounter\".\"Id\"").
Where("\"Encounter\".\"Patient_Id\" = ?", i.Patient_Id).
Where("\"Rehab\".\"VisitMode_Code\" = ?", ere.VMCAdm).
Order("\"CreatedAt\" DESC").
First(&recentEncounterAdm).Error
if err != nil {
@@ -277,22 +310,41 @@ func verifyAllocatedVisitCount(i e.CreateDto, event *pl.Event) (e.Encounter, boo
return e.Encounter{}, false, pl.SetLogError(event, i)
}
err = tx.
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.ACCRehab, ere.VMCSeries).
Where("\"Encounter\".\"CreatedAt\" > ?", recentEncounterAdm.CreatedAt).
Count(&countEncounterSeries).Error
if err != nil {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "read-countEncounter-fail",
Detail: "Database read failed",
Raw: err,
}
return e.Encounter{}, false, pl.SetLogError(event, i)
// validate count rehab children
if recentEncounterAdm.RehabChildren != nil {
valid = len(*recentEncounterAdm.RehabChildren) < *recentEncounterAdm.Rehab.AllocatedVisitCount
}
return recentEncounterAdm, countEncounterSeries < int64(*recentEncounterAdm.Rehab.AllocatedVisitCount), nil
return recentEncounterAdm, valid, nil
}
func updateEncounterApproveSwitchUnit(input eir.InternalReference, event *pl.Event, dbx ...*gorm.DB) (err error) {
pl.SetLogInfo(event, nil, "started", "DBCreate")
var tx *gorm.DB
if len(dbx) > 0 {
tx = dbx[0]
} else {
tx = dg.I
}
if err := tx.Model(&e.Encounter{}).
Where("\"Id\" = ?", input.Encounter_Id).
Updates(map[string]interface{}{
"Responsible_Doctor_Id": input.Doctor_Id,
"Unit_Id": input.Unit_Id,
"Specialist_Id": input.Doctor.Specialist_Id,
"Subspecialist_Id": input.Doctor.Subspecialist_Id,
}).Error; err != nil {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "update-fail",
Detail: "Failed to update encounter approve switch unit",
Raw: err,
}
return pl.SetLogError(event, input)
}
pl.SetLogInfo(event, input, "complete")
return nil
}
@@ -6,6 +6,7 @@ package internal_reference
import (
ir "simrs-vx/internal/domain/main-entities/internal-reference"
erc "simrs-vx/internal/domain/references/common"
)
func setData[T *ir.CreateDto | *ir.UpdateDto](input T, data *ir.InternalReference) {
@@ -20,16 +21,19 @@ func setData[T *ir.CreateDto | *ir.UpdateDto](input T, data *ir.InternalReferenc
data.Encounter_Id = inputSrc.Encounter_Id
data.Unit_Id = inputSrc.Unit_Id
data.Doctor_Id = inputSrc.Doctor_Id
data.Status_Code = &inputSrc.Status_Code
}
func setBulkData(input []ir.CreateDto, encounterId uint) []ir.InternalReference {
var data []ir.InternalReference
for _, v := range input {
statusCode := erc.DACNew
data = append(data, ir.InternalReference{
Encounter_Id: &encounterId,
Unit_Id: v.Unit_Id,
Doctor_Id: v.Doctor_Id,
Status_Code: &statusCode,
})
}
@@ -18,6 +18,9 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Rehab) {
}
data.Encounter_Id = inputSrc.Encounter_Id
data.Doctor_Id = inputSrc.Doctor_Id
data.Parent_Encounter_Id = inputSrc.Parent_Encounter_Id
data.AllocatedVisitCount = inputSrc.AllocatedVisitCount
data.ExpiredAt = inputSrc.ExpiredAt
data.VisitMode_Code = &inputSrc.VisitMode_Code
data.Status_Code = &inputSrc.Status_Code
}