feat (generate-file): control letter done

This commit is contained in:
dpurbosakti
2025-11-20 13:18:33 +07:00
parent a5ea881e1f
commit ffb8c4e413
5 changed files with 185 additions and 145 deletions

No files matched your search

+36 -21
View File
@@ -3,6 +3,9 @@
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<style> <style>
body {
padding: 10px 30px;
}
table { table {
width: 100%; width: 100%;
border-collapse: collapse border-collapse: collapse
@@ -18,6 +21,12 @@
margin-top: 1rem; margin-top: 1rem;
margin-bottom: 0rem; margin-bottom: 0rem;
} }
td {
vertical-align: top;
}
@page {
size: 148mm 210mm;
}
</style> </style>
</head> </head>
@@ -25,7 +34,7 @@
<table style="margin-top: 1rem;"> <table style="margin-top: 1rem;">
<tr> <tr>
<td> <td>
<img src="logo-1.png" alt="logo" style="height: 70px" /> <img src="logo-1.png" alt="logo" style="height: 70px; margin-bottom: 20px;" />
</td> </td>
<td> <td>
<div> <div>
@@ -35,15 +44,10 @@
RSUD dr. Saiful Anwar RSUD dr. Saiful Anwar
</div> </div>
</td> </td>
<td> <td style="text-align: right;">
<div>
No. : {{ .Number }} No. : {{ .Number }}
</div>
</td> </td>
</tr> </tr>
<tr>
<td style="height: 0.5rem;"></td>
</tr>
<tr> <tr>
<td> <td>
<div> <div>
@@ -65,46 +69,50 @@
Mohon Pemeriksaan dan Penanganan Lebih Lanjut: Mohon Pemeriksaan dan Penanganan Lebih Lanjut:
</div> </div>
<table style="margin-top: 1rem;"> <table style="margin-top: 1rem;">
<tr> <tr>
<td style="width: 9rem;"> <td style="width: 9rem;">
No.Kartu No.Kartu
</td> </td>
<td style="width: 10px;">:</td>
<td> <td>
: {{ .CardNumber }} {{ .CardNumber }}
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
Nama Peserta Nama Peserta
</td> </td>
<td>: </td>
<td> <td>
: {{ .Name }} {{ .Name }}
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
Tgl.Lahir Tgl.Lahir
</td> </td>
<td>: </td>
<td> <td>
: {{ .BirthDate }} {{ .BirthDate }}
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
Diagnosa Diagnosa
</td> </td>
<td>: </td>
<td> <td>
: {{ .Diagnose }} {{ .Diagnose }}
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
Rencana Kontrol Rencana Kontrol
</td> </td>
<td>: </td>
<td> <td>
: {{ .PlanDate }} {{ .PlanDate }}
</td> </td>
</tr> </tr>
</table> </table>
@@ -113,19 +121,26 @@
Demikian atas bantuannya, diucapkan banyak terima kasih. Demikian atas bantuannya, diucapkan banyak terima kasih.
</div> </div>
<table> <table style="width:100%">
<tbody>
<tr> <tr>
<td style="width:20%"></td>
<td></td> <td></td>
<td style="width: 15rem;"> <td style="width:20%; text-align: center;">Mengetahui:</td>
Mengetahui, DPJP : {{ .ResponsibleDoctor_Name }}
</td>
</tr> </tr>
<tr>
<td style="height:100px"></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Tgl. Cetak: {{ .PrintDate }}</td>
<td></td>
<td style="text-align: center;">{{ .ResponsibleDoctor_Name }}</td>
</tr>
</tbody>
</table> </table>
<div style="margin-top: 6rem;">
Tgl. Cetak : {{ .PrintDate }}
</div>
<div style="height: 3rem;"></div> <div style="height: 3rem;"></div>
</body> </body>
@@ -18,6 +18,7 @@ import (
dg "github.com/karincake/apem/db-gorm-pg" dg "github.com/karincake/apem/db-gorm-pg"
d "github.com/karincake/dodol" d "github.com/karincake/dodol"
"gorm.io/gorm"
erc "simrs-vx/internal/domain/references/common" erc "simrs-vx/internal/domain/references/common"
ere "simrs-vx/internal/domain/references/encounter" ere "simrs-vx/internal/domain/references/encounter"
@@ -36,18 +37,19 @@ func Generate(input GenerateDto) (*d.Data, error) {
// Start log // Start log
pl.SetLogInfo(&event, input, "started", "create") pl.SetLogInfo(&event, input, "started", "create")
err := dg.I.Transaction(func(tx *gorm.DB) error {
switch input.Type_Code { switch input.Type_Code {
// general-consent // general-consent
case ere.DTCGC: case ere.DTCGC:
// get value from general consent by ref_id // get value from general consent by ref_id
gc, err := ugc.ReadDetailData(egc.ReadDetailDto{Id: uint(*pc.StringToUint64(*input.Ref_Id))}, &event) gc, err := ugc.ReadDetailData(egc.ReadDetailDto{Id: uint(*pc.StringToUint64(*input.Ref_Id))}, &event)
if err != nil { if err != nil {
return nil, err return err
} }
if gc.FileUrl != nil { if gc.FileUrl != nil {
if err := removeFile(string(input.EntityType_Code), *gc.FileUrl); err != nil { if err := removeFile(string(input.EntityType_Code), *gc.FileUrl); err != nil {
return nil, err return err
} }
} }
@@ -61,10 +63,10 @@ func Generate(input GenerateDto) (*d.Data, error) {
Detail: err.Error(), Detail: err.Error(),
Raw: err, Raw: err,
} }
return nil, err return err
} }
} else { } else {
return nil, errors.New("no value in this general consent") return errors.New("no value in this general consent")
} }
input.FormatType = erc.DFTCPDF input.FormatType = erc.DFTCPDF
@@ -75,12 +77,12 @@ func Generate(input GenerateDto) (*d.Data, error) {
// generate file // generate file
urlPub, err := generateFile(input, templateData) urlPub, err := generateFile(input, templateData)
if err != nil { if err != nil {
return nil, err return err
} }
gc.FileUrl = &urlPub gc.FileUrl = &urlPub
if err := dg.I.Save(&gc).Error; err != nil { if err := dg.I.Save(&gc).Error; err != nil {
return nil, err return err
} }
response = ResponseDto{ response = ResponseDto{
@@ -93,13 +95,13 @@ func Generate(input GenerateDto) (*d.Data, error) {
cl, err := uvscl.ReadDetailData(evscl.ReadDetailDto{Number: input.Ref_Id}, &event) cl, err := uvscl.ReadDetailData(evscl.ReadDetailDto{Number: input.Ref_Id}, &event)
if err != nil { if err != nil {
if !pu.IsDataNotFoundError(err) { if !pu.IsDataNotFoundError(err) {
return nil, err return err
} }
} }
if cl != nil && cl.FileUrl != nil { if cl != nil && cl.FileUrl != nil {
if err := removeFile(string(input.EntityType_Code), *cl.FileUrl); err != nil { if err := removeFile(string(input.EntityType_Code), *cl.FileUrl); err != nil {
return nil, err return err
} }
} }
@@ -113,10 +115,10 @@ func Generate(input GenerateDto) (*d.Data, error) {
Detail: err.Error(), Detail: err.Error(),
Raw: err, Raw: err,
} }
return nil, err return err
} }
} else { } else {
return nil, errors.New("there is no data to be used") return errors.New("there is no data to be used")
} }
if cl == nil { if cl == nil {
@@ -125,31 +127,32 @@ func Generate(input GenerateDto) (*d.Data, error) {
Number: &clData.Number, Number: &clData.Number,
Value: input.Data, Value: input.Data,
} }
if cl, err = uvscl.CreateData(createCL, &event); err != nil { if cl, err = uvscl.CreateData(createCL, &event, tx); err != nil {
return nil, err return err
} }
} }
// get encounter id by vclaim sep number // get encounter id by vclaim sep number
vs, err := uvs.ReadDetailData(evs.ReadDetailDto{Number: &clData.VclaimSep.Number}, &event) vs, err := uvs.ReadDetailData(evs.ReadDetailDto{Number: &clData.VclaimSep.Number}, &event)
if err != nil { if err != nil {
return nil, err return err
} }
input.FormatType = erc.DFTCPDF input.FormatType = erc.DFTCPDF
input.TemplateName = TDNCL input.TemplateName = TDNCL
input.Encounter_Id = vs.Encounter_Id input.Encounter_Id = vs.Encounter_Id
input.UseA5Lanscape = true
templateData := clData.generateTemplateData() templateData := clData.generateTemplateData()
// generate file // generate file
urlPub, err := generateFile(input, templateData) urlPub, err := generateFile(input, templateData)
if err != nil { if err != nil {
return nil, err return err
} }
cl.FileUrl = &urlPub cl.FileUrl = &urlPub
if err := dg.I.Save(&cl).Error; err != nil { if err := tx.Save(&cl).Error; err != nil {
return nil, err return err
} }
response = ResponseDto{ response = ResponseDto{
@@ -157,7 +160,14 @@ func Generate(input GenerateDto) (*d.Data, error) {
} }
default: default:
return nil, errors.New("invalid type code") return errors.New("invalid type code")
}
return nil
})
if err != nil {
return nil, err
} }
return &d.Data{ return &d.Data{
@@ -33,6 +33,7 @@ func generateFile(input GenerateDto, templateData any) (string, error) {
TemplatePath: templatePath, TemplatePath: templatePath,
TemplateData: templateData, TemplateData: templateData,
PdfPath: fPath, PdfPath: fPath,
UseA5Lanscape: input.UseA5Lanscape,
}); err != nil { }); err != nil {
return "", err return "", err
} }
@@ -73,7 +74,7 @@ func generatePDF(input GeneratePDFdto) error {
// parse template data into html template // parse template data into html template
r := pp.NewRequestPdf("") r := pp.NewRequestPdf("")
if err := r.ParseTemplate(input.TemplatePath, input.TemplateData); err == nil { 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 { if err != nil {
return errors.New("generate pdf by command error : " + err.Error()) return errors.New("generate pdf by command error : " + err.Error())
} }
@@ -39,6 +39,7 @@ type GenerateDto struct {
FormatType erc.DocFormatTypeCode `json:"formatType"` FormatType erc.DocFormatTypeCode `json:"formatType"`
TemplateName TemplateDocsName `json:"-"` TemplateName TemplateDocsName `json:"-"`
Encounter_Id *uint `json:"-"` Encounter_Id *uint `json:"-"`
UseA5Lanscape bool `json:"-"`
Data *string `json:"data"` Data *string `json:"data"`
} }
@@ -46,7 +47,6 @@ type GenerateDto struct {
type VclaimControlLetter struct { type VclaimControlLetter struct {
Number string `json:"noSuratKontrol"` Number string `json:"noSuratKontrol"`
PlannedControlDate string `json:"tglRencanaKontrol"` PlannedControlDate string `json:"tglRencanaKontrol"`
IssuedDate string `json:"tglTerbit"`
Doctor_Name string `json:"namaDokter"` Doctor_Name string `json:"namaDokter"`
DstUnit_Name string `json:"namaPoliTujuan"` DstUnit_Name string `json:"namaPoliTujuan"`
ResponsibleDoctor_Name string `json:"namaDokterPembuat"` ResponsibleDoctor_Name string `json:"namaDokterPembuat"`
@@ -70,6 +70,7 @@ type GeneratePDFdto struct {
TemplatePath string TemplatePath string
TemplateData any TemplateData any
PdfPath string PdfPath string
UseA5Lanscape bool
} }
type ResponseDto struct { type ResponseDto struct {
+16 -3
View File
@@ -47,9 +47,9 @@ func (r *RequestPdf) ParseTemplate(templatePath string, data interface{}) error
return nil return nil
} }
func (r *RequestPdf) GenerateByCommand(pdfPath string, templatePath string) (bool, error) { func (r *RequestPdf) GenerateByCommand(pdfPath string, templatePath string, useA5Lanscape bool) (bool, error) {
// wkhtmltopdf -L 0 -R 0 -B 0 -s Legal --enable-local-file-access resultAntigen2.html out.pdf
t := time.Now().Unix() t := time.Now().Unix()
var cmd *exec.Cmd
if _, err := os.Stat("cloneTemplate/"); os.IsNotExist(err) { if _, err := os.Stat("cloneTemplate/"); os.IsNotExist(err) {
errDir := os.Mkdir("cloneTemplate/", 0777) errDir := os.Mkdir("cloneTemplate/", 0777)
@@ -63,7 +63,20 @@ func (r *RequestPdf) GenerateByCommand(pdfPath string, templatePath string) (boo
panic(err) 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 { if err := cmd.Run(); err != nil {
return false, err return false, err