diff --git a/cmd/migration/migrations/20250908062237.sql b/cmd/migration/migrations/20250908062237.sql new file mode 100644 index 00000000..cc509de4 --- /dev/null +++ b/cmd/migration/migrations/20250908062237.sql @@ -0,0 +1,96 @@ +-- Create "Appointment" table +CREATE TABLE "public"."Appointment" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "PracticeSchedule_Id" bigint NULL, + "Patient_Id" bigint NULL, + "Person_ResidentIdentityNumber" character varying(16) NULL, + "Person_Name" character varying(100) NULL, + "Person_PhoneNumber" character varying(30) NULL, + "PaymentMethod_Code" character varying(10) NULL, + "RefNumber" character varying(20) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Appointment_Patient" FOREIGN KEY ("Patient_Id") REFERENCES "public"."Patient" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_Appointment_PracticeSchedule" FOREIGN KEY ("PracticeSchedule_Id") REFERENCES "public"."PracticeSchedule" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Modify "Encounter" table +ALTER TABLE "public"."Encounter" ADD COLUMN "Appointment_Doctor_Id" bigint NULL, ADD COLUMN "Appointment_Id" bigint NULL, ADD COLUMN "EarlyEducation" text NULL, ADD COLUMN "MedicalDischargeEducation" text NULL, ADD COLUMN "AdmDischargeEducation" text NULL, ADD COLUMN "DischargeReason" text NULL, ADD CONSTRAINT "fk_Encounter_Appointment" FOREIGN KEY ("Appointment_Id") REFERENCES "public"."Appointment" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, ADD CONSTRAINT "fk_Encounter_Appointment_Doctor" FOREIGN KEY ("Appointment_Doctor_Id") REFERENCES "public"."Doctor" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION; +-- Create "Adime" table +CREATE TABLE "public"."Adime" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Encounter_Id" bigint NULL, + "Employee_Id" bigint NULL, + "Time" timestamptz NULL, + "Value" text NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Adime_Employee" FOREIGN KEY ("Employee_Id") REFERENCES "public"."Employee" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_Adime_Encounter" FOREIGN KEY ("Encounter_Id") REFERENCES "public"."Encounter" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "Ambulatory" table +CREATE TABLE "public"."Ambulatory" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Encounter_Id" bigint NULL, + "Class_Code" character varying(10) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Ambulatory_Encounter" FOREIGN KEY ("Encounter_Id") REFERENCES "public"."Encounter" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "Emergency" table +CREATE TABLE "public"."Emergency" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Encounter_Id" bigint NULL, + "Class_Code" character varying(10) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Emergency_Encounter" FOREIGN KEY ("Encounter_Id") REFERENCES "public"."Encounter" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "Inpatient" table +CREATE TABLE "public"."Inpatient" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Encounter_Id" bigint NULL, + "Class_Code" character varying(10) NULL, + "Infra_Id" integer NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Inpatient_Encounter" FOREIGN KEY ("Encounter_Id") REFERENCES "public"."Encounter" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_Inpatient_Infra" FOREIGN KEY ("Infra_Id") REFERENCES "public"."Infra" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "Sbar" table +CREATE TABLE "public"."Sbar" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Encounter_Id" bigint NULL, + "Employee_Id" bigint NULL, + "Time" timestamptz NULL, + "Value" text NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Sbar_Employee" FOREIGN KEY ("Employee_Id") REFERENCES "public"."Employee" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_Sbar_Encounter" FOREIGN KEY ("Encounter_Id") REFERENCES "public"."Encounter" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "Soapi" table +CREATE TABLE "public"."Soapi" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Encounter_Id" bigint NULL, + "Employee_Id" bigint NULL, + "Time" timestamptz NULL, + "Value" text NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Soapi_Employee" FOREIGN KEY ("Employee_Id") REFERENCES "public"."Employee" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_Soapi_Encounter" FOREIGN KEY ("Encounter_Id") REFERENCES "public"."Encounter" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); diff --git a/cmd/migration/migrations/20250908062323.sql b/cmd/migration/migrations/20250908062323.sql new file mode 100644 index 00000000..cc63543f --- /dev/null +++ b/cmd/migration/migrations/20250908062323.sql @@ -0,0 +1,2 @@ +-- Modify "Encounter" table +ALTER TABLE "public"."Encounter" DROP COLUMN "Assignment_Doctor_Id"; diff --git a/cmd/migration/migrations/20250908073811.sql b/cmd/migration/migrations/20250908073811.sql new file mode 100644 index 00000000..ead1e965 --- /dev/null +++ b/cmd/migration/migrations/20250908073811.sql @@ -0,0 +1,2 @@ +-- Modify "Encounter" table +ALTER TABLE "public"."Encounter" ADD COLUMN "DischargeMethod_Code" character varying(10) NULL; diff --git a/cmd/migration/migrations/20250908073839.sql b/cmd/migration/migrations/20250908073839.sql new file mode 100644 index 00000000..43710589 --- /dev/null +++ b/cmd/migration/migrations/20250908073839.sql @@ -0,0 +1,2 @@ +-- Modify "Encounter" table +ALTER TABLE "public"."Encounter" DROP COLUMN "DischardeMethod_Code"; diff --git a/cmd/migration/migrations/20250910055902.sql b/cmd/migration/migrations/20250910055902.sql new file mode 100644 index 00000000..19583065 --- /dev/null +++ b/cmd/migration/migrations/20250910055902.sql @@ -0,0 +1,2 @@ +-- Modify "Encounter" table +ALTER TABLE "public"."Encounter" ADD COLUMN "Status_Code" character varying(10) NULL; diff --git a/cmd/migration/migrations/atlas.sum b/cmd/migration/migrations/atlas.sum index 10859e9b..28fa58f4 100644 --- a/cmd/migration/migrations/atlas.sum +++ b/cmd/migration/migrations/atlas.sum @@ -1,3 +1,8 @@ -h1:G2T3Gv3jMXqZDaBw/lSU8IhowMI3z//r+ZtHxndsLc4= -20250904105930.sql h1:Vv4vCurl7m7/ZB6TjRpkubHpQ4RYwSUn0QHdzfoGpzY= -20250904141448.sql h1:FYCHH9Os4KkrZMDu/jR8FMP+wLMRW+Mb0PkLU/9BRDg= +h1:dw8c/C5xz/Do+p93EVuqfaZWYja1GO1VsbM7vuCJYGo= +20250904105930.sql h1:MEM6blCgke9DzWQSTnLzasbPIrcHssNNrJqZpSkEo6k= +20250904141448.sql h1:J8cmYNk4ZrG9fhfbi2Z1IWz7YkfvhFqTzrLFo58BPY0= +20250908062237.sql h1:Pu23yEW/aKkwozHoOuROvHS/GK4ngARJGdO7FB7HZuI= +20250908062323.sql h1:oXl6Z143tOpIl4EfP4B8JNU8LrMvVmHEtCgAfiB4gs8= +20250908073811.sql h1:m2aNXfnGxnLq1+rVWrh4f60q7fhyhV3gEwNu/OIqQlE= +20250908073839.sql h1:cPk54xjLdMs26uY8ZHjNWLuyfAMzV7Zb0/9oJQrsw04= +20250910055902.sql h1:fnLqf63sb0R02rzoj1Gnncp32NW/bUcBAMLyV4qF968= diff --git a/go.mod b/go.mod index da8ef314..c7e8a5fc 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/karincake/lepet v0.0.1 github.com/karincake/risoles v0.0.3 github.com/karincake/semprit v0.0.3 + github.com/karincake/serabi v0.0.14 github.com/rs/zerolog v1.33.0 golang.org/x/crypto v0.41.0 gorm.io/driver/postgres v1.5.11 @@ -34,7 +35,6 @@ require ( github.com/jackc/puddle/v2 v2.2.1 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect - github.com/karincake/serabi v0.0.14 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-sqlite3 v1.14.28 // indirect diff --git a/internal/domain/main-entities/adime/dto.go b/internal/domain/main-entities/adime/dto.go new file mode 100644 index 00000000..39c48ab7 --- /dev/null +++ b/internal/domain/main-entities/adime/dto.go @@ -0,0 +1,86 @@ +package adime + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + eem "simrs-vx/internal/domain/main-entities/employee" + ee "simrs-vx/internal/domain/main-entities/encounter" + + pa "simrs-vx/pkg/auth-helper" + "time" +) + +type CreateDto struct { + Encounter_Id *uint `json:"encounter_id"` + Employee_Id *uint `json:"-"` + Time *time.Time `json:"time"` + Value *string `json:"value"` + + pa.AuthInfo +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Preloads []string `json:"-"` +} + +type FilterDto struct { + Encounter_Id *uint `json:"encounter_id"` + Employee_Id *uint `json:"employee_id"` + Time *time.Time `json:"time"` + Value *string `json:"value"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` +} + +type UpdateDto struct { + Id uint16 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint16 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Encounter_Id *uint `json:"encounter_id"` + Encounter *ee.Encounter `json:"encounter,omitempty"` + Employee_Id *uint `json:"employee_id"` + Employee *eem.Employee `json:"employee,omitempty"` + Time *time.Time `json:"time"` + Value *string `json:"value"` +} + +func (d Adime) ToResponse() ResponseDto { + resp := ResponseDto{ + Encounter_Id: d.Encounter_Id, + Encounter: d.Encounter, + Employee_Id: d.Employee_Id, + Employee: d.Employee, + Time: d.Time, + Value: d.Value, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []Adime) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/adime/entity.go b/internal/domain/main-entities/adime/entity.go new file mode 100644 index 00000000..35fa7276 --- /dev/null +++ b/internal/domain/main-entities/adime/entity.go @@ -0,0 +1,18 @@ +package adime + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + eem "simrs-vx/internal/domain/main-entities/employee" + ee "simrs-vx/internal/domain/main-entities/encounter" + "time" +) + +type Adime struct { + ecore.Main // adjust this according to the needs + Encounter_Id *uint `json:"encounter_id"` + Encounter *ee.Encounter `json:"encounter,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"` + Employee_Id *uint `json:"employee_id"` + Employee *eem.Employee `json:"employee,omitempty" gorm:"foreignKey:Employee_Id;references:Id"` + Time *time.Time `json:"time"` + Value *string `json:"value"` +} diff --git a/internal/domain/main-entities/ambulatory/dto.go b/internal/domain/main-entities/ambulatory/dto.go new file mode 100644 index 00000000..68147819 --- /dev/null +++ b/internal/domain/main-entities/ambulatory/dto.go @@ -0,0 +1,67 @@ +package ambulatory + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ee "simrs-vx/internal/domain/main-entities/encounter" + ere "simrs-vx/internal/domain/references/encounter" +) + +type CreateDto struct { + Encounter_Id *uint `json:"encounter_id"` + Class_Code ere.AmbulatoryClassCode `json:"class_code" validate:"maxLength=10"` +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Preloads []string `json:"-"` +} + +type FilterDto struct { + Encounter_Id *uint `json:"encounter_id"` + Class_Code ere.AmbulatoryClassCode `json:"class_code"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` +} + +type UpdateDto struct { + Id uint16 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint16 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Encounter_Id *uint `json:"encounter_id"` + Encounter *ee.Encounter `json:"encounter,omitempty"` + Class_Code ere.AmbulatoryClassCode `json:"class_code"` +} + +func (d Ambulatory) ToResponse() ResponseDto { + resp := ResponseDto{} + resp.Main = d.Main + return resp +} + +func ToResponseList(data []Ambulatory) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/ambulatory/entity.go b/internal/domain/main-entities/ambulatory/entity.go new file mode 100644 index 00000000..58a9810e --- /dev/null +++ b/internal/domain/main-entities/ambulatory/entity.go @@ -0,0 +1,15 @@ +package ambulatory + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ee "simrs-vx/internal/domain/main-entities/encounter" + + ere "simrs-vx/internal/domain/references/encounter" +) + +type Ambulatory struct { + ecore.Main // adjust this according to the needs + Encounter_Id *uint `json:"encounter_id"` + Encounter *ee.Encounter `json:"encounter,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"` + Class_Code ere.AmbulatoryClassCode `json:"class_code" gorm:"size:10"` +} diff --git a/internal/domain/main-entities/appointment/dto.go b/internal/domain/main-entities/appointment/dto.go new file mode 100644 index 00000000..ff91ae92 --- /dev/null +++ b/internal/domain/main-entities/appointment/dto.go @@ -0,0 +1,88 @@ +package appointment + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ep "simrs-vx/internal/domain/main-entities/patient" + eps "simrs-vx/internal/domain/main-entities/practice-schedule" + erc "simrs-vx/internal/domain/references/common" +) + +type CreateDto struct { + PracticeSchedule_Id *uint `json:"practiceSchedule_id"` + Patient_Id *uint `json:"patient_id"` + Person_ResidentIdentityNumber string `json:"person_residentIdentityNumber"` + Person_Name string `json:"person_name"` + Person_PhoneNumber string `json:"person_phoneNumber"` + PaymentMethod_Code erc.PaymentMethodCode `json:"paymentMethod_code"` + RefNumber string `json:"refNumber"` +} + +type ReadListDto struct { + PracticeSchedule_Id *uint `json:"practiceSchedule_id"` + Patient_Id *uint `json:"patient_id"` + Person_ResidentIdentityNumber string `json:"person_residentIdentityNumber"` + Person_Name string `json:"person_name"` + Person_PhoneNumber string `json:"person_phoneNumber"` + PaymentMethod_Code erc.PaymentMethodCode `json:"paymentMethod_code"` + RefNumber string `json:"refNumber"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` +} + +type UpdateDto struct { + Id uint16 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint16 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + PracticeSchedule_Id *uint `json:"practiceSchedule_id"` + PracticeSchedule *eps.PracticeSchedule `json:"practiceSchedule,omitempty"` + Patient_Id *uint `json:"patient_id"` + Patient *ep.Patient `json:"patient,omitempty"` + Person_ResidentIdentityNumber string `json:"person_residentIdentityNumber"` + Person_Name string `json:"person_name"` + Person_PhoneNumber string `json:"person_phoneNumber"` + PaymentMethod_Code erc.PaymentMethodCode `json:"paymentMethod_code"` + RefNumber string `json:"refNumber"` +} + +func (d Appointment) ToResponse() ResponseDto { + resp := ResponseDto{ + PracticeSchedule_Id: d.PracticeSchedule_Id, + PracticeSchedule: d.PracticeSchedule, + Patient_Id: d.Patient_Id, + Patient: d.Patient, + Person_ResidentIdentityNumber: d.Person_ResidentIdentityNumber, + Person_Name: d.Person_Name, + Person_PhoneNumber: d.Person_PhoneNumber, + PaymentMethod_Code: d.PaymentMethod_Code, + RefNumber: d.RefNumber, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []Appointment) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/appointment/entity.go b/internal/domain/main-entities/appointment/entity.go new file mode 100644 index 00000000..fada15ac --- /dev/null +++ b/internal/domain/main-entities/appointment/entity.go @@ -0,0 +1,21 @@ +package appointment + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ep "simrs-vx/internal/domain/main-entities/patient" + eps "simrs-vx/internal/domain/main-entities/practice-schedule" + erc "simrs-vx/internal/domain/references/common" +) + +type Appointment struct { + ecore.Main // adjust this according to the needs + PracticeSchedule_Id *uint `json:"practiceSchedule_id"` + PracticeSchedule *eps.PracticeSchedule `json:"practiceSchedule,omitempty" gorm:"foreignKey:PracticeSchedule_Id;references:Id"` + Patient_Id *uint `json:"patient_id"` + Patient *ep.Patient `json:"patient,omitempty" gorm:"foreignKey:Patient_Id;references:Id"` + Person_ResidentIdentityNumber string `json:"person_residentIdentityNumber" gorm:"size:16"` + Person_Name string `json:"person_name" gorm:"size:100"` + Person_PhoneNumber string `json:"person_phoneNumber" gorm:"size:30"` + PaymentMethod_Code erc.PaymentMethodCode `json:"paymentMethod_code" gorm:"size:10"` + RefNumber string `json:"refNumber" gorm:"size:20"` +} diff --git a/internal/domain/main-entities/emergency/dto.go b/internal/domain/main-entities/emergency/dto.go new file mode 100644 index 00000000..b98096f2 --- /dev/null +++ b/internal/domain/main-entities/emergency/dto.go @@ -0,0 +1,67 @@ +package emergency + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ee "simrs-vx/internal/domain/main-entities/encounter" + ere "simrs-vx/internal/domain/references/encounter" +) + +type CreateDto struct { + Encounter_Id *uint `json:"encounter_id"` + Class_Code ere.EmergencyClassCode `json:"class_code" validate:"maxLength=10"` +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Preloads []string `json:"-"` +} + +type FilterDto struct { + Encounter_Id *uint `json:"encounter_id"` + Class_Code ere.EmergencyClassCode `json:"class_code"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` +} + +type UpdateDto struct { + Id uint16 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint16 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Encounter_Id *uint `json:"encounter_id"` + Encounter *ee.Encounter `json:"encounter,omitempty"` + Class_Code ere.EmergencyClassCode `json:"class_code"` +} + +func (d Emergency) ToResponse() ResponseDto { + resp := ResponseDto{} + resp.Main = d.Main + return resp +} + +func ToResponseList(data []Emergency) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/emergency/entity.go b/internal/domain/main-entities/emergency/entity.go new file mode 100644 index 00000000..1e6fb078 --- /dev/null +++ b/internal/domain/main-entities/emergency/entity.go @@ -0,0 +1,15 @@ +package emergency + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ee "simrs-vx/internal/domain/main-entities/encounter" + + ere "simrs-vx/internal/domain/references/encounter" +) + +type Emergency struct { + ecore.Main // adjust this according to the needs + Encounter_Id *uint `json:"encounter_id"` + Encounter *ee.Encounter `json:"encounter,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"` + Class_Code ere.EmergencyClassCode `json:"class_code" gorm:"size:10"` +} diff --git a/internal/domain/main-entities/encounter/dto.go b/internal/domain/main-entities/encounter/dto.go index 49a3b987..a431ad4e 100644 --- a/internal/domain/main-entities/encounter/dto.go +++ b/internal/domain/main-entities/encounter/dto.go @@ -2,28 +2,31 @@ package encounter import ( ecore "simrs-vx/internal/domain/base-entities/core" + ea "simrs-vx/internal/domain/main-entities/appointment" ed "simrs-vx/internal/domain/main-entities/doctor" ep "simrs-vx/internal/domain/main-entities/patient" es "simrs-vx/internal/domain/main-entities/specialist" ess "simrs-vx/internal/domain/main-entities/subspecialist" eu "simrs-vx/internal/domain/main-entities/unit" + erc "simrs-vx/internal/domain/references/common" ere "simrs-vx/internal/domain/references/encounter" "time" ) type CreateDto struct { - Patient_Id *uint `json:"patient_id"` - Patient *ep.Patient `json:"patient,omitempty"` - RegisteredAt *time.Time `json:"registeredAt"` - Class_Code ere.EncounterClassCode `json:"class_code" validate:"maxLength=10"` - Unit_Id *uint `json:"unit_id"` - Specialist_Id *uint16 `json:"specialist_id"` - Subspecialist_Id *uint16 `json:"subspecialist_id"` - VisitDate time.Time `json:"visitDate"` - Assignment_Doctor_Id *uint `json:"assignment_doctor_id"` - Responsible_Doctor_Id *uint `json:"responsible_doctor_id"` - DischardeMethod_Code ere.DischargeMethodCode `json:"dischardeMethod_code" validate:"maxLength=10"` - RefSource_Name *string `json:"refSource_name" validate:"maxLength=100"` + Patient_Id *uint `json:"patient_id"` + RegisteredAt *time.Time `json:"registeredAt"` + Class_Code ere.EncounterClassCode `json:"class_code" validate:"maxLength=10"` + SubClass_Code *string `json:"subClass_code" validate:"maxLength=10"` // for sub + Infra_Id *uint16 `json:"infra_id"` // for inpatient + Unit_Id *uint `json:"unit_id"` + Specialist_Id *uint16 `json:"specialist_id"` + Subspecialist_Id *uint16 `json:"subspecialist_id"` + VisitDate time.Time `json:"visitDate"` + Appointment_Doctor_Id *uint `json:"appointment_doctor_id"` + Responsible_Doctor_Id *uint `json:"responsible_doctor_id"` + RefSource_Name *string `json:"refSource_name" validate:"maxLength=100"` + Appointment_Id *uint `json:"appointment_id"` } type ReadListDto struct { @@ -33,18 +36,23 @@ type ReadListDto struct { } type FilterDto struct { - Patient_Id *uint `json:"patient_id"` - Patient *ep.Patient `json:"patient,omitempty"` - RegisteredAt *time.Time `json:"registeredAt"` - Class_Code ere.EncounterClassCode `json:"class_code" validate:"maxLength=10"` - Unit_Id *uint `json:"unit_id"` - Specialist_Id *uint16 `json:"specialist_id"` - Subspecialist_Id *uint16 `json:"subspecialist_id"` - VisitDate time.Time `json:"visitDate"` - Assignment_Doctor_Id *uint `json:"assignment_doctor_id"` - Responsible_Doctor_Id *uint `json:"responsible_doctor_id"` - DischardeMethod_Code ere.DischargeMethodCode `json:"dischardeMethod_code" validate:"maxLength=10"` - RefSource_Name *string `json:"refSource_name" validate:"maxLength=100"` + Patient_Id *uint `json:"patient_id"` + Patient *ep.Patient `json:"patient,omitempty"` + RegisteredAt *time.Time `json:"registeredAt"` + Class_Code ere.EncounterClassCode `json:"class_code" validate:"maxLength=10"` + Unit_Id *uint `json:"unit_id"` + Specialist_Id *uint16 `json:"specialist_id"` + Subspecialist_Id *uint16 `json:"subspecialist_id"` + VisitDate time.Time `json:"visitDate"` + Appoinment_Doctor_Id *uint `json:"appointment_doctor_id"` + Responsible_Doctor_Id *uint `json:"responsible_doctor_id"` + DischargeMethod_Code ere.DischargeMethodCode `json:"dischargeMethod_code" validate:"maxLength=10"` + RefSource_Name *string `json:"refSource_name" validate:"maxLength=100"` + Appointment_Id *uint `json:"appointment_id"` + EarlyEducation *string `json:"earlyEducation"` + MedicalDischargeEducation *string `json:"medicalDischargeEducation"` + AdmDischargeEducation *string `json:"admDischargeEducation"` + DischargeReason *string `json:"dischargeReason"` Page int `json:"page"` PageSize int `json:"page_size"` @@ -52,10 +60,7 @@ type FilterDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` - Code string `json:"code"` - Name string `json:"name"` - Parent_Id *int16 `json:"parent_id"` + Id uint16 `json:"id"` } type UpdateDto struct { @@ -72,47 +77,69 @@ type MetaDto struct { PageSize int `json:"page_size"` Count int `json:"count"` } +type DischargeDto struct { + Id uint `json:"id"` + DischargeMethod_Code *ere.DischargeMethodCode `json:"dischargeMethod_code" validate:"maxLength=10"` + EarlyEducation *string `json:"earlyEducation"` + MedicalDischargeEducation *string `json:"medicalDischargeEducation"` + AdmDischargeEducation *string `json:"admDischargeEducation"` + DischargeReason *string `json:"dischargeReason"` +} type ResponseDto struct { ecore.Main - Patient_Id *uint `json:"patient_id"` - Patient *ep.Patient `json:"patient,omitempty"` - RegisteredAt *time.Time `json:"registeredAt"` - Class_Code ere.EncounterClassCode `json:"class_code"` - Unit_Id *uint `json:"unit_id"` - Specialist_Id *uint16 `json:"specialist_id"` - Specialist *es.Specialist `json:"specialist,omitempty"` - Subspecialist_Id *uint16 `json:"subspecialist_id"` - Subspecialist *ess.Subspecialist `json:"subspecialist,omitempty"` - Unit *eu.Unit `json:"unit,omitempty"` - VisitDate time.Time `json:"visitDate"` - Assignment_Doctor_Id *uint `json:"assignment_doctor_id"` - Assignment_Doctor *ed.Doctor `json:"assignment_doctor,omitempty"` - Responsible_Doctor_Id *uint `json:"responsible_doctor_id"` - Responsible_Doctor *ed.Doctor `json:"responsible_doctor,omitempty"` - DischardeMethod_Code ere.DischargeMethodCode `json:"dischardeMethod_code` - RefSource_Name *string `json:"refSource_name"` + Patient_Id *uint `json:"patient_id"` + Patient *ep.Patient `json:"patient,omitempty"` + RegisteredAt *time.Time `json:"registeredAt"` + Class_Code ere.EncounterClassCode `json:"class_code"` + Unit_Id *uint `json:"unit_id"` + Specialist_Id *uint16 `json:"specialist_id"` + Specialist *es.Specialist `json:"specialist,omitempty"` + Subspecialist_Id *uint16 `json:"subspecialist_id"` + Subspecialist *ess.Subspecialist `json:"subspecialist,omitempty"` + Unit *eu.Unit `json:"unit,omitempty"` + VisitDate time.Time `json:"visitDate"` + Appointment_Doctor_Id *uint `json:"assignment_doctor_id"` + Appointment_Doctor *ed.Doctor `json:"assignment_doctor,omitempty"` + Responsible_Doctor_Id *uint `json:"responsible_doctor_id"` + Responsible_Doctor *ed.Doctor `json:"responsible_doctor,omitempty"` + DischargeMethod_Code *ere.DischargeMethodCode `json:"dischargeMethod_code"` + RefSource_Name *string `json:"refSource_name"` + Appointment_Id *uint `json:"appointment_id"` + Appointment *ea.Appointment `json:"appointment,omitempty"` + EarlyEducation *string `json:"earlyEducation"` + MedicalDischargeEducation *string `json:"medicalDischargeEducation"` + AdmDischargeEducation *string `json:"admDischargeEducation"` + DischargeReason *string `json:"dischargeReason"` + Status_Code erc.DataStatusCode `json:"status_code"` } func (d Encounter) ToResponse() ResponseDto { resp := ResponseDto{ - Patient_Id: d.Patient_Id, - Patient: d.Patient, - RegisteredAt: d.RegisteredAt, - Class_Code: d.Class_Code, - Unit_Id: d.Unit_Id, - Unit: d.Unit, - Specialist_Id: d.Specialist_Id, - Specialist: d.Specialist, - Subspecialist_Id: d.Subspecialist_Id, - Subspecialist: d.Subspecialist, - VisitDate: d.VisitDate, - Assignment_Doctor_Id: d.Assignment_Doctor_Id, - Assignment_Doctor: d.Assignment_Doctor, - Responsible_Doctor_Id: d.Responsible_Doctor_Id, - Responsible_Doctor: d.Responsible_Doctor, - DischardeMethod_Code: d.DischardeMethod_Code, - RefSource_Name: d.RefSource_Name, + Patient_Id: d.Patient_Id, + Patient: d.Patient, + RegisteredAt: d.RegisteredAt, + Class_Code: d.Class_Code, + Unit_Id: d.Unit_Id, + Unit: d.Unit, + Specialist_Id: d.Specialist_Id, + Specialist: d.Specialist, + Subspecialist_Id: d.Subspecialist_Id, + Subspecialist: d.Subspecialist, + VisitDate: d.VisitDate, + Appointment_Doctor_Id: d.Appointment_Doctor_Id, + Appointment_Doctor: d.Appointment_Doctor, + Responsible_Doctor_Id: d.Responsible_Doctor_Id, + Responsible_Doctor: d.Responsible_Doctor, + DischargeMethod_Code: d.DischargeMethod_Code, + RefSource_Name: d.RefSource_Name, + Appointment_Id: d.Appointment_Id, + Appointment: d.Appointment, + EarlyEducation: d.EarlyEducation, + MedicalDischargeEducation: d.MedicalDischargeEducation, + AdmDischargeEducation: d.AdmDischargeEducation, + DischargeReason: d.DischargeReason, + Status_Code: d.Status_Code, } resp.Main = d.Main return resp diff --git a/internal/domain/main-entities/encounter/entity.go b/internal/domain/main-entities/encounter/entity.go index 95d2cac7..0a685611 100644 --- a/internal/domain/main-entities/encounter/entity.go +++ b/internal/domain/main-entities/encounter/entity.go @@ -2,32 +2,45 @@ package encounter import ( ecore "simrs-vx/internal/domain/base-entities/core" + ea "simrs-vx/internal/domain/main-entities/appointment" ed "simrs-vx/internal/domain/main-entities/doctor" ep "simrs-vx/internal/domain/main-entities/patient" es "simrs-vx/internal/domain/main-entities/specialist" ess "simrs-vx/internal/domain/main-entities/subspecialist" eu "simrs-vx/internal/domain/main-entities/unit" + erc "simrs-vx/internal/domain/references/common" ere "simrs-vx/internal/domain/references/encounter" "time" ) type Encounter struct { - ecore.Main // adjust this according to the needs - Patient_Id *uint `json:"patient_id"` - Patient *ep.Patient `json:"patient,omitempty" gorm:"foreignKey:Patient_Id;references:Id"` - RegisteredAt *time.Time `json:"registeredAt"` - Class_Code ere.EncounterClassCode `json:"class_code" gorm:"not null;size:10"` - Unit_Id *uint `json:"unit_id"` - Unit *eu.Unit `json:"unit,omitempty" gorm:"foreignKey:Unit_Id;references:Id"` - Specialist_Id *uint16 `json:"specialist_id"` - Specialist *es.Specialist `json:"specialist,omitempty" gorm:"foreignKey:Specialist_Id;references:Id"` - Subspecialist_Id *uint16 `json:"subspecialist_id"` - Subspecialist *ess.Subspecialist `json:"subspecialist,omitempty" gorm:"foreignKey:Subspecialist_Id;references:Id"` - VisitDate time.Time `json:"visitDate"` - Assignment_Doctor_Id *uint `json:"assignment_doctor_id"` - Assignment_Doctor *ed.Doctor `json:"assignment_doctor,omitempty" gorm:"foreignKey:Assignment_Doctor_Id;references:Id"` - Responsible_Doctor_Id *uint `json:"responsible_doctor_id"` - Responsible_Doctor *ed.Doctor `json:"responsible_doctor,omitempty" gorm:"foreignKey:Responsible_Doctor_Id;references:Id"` - DischardeMethod_Code ere.DischargeMethodCode `json:"dischardeMethod_code" gorm:"size:10"` - RefSource_Name *string `json:"refSource_name" gorm:"size:100"` + ecore.Main // adjust this according to the needs + Patient_Id *uint `json:"patient_id"` + Patient *ep.Patient `json:"patient,omitempty" gorm:"foreignKey:Patient_Id;references:Id"` + RegisteredAt *time.Time `json:"registeredAt"` + Class_Code ere.EncounterClassCode `json:"class_code" gorm:"not null;size:10"` + Unit_Id *uint `json:"unit_id"` + Unit *eu.Unit `json:"unit,omitempty" gorm:"foreignKey:Unit_Id;references:Id"` + Specialist_Id *uint16 `json:"specialist_id"` + Specialist *es.Specialist `json:"specialist,omitempty" gorm:"foreignKey:Specialist_Id;references:Id"` + Subspecialist_Id *uint16 `json:"subspecialist_id"` + Subspecialist *ess.Subspecialist `json:"subspecialist,omitempty" gorm:"foreignKey:Subspecialist_Id;references:Id"` + VisitDate time.Time `json:"visitDate"` + Appointment_Doctor_Id *uint `json:"appointment_doctor_id"` + Appointment_Doctor *ed.Doctor `json:"appointment_doctor,omitempty" gorm:"foreignKey:Appointment_Doctor_Id;references:Id"` + Responsible_Doctor_Id *uint `json:"responsible_doctor_id"` + Responsible_Doctor *ed.Doctor `json:"responsible_doctor,omitempty" gorm:"foreignKey:Responsible_Doctor_Id;references:Id"` + DischargeMethod_Code *ere.DischargeMethodCode `json:"dischargeMethod_code" gorm:"size:10"` + RefSource_Name *string `json:"refSource_name" gorm:"size:100"` + Appointment_Id *uint `json:"appointment_id"` + Appointment *ea.Appointment `json:"appointment,omitempty" gorm:"foreignKey:Appointment_Id;references:Id"` + EarlyEducation *string `json:"earlyEducation"` + MedicalDischargeEducation *string `json:"medicalDischargeEducation"` + AdmDischargeEducation *string `json:"admDischargeEducation"` + DischargeReason *string `json:"dischargeReason"` + Status_Code erc.DataStatusCode `json:"status_code" gorm:"size:10"` +} + +func (d Encounter) IsDone() bool { + return d.Status_Code == erc.DSCDone } diff --git a/internal/domain/main-entities/inpatient/dto.go b/internal/domain/main-entities/inpatient/dto.go new file mode 100644 index 00000000..acf1442a --- /dev/null +++ b/internal/domain/main-entities/inpatient/dto.go @@ -0,0 +1,78 @@ +package inpatient + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ee "simrs-vx/internal/domain/main-entities/encounter" + ei "simrs-vx/internal/domain/main-entities/infra" + ere "simrs-vx/internal/domain/references/encounter" +) + +type CreateDto struct { + Encounter_Id *uint `json:"encounter_id"` + Class_Code ere.InpatientClassCode `json:"class_code" validate:"maxLength=10"` + Infra_Id *uint16 `json:"infra_id"` +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Preloads []string `json:"-"` +} + +type FilterDto struct { + Encounter_Id *uint `json:"encounter_id"` + Class_Code ere.InpatientClassCode `json:"class_code"` + Infra_Id *uint16 `json:"infra_id"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` +} + +type UpdateDto struct { + Id uint16 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint16 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Encounter_Id *uint `json:"encounter_id"` + Encounter *ee.Encounter `json:"encounter,omitempty"` + Class_Code ere.InpatientClassCode `json:"class_code"` + Infra_Id *uint16 `json:"infra_id"` + Infra *ei.Infra `json:"infra,omitempty"` +} + +func (d Inpatient) ToResponse() ResponseDto { + resp := ResponseDto{ + Encounter_Id: d.Encounter_Id, + Encounter: d.Encounter, + Class_Code: d.Class_Code, + Infra_Id: d.Infra_Id, + Infra: d.Infra, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []Inpatient) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/inpatient/entity.go b/internal/domain/main-entities/inpatient/entity.go new file mode 100644 index 00000000..328f5d12 --- /dev/null +++ b/internal/domain/main-entities/inpatient/entity.go @@ -0,0 +1,18 @@ +package inpatient + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ee "simrs-vx/internal/domain/main-entities/encounter" + ei "simrs-vx/internal/domain/main-entities/infra" + + ere "simrs-vx/internal/domain/references/encounter" +) + +type Inpatient struct { + ecore.Main // adjust this according to the needs + Encounter_Id *uint `json:"encounter_id"` + Encounter *ee.Encounter `json:"encounter,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"` + Class_Code ere.InpatientClassCode `json:"class_code" gorm:"size:10"` + Infra_Id *uint16 `json:"infra_id"` + Infra *ei.Infra `json:"infra,omitempty" gorm:"foreignKey:Infra_Id;references:Id"` +} diff --git a/internal/domain/main-entities/sbar/dto.go b/internal/domain/main-entities/sbar/dto.go new file mode 100644 index 00000000..edba338c --- /dev/null +++ b/internal/domain/main-entities/sbar/dto.go @@ -0,0 +1,86 @@ +package sbar + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + eem "simrs-vx/internal/domain/main-entities/employee" + ee "simrs-vx/internal/domain/main-entities/encounter" + + pa "simrs-vx/pkg/auth-helper" + "time" +) + +type CreateDto struct { + Encounter_Id *uint `json:"encounter_id"` + Employee_Id *uint `json:"-"` + Time *time.Time `json:"time"` + Value *string `json:"value"` + + pa.AuthInfo +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Preloads []string `json:"-"` +} + +type FilterDto struct { + Encounter_Id *uint `json:"encounter_id"` + Employee_Id *uint `json:"employee_id"` + Time *time.Time `json:"time"` + Value *string `json:"value"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` +} + +type UpdateDto struct { + Id uint16 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint16 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Encounter_Id *uint `json:"encounter_id"` + Encounter *ee.Encounter `json:"encounter,omitempty"` + Employee_Id *uint `json:"employee_id"` + Employee *eem.Employee `json:"employee,omitempty"` + Time *time.Time `json:"time"` + Value *string `json:"value"` +} + +func (d Sbar) ToResponse() ResponseDto { + resp := ResponseDto{ + Encounter_Id: d.Encounter_Id, + Encounter: d.Encounter, + Employee_Id: d.Employee_Id, + Employee: d.Employee, + Time: d.Time, + Value: d.Value, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []Sbar) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/sbar/entity.go b/internal/domain/main-entities/sbar/entity.go new file mode 100644 index 00000000..62303f05 --- /dev/null +++ b/internal/domain/main-entities/sbar/entity.go @@ -0,0 +1,18 @@ +package sbar + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + eem "simrs-vx/internal/domain/main-entities/employee" + ee "simrs-vx/internal/domain/main-entities/encounter" + "time" +) + +type Sbar struct { + ecore.Main // adjust this according to the needs + Encounter_Id *uint `json:"encounter_id"` + Encounter *ee.Encounter `json:"encounter,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"` + Employee_Id *uint `json:"employee_id"` + Employee *eem.Employee `json:"employee,omitempty" gorm:"foreignKey:Employee_Id;references:Id"` + Time *time.Time `json:"time"` + Value *string `json:"value"` +} diff --git a/internal/domain/main-entities/soapi/dto.go b/internal/domain/main-entities/soapi/dto.go new file mode 100644 index 00000000..6aac522e --- /dev/null +++ b/internal/domain/main-entities/soapi/dto.go @@ -0,0 +1,86 @@ +package soapi + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + eem "simrs-vx/internal/domain/main-entities/employee" + ee "simrs-vx/internal/domain/main-entities/encounter" + + pa "simrs-vx/pkg/auth-helper" + "time" +) + +type CreateDto struct { + Encounter_Id *uint `json:"encounter_id"` + Employee_Id *uint `json:"-"` + Time *time.Time `json:"time"` + Value *string `json:"value"` + + pa.AuthInfo +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Preloads []string `json:"-"` +} + +type FilterDto struct { + Encounter_Id *uint `json:"encounter_id"` + Employee_Id *uint `json:"employee_id"` + Time *time.Time `json:"time"` + Value *string `json:"value"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` +} + +type UpdateDto struct { + Id uint16 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint16 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Encounter_Id *uint `json:"encounter_id"` + Encounter *ee.Encounter `json:"encounter,omitempty"` + Employee_Id *uint `json:"employee_id"` + Employee *eem.Employee `json:"employee,omitempty"` + Time *time.Time `json:"time"` + Value *string `json:"value"` +} + +func (d Soapi) ToResponse() ResponseDto { + resp := ResponseDto{ + Encounter_Id: d.Encounter_Id, + Encounter: d.Encounter, + Employee_Id: d.Employee_Id, + Employee: d.Employee, + Time: d.Time, + Value: d.Value, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []Soapi) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/soapi/entity.go b/internal/domain/main-entities/soapi/entity.go new file mode 100644 index 00000000..f6c6b5e9 --- /dev/null +++ b/internal/domain/main-entities/soapi/entity.go @@ -0,0 +1,18 @@ +package soapi + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + eem "simrs-vx/internal/domain/main-entities/employee" + ee "simrs-vx/internal/domain/main-entities/encounter" + "time" +) + +type Soapi struct { + ecore.Main // adjust this according to the needs + Encounter_Id *uint `json:"encounter_id"` + Encounter *ee.Encounter `json:"encounter,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"` + Employee_Id *uint `json:"employee_id"` + Employee *eem.Employee `json:"employee,omitempty" gorm:"foreignKey:Employee_Id;references:Id"` + Time *time.Time `json:"time"` + Value *string `json:"value"` +} diff --git a/internal/domain/references/clinical/clinical.go b/internal/domain/references/clinical/clinical.go index 3998811b..b7709333 100644 --- a/internal/domain/references/clinical/clinical.go +++ b/internal/domain/references/clinical/clinical.go @@ -1,9 +1,11 @@ +// Package clinical mostly about SOAPI package clinical type ( SubjectCode string ObjectCode string AssessmentCode string + PlanCode string InstructionCode string ) @@ -31,8 +33,47 @@ const ( ACLateDiag AssessmentCode = "late-diag" // Diagnosis Akhir ACSecDiag AssessmentCode = "sec-diag" // Diagnosis Sekunder + PCPlan PlanCode = "plan" // Rencana + ICDetail InstructionCode = "detail" // Detail instruksi ICMedAct InstructionCode = "med-act" // Tindakan medis ICMedication InstructionCode = "medication" // Obat ICMaterial InstructionCode = "material" // BMHP ) + +type Soapi struct { + // Subject + PrimaryComplaint string `json:"pri-compl"` + SecondaryComplaint string `json:"sec-compl"` + CurrentDiseaseHistory string `json:"cur-disea-hist"` + PastDiseaseHistory string `json:"pas-disea-hist"` + FamilyDiseaseHistory string `json:"fam-disea-hist"` + AllergyHistory string `json:"alg-hist"` + AllergyReaction string `json:"alg-react"` + MedicationHistory string `json:"med-hist"` + + // Object + ConsciousnessLevel string `json:"consc-level"` + ConsciousnessLevelDet string `json:"consc-level-det"` + SystolicBloodPressure string `json:"syst-bp"` + DiastolicBloodPressure string `json:"diast-bp"` + HeartRate string `json:"hear-rt"` + Temperature string `json:"temp"` + SpO2 string `json:"spo2"` + Weight string `json:"weight"` + Height string `json:"height"` + + // Assessment + EarlyDiagnosis string `json:"early-diag"` + LateDiagnosis string `json:"late-diag"` + SecondaryDiag string `json:"sec-diag"` + + // Plan + Plan string `json:"plan"` + + // Instruction + InstructionDetail string `json:"detail"` + MedicalAction string `json:"med-act"` + Medication string `json:"medication"` + Material string `json:"material"` +} diff --git a/internal/domain/references/encounter/encounter.go b/internal/domain/references/encounter/encounter.go index 00b01236..68585f9e 100644 --- a/internal/domain/references/encounter/encounter.go +++ b/internal/domain/references/encounter/encounter.go @@ -9,17 +9,14 @@ type ( EmergencyClassCode string OutpatientClassCode string CheckupScopeCode string + AmbulatoryClassCode string + InpatientClassCode string ) const ( - ECOutpatient EncounterClassCode = "outpatient" ECAmbulatory EncounterClassCode = "ambulatory" ECEmergency EncounterClassCode = "emergency" ECInpatient EncounterClassCode = "inpatient" - ECDraft EncounterClassCode = "draft" - ECDone EncounterClassCode = "done" - ECCancel EncounterClassCode = "cancel" - ECSkip EncounterClassCode = "skip" QSCWait QueueStatusCode = "wait" // Tunggu QSCProc QueueStatusCode = "proc" // Proses @@ -27,8 +24,13 @@ const ( QSCCancel QueueStatusCode = "cancel" // Dibatalkan QSCSkip QueueStatusCode = "skip" // Dilewati - DMCHome DischargeMethodCode = "home" // Rumah - DMCHomeReq DischargeMethodCode = "home-request" // Rumah (Dibutuhkan) + DMCHome DischargeMethodCode = "home" // Rumah + DMCHomeReq DischargeMethodCode = "home-request" // Rumah (Dibutuhkan) + DMCConsulation DischargeMethodCode = "consulation" // Konsultasi Lanjutan + DMCInpatient DischargeMethodCode = "inpatient" // Inpatient + DMCExtRef DischargeMethodCode = "external-ref" // Rujuk Eksternal + DMCIntRef DischargeMethodCode = "internal-ref" // Rujuk Internal + DMCDeath DischargeMethodCode = "death" // Meninggal TCAmbulance TransportationCode = "ambulance" TCCar TransportationCode = "car" @@ -55,11 +57,18 @@ const ( CSCPLab CheckupScopeCode = "pa-lab" // Patology Anatomy Laboratorium CSCRad CheckupScopeCode = "radiology" // Radiology + ACCReg AmbulatoryClassCode = "reg" // Regular + ACCRme AmbulatoryClassCode = "rme" // Rehab Medik + + ICCIp InpatientClassCode = "ip" // Regular Rawat Inap + ICCICU InpatientClassCode = "icu" // ICU + ICCHCU InpatientClassCode = "hcu" // HCU + ICCVK InpatientClassCode = "vk" // Verlos kamer ) func (ec EncounterClassCode) Code() string { switch ec { - case ECAmbulatory, ECOutpatient: + case ECAmbulatory: return "AMB" case ECInpatient: return "IMP" diff --git a/internal/interface/main-handler/adime/handler.go b/internal/interface/main-handler/adime/handler.go new file mode 100644 index 00000000..9eabb0af --- /dev/null +++ b/internal/interface/main-handler/adime/handler.go @@ -0,0 +1,80 @@ +package adime + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/adime" + u "simrs-vx/internal/use-case/main-use-case/adime" + + pa "simrs-vx/pkg/auth-helper" + + d "github.com/karincake/dodol" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + authInfo, err := pa.GetAuthInfo(r) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) + } + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.AuthInfo = *authInfo + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint16(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint16(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/authentication/authentication.go b/internal/interface/main-handler/authentication/handler.go similarity index 83% rename from internal/interface/main-handler/authentication/authentication.go rename to internal/interface/main-handler/authentication/handler.go index 37b84346..01d4fb89 100644 --- a/internal/interface/main-handler/authentication/authentication.go +++ b/internal/interface/main-handler/authentication/handler.go @@ -9,16 +9,10 @@ import ( m "simrs-vx/internal/domain/main-entities/user" s "simrs-vx/internal/use-case/main-use-case/authentication" + + pa "simrs-vx/pkg/auth-helper" ) -type authKey string - -const akInfo authKey = "authInfo" - -type AuthKey struct{} - -// var Position m.Position - func Login(w http.ResponseWriter, r *http.Request) { var input m.LoginDto if !(rw.ValidateStructByIOR(w, r.Body, &input)) { @@ -35,12 +29,12 @@ func Login(w http.ResponseWriter, r *http.Request) { } func Logout(w http.ResponseWriter, r *http.Request) { - ctxVal := r.Context().Value(AuthKey{}) + ctxVal := r.Context().Value(pa.AuthKey{}) if ctxVal == nil { rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "logout skiped. the request is done wihtout authorization."}, nil) return } - authInfo := ctxVal.(*s.AuthInfo) + authInfo := ctxVal.(*pa.AuthInfo) s.RevokeToken(authInfo.Uuid) rw.WriteJSON(w, http.StatusOK, d.IS{"message": "logged out"}, nil) } @@ -52,7 +46,7 @@ func GuardMW(next http.Handler) http.Handler { rw.WriteJSON(w, http.StatusUnauthorized, err.(d.FieldError), nil) return } - ctx := context.WithValue(r.Context(), AuthKey{}, accessDetail) + ctx := context.WithValue(r.Context(), pa.AuthKey{}, accessDetail) next.ServeHTTP(w, r.WithContext(ctx)) }) } diff --git a/internal/interface/main-handler/encounter/handler.go b/internal/interface/main-handler/encounter/handler.go new file mode 100644 index 00000000..c2634a91 --- /dev/null +++ b/internal/interface/main-handler/encounter/handler.go @@ -0,0 +1,80 @@ +package encounter + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/encounter" + u "simrs-vx/internal/use-case/main-use-case/encounter" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint16(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint16(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) CheckOut(w http.ResponseWriter, r *http.Request) { + dto := e.DischargeDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.CheckOut(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/main-handler.go b/internal/interface/main-handler/main-handler.go index 476dacc7..5c9559f4 100644 --- a/internal/interface/main-handler/main-handler.go +++ b/internal/interface/main-handler/main-handler.go @@ -4,11 +4,15 @@ import ( "net/http" /******************** main / transaction ********************/ + adime "simrs-vx/internal/interface/main-handler/adime" auth "simrs-vx/internal/interface/main-handler/authentication" counter "simrs-vx/internal/interface/main-handler/counter" + encounter "simrs-vx/internal/interface/main-handler/encounter" medicicinemix "simrs-vx/internal/interface/main-handler/medicine-mix" medicicinemixitem "simrs-vx/internal/interface/main-handler/medicine-mix-item" practiceschedule "simrs-vx/internal/interface/main-handler/practice-schedule" + sbar "simrs-vx/internal/interface/main-handler/sbar" + soapi "simrs-vx/internal/interface/main-handler/soapi" /******************** actor ********************/ doctor "simrs-vx/internal/interface/main-handler/doctor" @@ -115,7 +119,18 @@ func SetRoutes() http.Handler { "DELETE /{id}": patient.O.Delete, "GET /by-identifier": patient.O.Search, }) + hk.GroupRoutes("/v1/encounter", r, 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}/checkout": encounter.O.CheckOut, + }) + hc.RegCrud(r, "/v1/soapi", auth.GuardMW, soapi.O) + hc.RegCrud(r, "/v1/adime", auth.GuardMW, adime.O) + hc.RegCrud(r, "/v1/sbar", auth.GuardMW, sbar.O) hc.RegCrud(r, "/v1/person", person.O) hc.RegCrud(r, "/v1/person-address", personaddress.O) hc.RegCrud(r, "/v1/person-contact", personcontact.O) diff --git a/internal/interface/main-handler/sbar/handler.go b/internal/interface/main-handler/sbar/handler.go new file mode 100644 index 00000000..7fac1e00 --- /dev/null +++ b/internal/interface/main-handler/sbar/handler.go @@ -0,0 +1,80 @@ +package sbar + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/sbar" + u "simrs-vx/internal/use-case/main-use-case/sbar" + + pa "simrs-vx/pkg/auth-helper" + + d "github.com/karincake/dodol" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + authInfo, err := pa.GetAuthInfo(r) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) + } + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.AuthInfo = *authInfo + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint16(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint16(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/soapi/handler.go b/internal/interface/main-handler/soapi/handler.go new file mode 100644 index 00000000..f5446b82 --- /dev/null +++ b/internal/interface/main-handler/soapi/handler.go @@ -0,0 +1,80 @@ +package soapi + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/soapi" + u "simrs-vx/internal/use-case/main-use-case/soapi" + + pa "simrs-vx/pkg/auth-helper" + + d "github.com/karincake/dodol" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + authInfo, err := pa.GetAuthInfo(r) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) + } + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.AuthInfo = *authInfo + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint16(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint16(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/migration/migration.go b/internal/interface/migration/migration.go index ee3cf1fc..990ca134 100644 --- a/internal/interface/migration/migration.go +++ b/internal/interface/migration/migration.go @@ -5,6 +5,9 @@ import ( "io" "os" "os/exec" + adime "simrs-vx/internal/domain/main-entities/adime" + ambulatory "simrs-vx/internal/domain/main-entities/ambulatory" + appointment "simrs-vx/internal/domain/main-entities/appointment" counter "simrs-vx/internal/domain/main-entities/counter" device "simrs-vx/internal/domain/main-entities/device" diagnosesrc "simrs-vx/internal/domain/main-entities/diagnose-src" @@ -13,10 +16,12 @@ import ( divisionposition "simrs-vx/internal/domain/main-entities/division-position" doctor "simrs-vx/internal/domain/main-entities/doctor" doctorfee "simrs-vx/internal/domain/main-entities/doctor-fee" + emergency "simrs-vx/internal/domain/main-entities/emergency" employee "simrs-vx/internal/domain/main-entities/employee" encounter "simrs-vx/internal/domain/main-entities/encounter" ethnic "simrs-vx/internal/domain/main-entities/ethnic" infra "simrs-vx/internal/domain/main-entities/infra" + inpatient "simrs-vx/internal/domain/main-entities/inpatient" installation "simrs-vx/internal/domain/main-entities/installation" insurancecompany "simrs-vx/internal/domain/main-entities/insurance-company" item "simrs-vx/internal/domain/main-entities/item" @@ -47,6 +52,8 @@ import ( province "simrs-vx/internal/domain/main-entities/province" regency "simrs-vx/internal/domain/main-entities/regency" room "simrs-vx/internal/domain/main-entities/room" + sbar "simrs-vx/internal/domain/main-entities/sbar" + soapi "simrs-vx/internal/domain/main-entities/soapi" specialist "simrs-vx/internal/domain/main-entities/specialist" specialistintern "simrs-vx/internal/domain/main-entities/specialist-intern" subspecialist "simrs-vx/internal/domain/main-entities/subspecialist" @@ -131,12 +138,19 @@ func GetEntities() []any { &language.Language{}, &personrelative.PersonRelative{}, &patient.Patient{}, + &appointment.Appointment{}, &encounter.Encounter{}, &laborant.Laborant{}, &specialist.Specialist{}, &subspecialist.Subspecialist{}, &specialistintern.SpecialistIntern{}, &room.Room{}, + &soapi.Soapi{}, + &sbar.Sbar{}, + &adime.Adime{}, + &emergency.Emergency{}, + &inpatient.Inpatient{}, + &ambulatory.Ambulatory{}, } } diff --git a/internal/use-case/main-use-case/adime/case.go b/internal/use-case/main-use-case/adime/case.go new file mode 100644 index 00000000..3a4c4496 --- /dev/null +++ b/internal/use-case/main-use-case/adime/case.go @@ -0,0 +1,298 @@ +package adime + +import ( + "errors" + "strconv" + + e "simrs-vx/internal/domain/main-entities/adime" + ee "simrs-vx/internal/domain/main-entities/employee" + + ue "simrs-vx/internal/use-case/main-use-case/employee" + + 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" +) + +const source = "adime" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Adime{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err := dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, &input, &data); err != nil { + return err + } + + if !input.AuthInfo.IsDoctor() && !input.AuthInfo.IsNurse() { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "auth-forbidden", + Detail: "user position is not allowed", + Raw: errors.New("authentication failed"), + } + return pl.SetLogError(&event, input) + } + + employee, err := ue.ReadDetailData(ee.ReadDetailDto{User_Id: &input.AuthInfo.User_Id}, &event, tx) + if err != nil { + return err + } + input.Employee_Id = &employee.Id + if resData, err := CreateData(input, &event, tx); err != nil { + return err + } else { + data = *resData + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + return err + } + + pl.SetLogInfo(&event, nil, "complete") + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + Data: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.Adime + var dataList []e.Adime + var metaList *e.MetaDto + var err error + + event := pl.Event{ + Feature: "ReadList", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readList") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, data); err != nil { + return err + } + + if len(input.Includes) > 0 { + input.Preloads = pu.GetPreloads(input.Includes) + } + if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadListMiddleware(readListPostMw, &input, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "list-data", + "status": "fetched", + "page_number": strconv.Itoa(metaList.PageNumber), + "page_size": strconv.Itoa(metaList.PageSize), + "record_totalCount": strconv.Itoa(metaList.Count), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Adime + var err error + + event := pl.Event{ + Feature: "ReadDetail", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readDetail") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { + return err + } + + if data, err = ReadDetailData(input, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPostMw, &input, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "fetched", + }, + Data: data.ToResponse(), + }, nil +} + +func Update(input e.UpdateDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.Adime + var err error + + event := pl.Event{ + Feature: "Update", + Source: source, + } + + // 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 + } + + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err + } + + if err := UpdateData(input, data, &event, tx); err != nil { + return err + } + + pl.SetLogInfo(&event, nil, "complete") + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err + } + + 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 + +} + +func Delete(input e.DeleteDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.Adime + var err error + + event := pl.Event{ + Feature: "Delete", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "delete") + + 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 + } + + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err + } + + if err := DeleteData(data, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + Data: data.ToResponse(), + }, nil + +} diff --git a/internal/use-case/main-use-case/adime/helper.go b/internal/use-case/main-use-case/adime/helper.go new file mode 100644 index 00000000..ab6a16c9 --- /dev/null +++ b/internal/use-case/main-use-case/adime/helper.go @@ -0,0 +1,24 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package adime + +import ( + e "simrs-vx/internal/domain/main-entities/adime" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Adime) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Encounter_Id = inputSrc.Encounter_Id + data.Employee_Id = inputSrc.Employee_Id + data.Time = inputSrc.Time + data.Value = inputSrc.Value +} diff --git a/internal/use-case/main-use-case/adime/lib.go b/internal/use-case/main-use-case/adime/lib.go new file mode 100644 index 00000000..851dfa4f --- /dev/null +++ b/internal/use-case/main-use-case/adime/lib.go @@ -0,0 +1,155 @@ +package adime + +import ( + e "simrs-vx/internal/domain/main-entities/adime" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Adime, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Adime{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Adime, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.Adime{} + pagination := gh.Pagination{} + count := int64(0) + meta := e.MetaDto{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if len(input.Preloads) > 0 { + for _, preload := range input.Preloads { + tx = tx.Preload(preload) + } + } + + tx = tx. + Model(&e.Adime{}). + Scopes(gh.Filter(input.FilterDto)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + + pl.SetLogInfo(event, nil, "complete") + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.Adime, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.Adime{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.First(&data, input.Id).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, input.Id, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func UpdateData(input e.UpdateDto, data *e.Adime, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBUpdate") + setData(&input, data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Save(&data).Error; 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 +} + +func DeleteData(data *e.Adime, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Delete(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-delete-fail", + Detail: "Database delete failed", + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/main-use-case/adime/middleware-runner.go b/internal/use-case/main-use-case/adime/middleware-runner.go new file mode 100644 index 00000000..5081ea55 --- /dev/null +++ b/internal/use-case/main-use-case/adime/middleware-runner.go @@ -0,0 +1,103 @@ +package adime + +import ( + e "simrs-vx/internal/domain/main-entities/adime" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" +) + +type middlewareRunner struct { + Event *pl.Event + Tx *gorm.DB + MwType pu.MWType +} + +// NewMiddlewareExecutor creates a new middleware executor +func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { + return &middlewareRunner{ + Event: event, + Tx: tx, + } +} + +// ExecuteCreateMiddleware executes create middleware +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.Adime) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.Adime) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Adime) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Adime) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Adime) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) setMwType(mwType pu.MWType) { + me.MwType = mwType +} diff --git a/internal/use-case/main-use-case/adime/middleware.go b/internal/use-case/main-use-case/adime/middleware.go new file mode 100644 index 00000000..eb7de7a4 --- /dev/null +++ b/internal/use-case/main-use-case/adime/middleware.go @@ -0,0 +1,9 @@ +package adime + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/adime/tycovar.go b/internal/use-case/main-use-case/adime/tycovar.go new file mode 100644 index 00000000..bb12cce1 --- /dev/null +++ b/internal/use-case/main-use-case/adime/tycovar.go @@ -0,0 +1,36 @@ +package adime + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/adime" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Adime, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Adime, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Adime, tx *gorm.DB) error +} + +type UpdateMw = readDetailMw +type DeleteMw = readDetailMw + +var createPreMw []createMw // preprocess middleware +var createPostMw []createMw // postprocess middleware +var readListPreMw []readListMw // .. +var readListPostMw []readListMw // .. +var readDetailPreMw []readDetailMw +var readDetailPostMw []readDetailMw +var updatePreMw []readDetailMw +var updatePostMw []readDetailMw +var deletePreMw []readDetailMw +var deletePostMw []readDetailMw diff --git a/internal/use-case/main-use-case/ambulatory/case.go b/internal/use-case/main-use-case/ambulatory/case.go new file mode 100644 index 00000000..14f6b2e5 --- /dev/null +++ b/internal/use-case/main-use-case/ambulatory/case.go @@ -0,0 +1,278 @@ +package ambulatory + +import ( + e "simrs-vx/internal/domain/main-entities/ambulatory" + "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" +) + +const source = "ambulatory" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Ambulatory{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err := dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, &input, &data); err != nil { + return err + } + + if resData, err := CreateData(input, &event, tx); err != nil { + return err + } else { + data = *resData + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + return err + } + + pl.SetLogInfo(&event, nil, "complete") + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + Data: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.Ambulatory + var dataList []e.Ambulatory + var metaList *e.MetaDto + var err error + + event := pl.Event{ + Feature: "ReadList", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readList") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, data); err != nil { + return err + } + + if len(input.Includes) > 0 { + input.Preloads = pu.GetPreloads(input.Includes) + } + if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadListMiddleware(readListPostMw, &input, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "list-data", + "status": "fetched", + "page_number": strconv.Itoa(metaList.PageNumber), + "page_size": strconv.Itoa(metaList.PageSize), + "record_totalCount": strconv.Itoa(metaList.Count), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Ambulatory + var err error + + event := pl.Event{ + Feature: "ReadDetail", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readDetail") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { + return err + } + + if data, err = ReadDetailData(input, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPostMw, &input, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "fetched", + }, + Data: data.ToResponse(), + }, nil +} + +func Update(input e.UpdateDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.Ambulatory + var err error + + event := pl.Event{ + Feature: "Update", + Source: source, + } + + // 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 + } + + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err + } + + if err := UpdateData(input, data, &event, tx); err != nil { + return err + } + + pl.SetLogInfo(&event, nil, "complete") + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err + } + + 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 + +} + +func Delete(input e.DeleteDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.Ambulatory + var err error + + event := pl.Event{ + Feature: "Delete", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "delete") + + 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 + } + + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err + } + + if err := DeleteData(data, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + Data: data.ToResponse(), + }, nil + +} diff --git a/internal/use-case/main-use-case/ambulatory/helper.go b/internal/use-case/main-use-case/ambulatory/helper.go new file mode 100644 index 00000000..39361d9d --- /dev/null +++ b/internal/use-case/main-use-case/ambulatory/helper.go @@ -0,0 +1,38 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package ambulatory + +import ( + "errors" + e "simrs-vx/internal/domain/main-entities/ambulatory" + + ere "simrs-vx/internal/domain/references/encounter" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Ambulatory) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Encounter_Id = inputSrc.Encounter_Id + data.Class_Code = inputSrc.Class_Code +} + +func CheckClassCode(input *string) (ere.AmbulatoryClassCode, error) { + if input != nil { + subCode := ere.AmbulatoryClassCode(*input) + switch subCode { + case ere.ACCReg, ere.ACCRme: + return subCode, nil + default: + return "", errors.New("unknown sub class code") + } + } + return "", errors.New("sub class code is nil") +} diff --git a/internal/use-case/main-use-case/ambulatory/lib.go b/internal/use-case/main-use-case/ambulatory/lib.go new file mode 100644 index 00000000..86d4fb06 --- /dev/null +++ b/internal/use-case/main-use-case/ambulatory/lib.go @@ -0,0 +1,155 @@ +package ambulatory + +import ( + e "simrs-vx/internal/domain/main-entities/ambulatory" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Ambulatory, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Ambulatory{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Ambulatory, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.Ambulatory{} + pagination := gh.Pagination{} + count := int64(0) + meta := e.MetaDto{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if len(input.Preloads) > 0 { + for _, preload := range input.Preloads { + tx = tx.Preload(preload) + } + } + + tx = tx. + Model(&e.Ambulatory{}). + Scopes(gh.Filter(input.FilterDto)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + + pl.SetLogInfo(event, nil, "complete") + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.Ambulatory, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.Ambulatory{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.First(&data, input.Id).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, input.Id, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func UpdateData(input e.UpdateDto, data *e.Ambulatory, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBUpdate") + setData(&input, data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Save(&data).Error; 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 +} + +func DeleteData(data *e.Ambulatory, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Delete(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-delete-fail", + Detail: "Database delete failed", + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/main-use-case/ambulatory/middleware-runner.go b/internal/use-case/main-use-case/ambulatory/middleware-runner.go new file mode 100644 index 00000000..292e6602 --- /dev/null +++ b/internal/use-case/main-use-case/ambulatory/middleware-runner.go @@ -0,0 +1,103 @@ +package ambulatory + +import ( + e "simrs-vx/internal/domain/main-entities/ambulatory" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" +) + +type middlewareRunner struct { + Event *pl.Event + Tx *gorm.DB + MwType pu.MWType +} + +// NewMiddlewareExecutor creates a new middleware executor +func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { + return &middlewareRunner{ + Event: event, + Tx: tx, + } +} + +// ExecuteCreateMiddleware executes create middleware +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.Ambulatory) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.Ambulatory) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Ambulatory) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Ambulatory) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Ambulatory) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) setMwType(mwType pu.MWType) { + me.MwType = mwType +} diff --git a/internal/use-case/main-use-case/ambulatory/middleware.go b/internal/use-case/main-use-case/ambulatory/middleware.go new file mode 100644 index 00000000..4bb381e4 --- /dev/null +++ b/internal/use-case/main-use-case/ambulatory/middleware.go @@ -0,0 +1,9 @@ +package ambulatory + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/ambulatory/tycovar.go b/internal/use-case/main-use-case/ambulatory/tycovar.go new file mode 100644 index 00000000..81239c8d --- /dev/null +++ b/internal/use-case/main-use-case/ambulatory/tycovar.go @@ -0,0 +1,44 @@ +/* +DESCRIPTION: +A sample, part of the package that contains type, constants, and/or variables. + +In this sample it also provides type and variable regarding the needs of the +middleware to separate from main use-case which has the basic CRUD +functionality. The purpose of this is to make the code more maintainable. +*/ +package ambulatory + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/ambulatory" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Ambulatory, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Ambulatory, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Ambulatory, tx *gorm.DB) error +} + +type UpdateMw = readDetailMw +type DeleteMw = readDetailMw + +var createPreMw []createMw // preprocess middleware +var createPostMw []createMw // postprocess middleware +var readListPreMw []readListMw // .. +var readListPostMw []readListMw // .. +var readDetailPreMw []readDetailMw +var readDetailPostMw []readDetailMw +var updatePreMw []readDetailMw +var updatePostMw []readDetailMw +var deletePreMw []readDetailMw +var deletePostMw []readDetailMw diff --git a/internal/use-case/main-use-case/authentication/case.go b/internal/use-case/main-use-case/authentication/case.go index 70925827..0c1f4884 100644 --- a/internal/use-case/main-use-case/authentication/case.go +++ b/internal/use-case/main-use-case/authentication/case.go @@ -16,10 +16,11 @@ import ( a "github.com/karincake/apem" ms "github.com/karincake/apem/ms-redis" + pa "simrs-vx/pkg/auth-helper" el "simrs-vx/pkg/logger" p "simrs-vx/pkg/password" - mu "simrs-vx/internal/domain/main-entities/user" + eu "simrs-vx/internal/domain/main-entities/user" erc "simrs-vx/internal/domain/references/common" ) @@ -31,9 +32,9 @@ func init() { // Generates token and store in redis at one place // just return the error code -func GenToken(input mu.LoginDto) (*d.Data, error) { +func GenToken(input eu.LoginDto) (*d.Data, error) { // Get User - user := &mu.User{Name: input.Name} + user := &eu.User{Name: input.Name} // if input.Position_Code != "" { // user.Position_Code = input.Position_Code // } @@ -94,7 +95,7 @@ func GenToken(input mu.LoginDto) (*d.Data, error) { atClaims["user_id"] = user.Id atClaims["user_name"] = user.Name // atClaims["user_email"] = user.Email - // atClaims["user_position_code"] = user.Position_Code + atClaims["user_position_code"] = user.Position_Code // atClaims["user_ref_id"] = user.Ref_Id atClaims["exp"] = atExpires atClaims["uuid"] = aUuid @@ -129,7 +130,7 @@ func GenToken(input mu.LoginDto) (*d.Data, error) { "user_id": strconv.Itoa(int(user.Id)), "user_name": user.Name, // "user_email": user.Email, - // "user_position_code": user.Position_Code, + "user_position_code": user.Position_Code, // "user_ref_id": user.Ref_Id, "accessToken": ats, }, @@ -167,7 +168,7 @@ func VerifyToken(r *http.Request, tokenType TokenType) (data *jwt.Token, errCode return token, "", "" } -func ExtractToken(r *http.Request, tokenType TokenType) (data *AuthInfo, err error) { +func ExtractToken(r *http.Request, tokenType TokenType) (data *pa.AuthInfo, err error) { token, errCode, errDetail := VerifyToken(r, tokenType) if errCode != "" { return nil, d.FieldError{Code: errCode, Message: el.GenMessage(errCode, errDetail)} @@ -196,17 +197,17 @@ func ExtractToken(r *http.Request, tokenType TokenType) (data *AuthInfo, err err // tmp := v.(float64) // ref_id = int(tmp) // } - // position_code := "" - // if v, exist := claims["user_position_code"]; exist && v != nil { - // position_code = v.(string) - // } - data = &AuthInfo{ + position_code := "" + if v, exist := claims["user_position_code"]; exist && v != nil { + position_code = v.(string) + } + data = &pa.AuthInfo{ Uuid: accessUuid, - User_Id: int(user_id), + User_Id: uint(user_id), User_Name: user_name, // User_Email: user_email, // User_Ref_Id: ref_id, - // User_Position_Code: position_code, + User_Position_Code: position_code, } return } diff --git a/internal/use-case/main-use-case/authentication/tycovar.go b/internal/use-case/main-use-case/authentication/tycovar.go index d4d5b5ea..c1b11420 100644 --- a/internal/use-case/main-use-case/authentication/tycovar.go +++ b/internal/use-case/main-use-case/authentication/tycovar.go @@ -5,15 +5,6 @@ type TokenType string const AccessToken = "Access" const RefreshToken = "Refresh" -type AuthInfo struct { - Uuid string - User_Id int - User_Name string - // User_Email string - // User_Ref_Id int - // User_Position_Code string -} - type AuthCfg struct { AtSecretKey string `yaml:"atSecretKey"` RtSecretKey string `yaml:"rtSecretKey"` diff --git a/internal/use-case/main-use-case/counter/lib.go b/internal/use-case/main-use-case/counter/lib.go index 64b22b0f..bfb0ee05 100644 --- a/internal/use-case/main-use-case/counter/lib.go +++ b/internal/use-case/main-use-case/counter/lib.go @@ -58,7 +58,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Co Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/device/lib.go b/internal/use-case/main-use-case/device/lib.go index 22c233b6..af8f9f80 100644 --- a/internal/use-case/main-use-case/device/lib.go +++ b/internal/use-case/main-use-case/device/lib.go @@ -64,7 +64,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.De Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/diagnose-src/lib.go b/internal/use-case/main-use-case/diagnose-src/lib.go index 344e36ef..1377c682 100644 --- a/internal/use-case/main-use-case/diagnose-src/lib.go +++ b/internal/use-case/main-use-case/diagnose-src/lib.go @@ -58,7 +58,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Di Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/district/lib.go b/internal/use-case/main-use-case/district/lib.go index ba98ad06..6911f4b3 100644 --- a/internal/use-case/main-use-case/district/lib.go +++ b/internal/use-case/main-use-case/district/lib.go @@ -57,7 +57,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Di Count(&count). Scopes(gh.Paginate(input, &pagination)) - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/division-position/lib.go b/internal/use-case/main-use-case/division-position/lib.go index c59506c0..6106f478 100644 --- a/internal/use-case/main-use-case/division-position/lib.go +++ b/internal/use-case/main-use-case/division-position/lib.go @@ -65,7 +65,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Di Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/division/lib.go b/internal/use-case/main-use-case/division/lib.go index ad9de8ef..64c58004 100644 --- a/internal/use-case/main-use-case/division/lib.go +++ b/internal/use-case/main-use-case/division/lib.go @@ -58,7 +58,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Di Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/doctor-fee/lib.go b/internal/use-case/main-use-case/doctor-fee/lib.go index ef4629f5..2f96d1ab 100644 --- a/internal/use-case/main-use-case/doctor-fee/lib.go +++ b/internal/use-case/main-use-case/doctor-fee/lib.go @@ -64,7 +64,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Do Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/doctor/lib.go b/internal/use-case/main-use-case/doctor/lib.go index 4383c666..e642336d 100644 --- a/internal/use-case/main-use-case/doctor/lib.go +++ b/internal/use-case/main-use-case/doctor/lib.go @@ -64,7 +64,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Do Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/emergency/case.go b/internal/use-case/main-use-case/emergency/case.go new file mode 100644 index 00000000..a21cc02c --- /dev/null +++ b/internal/use-case/main-use-case/emergency/case.go @@ -0,0 +1,278 @@ +package emergency + +import ( + e "simrs-vx/internal/domain/main-entities/emergency" + "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" +) + +const source = "emergency" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Emergency{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err := dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, &input, &data); err != nil { + return err + } + + if resData, err := CreateData(input, &event, tx); err != nil { + return err + } else { + data = *resData + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + return err + } + + pl.SetLogInfo(&event, nil, "complete") + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + Data: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.Emergency + var dataList []e.Emergency + var metaList *e.MetaDto + var err error + + event := pl.Event{ + Feature: "ReadList", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readList") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, data); err != nil { + return err + } + + if len(input.Includes) > 0 { + input.Preloads = pu.GetPreloads(input.Includes) + } + if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadListMiddleware(readListPostMw, &input, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "list-data", + "status": "fetched", + "page_number": strconv.Itoa(metaList.PageNumber), + "page_size": strconv.Itoa(metaList.PageSize), + "record_totalCount": strconv.Itoa(metaList.Count), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Emergency + var err error + + event := pl.Event{ + Feature: "ReadDetail", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readDetail") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { + return err + } + + if data, err = ReadDetailData(input, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPostMw, &input, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "fetched", + }, + Data: data.ToResponse(), + }, nil +} + +func Update(input e.UpdateDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.Emergency + var err error + + event := pl.Event{ + Feature: "Update", + Source: source, + } + + // 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 + } + + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err + } + + if err := UpdateData(input, data, &event, tx); err != nil { + return err + } + + pl.SetLogInfo(&event, nil, "complete") + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err + } + + 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 + +} + +func Delete(input e.DeleteDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.Emergency + var err error + + event := pl.Event{ + Feature: "Delete", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "delete") + + 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 + } + + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err + } + + if err := DeleteData(data, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + Data: data.ToResponse(), + }, nil + +} diff --git a/internal/use-case/main-use-case/emergency/helper.go b/internal/use-case/main-use-case/emergency/helper.go new file mode 100644 index 00000000..00cde658 --- /dev/null +++ b/internal/use-case/main-use-case/emergency/helper.go @@ -0,0 +1,38 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package emergency + +import ( + "errors" + e "simrs-vx/internal/domain/main-entities/emergency" + + ere "simrs-vx/internal/domain/references/encounter" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Emergency) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Encounter_Id = inputSrc.Encounter_Id + data.Class_Code = inputSrc.Class_Code +} + +func CheckClassCode(input *string) (ere.EmergencyClassCode, error) { + if input != nil { + subCode := ere.EmergencyClassCode(*input) + switch subCode { + case ere.ECCEmg, ere.ECCEon: + return subCode, nil + default: + return "", errors.New("unknown sub class code") + } + } + return "", errors.New("sub class code is nil") +} diff --git a/internal/use-case/main-use-case/emergency/lib.go b/internal/use-case/main-use-case/emergency/lib.go new file mode 100644 index 00000000..a1762d3e --- /dev/null +++ b/internal/use-case/main-use-case/emergency/lib.go @@ -0,0 +1,155 @@ +package emergency + +import ( + e "simrs-vx/internal/domain/main-entities/emergency" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Emergency, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Emergency{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Emergency, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.Emergency{} + pagination := gh.Pagination{} + count := int64(0) + meta := e.MetaDto{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if len(input.Preloads) > 0 { + for _, preload := range input.Preloads { + tx = tx.Preload(preload) + } + } + + tx = tx. + Model(&e.Emergency{}). + Scopes(gh.Filter(input.FilterDto)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + + pl.SetLogInfo(event, nil, "complete") + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.Emergency, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.Emergency{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.First(&data, input.Id).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, input.Id, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func UpdateData(input e.UpdateDto, data *e.Emergency, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBUpdate") + setData(&input, data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Save(&data).Error; 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 +} + +func DeleteData(data *e.Emergency, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Delete(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-delete-fail", + Detail: "Database delete failed", + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/main-use-case/emergency/middleware-runner.go b/internal/use-case/main-use-case/emergency/middleware-runner.go new file mode 100644 index 00000000..121d1b79 --- /dev/null +++ b/internal/use-case/main-use-case/emergency/middleware-runner.go @@ -0,0 +1,103 @@ +package emergency + +import ( + e "simrs-vx/internal/domain/main-entities/emergency" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" +) + +type middlewareRunner struct { + Event *pl.Event + Tx *gorm.DB + MwType pu.MWType +} + +// NewMiddlewareExecutor creates a new middleware executor +func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { + return &middlewareRunner{ + Event: event, + Tx: tx, + } +} + +// ExecuteCreateMiddleware executes create middleware +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.Emergency) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.Emergency) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Emergency) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Emergency) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Emergency) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) setMwType(mwType pu.MWType) { + me.MwType = mwType +} diff --git a/internal/use-case/main-use-case/emergency/middleware.go b/internal/use-case/main-use-case/emergency/middleware.go new file mode 100644 index 00000000..3ad52516 --- /dev/null +++ b/internal/use-case/main-use-case/emergency/middleware.go @@ -0,0 +1,9 @@ +package emergency + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/emergency/tycovar.go b/internal/use-case/main-use-case/emergency/tycovar.go new file mode 100644 index 00000000..e057fa29 --- /dev/null +++ b/internal/use-case/main-use-case/emergency/tycovar.go @@ -0,0 +1,44 @@ +/* +DESCRIPTION: +A sample, part of the package that contains type, constants, and/or variables. + +In this sample it also provides type and variable regarding the needs of the +middleware to separate from main use-case which has the basic CRUD +functionality. The purpose of this is to make the code more maintainable. +*/ +package emergency + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/emergency" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Emergency, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Emergency, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Emergency, tx *gorm.DB) error +} + +type UpdateMw = readDetailMw +type DeleteMw = readDetailMw + +var createPreMw []createMw // preprocess middleware +var createPostMw []createMw // postprocess middleware +var readListPreMw []readListMw // .. +var readListPostMw []readListMw // .. +var readDetailPreMw []readDetailMw +var readDetailPostMw []readDetailMw +var updatePreMw []readDetailMw +var updatePostMw []readDetailMw +var deletePreMw []readDetailMw +var deletePostMw []readDetailMw diff --git a/internal/use-case/main-use-case/employee/lib.go b/internal/use-case/main-use-case/employee/lib.go index 377fdfb8..594ce040 100644 --- a/internal/use-case/main-use-case/employee/lib.go +++ b/internal/use-case/main-use-case/employee/lib.go @@ -65,7 +65,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Em Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/encounter/case.go b/internal/use-case/main-use-case/encounter/case.go new file mode 100644 index 00000000..ed8fa816 --- /dev/null +++ b/internal/use-case/main-use-case/encounter/case.go @@ -0,0 +1,399 @@ +package encounter + +import ( + "errors" + "strconv" + + ea "simrs-vx/internal/domain/main-entities/ambulatory" + ee "simrs-vx/internal/domain/main-entities/emergency" + e "simrs-vx/internal/domain/main-entities/encounter" + ei "simrs-vx/internal/domain/main-entities/inpatient" + + 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" + + ere "simrs-vx/internal/domain/references/encounter" + + 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" +) + +const source = "encounter" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Encounter{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err := dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, &input, &data); err != nil { + return err + } + + if resData, err := CreateData(input, &event, tx); err != nil { + return err + } else { + data = *resData + } + + switch input.Class_Code { + case ere.ECAmbulatory: + subCode, err := ua.CheckClassCode(input.SubClass_Code) + if err != nil { + return err + } + ambCreate := ea.CreateDto{ + Encounter_Id: &data.Id, + Class_Code: subCode, + } + _, err = ua.CreateData(ambCreate, &event, tx) + if err != nil { + return err + } + case ere.ECEmergency: + subCode, err := ue.CheckClassCode(input.SubClass_Code) + if err != nil { + return err + } + emerCreate := ee.CreateDto{ + Encounter_Id: &data.Id, + Class_Code: subCode, + } + _, err = ue.CreateData(emerCreate, &event, tx) + if err != nil { + return err + } + case ere.ECInpatient: + subCode, err := ui.CheckClassCode(input.SubClass_Code) + if err != nil { + return err + } + inpCreate := ei.CreateDto{ + Encounter_Id: &data.Id, + Class_Code: subCode, + Infra_Id: input.Infra_Id, + } + _, err = ui.CreateData(inpCreate, &event, tx) + if err != nil { + return err + } + default: + return errors.New("invalid encounter class code") + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + return err + } + + pl.SetLogInfo(&event, nil, "complete") + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + Data: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.Encounter + var dataList []e.Encounter + var metaList *e.MetaDto + var err error + + event := pl.Event{ + Feature: "ReadList", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readList") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, data); err != nil { + return err + } + + if len(input.Includes) > 0 { + input.Preloads = pu.GetPreloads(input.Includes) + } + if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadListMiddleware(readListPostMw, &input, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "list-data", + "status": "fetched", + "page_number": strconv.Itoa(metaList.PageNumber), + "page_size": strconv.Itoa(metaList.PageSize), + "record_totalCount": strconv.Itoa(metaList.Count), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Encounter + var err error + + event := pl.Event{ + Feature: "ReadDetail", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readDetail") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { + return err + } + + if data, err = ReadDetailData(input, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPostMw, &input, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "fetched", + }, + Data: data.ToResponse(), + }, nil +} + +func Update(input e.UpdateDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.Encounter + var err error + + event := pl.Event{ + Feature: "Update", + Source: source, + } + + // 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.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) + } + + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err + } + + if err := UpdateData(input, data, &event, tx); err != nil { + return err + } + + pl.SetLogInfo(&event, nil, "complete") + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err + } + + 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 + +} + +func Delete(input e.DeleteDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.Encounter + var err error + + event := pl.Event{ + Feature: "Delete", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "delete") + + 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 + } + + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err + } + + if err := DeleteData(data, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + Data: data.ToResponse(), + }, nil + +} + +func CheckOut(input e.DischargeDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.Encounter + var err error + + event := pl.Event{ + Feature: "CheckOut", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "checkOut") + + 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.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) + } + if err := checkSoapiByDocExists(data.Id, &event, tx); err != nil { + return err + } + + if err := UpdateDischargeData(input, data, &event, tx); err != nil { + return err + } + + 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": "checkOut", + }, + Data: data.ToResponse(), + }, nil +} diff --git a/internal/use-case/main-use-case/encounter/helper.go b/internal/use-case/main-use-case/encounter/helper.go new file mode 100644 index 00000000..b40783b7 --- /dev/null +++ b/internal/use-case/main-use-case/encounter/helper.go @@ -0,0 +1,100 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package encounter + +import ( + "errors" + e "simrs-vx/internal/domain/main-entities/encounter" + es "simrs-vx/internal/domain/main-entities/soapi" + pl "simrs-vx/pkg/logger" + + erc "simrs-vx/internal/domain/references/common" + ero "simrs-vx/internal/domain/references/organization" + + "gorm.io/gorm" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Encounter) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Patient_Id = inputSrc.Patient_Id + data.RegisteredAt = inputSrc.RegisteredAt + data.Class_Code = inputSrc.Class_Code + data.Unit_Id = inputSrc.Unit_Id + data.Specialist_Id = inputSrc.Specialist_Id + data.Subspecialist_Id = inputSrc.Subspecialist_Id + data.VisitDate = inputSrc.VisitDate + data.Appointment_Doctor_Id = inputSrc.Appointment_Doctor_Id + data.Responsible_Doctor_Id = inputSrc.Responsible_Doctor_Id + data.RefSource_Name = inputSrc.RefSource_Name + data.Appointment_Id = inputSrc.Appointment_Id + data.Status_Code = erc.DSCNew +} + +func setDataUpdate(src e.UpdateDto, dst *e.Encounter) { + dst.Appointment_Doctor_Id = src.Appointment_Doctor_Id + dst.Responsible_Doctor_Id = src.Responsible_Doctor_Id + dst.Unit_Id = src.Unit_Id + dst.Specialist_Id = src.Specialist_Id + dst.Subspecialist_Id = src.Subspecialist_Id + dst.VisitDate = src.VisitDate +} + +func setDataDischarge(src e.DischargeDto, dst *e.Encounter) { + dst.DischargeMethod_Code = src.DischargeMethod_Code + dst.EarlyEducation = src.EarlyEducation + dst.MedicalDischargeEducation = src.MedicalDischargeEducation + dst.AdmDischargeEducation = src.AdmDischargeEducation + dst.DischargeReason = src.DischargeReason + dst.Status_Code = erc.DSCDone +} + +func checkSoapiByDocExists(encounter_id uint, event *pl.Event, tx *gorm.DB) error { + pl.SetLogInfo(event, nil, "started", "checkSoapiByDocExists") + var soapies []es.Soapi + err := tx. + Preload("Employee"). + Preload("Employee.User"). + Where("\"Encounter_Id\" = ?", encounter_id).Find(&soapies).Error + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "get soapi failed", + Raw: err, + } + return pl.SetLogError(event, nil) + } + + if len(soapies) == 0 { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-notFound", + Detail: "no soapi found for encounter", + Raw: errors.New("soapi not found"), + } + return pl.SetLogError(event, nil) + } + + for _, s := range soapies { + if s.Employee != nil && s.Employee.User != nil && s.Employee.User.Position_Code == ero.UPCDoc { + return nil + } + } + + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-update-fail", + Detail: "no soapi written by a doctor found", + Raw: errors.New("all soapi employees are not doctors"), + } + return pl.SetLogError(event, nil) +} diff --git a/internal/use-case/main-use-case/encounter/lib.go b/internal/use-case/main-use-case/encounter/lib.go new file mode 100644 index 00000000..a0aaa94b --- /dev/null +++ b/internal/use-case/main-use-case/encounter/lib.go @@ -0,0 +1,180 @@ +package encounter + +import ( + e "simrs-vx/internal/domain/main-entities/encounter" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Encounter, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Encounter{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Encounter, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.Encounter{} + pagination := gh.Pagination{} + count := int64(0) + meta := e.MetaDto{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if len(input.Preloads) > 0 { + for _, preload := range input.Preloads { + tx = tx.Preload(preload) + } + } + + tx = tx. + Model(&e.Encounter{}). + Scopes(gh.Filter(input.FilterDto)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + + pl.SetLogInfo(event, nil, "complete") + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.Encounter, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.Encounter{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.First(&data, input.Id).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, input.Id, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func UpdateData(input e.UpdateDto, data *e.Encounter, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBUpdate") + setDataUpdate(input, data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Save(&data).Error; 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 +} + +func DeleteData(data *e.Encounter, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Delete(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-delete-fail", + Detail: "Database delete failed", + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} + +func UpdateDischargeData(input e.DischargeDto, data *e.Encounter, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBUpdateDischarge") + setDataDischarge(input, data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Save(&data).Error; 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 +} diff --git a/internal/use-case/main-use-case/encounter/middleware-runner.go b/internal/use-case/main-use-case/encounter/middleware-runner.go new file mode 100644 index 00000000..1448a7af --- /dev/null +++ b/internal/use-case/main-use-case/encounter/middleware-runner.go @@ -0,0 +1,103 @@ +package encounter + +import ( + e "simrs-vx/internal/domain/main-entities/encounter" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" +) + +type middlewareRunner struct { + Event *pl.Event + Tx *gorm.DB + MwType pu.MWType +} + +// NewMiddlewareExecutor creates a new middleware executor +func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { + return &middlewareRunner{ + Event: event, + Tx: tx, + } +} + +// ExecuteCreateMiddleware executes create middleware +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.Encounter) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.Encounter) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Encounter) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Encounter) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Encounter) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) setMwType(mwType pu.MWType) { + me.MwType = mwType +} diff --git a/internal/use-case/main-use-case/encounter/middleware.go b/internal/use-case/main-use-case/encounter/middleware.go new file mode 100644 index 00000000..8a047d33 --- /dev/null +++ b/internal/use-case/main-use-case/encounter/middleware.go @@ -0,0 +1,9 @@ +package encounter + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/encounter/tycovar.go b/internal/use-case/main-use-case/encounter/tycovar.go new file mode 100644 index 00000000..17890a1b --- /dev/null +++ b/internal/use-case/main-use-case/encounter/tycovar.go @@ -0,0 +1,44 @@ +/* +DESCRIPTION: +A sample, part of the package that contains type, constants, and/or variables. + +In this sample it also provides type and variable regarding the needs of the +middleware to separate from main use-case which has the basic CRUD +functionality. The purpose of this is to make the code more maintainable. +*/ +package encounter + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/encounter" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Encounter, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Encounter, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Encounter, tx *gorm.DB) error +} + +type UpdateMw = readDetailMw +type DeleteMw = readDetailMw + +var createPreMw []createMw // preprocess middleware +var createPostMw []createMw // postprocess middleware +var readListPreMw []readListMw // .. +var readListPostMw []readListMw // .. +var readDetailPreMw []readDetailMw +var readDetailPostMw []readDetailMw +var updatePreMw []readDetailMw +var updatePostMw []readDetailMw +var deletePreMw []readDetailMw +var deletePostMw []readDetailMw diff --git a/internal/use-case/main-use-case/ethnic/lib.go b/internal/use-case/main-use-case/ethnic/lib.go index 96921640..353618ef 100644 --- a/internal/use-case/main-use-case/ethnic/lib.go +++ b/internal/use-case/main-use-case/ethnic/lib.go @@ -58,7 +58,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Et Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/infra/lib.go b/internal/use-case/main-use-case/infra/lib.go index d4ec76d0..56e528fb 100644 --- a/internal/use-case/main-use-case/infra/lib.go +++ b/internal/use-case/main-use-case/infra/lib.go @@ -64,7 +64,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.In Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/inpatient/case.go b/internal/use-case/main-use-case/inpatient/case.go new file mode 100644 index 00000000..9c6aa963 --- /dev/null +++ b/internal/use-case/main-use-case/inpatient/case.go @@ -0,0 +1,278 @@ +package inpatient + +import ( + e "simrs-vx/internal/domain/main-entities/inpatient" + "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" +) + +const source = "ambulatory" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Inpatient{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err := dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, &input, &data); err != nil { + return err + } + + if resData, err := CreateData(input, &event, tx); err != nil { + return err + } else { + data = *resData + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + return err + } + + pl.SetLogInfo(&event, nil, "complete") + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + Data: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.Inpatient + var dataList []e.Inpatient + var metaList *e.MetaDto + var err error + + event := pl.Event{ + Feature: "ReadList", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readList") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, data); err != nil { + return err + } + + if len(input.Includes) > 0 { + input.Preloads = pu.GetPreloads(input.Includes) + } + if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadListMiddleware(readListPostMw, &input, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "list-data", + "status": "fetched", + "page_number": strconv.Itoa(metaList.PageNumber), + "page_size": strconv.Itoa(metaList.PageSize), + "record_totalCount": strconv.Itoa(metaList.Count), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Inpatient + var err error + + event := pl.Event{ + Feature: "ReadDetail", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readDetail") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { + return err + } + + if data, err = ReadDetailData(input, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPostMw, &input, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "fetched", + }, + Data: data.ToResponse(), + }, nil +} + +func Update(input e.UpdateDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.Inpatient + var err error + + event := pl.Event{ + Feature: "Update", + Source: source, + } + + // 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 + } + + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err + } + + if err := UpdateData(input, data, &event, tx); err != nil { + return err + } + + pl.SetLogInfo(&event, nil, "complete") + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err + } + + 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 + +} + +func Delete(input e.DeleteDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.Inpatient + var err error + + event := pl.Event{ + Feature: "Delete", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "delete") + + 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 + } + + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err + } + + if err := DeleteData(data, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + Data: data.ToResponse(), + }, nil + +} diff --git a/internal/use-case/main-use-case/inpatient/helper.go b/internal/use-case/main-use-case/inpatient/helper.go new file mode 100644 index 00000000..45014af1 --- /dev/null +++ b/internal/use-case/main-use-case/inpatient/helper.go @@ -0,0 +1,38 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package inpatient + +import ( + "errors" + e "simrs-vx/internal/domain/main-entities/inpatient" + + ere "simrs-vx/internal/domain/references/encounter" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Inpatient) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Encounter_Id = inputSrc.Encounter_Id + data.Class_Code = inputSrc.Class_Code +} + +func CheckClassCode(input *string) (ere.InpatientClassCode, error) { + if input != nil { + subCode := ere.InpatientClassCode(*input) + switch subCode { + case ere.ICCHCU, ere.ICCICU, ere.ICCVK, ere.ICCIp: + return subCode, nil + default: + return "", errors.New("unknown sub class code") + } + } + return "", errors.New("sub class code is nil") +} diff --git a/internal/use-case/main-use-case/inpatient/lib.go b/internal/use-case/main-use-case/inpatient/lib.go new file mode 100644 index 00000000..f7b49d8a --- /dev/null +++ b/internal/use-case/main-use-case/inpatient/lib.go @@ -0,0 +1,155 @@ +package inpatient + +import ( + e "simrs-vx/internal/domain/main-entities/inpatient" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Inpatient, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Inpatient{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Inpatient, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.Inpatient{} + pagination := gh.Pagination{} + count := int64(0) + meta := e.MetaDto{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if len(input.Preloads) > 0 { + for _, preload := range input.Preloads { + tx = tx.Preload(preload) + } + } + + tx = tx. + Model(&e.Inpatient{}). + Scopes(gh.Filter(input.FilterDto)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + + pl.SetLogInfo(event, nil, "complete") + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.Inpatient, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.Inpatient{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.First(&data, input.Id).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, input.Id, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func UpdateData(input e.UpdateDto, data *e.Inpatient, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBUpdate") + setData(&input, data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Save(&data).Error; 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 +} + +func DeleteData(data *e.Inpatient, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Delete(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-delete-fail", + Detail: "Database delete failed", + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/main-use-case/inpatient/middleware-runner.go b/internal/use-case/main-use-case/inpatient/middleware-runner.go new file mode 100644 index 00000000..5f771f5a --- /dev/null +++ b/internal/use-case/main-use-case/inpatient/middleware-runner.go @@ -0,0 +1,103 @@ +package inpatient + +import ( + e "simrs-vx/internal/domain/main-entities/inpatient" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" +) + +type middlewareRunner struct { + Event *pl.Event + Tx *gorm.DB + MwType pu.MWType +} + +// NewMiddlewareExecutor creates a new middleware executor +func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { + return &middlewareRunner{ + Event: event, + Tx: tx, + } +} + +// ExecuteCreateMiddleware executes create middleware +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.Inpatient) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.Inpatient) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Inpatient) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Inpatient) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Inpatient) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) setMwType(mwType pu.MWType) { + me.MwType = mwType +} diff --git a/internal/use-case/main-use-case/inpatient/middleware.go b/internal/use-case/main-use-case/inpatient/middleware.go new file mode 100644 index 00000000..017be42d --- /dev/null +++ b/internal/use-case/main-use-case/inpatient/middleware.go @@ -0,0 +1,9 @@ +package inpatient + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/inpatient/tycovar.go b/internal/use-case/main-use-case/inpatient/tycovar.go new file mode 100644 index 00000000..209477ff --- /dev/null +++ b/internal/use-case/main-use-case/inpatient/tycovar.go @@ -0,0 +1,44 @@ +/* +DESCRIPTION: +A sample, part of the package that contains type, constants, and/or variables. + +In this sample it also provides type and variable regarding the needs of the +middleware to separate from main use-case which has the basic CRUD +functionality. The purpose of this is to make the code more maintainable. +*/ +package inpatient + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/inpatient" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Inpatient, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Inpatient, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Inpatient, tx *gorm.DB) error +} + +type UpdateMw = readDetailMw +type DeleteMw = readDetailMw + +var createPreMw []createMw // preprocess middleware +var createPostMw []createMw // postprocess middleware +var readListPreMw []readListMw // .. +var readListPostMw []readListMw // .. +var readDetailPreMw []readDetailMw +var readDetailPostMw []readDetailMw +var updatePreMw []readDetailMw +var updatePostMw []readDetailMw +var deletePreMw []readDetailMw +var deletePostMw []readDetailMw diff --git a/internal/use-case/main-use-case/installation/lib.go b/internal/use-case/main-use-case/installation/lib.go index 0cd9a6dc..5fa5bbf9 100644 --- a/internal/use-case/main-use-case/installation/lib.go +++ b/internal/use-case/main-use-case/installation/lib.go @@ -58,7 +58,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.In Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/insurance-company/lib.go b/internal/use-case/main-use-case/insurance-company/lib.go index 15073715..95d004b5 100644 --- a/internal/use-case/main-use-case/insurance-company/lib.go +++ b/internal/use-case/main-use-case/insurance-company/lib.go @@ -64,7 +64,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.In Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/item-price/lib.go b/internal/use-case/main-use-case/item-price/lib.go index 8d61f2f8..6e3a8d5c 100644 --- a/internal/use-case/main-use-case/item-price/lib.go +++ b/internal/use-case/main-use-case/item-price/lib.go @@ -64,7 +64,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.It Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/item/lib.go b/internal/use-case/main-use-case/item/lib.go index b62e1c3a..ed1eb3b8 100644 --- a/internal/use-case/main-use-case/item/lib.go +++ b/internal/use-case/main-use-case/item/lib.go @@ -64,7 +64,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.It Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/laborant/lib.go b/internal/use-case/main-use-case/laborant/lib.go index 9c1ee441..0802f601 100644 --- a/internal/use-case/main-use-case/laborant/lib.go +++ b/internal/use-case/main-use-case/laborant/lib.go @@ -64,7 +64,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.La Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/language/lib.go b/internal/use-case/main-use-case/language/lib.go index 65a2ed08..d44689d4 100644 --- a/internal/use-case/main-use-case/language/lib.go +++ b/internal/use-case/main-use-case/language/lib.go @@ -58,7 +58,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.La Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/material/lib.go b/internal/use-case/main-use-case/material/lib.go index f1a3f40b..c74f7b6c 100644 --- a/internal/use-case/main-use-case/material/lib.go +++ b/internal/use-case/main-use-case/material/lib.go @@ -64,7 +64,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Ma Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/mcu-src-category/lib.go b/internal/use-case/main-use-case/mcu-src-category/lib.go index d62184d1..aea54986 100644 --- a/internal/use-case/main-use-case/mcu-src-category/lib.go +++ b/internal/use-case/main-use-case/mcu-src-category/lib.go @@ -58,7 +58,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Mc Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/mcu-src/lib.go b/internal/use-case/main-use-case/mcu-src/lib.go index e7e76041..36a1a604 100644 --- a/internal/use-case/main-use-case/mcu-src/lib.go +++ b/internal/use-case/main-use-case/mcu-src/lib.go @@ -64,7 +64,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Mc Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/medical-action-src-item/lib.go b/internal/use-case/main-use-case/medical-action-src-item/lib.go index 02d81f6c..50f7cecd 100644 --- a/internal/use-case/main-use-case/medical-action-src-item/lib.go +++ b/internal/use-case/main-use-case/medical-action-src-item/lib.go @@ -64,7 +64,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Me Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/medical-action-src/lib.go b/internal/use-case/main-use-case/medical-action-src/lib.go index 5bef2fca..1446b759 100644 --- a/internal/use-case/main-use-case/medical-action-src/lib.go +++ b/internal/use-case/main-use-case/medical-action-src/lib.go @@ -64,7 +64,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Me Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/medicine-group/lib.go b/internal/use-case/main-use-case/medicine-group/lib.go index 6388544c..f4288b03 100644 --- a/internal/use-case/main-use-case/medicine-group/lib.go +++ b/internal/use-case/main-use-case/medicine-group/lib.go @@ -58,7 +58,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Me Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/medicine-method/lib.go b/internal/use-case/main-use-case/medicine-method/lib.go index 8e11d043..828427bc 100644 --- a/internal/use-case/main-use-case/medicine-method/lib.go +++ b/internal/use-case/main-use-case/medicine-method/lib.go @@ -58,7 +58,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Me Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/medicine-mix-item/lib.go b/internal/use-case/main-use-case/medicine-mix-item/lib.go index 3bea8e9c..fa85aab5 100644 --- a/internal/use-case/main-use-case/medicine-mix-item/lib.go +++ b/internal/use-case/main-use-case/medicine-mix-item/lib.go @@ -64,7 +64,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Me Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/medicine-mix/lib.go b/internal/use-case/main-use-case/medicine-mix/lib.go index 2c20870c..6a2cf257 100644 --- a/internal/use-case/main-use-case/medicine-mix/lib.go +++ b/internal/use-case/main-use-case/medicine-mix/lib.go @@ -58,7 +58,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Me Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/medicine/lib.go b/internal/use-case/main-use-case/medicine/lib.go index c7295e10..ce894baa 100644 --- a/internal/use-case/main-use-case/medicine/lib.go +++ b/internal/use-case/main-use-case/medicine/lib.go @@ -64,7 +64,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Me Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/nurse/lib.go b/internal/use-case/main-use-case/nurse/lib.go index 723829b6..d3c48f60 100644 --- a/internal/use-case/main-use-case/nurse/lib.go +++ b/internal/use-case/main-use-case/nurse/lib.go @@ -64,7 +64,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Nu Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/nutritionist/lib.go b/internal/use-case/main-use-case/nutritionist/lib.go index 211e3718..c9d219a3 100644 --- a/internal/use-case/main-use-case/nutritionist/lib.go +++ b/internal/use-case/main-use-case/nutritionist/lib.go @@ -64,7 +64,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Nu Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/patient/lib.go b/internal/use-case/main-use-case/patient/lib.go index 539f6843..590e732e 100644 --- a/internal/use-case/main-use-case/patient/lib.go +++ b/internal/use-case/main-use-case/patient/lib.go @@ -67,7 +67,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Pa Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/person-address/lib.go b/internal/use-case/main-use-case/person-address/lib.go index 0743f427..fa7484ad 100644 --- a/internal/use-case/main-use-case/person-address/lib.go +++ b/internal/use-case/main-use-case/person-address/lib.go @@ -58,7 +58,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Pe Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/person-contact/lib.go b/internal/use-case/main-use-case/person-contact/lib.go index 9e61bb59..18c78dd3 100644 --- a/internal/use-case/main-use-case/person-contact/lib.go +++ b/internal/use-case/main-use-case/person-contact/lib.go @@ -58,7 +58,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Pe Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/person-relative/lib.go b/internal/use-case/main-use-case/person-relative/lib.go index 872ad321..44a75cda 100644 --- a/internal/use-case/main-use-case/person-relative/lib.go +++ b/internal/use-case/main-use-case/person-relative/lib.go @@ -58,7 +58,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Pe Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/person/lib.go b/internal/use-case/main-use-case/person/lib.go index 17380cb2..42703287 100644 --- a/internal/use-case/main-use-case/person/lib.go +++ b/internal/use-case/main-use-case/person/lib.go @@ -67,7 +67,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Pe Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/pharmacist/lib.go b/internal/use-case/main-use-case/pharmacist/lib.go index fb6d5168..5559be6c 100644 --- a/internal/use-case/main-use-case/pharmacist/lib.go +++ b/internal/use-case/main-use-case/pharmacist/lib.go @@ -64,7 +64,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Ph Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/pharmacy-company/lib.go b/internal/use-case/main-use-case/pharmacy-company/lib.go index f4eca38e..3fca529a 100644 --- a/internal/use-case/main-use-case/pharmacy-company/lib.go +++ b/internal/use-case/main-use-case/pharmacy-company/lib.go @@ -58,7 +58,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Ph Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/practice-schedule/lib.go b/internal/use-case/main-use-case/practice-schedule/lib.go index 1d5e34ac..ae494b9d 100644 --- a/internal/use-case/main-use-case/practice-schedule/lib.go +++ b/internal/use-case/main-use-case/practice-schedule/lib.go @@ -64,7 +64,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Pr Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/procedure-src/lib.go b/internal/use-case/main-use-case/procedure-src/lib.go index b1b1b01f..501315ea 100644 --- a/internal/use-case/main-use-case/procedure-src/lib.go +++ b/internal/use-case/main-use-case/procedure-src/lib.go @@ -58,7 +58,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Pr Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/province/lib.go b/internal/use-case/main-use-case/province/lib.go index b84db301..5b8b4b33 100644 --- a/internal/use-case/main-use-case/province/lib.go +++ b/internal/use-case/main-use-case/province/lib.go @@ -57,7 +57,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Pr Count(&count). Scopes(gh.Paginate(input, &pagination)) - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/regency/lib.go b/internal/use-case/main-use-case/regency/lib.go index c098aabd..21433f6b 100644 --- a/internal/use-case/main-use-case/regency/lib.go +++ b/internal/use-case/main-use-case/regency/lib.go @@ -57,7 +57,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Re Count(&count). Scopes(gh.Paginate(input, &pagination)) - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/room/lib.go b/internal/use-case/main-use-case/room/lib.go index f8943263..df416fa1 100644 --- a/internal/use-case/main-use-case/room/lib.go +++ b/internal/use-case/main-use-case/room/lib.go @@ -64,7 +64,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Ro Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/sbar/case.go b/internal/use-case/main-use-case/sbar/case.go new file mode 100644 index 00000000..3606bae4 --- /dev/null +++ b/internal/use-case/main-use-case/sbar/case.go @@ -0,0 +1,298 @@ +package sbar + +import ( + "errors" + "strconv" + + ee "simrs-vx/internal/domain/main-entities/employee" + e "simrs-vx/internal/domain/main-entities/sbar" + + ue "simrs-vx/internal/use-case/main-use-case/employee" + + 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" +) + +const source = "sbar" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Sbar{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err := dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, &input, &data); err != nil { + return err + } + + if !input.AuthInfo.IsDoctor() && !input.AuthInfo.IsNurse() { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "auth-forbidden", + Detail: "user position is not allowed", + Raw: errors.New("authentication failed"), + } + return pl.SetLogError(&event, input) + } + + employee, err := ue.ReadDetailData(ee.ReadDetailDto{User_Id: &input.AuthInfo.User_Id}, &event, tx) + if err != nil { + return err + } + input.Employee_Id = &employee.Id + if resData, err := CreateData(input, &event, tx); err != nil { + return err + } else { + data = *resData + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + return err + } + + pl.SetLogInfo(&event, nil, "complete") + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + Data: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.Sbar + var dataList []e.Sbar + var metaList *e.MetaDto + var err error + + event := pl.Event{ + Feature: "ReadList", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readList") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, data); err != nil { + return err + } + + if len(input.Includes) > 0 { + input.Preloads = pu.GetPreloads(input.Includes) + } + if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadListMiddleware(readListPostMw, &input, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "list-data", + "status": "fetched", + "page_number": strconv.Itoa(metaList.PageNumber), + "page_size": strconv.Itoa(metaList.PageSize), + "record_totalCount": strconv.Itoa(metaList.Count), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Sbar + var err error + + event := pl.Event{ + Feature: "ReadDetail", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readDetail") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { + return err + } + + if data, err = ReadDetailData(input, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPostMw, &input, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "fetched", + }, + Data: data.ToResponse(), + }, nil +} + +func Update(input e.UpdateDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.Sbar + var err error + + event := pl.Event{ + Feature: "Update", + Source: source, + } + + // 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 + } + + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err + } + + if err := UpdateData(input, data, &event, tx); err != nil { + return err + } + + pl.SetLogInfo(&event, nil, "complete") + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err + } + + 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 + +} + +func Delete(input e.DeleteDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.Sbar + var err error + + event := pl.Event{ + Feature: "Delete", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "delete") + + 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 + } + + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err + } + + if err := DeleteData(data, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + Data: data.ToResponse(), + }, nil + +} diff --git a/internal/use-case/main-use-case/sbar/helper.go b/internal/use-case/main-use-case/sbar/helper.go new file mode 100644 index 00000000..06eefec6 --- /dev/null +++ b/internal/use-case/main-use-case/sbar/helper.go @@ -0,0 +1,24 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package sbar + +import ( + e "simrs-vx/internal/domain/main-entities/sbar" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Sbar) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Encounter_Id = inputSrc.Encounter_Id + data.Employee_Id = inputSrc.Employee_Id + data.Time = inputSrc.Time + data.Value = inputSrc.Value +} diff --git a/internal/use-case/main-use-case/sbar/lib.go b/internal/use-case/main-use-case/sbar/lib.go new file mode 100644 index 00000000..4151d276 --- /dev/null +++ b/internal/use-case/main-use-case/sbar/lib.go @@ -0,0 +1,155 @@ +package sbar + +import ( + e "simrs-vx/internal/domain/main-entities/sbar" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Sbar, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Sbar{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Sbar, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.Sbar{} + pagination := gh.Pagination{} + count := int64(0) + meta := e.MetaDto{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if len(input.Preloads) > 0 { + for _, preload := range input.Preloads { + tx = tx.Preload(preload) + } + } + + tx = tx. + Model(&e.Sbar{}). + Scopes(gh.Filter(input.FilterDto)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + + pl.SetLogInfo(event, nil, "complete") + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.Sbar, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.Sbar{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.First(&data, input.Id).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, input.Id, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func UpdateData(input e.UpdateDto, data *e.Sbar, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBUpdate") + setData(&input, data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Save(&data).Error; 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 +} + +func DeleteData(data *e.Sbar, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Delete(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-delete-fail", + Detail: "Database delete failed", + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/main-use-case/sbar/middleware-runner.go b/internal/use-case/main-use-case/sbar/middleware-runner.go new file mode 100644 index 00000000..a628d1b0 --- /dev/null +++ b/internal/use-case/main-use-case/sbar/middleware-runner.go @@ -0,0 +1,103 @@ +package sbar + +import ( + e "simrs-vx/internal/domain/main-entities/sbar" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" +) + +type middlewareRunner struct { + Event *pl.Event + Tx *gorm.DB + MwType pu.MWType +} + +// NewMiddlewareExecutor creates a new middleware executor +func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { + return &middlewareRunner{ + Event: event, + Tx: tx, + } +} + +// ExecuteCreateMiddleware executes create middleware +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.Sbar) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.Sbar) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Sbar) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Sbar) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Sbar) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) setMwType(mwType pu.MWType) { + me.MwType = mwType +} diff --git a/internal/use-case/main-use-case/sbar/middleware.go b/internal/use-case/main-use-case/sbar/middleware.go new file mode 100644 index 00000000..6ed8e657 --- /dev/null +++ b/internal/use-case/main-use-case/sbar/middleware.go @@ -0,0 +1,9 @@ +package sbar + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/sbar/tycovar.go b/internal/use-case/main-use-case/sbar/tycovar.go new file mode 100644 index 00000000..dda3872a --- /dev/null +++ b/internal/use-case/main-use-case/sbar/tycovar.go @@ -0,0 +1,44 @@ +/* +DESCRIPTION: +A sample, part of the package that contains type, constants, and/or variables. + +In this sample it also provides type and variable regarding the needs of the +middleware to separate from main use-case which has the basic CRUD +functionality. The purpose of this is to make the code more maintainable. +*/ +package sbar + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/sbar" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Sbar, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Sbar, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Sbar, tx *gorm.DB) error +} + +type UpdateMw = readDetailMw +type DeleteMw = readDetailMw + +var createPreMw []createMw // preprocess middleware +var createPostMw []createMw // postprocess middleware +var readListPreMw []readListMw // .. +var readListPostMw []readListMw // .. +var readDetailPreMw []readDetailMw +var readDetailPostMw []readDetailMw +var updatePreMw []readDetailMw +var updatePostMw []readDetailMw +var deletePreMw []readDetailMw +var deletePostMw []readDetailMw diff --git a/internal/use-case/main-use-case/soapi/case.go b/internal/use-case/main-use-case/soapi/case.go new file mode 100644 index 00000000..46e64e71 --- /dev/null +++ b/internal/use-case/main-use-case/soapi/case.go @@ -0,0 +1,298 @@ +package soapi + +import ( + "errors" + "strconv" + + ee "simrs-vx/internal/domain/main-entities/employee" + e "simrs-vx/internal/domain/main-entities/soapi" + + ue "simrs-vx/internal/use-case/main-use-case/employee" + + 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" +) + +const source = "soapi" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Soapi{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err := dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, &input, &data); err != nil { + return err + } + + if !input.AuthInfo.IsDoctor() && !input.AuthInfo.IsNurse() { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "auth-forbidden", + Detail: "user position is not allowed", + Raw: errors.New("authentication failed"), + } + return pl.SetLogError(&event, input) + } + + employee, err := ue.ReadDetailData(ee.ReadDetailDto{User_Id: &input.AuthInfo.User_Id}, &event, tx) + if err != nil { + return err + } + input.Employee_Id = &employee.Id + if resData, err := CreateData(input, &event, tx); err != nil { + return err + } else { + data = *resData + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + return err + } + + pl.SetLogInfo(&event, nil, "complete") + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + Data: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.Soapi + var dataList []e.Soapi + var metaList *e.MetaDto + var err error + + event := pl.Event{ + Feature: "ReadList", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readList") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, data); err != nil { + return err + } + + if len(input.Includes) > 0 { + input.Preloads = pu.GetPreloads(input.Includes) + } + if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadListMiddleware(readListPostMw, &input, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "list-data", + "status": "fetched", + "page_number": strconv.Itoa(metaList.PageNumber), + "page_size": strconv.Itoa(metaList.PageSize), + "record_totalCount": strconv.Itoa(metaList.Count), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Soapi + var err error + + event := pl.Event{ + Feature: "ReadDetail", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readDetail") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { + return err + } + + if data, err = ReadDetailData(input, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPostMw, &input, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "fetched", + }, + Data: data.ToResponse(), + }, nil +} + +func Update(input e.UpdateDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.Soapi + var err error + + event := pl.Event{ + Feature: "Update", + Source: source, + } + + // 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 + } + + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err + } + + if err := UpdateData(input, data, &event, tx); err != nil { + return err + } + + pl.SetLogInfo(&event, nil, "complete") + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err + } + + 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 + +} + +func Delete(input e.DeleteDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.Soapi + var err error + + event := pl.Event{ + Feature: "Delete", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "delete") + + 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 + } + + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err + } + + if err := DeleteData(data, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + Data: data.ToResponse(), + }, nil + +} diff --git a/internal/use-case/main-use-case/soapi/helper.go b/internal/use-case/main-use-case/soapi/helper.go new file mode 100644 index 00000000..504acff6 --- /dev/null +++ b/internal/use-case/main-use-case/soapi/helper.go @@ -0,0 +1,24 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package soapi + +import ( + e "simrs-vx/internal/domain/main-entities/soapi" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Soapi) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Encounter_Id = inputSrc.Encounter_Id + data.Employee_Id = inputSrc.Employee_Id + data.Time = inputSrc.Time + data.Value = inputSrc.Value +} diff --git a/internal/use-case/main-use-case/soapi/lib.go b/internal/use-case/main-use-case/soapi/lib.go new file mode 100644 index 00000000..bc848678 --- /dev/null +++ b/internal/use-case/main-use-case/soapi/lib.go @@ -0,0 +1,155 @@ +package soapi + +import ( + e "simrs-vx/internal/domain/main-entities/soapi" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Soapi, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Soapi{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Soapi, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.Soapi{} + pagination := gh.Pagination{} + count := int64(0) + meta := e.MetaDto{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if len(input.Preloads) > 0 { + for _, preload := range input.Preloads { + tx = tx.Preload(preload) + } + } + + tx = tx. + Model(&e.Soapi{}). + Scopes(gh.Filter(input.FilterDto)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + + pl.SetLogInfo(event, nil, "complete") + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.Soapi, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.Soapi{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.First(&data, input.Id).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, input.Id, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func UpdateData(input e.UpdateDto, data *e.Soapi, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBUpdate") + setData(&input, data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Save(&data).Error; 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 +} + +func DeleteData(data *e.Soapi, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Delete(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-delete-fail", + Detail: "Database delete failed", + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/main-use-case/soapi/middleware-runner.go b/internal/use-case/main-use-case/soapi/middleware-runner.go new file mode 100644 index 00000000..a840a33a --- /dev/null +++ b/internal/use-case/main-use-case/soapi/middleware-runner.go @@ -0,0 +1,103 @@ +package soapi + +import ( + e "simrs-vx/internal/domain/main-entities/soapi" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" +) + +type middlewareRunner struct { + Event *pl.Event + Tx *gorm.DB + MwType pu.MWType +} + +// NewMiddlewareExecutor creates a new middleware executor +func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { + return &middlewareRunner{ + Event: event, + Tx: tx, + } +} + +// ExecuteCreateMiddleware executes create middleware +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.Soapi) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.Soapi) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Soapi) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Soapi) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Soapi) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) setMwType(mwType pu.MWType) { + me.MwType = mwType +} diff --git a/internal/use-case/main-use-case/soapi/middleware.go b/internal/use-case/main-use-case/soapi/middleware.go new file mode 100644 index 00000000..f2fecda5 --- /dev/null +++ b/internal/use-case/main-use-case/soapi/middleware.go @@ -0,0 +1,9 @@ +package soapi + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/soapi/tycovar.go b/internal/use-case/main-use-case/soapi/tycovar.go new file mode 100644 index 00000000..956193a4 --- /dev/null +++ b/internal/use-case/main-use-case/soapi/tycovar.go @@ -0,0 +1,44 @@ +/* +DESCRIPTION: +A sample, part of the package that contains type, constants, and/or variables. + +In this sample it also provides type and variable regarding the needs of the +middleware to separate from main use-case which has the basic CRUD +functionality. The purpose of this is to make the code more maintainable. +*/ +package soapi + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/soapi" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Soapi, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Soapi, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Soapi, tx *gorm.DB) error +} + +type UpdateMw = readDetailMw +type DeleteMw = readDetailMw + +var createPreMw []createMw // preprocess middleware +var createPostMw []createMw // postprocess middleware +var readListPreMw []readListMw // .. +var readListPostMw []readListMw // .. +var readDetailPreMw []readDetailMw +var readDetailPostMw []readDetailMw +var updatePreMw []readDetailMw +var updatePostMw []readDetailMw +var deletePreMw []readDetailMw +var deletePostMw []readDetailMw diff --git a/internal/use-case/main-use-case/specialist-intern/lib.go b/internal/use-case/main-use-case/specialist-intern/lib.go index 81c0f0a9..81590bc3 100644 --- a/internal/use-case/main-use-case/specialist-intern/lib.go +++ b/internal/use-case/main-use-case/specialist-intern/lib.go @@ -64,7 +64,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Sp Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/specialist/lib.go b/internal/use-case/main-use-case/specialist/lib.go index 5d31ea56..206682e0 100644 --- a/internal/use-case/main-use-case/specialist/lib.go +++ b/internal/use-case/main-use-case/specialist/lib.go @@ -64,7 +64,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Sp Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/subspecialist/lib.go b/internal/use-case/main-use-case/subspecialist/lib.go index 49c87685..5d879b1e 100644 --- a/internal/use-case/main-use-case/subspecialist/lib.go +++ b/internal/use-case/main-use-case/subspecialist/lib.go @@ -64,7 +64,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Su Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/unit/lib.go b/internal/use-case/main-use-case/unit/lib.go index f43530dc..9be91f11 100644 --- a/internal/use-case/main-use-case/unit/lib.go +++ b/internal/use-case/main-use-case/unit/lib.go @@ -65,7 +65,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Un Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/uom/lib.go b/internal/use-case/main-use-case/uom/lib.go index 655be4cd..0cbc85e0 100644 --- a/internal/use-case/main-use-case/uom/lib.go +++ b/internal/use-case/main-use-case/uom/lib.go @@ -58,7 +58,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Uo Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/user/lib.go b/internal/use-case/main-use-case/user/lib.go index 0af63c75..e857e9b3 100644 --- a/internal/use-case/main-use-case/user/lib.go +++ b/internal/use-case/main-use-case/user/lib.go @@ -58,7 +58,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Us Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/village/lib.go b/internal/use-case/main-use-case/village/lib.go index c67f3ac4..2e7dd2da 100644 --- a/internal/use-case/main-use-case/village/lib.go +++ b/internal/use-case/main-use-case/village/lib.go @@ -57,7 +57,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Vi Count(&count). Scopes(gh.Paginate(input, &pagination)) - if err := tx.Debug().Find(&data).Error; err != nil { + if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/pkg/auth-helper/auth-helper.go b/pkg/auth-helper/auth-helper.go new file mode 100644 index 00000000..934d8d61 --- /dev/null +++ b/pkg/auth-helper/auth-helper.go @@ -0,0 +1,15 @@ +package authhelper + +import ( + "errors" + "net/http" +) + +func GetAuthInfo(r *http.Request) (*AuthInfo, error) { + ctxVal := r.Context().Value(AuthKey{}) + if ctxVal == nil { + return nil, errors.New("can't get auth info") + } + authInfo := ctxVal.(*AuthInfo) + return authInfo, nil +} diff --git a/pkg/auth-helper/tycovar.go b/pkg/auth-helper/tycovar.go new file mode 100644 index 00000000..7586956d --- /dev/null +++ b/pkg/auth-helper/tycovar.go @@ -0,0 +1,52 @@ +package authhelper + +import ( + ero "simrs-vx/internal/domain/references/organization" +) + +type AuthKey struct{} + +type AuthInfo struct { + Uuid string + User_Id uint + User_Name string + // User_Email string + // User_Ref_Id int + User_Position_Code string +} + +func (a AuthInfo) IsDoctor() bool { + return a.User_Position_Code == string(ero.UPCDoc) +} + +func (a AuthInfo) IsNurse() bool { + return a.User_Position_Code == string(ero.UPCNur) +} + +func (a AuthInfo) IsNutritionist() bool { + return a.User_Position_Code == string(ero.UPCNut) +} + +func (a AuthInfo) IsLaborant() bool { + return a.User_Position_Code == string(ero.UPCLab) +} + +func (a AuthInfo) IsPharmacist() bool { + return a.User_Position_Code == string(ero.UPCPha) +} + +func (a AuthInfo) IsPayment() bool { + return a.User_Position_Code == string(ero.UPCPay) +} + +func (a AuthInfo) IsPaymentVerificator() bool { + return a.User_Position_Code == string(ero.UPCPav) +} + +func (a AuthInfo) IsManagement() bool { + return a.User_Position_Code == string(ero.UPCMan) +} + +func (a AuthInfo) IsSpecialistIntern() bool { + return a.User_Position_Code == string(ero.UPCInt) +}