diff --git a/Backend/endpoints/pdf-create.go b/Backend/endpoints/pdf-create.go index cfeab6a..2672371 100644 --- a/Backend/endpoints/pdf-create.go +++ b/Backend/endpoints/pdf-create.go @@ -72,7 +72,7 @@ func renderPDF(days []typstDay, metadata typstMetadata) (bytes.Buffer, error) { // Import the template and invoke the template function with the custom data. // Show is used to replace the current document with whatever content the template function in `template.typ` returns. markup.WriteString(` - #import "template.typ": abrechnung + #import "templates/abrechnung.typ": abrechnung #show: doc => abrechnung(meta, days) `) @@ -84,7 +84,10 @@ func renderPDF(days []typstDay, metadata typstMetadata) (bytes.Buffer, error) { // defer f.Close() // - typstCLI := typst.CLI{} + // typstCLI := typst.CLI{} + typstCLI := typst.DockerExec{ + ContainerName: helper.GetEnv("TYPST_CONTAINER", "arbeitszeitmessung-doc-creator"), + } if err := typstCLI.Compile(&markup, &output, nil); err != nil { return output, err } diff --git a/Backend/go.mod b/Backend/go.mod index 34c75a2..518cfc4 100644 --- a/Backend/go.mod +++ b/Backend/go.mod @@ -9,7 +9,7 @@ require github.com/a-h/templ v0.3.943 require github.com/alexedwards/scs/v2 v2.8.0 require ( - github.com/Dadido3/go-typst v0.3.0 + github.com/Dadido3/go-typst v0.8.0 github.com/golang-migrate/migrate/v4 v4.18.3 github.com/joho/godotenv v1.5.1 ) diff --git a/Backend/go.sum b/Backend/go.sum index 4bbe15a..95a0e66 100644 --- a/Backend/go.sum +++ b/Backend/go.sum @@ -1,7 +1,7 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= -github.com/Dadido3/go-typst v0.3.0 h1:Itix2FtQgBiOuHUNqgGUAK11Oo2WMlZGGGpCiQNK1IA= -github.com/Dadido3/go-typst v0.3.0/go.mod h1:QYis9sT70u65kn1SkFfyPRmHsPxgoxWbAixwfPReOZA= +github.com/Dadido3/go-typst v0.8.0 h1:uTLYprhkrBjwsCXRRuyYUFL0fpYHa2kIYoOB/CGqVNs= +github.com/Dadido3/go-typst v0.8.0/go.mod h1:QYis9sT70u65kn1SkFfyPRmHsPxgoxWbAixwfPReOZA= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/a-h/templ v0.3.943 h1:o+mT/4yqhZ33F3ootBiHwaY4HM5EVaOJfIshvd5UNTY= diff --git a/Docker/docker-compose.dev.yml b/Docker/docker-compose.dev.yml index 2554fbb..b5a413b 100644 --- a/Docker/docker-compose.dev.yml +++ b/Docker/docker-compose.dev.yml @@ -1,12 +1,6 @@ name: arbeitszeitmessung-dev services: db: - image: postgres:16 - restart: unless-stopped - env_file: - - .env - environment: - PGDATA: /var/lib/postgresql/data/pg_data volumes: - ${POSTGRES_PATH}:/var/lib/postgresql/data # - ${POSTGRES_PATH}/initdb:/docker-entrypoint-initdb.d @@ -19,21 +13,8 @@ services: ports: - 8001:8080 backend: - image: git.letsstein.de/tom/arbeitszeitmessung - restart: unless-stopped - env_file: - - .env environment: - POSTGRES_HOST: db - POSTGRES_DB: ${POSTGRES_DB} - EXPOSED_PORT: ${EXPOSED_PORT} NO_CORS: true - ports: - - ${EXPOSED_PORT}:8080 - volumes: - - ../logs:/app/Backend/logs - depends_on: - - db swagger: image: swaggerapi/swagger-ui diff --git a/Docker/docker-compose.yml b/Docker/docker-compose.yml index d3d97c0..a5fc78d 100644 --- a/Docker/docker-compose.yml +++ b/Docker/docker-compose.yml @@ -12,20 +12,25 @@ services: - ${POSTGRES_PATH}:/var/lib/postgresql/data - ${POSTGRES_PATH}/initdb:/docker-entrypoint-initdb.d ports: - - 5432:5432 + - ${POSTGRES_PORT}:5432 backend: - image: git.letsstein.de/tom/arbeitszeitmessung + image: git.letsstein.de/tom/arbeitszeitmessung-webserver env_file: - .env environment: POSTGRES_HOST: db POSTGRES_DB: ${POSTGRES_DB} - EXPOSED_PORT: ${EXPOSED_PORT} ports: - - ${EXPOSED_PORT}:8080 + - ${WEB_PORT}:8080 depends_on: - db + - document-creator volumes: - ../logs:/app/Backend/logs restart: unless-stopped + + document-creator: + image: git.letsstein.de/tom/arbeitszeitmessung-doc-creator + container_name: ${TYPST_CONTAINER} + restart: unless-stopped diff --git a/DocumentCreator/Dockerfile b/DocumentCreator/Dockerfile new file mode 100644 index 0000000..1989fed --- /dev/null +++ b/DocumentCreator/Dockerfile @@ -0,0 +1,6 @@ +FROM ghcr.io/typst/typst:0.14.0 + +COPY ./templates ./templates +COPY ./static ./static + +ENTRYPOINT ["sh", "-c", "while true; do sleep 3600; done"] diff --git a/DocumentCreator/static/logo.png b/DocumentCreator/static/logo.png new file mode 100644 index 0000000..53694f9 Binary files /dev/null and b/DocumentCreator/static/logo.png differ diff --git a/DocumentCreator/templates/abrechnung.typ b/DocumentCreator/templates/abrechnung.typ new file mode 100644 index 0000000..ade04ab --- /dev/null +++ b/DocumentCreator/templates/abrechnung.typ @@ -0,0 +1,92 @@ +#let table-header(..headers) = { + table.header( + ..headers.pos().map(h => strong(h)) + ) +} + + +#let abrechnung(meta, days) = { + set page(paper: "a4", margin: (x:1.5cm, y:2.25cm), + footer:[#grid( + columns: (3fr, .65fr), + align: left + horizon, + inset: .5em, + [#meta.EmployeeName -- #meta.TimeRange], grid.cell(rowspan: 2)[#image("static/logo.png")], + [Arbeitszeitrechnung maschinell erstellt am #meta.CurrentTimestamp], + ) + ]) + set text(font: "Noto Sans", size:10pt, fill: luma(10%)) + set table( + stroke: 0.5pt + luma(10%), + inset: .5em, + align: center + horizon, + ) + show text: it => { + if it.text == "0min"{ + text(oklch(70.8%, 0, 0deg))[#it] + }else if it.text.starts-with("-"){ + text(red)[#it] + }else{ + it + } + } + + + [= Abrechnung Arbeitszeit -- #meta.EmployeeName] + + [Zeitraum: #meta.TimeRange] + + table( + columns: (1fr, 1fr, 1fr, 1fr, 1fr, 1fr, 1.25fr), + fill: (x, y) => + if y == 0 { oklch(87%, 0, 0deg) }, + table-header( + [Datum], [Kommen], [Gehen], [Arbeitsart], [Stunden], [Pause], [Überstunden] + ), + .. for day in days { + ( + [#day.Date], + if day.DayParts.len() == 0{ + table.cell(colspan: 3)[Keine Buchungen] + }else if not day.DayParts.first().IsWorkDay{ + table.cell(colspan: 3)[#day.DayParts.first().WorkType] + } + else { + + table.cell(colspan: 3, inset: 0em)[ + + #table( + columns: (1fr, 1fr, 1fr), + .. for Zeit in day.DayParts { + ( + [#Zeit.BookingFrom], + [#Zeit.BookingTo], + [#Zeit.WorkType], + ) + }, + ) + ] + }, + [#day.Worktime], + [#day.Pausetime], + [#day.Overtime], + ) + if day.IsFriday { + ( table.cell(colspan: 7, fill: oklch(87%, 0, 0deg))[Wochenende], ) // note the trailing comma + } + } + ) + + table( + columns: (3fr, 1fr), + align: right, + inset: (x: .25em, y:.75em), + stroke: none, + table.hline(start: 0, end: 2, stroke: stroke(dash:"dashed", thickness:.5pt)), + [Arbeitszeit :], table.cell(align: left)[#meta.WorkTime], + [Überstunden :], table.cell(align: left)[#meta.Overtime], + [Überstunden :],table.cell(align: left)[#meta.OvertimeTotal], + table.hline(start: 0, end: 2), + +) +}