diff --git a/.gitignore b/.gitignore index 4c10eb38..7800ac94 100644 --- a/.gitignore +++ b/.gitignore @@ -27,8 +27,6 @@ go.work.sum # env file .env config.yml -Dockerfile-main-api -Dockerfile-sync-api **/atlas.hcl !**/atlas.hcl.example diff --git a/Dockerfile-main-api-example b/Dockerfile-main-api similarity index 89% rename from Dockerfile-main-api-example rename to Dockerfile-main-api index cb8839b9..2037fec7 100644 --- a/Dockerfile-main-api-example +++ b/Dockerfile-main-api @@ -7,7 +7,7 @@ RUN CGO_ENABLED=0 GOOS=linux go build -o ./cmd/main-api/main-api ./cmd/main-api/ FROM alpine:latest WORKDIR /app -COPY --from=builder /src/assets . +COPY --from=builder /src/assets ./assets COPY --from=builder /src/cmd/main-api/main-api . COPY --from=builder /src/cmd/main-api/config.yml . EXPOSE 8010 diff --git a/Dockerfile-sync-api b/Dockerfile-sync-api new file mode 100644 index 00000000..2a66ceb8 --- /dev/null +++ b/Dockerfile-sync-api @@ -0,0 +1,14 @@ +FROM golang:1.24.10 AS builder +WORKDIR /src +COPY go.mod go.sum ./ +RUN go mod download +COPY . . +RUN CGO_ENABLED=0 GOOS=linux go build -o ./cmd/sync-api/sync-api ./cmd/sync-api/main.go + +FROM alpine:latest +WORKDIR /app +COPY --from=builder /src/assets ./assets +COPY --from=builder /src/cmd/sync-api/sync-api . +COPY --from=builder /src/cmd/sync-api/config.yml . +EXPOSE 8011 +CMD ["./sync-api"] diff --git a/Dockerfile-sync-api-example b/Dockerfile-sync-api-example deleted file mode 100644 index 5b32d522..00000000 --- a/Dockerfile-sync-api-example +++ /dev/null @@ -1,14 +0,0 @@ -FROM golang:1.24.10 AS builder -WORKDIR /src -COPY go.mod go.sum ./ -RUN go mod download -COPY . . -RUN CGO_ENABLED=0 GOOS=linux go build -o ./cmd/simgos-sync-api/simgos-sync-api ./cmd/simgos-sync-api/main.go - -FROM alpine:latest -WORKDIR /app -COPY --from=builder /src/assets . -COPY --from=builder /src/cmd/simgos-sync-api/simgos-sync-api . -COPY --from=builder /src/cmd/simgos-sync-api/config.yml . -EXPOSE 8011 -CMD ["./simgos-sync-api"] diff --git a/assets/docs/resume.html b/assets/docs/resume.html index 4ad209ff..8715f1ba 100644 --- a/assets/docs/resume.html +++ b/assets/docs/resume.html @@ -627,17 +627,17 @@ Fasyankes : - {{ .NIK }} + {{ .ControlHealthcare }} Tanggal : - {{ .NIK }} + {{ .ControlDate }} Klinik : - {{ .NIK }} + {{ .ControlUnit }} diff --git a/cmd/simgos-sync-api/config.yml-example b/cmd/sync-api/config.yml-example similarity index 100% rename from cmd/simgos-sync-api/config.yml-example rename to cmd/sync-api/config.yml-example diff --git a/cmd/simgos-sync-api/main.go b/cmd/sync-api/main.go similarity index 100% rename from cmd/simgos-sync-api/main.go rename to cmd/sync-api/main.go diff --git a/cmd/simgos-sync-migration/Makefile b/cmd/sync-migration/Makefile similarity index 100% rename from cmd/simgos-sync-migration/Makefile rename to cmd/sync-migration/Makefile diff --git a/cmd/simgos-sync-migration/README-ATLAS.MD b/cmd/sync-migration/README-ATLAS.MD similarity index 100% rename from cmd/simgos-sync-migration/README-ATLAS.MD rename to cmd/sync-migration/README-ATLAS.MD diff --git a/cmd/simgos-sync-migration/atlas.hcl.example b/cmd/sync-migration/atlas.hcl.example similarity index 100% rename from cmd/simgos-sync-migration/atlas.hcl.example rename to cmd/sync-migration/atlas.hcl.example diff --git a/cmd/simgos-sync-migration/migration.go b/cmd/sync-migration/migration.go similarity index 100% rename from cmd/simgos-sync-migration/migration.go rename to cmd/sync-migration/migration.go diff --git a/cmd/simgos-sync-migration/migrations/20251113035508.sql b/cmd/sync-migration/migrations/20251113035508.sql similarity index 100% rename from cmd/simgos-sync-migration/migrations/20251113035508.sql rename to cmd/sync-migration/migrations/20251113035508.sql diff --git a/cmd/simgos-sync-migration/migrations/20251114071129.sql b/cmd/sync-migration/migrations/20251114071129.sql similarity index 100% rename from cmd/simgos-sync-migration/migrations/20251114071129.sql rename to cmd/sync-migration/migrations/20251114071129.sql diff --git a/cmd/simgos-sync-migration/migrations/20251117041601.sql b/cmd/sync-migration/migrations/20251117041601.sql similarity index 100% rename from cmd/simgos-sync-migration/migrations/20251117041601.sql rename to cmd/sync-migration/migrations/20251117041601.sql diff --git a/cmd/simgos-sync-migration/migrations/20251118082246.sql b/cmd/sync-migration/migrations/20251118082246.sql similarity index 100% rename from cmd/simgos-sync-migration/migrations/20251118082246.sql rename to cmd/sync-migration/migrations/20251118082246.sql diff --git a/cmd/simgos-sync-migration/migrations/20251118082915.sql b/cmd/sync-migration/migrations/20251118082915.sql similarity index 100% rename from cmd/simgos-sync-migration/migrations/20251118082915.sql rename to cmd/sync-migration/migrations/20251118082915.sql diff --git a/cmd/simgos-sync-migration/migrations/20251126115527.sql b/cmd/sync-migration/migrations/20251126115527.sql similarity index 100% rename from cmd/simgos-sync-migration/migrations/20251126115527.sql rename to cmd/sync-migration/migrations/20251126115527.sql diff --git a/cmd/simgos-sync-migration/migrations/20251201093443.sql b/cmd/sync-migration/migrations/20251201093443.sql similarity index 100% rename from cmd/simgos-sync-migration/migrations/20251201093443.sql rename to cmd/sync-migration/migrations/20251201093443.sql diff --git a/cmd/simgos-sync-migration/migrations/20251209083238.sql b/cmd/sync-migration/migrations/20251209083238.sql similarity index 100% rename from cmd/simgos-sync-migration/migrations/20251209083238.sql rename to cmd/sync-migration/migrations/20251209083238.sql diff --git a/cmd/simgos-sync-migration/migrations/atlas.sum b/cmd/sync-migration/migrations/atlas.sum similarity index 100% rename from cmd/simgos-sync-migration/migrations/atlas.sum rename to cmd/sync-migration/migrations/atlas.sum diff --git a/go.mod b/go.mod index c395bd8f..74ce299b 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/jackc/pgx/v5 v5.5.5 github.com/karincake/apem v0.0.17 github.com/karincake/dodol v0.0.1 - github.com/karincake/getuk v0.3.1 + github.com/karincake/getuk v0.3.2 github.com/karincake/hongkue v0.0.4 github.com/karincake/lepet v0.0.1 github.com/karincake/risoles v0.0.3 diff --git a/go.sum b/go.sum index da70ac51..088ad636 100644 --- a/go.sum +++ b/go.sum @@ -81,8 +81,8 @@ github.com/karincake/apem v0.0.17 h1:y3WXCr9GWLFFFH4Qyq/VWlWWpijHh5zpTc3Lm96twa4 github.com/karincake/apem v0.0.17/go.mod h1:cQP2sJfDrLRIiwWoaLWw/z8uAya+DWu/FpmYeinMQXM= github.com/karincake/dodol v0.0.1 h1:jUXmJh1r0Ei4fmHPZ6IUkoplW/V9d27L63JEl6zudL0= github.com/karincake/dodol v0.0.1/go.mod h1:2f1NcvkvY0J3GMUkwILNDYVvRUpz0W3lpPp/Ha/Ld24= -github.com/karincake/getuk v0.3.1 h1:yRqBTrwpnjYcZD3gPDoSxFlsLgI9/GKCr3ZCsS4TtYQ= -github.com/karincake/getuk v0.3.1/go.mod h1:NVnvxSGAkQ/xuq99FzWACvY5efyKPLFla1cKB8czm7c= +github.com/karincake/getuk v0.3.2 h1:Qe+PRQ2qdgdiJlWiVEq37N8rrgS654nUnY0PWS6pMzA= +github.com/karincake/getuk v0.3.2/go.mod h1:nFl133aKQqxRbe5q9lo8q7BxlYBavmbkpglBhq/dNWk= github.com/karincake/hongkue v0.0.4 h1:oWthq6cDg5DvDm1Z3e7mCLOATQf+oAdtHxN9OPnCfA8= github.com/karincake/hongkue v0.0.4/go.mod h1:YVi5Lyh3DE+GRHx2OSODOr7FwvLi8U4idvcPHO7yeag= github.com/karincake/lepet v0.0.1 h1:eq/cwn5BBg0jWZ1c/MmvhFIBma0zBpVs2LwkfDOncy4= diff --git a/internal/domain/bpjs-entities/vclaim-sep-control-letter/dto.go b/internal/domain/bpjs-entities/vclaim-sep-control-letter/dto.go index 1974e66c..516fb131 100644 --- a/internal/domain/bpjs-entities/vclaim-sep-control-letter/dto.go +++ b/internal/domain/bpjs-entities/vclaim-sep-control-letter/dto.go @@ -40,8 +40,9 @@ type UpdateDto struct { } type DeleteDto struct { - Id uint `json:"id"` - Number *string `json:"number"` + Id uint `json:"id"` + Number *string `json:"number"` + RequestPayload string `json:"requestPayload" validate:"maxLength=1024"` } type MetaDto struct { @@ -52,10 +53,11 @@ type MetaDto struct { type ResponseDto struct { ecore.Main - VclaimSep_Number *string `json:"vclaimSep_number"` - Number *string `json:"number"` - Value *string `json:"value"` - FileUrl *string `json:"fileUrl"` + VclaimSep_Number *string `json:"vclaimSep_number"` + Number *string `json:"number"` + Value *string `json:"value"` + FileUrl *string `json:"fileUrl"` + Detail *FullResponse `json:"detail,omitempty"` } func (d VclaimSepControlLetter) ToResponse() ResponseDto { @@ -64,6 +66,7 @@ func (d VclaimSepControlLetter) ToResponse() ResponseDto { Number: d.Number, Value: d.Value, FileUrl: d.FileUrl, + Detail: d.Detail, } resp.Main = d.Main return resp @@ -77,6 +80,15 @@ func ToResponseList(data []VclaimSepControlLetter) []ResponseDto { return resp } +func (d DeleteDto) RequestPayloadIntoJson() ([]byte, error) { + payload := map[string]interface{}{} + err := json.Unmarshal([]byte(d.RequestPayload), &payload) + if err != nil { + return nil, err + } + return json.Marshal(payload) +} + func (c CreateDto) RequestPayloadIntoJson() ([]byte, error) { payload := map[string]interface{}{} err := json.Unmarshal([]byte(c.RequestPayload), &payload) @@ -122,3 +134,154 @@ func (v ResponseForPDF) GenerateBirthDate() string { t, _ := time.Parse("2006-01-02", v.VclaimSep.VclaimMember.BirthDate) return pu.FormatIndonesianDate(t) } + +type SuratKontrol struct { + NoSuratKontrol string `json:"noSuratKontrol"` + TglRencanaKontrol string `json:"tglRencanaKontrol"` + TglTerbit string `json:"tglTerbit"` + JnsKontrol string `json:"jnsKontrol"` + PoliTujuan string `json:"poliTujuan"` + NamaPoliTujuan string `json:"namaPoliTujuan"` + KodeDokter string `json:"kodeDokter"` + NamaDokter string `json:"namaDokter"` + FlagKontrol string `json:"flagKontrol"` + KodeDokterPembuat *string `json:"kodeDokterPembuat"` + NamaDokterPembuat *string `json:"namaDokterPembuat"` + NamaJnsKontrol string `json:"namaJnsKontrol"` + Sep Sep `json:"sep"` +} + +type Sep struct { + NoSep string `json:"noSep"` + TglSep string `json:"tglSep"` + JnsPelayanan string `json:"jnsPelayanan"` + Poli string `json:"poli"` + Diagnosa string `json:"diagnosa"` + Peserta Peserta `json:"peserta"` + ProvUmum ProvUmum `json:"provUmum"` + ProvPerujuk ProvPerujuk `json:"provPerujuk"` +} + +type Peserta struct { + NoKartu string `json:"noKartu"` + Nama string `json:"nama"` + TglLahir string `json:"tglLahir"` + Kelamin string `json:"kelamin"` + HakKelas string `json:"hakKelas"` +} + +type ProvUmum struct { + KdProvider string `json:"kdProvider"` + NmProvider string `json:"nmProvider"` +} + +type ProvPerujuk struct { + KdProviderPerujuk string `json:"kdProviderPerujuk"` + NmProviderPerujuk string `json:"nmProviderPerujuk"` + AsalRujukan string `json:"asalRujukan"` + NoRujukan string `json:"noRujukan"` + TglRujukan string `json:"tglRujukan"` +} + +type VclaimResponse struct { + MetaData MetaData `json:"metaData"` + Response *SuratKontrol `json:"response"` // nullable +} + +type DetailVclaimResponse struct { + MetaData MetaData `json:"metaData"` + Response *FullResponse `json:"response"` // nullable +} + +type MetaData struct { + Code string `json:"code"` + Message string `json:"message"` +} + +func (r VclaimResponse) ToPDFNeeds() ([]byte, error) { + response := ResponseForPDF{ + Number: r.Response.Sep.NoSep, + PlannedControlDate: r.Response.TglRencanaKontrol, + IssuedDate: r.Response.TglTerbit, + Doctor_Name: r.Response.NamaDokter, + DstUnit_Name: r.Response.NamaPoliTujuan, + ResponsibleDoctor_Name: *r.Response.NamaDokterPembuat, + VclaimSep: VclaimSep{ + VclaimMember: VclaimMember{ + CardNumber: r.Response.Sep.Peserta.NoKartu, + Name: r.Response.Sep.Peserta.Nama, + BirthDate: r.Response.Sep.Peserta.TglLahir, + Gender: r.Response.Sep.Peserta.Kelamin, + }, + Diagnose: r.Response.Sep.Diagnosa, + Number: r.Response.Sep.NoSep, + }, + } + return json.Marshal(response) +} + +type FullResponse struct { + NoSuratKontrol string `json:"noSuratKontrol"` + TglRencanaKontrol string `json:"tglRencanaKontrol"` + TglTerbit string `json:"tglTerbit"` + JnsKontrol string `json:"jnsKontrol"` + PoliTujuan string `json:"poliTujuan"` + NamaPoliTujuan string `json:"namaPoliTujuan"` + KodeDokter string `json:"kodeDokter"` + NamaDokter string `json:"namaDokter"` + FlagKontrol string `json:"flagKontrol"` + KodeDokterPembuat string `json:"kodeDokterPembuat"` + NamaDokterPembuat string `json:"namaDokterPembuat"` + NamaJnsKontrol string `json:"namaJnsKontrol"` + Sep Sep `json:"sep"` + FormPRB FormPRB `json:"formPRB"` +} + +type Provider struct { + KdProvider string `json:"kdProvider"` + NmProvider string `json:"nmProvider"` +} + +type FormPRB struct { + KdStatusPRB *string `json:"kdStatusPRB"` + Data PRBData `json:"data"` +} + +type PRBData struct { + HBA1C *string `json:"HBA1C"` + GDP *string `json:"GDP"` + GD2JPP *string `json:"GD2JPP"` + EGFR *string `json:"eGFR"` + TD_Sistolik *string `json:"TD_Sistolik"` + TD_Diastolik *string `json:"TD_Diastolik"` + LDL *string `json:"LDL"` + Rata_TD_Sistolik *string `json:"Rata_TD_Sistolik"` + Rata_TD_Diastolik *string `json:"Rata_TD_Diastolik"` + JantungKoroner *string `json:"JantungKoroner"` + Stroke *string `json:"Stroke"` + VaskularPerifer *string `json:"VaskularPerifer"` + Aritmia *string `json:"Aritmia"` + AtrialFibrilasi *string `json:"AtrialFibrilasi"` + SesakNapas3Bulan *string `json:"SesakNapas3Bulan"` + NyeriDada3Bulan *string `json:"NyeriDada3Bulan"` + Terkontrol *string `json:"Terkontrol"` + Gejala2xMinggu *string `json:"Gejala2xMinggu"` + BangunMalam *string `json:"BangunMalam"` + KeterbatasanFisik *string `json:"KeterbatasanFisik"` + FungsiParu *string `json:"FungsiParu"` + SkorMMRC *string `json:"SkorMMRC"` + Eksaserbasi1Tahun *string `json:"Eksaserbasi1Tahun"` + MampuAktivitas *string `json:"MampuAktivitas"` + Epileptik6Bulan *string `json:"Epileptik6Bulan"` + EfekSampingOAB *string `json:"EfekSampingOAB"` + HamilMenyusui *string `json:"HamilMenyusui"` + Remisi *string `json:"Remisi"` + TerapiRumatan *string `json:"TerapiRumatan"` + Usia *string `json:"Usia"` + AsamUrat *string `json:"AsamUrat"` + RemisiSLE *string `json:"RemisiSLE"` + Hamil *string `json:"Hamil"` + NadiIstirahat *string `json:"NadiIstirahat"` + SesakNapasAktivitas *string `json:"SesakNapasAktivitas"` + NyeriDadaAktivitas *string `json:"NyeriDadaAktivitas"` +} diff --git a/internal/domain/bpjs-entities/vclaim-sep-control-letter/entity.go b/internal/domain/bpjs-entities/vclaim-sep-control-letter/entity.go index 57f758fb..8f5f65be 100644 --- a/internal/domain/bpjs-entities/vclaim-sep-control-letter/entity.go +++ b/internal/domain/bpjs-entities/vclaim-sep-control-letter/entity.go @@ -10,4 +10,6 @@ type VclaimSepControlLetter struct { Number *string `json:"number" gorm:"unique;size:20"` Value *string `json:"value"` FileUrl *string `json:"fileUrl" gorm:"unique;size:1024"` + + Detail *FullResponse `json:"detail,omitempty" gorm:"-"` } diff --git a/internal/domain/main-entities/chemo-plan/dto.go b/internal/domain/main-entities/chemo-plan/dto.go index b2c05a61..29f47a70 100644 --- a/internal/domain/main-entities/chemo-plan/dto.go +++ b/internal/domain/main-entities/chemo-plan/dto.go @@ -11,13 +11,14 @@ import ( ) type CreateDto struct { - Parent_Id *uint `json:"parent_id"` - SeriesNumber *uint16 `json:"seriesNumber"` - CycleNumber *uint `json:"cycleNumber"` - PlanDate *time.Time `json:"planDate"` - RealizationDate *time.Time `json:"realizationDate"` - Notes *string `json:"notes"` - Status ere.StatusProtocolChemo `json:"status"` + Parent_Id *uint `json:"parent_id"` + SeriesNumber *uint16 `json:"seriesNumber"` + CycleNumber *uint `json:"cycleNumber"` + PlanDate *time.Time `json:"planDate"` + RealizationDate *time.Time `json:"realizationDate"` + Notes *string `json:"notes"` + Status *ere.StatusProtocolChemo `json:"status"` + Encounter_Id *uint `json:"encounter_id"` } type ReadListDto struct { @@ -32,17 +33,27 @@ type FilterDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` + Id uint `json:"id"` Includes string `json:"includes"` } type UpdateDto struct { - Id uint16 `json:"id"` + Id uint `json:"id"` CreateDto } type DeleteDto struct { - Id uint16 `json:"id"` + Id uint `json:"id"` +} + +type FailDto struct { + Id uint `json:"id"` + Reasons string `json:"reasons" validate:"required"` +} +type FailReason struct { + Date *time.Time `json:"date"` + FailReason string `json:"failReason"` + Encounter_Id *uint `json:"encounter_id"` } type MetaDto struct { @@ -53,15 +64,15 @@ type MetaDto struct { type ResponseDto struct { ecore.Main - Parent_Id *uint `json:"parent_id"` // chemo.Id - Protocol_Id *uint `json:"protocol_id"` - SeriesNumber *uint16 `json:"seriesNumber"` // series ke - - CycleNumber *uint `json:"cycleNumber"` // cycle ke - - PlanDate *time.Time `json:"planDate"` - RealizationDate *time.Time `json:"realizationDate"` - Notes *string `json:"notes"` - Status ere.StatusProtocolChemo `json:"status"` - Reasons *string `json:"reasons"` + Parent_Id *uint `json:"parent_id"` // chemo.Id + Protocol_Id *uint `json:"protocol_id"` + SeriesNumber *uint16 `json:"seriesNumber"` // series ke - + CycleNumber *uint `json:"cycleNumber"` // cycle ke - + PlanDate *time.Time `json:"planDate"` + RealizationDate *time.Time `json:"realizationDate"` + Notes *string `json:"notes"` + Status *ere.StatusProtocolChemo `json:"status"` + Reasons *string `json:"reasons"` } func (d ChemoPlan) ToResponse() ResponseDto { diff --git a/internal/domain/main-entities/chemo-plan/entity.go b/internal/domain/main-entities/chemo-plan/entity.go index 1fef099e..3698039f 100644 --- a/internal/domain/main-entities/chemo-plan/entity.go +++ b/internal/domain/main-entities/chemo-plan/entity.go @@ -11,15 +11,15 @@ import ( type ChemoPlan struct { ecore.Main - Parent_Id *uint `json:"parent_id"` // chemo.Id - Protocol_Id *uint `json:"protocol_id"` - SeriesNumber *uint16 `json:"seriesNumber"` // series ke - - CycleNumber *uint `json:"cycleNumber"` // cycle ke - - PlanDate *time.Time `json:"planDate"` - RealizationDate *time.Time `json:"realizationDate"` - Notes *string `json:"notes"` - Status ere.StatusProtocolChemo `json:"status"` - Encounter_Id *uint `json:"encounter_id"` - Encounter *ee.Encounter `json:"encounter,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"` - Reasons *string `json:"reasons"` // json + Parent_Id *uint `json:"parent_id"` // chemo.Id + Protocol_Id *uint `json:"protocol_id"` + SeriesNumber *uint16 `json:"seriesNumber"` // series ke - + CycleNumber *uint `json:"cycleNumber"` // cycle ke - + PlanDate *time.Time `json:"planDate"` + RealizationDate *time.Time `json:"realizationDate"` + Notes *string `json:"notes"` + Status *ere.StatusProtocolChemo `json:"status"` + Encounter_Id *uint `json:"encounter_id"` + Encounter *ee.Encounter `json:"encounter,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"` + Reasons *string `json:"reasons"` // json } diff --git a/internal/domain/main-entities/chemo-protocol/dto.go b/internal/domain/main-entities/chemo-protocol/dto.go index 03ad0c10..7156b846 100644 --- a/internal/domain/main-entities/chemo-protocol/dto.go +++ b/internal/domain/main-entities/chemo-protocol/dto.go @@ -1,6 +1,8 @@ package chemo_protocol import ( + eus "simrs-vx/internal/domain/main-entities/user" + pa "simrs-vx/internal/lib/auth" // std "time" @@ -11,19 +13,25 @@ import ( ecore "simrs-vx/internal/domain/base-entities/core" ec "simrs-vx/internal/domain/main-entities/chemo" + ep "simrs-vx/internal/domain/main-entities/chemo-plan" ) type CreateDto struct { - Chemo_Id *uint `json:"chemo_id"` - Patient_Weight *float32 `json:"patient_weight"` - Patient_Height *float32 `json:"patient_height"` - Diagnoses *string `json:"diagnoses"` - Interval *uint `json:"interval"` - Cycle *uint `json:"cycle"` - Series *uint16 `json:"series"` - StartDate *time.Time `json:"startDate"` - EndDate *time.Time `json:"endDate"` - Status_Code erc.DataVerifiedCode `json:"-"` + Encounter_Id *uint `json:"encounter_id" validate:"required"` + Chemo_Id *uint `json:"chemo_id" validate:"required"` + Patient_Weight *float32 `json:"patient_weight"` + Patient_Height *float32 `json:"patient_height"` + Diagnoses *string `json:"diagnoses" validate:"required"` + Interval *uint `json:"interval" validate:"required"` + Cycle *uint `json:"cycle" validate:"required"` + Series *uint16 `json:"series" validate:"required"` + StartDate *time.Time `json:"startDate"` + EndDate *time.Time `json:"endDate"` + Patient_Id *uint `json:"patient_id"` + ChemoPlans *[]ep.CreateDto `json:"chemoPlans" validate:"required"` + + Id *uint `json:"-"` + Status_Code erc.DataVerifiedCode `json:"-"` } type ReadListDto struct { @@ -33,21 +41,29 @@ type ReadListDto struct { } type FilterDto struct { - Chemo_Id *uint `json:"chemo-id"` + Chemo_Id *uint `json:"chemo-id"` + Patient_Id *uint `json:"patient-id"` } type ReadDetailDto struct { - Id uint16 `json:"id"` + Id uint `json:"id"` Includes string `json:"includes"` } type UpdateDto struct { - Id uint16 `json:"id"` + Id uint `json:"id"` CreateDto } type DeleteDto struct { - Id uint16 `json:"id"` + Id uint `json:"id"` +} + +type VerifyDto struct { + Id uint `json:"id"` + Status_Code erc.DataVerifiedCode `json:"-"` + + pa.AuthInfo } type MetaDto struct { @@ -58,32 +74,42 @@ type MetaDto struct { type ResponseDto struct { ecore.Main - Chemo_Id *uint `json:"chemo_id"` - Chemo *ec.Chemo `json:"chemo,omitempty"` - Patient_Weight *float32 `json:"patient_weight"` - Patient_Height *float32 `json:"patient_height"` - Diagnoses *string `json:"diagnoses"` - Interval *uint `json:"interval"` - Cycle *uint `json:"cycle"` - Series *uint16 `json:"series"` - StartDate *time.Time `json:"startDate"` - EndDate *time.Time `json:"endDate"` - Status_Code erc.DataVerifiedCode `json:"status_code"` + Chemo_Id *uint `json:"chemo_id"` + Chemo *ec.Chemo `json:"chemo,omitempty"` + Patient_Weight *float32 `json:"patient_weight"` + Patient_Height *float32 `json:"patient_height"` + Diagnoses *string `json:"diagnoses"` + Interval *uint `json:"interval"` + Cycle *uint `json:"cycle"` + Series *uint16 `json:"series"` + StartDate *time.Time `json:"startDate"` + EndDate *time.Time `json:"endDate"` + Status_Code erc.DataVerifiedCode `json:"status_code"` + VerifiedAt *time.Time `json:"verifiedAt"` + VerifiedBy_User_Id *uint `json:"verifiedBy_user_id"` + VerifiedBy *eus.User `json:"verifiedBy,omitempty"` + ChemoPlans *[]ep.ChemoPlan `json:"chemoPlans,omitempty"` + Patient_Id *uint `json:"patient_id"` } func (d ChemoProtocol) ToResponse() ResponseDto { resp := ResponseDto{ - Chemo_Id: d.Chemo_Id, - Chemo: d.Chemo, - Patient_Weight: d.Patient_Weight, - Patient_Height: d.Patient_Height, - Diagnoses: d.Diagnoses, - Interval: d.Interval, - Cycle: d.Cycle, - Series: d.Series, - StartDate: d.StartDate, - EndDate: d.EndDate, - Status_Code: d.Status_Code, + Chemo_Id: d.Chemo_Id, + Chemo: d.Chemo, + Patient_Weight: d.Patient_Weight, + Patient_Height: d.Patient_Height, + Diagnoses: d.Diagnoses, + Interval: d.Interval, + Cycle: d.Cycle, + Series: d.Series, + StartDate: d.StartDate, + EndDate: d.EndDate, + Status_Code: d.Status_Code, + VerifiedAt: d.VerifiedAt, + VerifiedBy_User_Id: d.VerifiedBy_User_Id, + VerifiedBy: d.VerifiedBy, + ChemoPlans: d.ChemoPlans, + Patient_Id: d.Patient_Id, } resp.Main = d.Main return resp diff --git a/internal/domain/main-entities/chemo/dto.go b/internal/domain/main-entities/chemo/dto.go index fa3bd8a5..7a74acf6 100644 --- a/internal/domain/main-entities/chemo/dto.go +++ b/internal/domain/main-entities/chemo/dto.go @@ -3,6 +3,9 @@ package chemo import ( ed "simrs-vx/internal/domain/main-entities/doctor" es "simrs-vx/internal/domain/main-entities/specialist" + ere "simrs-vx/internal/domain/references/encounter" + + // std "time" // internal - lib @@ -21,6 +24,7 @@ type CreateDto struct { Encounter_Id *uint `json:"encounter_id"` Status_Code erc.DataVerifiedCode `json:"status_code"` Specialist_Code *string `json:"specialist_code"` + Class_Code ere.ChemoClassCode `json:"class_code"` } type ReadListDto struct { @@ -34,28 +38,32 @@ type FilterDto struct { Status_Code *erc.DataVerifiedCode `json:"status-code"` VerifiedBy_User_Id *uint `json:"verifiedBy-user-id"` Specialist_Code *string `json:"specialist-code"` + Patient_Id *uint `json:"patient-id"` + Class_Code ere.ChemoClassCode `json:"class-code"` } type ReadDetailDto struct { - Id uint16 `json:"id"` + Id uint `json:"id"` + Includes string `json:"includes"` + FilterDto } type UpdateDto struct { - Id uint16 `json:"id"` + Id uint `json:"id"` CreateDto } type DeleteDto struct { - Id uint16 `json:"id"` + Id uint `json:"id"` } type VerifyDto struct { - Id uint16 `json:"id"` + Id uint `json:"id"` Status_Code erc.DataVerifiedCode `json:"status_code"` Bed *string `json:"bed"` Needs *string `json:"needs"` Doctor_Code *string `json:"doctor_code" validate:"required"` - NextChemoDate *time.Time `json:"nextChemoDate"` + NextChemoDate *time.Time `json:"nextChemoDate" validate:"required"` pa.AuthInfo } diff --git a/internal/domain/main-entities/doctor/dto.go b/internal/domain/main-entities/doctor/dto.go index 9bcbc932..4a8901a5 100644 --- a/internal/domain/main-entities/doctor/dto.go +++ b/internal/domain/main-entities/doctor/dto.go @@ -26,14 +26,15 @@ 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"` - SIP_ExpiredDate *string `json:"sip-expiredDate"` - Unit_Code *string `json:"unit-code"` - Specialist_Code *string `json:"specialist-code"` - Subspecialist_Code *string `json:"subspecialist-code"` + 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"` + Specialist_Code_Opt *string `json:"specialist-code-opt"` + Subspecialist_Code *string `json:"subspecialist-code"` } type ReadDetailDto struct { diff --git a/internal/domain/main-entities/encounter/dto.go b/internal/domain/main-entities/encounter/dto.go index 5dcf76db..b6072a68 100644 --- a/internal/domain/main-entities/encounter/dto.go +++ b/internal/domain/main-entities/encounter/dto.go @@ -105,6 +105,7 @@ type FilterDto struct { RegisteredAt *time.Time `json:"registeredAt"` Class_Code ere.EncounterClassCode `json:"class-code" validate:"maxLength=10"` Specialist_Code *string `json:"specialist-code"` + Specialist_Code_Opt *string `json:"specialist-code-opt"` Subspecialist_Code *string `json:"subspecialist-code"` VisitDate time.Time `json:"visitDate"` Appoinment_Doctor_Code *string `json:"appointment-doctor-code"` @@ -116,6 +117,7 @@ type FilterDto struct { MedicalDischargeEducation *string `json:"medicalDischargeEducation"` AdmDischargeEducation *string `json:"admDischargeEducation"` DischargeReason *string `json:"dischargeReason"` + ChemoClass *ere.ChemoClassCode `json:"chemo-class"` } type ReadDetailDto struct { @@ -293,6 +295,6 @@ func ToResponseList(data []Encounter) []ResponseDto { } type CreateWithPatientDto struct { - Encounter CreateDto `json:"encounter"` - Patient ep.CreateDto `json:"patient"` + CreateDto + Patient ep.CreateDto `json:"patient"` } diff --git a/internal/domain/main-entities/installation/dto.go b/internal/domain/main-entities/installation/dto.go index bd6fcc0e..56fdb382 100644 --- a/internal/domain/main-entities/installation/dto.go +++ b/internal/domain/main-entities/installation/dto.go @@ -14,6 +14,10 @@ type CreateDto struct { EncounterClass_Code ere.EncounterClassCode `json:"encounterClass_code" validate:"maxLength=20"` } +type CreateBulkDto struct { + Value []CreateDto `json:"value"` +} + type ReadListDto struct { FilterDto Includes string `json:"includes"` diff --git a/internal/domain/main-entities/resume/dto.go b/internal/domain/main-entities/resume/dto.go index e7ddf09b..d75fe3da 100644 --- a/internal/domain/main-entities/resume/dto.go +++ b/internal/domain/main-entities/resume/dto.go @@ -2,6 +2,7 @@ package resume import ( ecore "simrs-vx/internal/domain/base-entities/core" + ed "simrs-vx/internal/domain/main-entities/doctor" "time" erc "simrs-vx/internal/domain/references/common" @@ -54,6 +55,7 @@ type ResponseDto struct { ecore.Main Encounter_Id *uint `json:"encounter_id"` Doctor_Code *string `json:"doctor_code"` + Doctor *ed.Doctor `json:"doctor,omitempty" gorm:"foreignKey:Doctor_Code;references:Code"` Value *string `json:"value"` FileUrl *string `json:"fileUrl"` Status_Code erc.DataVerifiedCode `json:"status_code"` @@ -63,6 +65,7 @@ func (d Resume) ToResponse() ResponseDto { resp := ResponseDto{ Encounter_Id: d.Encounter_Id, Doctor_Code: d.Doctor_Code, + Doctor: d.Doctor, Value: d.Value, FileUrl: d.FileUrl, Status_Code: d.Status_Code, diff --git a/internal/domain/main-entities/specialist/dto.go b/internal/domain/main-entities/specialist/dto.go index 78f7ae31..1b75e7cb 100644 --- a/internal/domain/main-entities/specialist/dto.go +++ b/internal/domain/main-entities/specialist/dto.go @@ -7,10 +7,10 @@ import ( ) type CreateDto struct { - Id *uint `json:"id"` - Installation_Code string `json:"installation_code"` - Code string `json:"code" validate:"maxLength=10"` - Name string `json:"name" validate:"maxLength=50"` + Id *uint `json:"id"` + Installation_Code *string `json:"installation_code"` + Code string `json:"code" validate:"maxLength=10"` + Name string `json:"name" validate:"maxLength=50"` } type ReadListDto struct { @@ -42,6 +42,10 @@ type DeleteDto struct { Code *string `json:"code"` } +type CreateBulkDto struct { + Value []CreateDto `json:"value"` +} + type MetaDto struct { PageNumber int `json:"page_number"` PageSize int `json:"page_size"` diff --git a/internal/domain/main-entities/subspecialist/dto.go b/internal/domain/main-entities/subspecialist/dto.go index 303da04f..378fdd2c 100644 --- a/internal/domain/main-entities/subspecialist/dto.go +++ b/internal/domain/main-entities/subspecialist/dto.go @@ -43,6 +43,10 @@ type DeleteDto struct { Code *string `json:"code"` } +type CreateBulkDto struct { + Value []CreateDto `json:"value"` +} + type MetaDto struct { PageNumber int `json:"page_number"` PageSize int `json:"page_size"` diff --git a/internal/domain/references/encounter/encounter.go b/internal/domain/references/encounter/encounter.go index 83ef759b..846b11be 100644 --- a/internal/domain/references/encounter/encounter.go +++ b/internal/domain/references/encounter/encounter.go @@ -70,7 +70,7 @@ const ( OCCHcu OutpatientClassCode = "hcu" // HCU OCCVk OutpatientClassCode = "vk" // Verlos kamer - ACCReg AmbulatoryClassCode = "reg" // Regular + ACCReg AmbulatoryClassCode = "regular" // Regular // ACCRehab ACCRme AmbulatoryClassCode = "rme" // Rehab Medik // ACCCad AmbulatoryClassCode = "chemo-adm" // Chemotherapy // ACCCac AmbulatoryClassCode = "chemo-act" // Chemotherapy @@ -130,9 +130,9 @@ const ( ETCEncounter EntityTypeCode = "encounter" ETCMCU EntityTypeCode = "mcu" - SPCComplete StatusProtocolChemo = "complete" - SPCPlanned StatusProtocolChemo = "planned" - SPCSchedule StatusProtocolChemo = "schedule" + SPCComplete StatusProtocolChemo = "complete" // Terealisasi + SPCPlanned StatusProtocolChemo = "planned" // Terencana + SPCSchedule StatusProtocolChemo = "schedule" // Terjadwal ) func (ec EncounterClassCode) Code() string { diff --git a/internal/domain/satu-entities/daftar-specialist/entity.go b/internal/domain/satu-entities/daftar-specialist/entity.go new file mode 100644 index 00000000..de69a7bf --- /dev/null +++ b/internal/domain/satu-entities/daftar-specialist/entity.go @@ -0,0 +1,12 @@ +package daftar_specialist + +type DaftarSpesialis struct { + ID uint `json:"id" gorm:"column:id;primaryKey;autoIncrement"` + Kode string `json:"kode" gorm:"column:Kode"` + Spesialis string `json:"spesialis" gorm:"column:Spesialis"` + IdGroupLocationSimgos *string `json:"id_group_location_simgos" gorm:"column:Id_group_location_simgos"` +} + +func (DaftarSpesialis) TableName() string { + return "daftar_spesialis" +} diff --git a/internal/domain/simgos-entities/m-ruang/entity.go b/internal/domain/simgos-entities/m-ruang/entity.go new file mode 100644 index 00000000..1c2b5b31 --- /dev/null +++ b/internal/domain/simgos-entities/m-ruang/entity.go @@ -0,0 +1,24 @@ +package m_ruang + +type MRuang struct { + No uint `json:"no" gorm:"column:no;primaryKey;autoIncrement"` + Nama string `json:"nama" gorm:"column:nama"` + Kelas string `json:"kelas" gorm:"column:kelas"` + IdxRuang string `json:"idx_ruang" gorm:"column:idx_ruang"` + Kelompok string `json:"kelompok" gorm:"column:kelompok"` + Ruang *string `json:"ruang" gorm:"column:ruang"` + KdUnit int `json:"kdunit" gorm:"column:kdunit"` + JumlahTT int `json:"jumlah_tt" gorm:"column:jumlah_tt"` + KetRuang *string `json:"ket_ruang" gorm:"column:ket_ruang"` + Fasilitas *string `json:"fasilitas" gorm:"column:fasilitas"` + Keterangan *string `json:"keterangan" gorm:"column:keterangan"` + SubSistem string `json:"subsistem" gorm:"column:subsistem"` + StAktif int16 `json:"st_aktif" gorm:"column:st_aktif"` + KodeRuang *string `json:"kode_ruang" gorm:"column:kode_ruang"` + IsPartial *string `json:"is_partial" gorm:"column:is_partial"` +} + +// Nama tabel (opsional jika nama struct ≠ nama tabel) +func (MRuang) TableName() string { + return "m_ruang" +} diff --git a/internal/infra/satu-db/satu-db.go b/internal/infra/satu-db/satu-db.go new file mode 100644 index 00000000..4894b4e3 --- /dev/null +++ b/internal/infra/satu-db/satu-db.go @@ -0,0 +1,9 @@ +package simgos_db + +import ( + dg "github.com/karincake/apem/db-gorm-pg" +) + +func SetInstance() { + I = dg.IS["satu"] +} diff --git a/internal/infra/satu-db/tycovar.go b/internal/infra/satu-db/tycovar.go new file mode 100644 index 00000000..b9c9f2b3 --- /dev/null +++ b/internal/infra/satu-db/tycovar.go @@ -0,0 +1,5 @@ +package simgos_db + +import "gorm.io/gorm" + +var I *gorm.DB diff --git a/internal/interface/main-handler/chemo-plan/handler.go b/internal/interface/main-handler/chemo-plan/handler.go new file mode 100644 index 00000000..215797b0 --- /dev/null +++ b/internal/interface/main-handler/chemo-plan/handler.go @@ -0,0 +1,88 @@ +package chemo_protocol + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + e "simrs-vx/internal/domain/main-entities/chemo-plan" + ep "simrs-vx/internal/domain/main-entities/chemo-protocol" + u "simrs-vx/internal/use-case/main-use-case/chemo-plan" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := ep.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) +} + +func (obj myBase) Fail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.FailDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + + dto.Id = uint(id) + res, err := u.Fail(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/chemo-protocol/handler.go b/internal/interface/main-handler/chemo-protocol/handler.go index 60d9db4d..4ac8d90f 100644 --- a/internal/interface/main-handler/chemo-protocol/handler.go +++ b/internal/interface/main-handler/chemo-protocol/handler.go @@ -2,7 +2,10 @@ package chemo_protocol import ( "net/http" + erc "simrs-vx/internal/domain/references/common" + pa "simrs-vx/internal/lib/auth" + d "github.com/karincake/dodol" rw "github.com/karincake/risoles" sf "github.com/karincake/semprit" @@ -39,7 +42,7 @@ func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { dto := e.ReadDetailDto{} sf.UrlQueryParam(&dto, *r.URL) - dto.Id = uint16(id) + dto.Id = uint(id) res, err := u.ReadDetail(dto) rw.DataResponse(w, res, err) } @@ -54,7 +57,7 @@ func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { return } - dto.Id = uint16(id) + dto.Id = uint(id) res, err := u.Update(dto) rw.DataResponse(w, res, err) } @@ -66,7 +69,46 @@ func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { } dto := e.DeleteDto{} - dto.Id = uint16(id) + dto.Id = uint(id) res, err := u.Delete(dto) rw.DataResponse(w, res, err) } + +func (obj myBase) Verify(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.VerifyDto{} + dto.Id = uint(id) + + authInfo, err := pa.GetAuthInfo(r) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) + } + + dto.AuthInfo = *authInfo + dto.Status_Code = erc.DVCVerified + res, err := u.Verify(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Reject(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.VerifyDto{} + dto.Id = uint(id) + authInfo, err := pa.GetAuthInfo(r) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) + } + + dto.AuthInfo = *authInfo + dto.Status_Code = erc.DVCRejected + res, err := u.Verify(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/chemo/handler.go b/internal/interface/main-handler/chemo/handler.go index 18435479..30535ac4 100644 --- a/internal/interface/main-handler/chemo/handler.go +++ b/internal/interface/main-handler/chemo/handler.go @@ -3,20 +3,16 @@ package chemo 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" - - erc "simrs-vx/internal/domain/references/common" - - u "simrs-vx/internal/use-case/main-use-case/chemo" - pa "simrs-vx/internal/lib/auth" d "github.com/karincake/dodol" + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + erc "simrs-vx/internal/domain/references/common" + + e "simrs-vx/internal/domain/main-entities/chemo" + u "simrs-vx/internal/use-case/main-use-case/chemo" ) type myBase struct{} @@ -45,7 +41,8 @@ func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { return } dto := e.ReadDetailDto{} - dto.Id = uint16(id) + sf.UrlQueryParam(&dto, *r.URL) + dto.Id = uint(id) res, err := u.ReadDetail(dto) rw.DataResponse(w, res, err) } @@ -60,7 +57,7 @@ func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { return } - dto.Id = uint16(id) + dto.Id = uint(id) res, err := u.Update(dto) rw.DataResponse(w, res, err) } @@ -72,7 +69,7 @@ func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { } dto := e.DeleteDto{} - dto.Id = uint16(id) + dto.Id = uint(id) res, err := u.Delete(dto) rw.DataResponse(w, res, err) } @@ -88,7 +85,7 @@ func (obj myBase) Verify(w http.ResponseWriter, r *http.Request) { return } - dto.Id = uint16(id) + dto.Id = uint(id) authInfo, err := pa.GetAuthInfo(r) if err != nil { rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) @@ -107,7 +104,7 @@ func (obj myBase) Reject(w http.ResponseWriter, r *http.Request) { } dto := e.VerifyDto{} - dto.Id = uint16(id) + dto.Id = uint(id) authInfo, err := pa.GetAuthInfo(r) if err != nil { rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) diff --git a/internal/interface/main-handler/encounter/handler.go b/internal/interface/main-handler/encounter/handler.go index 8b8babc9..0801f805 100644 --- a/internal/interface/main-handler/encounter/handler.go +++ b/internal/interface/main-handler/encounter/handler.go @@ -325,7 +325,7 @@ func (obj myBase) CreateWithPatient(w http.ResponseWriter, r *http.Request) { } // validate SubClass - if err := verifyClassCode(dto.Encounter); err != nil { + if err := verifyClassCode(dto.CreateDto); err != nil { rw.DataResponse(w, nil, d.FieldError{ Code: dataValidationFail, Message: err.Error(), @@ -333,7 +333,7 @@ func (obj myBase) CreateWithPatient(w http.ResponseWriter, r *http.Request) { return } - dto.Encounter.AuthInfo = *authInfo + dto.AuthInfo = *authInfo dto.Patient.AuthInfo = *authInfo res, err := u.CreateWithPatient(dto) rw.DataResponse(w, res, err) diff --git a/internal/interface/main-handler/installation/handler.go b/internal/interface/main-handler/installation/handler.go index 0b3f52ef..f9644129 100644 --- a/internal/interface/main-handler/installation/handler.go +++ b/internal/interface/main-handler/installation/handler.go @@ -71,3 +71,12 @@ func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { res, err := u.Delete(dto) rw.DataResponse(w, res, err) } + +func (obj myBase) CreateBulk(w http.ResponseWriter, r *http.Request) { + dto := e.CreateBulkDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.CreateBulk(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/main-handler.go b/internal/interface/main-handler/main-handler.go index fced567e..a4249e08 100644 --- a/internal/interface/main-handler/main-handler.go +++ b/internal/interface/main-handler/main-handler.go @@ -9,7 +9,6 @@ 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" @@ -43,6 +42,7 @@ import ( screening "simrs-vx/internal/interface/main-handler/screening" soapi "simrs-vx/internal/interface/main-handler/soapi" uploadfile "simrs-vx/internal/interface/main-handler/upload-file" + vaccineData "simrs-vx/internal/interface/main-handler/vaccine-data" /******************** actor ********************/ authpartner "simrs-vx/internal/interface/main-handler/auth-partner" @@ -82,6 +82,8 @@ import ( /******************** sources ********************/ antibioticsrc "simrs-vx/internal/interface/main-handler/antibiotic-src" antibioticsrccat "simrs-vx/internal/interface/main-handler/antibiotic-src-category" + chemoplan "simrs-vx/internal/interface/main-handler/chemo-plan" + chemoprotocol "simrs-vx/internal/interface/main-handler/chemo-protocol" device "simrs-vx/internal/interface/main-handler/device" diagnosesrc "simrs-vx/internal/interface/main-handler/diagnose-src" division "simrs-vx/internal/interface/main-handler/division" @@ -314,8 +316,20 @@ func SetRoutes() http.Handler { "PATCH /{id}/verify": therapyprotocol.O.Verify, "PATCH /{id}/reject": therapyprotocol.O.Reject, }) - hc.RegCrud(r, "/v1/chemo-protocol", chemoprotocol.O) + hk.GroupRoutes("/v1/chemo-protocol", r, auth.GuardMW, hk.MapHandlerFunc{ + "GET /": chemoprotocol.O.GetList, + "GET /{id}": chemoprotocol.O.GetDetail, + "POST /": chemoprotocol.O.Create, + "PATCH /{id}": chemoprotocol.O.Update, + "DELETE /{id}": chemoprotocol.O.Delete, + "PATCH /{id}/verify": chemoprotocol.O.Verify, + "PATCH /{id}/reject": chemoprotocol.O.Reject, + }) + hk.GroupRoutes("/v1/chemo-plan", r, auth.GuardMW, hk.MapHandlerFunc{ + "PATCH /{id}/fail": chemoplan.O.Fail, + }) hc.RegCrud(r, "/v1/upload-file", uploadfile.O) + hc.RegCrud(r, "/v1/vaccine-data", vaccineData.O) hc.RegCrud(r, "/v1/encounter-document", encounterdocument.O) hc.RegCrud(r, "/v1/general-consent", generalconsent.O) r.HandleFunc("POST /v1/generate-file", generatefile.Generate) @@ -366,10 +380,31 @@ func SetRoutes() http.Handler { /******************** sources ********************/ hc.RegCrudByCode(r, "/v1/division", division.O) hc.RegCrudByCode(r, "/v1/division-position", divisionposition.O) - hc.RegCrudByCode(r, "/v1/installation", installation.O) + hk.GroupRoutes("/v1/installation", r, hk.MapHandlerFunc{ + "GET /": installation.O.GetList, + "GET /{id}": installation.O.GetDetail, + "POST /": installation.O.Create, + "PATCH /{id}": installation.O.Update, + "DELETE /{id}": installation.O.Delete, + "POST /bulk": installation.O.CreateBulk, + }) hc.RegCrudByCode(r, "/v1/installation-position", installationposition.O) - hc.RegCrudByCode(r, "/v1/specialist", specialist.O) - hc.RegCrudByCode(r, "/v1/subspecialist", subspecialist.O) + hk.GroupRoutes("/v1/specialist", r, hk.MapHandlerFunc{ + "GET /": specialist.O.GetList, + "GET /{id}": specialist.O.GetDetail, + "POST /": specialist.O.Create, + "PATCH /{id}": specialist.O.Update, + "DELETE /{id}": specialist.O.Delete, + "POST /bulk": specialist.O.CreateBulk, + }) + hk.GroupRoutes("/v1/subspecialist", r, hk.MapHandlerFunc{ + "GET /": subspecialist.O.GetList, + "GET /{id}": subspecialist.O.GetDetail, + "POST /": subspecialist.O.Create, + "PATCH /{id}": subspecialist.O.Update, + "DELETE /{id}": subspecialist.O.Delete, + "POST /bulk": subspecialist.O.CreateBulk, + }) hc.RegCrudByCode(r, "/v1/specialist-position", specialistposition.O) hc.RegCrudByCode(r, "/v1/subspecialist-position", subspecialistposition.O) hc.RegCrudByCode(r, "/v1/infra", infra.O) @@ -413,7 +448,9 @@ func SetRoutes() http.Handler { }) hk.GroupRoutes("/v1/vclaim-sep-control-letter", r, hk.MapHandlerFunc{ - "POST /": vclaimsepcontrolletter.O.Create, + "POST /": vclaimsepcontrolletter.O.Create, + "GET /{number}": vclaimsepcontrolletter.O.GetDetail, + "DELETE /{number}": vclaimsepcontrolletter.O.Delete, }) hk.GroupRoutes("/v1/vclaim-sep-hist", r, hk.MapHandlerFunc{ diff --git a/internal/interface/main-handler/specialist/handler.go b/internal/interface/main-handler/specialist/handler.go index 246da8f4..184fbd79 100644 --- a/internal/interface/main-handler/specialist/handler.go +++ b/internal/interface/main-handler/specialist/handler.go @@ -71,3 +71,12 @@ func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { res, err := u.Delete(dto) rw.DataResponse(w, res, err) } + +func (obj myBase) CreateBulk(w http.ResponseWriter, r *http.Request) { + dto := e.CreateBulkDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.CreateBulk(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/subspecialist/handler.go b/internal/interface/main-handler/subspecialist/handler.go index 0e5a41d0..f021b592 100644 --- a/internal/interface/main-handler/subspecialist/handler.go +++ b/internal/interface/main-handler/subspecialist/handler.go @@ -71,3 +71,12 @@ func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { res, err := u.Delete(dto) rw.DataResponse(w, res, err) } + +func (obj myBase) CreateBulk(w http.ResponseWriter, r *http.Request) { + dto := e.CreateBulkDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.CreateBulk(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/vaccine-data/handler.go b/internal/interface/main-handler/vaccine-data/handler.go new file mode 100644 index 00000000..1aa163ba --- /dev/null +++ b/internal/interface/main-handler/vaccine-data/handler.go @@ -0,0 +1,72 @@ +package vaccinedata + +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/vaccine-data" + u "simrs-vx/internal/use-case/main-use-case/vaccine-data" +) + +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/vclaim-sep-control-letter/handler.go b/internal/interface/main-handler/vclaim-sep-control-letter/handler.go index d26cc633..4bdd3d5d 100644 --- a/internal/interface/main-handler/vclaim-sep-control-letter/handler.go +++ b/internal/interface/main-handler/vclaim-sep-control-letter/handler.go @@ -29,16 +29,16 @@ func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { // rw.DataResponse(w, res, err) // } -// func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { -// number := rw.ValidateString(w, "number", r.PathValue("number")) -// if number <= "" { -// return -// } -// dto := e.ReadDetailDto{} -// dto.Number = &number -// res, err := u.ReadDetail(dto) -// rw.DataResponse(w, res, err) -// } +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + number := rw.ValidateString(w, "number", r.PathValue("number")) + if number == "" { + return + } + dto := e.ReadDetailDto{} + dto.Number = &number + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} // func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { // number := rw.ValidateString(w, "number", r.PathValue("number")) @@ -55,13 +55,13 @@ func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { // 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) -// } +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + number := rw.ValidateString(w, "number", r.PathValue("number")) + if number == "" { + return + } + dto := e.DeleteDto{} + dto.Number = &number + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/simgos-sync-handler/simgos-sync-handler.go b/internal/interface/simgos-sync-handler/simgos-sync-handler.go index 761c6b74..d454c189 100644 --- a/internal/interface/simgos-sync-handler/simgos-sync-handler.go +++ b/internal/interface/simgos-sync-handler/simgos-sync-handler.go @@ -5,6 +5,7 @@ import ( /******************** infra ********************/ gs "simrs-vx/internal/infra/gorm-setting" + satudb "simrs-vx/internal/infra/satu-db" simgosdb "simrs-vx/internal/infra/simgos-db" sync "simrs-vx/internal/infra/sync-cfg" @@ -43,6 +44,7 @@ func SetRoutes() http.Handler { a.RegisterExtCall(lh.Populate) a.RegisterExtCall(sync.SetConfig) a.RegisterExtCall(simgosdb.SetInstance) + a.RegisterExtCall(satudb.SetInstance) r := http.NewServeMux() diff --git a/internal/use-case/bpjs-plugin/vclaim-sep-control-letter/plugin.go b/internal/use-case/bpjs-plugin/vclaim-sep-control-letter/plugin.go index 3ad81f74..cedb3dc9 100644 --- a/internal/use-case/bpjs-plugin/vclaim-sep-control-letter/plugin.go +++ b/internal/use-case/bpjs-plugin/vclaim-sep-control-letter/plugin.go @@ -35,7 +35,7 @@ func CreateSepControlLetter(input *e.CreateDto, data *e.VclaimSepControlLetter, return err } - var vresp Response + var vresp e.VclaimResponse if err := json.Unmarshal(body, &vresp); err != nil { return fmt.Errorf("failed to parse response JSON: %w", err) } @@ -55,71 +55,68 @@ func CreateSepControlLetter(input *e.CreateDto, data *e.VclaimSepControlLetter, return nil } -// func ReadDetailSep(input *e.ReadDetailDto, data *e.VclaimSep, tx *gorm.DB) error { -// endpoint := fmt.Sprintf("sep/%s", input.Number) -// req, err := http.NewRequest("GET", ibpjs.O.BaseUrl+endpoint, nil) -// if err != nil { -// return err -// } -// req.Header.Set("Content-Type", "application/json") +func DeleteSepControlLetter(input *e.DeleteDto, data *e.VclaimSepControlLetter, tx *gorm.DB) error { + payload, err := input.RequestPayloadIntoJson() + if err != nil { + return err + } + req, err := http.NewRequest("DELETE", ibpjs.O.BaseUrl+"RencanaKontrol/Delete", bytes.NewBuffer(payload)) + if err != nil { + return err + } + req.Header.Set("Content-Type", "application/json") -// resp, err := http.DefaultClient.Do(req) -// if err != nil { -// return err -// } -// defer resp.Body.Close() + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() -// body, err := io.ReadAll(resp.Body) -// if err != nil { -// return err -// } + body, err := io.ReadAll(resp.Body) + if err != nil { + return err + } -// var detail e.SepResponse -// if err := json.Unmarshal(body, &detail); err != nil { -// return fmt.Errorf("failed to parse response JSON: %w", err) -// } + var vresp e.VclaimResponse + if err := json.Unmarshal(body, &vresp); err != nil { + return fmt.Errorf("failed to parse response JSON: %w", err) + } -// data.Detail = detail.Response + if vresp.MetaData.Code != "200" { + return fmt.Errorf("failed to delete sep control letter: %s", vresp.MetaData.Message) + } -// return nil -// } + return nil +} -// func DeleteSep(input *e.DeleteDto, data *e.VclaimSep, tx *gorm.DB) error { -// payload := e.SepDeleteRequest{} -// payload.Request.TSep.NoSep = *input.Number -// payload.Request.TSep.User = "Coba Ws" +func GetDetailSepControlLetterByNumber(input *e.ReadDetailDto, data *e.VclaimSepControlLetter, tx *gorm.DB) error { + req, err := http.NewRequest("GET", ibpjs.O.BaseUrl+"RencanaKontrol/noSuratKontrol/"+*input.Number, nil) + if err != nil { + return err + } + req.Header.Set("Content-Type", "application/json") -// jsonPayload, err := json.Marshal(payload) -// if err != nil { -// return err -// } + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() -// req, err := http.NewRequest("DELETE", ibpjs.O.BaseUrl+"sep", bytes.NewBuffer(jsonPayload)) -// if err != nil { -// return err -// } + body, err := io.ReadAll(resp.Body) + if err != nil { + return err + } -// req.Header.Set("Content-Type", "application/json") + var vresp e.DetailVclaimResponse + if err := json.Unmarshal(body, &vresp); err != nil { + return fmt.Errorf("failed to parse response JSON: %w", err) + } -// resp, err := http.DefaultClient.Do(req) -// if err != nil { -// return err -// } -// defer resp.Body.Close() + if vresp.MetaData.Code != "200" { + return fmt.Errorf("failed to get detail sep control letter by number: %s", vresp.MetaData.Message) + } -// body, err := io.ReadAll(resp.Body) -// if err != nil { -// return err -// } + data.Detail = vresp.Response -// var detail e.SepResponse -// if err := json.Unmarshal(body, &detail); err != nil { -// return fmt.Errorf("failed to parse response JSON: %w", err) -// } - -// if detail.MetaData.Message == SepNotFound { -// return fmt.Errorf("sep with number %s not found", *data.Number) -// } - -// return nil -// } + return nil +} diff --git a/internal/use-case/bpjs-plugin/vclaim-sep-control-letter/tycovar.go b/internal/use-case/bpjs-plugin/vclaim-sep-control-letter/tycovar.go deleted file mode 100644 index c732afa5..00000000 --- a/internal/use-case/bpjs-plugin/vclaim-sep-control-letter/tycovar.go +++ /dev/null @@ -1,87 +0,0 @@ -package vclaimsepcontrolletter - -import ( - "encoding/json" - - e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-control-letter" -) - -type SuratKontrol struct { - NoSuratKontrol string `json:"noSuratKontrol"` - TglRencanaKontrol string `json:"tglRencanaKontrol"` - TglTerbit string `json:"tglTerbit"` - JnsKontrol string `json:"jnsKontrol"` - PoliTujuan string `json:"poliTujuan"` - NamaPoliTujuan string `json:"namaPoliTujuan"` - KodeDokter string `json:"kodeDokter"` - NamaDokter string `json:"namaDokter"` - FlagKontrol string `json:"flagKontrol"` - KodeDokterPembuat *string `json:"kodeDokterPembuat"` - NamaDokterPembuat *string `json:"namaDokterPembuat"` - NamaJnsKontrol string `json:"namaJnsKontrol"` - Sep Sep `json:"sep"` -} - -type Sep struct { - NoSep string `json:"noSep"` - TglSep string `json:"tglSep"` - JnsPelayanan string `json:"jnsPelayanan"` - Poli string `json:"poli"` - Diagnosa string `json:"diagnosa"` - Peserta Peserta `json:"peserta"` - ProvUmum ProvUmum `json:"provUmum"` - ProvPerujuk ProvPerujuk `json:"provPerujuk"` -} - -type Peserta struct { - NoKartu string `json:"noKartu"` - Nama string `json:"nama"` - TglLahir string `json:"tglLahir"` - Kelamin string `json:"kelamin"` - HakKelas string `json:"hakKelas"` -} - -type ProvUmum struct { - KdProvider string `json:"kdProvider"` - NmProvider string `json:"nmProvider"` -} - -type ProvPerujuk struct { - KdProviderPerujuk string `json:"kdProviderPerujuk"` - NmProviderPerujuk string `json:"nmProviderPerujuk"` - AsalRujukan string `json:"asalRujukan"` - NoRujukan string `json:"noRujukan"` - TglRujukan string `json:"tglRujukan"` -} - -type Response struct { - MetaData MetaData `json:"metaData"` - Response *SuratKontrol `json:"response"` // nullable -} - -type MetaData struct { - Code string `json:"code"` - Message string `json:"message"` -} - -func (r Response) ToPDFNeeds() ([]byte, error) { - response := e.ResponseForPDF{ - Number: r.Response.Sep.NoSep, - PlannedControlDate: r.Response.TglRencanaKontrol, - IssuedDate: r.Response.TglTerbit, - Doctor_Name: r.Response.NamaDokter, - DstUnit_Name: r.Response.NamaPoliTujuan, - ResponsibleDoctor_Name: *r.Response.NamaDokterPembuat, - VclaimSep: e.VclaimSep{ - VclaimMember: e.VclaimMember{ - CardNumber: r.Response.Sep.Peserta.NoKartu, - Name: r.Response.Sep.Peserta.Nama, - BirthDate: r.Response.Sep.Peserta.TglLahir, - Gender: r.Response.Sep.Peserta.Kelamin, - }, - Diagnose: r.Response.Sep.Diagnosa, - Number: r.Response.Sep.NoSep, - }, - } - return json.Marshal(response) -} diff --git a/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/middleware.go b/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/middleware.go index 0cca1159..c9785da8 100644 --- a/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/middleware.go +++ b/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/middleware.go @@ -9,4 +9,10 @@ func init() { createPreMw = append(createPreMw, createMw{Name: "create-sep-control-letter", Func: pvscl.CreateSepControlLetter}, ) + readDetailPreMw = append(readDetailPreMw, + readDetailMw{Name: "get-detail-sep-control-letter-by-number", Func: pvscl.GetDetailSepControlLetterByNumber}, + ) + deletePreMw = append(deletePreMw, + DeleteMw{Name: "delete-sep-control-letter", Func: pvscl.DeleteSepControlLetter}, + ) } diff --git a/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/tycovar.go b/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/tycovar.go index 2e921ae9..ee2e73f1 100644 --- a/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/tycovar.go +++ b/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/tycovar.go @@ -30,7 +30,10 @@ type readDetailMw struct { } type UpdateMw = readDetailMw -type DeleteMw = readDetailMw +type DeleteMw struct { + Name string + Func func(input *e.DeleteDto, data *e.VclaimSepControlLetter, tx *gorm.DB) error +} var createPreMw []createMw // preprocess middleware var createPostMw []createMw // postprocess middleware @@ -40,5 +43,5 @@ var readDetailPreMw []readDetailMw var readDetailPostMw []readDetailMw var updatePreMw []readDetailMw var updatePostMw []readDetailMw -var deletePreMw []readDetailMw -var deletePostMw []readDetailMw +var deletePreMw []DeleteMw +var deletePostMw []DeleteMw diff --git a/internal/use-case/main-use-case/chemo-plan/case.go b/internal/use-case/main-use-case/chemo-plan/case.go new file mode 100644 index 00000000..eff45b46 --- /dev/null +++ b/internal/use-case/main-use-case/chemo-plan/case.go @@ -0,0 +1,317 @@ +package chemo_plan + +import ( + ere "simrs-vx/internal/domain/references/encounter" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + "strconv" + + dg "github.com/karincake/apem/db-gorm-pg" + d "github.com/karincake/dodol" + "gorm.io/gorm" + + erc "simrs-vx/internal/domain/references/common" + + e "simrs-vx/internal/domain/main-entities/chemo-plan" + ep "simrs-vx/internal/domain/main-entities/chemo-protocol" +) + +const source = "chemo-plan" + +func Create(input ep.CreateDto) (*d.Data, error) { + data := []e.ChemoPlan{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err := dg.I.Transaction(func(tx *gorm.DB) error { + input.Status_Code = erc.DVCNew + + if resData, err := CreateData(&input, &event, tx); err != nil { + return err + } else { + data = *resData + } + + 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: e.ToResponseList(data), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.ChemoPlan + var dataList []e.ChemoPlan + 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.ChemoPlan + 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.ChemoPlan + var err error + + event := pl.Event{ + Feature: "Update", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "update") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err + } + + if err := UpdateData(data, "", &event, tx); err != nil { + return err + } + + pl.SetLogInfo(&event, nil, "complete") + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + Data: data.ToResponse(), + }, nil + +} + +func Delete(input e.DeleteDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.ChemoPlan + 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 Fail(input e.FailDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.ChemoPlan + var err error + + event := pl.Event{ + Feature: "Chemo-Fail", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "update") + + if data, err = ReadDetailData(rdDto, &event); err != nil { + return nil, err + } + + dataSoapi, err := getSoapiByEncounterId(*data.Encounter_Id, &event) + if err != nil { + return nil, err + } + + if dataSoapi != nil && len(*dataSoapi) > 0 { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "soapi-exist", + Detail: "cancel soapi to proceed", + } + return nil, pl.SetLogError(&event, data) + } + + if *data.Status != ere.SPCPlanned { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "invalid-chemo-status", + Detail: "only chemo plans with status 'planned' can be deleted.", + } + } + + err = dg.I.Transaction(func(tx *gorm.DB) error { + if err := UpdateFailData(input, data, &event, tx); err != nil { + return err + } + + pl.SetLogInfo(&event, nil, "complete") + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + Data: data.ToResponse(), + }, nil + +} diff --git a/internal/use-case/main-use-case/chemo-plan/helper.go b/internal/use-case/main-use-case/chemo-plan/helper.go new file mode 100644 index 00000000..4d62f819 --- /dev/null +++ b/internal/use-case/main-use-case/chemo-plan/helper.go @@ -0,0 +1,90 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package chemo_plan + +import ( + "encoding/json" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + "time" + + dg "github.com/karincake/apem/db-gorm-pg" + + ere "simrs-vx/internal/domain/references/encounter" + + e "simrs-vx/internal/domain/main-entities/chemo-plan" + ep "simrs-vx/internal/domain/main-entities/chemo-protocol" + es "simrs-vx/internal/domain/main-entities/soapi" +) + +var now = time.Now() + +func setDataCreate(input *ep.CreateDto) (data []e.ChemoPlan) { + for _, c := range *input.ChemoPlans { + data = append(data, e.ChemoPlan{ + Parent_Id: input.Chemo_Id, + Protocol_Id: input.Id, + SeriesNumber: c.SeriesNumber, + CycleNumber: c.CycleNumber, + PlanDate: c.PlanDate, + }) + } + return +} + +func setDataCreateSoapi(data *e.ChemoPlan) { + data.RealizationDate = &now + + status := ere.SPCComplete + data.Status = &status +} + +func setDataDeleteSoapi(data *e.ChemoPlan) { + status := ere.SPCPlanned + data.Status = &status +} + +func setDatafail(input e.FailDto, data *e.ChemoPlan) { + data.RealizationDate = nil + + status := ere.SPCSchedule + data.Status = &status + + var reasons []e.FailReason + + if data.Reasons != nil { + json.Unmarshal([]byte(*data.Reasons), &reasons) + } + + reasons = append(reasons, e.FailReason{ + FailReason: input.Reasons, + Date: &now, + Encounter_Id: data.Encounter_Id, + }) + + if b, err := json.Marshal(reasons); err == nil { + jsonStr := string(b) + data.Reasons = &jsonStr + } +} + +func getSoapiByEncounterId(encounterId uint, event *pl.Event) (*[]es.Soapi, error) { + pl.SetLogInfo(event, encounterId, "started", "DBReadDetail") + var data []es.Soapi + + var tx = dg.I + + if err := tx. + Model(&es.Soapi{}). + Where(`"Encounter_Id" = ?`, encounterId). + Find(&data).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, encounterId, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} diff --git a/internal/use-case/main-use-case/chemo-plan/lib.go b/internal/use-case/main-use-case/chemo-plan/lib.go new file mode 100644 index 00000000..22d6259b --- /dev/null +++ b/internal/use-case/main-use-case/chemo-plan/lib.go @@ -0,0 +1,178 @@ +package chemo_plan + +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-plan" + ep "simrs-vx/internal/domain/main-entities/chemo-protocol" +) + +func CreateData(input *ep.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*[]e.ChemoPlan, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := setDataCreate(input) + + 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.ChemoPlan, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.ChemoPlan{} + 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.ChemoPlan{}). + 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.ChemoPlan, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.ChemoPlan{} + + 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(data *e.ChemoPlan, method string, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBUpdate") + + switch method { + case "c": + setDataCreateSoapi(data) + case "d": + setDataDeleteSoapi(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, data) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} + +func DeleteData(data *e.ChemoPlan, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Delete(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-delete-fail", + Detail: "Database delete failed", + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} + +func UpdateFailData(input e.FailDto, data *e.ChemoPlan, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBUpdate") + setDatafail(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, data) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/main-use-case/chemo-plan/middleware-runner.go b/internal/use-case/main-use-case/chemo-plan/middleware-runner.go new file mode 100644 index 00000000..406b109d --- /dev/null +++ b/internal/use-case/main-use-case/chemo-plan/middleware-runner.go @@ -0,0 +1,103 @@ +package chemo_plan + +import ( + e "simrs-vx/internal/domain/main-entities/chemo-plan" + 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.ChemoPlan) 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.ChemoPlan) 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.ChemoPlan) 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.ChemoPlan) 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.ChemoPlan) 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-plan/middleware.go b/internal/use-case/main-use-case/chemo-plan/middleware.go new file mode 100644 index 00000000..10e658f5 --- /dev/null +++ b/internal/use-case/main-use-case/chemo-plan/middleware.go @@ -0,0 +1,9 @@ +package chemo_plan + +// 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-plan/tycovar.go b/internal/use-case/main-use-case/chemo-plan/tycovar.go new file mode 100644 index 00000000..c438e2de --- /dev/null +++ b/internal/use-case/main-use-case/chemo-plan/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_plan + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/chemo-plan" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.ChemoPlan, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.ChemoPlan, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.ChemoPlan, 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-protocol/case.go b/internal/use-case/main-use-case/chemo-protocol/case.go index 4e007d28..38e6ba4b 100644 --- a/internal/use-case/main-use-case/chemo-protocol/case.go +++ b/internal/use-case/main-use-case/chemo-protocol/case.go @@ -1,6 +1,7 @@ package chemo_protocol import ( + "errors" "strconv" dg "github.com/karincake/apem/db-gorm-pg" @@ -11,13 +12,22 @@ import ( "gorm.io/gorm" + erc "simrs-vx/internal/domain/references/common" + + ec "simrs-vx/internal/domain/main-entities/chemo" e "simrs-vx/internal/domain/main-entities/chemo-protocol" + ee "simrs-vx/internal/domain/main-entities/encounter" + + uc "simrs-vx/internal/use-case/main-use-case/chemo" + ucp "simrs-vx/internal/use-case/main-use-case/chemo-plan" + ue "simrs-vx/internal/use-case/main-use-case/encounter" ) const source = "chemo-protocol" func Create(input e.CreateDto) (*d.Data, error) { data := e.ChemoProtocol{} + var err error event := pl.Event{ Feature: "Create", @@ -27,23 +37,43 @@ func Create(input e.CreateDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "create") - err := dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event, tx) - mwRunner.setMwType(pu.MWTPre) - // Run pre-middleware - if err := mwRunner.RunCreateMiddleware(createPreMw, &input, &data); err != nil { - return err + if input.Patient_Id == nil { + // get encounter + dataEncounter, err := ue.ReadDetailData(ee.ReadDetailDto{Id: *input.Encounter_Id}, &event) + if err != nil { + return nil, err } + input.Patient_Id = dataEncounter.Patient_Id + input.Status_Code = erc.DVCNew + } + + // get chemo + dataChemo, err := uc.ReadDetailData(ec.ReadDetailDto{Id: *input.Chemo_Id}, &event) + if err != nil { + return nil, err + } + + if dataChemo.Status_Code != erc.DVCVerified { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-validation-fail", + Detail: "chemo must be verified", + } + return nil, pl.SetLogError(&event, input) + } + + err = dg.I.Transaction(func(tx *gorm.DB) error { + // Insert Chemo-Protocol 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 { + // Insert Chemo-Plans + input.Id = &data.Id + if data.ChemoPlans, err = ucp.CreateData(&input, &event, tx); err != nil { return err } @@ -80,6 +110,15 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "readList") + if input.Patient_Id == nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-validation-fail", + Detail: "patient-id is required", + } + return nil, pl.SetLogError(&event, input) + } + err = dg.I.Transaction(func(tx *gorm.DB) error { mwRunner := newMiddlewareRunner(&event, tx) mwRunner.setMwType(pu.MWTPre) @@ -275,3 +314,65 @@ func Delete(input e.DeleteDto) (*d.Data, error) { }, nil } + +func Verify(input e.VerifyDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.ChemoProtocol + var err error + + event := pl.Event{ + Feature: "Verify", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "verify") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err + } + + if data.Status_Code != erc.DVCNew { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-state-mismatch", + Detail: "data is not new", + Raw: errors.New("data is not new"), + } + return pl.SetLogError(&event, input) + } + + data.VerifiedAt = pu.GetTimeNow() + data.Status_Code = erc.DVCVerified + data.VerifiedBy_User_Id = &input.AuthInfo.User_Id + + err = tx.Save(&data).Error + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-update-fail", + Detail: "Database update failed", + Raw: err, + } + return pl.SetLogError(&event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + + return nil + }) + + if err != nil { + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "verify", + }, + 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 index 66a63dcc..73e487f5 100644 --- a/internal/use-case/main-use-case/chemo-protocol/helper.go +++ b/internal/use-case/main-use-case/chemo-protocol/helper.go @@ -17,9 +17,15 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.ChemoProtocol) { inputSrc = &inputTemp.CreateDto } + data.Chemo_Id = inputSrc.Chemo_Id data.Patient_Weight = inputSrc.Patient_Weight data.Patient_Height = inputSrc.Patient_Height data.Diagnoses = inputSrc.Diagnoses + data.Interval = inputSrc.Interval + data.Cycle = inputSrc.Cycle + data.Series = inputSrc.Series data.StartDate = inputSrc.StartDate data.EndDate = inputSrc.EndDate + data.Status_Code = inputSrc.Status_Code + data.Patient_Id = inputSrc.Patient_Id } diff --git a/internal/use-case/main-use-case/chemo-protocol/lib.go b/internal/use-case/main-use-case/chemo-protocol/lib.go index 22e8808c..44a0bc80 100644 --- a/internal/use-case/main-use-case/chemo-protocol/lib.go +++ b/internal/use-case/main-use-case/chemo-protocol/lib.go @@ -2,7 +2,6 @@ package chemo_protocol import ( "errors" - plh "simrs-vx/pkg/lib-helper" pl "simrs-vx/pkg/logger" pu "simrs-vx/pkg/use-case-helper" diff --git a/internal/use-case/main-use-case/chemo/case.go b/internal/use-case/main-use-case/chemo/case.go index f7b3c7d3..a922c74a 100644 --- a/internal/use-case/main-use-case/chemo/case.go +++ b/internal/use-case/main-use-case/chemo/case.go @@ -4,10 +4,6 @@ import ( "errors" "strconv" - e "simrs-vx/internal/domain/main-entities/chemo" - - erc "simrs-vx/internal/domain/references/common" - dg "github.com/karincake/apem/db-gorm-pg" d "github.com/karincake/dodol" @@ -15,9 +11,13 @@ import ( pu "simrs-vx/pkg/use-case-helper" "gorm.io/gorm" + + erc "simrs-vx/internal/domain/references/common" + + e "simrs-vx/internal/domain/main-entities/chemo" ) -const source = "division" +const source = "chemo" func Create(input e.CreateDto) (*d.Data, error) { data := e.Chemo{} @@ -70,7 +70,6 @@ func Create(input e.CreateDto) (*d.Data, error) { } func ReadList(input e.ReadListDto) (*d.Data, error) { - var data *e.Chemo var dataList []e.Chemo var metaList *e.MetaDto var err error @@ -83,28 +82,17 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { // 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 input.Patient_Id == nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-validation-fail", + Detail: "patient-id is required", } + return nil, pl.SetLogError(&event, input) + } - 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 { + input.Encounter_Id = nil + if dataList, metaList, err = ReadListData(input, &event); err != nil { return nil, err } @@ -134,6 +122,15 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "readDetail") + if input.Encounter_Id == nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-validation-fail", + Detail: "Encounter-Id is required", + } + return nil, pl.SetLogError(&event, input) + } + err = dg.I.Transaction(func(tx *gorm.DB) error { mwRunner := newMiddlewareRunner(&event, tx) mwRunner.setMwType(pu.MWTPre) @@ -309,10 +306,12 @@ func Verify(input e.VerifyDto) (*d.Data, error) { } data.VerifiedAt = pu.GetTimeNow() - data.Status_Code = input.Status_Code + data.Status_Code = erc.DVCVerified data.VerifiedBy_User_Id = &input.AuthInfo.User_Id data.Bed = input.Bed data.Needs = input.Needs + data.Doctor_Code = input.Doctor_Code + data.NextChemoDate = input.NextChemoDate err = tx.Save(&data).Error if err != nil { diff --git a/internal/use-case/main-use-case/chemo/helper.go b/internal/use-case/main-use-case/chemo/helper.go index c241bce3..96012228 100644 --- a/internal/use-case/main-use-case/chemo/helper.go +++ b/internal/use-case/main-use-case/chemo/helper.go @@ -20,4 +20,5 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Chemo) { data.Encounter_Id = inputSrc.Encounter_Id data.Status_Code = inputSrc.Status_Code data.Specialist_Code = inputSrc.Specialist_Code + data.Class_Code = inputSrc.Class_Code } diff --git a/internal/use-case/main-use-case/chemo/lib.go b/internal/use-case/main-use-case/chemo/lib.go index 39679170..8b848d8f 100644 --- a/internal/use-case/main-use-case/chemo/lib.go +++ b/internal/use-case/main-use-case/chemo/lib.go @@ -47,8 +47,16 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Ch tx = dg.I } + if input.Class_Code != "" { + tx = tx.Where(`"Chemo"."Class_Code" = ?`, input.Class_Code) + input.Class_Code = "" + } + tx = tx. Model(&e.Chemo{}). + Joins(`LEFT JOIN "Encounter" "e" ON "e"."Id" = "Chemo"."Encounter_Id"`). + Joins(`LEFT JOIN "Patient" "p" ON "e"."Patient_Id" = "p"."Id"`). + Where(`"p"."Id" = ?`, input.Patient_Id). Scopes(gh.Preload(input.Includes)). Scopes(gh.Filter(input.FilterDto)). Count(&count). @@ -81,7 +89,10 @@ func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e tx = dg.I } - if err := tx.First(&data, input.Id).Error; err != nil { + if err := tx. + Scopes(gh.Preload(input.Includes)). + Scopes(gh.Filter(input.FilterDto)). + First(&data, input.Id).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/encounter/case.go b/internal/use-case/main-use-case/encounter/case.go index dd131944..eb0c29dc 100644 --- a/internal/use-case/main-use-case/encounter/case.go +++ b/internal/use-case/main-use-case/encounter/case.go @@ -889,7 +889,7 @@ func ApproveSwitchSpecialist(input e.ApproveCancelSpecialistDto) (*d.Data, error } // Set doctor_code; nil indicates no change. - if input.Dst_Doctor_Code == nil { + if input.Dst_Doctor_Code == nil || *input.Dst_Doctor_Code == "" { input.Dst_Doctor_Code = irData.Doctor_Code } @@ -1094,17 +1094,17 @@ func CreateWithPatient(input e.CreateWithPatientDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "create") roleAllowed := []string{string(erg.EPCReg)} - err = validateAuth(input.Encounter.AuthInfo, roleAllowed, "create-encounter", &event) + err = validateAuth(input.AuthInfo, roleAllowed, "create-encounter", &event) if err != nil { return nil, err } // validate rehab by bpjs - if input.Encounter.RefTypeCode == ere.RTCBpjs && - input.Encounter.Class_Code == ere.ECAmbulatory && - ere.AmbulatoryClassCode(*input.Encounter.SubClass_Code) == ere.ACCRehab { + if input.RefTypeCode == ere.RTCBpjs && + input.Class_Code == ere.ECAmbulatory && + ere.AmbulatoryClassCode(*input.SubClass_Code) == ere.ACCRehab { // get latest rehab data - recentRehabData, err := getLatestRehabData(input.Encounter, &event) + recentRehabData, err := getLatestRehabData(input.CreateDto, &event) if err != nil { return nil, err } @@ -1115,18 +1115,18 @@ func CreateWithPatient(input e.CreateWithPatientDto) (*d.Data, error) { // If the mode is "series", verify whether the visit count still remains // and whether the series has not expired. // If visitMode is "series", then get encounterAdm - input.Encounter.VisitMode_Code, input.Encounter.RecentEncounterAdm, err = determineVisitMode(recentRehabData, input.Encounter, &event) + input.VisitMode_Code, input.RecentEncounterAdm, err = determineVisitMode(recentRehabData, input.CreateDto, &event) if err != nil { return nil, err } } else { - input.Encounter.VisitMode_Code = ere.VMCAdm + input.VisitMode_Code = ere.VMCAdm } // When visitMode_Code is "series", load the associated SOAPI record to copy its values. - if input.Encounter.VisitMode_Code == ere.VMCSeries { + if input.VisitMode_Code == ere.VMCSeries { // get data soapi - recentSoapiDataforCopy, err = getSoapiEncounterAdm(*input.Encounter.RecentEncounterAdm, &event) + recentSoapiDataforCopy, err = getSoapiEncounterAdm(*input.RecentEncounterAdm, &event) if err != nil { return nil, err } @@ -1134,13 +1134,13 @@ func CreateWithPatient(input e.CreateWithPatientDto) (*d.Data, error) { } // check if patient is new in the hospital - input.Encounter.NewStatus, err = identifyPatientStatus(input.Encounter) + input.NewStatus, err = identifyPatientStatus(input.CreateDto) if err != nil { return nil, err } - input.Encounter.Adm_Employee_Id = input.Encounter.AuthInfo.Employee_Id + input.Adm_Employee_Id = input.AuthInfo.Employee_Id - mwRunner := newMiddlewareRunner(&event, input.Encounter.Sync) + mwRunner := newMiddlewareRunner(&event, input.Sync) err = dg.I.Transaction(func(tx *gorm.DB) error { // create patient @@ -1155,28 +1155,28 @@ func CreateWithPatient(input e.CreateWithPatientDto) (*d.Data, error) { } // create encounter - input.Encounter.Patient_Id = &patientId - if resData, err := CreateData(input.Encounter, &event, tx); err != nil { + input.Patient_Id = &patientId + if resData, err := CreateData(input.CreateDto, &event, tx); err != nil { return err } else { data = *resData - input.Encounter.Id = data.Id + input.Id = data.Id } // insert ambulatory/emergency/inpatient - err = insertdataClassCode(input.Encounter, recentSoapiDataforCopy, &event, tx) + err = insertdataClassCode(input.CreateDto, recentSoapiDataforCopy, &event, tx) if err != nil { return err } // insert vclaimReference - if vr := input.Encounter.VclaimReference; vr != nil { + if vr := input.VclaimReference; vr != nil { t, _ := time.Parse("2006-01-02", vr.TglRujukan) _, err = uv.CreateData(ev.CreateDto{ Encounter_Id: &data.Id, Date: &t, - SrcCode: input.Encounter.Ref_Number, - SrcName: input.Encounter.RefSource_Name, + SrcCode: input.Ref_Number, + SrcName: input.RefSource_Name, Number: &vr.NoSep}, &event, tx) if err != nil { return err diff --git a/internal/use-case/main-use-case/encounter/helper.go b/internal/use-case/main-use-case/encounter/helper.go index e3dfb00c..29d7fa9b 100644 --- a/internal/use-case/main-use-case/encounter/helper.go +++ b/internal/use-case/main-use-case/encounter/helper.go @@ -7,7 +7,6 @@ package encounter import ( "errors" "fmt" - un "simrs-vx/internal/use-case/main-use-case/nurse" "strings" "time" @@ -24,9 +23,10 @@ import ( 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" ec "simrs-vx/internal/domain/main-entities/chemo" + ecpl "simrs-vx/internal/domain/main-entities/chemo-plan" + ecp "simrs-vx/internal/domain/main-entities/chemo-protocol" edo "simrs-vx/internal/domain/main-entities/device-order" ed "simrs-vx/internal/domain/main-entities/doctor" ee "simrs-vx/internal/domain/main-entities/emergency" @@ -42,12 +42,9 @@ import ( 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" es "simrs-vx/internal/domain/main-entities/soapi" esp "simrs-vx/internal/domain/main-entities/specialist" - // udo "simrs-vx/internal/use-case/main-use-case/device-order" - uaeh "simrs-vx/internal/use-case/main-use-case/adm-employee-hist" ua "simrs-vx/internal/use-case/main-use-case/ambulatory" uc "simrs-vx/internal/use-case/main-use-case/chemo" ud "simrs-vx/internal/use-case/main-use-case/doctor" @@ -58,10 +55,10 @@ import ( umi "simrs-vx/internal/use-case/main-use-case/medicine-mix" ummi "simrs-vx/internal/use-case/main-use-case/medicine-mix-item" _ "simrs-vx/internal/use-case/main-use-case/nurse" + un "simrs-vx/internal/use-case/main-use-case/nurse" up "simrs-vx/internal/use-case/main-use-case/prescription" upi "simrs-vx/internal/use-case/main-use-case/prescription-item" ur "simrs-vx/internal/use-case/main-use-case/rehab" - urdh "simrs-vx/internal/use-case/main-use-case/responsible-doctor-hist" us "simrs-vx/internal/use-case/main-use-case/soapi" ) @@ -396,192 +393,6 @@ func getMcuOrders(encounter_id uint, event *pl.Event, tx *gorm.DB) error { return 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_Code": input.Doctor_Code, - "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.FinishedAt) - - 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.FinishedAt) - - 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 getSoapiByResponsibleDoctor(enc e.Encounter, event *pl.Event) (data []es.Soapi, err error) { pl.SetLogInfo(event, enc, "started", "DBReadList") @@ -849,13 +660,31 @@ func insertdataClassCode(input e.CreateDto, soapiData []es.CreateDto, event *pl. func insertDataSubClassAmbulatory(input e.CreateDto, soapiData []es.CreateDto, event *pl.Event, tx *gorm.DB) (err error) { subCode := ere.AmbulatoryClassCode(*input.SubClass_Code) + var chemoPlan *ecpl.ChemoPlan switch { case subCode == ere.ACCChemo: + // validate if encounter Chemo valid + chemoPlan, err = validateChemo(*input.Patient_Id, event) + if err != nil { + return err + } + + if chemoPlan == nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-not-found", + Detail: "chemo plan not found", + } + + return pl.SetLogError(event, input) + } + chemoCreate := ec.CreateDto{ Encounter_Id: &input.Id, - Status_Code: erc.DVCNew, + Status_Code: erc.DVCVerified, Specialist_Code: input.Specialist_Code, + Class_Code: ere.CCCAct, } // create data chemo @@ -864,6 +693,13 @@ func insertDataSubClassAmbulatory(input e.CreateDto, soapiData []es.CreateDto, e return err } + // set chemo-plan to planned + chemoPlan.Encounter_Id = &input.Id + err = updateChemoPlan(chemoPlan, event, tx) + if err != nil { + return err + } + case subCode == ere.ACCRehab: rehabData := er.CreateDto{ Encounter_Id: &input.Id, @@ -1009,18 +845,18 @@ func getDoctors(doctorIds []string, event *pl.Event) ([]ed.Doctor, error) { return doctors, nil } -func validateSpecialistCodes(unitCodes map[string]struct{}, event *pl.Event) error { - if len(unitCodes) > 0 { +func validateSpecialistCodes(speCodes map[string]struct{}, event *pl.Event) error { + if len(speCodes) > 0 { var codes []string - for code := range unitCodes { + for code := range speCodes { codes = append(codes, code) } - units, err := getSpecialists(codes, event) + specialists, err := getSpecialists(codes, event) if err != nil { return fmt.Errorf("failed to fetch units: %w", err) } - if len(units) != len(codes) { + if len(specialists) != len(codes) { event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ Code: "data-validation-fail", @@ -1056,3 +892,127 @@ func validateDoctorCodes(doctorCodes map[string]struct{}, event *pl.Event) error return nil } + +func updateChemoPlan(data *ecpl.ChemoPlan, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, nil, "started", "getChemoFromEncounter") + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + err := tx.Model(&data).Updates(map[string]interface{}{ + `"Status"`: ere.SPCPlanned, + `"Encounter_Id"`: data.Encounter_Id}).Error + if err != nil { + return err + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} + +func getChemoProtocol(patientId uint, event *pl.Event) (*ecp.ChemoProtocol, error) { + pl.SetLogInfo(event, nil, "started", "getChemoProtocol") + data := ecp.ChemoProtocol{} + + var tx = dg.I + + tx = tx.Model(&ecp.ChemoProtocol{}). + Joins(`LEFT JOIN "ChemoPlan" cp ON cp."Protocol_Id" = "ChemoProtocol"."Id"`). + Where(`"ChemoProtocol"."Patient_Id" = ?`, patientId). + Preload("ChemoPlans", func(db *gorm.DB) *gorm.DB { + return db. + Where(`"Status" IS NULL OR "Status" = ?`, ere.SPCSchedule). + Order(`"Id" ASC`). + Limit(1) + }). + Order(`"CreatedAt" DESC`). + First(&data) + + if err := tx.Error; err != nil { + return nil, err + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func validateChemo(patientId uint, event *pl.Event) (*ecpl.ChemoPlan, error) { + // get chemo adm + chemoAdm, err := getChemoAdm(patientId, event) + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-not-found", + Detail: "patient doesn't have active chemo", + } + + return nil, pl.SetLogError(event, patientId) + } + return nil, err + } + + // validate is chemo verified + if chemoAdm.Status_Code != erc.DVCVerified { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-not-match", + Detail: fmt.Sprintf("chemo not yet verified"), + } + return nil, pl.SetLogError(event, chemoAdm) + } + + // get chemo protocol + chemoProtocol, err := getChemoProtocol(patientId, event) + if err != nil { + return nil, err + } + + if chemoProtocol.Status_Code != erc.DVCVerified { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-not-match", + Detail: fmt.Sprintf("protocol chemo not yet verified"), + } + return nil, pl.SetLogError(event, chemoProtocol) + } + + if now.Before(*chemoProtocol.StartDate) || now.After(*chemoProtocol.EndDate) { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "invalid-date-range", + Detail: "chemo cannot be performed because the current date is outside the allowed treatment window.", + } + return nil, pl.SetLogError(event, chemoProtocol) + } + + if chemoProtocol.ChemoPlans == nil || len(*chemoProtocol.ChemoPlans) == 0 { + return nil, nil + } + + // Return the first chemo plan + return &(*chemoProtocol.ChemoPlans)[0], nil +} + +func getChemoAdm(patientId uint, event *pl.Event) (*ec.Chemo, error) { + pl.SetLogInfo(event, nil, "started", "getChemoProtocol") + data := ec.Chemo{} + + var tx = dg.I + + tx = tx.Model(&ec.Chemo{}). + Joins(`LEFT JOIN "Encounter" e ON e."Id" = "Chemo"."Encounter_Id"`). + Where(`e."Patient_Id" = ? AND "Chemo"."Class_Code" = ?`, patientId, ere.CCCAdm). + Order(`"CreatedAt" DESC`). + First(&data) + + if err := tx.Error; err != nil { + return nil, err + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} diff --git a/internal/use-case/main-use-case/encounter/lib.go b/internal/use-case/main-use-case/encounter/lib.go index d102030a..79ba4aed 100644 --- a/internal/use-case/main-use-case/encounter/lib.go +++ b/internal/use-case/main-use-case/encounter/lib.go @@ -59,10 +59,11 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.En } else { tx = dg.I } + tx = tx.Model(&e.Encounter{}) if input.AuthInfo.Doctor_Code != nil { - tx.Where("\"Responsible_Doctor_Code\" = ?", *input.AuthInfo.Doctor_Code) // + tx = tx.Where("\"Responsible_Doctor_Code\" = ?", *input.AuthInfo.Doctor_Code) // } if input.StartDate != nil && input.EndDate != nil { @@ -75,7 +76,8 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.En if input.Patient_Identifier != nil { tx = tx.Joins("JOIN \"Patient\" ON \"Patient\".\"Id\" = \"Encounter\".\"Patient_Id\""). - Joins("JOIN \"Person\" ON \"Person\".\"Id\" = \"Patient\".\"Person_Id\"").Where("\"Person\".\"Name\" ILIKE ? OR \"Patient\".\"Number\" = ?", "%"+*input.Patient_Identifier+"%", *input.Patient_Identifier) + Joins("JOIN \"Person\" ON \"Person\".\"Id\" = \"Patient\".\"Person_Id\""). + Where("\"Person\".\"Name\" ILIKE ? OR \"Patient\".\"Number\" = ?", "%"+*input.Patient_Identifier+"%", *input.Patient_Identifier) } // TODO: getuk lib need to be updated to support this @@ -91,10 +93,15 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.En tx = tx.Where("\"Encounter\".\"PaymentMethod_Code\" = ?", *input.PaymentMethod_Code) } - tx = tx.Scopes(gh.Preload(input.Includes)). - Count(&count). - Scopes(gh.Paginate(input, &pagination)). - Order("\"CreatedAt\" DESC") + if input.ChemoClass != nil { + tx = tx.Joins(`RIGHT JOIN "Chemo" "c" ON "c"."Encounter_Id" = "Encounter"."Id"`). + Where(`"c"."Class_Code" = ?`, *input.ChemoClass) + } + + // count + if err := tx.Count(&count).Error; err != nil { + return nil, nil, plh.HandleListError(input, event, err) + } // tx.Debug().Scopes(gh.Preload(input.Includes)). // Scopes(gh.Filter(input.FilterDto)). @@ -102,7 +109,11 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.En // Scopes(gh.Paginate(input, &pagination)). // Order("\"CreatedAt\" DESC") - if err := tx.Find(&data).Error; err != nil { + if err := tx. + Scopes(gh.Preload(input.Includes)). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC"). + Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/internal/use-case/main-use-case/generate-file/helper.go b/internal/use-case/main-use-case/generate-file/helper.go index adcdc16d..3756330e 100644 --- a/internal/use-case/main-use-case/generate-file/helper.go +++ b/internal/use-case/main-use-case/generate-file/helper.go @@ -328,6 +328,10 @@ func generateResumeTemplateData(resume er.Resume, event pl.Event, tx *gorm.DB) ( templateData.DischargeMethod = rData.Management.DischargeMethod templateData.Medications = rData.Medication.Medications templateData.Date = pu.GetTimeNow().Format("02-01-2006") + // this below is just my guess + // templateData.ControlHealthcare = get from vclaim sep eg. III + // templateData.ControlUnit = get from vclaim sep eg. R.KERINCI - KLS 3 + // templateData.ControlDate = get from vclaim sep eg. 2022-01-01 return &templateData, nil } diff --git a/internal/use-case/main-use-case/generate-file/tycovar.go b/internal/use-case/main-use-case/generate-file/tycovar.go index fd62787a..bf68b143 100644 --- a/internal/use-case/main-use-case/generate-file/tycovar.go +++ b/internal/use-case/main-use-case/generate-file/tycovar.go @@ -62,10 +62,10 @@ type ResumePDF struct { ConditionOnDischarge string DischargeMethod string Medications []er.MedicationEntry - // fasyankes - // date - // klinik - Date string + ControlHealthcare string + ControlUnit string + ControlDate string + Date string } type ScreeningPDF struct { diff --git a/internal/use-case/main-use-case/installation/case.go b/internal/use-case/main-use-case/installation/case.go index b80b6ca5..fb18b655 100644 --- a/internal/use-case/main-use-case/installation/case.go +++ b/internal/use-case/main-use-case/installation/case.go @@ -241,6 +241,40 @@ func Delete(input e.DeleteDto) (*d.Data, error) { } +func CreateBulk(input e.CreateBulkDto) (*d.Data, error) { + var data []e.Installation + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + err := dg.I.Transaction(func(tx *gorm.DB) error { + if resData, err := CreateBulkData(input.Value, &event, tx); err != nil { + return err + } else { + data = *resData + } + return nil + }) + + if err != nil { + return nil, err + } + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + Data: e.ToResponseList(data), + }, nil +} + func runLogMiddleware(err error, input any, mwRunner *middlewareRunner) error { var errMsg string inputLog := esync.SimxLogDto{ diff --git a/internal/use-case/main-use-case/installation/helper.go b/internal/use-case/main-use-case/installation/helper.go index d3d96b5c..a8055c6c 100644 --- a/internal/use-case/main-use-case/installation/helper.go +++ b/internal/use-case/main-use-case/installation/helper.go @@ -21,3 +21,15 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Installation) { data.Name = inputSrc.Name data.EncounterClass_Code = inputSrc.EncounterClass_Code } + +func setBulkData(input []e.CreateDto) (data []e.Installation) { + for _, i := range input { + data = append(data, e.Installation{ + Code: *i.Code, + Name: i.Name, + EncounterClass_Code: i.EncounterClass_Code, + }) + } + + return data +} diff --git a/internal/use-case/main-use-case/installation/lib.go b/internal/use-case/main-use-case/installation/lib.go index d75b2ecd..218c738d 100644 --- a/internal/use-case/main-use-case/installation/lib.go +++ b/internal/use-case/main-use-case/installation/lib.go @@ -1,6 +1,7 @@ package installation import ( + "fmt" e "simrs-vx/internal/domain/main-entities/installation" plh "simrs-vx/pkg/lib-helper" @@ -147,3 +148,26 @@ func DeleteData(data *e.Installation, event *pl.Event, dbx ...*gorm.DB) error { pl.SetLogInfo(event, nil, "complete") return nil } + +func CreateBulkData(input []e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*[]e.Installation, error) { + pl.SetLogInfo(event, nil, "started", "DBBulkCreate") + + data := setBulkData(input) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + result := tx.Create(&data) + if err := result.Error; err != nil { + return nil, plh.HandleCreateError(input, event, err) + } + + fmt.Println("Inserted:", result.RowsAffected) + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} diff --git a/internal/use-case/main-use-case/prescription-item/lib.go b/internal/use-case/main-use-case/prescription-item/lib.go index aa5c9e2b..1c21304b 100644 --- a/internal/use-case/main-use-case/prescription-item/lib.go +++ b/internal/use-case/main-use-case/prescription-item/lib.go @@ -47,7 +47,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Pr tx = dg.I } - tx = tx.Debug(). + tx = tx. Model(&e.PrescriptionItem{}). Scopes(gh.Preload(input.Includes)). Scopes(gh.Filter(input.FilterDto)). diff --git a/internal/use-case/main-use-case/soapi/case.go b/internal/use-case/main-use-case/soapi/case.go index ebf1c7d8..f74ef594 100644 --- a/internal/use-case/main-use-case/soapi/case.go +++ b/internal/use-case/main-use-case/soapi/case.go @@ -2,19 +2,20 @@ package soapi import ( "errors" - erc "simrs-vx/internal/domain/references/common" - esync "simrs-vx/internal/domain/sync-entities/log" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" "strconv" - e "simrs-vx/internal/domain/main-entities/soapi" - dg "github.com/karincake/apem/db-gorm-pg" d "github.com/karincake/dodol" - - pl "simrs-vx/pkg/logger" - pu "simrs-vx/pkg/use-case-helper" - "gorm.io/gorm" + + erc "simrs-vx/internal/domain/references/common" + + e "simrs-vx/internal/domain/main-entities/soapi" + esync "simrs-vx/internal/domain/sync-entities/log" + + ucp "simrs-vx/internal/use-case/main-use-case/chemo-plan" ) const source = "soapi" @@ -41,13 +42,26 @@ func Create(input e.CreateDto) (*d.Data, error) { return nil, pl.SetLogError(&event, input) } - err := dg.I.Transaction(func(tx *gorm.DB) error { + chemoPlan, err := validateIfEncounterIsChemo(*input.Encounter_Id, "c", &event) + if err != nil { + return nil, err + } + + err = dg.I.Transaction(func(tx *gorm.DB) error { if resData, err := CreateData(input, &event, tx); err != nil { return err } else { data = *resData } + // update chemoPlan + if chemoPlan != nil { + chemoPlan.Encounter_Id = input.Encounter_Id + if err = ucp.UpdateData(chemoPlan, "c", &event, tx); err != nil { + return err + } + } + // get detail for sync soapiData, err := ReadDetailData(e.ReadDetailDto{ Id: data.Id, @@ -238,6 +252,18 @@ func Delete(input e.DeleteDto) (*d.Data, error) { return err } + // update chemoPlan + chemoPlan, err := validateIfEncounterIsChemo(*data.Encounter_Id, "d", &event) + if err != nil { + return err + } + + if chemoPlan != nil { + if err = ucp.UpdateData(chemoPlan, "d", &event, tx); err != nil { + return err + } + } + mwRunner.setMwType(pu.MWTPre) // Run pre-middleware if err = mwRunner.ExecuteIfSyncOn(func() error { diff --git a/internal/use-case/main-use-case/soapi/helper.go b/internal/use-case/main-use-case/soapi/helper.go index c42b95d0..74a63b80 100644 --- a/internal/use-case/main-use-case/soapi/helper.go +++ b/internal/use-case/main-use-case/soapi/helper.go @@ -5,6 +5,17 @@ Any functions that are used internally by the use-case package soapi import ( + "errors" + pl "simrs-vx/pkg/logger" + + dg "github.com/karincake/apem/db-gorm-pg" + "gorm.io/gorm" + + ere "simrs-vx/internal/domain/references/encounter" + + ecpl "simrs-vx/internal/domain/main-entities/chemo-plan" + ecp "simrs-vx/internal/domain/main-entities/chemo-protocol" + ee "simrs-vx/internal/domain/main-entities/encounter" e "simrs-vx/internal/domain/main-entities/soapi" ) @@ -39,3 +50,77 @@ func setBulkData(input []e.CreateDto, encounterId uint) []e.Soapi { return data } + +func validateIfEncounterIsChemo(encounterId uint, method string, event *pl.Event) (*ecpl.ChemoPlan, error) { + // get encounter + enc, err := getEncounter(encounterId, event) + if err != nil { + return nil, err + } + + // Encounter must be Ambulatory and NOT Rehab + a := enc.Ambulatory + if a == nil || a.Class_Code == ere.ACCRehab { + return nil, nil + } + + // get chemo protocol + chemo, err := getChemo(*enc.Patient_Id, enc.Id, event) + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, nil + } + return nil, pl.SetLogError(event, nil) + } + + if chemo.ChemoPlans == nil || len(*chemo.ChemoPlans) == 0 { + return nil, nil + } + + // Return the first chemo plan + return &(*chemo.ChemoPlans)[0], nil +} + +func getEncounter(encounterId uint, event *pl.Event) (*ee.Encounter, error) { + pl.SetLogInfo(event, nil, "started", "getEncounter") + data := ee.Encounter{} + + var tx = dg.I + + err := tx.Model(&ee.Encounter{}). + Joins(`LEFT JOIN "Ambulatory" a ON a."Encounter_Id" = "Encounter"."Id"`). + Where(`"Encounter"."Id" = ?`, encounterId). + Where(`"Encounter"."Class_Code" = ?`, ere.ECAmbulatory). + Preload("Ambulatory"). + First(&data).Error + + if err != nil { + return nil, err + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func getChemo(patientId, encounterId uint, event *pl.Event) (*ecp.ChemoProtocol, error) { + pl.SetLogInfo(event, nil, "started", "getChemo") + data := ecp.ChemoProtocol{} + + var tx = dg.I + + tx = tx.Model(&ecp.ChemoProtocol{}). + Joins(`LEFT JOIN "ChemoPlan" cp ON cp."Protocol_Id" = "ChemoProtocol"."Id"`). + Where(`"ChemoProtocol"."Patient_Id" = ?`, patientId). + Preload("ChemoPlans", func(db *gorm.DB) *gorm.DB { + return db. + Where(`"Encounter_Id" = ?`, encounterId) + }). + First(&data) + + if err := tx.Error; err != nil { + return nil, err + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} diff --git a/internal/use-case/main-use-case/specialist/case.go b/internal/use-case/main-use-case/specialist/case.go index f9f5442b..547677cd 100644 --- a/internal/use-case/main-use-case/specialist/case.go +++ b/internal/use-case/main-use-case/specialist/case.go @@ -295,3 +295,37 @@ func runLogMiddleware(err error, input any, mwRunner *middlewareRunner) error { return nil } + +func CreateBulk(input e.CreateBulkDto) (*d.Data, error) { + var data []e.Specialist + + event := pl.Event{ + Feature: "CreateBulk", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + err := dg.I.Transaction(func(tx *gorm.DB) error { + if resData, err := CreateBulkData(input.Value, &event, tx); err != nil { + return err + } else { + data = *resData + } + return nil + }) + + if err != nil { + return nil, err + } + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + Data: e.ToResponseList(data), + }, nil +} diff --git a/internal/use-case/main-use-case/specialist/helper.go b/internal/use-case/main-use-case/specialist/helper.go index 8a71d2cb..f5130d4e 100644 --- a/internal/use-case/main-use-case/specialist/helper.go +++ b/internal/use-case/main-use-case/specialist/helper.go @@ -21,3 +21,15 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Specialist) { data.Name = inputSrc.Name data.Installation_Code = inputSrc.Installation_Code } + +func setBulkData(input []e.CreateDto) (data []e.Specialist) { + for _, i := range input { + data = append(data, e.Specialist{ + Code: i.Code, + Name: i.Name, + Installation_Code: i.Installation_Code, + }) + } + + return data +} diff --git a/internal/use-case/main-use-case/specialist/lib.go b/internal/use-case/main-use-case/specialist/lib.go index 069f5fbb..c7f27b91 100644 --- a/internal/use-case/main-use-case/specialist/lib.go +++ b/internal/use-case/main-use-case/specialist/lib.go @@ -1,6 +1,7 @@ package specialist import ( + "fmt" e "simrs-vx/internal/domain/main-entities/specialist" plh "simrs-vx/pkg/lib-helper" @@ -147,3 +148,26 @@ func DeleteData(data *e.Specialist, event *pl.Event, dbx ...*gorm.DB) error { pl.SetLogInfo(event, nil, "complete") return nil } + +func CreateBulkData(input []e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*[]e.Specialist, error) { + pl.SetLogInfo(event, nil, "started", "DBBulkCreate") + + data := setBulkData(input) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + result := tx.Create(&data) + if err := result.Error; err != nil { + return nil, plh.HandleCreateError(input, event, err) + } + + fmt.Println("Inserted:", result.RowsAffected) + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} diff --git a/internal/use-case/main-use-case/subspecialist/case.go b/internal/use-case/main-use-case/subspecialist/case.go index ca99750d..7d60b73b 100644 --- a/internal/use-case/main-use-case/subspecialist/case.go +++ b/internal/use-case/main-use-case/subspecialist/case.go @@ -293,3 +293,37 @@ func runLogMiddleware(err error, input any, mwRunner *middlewareRunner) error { return nil } + +func CreateBulk(input e.CreateBulkDto) (*d.Data, error) { + var data []e.Subspecialist + + event := pl.Event{ + Feature: "CreateBulk", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + err := dg.I.Transaction(func(tx *gorm.DB) error { + if resData, err := CreateBulkData(input.Value, &event, tx); err != nil { + return err + } else { + data = *resData + } + return nil + }) + + if err != nil { + return nil, err + } + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + Data: e.ToResponseList(data), + }, nil +} diff --git a/internal/use-case/main-use-case/subspecialist/helper.go b/internal/use-case/main-use-case/subspecialist/helper.go index 08d64941..4cb1b8da 100644 --- a/internal/use-case/main-use-case/subspecialist/helper.go +++ b/internal/use-case/main-use-case/subspecialist/helper.go @@ -6,6 +6,7 @@ package subspecialist import ( e "simrs-vx/internal/domain/main-entities/subspecialist" + "simrs-vx/internal/domain/main-entities/subspecialist/base" ) func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Subspecialist) { @@ -21,3 +22,16 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Subspecialist) { data.Name = inputSrc.Name data.Specialist_Code = inputSrc.Specialist_Code } + +func setBulkData(input []e.CreateDto) (data []e.Subspecialist) { + for _, i := range input { + data = append(data, e.Subspecialist{ + Basic: base.Basic{ + Code: i.Code, + Name: i.Name, + }, + }) + } + + return data +} diff --git a/internal/use-case/main-use-case/subspecialist/lib.go b/internal/use-case/main-use-case/subspecialist/lib.go index c5a742df..af35fa56 100644 --- a/internal/use-case/main-use-case/subspecialist/lib.go +++ b/internal/use-case/main-use-case/subspecialist/lib.go @@ -1,6 +1,7 @@ package subspecialist import ( + "fmt" e "simrs-vx/internal/domain/main-entities/subspecialist" plh "simrs-vx/pkg/lib-helper" @@ -147,3 +148,26 @@ func DeleteData(data *e.Subspecialist, event *pl.Event, dbx ...*gorm.DB) error { pl.SetLogInfo(event, nil, "complete") return nil } + +func CreateBulkData(input []e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*[]e.Subspecialist, error) { + pl.SetLogInfo(event, nil, "started", "DBBulkCreate") + + data := setBulkData(input) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + result := tx.Create(&data) + if err := result.Error; err != nil { + return nil, plh.HandleCreateError(input, event, err) + } + + fmt.Println("Inserted:", result.RowsAffected) + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} diff --git a/internal/use-case/main-use-case/vaccine-data/case.go b/internal/use-case/main-use-case/vaccine-data/case.go new file mode 100644 index 00000000..dbe76f96 --- /dev/null +++ b/internal/use-case/main-use-case/vaccine-data/case.go @@ -0,0 +1,303 @@ +package vaccinedata + +import ( + "errors" + "strconv" + + e "simrs-vx/internal/domain/main-entities/vaccine-data" + 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 = "vaccine-data" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.VaccineData{} + + 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.Vaccination_datetime) { + return errors.New("vaccination date is in the past") + } + if pu.IsDateBeforeNow(input.Vaccine_expiration_date) { + return errors.New("vaccine expiration 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.VaccineData + var dataList []e.VaccineData + 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.VaccineData + 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.VaccineData + 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.Vaccination_datetime) { + return errors.New("vaccination date is in the past") + } + if pu.IsDateBeforeNow(input.Vaccine_expiration_date) { + return errors.New("vaccine expiration 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.VaccineData + 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/vaccine-data/helper.go b/internal/use-case/main-use-case/vaccine-data/helper.go new file mode 100644 index 00000000..a2b423ec --- /dev/null +++ b/internal/use-case/main-use-case/vaccine-data/helper.go @@ -0,0 +1,28 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package vaccinedata + +import ( + e "simrs-vx/internal/domain/main-entities/vaccine-data" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.VaccineData) { + 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.Vaccine_type_Code = inputSrc.Vaccine_type_Code + data.Vaccine_batch_number = inputSrc.Vaccine_batch_number + data.Vaccine_dose = inputSrc.Vaccine_dose + data.Dose_order = inputSrc.Dose_order + data.Injection_location = inputSrc.Injection_location + data.Vaccination_datetime = inputSrc.Vaccination_datetime + data.Vaccine_expiration_date = inputSrc.Vaccine_expiration_date +} diff --git a/internal/use-case/main-use-case/vaccine-data/lib.go b/internal/use-case/main-use-case/vaccine-data/lib.go new file mode 100644 index 00000000..e9d0a5e2 --- /dev/null +++ b/internal/use-case/main-use-case/vaccine-data/lib.go @@ -0,0 +1,144 @@ +package vaccinedata + +import ( + e "simrs-vx/internal/domain/main-entities/vaccine-data" + + 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.VaccineData, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.VaccineData{} + 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.VaccineData, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.VaccineData{} + 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.VaccineData{}). + 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.VaccineData, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.VaccineData{} + + 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.VaccineData, 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.VaccineData, 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/vaccine-data/middleware-runner.go b/internal/use-case/main-use-case/vaccine-data/middleware-runner.go new file mode 100644 index 00000000..985cb6d9 --- /dev/null +++ b/internal/use-case/main-use-case/vaccine-data/middleware-runner.go @@ -0,0 +1,103 @@ +package vaccinedata + +import ( + e "simrs-vx/internal/domain/main-entities/vaccine-data" + 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.VaccineData) 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.VaccineData) 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.VaccineData) 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.VaccineData) 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.VaccineData) 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/vaccine-data/middleware.go b/internal/use-case/main-use-case/vaccine-data/middleware.go new file mode 100644 index 00000000..02c0cda6 --- /dev/null +++ b/internal/use-case/main-use-case/vaccine-data/middleware.go @@ -0,0 +1,9 @@ +package vaccinedata + +// 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/vaccine-data/tycovar.go b/internal/use-case/main-use-case/vaccine-data/tycovar.go new file mode 100644 index 00000000..d32700e1 --- /dev/null +++ b/internal/use-case/main-use-case/vaccine-data/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 vaccinedata + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/vaccine-data" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.VaccineData, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.VaccineData, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.VaccineData, 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/simgos-sync-use-case/new/installation/helper.go b/internal/use-case/simgos-sync-use-case/new/installation/helper.go index 1bb722dd..ab0efb25 100644 --- a/internal/use-case/simgos-sync-use-case/new/installation/helper.go +++ b/internal/use-case/simgos-sync-use-case/new/installation/helper.go @@ -11,6 +11,7 @@ import ( esimgos "simrs-vx/internal/domain/simgos-entities/m-instalasi" esync "simrs-vx/internal/domain/sync-entities/installation" esyncLog "simrs-vx/internal/domain/sync-entities/log" + "strconv" ) func setDataSimgos[T *e.CreateDto | *e.UpdateDto](input T) (data esimgos.MInstalasi) { @@ -56,3 +57,14 @@ func setDataSimxLink(simxId, simgosId uint) (data esync.InstallationLink) { data.Simgos_Id = simgosId return } + +func setBulkDataSimxLink(input []e.Installation) (data []esync.InstallationLink) { + for _, i := range input { + kode, _ := strconv.Atoi(i.Code) + data = append(data, esync.InstallationLink{ + Simx_Id: uint(i.Id), + Simgos_Id: uint(kode), + }) + } + return +} diff --git a/internal/use-case/simgos-sync-use-case/new/installation/lib.go b/internal/use-case/simgos-sync-use-case/new/installation/lib.go index a8d074fa..bd906679 100644 --- a/internal/use-case/simgos-sync-use-case/new/installation/lib.go +++ b/internal/use-case/simgos-sync-use-case/new/installation/lib.go @@ -1,6 +1,7 @@ package installation import ( + "fmt" plh "simrs-vx/pkg/lib-helper" pl "simrs-vx/pkg/logger" pu "simrs-vx/pkg/use-case-helper" @@ -212,3 +213,25 @@ func CreateLogData(input esynclog.SimxLogDto, event *pl.Event, dbx ...*gorm.DB) pl.SetLogInfo(event, nil, "complete") return nil } + +func CreateBulkLinkData(input []e.Installation, event *pl.Event, dbx ...*gorm.DB) (*[]esync.InstallationLink, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setBulkDataSimxLink(input) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + result := tx.Create(&data) + if err := result.Error; err != nil { + return nil, plh.HandleCreateError(input, event, err) + } + + fmt.Println("Inserted Link:", result.RowsAffected) + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} diff --git a/internal/use-case/simgos-sync-use-case/new/specialist/helper.go b/internal/use-case/simgos-sync-use-case/new/specialist/helper.go index adce079f..21ed4996 100644 --- a/internal/use-case/simgos-sync-use-case/new/specialist/helper.go +++ b/internal/use-case/simgos-sync-use-case/new/specialist/helper.go @@ -7,6 +7,7 @@ package specialist import ( "encoding/json" erc "simrs-vx/internal/domain/references/common" + "strconv" e "simrs-vx/internal/domain/main-entities/specialist" esimgos "simrs-vx/internal/domain/simgos-entities/m-polihfis" @@ -58,3 +59,14 @@ func setDataSimxLink(simxId, simgosId uint) (data esync.SpecialistLink) { data.Simgos_Id = simgosId return } + +func setBulkDataSimxLink(input []e.Specialist) (data []esync.SpecialistLink) { + for _, i := range input { + kode, _ := strconv.Atoi(i.Code) + data = append(data, esync.SpecialistLink{ + Simx_Id: uint(i.Id), + Simgos_Id: uint(kode), + }) + } + return +} diff --git a/internal/use-case/simgos-sync-use-case/new/specialist/lib.go b/internal/use-case/simgos-sync-use-case/new/specialist/lib.go index 0aee2ceb..26cc8efc 100644 --- a/internal/use-case/simgos-sync-use-case/new/specialist/lib.go +++ b/internal/use-case/simgos-sync-use-case/new/specialist/lib.go @@ -1,6 +1,7 @@ package specialist import ( + "fmt" plh "simrs-vx/pkg/lib-helper" pl "simrs-vx/pkg/logger" pu "simrs-vx/pkg/use-case-helper" @@ -30,7 +31,7 @@ func CreateSimgosData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*esi tx = dg.IS["simrs"] } - if err := tx.Debug().Create(&data).Error; err != nil { + if err := tx.Create(&data).Error; err != nil { return nil, plh.HandleCreateError(input, event, err) } @@ -189,3 +190,25 @@ func CreateLogData(input esynclog.SimxLogDto, event *pl.Event, dbx ...*gorm.DB) pl.SetLogInfo(event, nil, "complete") return nil } + +func CreateBulkLinkData(input []e.Specialist, event *pl.Event, dbx ...*gorm.DB) (*[]esync.SpecialistLink, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setBulkDataSimxLink(input) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + result := tx.Create(&data) + if err := result.Error; err != nil { + return nil, plh.HandleCreateError(input, event, err) + } + + fmt.Println("Inserted Link:", result.RowsAffected) + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} diff --git a/internal/use-case/simgos-sync-use-case/new/subspecialist/helper.go b/internal/use-case/simgos-sync-use-case/new/subspecialist/helper.go index 898f161c..2e1460d6 100644 --- a/internal/use-case/simgos-sync-use-case/new/subspecialist/helper.go +++ b/internal/use-case/simgos-sync-use-case/new/subspecialist/helper.go @@ -9,7 +9,7 @@ import ( erc "simrs-vx/internal/domain/references/common" //esimgos "simrs-vx/internal/domain/simgos-entities/specialist" esyncLog "simrs-vx/internal/domain/sync-entities/log" - esync "simrs-vx/internal/domain/sync-entities/specialist" + esync "simrs-vx/internal/domain/sync-entities/subspecialist" ) //func setDataSimgos[T *e.CreateDto | *e.UpdateDto](input T) (data esimgos.MPolihfis) { @@ -30,7 +30,7 @@ import ( // return //} -func setDataSimxLog(input *esyncLog.SimxLogDto) (data esync.SpecialistSimxLog) { +func setDataSimxLog(input *esyncLog.SimxLogDto) (data esync.SubspecialistSimxLog) { // encode to JSON jsonData, _ := json.MarshalIndent(input.Payload, "", " ") jsonString := string(jsonData) @@ -52,7 +52,7 @@ func setDataSimxLog(input *esyncLog.SimxLogDto) (data esync.SpecialistSimxLog) { return } -func setDataSimxLink(simxId, simgosId uint) (data esync.SpecialistLink) { +func setDataSimxLink(simxId, simgosId uint) (data esync.SubspecialistLink) { data.Simx_Id = simxId data.Simgos_Id = simgosId return diff --git a/internal/use-case/simgos-sync-use-case/new/subspecialist/lib.go b/internal/use-case/simgos-sync-use-case/new/subspecialist/lib.go index 781e899d..d9d7381d 100644 --- a/internal/use-case/simgos-sync-use-case/new/subspecialist/lib.go +++ b/internal/use-case/simgos-sync-use-case/new/subspecialist/lib.go @@ -1,6 +1,7 @@ package subspecialist import ( + "fmt" plh "simrs-vx/pkg/lib-helper" pl "simrs-vx/pkg/logger" pu "simrs-vx/pkg/use-case-helper" @@ -9,9 +10,8 @@ import ( dg "github.com/karincake/apem/db-gorm-pg" "gorm.io/gorm" - //esimgos "simrs-vx/internal/domain/simgos-entities/specialist" esynclog "simrs-vx/internal/domain/sync-entities/log" - esync "simrs-vx/internal/domain/sync-entities/specialist" + esync "simrs-vx/internal/domain/sync-entities/subspecialist" ) var now = time.Now() @@ -106,7 +106,7 @@ var now = time.Now() // return nil //} -func CreateLinkData(simxId, simgosId uint, event *pl.Event, dbx ...*gorm.DB) (*esync.SpecialistLink, error) { +func CreateLinkData(simxId, simgosId uint, event *pl.Event, dbx ...*gorm.DB) (*esync.SubspecialistLink, error) { pl.SetLogInfo(event, nil, "started", "DBCreate") data := setDataSimxLink(simxId, simgosId) @@ -125,9 +125,9 @@ func CreateLinkData(simxId, simgosId uint, event *pl.Event, dbx ...*gorm.DB) (*e return &data, nil } -func ReadDetailLinkData(simxId uint16, event *pl.Event) (*esync.SpecialistLink, error) { +func ReadDetailLinkData(simxId uint16, event *pl.Event) (*esync.SubspecialistLink, error) { pl.SetLogInfo(event, simxId, "started", "DBReadDetail") - data := esync.SpecialistLink{} + data := esync.SubspecialistLink{} var tx = dg.I @@ -143,7 +143,7 @@ func ReadDetailLinkData(simxId uint16, event *pl.Event) (*esync.SpecialistLink, return &data, nil } -func DeleteLinkData(data *esync.SpecialistLink, event *pl.Event, dbx ...*gorm.DB) error { +func DeleteLinkData(data *esync.SubspecialistLink, event *pl.Event, dbx ...*gorm.DB) error { pl.SetLogInfo(event, data, "started", "DBDelete") var tx *gorm.DB @@ -185,3 +185,24 @@ func CreateLogData(input esynclog.SimxLogDto, event *pl.Event, dbx ...*gorm.DB) pl.SetLogInfo(event, nil, "complete") return nil } + +func CreateBulkLinkData(data []esync.SubspecialistLink, event *pl.Event, dbx ...*gorm.DB) (*[]esync.SubspecialistLink, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + result := tx.Create(&data) + if err := result.Error; err != nil { + return nil, plh.HandleCreateError(data, event, err) + } + + fmt.Println("Inserted Link:", result.RowsAffected) + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} diff --git a/internal/use-case/simgos-sync-use-case/seeder/helper.go b/internal/use-case/simgos-sync-use-case/seeder/helper.go index 74006fe2..8fc5538e 100644 --- a/internal/use-case/simgos-sync-use-case/seeder/helper.go +++ b/internal/use-case/simgos-sync-use-case/seeder/helper.go @@ -15,6 +15,7 @@ import ( type Dto struct { LoginNip []string `json:"loginNip"` Instalasi_Code string `json:"instalasi_code"` + SeedTableName string `json:"seedTableName"` } func Send(method string, endpoint string, body *bytes.Buffer, username string) ([]byte, error) { diff --git a/internal/use-case/simgos-sync-use-case/seeder/installation/seeder.go b/internal/use-case/simgos-sync-use-case/seeder/installation/seeder.go new file mode 100644 index 00000000..04c7f028 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/seeder/installation/seeder.go @@ -0,0 +1,92 @@ +package installation + +import ( + "bytes" + "encoding/json" + "log" + "net/http" + ere "simrs-vx/internal/domain/references/encounter" + db "simrs-vx/pkg/dualtrx-helper" + pl "simrs-vx/pkg/logger" + "strconv" + + ei "simrs-vx/internal/domain/main-entities/installation" + eu "simrs-vx/internal/domain/simgos-entities/m-unit" + + ui "simrs-vx/internal/use-case/simgos-sync-use-case/new/installation" + "simrs-vx/internal/use-case/simgos-sync-use-case/seeder" +) + +func SeedInstallation(event *pl.Event, tx *db.Dualtx) error { + unit := []eu.MUnit{} + + // Get M_Unit + err := tx.Simgos.Model(&eu.MUnit{}). + Find(&unit).Error + if err != nil { + log.Println("Error Querying MUnit:", err) + return err + } + + // Mapping To Installation + var installationData []ei.CreateDto + for _, v := range unit { + + codeString := strconv.Itoa(int(v.KodeUnit)) + installationData = append(installationData, ei.CreateDto{ + Name: v.NamaUnit, + EncounterClass_Code: ere.ECAmbulatory, + Code: &codeString, + }) + } + + dataInstallation, err := CreateBulkInstallation(ei.CreateBulkDto{Value: installationData}) + if err != nil { + return err + } + + _, err = ui.CreateBulkLinkData(dataInstallation, event, tx.Sync) + if err != nil { + return err + } + + return nil + +} + +func CreateBulkInstallation(ins ei.CreateBulkDto) ([]ei.Installation, error) { + var path = "installation/bulk" + + // create request body + jsonData, err := json.Marshal(ins) + if err != nil { + return nil, err + } + + reqBody := bytes.NewBuffer(jsonData) + // send data to main-api + resp, err := seeder.Send(http.MethodPost, path, reqBody, "von") + if err != nil { + return nil, err + } + + type MetaData struct { + Source string `json:"source"` + Status string `json:"status"` + Structure string `json:"structure"` + } + + type MainApiResp struct { + Meta MetaData `json:"meta"` + Data []ei.Installation `json:"data"` + } + + // getting response + var data MainApiResp + err = json.Unmarshal(resp, &data) + if err != nil { + return nil, err + } + + return data.Data, nil +} diff --git a/internal/use-case/simgos-sync-use-case/seeder/seeder/seeder.go b/internal/use-case/simgos-sync-use-case/seeder/seeder/seeder.go index 49f59b99..d52caec6 100644 --- a/internal/use-case/simgos-sync-use-case/seeder/seeder/seeder.go +++ b/internal/use-case/simgos-sync-use-case/seeder/seeder/seeder.go @@ -2,9 +2,6 @@ package seeder import ( "log" - "simrs-vx/internal/use-case/simgos-sync-use-case/seeder/doctor" - "simrs-vx/internal/use-case/simgos-sync-use-case/seeder/nurse" - "simrs-vx/internal/use-case/simgos-sync-use-case/seeder/regular" db "simrs-vx/pkg/dualtrx-helper" pl "simrs-vx/pkg/logger" @@ -14,6 +11,13 @@ import ( el "simrs-vx/internal/domain/simgos-entities/m-login" "simrs-vx/internal/use-case/simgos-sync-use-case/seeder" + + "simrs-vx/internal/use-case/simgos-sync-use-case/seeder/doctor" + "simrs-vx/internal/use-case/simgos-sync-use-case/seeder/installation" + "simrs-vx/internal/use-case/simgos-sync-use-case/seeder/nurse" + "simrs-vx/internal/use-case/simgos-sync-use-case/seeder/regular" + "simrs-vx/internal/use-case/simgos-sync-use-case/seeder/specialist" + "simrs-vx/internal/use-case/simgos-sync-use-case/seeder/subspecialist" ) const source = "seeder" @@ -33,52 +37,69 @@ func SeedToSimx(input seeder.Dto) (*d.Data, error) { kddokter, kdperawat []uint ) - // Get M_login - err := tx.Simgos.Model(&el.MLogin{}). - Select(`DISTINCT ON (nip) m_login.*`). - Where(`"nip" IN (?)`, input.LoginNip). - Find(&mlogin).Error - if err != nil { - log.Println("Error Querying Mlogin:", err) - return nil, err - } + switch input.SeedTableName { + case "installation": + if err := installation.SeedInstallation(&event, tx); err != nil { + return nil, err + } + case "specialist": + if err := specialist.SeedSpecialist(&event, tx); err != nil { + return nil, err + } + case "subspecialist": + if err := subspecialist.SeedSubspecialist(&event, tx); err != nil { + return nil, err + } - // SET data - if len(mlogin) > 0 { - for _, l := range mlogin { - if l.KdDokter != 0 { - kddokter = append(kddokter, l.KdDokter) - continue + default: + + // Get M_login + err := tx.Simgos.Model(&el.MLogin{}). + Select(`DISTINCT ON (nip) m_login.*`). + Where(`"nip" IN (?)`, input.LoginNip). + Find(&mlogin).Error + if err != nil { + log.Println("Error Querying Mlogin:", err) + return nil, err + } + + // SET data + if len(mlogin) > 0 { + for _, l := range mlogin { + if l.KdDokter != 0 { + kddokter = append(kddokter, l.KdDokter) + continue + } + + if l.KdPerawat != 0 { + kdperawat = append(kdperawat, l.KdPerawat) + continue + } + + regLogin = append(regLogin, l) } + } - if l.KdPerawat != 0 { - kdperawat = append(kdperawat, l.KdPerawat) - continue + // Seed based on role + if len(kddokter) > 0 { + err = doctor.SeedDoctor(kddokter, &event, tx) + if err != nil { + return nil, err } - - regLogin = append(regLogin, l) } - } - // Seed based on role - if len(kddokter) > 0 { - err = doctor.SeedDoctor(kddokter, &event, tx) - if err != nil { - return nil, err + if len(kdperawat) > 0 { + err = nurse.SeedNurse(kdperawat, &event, tx) + if err != nil { + return nil, err + } } - } - if len(kdperawat) > 0 { - err = nurse.SeedNurse(kdperawat, &event, tx) - if err != nil { - return nil, err - } - } - - if len(regLogin) > 0 { - err = regular.SeedRegular(regLogin, input.Instalasi_Code) - if err != nil { - return nil, err + if len(regLogin) > 0 { + err = regular.SeedRegular(regLogin, input.Instalasi_Code) + if err != nil { + return nil, err + } } } diff --git a/internal/use-case/simgos-sync-use-case/seeder/specialist/seeder.go b/internal/use-case/simgos-sync-use-case/seeder/specialist/seeder.go new file mode 100644 index 00000000..e108aaee --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/seeder/specialist/seeder.go @@ -0,0 +1,101 @@ +package specialist + +import ( + "bytes" + "encoding/json" + "log" + "net/http" + db "simrs-vx/pkg/dualtrx-helper" + pl "simrs-vx/pkg/logger" + "strconv" + + es "simrs-vx/internal/domain/main-entities/specialist" + er "simrs-vx/internal/domain/simgos-entities/m-ruang" + + us "simrs-vx/internal/use-case/simgos-sync-use-case/new/specialist" + "simrs-vx/internal/use-case/simgos-sync-use-case/seeder" +) + +func SeedSpecialist(event *pl.Event, tx *db.Dualtx) error { + ruang := []er.MRuang{} + + // Get M_Ruang + err := tx.Simgos.Model(&er.MRuang{}). + Find(&ruang).Error + if err != nil { + log.Println("Error Querying MRuang:", err) + return err + } + + // Mapping To Specialist + var speData []es.CreateDto + for _, v := range ruang { + if v.StAktif == 0 { + continue + } + + speCode := strconv.Itoa(int(v.No)) + + var insCode *string + if v.KdUnit != 0 { + code := strconv.Itoa(v.KdUnit) + insCode = &code + } + + speData = append(speData, es.CreateDto{ + Code: speCode, + Name: v.Nama, + Installation_Code: insCode, + }) + } + + dataSpe, err := CreateBulkSpecialist(es.CreateBulkDto{Value: speData}) + if err != nil { + return err + } + + _, err = us.CreateBulkLinkData(dataSpe, event, tx.Sync) + if err != nil { + return err + } + + return nil + +} + +func CreateBulkSpecialist(ins es.CreateBulkDto) ([]es.Specialist, error) { + var path = "specialist/bulk" + + // create request body + jsonData, err := json.Marshal(ins) + if err != nil { + return nil, err + } + + reqBody := bytes.NewBuffer(jsonData) + // send data to main-api + resp, err := seeder.Send(http.MethodPost, path, reqBody, "von") + if err != nil { + return nil, err + } + + type MetaData struct { + Source string `json:"source"` + Status string `json:"status"` + Structure string `json:"structure"` + } + + type MainApiResp struct { + Meta MetaData `json:"meta"` + Data []es.Specialist `json:"data"` + } + + // getting response + var data MainApiResp + err = json.Unmarshal(resp, &data) + if err != nil { + return nil, err + } + + return data.Data, nil +} diff --git a/internal/use-case/simgos-sync-use-case/seeder/subspecialist/seeder.go b/internal/use-case/simgos-sync-use-case/seeder/subspecialist/seeder.go new file mode 100644 index 00000000..cc95d371 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/seeder/subspecialist/seeder.go @@ -0,0 +1,100 @@ +package subspecialist + +import ( + "bytes" + "encoding/json" + "log" + "net/http" + db "simrs-vx/pkg/dualtrx-helper" + pl "simrs-vx/pkg/logger" + + es "simrs-vx/internal/domain/main-entities/subspecialist" + eds "simrs-vx/internal/domain/satu-entities/daftar-specialist" + esb "simrs-vx/internal/domain/sync-entities/subspecialist" + + us "simrs-vx/internal/use-case/simgos-sync-use-case/new/subspecialist" + "simrs-vx/internal/use-case/simgos-sync-use-case/seeder" +) + +func SeedSubspecialist(event *pl.Event, tx *db.Dualtx) error { + dspe := []eds.DaftarSpesialis{} + subspeMap := make(map[string]uint) + + // Get Daftar Specialist + err := tx.Satu.Model(&eds.DaftarSpesialis{}). + Find(&dspe).Error + if err != nil { + log.Println("Error Querying DaftarSpecialist:", err) + return err + } + + // Mapping To Subspecialist + var speData []es.CreateDto + for _, v := range dspe { + speData = append(speData, es.CreateDto{ + Code: v.Kode, + Name: v.Spesialis, + }) + + subspeMap[v.Kode] = v.ID + } + + dataSpe, err := CreateBulkSubSpecialist(es.CreateBulkDto{Value: speData}) + if err != nil { + return err + } + + // mapping link for subspecialist + var subspecliast []esb.SubspecialistLink + for _, v := range dataSpe { + subspecliast = append(subspecliast, esb.SubspecialistLink{ + Simx_Id: uint(v.Id), + Simgos_Id: subspeMap[v.Code], + }) + } + + _, err = us.CreateBulkLinkData(subspecliast, event, tx.Sync) + if err != nil { + return err + } + + return nil + +} + +func CreateBulkSubSpecialist(ins es.CreateBulkDto) ([]es.Subspecialist, error) { + var path = "subspecialist/bulk" + + // create request body + jsonData, err := json.Marshal(ins) + if err != nil { + return nil, err + } + + reqBody := bytes.NewBuffer(jsonData) + // send data to main-api + resp, err := seeder.Send(http.MethodPost, path, reqBody, "von") + if err != nil { + return nil, err + } + + type MetaData struct { + Source string `json:"source"` + Status string `json:"status"` + Structure string `json:"structure"` + } + + type MainApiResp struct { + Meta MetaData `json:"meta"` + Data []es.Subspecialist `json:"data"` + } + + // getting response + var data MainApiResp + err = json.Unmarshal(resp, &data) + if err != nil { + return nil, err + } + + return data.Data, nil +} diff --git a/pkg/dualtrx-helper/dualtrx-helper.go b/pkg/dualtrx-helper/dualtrx-helper.go index 144337c5..94b60a5a 100644 --- a/pkg/dualtrx-helper/dualtrx-helper.go +++ b/pkg/dualtrx-helper/dualtrx-helper.go @@ -8,6 +8,7 @@ import ( type Dualtx struct { Sync *gorm.DB Simgos *gorm.DB + Satu *gorm.DB } func NewDualtx() *Dualtx { @@ -24,6 +25,7 @@ func NewTx() *Dualtx { return &Dualtx{ Sync: dg.I, Simgos: dg.IS["simrs"], + Satu: dg.IS["satu"], } }