diff --git a/assets/docs/control-letter.html b/assets/docs/control-letter.html new file mode 100644 index 00000000..780a052f --- /dev/null +++ b/assets/docs/control-letter.html @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + +
+ logo + +
+ SURAT RENCANA KONTROL +
+
+ RSUD dr. Saiful Anwar +
+
+ No. : {{ .Number }} +
+
+ Kepada Yth +
+
+
+ {{ .Doctor_Name }} +
+
+ Sp./Sub. {{ .DstUnit_Name }} +
+
+ +
+ Mohon Pemeriksaan dan Penanganan Lebih Lanjut: +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ No.Kartu + : + {{ .CardNumber }} +
+ Nama Peserta + : + {{ .Name }} +
+ Tgl.Lahir + : + {{ .BirthDate }} +
+ Diagnosa + : + {{ .Diagnose }} +
+ Rencana Kontrol + : + {{ .PlanDate }} +
+ +
+ Demikian atas bantuannya, diucapkan banyak terima kasih. +
+ + + + + + + + + + + + + + + + + + + +
Mengetahui:
Tgl. Cetak: {{ .PrintDate }}{{ .ResponsibleDoctor_Name }}
+ +
+ + + \ No newline at end of file diff --git a/cmd/main-migration/migrations/20251120005512.sql b/cmd/main-migration/migrations/20251120005512.sql new file mode 100644 index 00000000..8fd4b6af --- /dev/null +++ b/cmd/main-migration/migrations/20251120005512.sql @@ -0,0 +1,2 @@ +-- Modify "McuOrderItem" table +ALTER TABLE "public"."McuOrderItem" ADD COLUMN "Note" character varying(1024) NULL; diff --git a/cmd/main-migration/migrations/20251120074415.sql b/cmd/main-migration/migrations/20251120074415.sql new file mode 100644 index 00000000..ae6cd675 --- /dev/null +++ b/cmd/main-migration/migrations/20251120074415.sql @@ -0,0 +1,11 @@ +-- Create "Resume" table +CREATE TABLE "public"."Resume" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Encounter_Id" bigint NOT NULL, + "Value" text NULL, + "FileUrl" character varying(1024) NULL, + PRIMARY KEY ("Id") +); diff --git a/cmd/main-migration/migrations/20251121033803.sql b/cmd/main-migration/migrations/20251121033803.sql new file mode 100644 index 00000000..48cb7f47 --- /dev/null +++ b/cmd/main-migration/migrations/20251121033803.sql @@ -0,0 +1,14 @@ +-- Create "VclaimReference" table +CREATE TABLE "public"."VclaimReference" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Encounter_Id" bigint NULL, + "Date" timestamptz NULL, + "SrcCode" text NULL, + "SrcName" text NULL, + "Number" text NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Encounter_VclaimReference" FOREIGN KEY ("Encounter_Id") REFERENCES "public"."Encounter" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); diff --git a/cmd/main-migration/migrations/atlas.sum b/cmd/main-migration/migrations/atlas.sum index e4ce72b0..87b0571b 100644 --- a/cmd/main-migration/migrations/atlas.sum +++ b/cmd/main-migration/migrations/atlas.sum @@ -1,4 +1,4 @@ -h1:8gw1BB9DWz+cNATJjG1oMXA+QAF1HrIw47xjbI33aC4= +h1:9o177sOy5hbZmLRLBxkW8WN1dveIe0pyAXoU84eeq0Y= 20250904105930.sql h1:MEM6blCgke9DzWQSTnLzasbPIrcHssNNrJqZpSkEo6k= 20250904141448.sql h1:J8cmYNk4ZrG9fhfbi2Z1IWz7YkfvhFqTzrLFo58BPY0= 20250908062237.sql h1:Pu23yEW/aKkwozHoOuROvHS/GK4ngARJGdO7FB7HZuI= @@ -123,5 +123,8 @@ h1:8gw1BB9DWz+cNATJjG1oMXA+QAF1HrIw47xjbI33aC4= 20251118074929.sql h1:p1KsWqCuR1JXA/jVO5BmOhCcaQ8clT7t0YRszAhPFbg= 20251119063438.sql h1:NVGM0X/LHD37EaPl8SNzkNiZDJ7AB1QR+LLwLh6WRdg= 20251119065730.sql h1:U5lzk1WvMB0bw3kwckou7jkEt4bwdYItwHr2Vxqe7w4= -20251119072302.sql h1:8L+NsXPFXGZDQZIOhShvuBM9aLwU3h95tXnz6jxHhlA= -20251119072450.sql h1:ksTc8ljaHFrBo1/HiHtcnT+iJ7kPS93KgetFTf3p4Qc= +20251119072302.sql h1:qCuI2WMEMF/XNbjV+RXPjBnuCKLu1Fia+mR9HiLWBIs= +20251119072450.sql h1:Xg+bTwqGyKPNFEQhJylvpz1wifdfmDJvcAq6vmNf0Ng= +20251120005512.sql h1:Ek6qpacAI/qVuTYxKno+uJyzn7s5z9pf3t7VA8gTzm4= +20251120074415.sql h1:NNUeJVA03EeBHJhHqPXEZoDv/PnC6yK1/cRhmukyaJo= +20251121033803.sql h1:1s3DvgbqF+lh/or9X6WGN2lwnYCZkP8JH6uJFHql15g= diff --git a/go.mod b/go.mod index b44bb011..493ad0a2 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ toolchain go1.24.6 require ( ariga.io/atlas-provider-gorm v0.5.6 + github.com/SebastiaanKlippert/go-wkhtmltopdf v1.9.3 github.com/golang-jwt/jwt v3.2.2+incompatible github.com/google/uuid v1.6.0 github.com/jackc/pgx/v5 v5.5.5 @@ -25,7 +26,6 @@ require ( require ( ariga.io/atlas v0.36.2-0.20250806044935-5bb51a0a956e // indirect - github.com/SebastiaanKlippert/go-wkhtmltopdf v1.9.3 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/go-ini/ini v1.67.0 // indirect github.com/go-redis/redis v6.15.9+incompatible // indirect diff --git a/internal/domain/bpjs-entities/vclaim-sep/dto.go b/internal/domain/bpjs-entities/vclaim-reference/dto.go similarity index 51% rename from internal/domain/bpjs-entities/vclaim-sep/dto.go rename to internal/domain/bpjs-entities/vclaim-reference/dto.go index 8a174688..027359a3 100644 --- a/internal/domain/bpjs-entities/vclaim-sep/dto.go +++ b/internal/domain/bpjs-entities/vclaim-reference/dto.go @@ -1,16 +1,16 @@ -package vclaimsep +package vclaimreference import ( ecore "simrs-vx/internal/domain/base-entities/core" - evsh "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-hist" + "time" ) type CreateDto struct { - Encounter_Id *uint `json:"encounter_id"` - Number *string `json:"number" validate:"maxLength=19"` - RequestPayload []byte `json:"requestPayload" validate:"maxLength=1024"` - - VclaimSepHist evsh.CreateDto + Encounter_Id *uint `json:"encounter_id"` + Date *time.Time `json:"date"` + SrcCode *string `json:"src_code"` + SrcName *string `json:"src_name"` + Number *string `json:"number"` } type ReadListDto struct { @@ -21,12 +21,11 @@ type ReadListDto struct { } type FilterDto struct { - Number *string `json:"number"` + Encounter_Id *uint `json:"encounter-id"` } type ReadDetailDto struct { - Id uint `json:"id"` - Number *string `json:"number"` + Id uint `json:"id"` } type UpdateDto struct { @@ -35,8 +34,7 @@ type UpdateDto struct { } type DeleteDto struct { - Id uint `json:"id"` - Number *string `json:"number"` + Id uint `json:"id"` } type MetaDto struct { @@ -47,27 +45,29 @@ type MetaDto struct { type ResponseDto struct { ecore.Main - Encounter_Id *uint `json:"encounter_id"` - Number *string `json:"number"` + Encounter_Id *uint `json:"encounter_id"` + Date *time.Time `json:"date"` + SrcCode *string `json:"src_code"` + SrcName *string `json:"src_name"` + Number *string `json:"number"` } -func (d VclaimSep) ToResponse() ResponseDto { +func (d VclaimReference) ToResponse() ResponseDto { resp := ResponseDto{ Encounter_Id: d.Encounter_Id, + Date: d.Date, + SrcCode: d.SrcCode, + SrcName: d.SrcName, Number: d.Number, } resp.Main = d.Main return resp } -func ToResponseList(data []VclaimSep) []ResponseDto { +func ToResponseList(data []VclaimReference) []ResponseDto { resp := make([]ResponseDto, len(data)) for i, u := range data { resp[i] = u.ToResponse() } return resp } - -func (c CreateDto) IsMessageSuccess() bool { - return c.VclaimSepHist.Message == "Sukses" -} diff --git a/internal/domain/bpjs-entities/vclaim-reference/entity.go b/internal/domain/bpjs-entities/vclaim-reference/entity.go new file mode 100644 index 00000000..a9a974d7 --- /dev/null +++ b/internal/domain/bpjs-entities/vclaim-reference/entity.go @@ -0,0 +1,15 @@ +package vclaimreference + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + "time" +) + +type VclaimReference struct { + ecore.Main + Encounter_Id *uint `json:"encounter_id"` + Date *time.Time `json:"date"` + SrcCode *string `json:"src_code"` + SrcName *string `json:"src_name"` + Number *string `json:"number"` +} 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 f12b57da..19530c2c 100644 --- a/internal/domain/bpjs-entities/vclaim-sep-control-letter/dto.go +++ b/internal/domain/bpjs-entities/vclaim-sep-control-letter/dto.go @@ -6,6 +6,9 @@ import ( type CreateDto struct { VclaimSep_Number *string `json:"vclaimSep_number"` + Number *string `json:"number" gorm:"unique;size:20"` + Value *string `json:"value"` + FileUrl *string `json:"fileUrl" gorm:"unique;size:1024"` } type ReadListDto struct { @@ -20,7 +23,8 @@ type FilterDto struct { } type ReadDetailDto struct { - Id uint `json:"id"` + Id *uint `json:"id"` + Number *string `json:"number"` } type UpdateDto struct { @@ -29,7 +33,8 @@ type UpdateDto struct { } type DeleteDto struct { - Id uint `json:"id"` + Id uint `json:"id"` + Number *string `json:"number"` } type MetaDto struct { @@ -41,12 +46,17 @@ type MetaDto struct { type ResponseDto struct { ecore.Main VclaimSep_Number *string `json:"vclaimSep_number"` - Counter *uint `json:"counter"` + Number *string `json:"number"` + Value *string `json:"value"` + FileUrl *string `json:"fileUrl"` } func (d VclaimSepControlLetter) ToResponse() ResponseDto { resp := ResponseDto{ VclaimSep_Number: d.VclaimSep_Number, + Number: d.Number, + Value: d.Value, + FileUrl: d.FileUrl, } resp.Main = d.Main return resp diff --git a/internal/domain/main-entities/encounter/entity.go b/internal/domain/main-entities/encounter/entity.go index 4d814ed0..0cbf5da1 100644 --- a/internal/domain/main-entities/encounter/entity.go +++ b/internal/domain/main-entities/encounter/entity.go @@ -1,7 +1,13 @@ package encounter import ( + "time" + + erc "simrs-vx/internal/domain/references/common" + ere "simrs-vx/internal/domain/references/encounter" + ecore "simrs-vx/internal/domain/base-entities/core" + evr "simrs-vx/internal/domain/bpjs-entities/vclaim-reference" evs "simrs-vx/internal/domain/bpjs-entities/vclaim-sep" eam "simrs-vx/internal/domain/main-entities/ambulatory" ea "simrs-vx/internal/domain/main-entities/appointment" @@ -19,10 +25,6 @@ import ( es "simrs-vx/internal/domain/main-entities/specialist" ess "simrs-vx/internal/domain/main-entities/subspecialist" eu "simrs-vx/internal/domain/main-entities/unit" - - erc "simrs-vx/internal/domain/references/common" - ere "simrs-vx/internal/domain/references/encounter" - "time" ) type Encounter struct { @@ -74,6 +76,7 @@ type Encounter struct { RehabChildren *[]er.Basic `json:"rehabChildren,omitempty" gorm:"foreignKey:Parent_Encounter_Id;references:Id"` EncounterDocuments *[]eed.EncounterDocument `json:"encounterDocuments,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"` GeneralConsents *[]egc.GeneralConsent `json:"generalConsents,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"` + VclaimReference *evr.VclaimReference `json:"vclaimReference,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"` } func (d Encounter) IsDone() bool { diff --git a/internal/domain/main-entities/mcu-order-item/base/entity.go b/internal/domain/main-entities/mcu-order-item/base/entity.go new file mode 100644 index 00000000..dcfb0625 --- /dev/null +++ b/internal/domain/main-entities/mcu-order-item/base/entity.go @@ -0,0 +1,20 @@ +package mcuorderitem + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ems "simrs-vx/internal/domain/main-entities/mcu-src" + "time" + + erc "simrs-vx/internal/domain/references/common" +) + +type McuOrderItem struct { + ecore.Main // adjust this according to the needs + McuOrder_Id *uint `json:"mcuOrder_id" gorm:"uniqueIndex:idx_order_src"` + McuSrc_Code *string `json:"mcuSrc_code" gorm:"uniqueIndex:idx_order_src"` + McuSrc *ems.McuSrc `json:"mcuSrc,omitempty" gorm:"foreignKey:McuSrc_Code;references:Code"` + ExaminationDate *time.Time `json:"examinationDate"` + Note *string `json:"note" gorm:"size:1024"` + Result *string `json:"result"` + Status_Code erc.DataStatusCode `json:"status_code"` +} diff --git a/internal/domain/main-entities/mcu-order-item/entity.go b/internal/domain/main-entities/mcu-order-item/entity.go index 97384243..48a57bac 100644 --- a/internal/domain/main-entities/mcu-order-item/entity.go +++ b/internal/domain/main-entities/mcu-order-item/entity.go @@ -1,23 +1,15 @@ package mcuorderitem import ( - ecore "simrs-vx/internal/domain/base-entities/core" emo "simrs-vx/internal/domain/main-entities/mcu-order" - ems "simrs-vx/internal/domain/main-entities/mcu-src" - "time" + emoib "simrs-vx/internal/domain/main-entities/mcu-order-item/base" erc "simrs-vx/internal/domain/references/common" ) type McuOrderItem struct { - ecore.Main // adjust this according to the needs - McuOrder_Id *uint `json:"mcuOrder_id" gorm:"uniqueIndex:idx_order_src"` - McuOrder *emo.McuOrder `json:"mcuOrder,omitempty" gorm:"foreignKey:McuOrder_Id;references:Id"` - McuSrc_Code *string `json:"mcuSrc_code" gorm:"uniqueIndex:idx_order_src"` - McuSrc *ems.McuSrc `json:"mcuSrc,omitempty" gorm:"foreignKey:McuSrc_Code;references:Code"` - ExaminationDate *time.Time `json:"examinationDate"` - Result *string `json:"result"` - Status_Code erc.DataStatusCode `json:"status_code"` + emoib.McuOrderItem + McuOrder *emo.McuOrder `json:"mcuOrder,omitempty" gorm:"foreignKey:McuOrder_Id;references:Id"` } func (d McuOrderItem) IsCompleted() bool { diff --git a/internal/domain/main-entities/resume/dto.go b/internal/domain/main-entities/resume/dto.go new file mode 100644 index 00000000..ea9485d7 --- /dev/null +++ b/internal/domain/main-entities/resume/dto.go @@ -0,0 +1,64 @@ +package resume + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type CreateDto struct { + Encounter_Id *uint `json:"encounter_id"` + Value *string `json:"value"` +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Pagination ecore.Pagination +} + +type FilterDto struct { + Encounter_Id *uint `json:"encounter-id"` +} + +type ReadDetailDto struct { + Id uint `json:"id"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Encounter_Id *uint `json:"encounter_id"` + Value *string `json:"value"` + FileUrl *string `json:"fileUrl"` +} + +func (d Resume) ToResponse() ResponseDto { + resp := ResponseDto{ + Encounter_Id: d.Encounter_Id, + Value: d.Value, + FileUrl: d.FileUrl, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []Resume) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/resume/entity.go b/internal/domain/main-entities/resume/entity.go new file mode 100644 index 00000000..cf756870 --- /dev/null +++ b/internal/domain/main-entities/resume/entity.go @@ -0,0 +1,12 @@ +package resume + +import ( + "simrs-vx/internal/domain/base-entities/core" +) + +type Resume struct { + core.Main + Encounter_Id *uint `json:"encounter_id" gorm:"not null"` + Value *string `json:"value"` + FileUrl *string `json:"fileUrl" gorm:"size:1024"` +} diff --git a/internal/domain/references/encounter/encounter.go b/internal/domain/references/encounter/encounter.go index 66025373..ca600246 100644 --- a/internal/domain/references/encounter/encounter.go +++ b/internal/domain/references/encounter/encounter.go @@ -121,6 +121,7 @@ const ( DTCSEP DocTypeCode = "vclaim-sep" // SEP DTCSIPP DocTypeCode = "vclaim-sipp" // SIPP DTCGC DocTypeCode = "general-consent" + DTCVSCL DocTypeCode = "vclaim-control-letter" // vclaim control letter ETCPerson EntityTypeCode = "person" ETCEncounter EntityTypeCode = "encounter" diff --git a/internal/interface/migration/main-entities.go b/internal/interface/migration/main-entities.go index 23e7422c..0b4a62fd 100644 --- a/internal/interface/migration/main-entities.go +++ b/internal/interface/migration/main-entities.go @@ -82,6 +82,7 @@ import ( regency "simrs-vx/internal/domain/main-entities/regency" rehab "simrs-vx/internal/domain/main-entities/rehab" responsibledoctorhist "simrs-vx/internal/domain/main-entities/responsible-doctor-hist" + resume "simrs-vx/internal/domain/main-entities/resume" room "simrs-vx/internal/domain/main-entities/room" sbar "simrs-vx/internal/domain/main-entities/sbar" soapi "simrs-vx/internal/domain/main-entities/soapi" @@ -102,6 +103,7 @@ import ( ///BPJS vclaimmember "simrs-vx/internal/domain/bpjs-entities/vclaim-member" + vclaimreference "simrs-vx/internal/domain/bpjs-entities/vclaim-reference" vclaimsep "simrs-vx/internal/domain/bpjs-entities/vclaim-sep" vclaimsepcontrolletter "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-control-letter" vclaimsephist "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-hist" @@ -213,5 +215,7 @@ func getMainEntities() []any { &chemoprotocol.ChemoProtocol{}, &fileattachemnt.EncounterDocument{}, &vclaimsepcontrolletter.VclaimSepControlLetter{}, + &resume.Resume{}, + &vclaimreference.VclaimReference{}, } } diff --git a/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/case.go b/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/case.go new file mode 100644 index 00000000..7c19819f --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/case.go @@ -0,0 +1,277 @@ +package vclaimsepcontrolletter + +import ( + "strconv" + + e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-control-letter" + + 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 = "vclaim-sep-control-letter" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.VclaimSepControlLetter{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err := dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, &input, &data); err != nil { + return err + } + + if resData, err := CreateData(input, &event, tx); err != nil { + return err + } else { + data = *resData + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + return err + } + + pl.SetLogInfo(&event, nil, "complete") + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + Data: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.VclaimSepControlLetter + var dataList []e.VclaimSepControlLetter + 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.VclaimSepControlLetter + 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{Number: input.Number} + var data *e.VclaimSepControlLetter + var err error + + event := pl.Event{ + Feature: "Update", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "update") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err + } + + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err + } + + if err := UpdateData(input, data, &event, tx); err != nil { + return err + } + + pl.SetLogInfo(&event, nil, "complete") + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + Data: data.ToResponse(), + }, nil + +} + +func Delete(input e.DeleteDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Number: input.Number} + var data *e.VclaimSepControlLetter + 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/bpjs-use-case/vclaim-sep-control-letter/helper.go b/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/helper.go new file mode 100644 index 00000000..891e7c4d --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/helper.go @@ -0,0 +1,24 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package vclaimsepcontrolletter + +import ( + e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-control-letter" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.VclaimSepControlLetter) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.VclaimSep_Number = inputSrc.VclaimSep_Number + data.Number = inputSrc.Number + data.Value = inputSrc.Value + data.FileUrl = inputSrc.FileUrl +} diff --git a/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/lib.go b/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/lib.go new file mode 100644 index 00000000..9f66baff --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/lib.go @@ -0,0 +1,148 @@ +package vclaimsepcontrolletter + +import ( + e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-control-letter" + + plh "simrs-vx/pkg/lib-helper" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.VclaimSepControlLetter, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.VclaimSepControlLetter{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + setData(&input, &data) + + 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.VclaimSepControlLetter, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.VclaimSepControlLetter{} + 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.VclaimSepControlLetter{}). + Scopes(gh.Preload(input.Includes)). + Scopes(gh.Filter(input.FilterDto)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Scopes(gh.Sort(input.Sort)) + + 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.VclaimSepControlLetter, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.VclaimSepControlLetter{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if input.Number != nil { + tx = tx.Where("\"Number\" = ?", *input.Number) + } + if input.Id != nil { + tx = tx.Where("\"Id\" = ?", *input.Id) + } + + if err := tx.First(&data).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.VclaimSepControlLetter, 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.VclaimSepControlLetter, 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/bpjs-use-case/vclaim-sep-control-letter/middleware-runner.go b/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/middleware-runner.go new file mode 100644 index 00000000..c0a0ecae --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/middleware-runner.go @@ -0,0 +1,103 @@ +package vclaimsepcontrolletter + +import ( + e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-control-letter" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" +) + +type middlewareRunner struct { + Event *pl.Event + Tx *gorm.DB + MwType pu.MWType +} + +// NewMiddlewareExecutor creates a new middleware executor +func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { + return &middlewareRunner{ + Event: event, + Tx: tx, + } +} + +// ExecuteCreateMiddleware executes create middleware +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.VclaimSepControlLetter) 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.VclaimSepControlLetter) 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.VclaimSepControlLetter) 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.VclaimSepControlLetter) 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.VclaimSepControlLetter) 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/bpjs-use-case/vclaim-sep-control-letter/middleware.go b/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/middleware.go new file mode 100644 index 00000000..57262cc2 --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/middleware.go @@ -0,0 +1,9 @@ +package vclaimsepcontrolletter + +// 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/bpjs-use-case/vclaim-sep-control-letter/tycovar.go b/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/tycovar.go new file mode 100644 index 00000000..2e921ae9 --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/tycovar.go @@ -0,0 +1,44 @@ +/* +DESCRIPTION: +A sample, part of the package that contains type, constants, and/or variables. + +In this sample it also provides type and variable regarding the needs of the +middleware to separate from main use-case which has the basic CRUD +functionality. The purpose of this is to make the code more maintainable. +*/ +package vclaimsepcontrolletter + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-control-letter" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.VclaimSepControlLetter, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.VclaimSepControlLetter, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.VclaimSepControlLetter, 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/generate-file/case.go b/internal/use-case/main-use-case/generate-file/case.go index 1c3ca51b..39cb2f02 100644 --- a/internal/use-case/main-use-case/generate-file/case.go +++ b/internal/use-case/main-use-case/generate-file/case.go @@ -4,14 +4,21 @@ import ( "encoding/json" "errors" + evs "simrs-vx/internal/domain/bpjs-entities/vclaim-sep" + evscl "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-control-letter" egc "simrs-vx/internal/domain/main-entities/general-consent" + + uvs "simrs-vx/internal/use-case/bpjs-use-case/vclaim-sep" + uvscl "simrs-vx/internal/use-case/bpjs-use-case/vclaim-sep-control-letter" ugc "simrs-vx/internal/use-case/main-use-case/general-consent" + pc "simrs-vx/pkg/conv-helper" pl "simrs-vx/pkg/logger" pu "simrs-vx/pkg/use-case-helper" dg "github.com/karincake/apem/db-gorm-pg" d "github.com/karincake/dodol" + "gorm.io/gorm" erc "simrs-vx/internal/domain/references/common" ere "simrs-vx/internal/domain/references/encounter" @@ -25,70 +32,150 @@ func Generate(input GenerateDto) (*d.Data, error) { Source: source, } + var response ResponseDto + // Start log pl.SetLogInfo(&event, input, "started", "create") - switch input.Type_Code { - // general-consent - case ere.DTCGC: - // get value from general consent by ref_id - gc, err := ugc.ReadDetailData(egc.ReadDetailDto{Id: *input.Ref_Id}, &event) - if err != nil { - return nil, err - } - - if gc.FileUrl != nil { - if err := removeFile(string(input.EntityType_Code), *gc.FileUrl); err != nil { - return nil, err - } - } - - // map template data - templateData := GeneralConsentPDF{} - if gc.Value != nil { - err := json.Unmarshal([]byte(*gc.Value), &templateData) + err := dg.I.Transaction(func(tx *gorm.DB) error { + switch input.Type_Code { + // general-consent + case ere.DTCGC: + // get value from general consent by ref_id + gc, err := ugc.ReadDetailData(egc.ReadDetailDto{Id: uint(*pc.StringToUint64(*input.Ref_Id))}, &event) if err != nil { - event.ErrInfo = pl.ErrorInfo{ - Code: "data-unmarshal-fail", - Detail: err.Error(), - Raw: err, - } - return nil, err + return err } - } else { - return nil, errors.New("no value in this general consent") + + if gc.FileUrl != nil { + if err := removeFile(string(input.EntityType_Code), *gc.FileUrl); err != nil { + return err + } + } + + // map template data + templateData := GeneralConsentPDF{} + if gc.Value != nil { + err := json.Unmarshal([]byte(*gc.Value), &templateData) + if err != nil { + event.ErrInfo = pl.ErrorInfo{ + Code: "data-unmarshal-fail", + Detail: err.Error(), + Raw: err, + } + return err + } + } else { + return errors.New("no value in this general consent") + } + + input.FormatType = erc.DFTCPDF + input.TemplateName = TDNGC + input.Encounter_Id = gc.Encounter_Id + templateData.Date = pu.FormatIndonesianDate(gc.CreatedAt) + + // generate file + urlPub, err := generateFile(input, templateData) + if err != nil { + return err + } + + gc.FileUrl = &urlPub + if err := dg.I.Save(&gc).Error; err != nil { + return err + } + + response = ResponseDto{ + FileUrl: urlPub, + } + + // control-letter + case ere.DTCVSCL: + // get value from control letter by ref_id + cl, err := uvscl.ReadDetailData(evscl.ReadDetailDto{Number: input.Ref_Id}, &event) + if err != nil { + if !pu.IsDataNotFoundError(err) { + return err + } + } + + if cl != nil && cl.FileUrl != nil { + if err := removeFile(string(input.EntityType_Code), *cl.FileUrl); err != nil { + return err + } + } + + // map template data + clData := VclaimControlLetter{} + if input.Data != nil { + err := json.Unmarshal([]byte(*input.Data), &clData) + if err != nil { + event.ErrInfo = pl.ErrorInfo{ + Code: "data-unmarshal-fail", + Detail: err.Error(), + Raw: err, + } + return err + } + } else { + return errors.New("there is no data to be used") + } + + if cl == nil { + createCL := evscl.CreateDto{ + VclaimSep_Number: &clData.VclaimSep.Number, + Number: &clData.Number, + Value: input.Data, + } + if cl, err = uvscl.CreateData(createCL, &event, tx); err != nil { + return err + } + + } + // get encounter id by vclaim sep number + vs, err := uvs.ReadDetailData(evs.ReadDetailDto{Number: &clData.VclaimSep.Number}, &event) + if err != nil { + return err + } + + input.FormatType = erc.DFTCPDF + input.TemplateName = TDNCL + input.Encounter_Id = vs.Encounter_Id + input.UseA5Lanscape = true + + templateData := clData.generateTemplateData() + // generate file + urlPub, err := generateFile(input, templateData) + if err != nil { + return err + } + + cl.FileUrl = &urlPub + if err := tx.Save(&cl).Error; err != nil { + return err + } + + response = ResponseDto{ + FileUrl: urlPub, + } + + default: + return errors.New("invalid type code") } - input.FormatType = erc.DFTCPDF - input.TemplateName = TDNGC - input.Encounter_Id = gc.Encounter_Id - templateData.Date = pu.FormatIndonesianDate(gc.CreatedAt) + return nil + }) - // generate file - urlPub, err := generateFile(input, templateData) - if err != nil { - return nil, err - } - - gc.FileUrl = &urlPub - if err := dg.I.Save(&gc).Error; err != nil { - return nil, err - } - - response := ResponseDto{ - FileUrl: urlPub, - } - - return &d.Data{ - Meta: d.II{ - "source": source, - "structure": "single-data", - "status": "created", - }, - Data: response, - }, nil - default: - return nil, errors.New("invalid type code") + if err != nil { + return nil, err } + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + Data: response, + }, 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 9bee2212..8cd3543f 100644 --- a/internal/use-case/main-use-case/generate-file/helper.go +++ b/internal/use-case/main-use-case/generate-file/helper.go @@ -30,9 +30,10 @@ func generateFile(input GenerateDto, templateData any) (string, error) { switch input.FormatType { case erc.DFTCPDF: if err := generatePDF(GeneratePDFdto{ - TemplatePath: templatePath, - TemplateData: templateData, - PdfPath: fPath, + TemplatePath: templatePath, + TemplateData: templateData, + PdfPath: fPath, + UseA5Lanscape: input.UseA5Lanscape, }); err != nil { return "", err } @@ -73,7 +74,7 @@ func generatePDF(input GeneratePDFdto) error { // parse template data into html template r := pp.NewRequestPdf("") if err := r.ParseTemplate(input.TemplatePath, input.TemplateData); err == nil { - _, err := r.GenerateByCommand(input.PdfPath, input.TemplatePath) + _, err := r.GenerateByCommand(input.PdfPath, input.TemplatePath, input.UseA5Lanscape) if err != nil { return errors.New("generate pdf by command error : " + err.Error()) } 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 fed3e28c..2f6a0ced 100644 --- a/internal/use-case/main-use-case/generate-file/tycovar.go +++ b/internal/use-case/main-use-case/generate-file/tycovar.go @@ -1,8 +1,13 @@ package generatefile import ( + "fmt" + "time" + erc "simrs-vx/internal/domain/references/common" ere "simrs-vx/internal/domain/references/encounter" + + pu "simrs-vx/pkg/use-case-helper" ) type GeneralConsentPDF struct { @@ -14,18 +19,34 @@ type GeneralConsentPDF struct { Date string `json:"date"` } +type ControlLetterPDF struct { + Number string + Doctor_Name string + DstUnit_Name string + CardNumber string + Name string + BirthDate string + Diagnose string + PlanDate string + ResponsibleDoctor_Name string + PrintDate string +} + type GenerateDto struct { EntityType_Code ere.EntityTypeCode `json:"entityType_code" validate:"required"` - Ref_Id *uint `json:"ref_id" validate:"required"` + Ref_Id *string `json:"ref_id" validate:"required"` Type_Code ere.DocTypeCode `json:"type_code" validate:"required"` FormatType erc.DocFormatTypeCode `json:"formatType"` TemplateName TemplateDocsName `json:"-"` Encounter_Id *uint `json:"-"` + UseA5Lanscape bool `json:"-"` + + Data *string `json:"data"` } type VclaimControlLetter struct { Number string `json:"noSuratKontrol"` - Date string `json:"tglRencanaKontrol"` + PlannedControlDate string `json:"tglRencanaKontrol"` Doctor_Name string `json:"namaDokter"` DstUnit_Name string `json:"namaPoliTujuan"` ResponsibleDoctor_Name string `json:"namaDokterPembuat"` @@ -46,9 +67,10 @@ type VclaimMember struct { } type GeneratePDFdto struct { - TemplatePath string - TemplateData any - PdfPath string + TemplatePath string + TemplateData any + PdfPath string + UseA5Lanscape bool } type ResponseDto struct { @@ -60,4 +82,40 @@ type TemplateDocsName string // TemplateDocsName is the name of the template file in the assets/docs folder const ( TDNGC TemplateDocsName = "general-consent.html" + TDNCL TemplateDocsName = "control-letter.html" ) + +func (v VclaimControlLetter) generateTemplateData() ControlLetterPDF { + + return ControlLetterPDF{ + Number: v.Number, + Doctor_Name: v.Doctor_Name, + DstUnit_Name: v.DstUnit_Name, + CardNumber: v.VclaimSep.VclaimMember.CardNumber, + Name: v.generateNameWithGender(), + BirthDate: v.generateBirthDate(), + Diagnose: v.VclaimSep.Diagnose, + PlanDate: v.PlannedControlDate, + ResponsibleDoctor_Name: v.ResponsibleDoctor_Name, + PrintDate: generatePrintDate(), + } +} + +func (v VclaimControlLetter) generateNameWithGender() string { + gender := "Perempuan" + if v.VclaimSep.VclaimMember.Gender == "L" { + gender = "Laki-Laki" + } + + return fmt.Sprintf("%s (%s)", v.VclaimSep.VclaimMember.Name, gender) +} + +func (v VclaimControlLetter) generateBirthDate() string { + t, _ := time.Parse("2006-01-02", v.VclaimSep.VclaimMember.BirthDate) + return pu.FormatIndonesianDate(t) +} + +func generatePrintDate() string { + now := time.Now() + return now.Format("2006/01/02") +} diff --git a/pkg/pdf-helper/pdf-helper.go b/pkg/pdf-helper/pdf-helper.go index 597052eb..9878ecbd 100644 --- a/pkg/pdf-helper/pdf-helper.go +++ b/pkg/pdf-helper/pdf-helper.go @@ -47,9 +47,9 @@ func (r *RequestPdf) ParseTemplate(templatePath string, data interface{}) error return nil } -func (r *RequestPdf) GenerateByCommand(pdfPath string, templatePath string) (bool, error) { - // wkhtmltopdf -L 0 -R 0 -B 0 -s Legal --enable-local-file-access resultAntigen2.html out.pdf +func (r *RequestPdf) GenerateByCommand(pdfPath string, templatePath string, useA5Lanscape bool) (bool, error) { t := time.Now().Unix() + var cmd *exec.Cmd if _, err := os.Stat("cloneTemplate/"); os.IsNotExist(err) { errDir := os.Mkdir("cloneTemplate/", 0777) @@ -63,7 +63,20 @@ func (r *RequestPdf) GenerateByCommand(pdfPath string, templatePath string) (boo panic(err) } - cmd := exec.Command("wkhtmltopdf", "--enable-local-file-access", "-L", "0", "-R", "0", "-B", "0", "-s", "A4", "cloneTemplate/"+htmlName, pdfPath) + if !useA5Lanscape { + cmd = exec.Command("wkhtmltopdf", "--enable-local-file-access", "-L", "0", "-R", "0", "-B", "0", "-s", "A4", "cloneTemplate/"+htmlName, pdfPath) + } else { + cmd = exec.Command("wkhtmltopdf", + "--enable-local-file-access", + "-L", "0", // left margin + "-R", "0", // right margin + "-B", "0", // bottom margin + "-T", "0", // top margin + "-s", "A5", // page size A5 + "-O", "Landscape", // landscape mode + "cloneTemplate/"+htmlName, + pdfPath) + } if err := cmd.Run(); err != nil { return false, err