diff --git a/cmd/main-migration/migrations/20251106050412.sql b/cmd/main-migration/migrations/20251106050412.sql new file mode 100644 index 00000000..11ef2a96 --- /dev/null +++ b/cmd/main-migration/migrations/20251106050412.sql @@ -0,0 +1,8 @@ +-- Modify "Prescription" table +ALTER TABLE "public"."Prescription" ADD COLUMN "Doctor_Code" character varying(20) NULL; +-- Modify "Doctor" table +ALTER TABLE "public"."Doctor" DROP CONSTRAINT "fk_Doctor_Specialist", DROP CONSTRAINT "fk_Doctor_Subspecialist", DROP CONSTRAINT "fk_Doctor_Unit", DROP COLUMN "Unit_Id", DROP COLUMN "Specialist_Id", DROP COLUMN "Subspecialist_Id", ADD CONSTRAINT "fk_Doctor_Specialist" FOREIGN KEY ("Specialist_Code") REFERENCES "public"."Specialist" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, ADD CONSTRAINT "fk_Doctor_Subspecialist" FOREIGN KEY ("Subspecialist_Code") REFERENCES "public"."Subspecialist" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, ADD CONSTRAINT "fk_Doctor_Unit" FOREIGN KEY ("Unit_Code") REFERENCES "public"."Unit" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION; +-- Modify "Nurse" table +ALTER TABLE "public"."Nurse" DROP CONSTRAINT "fk_Nurse_Infra", DROP CONSTRAINT "fk_Nurse_Unit", DROP COLUMN "Unit_Id", DROP COLUMN "Infra_Id", ADD CONSTRAINT "fk_Nurse_Infra" FOREIGN KEY ("Infra_Code") REFERENCES "public"."Infra" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, ADD CONSTRAINT "fk_Nurse_Unit" FOREIGN KEY ("Unit_Code") REFERENCES "public"."Unit" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION; +-- Modify "SpecialistIntern" table +ALTER TABLE "public"."SpecialistIntern" DROP CONSTRAINT "fk_SpecialistIntern_Specialist", DROP CONSTRAINT "fk_SpecialistIntern_Subspecialist", DROP COLUMN "Specialist_Id", DROP COLUMN "Subspecialist_Id", ADD CONSTRAINT "fk_SpecialistIntern_Specialist" FOREIGN KEY ("Specialist_Code") REFERENCES "public"."Specialist" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, ADD CONSTRAINT "fk_SpecialistIntern_Subspecialist" FOREIGN KEY ("Subspecialist_Code") REFERENCES "public"."Subspecialist" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION; diff --git a/cmd/main-migration/migrations/atlas.sum b/cmd/main-migration/migrations/atlas.sum index 90d23a8a..e8641831 100644 --- a/cmd/main-migration/migrations/atlas.sum +++ b/cmd/main-migration/migrations/atlas.sum @@ -1,8 +1,6 @@ h1:lDfnkzBVHYhHwd5okbIRgBk5zo9kmeAK9Ideg1SsSw4= -20250904105930.sql h1:Vv4vCurl7m7/ZB6TjRpkubHpQ4RYwSUn0QHdzfoGpzY= -20250904141448.sql h1:FYCHH9Os4KkrZMDu/jR8FMP+wLMRW+Mb0PkLU/9BRDg= -20250908062237.sql h1:oanBpKZd+akPu2I/xYhUSbd0G5tAFbXzKLER/Zs8ENI= -20250908062323.sql h1:miNG9COddXkD1jGTgaROMAZ618eT6oiLGiJhXWnQwhE= +20250904105930.sql h1:Vv4vCurl7m7/ZB6TjRpkubHpQ4RYwSUn0QHdzfoGpzY=20250904141448.sql h1:FYCHH9Os4KkrZMDu/jR8FMP+wLMRW+Mb0PkLU/9BRDg= +20250908062237.sql h1:oanBpKZd+akPu2I/xYhUSbd0G5tAFbXzKLER/Zs8ENI=20250908062323.sql h1:miNG9COddXkD1jGTgaROMAZ618eT6oiLGiJhXWnQwhE= 20250908073811.sql h1:gOi5cnGG1htlpfizybYmUIT0vYjZTBfXiI0nPSYK2u8= 20250908073839.sql h1:cWNDA4YikjoOteAJuNLFILjQUJPFB6o8Wxreiek4QyI= 20250910055902.sql h1:nxxOGnU0BbH/v3IPgeIOXOwH8d3tKomw7h6FTeMnnBs= @@ -66,12 +64,82 @@ h1:lDfnkzBVHYhHwd5okbIRgBk5zo9kmeAK9Ideg1SsSw4= 20251102091932.sql h1:A6y9j4wAqm4/HfMDxhpy/ChDn3UNRVN99KGgSCX+e18= 20251103081637.sql h1:RFqJNhJItSwJQaMP5IcQ14mL7eQ3EJjGZua9zLWzwMU= 20251104042334.sql h1:BbjLAwImggvI6489FQgD+S/AaafeiZut8k19TdH7XUE= -20251104043530.sql h1:Y0sOQqgnHxd5vKPA4+4fAGGdWCv6duKAYgHnjRJZUIc= -20251104080952.sql h1:hDHzFs/k+NhPYJ64ifbVp+nTJLMCG5MIMJU1zBMP0V0= -20251104084135.sql h1:p97mW1MPtPrMWJKy/KZqvymMO/vlelnXp43N9bZVCTI= -20251105044629.sql h1:E4BkVD3YyWvd0D18jA57EwTmkeoAMUWrdTCEwdPHA1U= -20251105121808.sql h1:kyMNzaJLyVtS1QpkX7cnVvhQmrrIE8m3GxUWwrMeyUo= -20251106035305.sql h1:VInVWBP1xpEhVIm1+ymuPzu0joxV2oS4qkNIyQvmTSU= -20251106040137.sql h1:7glRO1VAgq89H6zhM6M50iLwMT0w2sb96DUGrvfXZo4= -20251106041333.sql h1:/2wLmx8awSYhVpusDPAI+VeYJOLeLCWsNaF79gl1lg8= -20251106042006.sql h1:05AZyIbRJi1W08ETScADyAhI3elW0bXaWizlCpDfFCI= +20251104043530.sq +h1:97IUzyfSecffgKmYYs+a+HW5thHnIY3OuWDTQYy3hGQ= +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:5xwjAV6QbtZT9empTJKfhyAjdknbHzb15B0Ku5dzqtQ= +20250915123412.sql h1:D83xaU2YlDEd21HLup/YQpQ2easMToYCyy/oK6AFgQs= +20250916043819.sql h1:ekoTJsBqQZ8G8n0qJ03d13+eoNoc7sAUEQGA5D/CCxk= +20250917040616.sql h1:zoCnmcXuM7AVv85SmN7RmFglCgJnoDmpRWExH0LAc9Q= +20250917040751.sql h1:J1xyRrh32y1+lezwAyNwPcUQ6ABBSgbvzNLva4SVdQU= +20250917045138.sql h1:jKe1Z0uOLG4SGBYM+S/3P+/zMPztmgoderD5swnMuCg= +20250917093645.sql h1:cNI3Pbz1R3LxvIXLuexafJFCXUXrmuFCgXXJ2sG+FW0= +20250918073552.sql h1:RJ1SvMzP6aeWnoPVD3eVAmIQOkcp6Php8z3QRri6v4g= +20250918073742.sql h1:+cEsnJTJFybe2fR69ZoOiX2R6c6iITl4m6WTZ1hjyzY= +20250918074745.sql h1:2hNVQCXF/dVYXAh+T/7oBFgERGWxzVb2FXJjwkFWGCI= +20250923025134.sql h1:Ykz/qpHiGDXPsCsWTjydQFVSibZP2D+h2fIeb2h2JGA= +20250924051317.sql h1:yQuW6SwJxIOM5fcxeAaie5lSm1oLysU/C2hH2xNCVoQ= +20250929034321.sql h1:101FJ8VH12mrZWlt/X1gvKUGOhoiF8tFbjiapAjnHzg= +20250929034428.sql h1:i+pROD9p+g5dOmmZma6WF/0Hw5g3Ha28NN85iTo1K34= +20250930025550.sql h1:+F+CsCUXD/ql0tHGEow70GhPBX1ZybVn+bh/T4YMh7Y= +20250930140351.sql h1:9AAEG1AnOAH+o0+oHL5G7I8vqlWOhwRlCGyyCpT/y1Q= +20251002085604.sql h1:3xZ68eYp4urXRnvotNH1XvG2mYOSDV/j3zHEZ/txg5E= +20251003032030.sql h1:HB+mQ2lXMNomHDpaRhB/9IwYI9/YiDO5eOJ+nAQH/jw= +20251005060450.sql h1:LbtCE2b+8osM3CvnmQJH1uCPtn+d7WchsslBOz8bL3Q= +20251006041122.sql h1:MlS7f21z06sutnf9dIekt5fuHJr4lgcQ4uCuCXAGsfc= +20251006045658.sql h1:3FmGCPCzjgMPdWDRodZTsx3KVaodd9zB9ilib69aewk= +20251006045928.sql h1:Z5g31PmnzNwk/OKdODcxZGm8fjJQdMFK32Xfnt3bRHg= +20251007022859.sql h1:FO03zEfaNEk/aXwY81d5Lp3MoBB9kPQuXlXJ4BPiSR8= +20251008031337.sql h1:l+sxUAGvcTfj3I6kAFHo+T6AYodC9k9GkR+jaKO2xXc= +20251008031554.sql h1:AqrVfIhSzY3PCy8ZlP5W91wn2iznfIuj5qQfubp6/94= +20251008052346.sql h1:nxnXmooIJ6r1mmzwnw+6efxLfc/k9h2aE6RMptPRons= +20251008073620.sql h1:6YsJp1W4SmQJ1lxpqF27BBlDC1zqhw7Yhc7pLzQTY6M= +20251009042854.sql h1:nkBV+R6j0fg7/JY6wH3eb5Vv0asJLnXmb6lINfT/GLQ= +20251009052657.sql h1:EPvdsib5rzCGPryd10HShGKvFPwM/R5S2lIVwtYxpms= +20251010031743.sql h1:T8IZmx8/btRFKLzTe78MzcBsPJNodnLvB0tby9QkirQ= +20251010070721.sql h1:5NQUk/yOV6sABLCB7swx++YIOyJe6MnU+yt1nRzde5w= +20251010072711.sql h1:ZJNqR2piyu8xJhBvVABSlnGEoKSKae3wuEs+wshPe4k= +20251013044536.sql h1:0Xjw8fNILiT8nnfrJDZgQnPf3dntmIoilbapnih8AE4= +20251013051438.sql h1:lfSuw5mgJnePBJamvhZ81osFIouXeiIEiSZ/evdwo48= +20251013081808.sql h1:ijgjNX08G6GBjA/ks8EKtb7P7Y7Cg7zbhqEOruGnv6M= +20251014060047.sql h1:0jqj49WTtneEIMQDBoo4c095ZGi8sCrA8NnHBrPU6D8= +20251014063537.sql h1:VZLXol0PTsTW21Epg6vBPsztWkDtcxup9F/z88EGgIg= +20251014063720.sql h1:2HVUyCV0ud3BJJDH2GEKZN/+IWLFPCsN1KqhP6csO14= +20251015045455.sql h1:MeLWmMhAOAz8b15Dd7IAQnt6JxjSml02XCXK22C0Lpg= +20251016010845.sql h1:4BncQdDOasRZJkzVJrSJJA7091A9VPNVx/faUCUPhBM= +20251016011023.sql h1:9JB9eFZKURK5RoCVDKR6glSvdJ8NTXrN7K/4q51zkz4= +20251016062912.sql h1:ACNn0fe+EMqUt3hoY+Dr3uqAV/QICBa1+mIW7fUc9Fk= +20251017060617.sql h1:4T3t9ifWrEQTPMSM0XJ98pF7Qdt+UfgtMui17bhrnWI= +20251017082207.sql h1:8vLG1l/saRRMHXkyA4nelJyjaSddhZd6r7R+Uo4JS/c= +20251018032635.sql h1:2xey5gnO3y2XSOrU8MLlIfoylPKbRGDRtHDD07B3MbQ= +20251018040322.sql h1:k/pdNiSoT8zFPqNQ/avOD0vYkNh3BTD64IlHrfVXr7I= +20251019093915.sql h1:hFcQE0y+p5dZiVwePGsRGto9m/q6kJNiUZbVDd5Rnjk= +20251020062553.sql h1:Iw7hulcm5iRQlfW+ygA4iTPxLqkxx6h9vXMXEwUAHKs= +20251021041042.sql h1:wMgSivBV2A0NDcsLmKGIp0kMcVh2IODSG9b4dgzCaOM= +20251021075552.sql h1:8gfSMAglflNO6L0sSzxFNEubYN8/O4thT7OQT+WH+3M= +20251023044432.sql h1:MkvajJs3bfk9+wHvQ43/ccAluJEBARm1gWr1u92ccLA= +20251024034832.sql h1:x3s3VEVYLOSKLAFxJGb2+c1FyTMMvPE+9k4Ew7rKQaI= +20251024074315.sql h1:EjAjelgi5qAfcRq/8vPTlGGYHvAKxNTllm8f0SzZDns= +20251025013451.sql h1:6hnuIiwYiG+6nLhOY/+Yyn+I6ZCFNRZxrJNqBV6HLqE= +20251025013609.sql h1:evPJaTD8WxYRMOJZHkSr7ONLx9PYxT+ankzQt9c/sJ0= +20251027075128.sql h1:/iFQBM1sytjqpyQSOx61q33gnorMgxTiFVSuL6bQqsM= +20251027091406.sql h1:eCZGtUkxAzEAqpC9UsGpP8Df9mS0DEOqSl885LgqpvM= +20251102002037.sql h1:lFJbuoZ2LMQnUNGdcwHVY3Xlfslgzu9t2WByT8yfOZI= +20251102091932.sql h1:rmdhb5m+P+fU8jROBZNyeYgZKuQvucsuljXv4ZVzvks= +20251103081637.sql h1:tf3BcwTeIw+oxMEisKDDfyKnBfalTLs8b0PJA8JWYxY= +20251104042334.sql h1:7PDMWOhmJywolAPKFZ14XaDBeMvcxShaXFN2IemNtzk= +20251104043530.sql h1:qvYVp3ysPf27f1BcoRNCFGovxuVE12lg9d6Xzda6zWU= +20251104080952.sql h1:avghpv1n3yaCDR/TA0X+hgxDGoLBQGu/GJUwj4VT/Ic= +20251104084135.sql h1:rg+eRE5/5sYWR7z+Xyn0zKw8rr8P/oWxF0xhcNVnNec= +20251105044629.sql h1:4NU27HeKUNFsV82LacnwmnCSAH0pSbZR9J9/ZESRs6M= +20251105121808.sql h1:fii6LjqWYjrm/pEIqttfvJI6QEUL49gque8wYHh1+yI= +20251106035305.sql h1:oQ7BwnxPuwY2q98adIVc+lNwL/Sz1OceLJeClDo9/TI= +20251106040137.sql h1:ppcqkVoT0o9jZcjI/TN7LuaPxXhJQhnIXEJtloP/46o= +20251106041333.sql h1:2JkxyelQ/EeB+boL5bfpnzefw32ttEGKvKchtQjWmAU= +20251106042006.sql h1:ruppYa1kAJQUU3ufQBbKGMcXrGbGJJiRPclT+dNc/YQ= +20251106050412.sql h1:MiEMJ1HCFYnalKuq3Z38xJeogfBAMqsTv2sG4EF8dDw= diff --git a/internal/domain/main-entities/adm-employee-hist/dto.go b/internal/domain/main-entities/adm-employee-hist/dto.go index 9a5d838f..a3500060 100644 --- a/internal/domain/main-entities/adm-employee-hist/dto.go +++ b/internal/domain/main-entities/adm-employee-hist/dto.go @@ -28,9 +28,8 @@ type FilterDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` - Code *string `json:"code"` - Includes string `json:"includes"` + Id uint16 `json:"id"` + Includes string `json:"includes"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/ambulatory/dto.go b/internal/domain/main-entities/ambulatory/dto.go index 9b6bc314..f580467a 100644 --- a/internal/domain/main-entities/ambulatory/dto.go +++ b/internal/domain/main-entities/ambulatory/dto.go @@ -6,8 +6,9 @@ import ( ) type CreateDto struct { - Encounter_Id *uint `json:"encounter_id"` - Class_Code ere.AmbulatoryClassCode `json:"class_code" validate:"maxLength=10"` + Encounter_Id *uint `json:"encounter_id"` + Class_Code ere.AmbulatoryClassCode `json:"class_code" validate:"maxLength=10"` + VisitMode_Code ere.VisitModeCode `json:"visitMode_code"` } type ReadListDto struct { @@ -42,12 +43,17 @@ type MetaDto struct { type ResponseDto struct { ecore.Main - Encounter_Id *uint `json:"encounter_id"` - Class_Code ere.AmbulatoryClassCode `json:"class_code"` + Encounter_Id *uint `json:"encounter_id"` + Class_Code ere.AmbulatoryClassCode `json:"class_code"` + VisitMode_Code ere.VisitModeCode `json:"visitMode_code"` } func (d Ambulatory) ToResponse() ResponseDto { - resp := ResponseDto{} + resp := ResponseDto{ + Encounter_Id: d.Encounter_Id, + Class_Code: d.Class_Code, + VisitMode_Code: d.VisitMode_Code, + } resp.Main = d.Main return resp } diff --git a/internal/domain/main-entities/chemo-protocol/dto.go b/internal/domain/main-entities/chemo-protocol/dto.go new file mode 100644 index 00000000..04ea0023 --- /dev/null +++ b/internal/domain/main-entities/chemo-protocol/dto.go @@ -0,0 +1,91 @@ +package chemo_protocol + +import ( + // std + "time" + + // internal - domain - references + erc "simrs-vx/internal/domain/references/common" + + // internal - domain - main-entities + ecore "simrs-vx/internal/domain/base-entities/core" + ee "simrs-vx/internal/domain/main-entities/encounter" +) + +type CreateDto struct { + Encounter_Id *uint `json:"encounter_id"` + Patient_Weight *float32 `json:"patient_weight"` + Patient_Height *float32 `json:"patient_height"` + Diagnoses *string `json:"diagnoses"` + Duration *uint `json:"duration"` + DurationUnit_Code *erc.TimeUnitCode `json:"durationUnit_code"` + StartDate *time.Time `json:"startDate"` + EndDate *time.Time `json:"endDate"` +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Pagination ecore.Pagination +} + +type FilterDto struct { + Encounter_Id *uint `json:"encounter-id"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Includes string `json:"includes"` +} + +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"` + Patient_Weight *float32 `json:"patient_weight"` + Patient_Height *float32 `json:"patient_height"` + Diagnoses *string `json:"diagnoses"` + Duration *uint `json:"duration"` + DurationUnit_Code *erc.TimeUnitCode `json:"durationUnit_code"` + StartDate *time.Time `json:"startDate"` + EndDate *time.Time `json:"endDate"` +} + +func (d ChemoProtocol) ToResponse() ResponseDto { + resp := ResponseDto{ + Encounter_Id: d.Encounter_Id, + Encounter: d.Encounter, + Patient_Weight: d.Patient_Weight, + Patient_Height: d.Patient_Height, + Diagnoses: d.Diagnoses, + Duration: d.Duration, + DurationUnit_Code: d.DurationUnit_Code, + StartDate: d.StartDate, + EndDate: d.EndDate, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []ChemoProtocol) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/chemo/dto.go b/internal/domain/main-entities/chemo/dto.go index 8317b259..653b5409 100644 --- a/internal/domain/main-entities/chemo/dto.go +++ b/internal/domain/main-entities/chemo/dto.go @@ -52,6 +52,8 @@ type DeleteDto struct { type VerifyDto struct { Id uint16 `json:"id"` Status_Code erc.DataVerifiedCode `json:"status_code"` + Bed *string `json:"bed" validate:"required"` + Needs *string `json:"needs" validate:"required"` pa.AuthInfo } diff --git a/internal/domain/main-entities/control-letter/dto.go b/internal/domain/main-entities/control-letter/dto.go index 270ff7b5..c2bab776 100644 --- a/internal/domain/main-entities/control-letter/dto.go +++ b/internal/domain/main-entities/control-letter/dto.go @@ -12,6 +12,7 @@ import ( // internal - domain - main-entities + ed "simrs-vx/internal/domain/main-entities/doctor" ee "simrs-vx/internal/domain/main-entities/encounter" es "simrs-vx/internal/domain/main-entities/specialist" ess "simrs-vx/internal/domain/main-entities/subspecialist" @@ -23,6 +24,7 @@ type CreateDto struct { Unit_Id *uint `json:"unit_id"` Specialist_Id *uint `json:"specialist_id"` Subspecialist_Id *uint `json:"subspecialist_id"` + Doctor_Id *uint `json:"doctor_id"` Date *time.Time `json:"date"` } @@ -37,11 +39,13 @@ type FilterDto struct { Unit_Id *uint `json:"unit-id"` Specialist_Id *uint `json:"specialist-id"` Subspecialist_Id *uint `json:"subspecialist-id"` + Doctor_Id *uint `json:"doctor-id"` Date *time.Time `json:"date"` } type ReadDetailDto struct { - Id uint16 `json:"id"` + Id uint16 `json:"id"` + Includes string `json:"includes"` } type UpdateDto struct { @@ -69,13 +73,15 @@ type MetaDto struct { type ResponseDto struct { ecore.Main Encounter_Id *uint `json:"encounter_id"` - Encounter *ee.Encounter `json:"encounter" gorm:"foreignKey:Encounter_Id;references:Id"` + Encounter *ee.Encounter `json:"encounter,omitempty"` Unit_Id *uint `json:"unit_id"` - Unit *eu.Unit `json:"unit" gorm:"foreignKey:Unit_Id;references:Id"` + Unit *eu.Unit `json:"unit,omitempty"` Specialist_Id *uint `json:"specialist_id"` - Specialist *es.Specialist `json:"specialist" gorm:"foreignKey:Specialist_Id;references:Id"` + Specialist *es.Specialist `json:"specialist,omitempty"` Subspecialist_Id *uint `json:"subspecialist_id"` - Subspecialist *ess.Subspecialist `json:"subspecialist" gorm:"foreignKey:Subspecialist_Id;references:Id"` + Subspecialist *ess.Subspecialist `json:"subspecialist,omitempty"` + Doctor_Id *uint `json:"doctor_id"` + Doctor *ed.Doctor `json:"doctor,omitempty"` Date *time.Time `json:"date"` } @@ -89,6 +95,8 @@ func (d ControlLetter) ToResponse() ResponseDto { Specialist: d.Specialist, Subspecialist_Id: d.Subspecialist_Id, Subspecialist: d.Subspecialist, + Doctor_Id: d.Doctor_Id, + Doctor: d.Doctor, Date: d.Date, } resp.Main = d.Main diff --git a/internal/domain/main-entities/doctor/dto.go b/internal/domain/main-entities/doctor/dto.go index 0abcd99b..67290551 100644 --- a/internal/domain/main-entities/doctor/dto.go +++ b/internal/domain/main-entities/doctor/dto.go @@ -6,16 +6,18 @@ import ( es "simrs-vx/internal/domain/main-entities/specialist" ess "simrs-vx/internal/domain/main-entities/subspecialist" eu "simrs-vx/internal/domain/main-entities/unit" + "time" ) type CreateDto struct { - Code *string `json:"code" validate:"maxLength=20"` - Employee_Id *uint `json:"employee_id"` - IHS_Number *string `json:"ihs_number"` - SIP_Number *string `json:"sip_number"` - Unit_Id *uint16 `json:"unit_id"` - Specialist_Id *uint16 `json:"specialist_id"` - Subspecialist_Id *uint16 `json:"subspecialist_id"` + Code *string `json:"code" validate:"maxLength=20"` + Employee_Id *uint `json:"employee_id"` + IHS_Number *string `json:"ihs_number"` + SIP_Number *string `json:"sip_number"` + SIP_ExpiredDate *time.Time `json:"sip_expiredDate"` + Unit_Code *string `json:"unit_code"` + Specialist_Code *string `json:"specialist_code"` + Subspecialist_Code *string `json:"subspecialist_code"` } type ReadListDto struct { @@ -25,13 +27,14 @@ type ReadListDto struct { } type FilterDto struct { - Code *string `json:"code"` - Employee_Id *uint `json:"employee-id"` - IHS_Number *string `json:"ihs-number" validate:"maxLength=20"` - SIP_Number *string `json:"sip-number" validate:"maxLength=20"` - Unit_Id *uint `json:"unit-id"` - Specialist_Id *uint16 `json:"specialist-id"` - Subspecialist_Id *uint16 `json:"subspecialist-id"` + Code *string `json:"code"` + Employee_Id *uint `json:"employee-id"` + IHS_Number *string `json:"ihs-number" validate:"maxLength=20"` + SIP_Number *string `json:"sip-number" validate:"maxLength=20"` + SIP_ExpiredDate *string `json:"sip-expiredDate"` + Unit_Code *string `json:"unit-code"` + Specialist_Code *string `json:"specialist-code"` + Subspecialist_Code *string `json:"subspecialist-code"` } type ReadDetailDto struct { @@ -59,32 +62,32 @@ type MetaDto struct { type ResponseDto struct { ecore.Main - Code *string `json:"code"` - Employee_Id *uint `json:"employee_id"` - Employee *ee.Employee `json:"employee,omitempty"` - IHS_Number *string `json:"ihs_number"` - SIP_Number *string `json:"sip_number"` - Unit_Id *uint16 `json:"unit_id"` - Unit *eu.Unit `json:"unit,omitempty"` - Specialist_Id *uint16 `json:"specialist_id"` - Specialist *es.Specialist `json:"specialist,omitempty" ` - Subspecialist_Id *uint16 `json:"subspecialist_id"` - Subspecialist *ess.Subspecialist `json:"subspecialist,omitempty"` + Code *string `json:"code"` + Employee_Id *uint `json:"employee_id"` + Employee *ee.Employee `json:"employee,omitempty"` + IHS_Number *string `json:"ihs_number"` + SIP_Number *string `json:"sip_number"` + Unit_Code *string `json:"unit_code"` + Unit *eu.Unit `json:"unit,omitempty"` + Specialist_Code *string `json:"specialist_code"` + Specialist *es.Specialist `json:"specialist,omitempty" ` + Subspecialist_Code *string `json:"subspecialist_code"` + Subspecialist *ess.Subspecialist `json:"subspecialist,omitempty"` } func (d Doctor) ToResponse() ResponseDto { resp := ResponseDto{ - Code: d.Code, - Employee_Id: d.Employee_Id, - Employee: d.Employee, - IHS_Number: d.IHS_Number, - SIP_Number: d.SIP_Number, - Unit_Id: d.Unit_Id, - Unit: d.Unit, - Specialist_Id: d.Specialist_Id, - Specialist: d.Specialist, - Subspecialist_Id: d.Subspecialist_Id, - Subspecialist: d.Subspecialist, + Code: d.Code, + Employee_Id: d.Employee_Id, + Employee: d.Employee, + IHS_Number: d.IHS_Number, + SIP_Number: d.SIP_Number, + Unit_Code: d.Unit_Code, + Unit: d.Unit, + Specialist_Code: d.Specialist_Code, + Specialist: d.Specialist, + Subspecialist_Code: d.Subspecialist_Code, + Subspecialist: d.Subspecialist, } resp.Main = d.Main return resp diff --git a/internal/domain/main-entities/doctor/entity.go b/internal/domain/main-entities/doctor/entity.go index 014c6c17..506271a2 100644 --- a/internal/domain/main-entities/doctor/entity.go +++ b/internal/domain/main-entities/doctor/entity.go @@ -10,21 +10,17 @@ import ( ) type Doctor struct { - ecore.Main // adjust this according to the needs - Code *string `json:"code" gorm:"unique;size:20"` - Employee_Id *uint `json:"employee_id"` - Employee *ee.Employee `json:"employee,omitempty" gorm:"foreignKey:Employee_Id;references:Id"` - IHS_Number *string `json:"ihs_number" gorm:"unique;size:20"` - SIP_Number *string `json:"sip_number" gorm:"unique;size:20"` - SIP_ExpiredDate *time.Time `json:"sip_expiredDate"` - Unit_Id *uint16 `json:"unit_id"` - Unit_Code *string `json:"unit_code" gorm:"size:10"` - Unit *eu.Unit `json:"unit,omitempty" gorm:"foreignKey:Unit_Id;references:Id"` - // Unit *eu.Unit `json:"unit,omitempty" gorm:"foreignKey:Unit_Code;references:Code"` - Specialist_Id *uint16 `json:"specialist_id"` + ecore.Main // adjust this according to the needs + Code *string `json:"code" gorm:"unique;size:20"` + Employee_Id *uint `json:"employee_id"` + Employee *ee.Employee `json:"employee,omitempty" gorm:"foreignKey:Employee_Id;references:Id"` + IHS_Number *string `json:"ihs_number" gorm:"unique;size:20"` + SIP_Number *string `json:"sip_number" gorm:"unique;size:20"` + SIP_ExpiredDate *time.Time `json:"sip_expiredDate"` + Unit_Code *string `json:"unit_code" gorm:"size:10"` + Unit *eu.Unit `json:"unit,omitempty" gorm:"foreignKey:Unit_Code;references:Code"` Specialist_Code *string `json:"specialist_code" gorm:"size:10"` - Specialist *es.Specialist `json:"specialist,omitempty" gorm:"foreignKey:Specialist_Id"` - Subspecialist_Id *uint16 `json:"subspecialist_id"` + Specialist *es.Specialist `json:"specialist,omitempty" gorm:"foreignKey:Specialist_Code;references:Code"` Subspecialist_Code *string `json:"subspecialist_code" gorm:"size:10"` - Subspecialist *ess.Subspecialist `json:"subspecialist,omitempty" gorm:"foreignKey:Subspecialist_Id"` + Subspecialist *ess.Subspecialist `json:"subspecialist,omitempty" gorm:"foreignKey:Subspecialist_Code;references:Code"` } diff --git a/internal/domain/main-entities/encounter/dto.go b/internal/domain/main-entities/encounter/dto.go index 89f12caf..6782b18c 100644 --- a/internal/domain/main-entities/encounter/dto.go +++ b/internal/domain/main-entities/encounter/dto.go @@ -48,6 +48,8 @@ type CreateDto struct { Appointment_Id *uint `json:"appointment_id"` RefTypeCode ere.RefTypeCode `json:"refTypeCode"` NewStatus bool `json:"newStatus"` + VisitMode_Code *ere.VisitModeCode `json:"visitMode_code"` // if subClass_Code is rehab + AllocatedVisitCount *int `json:"allocatedVisitCount"` // if subClass_Code is rehab and VisitMode_Code is "adm" pa.AuthInfo } diff --git a/internal/domain/main-entities/nurse/dto.go b/internal/domain/main-entities/nurse/dto.go index 7b7b283c..f48014dd 100644 --- a/internal/domain/main-entities/nurse/dto.go +++ b/internal/domain/main-entities/nurse/dto.go @@ -11,8 +11,8 @@ type CreateDto struct { Code *string `json:"code" validate:"maxLength=20"` Employee_Id *uint `json:"employee_id"` IHS_Number *string `json:"ihs_number" validate:"maxLength=20"` - Unit_Id *uint16 `json:"unit_id"` - Infra_Id *uint16 `json:"infra_id"` + Unit_Code *string `json:"unit_code"` + Infra_Code *string `json:"infra_code"` } type ReadListDto struct { @@ -25,8 +25,8 @@ type FilterDto struct { Code *string `json:"code"` Employee_Id *uint `json:"employee-id"` IHS_Number *string `json:"ihs-number"` - Unit_Id *uint16 `json:"unit-id"` - Infra_Id *uint16 `json:"infra-id"` + Unit_Code *string `json:"unit-code"` + Infra_Code *string `json:"infra-code"` } type ReadDetailDto struct { Id uint16 `json:"id"` @@ -56,9 +56,9 @@ type ResponseDto struct { Employee_Id *uint `json:"employee_id"` Employee *ee.Employee `json:"employee,omitempty"` IHS_Number *string `json:"ihs_number"` - Unit_Id *uint16 `json:"unit_id"` + Unit_Code *string `json:"unit_code"` Unit *eu.Unit `json:"unit,omitempty"` - Infra_Id *uint16 `json:"infra_id"` + Infra_Code *string `json:"infra_code"` Infra *ei.Infra `json:"infra,omitempty"` } @@ -68,9 +68,9 @@ func (d Nurse) ToResponse() ResponseDto { Employee_Id: d.Employee_Id, Employee: d.Employee, IHS_Number: d.IHS_Number, - Unit_Id: d.Unit_Id, + Unit_Code: d.Unit_Code, Unit: d.Unit, - Infra_Id: d.Infra_Id, + Infra_Code: d.Infra_Code, Infra: d.Infra, } resp.Main = d.Main diff --git a/internal/domain/main-entities/nurse/entity.go b/internal/domain/main-entities/nurse/entity.go index 54f06fd1..cb1df0a8 100644 --- a/internal/domain/main-entities/nurse/entity.go +++ b/internal/domain/main-entities/nurse/entity.go @@ -13,10 +13,8 @@ type Nurse struct { Employee_Id *uint `json:"employee_id"` Employee *ee.Employee `json:"employee,omitempty" gorm:"foreignKey:Employee_Id;references:Id"` IHS_Number *string `json:"ihs_number" gorm:"unique;size:20"` - Unit_Id *uint16 `json:"unit_id"` Unit_Code *string `json:"unit_code" gorm:"size:10"` - Unit *eu.Unit `json:"unit,omitempty" gorm:"foreignKey:Unit_Id;references:Id"` - Infra_Id *uint16 `json:"infra_id"` + Unit *eu.Unit `json:"unit,omitempty" gorm:"foreignKey:Unit_Code;references:Code"` Infra_Code *string `json:"infra_code" gorm:"size:10"` - Infra *ei.Infra `json:"infra,omitempty" gorm:"foreignKey:Infra_Id;references:Id"` + Infra *ei.Infra `json:"infra,omitempty" gorm:"foreignKey:Infra_Code;references:Code"` } diff --git a/internal/domain/main-entities/prescription/entity.go b/internal/domain/main-entities/prescription/entity.go index bdc2d2fb..c32c9d9e 100644 --- a/internal/domain/main-entities/prescription/entity.go +++ b/internal/domain/main-entities/prescription/entity.go @@ -15,6 +15,7 @@ type Prescription struct { Encounter_Id *uint `json:"encounter_id"` Encounter *ee.Encounter `json:"encounter,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"` Doctor_Id *uint `json:"doctor_id"` + Doctor_Code *string `json:"doctor_code" gorm:"size:20"` Doctor *ed.Doctor `json:"doctor,omitempty" gorm:"foreignKey:Doctor_Id;references:Id"` IssuedAt *time.Time `json:"issuedAt"` Status_Code erc.DataStatusCode `json:"status_code"` diff --git a/internal/domain/main-entities/rehab/dto.go b/internal/domain/main-entities/rehab/dto.go new file mode 100644 index 00000000..0cec61d8 --- /dev/null +++ b/internal/domain/main-entities/rehab/dto.go @@ -0,0 +1,70 @@ +package rehab + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ed "simrs-vx/internal/domain/main-entities/doctor" +) + +type CreateDto struct { + Encounter_Id *uint `json:"encounter_id"` + Doctor_Id *uint `json:"doctor_id"` + AllocatedVisitCount *int `json:"allocatedVisitCount"` +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Pagination ecore.Pagination +} + +type FilterDto struct { + Encounter_Id *uint `json:"encounter-id"` + Doctor_Id *uint `json:"doctor-id"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Includes string `json:"includes"` +} + +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"` + Doctor_Id *uint `json:"doctor_id"` + Doctor *ed.Doctor `json:"doctor,omitempty"` + AllocatedVisitCount *int `json:"allocatedVisitCount"` +} + +func (d Rehab) ToResponse() ResponseDto { + resp := ResponseDto{ + Encounter_Id: d.Encounter_Id, + Doctor_Id: d.Doctor_Id, + Doctor: d.Doctor, + AllocatedVisitCount: d.AllocatedVisitCount, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []Rehab) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/responsible-doctor-hist/dto.go b/internal/domain/main-entities/responsible-doctor-hist/dto.go index 342faffa..68c8dd21 100644 --- a/internal/domain/main-entities/responsible-doctor-hist/dto.go +++ b/internal/domain/main-entities/responsible-doctor-hist/dto.go @@ -28,9 +28,8 @@ type FilterDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` - Code *string `json:"code"` - Includes string `json:"includes"` + Id uint16 `json:"id"` + Includes string `json:"includes"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/specialist-intern/dto.go b/internal/domain/main-entities/specialist-intern/dto.go index 2d01c861..bf87b00e 100644 --- a/internal/domain/main-entities/specialist-intern/dto.go +++ b/internal/domain/main-entities/specialist-intern/dto.go @@ -9,10 +9,10 @@ import ( ) type CreateDto struct { - Person_Id *uint `json:"person_id"` - Specialist_Id *uint16 `json:"specialist_id"` - Subspecialist_Id *uint16 `json:"subspecialist_id"` - User_Id *uint `json:"user_id"` + Person_Id *uint `json:"person_id"` + Specialist_Code *string `json:"specialist_code"` + Subspecialist_Code *string `json:"subspecialist_code"` + User_Id *uint `json:"user_id"` } type ReadListDto struct { @@ -22,10 +22,10 @@ type ReadListDto struct { } type FilterDto struct { - Person_Id *uint `json:"person-id"` - Specialist_Id *uint16 `json:"specialist-id"` - Subspecialist_Id *uint16 `json:"subspecialist-id"` - User_Id *uint `json:"user-id"` + Person_Id *uint `json:"person-id"` + Specialist_Code *string `json:"specialist-code"` + Subspecialist_Code *string `json:"subspecialist-code"` + User_Id *uint `json:"user-id"` } type ReadDetailDto struct { @@ -50,26 +50,26 @@ type MetaDto struct { type ResponseDto struct { ecore.Main - Person_Id *uint `json:"person_id"` - Person *ep.Person `json:"person,omitempty"` - Specialist_Id *uint16 `json:"specialist_id"` - Specialist *es.Specialist `json:"specialist,omitempty"` - Subspecialist_Id *uint16 `json:"subspecialist_id"` - Subspecialist *ess.Subspecialist `json:"subspecialist,omitempty"` - User_Id *uint `json:"user_id"` - User *eu.User `json:"user,omitempty"` + Person_Id *uint `json:"person_id"` + Person *ep.Person `json:"person,omitempty"` + Specialist_Code *string `json:"specialist_code"` + Specialist *es.Specialist `json:"specialist,omitempty"` + Subspecialist_Code *string `json:"subspecialist_code"` + Subspecialist *ess.Subspecialist `json:"subspecialist,omitempty"` + User_Id *uint `json:"user_id"` + User *eu.User `json:"user,omitempty"` } func (d SpecialistIntern) ToResponse() ResponseDto { resp := ResponseDto{ - Person_Id: d.Person_Id, - Person: d.Person, - Specialist_Id: d.Specialist_Id, - Specialist: d.Specialist, - Subspecialist_Id: d.Subspecialist_Id, - Subspecialist: d.Subspecialist, - User_Id: d.User_Id, - User: d.User, + Person_Id: d.Person_Id, + Person: d.Person, + Specialist_Code: d.Specialist_Code, + Specialist: d.Specialist, + Subspecialist_Code: d.Subspecialist_Code, + Subspecialist: d.Subspecialist, + User_Id: d.User_Id, + User: d.User, } resp.Main = d.Main return resp diff --git a/internal/domain/main-entities/specialist-intern/entity.go b/internal/domain/main-entities/specialist-intern/entity.go index 482c9b5a..5d87e1a7 100644 --- a/internal/domain/main-entities/specialist-intern/entity.go +++ b/internal/domain/main-entities/specialist-intern/entity.go @@ -12,12 +12,10 @@ type SpecialistIntern struct { ecore.Main // adjust this according to the needs Person_Id *uint `json:"person_id"` Person *ep.Person `json:"person,omitempty" gorm:"foreignKey:Person_Id"` - Specialist_Id *uint16 `json:"specialist_id"` Specialist_Code *string `json:"specialist_code" gorm:"size:10"` - Specialist *es.Specialist `json:"specialist,omitempty" gorm:"foreignKey:Specialist_Id"` - Subspecialist_Id *uint16 `json:"subspecialist_id"` + Specialist *es.Specialist `json:"specialist,omitempty" gorm:"foreignKey:Specialist_Code;references:Code"` Subspecialist_Code *string `json:"subspecialist_code" gorm:"size:10"` - Subspecialist *ess.Subspecialist `json:"subspecialist,omitempty" gorm:"foreignKey:Subspecialist_Id"` + Subspecialist *ess.Subspecialist `json:"subspecialist,omitempty" gorm:"foreignKey:Subspecialist_Code;references:Code"` User_Id *uint `json:"user_id"` User *eu.User `json:"user,omitempty" gorm:"foreignKey:User_Id"` } diff --git a/internal/domain/main-entities/therapy-protocol/dto.go b/internal/domain/main-entities/therapy-protocol/dto.go new file mode 100644 index 00000000..f7a5f2e4 --- /dev/null +++ b/internal/domain/main-entities/therapy-protocol/dto.go @@ -0,0 +1,107 @@ +package therapy_protocol + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ed "simrs-vx/internal/domain/main-entities/doctor" + ee "simrs-vx/internal/domain/main-entities/encounter" + "simrs-vx/internal/domain/references/common" +) + +type CreateDto struct { + Encounter_Id *uint `json:"encounter_id"` + Doctor_Id *uint `json:"doctor_id"` + Anamnesis *string `json:"anamnesis" validate:"maxLength=2048"` + MedicalDiagnoses *string `json:"medicalDiagnoses"` + FunctionDiagnoses *string `json:"functionDiagnoses"` + Procedures *string `json:"procedures"` + SupportingExams *string `json:"supportingExams" validate:"maxLength=2048"` + Instruction *string `json:"instruction" validate:"maxLength=2048"` + Evaluation *string `json:"evaluation" validate:"maxLength=2048"` + WorkCauseStatus *string `json:"workCauseStatus"` + Frequency *uint `json:"frequency"` + IntervalUnit_Code *common.TimeUnitCode `json:"intervalUnit_code" validate:"maxLength=10"` + Duration *uint `json:"duration"` + DurationUnit_Code *common.TimeUnitCode `json:"durationUnit_code" validate:"maxLength=10"` +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Pagination ecore.Pagination +} + +type FilterDto struct { + Encounter_Id *uint `json:"encounter-id"` + Doctor_Id *uint `json:"doctor-id"` +} + +type ReadDetailDto struct { + Id uint `json:"id"` + Includes string `json:"includes"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `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"` + Doctor_Id *uint `json:"doctor_id"` + Doctor *ed.Doctor `json:"doctor,omitempty"` + Anamnesis *string `json:"anamnesis"` + MedicalDiagnoses *string `json:"medicalDiagnoses"` + FunctionDiagnoses *string `json:"functionDiagnoses"` + Procedures *string `json:"procedures"` + SupportingExams *string `json:"supportingExams"` + Instruction *string `json:"instruction"` + Evaluation *string `json:"evaluation"` + WorkCauseStatus *string `json:"workCauseStatus"` + Frequency *uint `json:"frequency"` + IntervalUnit_Code *common.TimeUnitCode `json:"intervalUnit_code"` + Duration *uint `json:"duration"` + DurationUnit_Code *common.TimeUnitCode `json:"durationUnit_code"` +} + +func (d TherapyProtocol) ToResponse() ResponseDto { + resp := ResponseDto{ + Encounter_Id: d.Encounter_Id, + Encounter: d.Encounter, + Doctor_Id: d.Doctor_Id, + Doctor: d.Doctor, + Anamnesis: d.Anamnesis, + MedicalDiagnoses: d.MedicalDiagnoses, + FunctionDiagnoses: d.FunctionDiagnoses, + Procedures: d.Procedures, + SupportingExams: d.SupportingExams, + Instruction: d.Instruction, + Evaluation: d.Evaluation, + WorkCauseStatus: d.WorkCauseStatus, + Frequency: d.Frequency, + IntervalUnit_Code: d.IntervalUnit_Code, + Duration: d.Duration, + DurationUnit_Code: d.DurationUnit_Code, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []TherapyProtocol) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/user/dto.go b/internal/domain/main-entities/user/dto.go index c3a84737..fd4b3f2c 100644 --- a/internal/domain/main-entities/user/dto.go +++ b/internal/domain/main-entities/user/dto.go @@ -24,10 +24,10 @@ type CreateDto struct { Employee *EmployeUpdateDto `json:"employee"` IHS_Number *string `json:"ihs_number" validate:"maxLength=20"` SIP_Number *string `json:"sip_number" validate:"maxLength=20"` - Unit_Id *uint16 `json:"unit_id"` - Infra_Id *uint16 `json:"infra_id"` - Specialist_Id *uint16 `json:"specialist_id"` - Subspecialist_Id *uint16 `json:"subspecialist_id"` + Unit_Code *string `json:"unit_code"` + Infra_Code *string `json:"infra_code"` + Specialist_Code *string `json:"specialist_code"` + Subspecialist_Code *string `json:"subspecialist_code"` ContractPosition_Code erg.ContractPositionCode `json:"contractPosition_code" gorm:"not null;size:20"` } diff --git a/internal/interface/main-handler/chemo-protocol/handler.go b/internal/interface/main-handler/chemo-protocol/handler.go new file mode 100644 index 00000000..60d9db4d --- /dev/null +++ b/internal/interface/main-handler/chemo-protocol/handler.go @@ -0,0 +1,72 @@ +package chemo_protocol + +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/chemo-protocol" + u "simrs-vx/internal/use-case/main-use-case/chemo-protocol" +) + +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{} + sf.UrlQueryParam(&dto, *r.URL) + + 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/chemo/handler.go b/internal/interface/main-handler/chemo/handler.go index 90552020..18435479 100644 --- a/internal/interface/main-handler/chemo/handler.go +++ b/internal/interface/main-handler/chemo/handler.go @@ -84,11 +84,16 @@ func (obj myBase) Verify(w http.ResponseWriter, r *http.Request) { } dto := e.VerifyDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint16(id) authInfo, err := pa.GetAuthInfo(r) if err != nil { rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) } + dto.AuthInfo = *authInfo dto.Status_Code = erc.DVCVerified res, err := u.Verify(dto) diff --git a/internal/interface/main-handler/consultation/handler.go b/internal/interface/main-handler/consultation/handler.go index 2810d2f3..e67accd4 100644 --- a/internal/interface/main-handler/consultation/handler.go +++ b/internal/interface/main-handler/consultation/handler.go @@ -1,4 +1,4 @@ -package device +package consultation import ( "net/http" diff --git a/internal/interface/main-handler/control-letter/handler.go b/internal/interface/main-handler/control-letter/handler.go new file mode 100644 index 00000000..b0714b25 --- /dev/null +++ b/internal/interface/main-handler/control-letter/handler.go @@ -0,0 +1,72 @@ +package controlletter + +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/control-letter" + u "simrs-vx/internal/use-case/main-use-case/control-letter" +) + +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{} + sf.UrlQueryParam(&dto, *r.URL) + 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 = uint(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 = uint(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/doctor/handler.go b/internal/interface/main-handler/doctor/handler.go index 27281884..ee1252ad 100644 --- a/internal/interface/main-handler/doctor/handler.go +++ b/internal/interface/main-handler/doctor/handler.go @@ -33,7 +33,7 @@ func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { } func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { - id := rw.ValidateInt(w, "id", r.PathValue("id")) + id := rw.ValidateInt(w, "code", r.PathValue("code")) if id <= 0 { return } @@ -44,7 +44,7 @@ func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { } func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { - id := rw.ValidateInt(w, "id", r.PathValue("id")) + id := rw.ValidateInt(w, "code", r.PathValue("code")) if id <= 0 { return } @@ -59,7 +59,7 @@ func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { } func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { - id := rw.ValidateInt(w, "id", r.PathValue("id")) + id := rw.ValidateInt(w, "code", r.PathValue("code")) if id <= 0 { return } diff --git a/internal/interface/main-handler/encounter/handler.go b/internal/interface/main-handler/encounter/handler.go index ed8b1fbc..b66abe76 100644 --- a/internal/interface/main-handler/encounter/handler.go +++ b/internal/interface/main-handler/encounter/handler.go @@ -26,10 +26,15 @@ func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { 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 } + if valid := validateRequestCreate(w, dto); !valid { + return + } + dto.AuthInfo = *authInfo res, err := u.Create(dto) rw.DataResponse(w, res, err) diff --git a/internal/interface/main-handler/encounter/request-validation.go b/internal/interface/main-handler/encounter/request-validation.go index 025298fc..b7d31e71 100644 --- a/internal/interface/main-handler/encounter/request-validation.go +++ b/internal/interface/main-handler/encounter/request-validation.go @@ -63,3 +63,21 @@ func validateRequestCheckIn(w http.ResponseWriter, i e.CheckinDto) (valid bool) return true } + +func validateRequestCreate(w http.ResponseWriter, i e.CreateDto) (valid bool) { + switch { + case i.Class_Code == ere.ECAmbulatory: + // field allocatedVisitCount required if ambulatory visitMode_Code is adm + if ere.AmbulatoryClassCode(*i.SubClass_Code) == ere.ACCRehab && *i.VisitMode_Code == ere.VMCAdm { + if *i.AllocatedVisitCount == 0 { + rw.DataResponse(w, nil, d.FieldError{ + Code: dataValidationFail, + Message: "allocatedVisitCount required", + }) + return + } + } + } + + return true +} diff --git a/internal/interface/main-handler/main-handler.go b/internal/interface/main-handler/main-handler.go index bedf3b71..0a6a917a 100644 --- a/internal/interface/main-handler/main-handler.go +++ b/internal/interface/main-handler/main-handler.go @@ -9,7 +9,9 @@ import ( ambulancetransportrequest "simrs-vx/internal/interface/main-handler/ambulance-transport-req" auth "simrs-vx/internal/interface/main-handler/authentication" chemo "simrs-vx/internal/interface/main-handler/chemo" + chemoprotocol "simrs-vx/internal/interface/main-handler/chemo-protocol" consultation "simrs-vx/internal/interface/main-handler/consultation" + controlletter "simrs-vx/internal/interface/main-handler/control-letter" counter "simrs-vx/internal/interface/main-handler/counter" deviceorder "simrs-vx/internal/interface/main-handler/device-order" deviceorderitem "simrs-vx/internal/interface/main-handler/device-order-item" @@ -33,9 +35,8 @@ import ( soapi "simrs-vx/internal/interface/main-handler/soapi" /******************** actor ********************/ - doctor "simrs-vx/internal/interface/main-handler/doctor" + employee "simrs-vx/internal/interface/main-handler/employee" - nurse "simrs-vx/internal/interface/main-handler/nurse" nutritionist "simrs-vx/internal/interface/main-handler/nutritionist" patient "simrs-vx/internal/interface/main-handler/patient" person "simrs-vx/internal/interface/main-handler/person" @@ -93,6 +94,7 @@ import ( specialistposition "simrs-vx/internal/interface/main-handler/specialist-position" subspecialist "simrs-vx/internal/interface/main-handler/subspecialist" subspecialistposition "simrs-vx/internal/interface/main-handler/subspecialist-position" + therapyprotocol "simrs-vx/internal/interface/main-handler/therapy-protocol" unit "simrs-vx/internal/interface/main-handler/unit" unitposition "simrs-vx/internal/interface/main-handler/unit-position" uom "simrs-vx/internal/interface/main-handler/uom" @@ -251,10 +253,13 @@ func SetRoutes() http.Handler { "PATCH /{id}/reject": chemo.O.Reject, }) + hc.RegCrud(r, "/v1/control-letter", controlletter.O) hc.RegCrud(r, "/v1/internal-reference", internalreference.O) hc.RegCrud(r, "/v1/ambulance-transport-req", ambulancetransportrequest.O) hc.RegCrud(r, "/v1/responsible-doctor-hist", responsibledoctorhist.O) hc.RegCrud(r, "/v1/adm-employee-hist", admemployeehist.O) + hc.RegCrud(r, "/v1/therapy-protocol", therapyprotocol.O) + hc.RegCrud(r, "/v1/chemo-protocol", chemoprotocol.O) /******************** actor ********************/ hc.RegCrud(r, "/v1/person", person.O) @@ -262,8 +267,6 @@ func SetRoutes() http.Handler { hc.RegCrud(r, "/v1/person-contact", personcontact.O) hc.RegCrud(r, "/v1/person-insurance", personinsurance.O) hc.RegCrud(r, "/v1/employee", employee.O) - hc.RegCrud(r, "/v1/doctor", doctor.O) - hc.RegCrud(r, "/v1/nurse", nurse.O) hc.RegCrud(r, "/v1/nutritionist", nutritionist.O) hc.RegCrud(r, "/v1/pharmacist", pharmacist.O) hk.GroupRoutes("/v1/user", r, hk.MapHandlerFunc{ diff --git a/internal/interface/main-handler/nurse/handler.go b/internal/interface/main-handler/nurse/handler.go index 6df7a18e..8817ae14 100644 --- a/internal/interface/main-handler/nurse/handler.go +++ b/internal/interface/main-handler/nurse/handler.go @@ -33,7 +33,7 @@ func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { } func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { - id := rw.ValidateInt(w, "id", r.PathValue("id")) + id := rw.ValidateInt(w, "code", r.PathValue("code")) if id <= 0 { return } @@ -44,7 +44,7 @@ func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { } func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { - id := rw.ValidateInt(w, "id", r.PathValue("id")) + id := rw.ValidateInt(w, "code", r.PathValue("code")) if id <= 0 { return } @@ -59,7 +59,7 @@ func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { } func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { - id := rw.ValidateInt(w, "id", r.PathValue("id")) + id := rw.ValidateInt(w, "code", r.PathValue("code")) if id <= 0 { return } diff --git a/internal/interface/main-handler/therapy-protocol/handler.go b/internal/interface/main-handler/therapy-protocol/handler.go new file mode 100644 index 00000000..2d9efc3b --- /dev/null +++ b/internal/interface/main-handler/therapy-protocol/handler.go @@ -0,0 +1,73 @@ +package therapy_protocol + +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/therapy-protocol" + u "simrs-vx/internal/use-case/main-use-case/therapy-protocol" +) + +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{} + + sf.UrlQueryParam(&dto, *r.URL) + dto.Id = uint(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 = uint(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 = uint(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/lib/auth/tycovar.go b/internal/lib/auth/tycovar.go index 44426d4b..467bd1b6 100644 --- a/internal/lib/auth/tycovar.go +++ b/internal/lib/auth/tycovar.go @@ -14,12 +14,12 @@ type AuthInfo struct { User_ContractPosition_code string Employee_Position_Code *string Employee_Id *uint - Doctor_Id *uint - Nurse_Id *uint - Midwife_Id *uint - Nutritionist_Id *uint - Laborant_Id *uint - Pharmachist_Id *uint + Doctor_Code *string + Nurse_Code *string + Midwife_Code *string + Nutritionist_Code *string + Laborant_Code *string + Pharmachist_Code *string Intern_Position_Code *string Roles []string // User_DivisionPositions []DivisionPosition diff --git a/internal/use-case/main-sync-case/.keep b/internal/use-case/main-sync-use-case/.keep similarity index 100% rename from internal/use-case/main-sync-case/.keep rename to internal/use-case/main-sync-use-case/.keep diff --git a/internal/use-case/main-use-case/adm-employee-hist/lib.go b/internal/use-case/main-use-case/adm-employee-hist/lib.go index dc03b28a..6bdcbe22 100644 --- a/internal/use-case/main-use-case/adm-employee-hist/lib.go +++ b/internal/use-case/main-use-case/adm-employee-hist/lib.go @@ -75,29 +75,18 @@ func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e pl.SetLogInfo(event, input, "started", "DBReadDetail") data := e.AdmEmployeeHist{} - var tx, getData *gorm.DB + var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] } else { tx = dg.I } - switch { - case input.Id != 0: - getData = tx.First(&data, input.Id) - case input.Code != nil && *input.Code != "": - getData = tx.Where("code = ?", *input.Code).First(&data) - default: - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-read-detail-fail", - Detail: "either Id or Code must be provided", - } + if err := tx. + Scopes(gh.Preload(input.Includes)). + First(&data, input.Id). + Error; err != nil { - return nil, pl.SetLogError(event, nil) - } - - if err := getData.Error; err != nil { if processedErr := pu.HandleReadError(err, event, source, input.Id, data); processedErr != nil { return nil, processedErr } diff --git a/internal/use-case/main-use-case/ambulatory/helper.go b/internal/use-case/main-use-case/ambulatory/helper.go index 912211c0..a8a00e0d 100644 --- a/internal/use-case/main-use-case/ambulatory/helper.go +++ b/internal/use-case/main-use-case/ambulatory/helper.go @@ -22,6 +22,7 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Ambulatory) { data.Encounter_Id = inputSrc.Encounter_Id data.Class_Code = inputSrc.Class_Code + data.VisitMode_Code = inputSrc.VisitMode_Code } func CheckClassCode(input *string) (ere.AmbulatoryClassCode, error) { diff --git a/internal/use-case/main-use-case/authentication/case.go b/internal/use-case/main-use-case/authentication/case.go index d00889ee..6a980d71 100644 --- a/internal/use-case/main-use-case/authentication/case.go +++ b/internal/use-case/main-use-case/authentication/case.go @@ -136,17 +136,17 @@ func GenToken(input eu.LoginDto) (*d.Data, error) { if doctor.Id == 0 { return nil, d.FieldErrors{"authentication": d.FieldError{Code: "auth-noDoctor", Message: el.GenMessage("auth-noDoctor")}} } - atClaims["doctor_id"] = doctor.Id - outputData["doctor_id"] = doctor.Id + atClaims["doctor_code"] = doctor.Code + outputData["doctor_code"] = doctor.Code // specialist - if doctor.Specialist_Id != nil { - atClaims["specialist_id"] = doctor.Specialist_Id - outputData["specialist_id"] = doctor.Specialist_Id + if doctor.Specialist_Code != nil { + atClaims["specialist_code"] = doctor.Specialist_Code + outputData["specialist_code"] = doctor.Specialist_Code } - if doctor.Subspecialist_Id != nil { - atClaims["subspecialist_id"] = doctor.Subspecialist_Id - outputData["subspecialist_id"] = doctor.Subspecialist_Id + if doctor.Subspecialist_Code != nil { + atClaims["subspecialist_code"] = doctor.Subspecialist_Code + outputData["subspecialist_code"] = doctor.Subspecialist_Code } case erg.EPCNur: empData := en.Nurse{} @@ -154,16 +154,16 @@ func GenToken(input eu.LoginDto) (*d.Data, error) { if empData.Id == 0 { return nil, d.FieldErrors{"authentication": d.FieldError{Code: "auth-noNurse", Message: el.GenMessage("auth-noNurse")}} } - atClaims["nurse_id"] = empData.Id - outputData["nurse_id"] = empData.Id + atClaims["nurse_code"] = empData.Code + outputData["nurse_code"] = empData.Code case erg.EPCMwi: empData := em.Midwife{} dg.I.Where("\"Employee_Id\" = ?", employee.Id).First(&empData) if empData.Id == 0 { - return nil, d.FieldErrors{"authentication": d.FieldError{Code: "auth-noNurse", Message: el.GenMessage("auth-noNurse")}} + return nil, d.FieldErrors{"authentication": d.FieldError{Code: "auth-noMidwife", Message: el.GenMessage("auth-noMidwife")}} } - atClaims["nurse_id"] = empData.Id - outputData["nurse_id"] = empData.Id + atClaims["midwife_code"] = empData.Code + outputData["midwife_code"] = empData.Code } errorGetPosition := d.FieldErrors{"authentication": d.FieldError{Code: "auth-getData-failed", Message: el.GenMessage("auth-getData-failed")}} @@ -308,12 +308,12 @@ func ExtractToken(r *http.Request, tokenType TokenType) (data *pa.AuthInfo, err data.User_ContractPosition_code = checkStrClaims(claims, "contractPosition_code") data.Employee_Position_Code = checkStrPtrClaims(claims, "employee_position_code") - data.Doctor_Id = checkUntPtrClaims(claims, "doctor_id") - data.Nurse_Id = checkUntPtrClaims(claims, "nurse_id") - data.Midwife_Id = checkUntPtrClaims(claims, "midwife_id") - data.Nutritionist_Id = checkUntPtrClaims(claims, "nutritionist_id") - data.Laborant_Id = checkUntPtrClaims(claims, "laborant_id") - data.Pharmachist_Id = checkUntPtrClaims(claims, "pharmachist_id") + data.Doctor_Code = checkStrPtrClaims(claims, "doctor_string") + data.Nurse_Code = checkStrPtrClaims(claims, "nurse_string") + data.Midwife_Code = checkStrPtrClaims(claims, "midwife_string") + data.Nutritionist_Code = checkStrPtrClaims(claims, "nutritionist_string") + data.Laborant_Code = checkStrPtrClaims(claims, "laborant_string") + data.Pharmachist_Code = checkStrPtrClaims(claims, "pharmachist_string") data.Intern_Position_Code = checkStrPtrClaims(claims, "intern_position_code") data.Employee_Id = checkUntPtrClaims(claims, "employee_id") return diff --git a/internal/use-case/main-use-case/chemo-protocol/case.go b/internal/use-case/main-use-case/chemo-protocol/case.go new file mode 100644 index 00000000..4e007d28 --- /dev/null +++ b/internal/use-case/main-use-case/chemo-protocol/case.go @@ -0,0 +1,277 @@ +package chemo_protocol + +import ( + "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" + + e "simrs-vx/internal/domain/main-entities/chemo-protocol" +) + +const source = "chemo-protocol" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.ChemoProtocol{} + + 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.ChemoProtocol + var dataList []e.ChemoProtocol + 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 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), + "record_currentCount": strconv.Itoa(len(dataList)), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.ChemoProtocol + 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.ChemoProtocol + 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.ChemoProtocol + 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/chemo-protocol/helper.go b/internal/use-case/main-use-case/chemo-protocol/helper.go new file mode 100644 index 00000000..885e6fbb --- /dev/null +++ b/internal/use-case/main-use-case/chemo-protocol/helper.go @@ -0,0 +1,28 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package chemo_protocol + +import ( + e "simrs-vx/internal/domain/main-entities/chemo-protocol" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.ChemoProtocol) { + 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.Patient_Weight = inputSrc.Patient_Weight + data.Patient_Height = inputSrc.Patient_Height + data.Diagnoses = inputSrc.Diagnoses + data.Duration = inputSrc.Duration + data.DurationUnit_Code = inputSrc.DurationUnit_Code + data.StartDate = inputSrc.StartDate + data.EndDate = inputSrc.EndDate +} diff --git a/internal/use-case/main-use-case/chemo-protocol/lib.go b/internal/use-case/main-use-case/chemo-protocol/lib.go new file mode 100644 index 00000000..22e8808c --- /dev/null +++ b/internal/use-case/main-use-case/chemo-protocol/lib.go @@ -0,0 +1,147 @@ +package chemo_protocol + +import ( + "errors" + + plh "simrs-vx/pkg/lib-helper" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + + e "simrs-vx/internal/domain/main-entities/chemo-protocol" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.ChemoProtocol, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.ChemoProtocol{} + 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 { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.ChemoProtocol, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.ChemoProtocol{} + pagination := gh.Pagination{} + count := int64(0) + meta := e.MetaDto{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + tx = tx. + Model(&e.ChemoProtocol{}). + Scopes(gh.Preload(input.Includes)). + Scopes(gh.Filter(input.FilterDto)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Find(&data).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, &meta, nil + } + return nil, nil, plh.HandleListError(input, event, err) + } + + 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.ChemoProtocol, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.ChemoProtocol{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx. + Scopes(gh.Preload(input.Includes)). + 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.ChemoProtocol, 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.ChemoProtocol, 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/chemo-protocol/middleware-runner.go b/internal/use-case/main-use-case/chemo-protocol/middleware-runner.go new file mode 100644 index 00000000..7c932d7b --- /dev/null +++ b/internal/use-case/main-use-case/chemo-protocol/middleware-runner.go @@ -0,0 +1,103 @@ +package chemo_protocol + +import ( + e "simrs-vx/internal/domain/main-entities/chemo-protocol" + 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.ChemoProtocol) 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.ChemoProtocol) 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.ChemoProtocol) 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.ChemoProtocol) 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.ChemoProtocol) 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/chemo-protocol/middleware.go b/internal/use-case/main-use-case/chemo-protocol/middleware.go new file mode 100644 index 00000000..a438fd1c --- /dev/null +++ b/internal/use-case/main-use-case/chemo-protocol/middleware.go @@ -0,0 +1,9 @@ +package chemo_protocol + +// 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/chemo-protocol/tycovar.go b/internal/use-case/main-use-case/chemo-protocol/tycovar.go new file mode 100644 index 00000000..f4822996 --- /dev/null +++ b/internal/use-case/main-use-case/chemo-protocol/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 chemo_protocol + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/chemo-protocol" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.ChemoProtocol, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.ChemoProtocol, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.ChemoProtocol, 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/chemo/case.go b/internal/use-case/main-use-case/chemo/case.go index 541faa04..f7b3c7d3 100644 --- a/internal/use-case/main-use-case/chemo/case.go +++ b/internal/use-case/main-use-case/chemo/case.go @@ -311,6 +311,8 @@ func Verify(input e.VerifyDto) (*d.Data, error) { data.VerifiedAt = pu.GetTimeNow() data.Status_Code = input.Status_Code data.VerifiedBy_User_Id = &input.AuthInfo.User_Id + data.Bed = input.Bed + data.Needs = input.Needs err = tx.Save(&data).Error if err != nil { diff --git a/internal/use-case/main-use-case/control-letter/case.go b/internal/use-case/main-use-case/control-letter/case.go new file mode 100644 index 00000000..6f28c43e --- /dev/null +++ b/internal/use-case/main-use-case/control-letter/case.go @@ -0,0 +1,297 @@ +package controlletter + +import ( + "errors" + "strconv" + + e "simrs-vx/internal/domain/main-entities/control-letter" + ue "simrs-vx/internal/use-case/main-use-case/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 = "control-letter" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.ControlLetter{} + + 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 pu.IsDateBeforeNow(input.Date) { + return errors.New("date is in the past") + } + + // check if encounter is done + if ue.IsDone(*input.Encounter_Id, &event, tx) { + return errors.New("encounter is already done") + } + + 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.ControlLetter + var dataList []e.ControlLetter + 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 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), + "record_currentCount": strconv.Itoa(len(dataList)), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.ControlLetter + 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.ControlLetter + 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 pu.IsDateBeforeNow(input.Date) { + return errors.New("date is in the past") + } + + // check if encounter is done + if ue.IsDone(*input.Encounter_Id, &event, tx) { + return errors.New("encounter is already done") + } + + 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.ControlLetter + 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/control-letter/helper.go b/internal/use-case/main-use-case/control-letter/helper.go new file mode 100644 index 00000000..5cc943c5 --- /dev/null +++ b/internal/use-case/main-use-case/control-letter/helper.go @@ -0,0 +1,26 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package controlletter + +import ( + e "simrs-vx/internal/domain/main-entities/control-letter" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.ControlLetter) { + 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.Unit_Id = inputSrc.Unit_Id + data.Specialist_Id = inputSrc.Specialist_Id + data.Subspecialist_Id = inputSrc.Subspecialist_Id + data.Doctor_Id = inputSrc.Doctor_Id + data.Date = inputSrc.Date +} diff --git a/internal/use-case/main-use-case/control-letter/lib.go b/internal/use-case/main-use-case/control-letter/lib.go new file mode 100644 index 00000000..5f82a856 --- /dev/null +++ b/internal/use-case/main-use-case/control-letter/lib.go @@ -0,0 +1,144 @@ +package controlletter + +import ( + e "simrs-vx/internal/domain/main-entities/control-letter" + + plh "simrs-vx/pkg/lib-helper" + 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.ControlLetter, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.ControlLetter{} + 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 { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.ControlLetter, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.ControlLetter{} + pagination := gh.Pagination{} + count := int64(0) + meta := e.MetaDto{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + tx = tx. + Model(&e.ControlLetter{}). + Scopes(gh.Preload(input.Includes)). + 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 + } + return nil, nil, plh.HandleListError(input, event, err) + } + + 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.ControlLetter, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.ControlLetter{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if input.Includes != "" { + tx = tx.Scopes(gh.Preload(input.Includes)) + } + + 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.ControlLetter, 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.ControlLetter, 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/control-letter/middleware-runner.go b/internal/use-case/main-use-case/control-letter/middleware-runner.go new file mode 100644 index 00000000..6335de13 --- /dev/null +++ b/internal/use-case/main-use-case/control-letter/middleware-runner.go @@ -0,0 +1,103 @@ +package controlletter + +import ( + e "simrs-vx/internal/domain/main-entities/control-letter" + 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.ControlLetter) 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.ControlLetter) 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.ControlLetter) 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.ControlLetter) 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.ControlLetter) 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/control-letter/middleware.go b/internal/use-case/main-use-case/control-letter/middleware.go new file mode 100644 index 00000000..42ae506c --- /dev/null +++ b/internal/use-case/main-use-case/control-letter/middleware.go @@ -0,0 +1,9 @@ +package controlletter + +// 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/control-letter/tycovar.go b/internal/use-case/main-use-case/control-letter/tycovar.go new file mode 100644 index 00000000..1f19c991 --- /dev/null +++ b/internal/use-case/main-use-case/control-letter/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 controlletter + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/control-letter" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.ControlLetter, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.ControlLetter, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.ControlLetter, 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/doctor/helper.go b/internal/use-case/main-use-case/doctor/helper.go index b62045c7..344d1c0e 100644 --- a/internal/use-case/main-use-case/doctor/helper.go +++ b/internal/use-case/main-use-case/doctor/helper.go @@ -21,7 +21,7 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Doctor) { data.Employee_Id = inputSrc.Employee_Id data.IHS_Number = inputSrc.IHS_Number data.SIP_Number = inputSrc.SIP_Number - data.Unit_Id = inputSrc.Unit_Id - data.Specialist_Id = inputSrc.Specialist_Id - data.Subspecialist_Id = inputSrc.Subspecialist_Id + data.Unit_Code = inputSrc.Unit_Code + data.Specialist_Code = inputSrc.Code + data.Subspecialist_Code = inputSrc.Code } diff --git a/internal/use-case/main-use-case/encounter/case.go b/internal/use-case/main-use-case/encounter/case.go index 829cf86c..ef70d9c2 100644 --- a/internal/use-case/main-use-case/encounter/case.go +++ b/internal/use-case/main-use-case/encounter/case.go @@ -25,6 +25,7 @@ import ( eem "simrs-vx/internal/domain/main-entities/employee" e "simrs-vx/internal/domain/main-entities/encounter" ei "simrs-vx/internal/domain/main-entities/inpatient" + er "simrs-vx/internal/domain/main-entities/rehab" erdh "simrs-vx/internal/domain/main-entities/responsible-doctor-hist" es "simrs-vx/internal/domain/main-entities/soapi" @@ -36,7 +37,7 @@ import ( ue "simrs-vx/internal/use-case/main-use-case/emergency" uem "simrs-vx/internal/use-case/main-use-case/employee" ui "simrs-vx/internal/use-case/main-use-case/inpatient" - urdh "simrs-vx/internal/use-case/main-use-case/responsible-doctor-hist" + ur "simrs-vx/internal/use-case/main-use-case/rehab" us "simrs-vx/internal/use-case/main-use-case/soapi" ) @@ -46,6 +47,7 @@ var now = time.Now() func Create(input e.CreateDto) (*d.Data, error) { data := e.Encounter{} + createSoapi := []es.CreateDto{} event := pl.Event{ Feature: "Create", @@ -55,6 +57,39 @@ func Create(input e.CreateDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "create") + // validate SubClass + var subCode interface{} + subCode, err := verifyClassCode(input) + if err != nil { + return nil, err + } + + // verify whether the allocated visit count has not exceeded the limit + if input.Class_Code == ere.ECAmbulatory && subCode.(ere.AmbulatoryClassCode) == ere.ACCRehab && + *input.VisitMode_Code == ere.VMCSeries { + + dataEncounter, valid, err := verifyAllocatedVisitCount(input, &event) + if err != nil { + return nil, err + } + + if !valid { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "visit-limit-exceeded", + Detail: "Encounter has exceeded the allowed number of visits", + Raw: errors.New("visit count exceeds allowed limit"), + } + return nil, pl.SetLogError(&event, input) + } + + // get data soapi + createSoapi, err = getSoapiEncounterAdm(dataEncounter, &event) + if err != nil { + return nil, err + } + } + // check if patient is new in the hospital dataPatient, err := ReadList(e.ReadListDto{ FilterDto: e.FilterDto{Patient_Id: input.Patient_Id}, @@ -62,7 +97,6 @@ func Create(input e.CreateDto) (*d.Data, error) { if err != nil { return nil, err } - if list, ok := dataPatient.Data.([]e.ResponseDto); ok { if len(list) < 1 { input.NewStatus = true @@ -83,6 +117,7 @@ func Create(input e.CreateDto) (*d.Data, error) { input.Adm_Employee_Id = &emp.Id } + // create encounter if resData, err := CreateData(input, &event, tx); err != nil { return err } else { @@ -91,52 +126,57 @@ func Create(input e.CreateDto) (*d.Data, error) { switch input.Class_Code { case ere.ECAmbulatory: - subCode, err := ua.CheckClassCode(input.SubClass_Code) - if err != nil { - return err - } + subCodeAmbulatory := subCode.(ere.AmbulatoryClassCode) ambCreate := ea.CreateDto{ - Encounter_Id: &data.Id, - Class_Code: subCode, + Encounter_Id: &data.Id, + Class_Code: subCodeAmbulatory, + VisitMode_Code: *input.VisitMode_Code, } _, err = ua.CreateData(ambCreate, &event, tx) if err != nil { return err } - if subCode == ere.ACCChemo { + if subCodeAmbulatory == ere.ACCChemo { chemoCreate := ec.CreateDto{ Encounter_Id: &data.Id, Status_Code: erc.DVCNew, SrcUnit_Id: input.Unit_Id, } - _, err = uc.CreateData(chemoCreate, &event, tx) if err != nil { return err } } - case ere.ECEmergency: - subCode, err := ue.CheckClassCode(input.SubClass_Code) - if err != nil { - return err + + if subCodeAmbulatory == ere.ACCRehab && *input.VisitMode_Code == ere.VMCAdm { + // create data rehab + if _, err = ur.CreateData(er.CreateDto{ + Encounter_Id: &data.Id, + Doctor_Id: input.Appointment_Doctor_Id, + AllocatedVisitCount: input.AllocatedVisitCount}, &event, tx); err != nil { + return err + } + } else if subCodeAmbulatory == ere.ACCRehab && *input.VisitMode_Code == ere.VMCSeries { + // Insert Soapi + if err = us.CreateBulkData(createSoapi, data.Id, &event, tx); err != nil { + return err + } } + + case ere.ECEmergency: emerCreate := ee.CreateDto{ Encounter_Id: &data.Id, - Class_Code: subCode, + Class_Code: subCode.(ere.EmergencyClassCode), } _, 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, + Class_Code: subCode.(ere.InpatientClassCode), Infra_Id: input.Infra_Id, } _, err = ui.CreateData(inpCreate, &event, tx) @@ -148,11 +188,10 @@ func Create(input e.CreateDto) (*d.Data, error) { } // insert adm_employee_hist - if _, err := uaeh.Create(eaeh.CreateDto{ + if _, err := uaeh.CreateData(eaeh.CreateDto{ Encounter_Id: &data.Main.Id, Employee_Id: data.Adm_Employee_Id, - StartedAt: &now, - }); err != nil { + StartedAt: &now}, &event, tx); err != nil { return err } @@ -402,7 +441,7 @@ func Delete(input e.DeleteDto) (*d.Data, error) { } func CheckOut(input e.DischargeDto) (*d.Data, error) { - rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + rdDto := e.ReadDetailDto{Id: uint16(input.Id), Includes: "Ambulatory"} var data *e.Encounter var err error @@ -430,8 +469,17 @@ func CheckOut(input e.DischargeDto) (*d.Data, error) { return pl.SetLogError(&event, input) } - if err := checkSoapiByDocExists(data.Id, &event, tx); err != nil { - return err + if data.Ambulatory != nil && (data.Ambulatory.Class_Code == ere.ACCReg || data.Ambulatory.Class_Code == ere.ACCRehab) { + // validate if soapi exist + err = getSoapiByTypeCode(input.Id, *data.Ambulatory, &event, "check-out") + if err != nil { + return err + } + } else { + // chemo TBC + if err := checkSoapiByDocExists(data.Id, &event, tx); err != nil { + return err + } } if err := updateDischargeData(input, data, &event, tx); err != nil { @@ -557,7 +605,7 @@ func UpdateStatusCode(input e.UpdateStatusDto) (*d.Data, error) { } func CheckIn(input e.CheckinDto) (*d.Data, error) { - rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + rdDto := e.ReadDetailDto{Id: uint16(input.Id), Includes: "Rehab,Ambulatory"} var data *e.Encounter var err error @@ -579,24 +627,6 @@ func CheckIn(input e.CheckinDto) (*d.Data, error) { input.StartedAt = &now } - // validate if soapi exist - dataSoapi, err := us.ReadList(es.ReadListDto{FilterDto: es.FilterDto{Encounter_Id: &input.Id}}) - if err != nil { - return nil, err - } - - if list, ok := dataSoapi.Data.([]es.ResponseDto); ok { - if len(list) > 0 { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-state-mismatch", - Detail: "soapi already exist", - Raw: errors.New("soapi already exist"), - } - return nil, pl.SetLogError(&event, input) - } - } - err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") if data, err = ReadDetailData(rdDto, &event, tx); err != nil { @@ -613,36 +643,34 @@ func CheckIn(input e.CheckinDto) (*d.Data, error) { return pl.SetLogError(&event, input) } - // Insert responsible_doctor_hist if responsible_doctor_id has changed && update latest history - if data.Responsible_Doctor_Id == nil || *input.Responsible_Doctor_Id != *data.Responsible_Doctor_Id { - // update finishedAt in latest responsible_doctor_hist - if err = updateLatestResponsibleDoctorHist(input, &event, tx); err != nil { + // validate if soapi exist + if data.Ambulatory != nil && (data.Ambulatory.Class_Code == ere.ACCReg || data.Ambulatory.Class_Code == ere.ACCRehab) { + err = getSoapiByTypeCode(input.Id, *data.Ambulatory, &event, "check-in") + if err != nil { return err } + } - //insert responsible_doctor_hist - if _, err = urdh.Create(erdh.CreateDto{ - Encounter_Id: &input.Id, + // Insert responsible_doctor_hist if responsible_doctor_id has changed && update latest history + if data.Responsible_Doctor_Id == nil || *input.Responsible_Doctor_Id != *data.Responsible_Doctor_Id { + // upsert responsibleDoctorHist + if err = upsertResponsibleDoctorHist(erdh.CreateDto{ + Encounter_Id: &data.Id, Doctor_Id: input.Responsible_Doctor_Id, StartedAt: input.StartedAt, - }); err != nil { + }, &event, tx); err != nil { return err } } // Insert adm_employee_hist if adm_employee_id has changed && update latest history if input.Adm_Employee_Id != nil && *input.Adm_Employee_Id != *data.Adm_Employee_Id { - // update finishedAt in latest adm_employee_hist - if err = updateLatestAdmEmployeeHist(input, &event, tx); err != nil { - return err - } - - // insert responsible_doctor_hist - if _, err = uaeh.Create(eaeh.CreateDto{ - Encounter_Id: &input.Id, + // upsert admEmployeeHist + if err = upsertAdmEmployeeHist(eaeh.CreateDto{ + Encounter_Id: &data.Id, Employee_Id: input.Adm_Employee_Id, StartedAt: input.StartedAt, - }); err != nil { + }, &event, tx); err != nil { return err } } @@ -652,6 +680,15 @@ func CheckIn(input e.CheckinDto) (*d.Data, error) { return err } + if data.Ambulatory.Class_Code == ere.ACCRehab { + if err := updateRehabDoctor(er.UpdateDto{CreateDto: er.CreateDto{ + Encounter_Id: &data.Id, + Doctor_Id: input.Responsible_Doctor_Id, + }}, &event, tx); err != nil { + return err + } + } + pl.SetLogInfo(&event, nil, "complete") return nil @@ -688,3 +725,26 @@ func validateForeignKey(input e.CheckinDto) error { return nil } + +func verifyClassCode(input e.CreateDto) (subCode interface{}, err error) { + switch input.Class_Code { + case ere.ECAmbulatory: + subCode, err = ua.CheckClassCode(input.SubClass_Code) + if err != nil { + return nil, err + } + case ere.ECEmergency: + subCode, err = ue.CheckClassCode(input.SubClass_Code) + if err != nil { + return nil, err + } + case ere.ECInpatient: + subCode, err = ui.CheckClassCode(input.SubClass_Code) + if err != nil { + return nil, err + } + default: + return nil, errors.New("invalid encounter class code") + } + return +} diff --git a/internal/use-case/main-use-case/encounter/helper.go b/internal/use-case/main-use-case/encounter/helper.go index c5eb155e..67cef58b 100644 --- a/internal/use-case/main-use-case/encounter/helper.go +++ b/internal/use-case/main-use-case/encounter/helper.go @@ -7,17 +7,25 @@ package encounter import ( "errors" "fmt" - uir "simrs-vx/internal/use-case/main-use-case/internal-reference" "strings" "time" + dg "github.com/karincake/apem/db-gorm-pg" "gorm.io/gorm" pl "simrs-vx/pkg/logger" pu "simrs-vx/pkg/use-case-helper" + ercl "simrs-vx/internal/domain/references/clinical" + erc "simrs-vx/internal/domain/references/common" + ere "simrs-vx/internal/domain/references/encounter" + erg "simrs-vx/internal/domain/references/organization" + + eaeh "simrs-vx/internal/domain/main-entities/adm-employee-hist" + ea "simrs-vx/internal/domain/main-entities/ambulatory" edo "simrs-vx/internal/domain/main-entities/device-order" ed "simrs-vx/internal/domain/main-entities/doctor" + e "simrs-vx/internal/domain/main-entities/encounter" emo "simrs-vx/internal/domain/main-entities/material-order" emco "simrs-vx/internal/domain/main-entities/mcu-order" em "simrs-vx/internal/domain/main-entities/medication" @@ -26,20 +34,21 @@ import ( emmi "simrs-vx/internal/domain/main-entities/medicine-mix-item" ep "simrs-vx/internal/domain/main-entities/prescription" epi "simrs-vx/internal/domain/main-entities/prescription-item" + er "simrs-vx/internal/domain/main-entities/rehab" + erdh "simrs-vx/internal/domain/main-entities/responsible-doctor-hist" eu "simrs-vx/internal/domain/main-entities/unit" // udo "simrs-vx/internal/use-case/main-use-case/device-order" es "simrs-vx/internal/domain/main-entities/soapi" + uaeh "simrs-vx/internal/use-case/main-use-case/adm-employee-hist" + uir "simrs-vx/internal/use-case/main-use-case/internal-reference" um "simrs-vx/internal/use-case/main-use-case/medication" umei "simrs-vx/internal/use-case/main-use-case/medication-item" umi "simrs-vx/internal/use-case/main-use-case/medicine-mix" ummi "simrs-vx/internal/use-case/main-use-case/medicine-mix-item" up "simrs-vx/internal/use-case/main-use-case/prescription" upi "simrs-vx/internal/use-case/main-use-case/prescription-item" - - e "simrs-vx/internal/domain/main-entities/encounter" - erc "simrs-vx/internal/domain/references/common" - erg "simrs-vx/internal/domain/references/organization" + urdh "simrs-vx/internal/use-case/main-use-case/responsible-doctor-hist" ) func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Encounter) { @@ -432,3 +441,371 @@ func getDoctors(doctorIds []uint, event *pl.Event, tx *gorm.DB) ([]ed.Doctor, er } return doctors, nil } + +func upsertResponsibleDoctorHist(input erdh.CreateDto, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + var latest erdh.ResponsibleDoctorHist + err := tx. + Where("\"Encounter_Id\" = ?", input.Encounter_Id). + Order("\"CreatedAt\" DESC"). + Limit(1). + First(&latest).Error + + switch { + case errors.Is(err, gorm.ErrRecordNotFound): + // Insert + if _, err = urdh.CreateData(input, event, tx); err != nil { + return err + } + case err != nil: + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "read-fail", + Detail: "Failed to read responsible doctor history", + Raw: err, + } + return pl.SetLogError(event, input) + default: + // Update + if err := tx.Model(&latest).Updates(map[string]interface{}{ + "Doctor_Id": input.Doctor_Id, + "StartedAt": input.StartedAt, + "UpdatedAt": time.Now(), + }).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "update-fail", + Detail: "Failed to update responsible doctor history", + Raw: err, + } + return pl.SetLogError(event, input) + } + } + pl.SetLogInfo(event, input, "complete") + return nil +} + +func upsertAdmEmployeeHist(input eaeh.CreateDto, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + var latest eaeh.AdmEmployeeHist + err := tx. + Where("\"Encounter_Id\" = ?", input.Encounter_Id). + Order("\"CreatedAt\" DESC"). + Limit(1). + First(&latest).Error + + switch { + case errors.Is(err, gorm.ErrRecordNotFound): + // Insert + if _, err = uaeh.CreateData(input, event, tx); err != nil { + return err + } + case err != nil: + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "read-fail", + Detail: "Failed to read responsible doctor history", + Raw: err, + } + return pl.SetLogError(event, input) + + default: + // Update + if err := tx.Model(&latest).Updates(map[string]interface{}{ + "Employee_Id": input.Employee_Id, + "StartedAt": input.StartedAt, + "UpdatedAt": time.Now(), + }).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "update-fail", + Detail: "Failed to update responsible doctor history", + Raw: err, + } + return pl.SetLogError(event, input) + } + } + pl.SetLogInfo(event, input, "complete") + + return nil +} + +func updateLatestResponsibleDoctorHist(input e.CheckinDto, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, "started", "DBUpdate") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + subQuery := tx. + Select("\"Id\""). + Model(&erdh.ResponsibleDoctorHist{}). + Where("\"Encounter_Id\" = ?", input.Id). + Order("\"CreatedAt\" DESC"). + Limit(1) + + result := tx. + Model(&erdh.ResponsibleDoctorHist{}). + Where("\"Id\" = (?)", subQuery). + Update("\"FinishedAt\"", input.StartedAt) + + if result.Error != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-update-fail", + Detail: "Database update failed", + Raw: result.Error, + } + return pl.SetLogError(event, input) + } + + if result.RowsAffected == 0 { + pl.SetLogInfo(event, input, "no previous data found to update") + return nil + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} + +func updateLatestAdmEmployeeHist(input e.CheckinDto, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, "started", "DBUpdate") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + subQuery := tx. + Select("\"Id\""). + Model(&eaeh.AdmEmployeeHist{}). + Where("\"Encounter_Id\" = ?", input.Id). + Order("\"CreatedAt\" DESC"). + Limit(1) + + result := tx. + Model(&eaeh.AdmEmployeeHist{}). + Where("\"Id\" = (?)", subQuery). + Update("\"FinishedAt\"", input.StartedAt) + + if result.Error != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-update-fail", + Detail: "Database update failed", + Raw: result.Error, + } + return pl.SetLogError(event, input) + } + + if result.RowsAffected == 0 { + pl.SetLogInfo(event, input, "no previous data found to update") + return nil + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} + +func getSoapiEncounterAdm(enc e.Encounter, event *pl.Event) (dataSoapi []es.CreateDto, err error) { + var data []es.Soapi + + pl.SetLogInfo(event, enc, "started", "DBReadList") + + if enc.Responsible_Doctor == nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "no responsible-doctor found", + Detail: "Encounter does not have responsible-doctor", + } + } + + err = dg.I. + Model(&es.Soapi{}). + Joins("JOIN \"Employee\" ON \"Employee\".\"Id\" = \"Soapi\".\"Employee_Id\""). + Where("\"Encounter_Id\" = ?", enc.Id). + Where("\"Employee\".\"Position_Code\" = ?", erg.EPCDoc). + Where("\"Soapi\".\"TypeCode\" IN ?", []ercl.SoapiTypeCode{ercl.STCEEarlyMedic, ercl.STCFunc}). + Where("\"Soapi\".\"Employee_Id\" = ?", *enc.Responsible_Doctor.Employee_Id). + Find(&data).Error + + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Raw: err, + } + + if errors.Is(err, gorm.ErrRecordNotFound) { + event.ErrInfo.Code = "data-not-found" + event.ErrInfo.Detail = "Data not found" + return nil, pl.SetLogError(event, enc) + } + + event.ErrInfo.Code = "read-fail" + event.ErrInfo.Detail = "Database read failed" + return nil, pl.SetLogError(event, enc) + } + + pl.SetLogInfo(event, nil, "complete") + + for _, s := range data { + // set data soapi for copy + dataSoapi = append(dataSoapi, es.CreateDto{ + Employee_Id: s.Employee_Id, + Time: s.Time, + TypeCode: s.TypeCode, + Value: s.Value, + }) + } + + if len(dataSoapi) < 2 { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "missing-soapi", + Detail: fmt.Sprintf("Missing required Soapi types"), + } + return nil, pl.SetLogError(event, enc) + } + return +} + +func getSoapiByTypeCode(encounterId uint, dataAmbulatory ea.Ambulatory, event *pl.Event, mode string) (err error) { + pl.SetLogInfo(event, encounterId, "started", "DBReadList") + + var ( + dataSoapi []es.Soapi + ) + + // Set Query for get data Soapi + tx := dg.I. + Model(&es.Soapi{}). + Joins("JOIN \"Employee\" ON \"Employee\".\"Id\" = \"Soapi\".\"Employee_Id\""). + Where("\"Encounter_Id\" = ?", encounterId). + Where("\"Employee\".\"Position_Code\" = ?", erg.EPCDoc) + + // Set Case + switch { + case dataAmbulatory.Class_Code == ere.ACCReg: + tx = tx.Where("\"Soapi\".\"TypeCode\" = ?", ercl.STCEEarlyMedic) + case dataAmbulatory.Class_Code == ere.ACCRehab && dataAmbulatory.VisitMode_Code == ere.VMCAdm: + tx = tx.Where("\"Soapi\".\"TypeCode\" IN ?", []ercl.SoapiTypeCode{ercl.STCEEarlyMedic, ercl.STCFunc, ercl.STCEarlyRehab}) + case dataAmbulatory.Class_Code == ere.ACCRehab && dataAmbulatory.VisitMode_Code == ere.VMCSeries: + tx = tx.Where("\"Soapi\".\"TypeCode\" = ?", ercl.STCEarlyRehab) + } + + if err = tx.Find(&dataSoapi).Error; err != nil { + return setDBError(event, err, encounterId) + } + + pl.SetLogInfo(event, nil, "complete") + return validateExistedSoapi(dataSoapi, &dataAmbulatory, event, mode) +} + +func validateExistedSoapi(dataSoapi []es.Soapi, dataAmbulatory *ea.Ambulatory, event *pl.Event, mode string) error { + typeExist := make(map[ercl.SoapiTypeCode]bool) + for _, s := range dataSoapi { + typeExist[s.TypeCode] = true + } + + required := []ercl.SoapiTypeCode{} + + switch { + case dataAmbulatory.Class_Code == ere.ACCReg: + required = []ercl.SoapiTypeCode{ercl.STCEEarlyMedic} + case dataAmbulatory.Class_Code == ere.ACCRehab && dataAmbulatory.VisitMode_Code == ere.VMCAdm: + required = []ercl.SoapiTypeCode{ercl.STCEEarlyMedic, ercl.STCFunc, ercl.STCEarlyRehab} + case dataAmbulatory.Class_Code == ere.ACCRehab && dataAmbulatory.VisitMode_Code == ere.VMCSeries: + required = []ercl.SoapiTypeCode{ercl.STCEarlyRehab} + } + + var missing, existing []string + for _, code := range required { + if typeExist[code] { + existing = append(existing, string(code)) + } else { + missing = append(missing, string(code)) + } + } + + switch mode { + case "check-in": + if len(existing) > 0 { + return setSoapiError(event, fmt.Sprintf("Soapi type(s) %s exist, can't check-in", strings.Join(existing, ", "))) + } + case "check-out": + if len(missing) > 0 { + return setSoapiError(event, fmt.Sprintf("Soapi type(s) %s not found, can't check-out", strings.Join(missing, ", "))) + } + } + + return nil +} + +func setSoapiError(event *pl.Event, detail string) error { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "invalid-soapi-state", + Detail: detail, + } + return pl.SetLogError(event, detail) +} + +func setDBError(event *pl.Event, err error, ctx any) error { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Raw: err, + Code: "read-fail", + Detail: "Database read failed", + } + return pl.SetLogError(event, ctx) +} + +func updateRehabDoctor(input er.UpdateDto, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, "started", "DBUpdate") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + result := tx. + Model(&er.Rehab{}). + Where("\"Encounter_Id\" = (?)", input.Encounter_Id). + Update("\"Doctor_Id\"", input.Doctor_Id) + + if result.Error != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-update-fail", + Detail: "Database update failed", + Raw: result.Error, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/main-use-case/encounter/lib.go b/internal/use-case/main-use-case/encounter/lib.go index 3327bcfa..18a632c3 100644 --- a/internal/use-case/main-use-case/encounter/lib.go +++ b/internal/use-case/main-use-case/encounter/lib.go @@ -3,6 +3,8 @@ package encounter import ( // std "errors" + ere "simrs-vx/internal/domain/references/encounter" + // external dg "github.com/karincake/apem/db-gorm-pg" gh "github.com/karincake/getuk" @@ -13,10 +15,7 @@ import ( pl "simrs-vx/pkg/logger" pu "simrs-vx/pkg/use-case-helper" - // internal - eaeh "simrs-vx/internal/domain/main-entities/adm-employee-hist" e "simrs-vx/internal/domain/main-entities/encounter" - erdh "simrs-vx/internal/domain/main-entities/responsible-doctor-hist" ) func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Encounter, error) { @@ -59,8 +58,8 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.En } tx = tx.Model(&e.Encounter{}) - if input.AuthInfo.Doctor_Id != nil { - tx.Where("\"Responsible_Doctor_Id\" = ?", *input.AuthInfo.Doctor_Id) + if input.AuthInfo.Doctor_Code != nil { + tx.Where("\"Responsible_Doctor_Id\" = ?", *input.AuthInfo.Doctor_Code) // TODO: fix this } tx.Scopes(gh.Preload(input.Includes)). @@ -252,84 +251,48 @@ func updateCheckInData(input e.CheckinDto, data *e.Encounter, event *pl.Event, d return nil } -func updateLatestResponsibleDoctorHist(input e.CheckinDto, event *pl.Event, dbx ...*gorm.DB) error { - pl.SetLogInfo(event, "started", "DBUpdate") +func verifyAllocatedVisitCount(i e.CreateDto, event *pl.Event) (e.Encounter, bool, error) { + pl.SetLogInfo(event, nil, "started", "DBGetRecentEncounterAdm") - var tx *gorm.DB - if len(dbx) > 0 { - tx = dbx[0] - } else { - tx = dg.I - } + var ( + tx = dg.I + recentEncounterAdm e.Encounter + countEncounterSeries int64 + ) - subQuery := tx. - Select("\"Id\""). - Model(&erdh.ResponsibleDoctorHist{}). - Where("\"Encounter_Id\" = ?", input.Id). + err := tx. + Scopes(gh.Preload("Rehab,Responsible_Doctor")). + Joins("JOIN \"Ambulatory\" ON \"Ambulatory\".\"Encounter_Id\" = \"Encounter\".\"Id\""). + Where("\"Patient_Id\" = ?", i.Patient_Id). + Where("\"Ambulatory\".\"Class_Code\" = ? AND \"Ambulatory\".\"VisitMode_Code\" = ?", ere.ACCRehab, ere.VMCAdm). Order("\"CreatedAt\" DESC"). - Limit(1) - - result := tx. - Model(&erdh.ResponsibleDoctorHist{}). - Where("\"Id\" = (?)", subQuery). - Update("\"FinishedAt\"", input.StartedAt) - - if result.Error != nil { + First(&recentEncounterAdm).Error + if err != nil { event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ - Code: "data-update-fail", - Detail: "Database update failed", - Raw: result.Error, + Code: "read-recentEncounter-fail", + Detail: "Database read failed", + Raw: err, } - return pl.SetLogError(event, input) + return e.Encounter{}, false, pl.SetLogError(event, i) } - if result.RowsAffected == 0 { - pl.SetLogInfo(event, input, "no previous data found to update") - return nil - } - - pl.SetLogInfo(event, nil, "complete") - return nil -} - -func updateLatestAdmEmployeeHist(input e.CheckinDto, event *pl.Event, dbx ...*gorm.DB) error { - pl.SetLogInfo(event, "started", "DBUpdate") - - var tx *gorm.DB - if len(dbx) > 0 { - tx = dbx[0] - } else { - tx = dg.I - } - - subQuery := tx. - Select("\"Id\""). - Model(&eaeh.AdmEmployeeHist{}). - Where("\"Encounter_Id\" = ?", input.Id). - Order("\"CreatedAt\" DESC"). - Limit(1) - - result := tx. - Model(&eaeh.AdmEmployeeHist{}). - Where("\"Id\" = (?)", subQuery). - Update("\"FinishedAt\"", input.StartedAt) - - if result.Error != nil { + err = tx. + Model(&e.Encounter{}). + Joins("JOIN \"Ambulatory\" ON \"Ambulatory\".\"Encounter_Id\" = \"Encounter\".\"Id\""). + Where("\"Patient_Id\" = ?", i.Patient_Id). + Where("\"Ambulatory\".\"Class_Code\" = ? AND \"Ambulatory\".\"VisitMode_Code\" = ?", ere.ACCRehab, ere.VMCSeries). + Where("\"Encounter\".\"CreatedAt\" > ?", recentEncounterAdm.CreatedAt). + Count(&countEncounterSeries).Error + if err != nil { event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ - Code: "data-update-fail", - Detail: "Database update failed", - Raw: result.Error, + Code: "read-countEncounter-fail", + Detail: "Database read failed", + Raw: err, } - return pl.SetLogError(event, input) + return e.Encounter{}, false, pl.SetLogError(event, i) } - if result.RowsAffected == 0 { - pl.SetLogInfo(event, input, "no previous data found to update") - return nil - } - - pl.SetLogInfo(event, nil, "complete") - return nil + return recentEncounterAdm, countEncounterSeries < int64(*recentEncounterAdm.Rehab.AllocatedVisitCount), nil } diff --git a/internal/use-case/main-use-case/nurse/helper.go b/internal/use-case/main-use-case/nurse/helper.go index 003230b3..49078088 100644 --- a/internal/use-case/main-use-case/nurse/helper.go +++ b/internal/use-case/main-use-case/nurse/helper.go @@ -20,6 +20,6 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Nurse) { data.Code = inputSrc.Code data.Employee_Id = inputSrc.Employee_Id data.IHS_Number = inputSrc.IHS_Number - data.Unit_Id = inputSrc.Unit_Id - data.Infra_Id = inputSrc.Infra_Id + data.Unit_Code = inputSrc.Unit_Code + data.Infra_Code = inputSrc.Infra_Code } diff --git a/internal/use-case/main-use-case/prescription/helper.go b/internal/use-case/main-use-case/prescription/helper.go index 35c55512..92fd4531 100644 --- a/internal/use-case/main-use-case/prescription/helper.go +++ b/internal/use-case/main-use-case/prescription/helper.go @@ -38,7 +38,7 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Prescription) { data.Encounter_Id = inputSrc.Encounter_Id // data.Doctor_Id = inputSrc.Doctor_Id - data.Doctor_Id = inputSrc.AuthInfo.Doctor_Id + data.Doctor_Code = inputSrc.AuthInfo.Doctor_Code data.IssuedAt = inputSrc.IssuedAt } diff --git a/internal/use-case/main-use-case/rehab/case.go b/internal/use-case/main-use-case/rehab/case.go new file mode 100644 index 00000000..0d7a243e --- /dev/null +++ b/internal/use-case/main-use-case/rehab/case.go @@ -0,0 +1,275 @@ +package rehab + +import ( + e "simrs-vx/internal/domain/main-entities/rehab" + "strconv" + + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + d "github.com/karincake/dodol" + "gorm.io/gorm" +) + +const source = "rehab" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Rehab{} + + 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.Rehab + var dataList []e.Rehab + 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 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), + "record_currentCount": strconv.Itoa(len(dataList)), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Rehab + 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.Rehab + 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.Rehab + 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/rehab/helper.go b/internal/use-case/main-use-case/rehab/helper.go new file mode 100644 index 00000000..5c06ca0a --- /dev/null +++ b/internal/use-case/main-use-case/rehab/helper.go @@ -0,0 +1,23 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package rehab + +import ( + e "simrs-vx/internal/domain/main-entities/rehab" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Rehab) { + 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.Doctor_Id = inputSrc.Doctor_Id + data.AllocatedVisitCount = inputSrc.AllocatedVisitCount +} diff --git a/internal/use-case/main-use-case/rehab/lib.go b/internal/use-case/main-use-case/rehab/lib.go new file mode 100644 index 00000000..faee1b35 --- /dev/null +++ b/internal/use-case/main-use-case/rehab/lib.go @@ -0,0 +1,144 @@ +package rehab + +import ( + "errors" + e "simrs-vx/internal/domain/main-entities/rehab" + plh "simrs-vx/pkg/lib-helper" + 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.Rehab, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Rehab{} + 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 { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Rehab, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.Rehab{} + pagination := gh.Pagination{} + count := int64(0) + meta := e.MetaDto{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + tx = tx. + Model(&e.Rehab{}). + Scopes(gh.Preload(input.Includes)). + Scopes(gh.Filter(input.FilterDto)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Find(&data).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, &meta, nil + } + return nil, nil, plh.HandleListError(input, event, err) + } + + 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.Rehab, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.Rehab{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx. + Scopes(gh.Preload(input.Includes)). + 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.Rehab, 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.Rehab, 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/rehab/middleware-runner.go b/internal/use-case/main-use-case/rehab/middleware-runner.go new file mode 100644 index 00000000..8c0af77a --- /dev/null +++ b/internal/use-case/main-use-case/rehab/middleware-runner.go @@ -0,0 +1,103 @@ +package rehab + +import ( + e "simrs-vx/internal/domain/main-entities/rehab" + 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.Rehab) 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.Rehab) 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.Rehab) 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.Rehab) 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.Rehab) 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/rehab/middleware.go b/internal/use-case/main-use-case/rehab/middleware.go new file mode 100644 index 00000000..dadf6b9b --- /dev/null +++ b/internal/use-case/main-use-case/rehab/middleware.go @@ -0,0 +1,9 @@ +package rehab + +// 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/rehab/tycovar.go b/internal/use-case/main-use-case/rehab/tycovar.go new file mode 100644 index 00000000..4899ec44 --- /dev/null +++ b/internal/use-case/main-use-case/rehab/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 rehab + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/rehab" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Rehab, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Rehab, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Rehab, 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/responsible-doctor-hist/lib.go b/internal/use-case/main-use-case/responsible-doctor-hist/lib.go index d91294fe..3f035d5e 100644 --- a/internal/use-case/main-use-case/responsible-doctor-hist/lib.go +++ b/internal/use-case/main-use-case/responsible-doctor-hist/lib.go @@ -75,29 +75,18 @@ func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e pl.SetLogInfo(event, input, "started", "DBReadDetail") data := e.ResponsibleDoctorHist{} - var tx, getData *gorm.DB + var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] } else { tx = dg.I } - switch { - case input.Id != 0: - getData = tx.First(&data, input.Id) - case input.Code != nil && *input.Code != "": - getData = tx.Where("code = ?", *input.Code).First(&data) - default: - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-read-detail-fail", - Detail: "either Id or Code must be provided", - } + if err := tx. + Scopes(gh.Preload(input.Includes)). + First(&data, input.Id). + Error; err != nil { - return nil, pl.SetLogError(event, nil) - } - - if err := getData.Error; err != nil { if processedErr := pu.HandleReadError(err, event, source, input.Id, data); processedErr != nil { return nil, processedErr } diff --git a/internal/use-case/main-use-case/soapi/helper.go b/internal/use-case/main-use-case/soapi/helper.go index 5a94848a..ae396270 100644 --- a/internal/use-case/main-use-case/soapi/helper.go +++ b/internal/use-case/main-use-case/soapi/helper.go @@ -23,3 +23,19 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Soapi) { data.TypeCode = inputSrc.TypeCode data.Value = inputSrc.Value } + +func setBulkData(input []e.CreateDto, encounterId uint) []e.Soapi { + var data []e.Soapi + + for _, v := range input { + data = append(data, e.Soapi{ + Encounter_Id: &encounterId, + Employee_Id: v.Employee_Id, + Time: v.Time, + TypeCode: v.TypeCode, + Value: v.Value, + }) + } + + return data +} diff --git a/internal/use-case/main-use-case/soapi/lib.go b/internal/use-case/main-use-case/soapi/lib.go index 7e551505..57bb5d23 100644 --- a/internal/use-case/main-use-case/soapi/lib.go +++ b/internal/use-case/main-use-case/soapi/lib.go @@ -138,3 +138,23 @@ func DeleteData(data *e.Soapi, event *pl.Event, dbx ...*gorm.DB) error { pl.SetLogInfo(event, nil, "complete") return nil } + +func CreateBulkData(input []e.CreateDto, encounterId uint, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := setBulkData(input, encounterId) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/main-use-case/specialist-intern/helper.go b/internal/use-case/main-use-case/specialist-intern/helper.go index 36b989d8..91bd2afc 100644 --- a/internal/use-case/main-use-case/specialist-intern/helper.go +++ b/internal/use-case/main-use-case/specialist-intern/helper.go @@ -18,7 +18,7 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.SpecialistIntern) { } data.Person_Id = inputSrc.Person_Id - data.Specialist_Id = inputSrc.Specialist_Id - data.Subspecialist_Id = inputSrc.Subspecialist_Id + data.Specialist_Code = inputSrc.Specialist_Code + data.Subspecialist_Code = inputSrc.Subspecialist_Code data.User_Id = inputSrc.User_Id } diff --git a/internal/use-case/main-use-case/therapy-protocol/case.go b/internal/use-case/main-use-case/therapy-protocol/case.go new file mode 100644 index 00000000..93cf05a4 --- /dev/null +++ b/internal/use-case/main-use-case/therapy-protocol/case.go @@ -0,0 +1,310 @@ +package therapy_protocol + +import ( + "strconv" + + "gorm.io/gorm" + + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + d "github.com/karincake/dodol" + + ed "simrs-vx/internal/domain/main-entities/doctor" + ee "simrs-vx/internal/domain/main-entities/encounter" + e "simrs-vx/internal/domain/main-entities/therapy-protocol" + + ud "simrs-vx/internal/use-case/main-use-case/doctor" + ue "simrs-vx/internal/use-case/main-use-case/encounter" +) + +const source = "therapy-protocol" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.TherapyProtocol{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + // validate foreign key + if err := validateForeignKey(input); err != nil { + return nil, err + } + + 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.TherapyProtocol + var dataList []e.TherapyProtocol + 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 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), + "record_currentCount": strconv.Itoa(len(dataList)), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.TherapyProtocol + 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.TherapyProtocol + var err error + + event := pl.Event{ + Feature: "Update", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "update") + + // validate foreign key + if err := validateForeignKey(input.CreateDto); err != nil { + return nil, err + } + + err = dg.I.Transaction(func(tx *gorm.DB) error { + pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err + } + + 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.TherapyProtocol + 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 validateForeignKey(input e.CreateDto) error { + // validate encounter + if input.Encounter_Id != nil { + if _, err := ue.ReadDetail(ee.ReadDetailDto{Id: uint16(*input.Encounter_Id)}); err != nil { + return err + } + } + + // validate doctor_id + if input.Doctor_Id != nil { + if _, err := ud.ReadDetail(ed.ReadDetailDto{Id: uint16(*input.Doctor_Id)}); err != nil { + return err + } + } + + return nil +} diff --git a/internal/use-case/main-use-case/therapy-protocol/helper.go b/internal/use-case/main-use-case/therapy-protocol/helper.go new file mode 100644 index 00000000..12e48747 --- /dev/null +++ b/internal/use-case/main-use-case/therapy-protocol/helper.go @@ -0,0 +1,34 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package therapy_protocol + +import ( + e "simrs-vx/internal/domain/main-entities/therapy-protocol" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.TherapyProtocol) { + 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.Doctor_Id = inputSrc.Doctor_Id + data.Anamnesis = inputSrc.Anamnesis + data.MedicalDiagnoses = inputSrc.MedicalDiagnoses + data.FunctionDiagnoses = inputSrc.FunctionDiagnoses + data.Procedures = inputSrc.Procedures + data.SupportingExams = inputSrc.SupportingExams + data.Instruction = inputSrc.Instruction + data.Evaluation = inputSrc.Evaluation + data.WorkCauseStatus = inputSrc.WorkCauseStatus + data.Frequency = inputSrc.Frequency + data.IntervalUnit_Code = inputSrc.IntervalUnit_Code + data.Duration = inputSrc.Duration + data.DurationUnit_Code = inputSrc.DurationUnit_Code +} diff --git a/internal/use-case/main-use-case/therapy-protocol/lib.go b/internal/use-case/main-use-case/therapy-protocol/lib.go new file mode 100644 index 00000000..550ef327 --- /dev/null +++ b/internal/use-case/main-use-case/therapy-protocol/lib.go @@ -0,0 +1,145 @@ +package therapy_protocol + +import ( + "errors" + e "simrs-vx/internal/domain/main-entities/therapy-protocol" + + plh "simrs-vx/pkg/lib-helper" + 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.TherapyProtocol, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.TherapyProtocol{} + 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 { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.TherapyProtocol, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.TherapyProtocol{} + pagination := gh.Pagination{} + count := int64(0) + meta := e.MetaDto{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + tx = tx. + Model(&e.TherapyProtocol{}). + Scopes(gh.Preload(input.Includes)). + Scopes(gh.Filter(input.FilterDto)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Find(&data).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, &meta, nil + } + return nil, nil, plh.HandleListError(input, event, err) + } + + 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.TherapyProtocol, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.TherapyProtocol{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx. + Scopes(gh.Preload(input.Includes)). + 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.TherapyProtocol, 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.TherapyProtocol, 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/therapy-protocol/middleware-runner.go b/internal/use-case/main-use-case/therapy-protocol/middleware-runner.go new file mode 100644 index 00000000..4391b63a --- /dev/null +++ b/internal/use-case/main-use-case/therapy-protocol/middleware-runner.go @@ -0,0 +1,103 @@ +package therapy_protocol + +import ( + e "simrs-vx/internal/domain/main-entities/therapy-protocol" + 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.TherapyProtocol) 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.TherapyProtocol) 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.TherapyProtocol) 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.TherapyProtocol) 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.TherapyProtocol) 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/therapy-protocol/middleware.go b/internal/use-case/main-use-case/therapy-protocol/middleware.go new file mode 100644 index 00000000..a2f3626f --- /dev/null +++ b/internal/use-case/main-use-case/therapy-protocol/middleware.go @@ -0,0 +1,9 @@ +package therapy_protocol + +// 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/therapy-protocol/tycovar.go b/internal/use-case/main-use-case/therapy-protocol/tycovar.go new file mode 100644 index 00000000..a027e334 --- /dev/null +++ b/internal/use-case/main-use-case/therapy-protocol/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 therapy_protocol + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/therapy-protocol" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.TherapyProtocol, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.TherapyProtocol, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.TherapyProtocol, 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/user/case.go b/internal/use-case/main-use-case/user/case.go index 8e452e62..7c66b153 100644 --- a/internal/use-case/main-use-case/user/case.go +++ b/internal/use-case/main-use-case/user/case.go @@ -87,10 +87,10 @@ func Create(input e.CreateDto) (*d.Data, error) { if input.ContractPosition_Code == ero.CSCInt { createInt := esi.CreateDto{ - Person_Id: input.Person_Id, - Specialist_Id: input.Specialist_Id, - Subspecialist_Id: input.Subspecialist_Id, - User_Id: &data.Id, + Person_Id: input.Person_Id, + Specialist_Code: input.Specialist_Code, + Subspecialist_Code: input.Subspecialist_Code, + User_Id: &data.Id, } if _, err := usi.CreateData(createInt, &event, tx); err != nil { return err @@ -108,13 +108,13 @@ func Create(input e.CreateDto) (*d.Data, error) { switch input.Employee.Position_Code { case ero.EPCDoc: createDoc := ed.CreateDto{ - Code: input.Code, - Employee_Id: &employeeData.Id, - IHS_Number: input.IHS_Number, - SIP_Number: input.SIP_Number, - Unit_Id: input.Unit_Id, - Specialist_Id: input.Specialist_Id, - Subspecialist_Id: input.Subspecialist_Id, + Code: input.Code, + Employee_Id: &employeeData.Id, + IHS_Number: input.IHS_Number, + SIP_Number: input.SIP_Number, + Unit_Code: input.Unit_Code, + Specialist_Code: input.Specialist_Code, + Subspecialist_Code: input.Subspecialist_Code, } if _, err := ud.CreateData(createDoc, &event, tx); err != nil { return err @@ -124,8 +124,8 @@ func Create(input e.CreateDto) (*d.Data, error) { Code: input.Code, Employee_Id: &employeeData.Id, IHS_Number: input.IHS_Number, - Unit_Id: input.Unit_Id, - Infra_Id: input.Infra_Id, + Unit_Code: input.Unit_Code, + Infra_Code: input.Infra_Code, } if _, err := un.CreateData(createNurse, &event, tx); err != nil { return err @@ -359,10 +359,10 @@ func Update(input e.UpdateDto) (*d.Data, error) { return err } createInt := esi.CreateDto{ - User_Id: &data.Id, - Person_Id: input.Person_Id, - Specialist_Id: input.Specialist_Id, - Subspecialist_Id: input.Subspecialist_Id, + User_Id: &data.Id, + Person_Id: input.Person_Id, + Specialist_Code: input.Specialist_Code, + Subspecialist_Code: input.Subspecialist_Code, } if readIntData != nil { if err := usi.UpdateData(esi.UpdateDto{CreateDto: createInt}, readIntData, &event, tx); err != nil { @@ -396,11 +396,13 @@ func Update(input e.UpdateDto) (*d.Data, error) { return err } createDoc := ed.CreateDto{ - Code: input.Code, - Employee_Id: &employeeData.Id, - IHS_Number: input.IHS_Number, - SIP_Number: input.SIP_Number, - Unit_Id: input.Unit_Id, + Code: input.Code, + Employee_Id: &employeeData.Id, + IHS_Number: input.IHS_Number, + SIP_Number: input.SIP_Number, + Unit_Code: input.Unit_Code, + Specialist_Code: input.Specialist_Code, + Subspecialist_Code: input.Subspecialist_Code, } if readDocData != nil { if err := ud.UpdateData(ed.UpdateDto{CreateDto: createDoc}, readDocData, &event, tx); err != nil { @@ -422,6 +424,8 @@ func Update(input e.UpdateDto) (*d.Data, error) { Code: input.Code, Employee_Id: &employeeData.Id, IHS_Number: input.IHS_Number, + Unit_Code: input.Unit_Code, + Infra_Code: input.Infra_Code, } if readNurData != nil { if err := un.UpdateData(en.UpdateDto{CreateDto: createNur}, readNurData, &event, tx); err != nil { diff --git a/internal/use-case/simgos-sync-case/.keep b/internal/use-case/simgos-sync-use-case/.keep similarity index 100% rename from internal/use-case/simgos-sync-case/.keep rename to internal/use-case/simgos-sync-use-case/.keep diff --git a/pkg/use-case-helper/use-case-helper.go b/pkg/use-case-helper/use-case-helper.go index 0df8fe3e..a80595bb 100644 --- a/pkg/use-case-helper/use-case-helper.go +++ b/pkg/use-case-helper/use-case-helper.go @@ -143,3 +143,10 @@ func GetTimeNow() *time.Time { tmp := time.Now() return &tmp } + +func IsDateBeforeNow(t *time.Time) bool { + if t == nil { + return false + } + return t.Before(time.Now()) +}