diff --git a/.dev-js/package.json b/.dev-js/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..f1a3b8b143115ffb8f0fee2d452ec2830cd888a3
--- /dev/null
+++ b/.dev-js/package.json
@@ -0,0 +1,14 @@
+{
+  "name": "aleksis-builddeps",
+  "version": "1.0.0",
+  "dependencies": {
+    "@intlify/eslint-plugin-vue-i18n": "^2.0.0",
+    "eslint": "^8.26.0",
+    "eslint-config-prettier": "^9.0.0",
+    "eslint-plugin-vue": "^9.7.0",
+    "prettier": "^3.0.0",
+    "stylelint": "^15.0.0",
+    "stylelint-config-prettier": "^9.0.3",
+    "stylelint-config-standard": "^34.0.0"
+  }
+}
diff --git a/.gitignore b/.gitignore
index 902d52b19777084e9cf9f373502f70b32b4495a6..79b5b76de6f6445254cbf64f7e4fb228ffdf0ab8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -52,6 +52,11 @@ DEADJOE
 .idea
 .idea/
 
+# VSCode
+.vscode/
+.history/
+*.code-workspace
+
 # Database
 db.sqlite3
 
@@ -62,15 +67,28 @@ docs/_build/
 *.aux
 
 # Generated files
-aleksis/node_modules/
-aleksis/static/
+/cache
+/node_modules
+.dev-js/node_modules
+/static/
+/whoosh_index/
+.vite
+.dev-js/.yarn
+.dev-js/.pnp.cjs
+.dev-js/.pnp.loader.mjs
+
+# Lock files
+poetry.lock
+package-lock.json
+yarn.lock
+.dev-js/yarn.lock
 
+# Tests
 .coverage
 .mypy_cache/
 .tox/
 htmlcov/
+
+# Data
 maintenance_mode_state.txt
 media/
-package-lock.json
-
-poetry.lock
diff --git a/.prettierignore b/.prettierignore
index 38d141b743fd55678f50077c0617924475817095..de783fc60a1ca5f6e25204bb7a51eab815bc77ce 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -89,3 +89,6 @@ yarn.lock
 # Do not check/reformat generated files
 aleksis/core/util/licenses.json
 .vite/
+
+.pnp.cjs
+.pnp.loader.mjs
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 03149158c9fe2a376f4adbacb7d9bff5502928b9..7eca79481851fc376fd585f9b4f1e0350e91c709 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -6,7 +6,54 @@ All notable changes to this project will be documented in this file.
 The format is based on `Keep a Changelog`_,
 and this project adheres to `Semantic Versioning`_.
 
-`2.0`_ - 2023-05-15
+`0.4`_ - 2023-09-16
+-------------------
+
+Added
+~~~~~
+
+* Deletion of print jobs is now possible.
+* Back button for card detail view.
+
+Changed
+~~~~~~~
+
+* The printer queue is now displayed with an improved design.
+
+Fixed
+~~~~~
+
+* Order of print jobs is now from new to old.
+* Deactivate and delete buttons weren't shown.
+
+`0.3.1`_ - 2023-09-10
+---------------------
+
+Fixed
+~~~~~
+
+* The last release included a broken migration.
+
+`0.3`_ - 2023-09-05
+-------------------
+
+Added
+~~~~~
+
+* Preview view for card layouts.
+
+`0.2.1`_ - 2023-08-30
+---------------------
+
+Fixed
+~~~~~
+
+* Columns had unsable links.
+* API endpoint for printer details returned 500 instead of 403.
+* Card PDF generation wasn't possible without a chip number.
+* Only hashed client secret was provided in config.json
+
+`0.2`_ - 2023-05-15
 -------------------
 
 This version requires AlekSIS-Core 3.0. It is incompatible with any previous
@@ -36,3 +83,7 @@ Added
 .. _0.1: https://edugit.org/AlekSIS/onboarding/AlekSIS-App-Kort/-/tags/0.1
 .. _0.1.1: https://edugit.org/AlekSIS/onboarding/AlekSIS-App-Kort/-/tags/0.1.1
 .. _0.2: https://edugit.org/AlekSIS/onboarding/AlekSIS-App-Kort/-/tags/0.2
+.. _0.2.1: https://edugit.org/AlekSIS/onboarding/AlekSIS-App-Kort/-/tags/0.2.1
+.. _0.3: https://edugit.org/AlekSIS/onboarding/AlekSIS-App-Kort/-/tags/0.3
+.. _0.3.1: https://edugit.org/AlekSIS/onboarding/AlekSIS-App-Kort/-/tags/0.3.1
+.. _0.4: https://edugit.org/AlekSIS/onboarding/AlekSIS-App-Kort/-/tags/0.4
diff --git a/aleksis/apps/kort/api.py b/aleksis/apps/kort/api.py
index ceaad65f4f80c96e95ceba77576a03521528fb16..f9f9d119cd813588b4f65800527e7608c67ba251 100644
--- a/aleksis/apps/kort/api.py
+++ b/aleksis/apps/kort/api.py
@@ -8,7 +8,7 @@ from oauth2_provider.oauth2_backends import get_oauthlib_core
 from oauthlib.common import Request as OauthlibRequest
 from rest_framework import generics, serializers
 from rest_framework.authentication import BaseAuthentication
-from rest_framework.exceptions import APIException, ValidationError
+from rest_framework.exceptions import APIException, PermissionDenied, ValidationError
 from rest_framework.permissions import BasePermission
 from rest_framework.response import Response
 from rest_framework.views import APIView
@@ -133,6 +133,8 @@ class CardPrinterDetails(generics.RetrieveAPIView):
 
     def get_object(self):
         token = self.request.auth
+        if not token:
+            raise PermissionDenied()
         return token.client.card_printers.all().first()
 
 
diff --git a/aleksis/apps/kort/frontend/index.js b/aleksis/apps/kort/frontend/index.js
index 997acdeab6833d6aff2ac9f36fde7ac8e8032d0c..d1cf2cb5c4a60cf74d2855f395adca5560402f31 100644
--- a/aleksis/apps/kort/frontend/index.js
+++ b/aleksis/apps/kort/frontend/index.js
@@ -52,6 +52,15 @@ export default {
         byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
       },
     },
+    {
+      path: "cards/:pk/preview/",
+      component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
+      name: "kort.previewCard",
+
+      props: {
+        byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
+      },
+    },
     {
       path: "cards/:pk/print/",
       component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
@@ -123,6 +132,14 @@ export default {
         byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
       },
     },
+    {
+      path: "jobs/:pk/delete/",
+      component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
+      name: "kort.deletePrintJob",
+      props: {
+        byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
+      },
+    },
     {
       path: "layouts/",
       component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
diff --git a/aleksis/apps/kort/locale/ar/LC_MESSAGES/django.po b/aleksis/apps/kort/locale/ar/LC_MESSAGES/django.po
index 6df710ddf6954b35c7a51068296d12c8f1bf16d4..bfb7b49c2de1be7f276e53b38d6163ddda0058fe 100644
--- a/aleksis/apps/kort/locale/ar/LC_MESSAGES/django.po
+++ b/aleksis/apps/kort/locale/ar/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-03-19 15:48+0100\n"
+"POT-Creation-Date: 2023-09-16 17:04+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -55,12 +55,12 @@ msgstr ""
 msgid "Groups"
 msgstr ""
 
-#: aleksis/apps/kort/forms.py:51 aleksis/apps/kort/models.py:191
+#: aleksis/apps/kort/forms.py:51 aleksis/apps/kort/models.py:209
 msgid "Card layout"
 msgstr ""
 
-#: aleksis/apps/kort/forms.py:53 aleksis/apps/kort/models.py:263
-#: aleksis/apps/kort/tables.py:30
+#: aleksis/apps/kort/forms.py:53 aleksis/apps/kort/models.py:281
+#: aleksis/apps/kort/tables.py:23
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:24
 #: aleksis/apps/kort/templates/kort/card/short.html:12
 msgid "Valid until"
@@ -82,43 +82,43 @@ msgstr ""
 msgid "Printer settings"
 msgstr ""
 
-#: aleksis/apps/kort/forms.py:138 aleksis/apps/kort/models.py:228
+#: aleksis/apps/kort/forms.py:138 aleksis/apps/kort/models.py:246
 msgid "Required data fields"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:24
+#: aleksis/apps/kort/models.py:25
 msgid "Online"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:25
+#: aleksis/apps/kort/models.py:26
 msgid "Offline"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:26
+#: aleksis/apps/kort/models.py:27
 msgid "With errors"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:27
+#: aleksis/apps/kort/models.py:28
 msgid "Not registered"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:56
+#: aleksis/apps/kort/models.py:57
 msgid "Registered"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:57
+#: aleksis/apps/kort/models.py:58
 msgid "In progress"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:58
+#: aleksis/apps/kort/models.py:59
 msgid "Finished"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:59
+#: aleksis/apps/kort/models.py:60
 msgid "Failed"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:64 aleksis/apps/kort/models.py:223
+#: aleksis/apps/kort/models.py:65 aleksis/apps/kort/models.py:241
 #: aleksis/apps/kort/templates/kort/card_layout/detail_content.html:11
 #: aleksis/apps/kort/templates/kort/card_layout/short.html:4
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:11
@@ -126,188 +126,196 @@ msgstr ""
 msgid "Name"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:65
+#: aleksis/apps/kort/models.py:66
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:24
 msgid "Description"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:66
+#: aleksis/apps/kort/models.py:67
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:17
 #: aleksis/apps/kort/templates/kort/printer/short.html:8
 msgid "Location"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:70 aleksis/apps/kort/models.py:336
-#: aleksis/apps/kort/tables.py:95
+#: aleksis/apps/kort/models.py:71 aleksis/apps/kort/models.py:354
+#: aleksis/apps/kort/tables.py:94
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:38
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:38
-#: aleksis/apps/kort/templates/kort/printer/detail_content.html:90
+#: aleksis/apps/kort/templates/kort/printer/detail_content.html:91
 #: aleksis/apps/kort/templates/kort/printer/short.html:12
 msgid "Status"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:74 aleksis/apps/kort/models.py:340
+#: aleksis/apps/kort/models.py:75 aleksis/apps/kort/models.py:358
 msgid "Status text"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:75 aleksis/apps/kort/tables.py:58
+#: aleksis/apps/kort/models.py:76 aleksis/apps/kort/tables.py:52
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:31
 msgid "Last seen at"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:80
+#: aleksis/apps/kort/models.py:81
 msgid "OAuth2 application"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:87
+#: aleksis/apps/kort/models.py:89
+msgid "OAuth2 client secret"
+msgstr ""
+
+#: aleksis/apps/kort/models.py:95
 msgid "CUPS printer"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:89
+#: aleksis/apps/kort/models.py:97
+msgid "Leave blank to deactivate CUPS printing"
+msgstr ""
+
+#: aleksis/apps/kort/models.py:100
 msgid "Generate card number on server"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:91
+#: aleksis/apps/kort/models.py:102
 msgid "Card detector"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:181
+#: aleksis/apps/kort/models.py:199
 msgid "Card printer"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:182
+#: aleksis/apps/kort/models.py:200
 #: aleksis/apps/kort/templates/kort/printer/list.html:8
 #: aleksis/apps/kort/templates/kort/printer/list.html:9
 msgid "Card printers"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:186
+#: aleksis/apps/kort/models.py:204
 msgid "Media file"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:198
+#: aleksis/apps/kort/models.py:216
 msgid "Media file for a card layout"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:199
+#: aleksis/apps/kort/models.py:217
 msgid "Media files for card layouts"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:224
+#: aleksis/apps/kort/models.py:242
 #: aleksis/apps/kort/templates/kort/card_layout/detail_content.html:43
 msgid "Template"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:225
+#: aleksis/apps/kort/models.py:243
 #: aleksis/apps/kort/templates/kort/card_layout/detail_content.html:49
 msgid "Custom CSS"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:226
+#: aleksis/apps/kort/models.py:244
 msgid "Width"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:226 aleksis/apps/kort/models.py:227
+#: aleksis/apps/kort/models.py:244 aleksis/apps/kort/models.py:245
 msgid "in mm"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:227
+#: aleksis/apps/kort/models.py:245
 msgid "Height"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:248
+#: aleksis/apps/kort/models.py:266
 msgid "Template is invalid: {}"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:254 aleksis/apps/kort/models.py:267
+#: aleksis/apps/kort/models.py:272 aleksis/apps/kort/models.py:285
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:31
 #: aleksis/apps/kort/templates/kort/card_layout/detail.html:8
 msgid "Card Layout"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:255
+#: aleksis/apps/kort/models.py:273
 msgid "Card Layouts"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:260
+#: aleksis/apps/kort/models.py:278 aleksis/apps/kort/tables.py:20
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:11
 #: aleksis/apps/kort/templates/kort/card/short.html:4
 msgid "Person"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:262
+#: aleksis/apps/kort/models.py:280
 msgid "Chip Number"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:264 aleksis/apps/kort/tables.py:31
+#: aleksis/apps/kort/models.py:282 aleksis/apps/kort/tables.py:24
 msgid "Deactivated"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:270
+#: aleksis/apps/kort/models.py:288
 msgid "PDF file"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:303
+#: aleksis/apps/kort/models.py:321
 msgid "There is no layout provided for the card."
 msgstr ""
 
-#: aleksis/apps/kort/models.py:322 aleksis/apps/kort/models.py:331
+#: aleksis/apps/kort/models.py:340 aleksis/apps/kort/models.py:349
 #: aleksis/apps/kort/templates/kort/card/detail.html:8
-#: aleksis/apps/kort/templates/kort/printer/detail_content.html:84
+#: aleksis/apps/kort/templates/kort/printer/detail_content.html:85
 msgid "Card"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:323
+#: aleksis/apps/kort/models.py:341
 #: aleksis/apps/kort/templates/kort/card/list.html:8
 #: aleksis/apps/kort/templates/kort/card/list.html:9
 msgid "Cards"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:328
+#: aleksis/apps/kort/models.py:346
 msgid "Printer"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:343
+#: aleksis/apps/kort/models.py:361
 msgid "Card print job"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:344
+#: aleksis/apps/kort/models.py:362
 msgid "Card print jobs"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:28
+#: aleksis/apps/kort/tables.py:21
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:17
 #: aleksis/apps/kort/templates/kort/card/short.html:8
 msgid "Chip number"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:29 aleksis/apps/kort/tables.py:57
+#: aleksis/apps/kort/tables.py:22 aleksis/apps/kort/tables.py:51
 msgid "Current status"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:32 aleksis/apps/kort/tables.py:61
-#: aleksis/apps/kort/tables.py:85
+#: aleksis/apps/kort/tables.py:25 aleksis/apps/kort/tables.py:55
+#: aleksis/apps/kort/tables.py:81
 msgid "Actions"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:54
+#: aleksis/apps/kort/tables.py:48
 msgid "Printer name"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:55
+#: aleksis/apps/kort/tables.py:49
 msgid "Printer location"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:59
+#: aleksis/apps/kort/tables.py:53
 msgid "Running jobs"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:81
+#: aleksis/apps/kort/tables.py:77
 msgid "Layout name"
 msgstr ""
 
 #: aleksis/apps/kort/templates/kort/card/actions.html:8
-#: aleksis/apps/kort/templates/kort/card/detail.html:9
+#: aleksis/apps/kort/templates/kort/card/detail.html:13
 #, python-format
 msgid "Card of %(person)s"
 msgstr ""
@@ -342,6 +350,7 @@ msgstr ""
 #: aleksis/apps/kort/templates/kort/printer/actions.html:33
 #: aleksis/apps/kort/templates/kort/printer/delete.html:29
 #: aleksis/apps/kort/templates/kort/printer/detail.html:31
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:22
 msgid "Delete"
 msgstr ""
 
@@ -365,9 +374,14 @@ msgstr ""
 #: aleksis/apps/kort/templates/kort/card/delete.html:26
 #: aleksis/apps/kort/templates/kort/card_layout/delete.html:25
 #: aleksis/apps/kort/templates/kort/printer/delete.html:25
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:18
 msgid "Go back"
 msgstr ""
 
+#: aleksis/apps/kort/templates/kort/card/detail.html:11
+msgid "Back"
+msgstr ""
+
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:6
 msgid "Card details"
 msgstr ""
@@ -384,6 +398,10 @@ msgstr ""
 msgid "Generate card as PDF"
 msgstr ""
 
+#: aleksis/apps/kort/templates/kort/card/detail_content.html:68
+msgid "Preview card layout"
+msgstr ""
+
 #: aleksis/apps/kort/templates/kort/card/edit.html:12
 #: aleksis/apps/kort/templates/kort/card/edit.html:13
 msgid "Edit card"
@@ -617,7 +635,7 @@ msgstr ""
 msgid "Print jobs"
 msgstr ""
 
-#: aleksis/apps/kort/templates/kort/printer/detail_content.html:87
+#: aleksis/apps/kort/templates/kort/printer/detail_content.html:88
 msgid "Created at"
 msgstr ""
 
@@ -630,6 +648,14 @@ msgstr ""
 msgid "Register new card printer"
 msgstr ""
 
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:8
+msgid "Delete Card Print Job"
+msgstr ""
+
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:12
+msgid "Do you really want to delete the following card print job?"
+msgstr ""
+
 #: aleksis/apps/kort/views.py:69
 msgid "The cards have been created successfully."
 msgstr ""
@@ -650,50 +676,50 @@ msgstr ""
 msgid "The card has been deactivated successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:220
-msgid "The chip number is missing."
-msgstr ""
-
-#: aleksis/apps/kort/views.py:232
+#: aleksis/apps/kort/views.py:238
 msgid "Progress: Generate card layout as PDF file"
 msgstr ""
 
-#: aleksis/apps/kort/views.py:233
+#: aleksis/apps/kort/views.py:239
 msgid "Generating PDF file …"
 msgstr ""
 
-#: aleksis/apps/kort/views.py:234
+#: aleksis/apps/kort/views.py:240
 msgid "The PDF file with the card layout has been generated successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:235
+#: aleksis/apps/kort/views.py:241
 msgid "There was a problem while generating the PDF file."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:237
+#: aleksis/apps/kort/views.py:243
 msgid "Show card"
 msgstr ""
 
-#: aleksis/apps/kort/views.py:275
+#: aleksis/apps/kort/views.py:281
 msgid "The card printer has been created successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:288
+#: aleksis/apps/kort/views.py:294
 msgid "The card printer has been changed successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:301
+#: aleksis/apps/kort/views.py:307
 msgid "The card printer has been deleted successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:364
+#: aleksis/apps/kort/views.py:317
+msgid "The card print job has been deleted successfully."
+msgstr ""
+
+#: aleksis/apps/kort/views.py:380
 msgid "The card layout has been created successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:382
+#: aleksis/apps/kort/views.py:398
 msgid "The card layout has been changed successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:395
+#: aleksis/apps/kort/views.py:411
 msgid "The card layout has been deleted successfully."
 msgstr ""
diff --git a/aleksis/apps/kort/locale/de_DE/LC_MESSAGES/django.po b/aleksis/apps/kort/locale/de_DE/LC_MESSAGES/django.po
index 52d13911397801b48cc76d6b536b3f40b117e84e..803fe03ed891f01c8d997ce155a2cee9b26d2ddb 100644
--- a/aleksis/apps/kort/locale/de_DE/LC_MESSAGES/django.po
+++ b/aleksis/apps/kort/locale/de_DE/LC_MESSAGES/django.po
@@ -7,8 +7,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-03-19 15:48+0100\n"
-"PO-Revision-Date: 2022-08-12 22:00+0000\n"
+"POT-Creation-Date: 2023-09-16 17:04+0200\n"
+"PO-Revision-Date: 2023-09-16 15:16+0000\n"
 "Last-Translator: Jonathan Weth <teckids@jonathanweth.de>\n"
 "Language-Team: German <https://translate.edugit.org/projects/aleksis/aleksis-app-kort/de/>\n"
 "Language: de_DE\n"
@@ -55,12 +55,12 @@ msgstr "Personen"
 msgid "Groups"
 msgstr "Gruppen"
 
-#: aleksis/apps/kort/forms.py:51 aleksis/apps/kort/models.py:191
+#: aleksis/apps/kort/forms.py:51 aleksis/apps/kort/models.py:209
 msgid "Card layout"
 msgstr "Kartenlayout"
 
-#: aleksis/apps/kort/forms.py:53 aleksis/apps/kort/models.py:263
-#: aleksis/apps/kort/tables.py:30
+#: aleksis/apps/kort/forms.py:53 aleksis/apps/kort/models.py:281
+#: aleksis/apps/kort/tables.py:23
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:24
 #: aleksis/apps/kort/templates/kort/card/short.html:12
 msgid "Valid until"
@@ -82,43 +82,43 @@ msgstr "Allgemeine Attribute"
 msgid "Printer settings"
 msgstr "Druckereinstellungen"
 
-#: aleksis/apps/kort/forms.py:138 aleksis/apps/kort/models.py:228
+#: aleksis/apps/kort/forms.py:138 aleksis/apps/kort/models.py:246
 msgid "Required data fields"
 msgstr "Benötigte Datenfelder"
 
-#: aleksis/apps/kort/models.py:24
+#: aleksis/apps/kort/models.py:25
 msgid "Online"
 msgstr "Online"
 
-#: aleksis/apps/kort/models.py:25
+#: aleksis/apps/kort/models.py:26
 msgid "Offline"
 msgstr "Offline"
 
-#: aleksis/apps/kort/models.py:26
+#: aleksis/apps/kort/models.py:27
 msgid "With errors"
 msgstr "Mit Fehlern"
 
-#: aleksis/apps/kort/models.py:27
+#: aleksis/apps/kort/models.py:28
 msgid "Not registered"
 msgstr "Nicht registriert"
 
-#: aleksis/apps/kort/models.py:56
+#: aleksis/apps/kort/models.py:57
 msgid "Registered"
 msgstr "Registriert"
 
-#: aleksis/apps/kort/models.py:57
+#: aleksis/apps/kort/models.py:58
 msgid "In progress"
 msgstr "In Bearbeitung"
 
-#: aleksis/apps/kort/models.py:58
+#: aleksis/apps/kort/models.py:59
 msgid "Finished"
 msgstr "Beendet"
 
-#: aleksis/apps/kort/models.py:59
+#: aleksis/apps/kort/models.py:60
 msgid "Failed"
 msgstr "Fehlgeschlagen"
 
-#: aleksis/apps/kort/models.py:64 aleksis/apps/kort/models.py:223
+#: aleksis/apps/kort/models.py:65 aleksis/apps/kort/models.py:241
 #: aleksis/apps/kort/templates/kort/card_layout/detail_content.html:11
 #: aleksis/apps/kort/templates/kort/card_layout/short.html:4
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:11
@@ -126,188 +126,196 @@ msgstr "Fehlgeschlagen"
 msgid "Name"
 msgstr "Name"
 
-#: aleksis/apps/kort/models.py:65
+#: aleksis/apps/kort/models.py:66
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:24
 msgid "Description"
 msgstr "Beschreibung"
 
-#: aleksis/apps/kort/models.py:66
+#: aleksis/apps/kort/models.py:67
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:17
 #: aleksis/apps/kort/templates/kort/printer/short.html:8
 msgid "Location"
 msgstr "Ort"
 
-#: aleksis/apps/kort/models.py:70 aleksis/apps/kort/models.py:336
-#: aleksis/apps/kort/tables.py:95
+#: aleksis/apps/kort/models.py:71 aleksis/apps/kort/models.py:354
+#: aleksis/apps/kort/tables.py:94
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:38
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:38
-#: aleksis/apps/kort/templates/kort/printer/detail_content.html:90
+#: aleksis/apps/kort/templates/kort/printer/detail_content.html:91
 #: aleksis/apps/kort/templates/kort/printer/short.html:12
 msgid "Status"
 msgstr "Status"
 
-#: aleksis/apps/kort/models.py:74 aleksis/apps/kort/models.py:340
+#: aleksis/apps/kort/models.py:75 aleksis/apps/kort/models.py:358
 msgid "Status text"
 msgstr "Statustext"
 
-#: aleksis/apps/kort/models.py:75 aleksis/apps/kort/tables.py:58
+#: aleksis/apps/kort/models.py:76 aleksis/apps/kort/tables.py:52
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:31
 msgid "Last seen at"
 msgstr "Zuletzt gesehen am"
 
-#: aleksis/apps/kort/models.py:80
+#: aleksis/apps/kort/models.py:81
 msgid "OAuth2 application"
 msgstr "OAuth2-Anwendung"
 
-#: aleksis/apps/kort/models.py:87
+#: aleksis/apps/kort/models.py:89
+msgid "OAuth2 client secret"
+msgstr "OAuth2-Client-Secret"
+
+#: aleksis/apps/kort/models.py:95
 msgid "CUPS printer"
 msgstr "CUPS-Drucker"
 
-#: aleksis/apps/kort/models.py:89
+#: aleksis/apps/kort/models.py:97
+msgid "Leave blank to deactivate CUPS printing"
+msgstr "Leer lassen, um CUPS-Drucken zu deaktivieren"
+
+#: aleksis/apps/kort/models.py:100
 msgid "Generate card number on server"
 msgstr "Kartennummer auf dem Server generieren"
 
-#: aleksis/apps/kort/models.py:91
+#: aleksis/apps/kort/models.py:102
 msgid "Card detector"
 msgstr "Karten-Detektor"
 
-#: aleksis/apps/kort/models.py:181
+#: aleksis/apps/kort/models.py:199
 msgid "Card printer"
 msgstr "Kartendrucker"
 
-#: aleksis/apps/kort/models.py:182
+#: aleksis/apps/kort/models.py:200
 #: aleksis/apps/kort/templates/kort/printer/list.html:8
 #: aleksis/apps/kort/templates/kort/printer/list.html:9
 msgid "Card printers"
 msgstr "Kartendrucker"
 
-#: aleksis/apps/kort/models.py:186
+#: aleksis/apps/kort/models.py:204
 msgid "Media file"
 msgstr "Mediendatei"
 
-#: aleksis/apps/kort/models.py:198
+#: aleksis/apps/kort/models.py:216
 msgid "Media file for a card layout"
 msgstr "Mediendatei für ein Kartenlayout"
 
-#: aleksis/apps/kort/models.py:199
+#: aleksis/apps/kort/models.py:217
 msgid "Media files for card layouts"
 msgstr "Mediendateien für Kartenlayouts"
 
-#: aleksis/apps/kort/models.py:224
+#: aleksis/apps/kort/models.py:242
 #: aleksis/apps/kort/templates/kort/card_layout/detail_content.html:43
 msgid "Template"
 msgstr "Template"
 
-#: aleksis/apps/kort/models.py:225
+#: aleksis/apps/kort/models.py:243
 #: aleksis/apps/kort/templates/kort/card_layout/detail_content.html:49
 msgid "Custom CSS"
 msgstr "Benutzerdefiniertes CSS"
 
-#: aleksis/apps/kort/models.py:226
+#: aleksis/apps/kort/models.py:244
 msgid "Width"
 msgstr "Breite"
 
-#: aleksis/apps/kort/models.py:226 aleksis/apps/kort/models.py:227
+#: aleksis/apps/kort/models.py:244 aleksis/apps/kort/models.py:245
 msgid "in mm"
 msgstr "in mm"
 
-#: aleksis/apps/kort/models.py:227
+#: aleksis/apps/kort/models.py:245
 msgid "Height"
 msgstr "Höhe"
 
-#: aleksis/apps/kort/models.py:248
+#: aleksis/apps/kort/models.py:266
 msgid "Template is invalid: {}"
 msgstr "Template ist ungültig: {}"
 
-#: aleksis/apps/kort/models.py:254 aleksis/apps/kort/models.py:267
+#: aleksis/apps/kort/models.py:272 aleksis/apps/kort/models.py:285
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:31
 #: aleksis/apps/kort/templates/kort/card_layout/detail.html:8
 msgid "Card Layout"
 msgstr "Kartenlayout"
 
-#: aleksis/apps/kort/models.py:255
+#: aleksis/apps/kort/models.py:273
 msgid "Card Layouts"
 msgstr "Kartenlayouts"
 
-#: aleksis/apps/kort/models.py:260
+#: aleksis/apps/kort/models.py:278 aleksis/apps/kort/tables.py:20
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:11
 #: aleksis/apps/kort/templates/kort/card/short.html:4
 msgid "Person"
 msgstr "Person"
 
-#: aleksis/apps/kort/models.py:262
+#: aleksis/apps/kort/models.py:280
 msgid "Chip Number"
 msgstr "Chip-Nummer"
 
-#: aleksis/apps/kort/models.py:264 aleksis/apps/kort/tables.py:31
+#: aleksis/apps/kort/models.py:282 aleksis/apps/kort/tables.py:24
 msgid "Deactivated"
 msgstr "Deaktiviert"
 
-#: aleksis/apps/kort/models.py:270
+#: aleksis/apps/kort/models.py:288
 msgid "PDF file"
 msgstr "PDF-Datei"
 
-#: aleksis/apps/kort/models.py:303
+#: aleksis/apps/kort/models.py:321
 msgid "There is no layout provided for the card."
 msgstr "Es wurde kein Layout für die Karte bereitgestellt."
 
-#: aleksis/apps/kort/models.py:322 aleksis/apps/kort/models.py:331
+#: aleksis/apps/kort/models.py:340 aleksis/apps/kort/models.py:349
 #: aleksis/apps/kort/templates/kort/card/detail.html:8
-#: aleksis/apps/kort/templates/kort/printer/detail_content.html:84
+#: aleksis/apps/kort/templates/kort/printer/detail_content.html:85
 msgid "Card"
 msgstr "Karte"
 
-#: aleksis/apps/kort/models.py:323
+#: aleksis/apps/kort/models.py:341
 #: aleksis/apps/kort/templates/kort/card/list.html:8
 #: aleksis/apps/kort/templates/kort/card/list.html:9
 msgid "Cards"
 msgstr "Karten"
 
-#: aleksis/apps/kort/models.py:328
+#: aleksis/apps/kort/models.py:346
 msgid "Printer"
 msgstr "Drucker"
 
-#: aleksis/apps/kort/models.py:343
+#: aleksis/apps/kort/models.py:361
 msgid "Card print job"
 msgstr "Karten-Druckauftrag"
 
-#: aleksis/apps/kort/models.py:344
+#: aleksis/apps/kort/models.py:362
 msgid "Card print jobs"
 msgstr "Karten-Druckaufträge"
 
-#: aleksis/apps/kort/tables.py:28
+#: aleksis/apps/kort/tables.py:21
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:17
 #: aleksis/apps/kort/templates/kort/card/short.html:8
 msgid "Chip number"
 msgstr "Chip-Nummer"
 
-#: aleksis/apps/kort/tables.py:29 aleksis/apps/kort/tables.py:57
+#: aleksis/apps/kort/tables.py:22 aleksis/apps/kort/tables.py:51
 msgid "Current status"
 msgstr "Aktueller Status"
 
-#: aleksis/apps/kort/tables.py:32 aleksis/apps/kort/tables.py:61
-#: aleksis/apps/kort/tables.py:85
+#: aleksis/apps/kort/tables.py:25 aleksis/apps/kort/tables.py:55
+#: aleksis/apps/kort/tables.py:81
 msgid "Actions"
 msgstr "Aktionen"
 
-#: aleksis/apps/kort/tables.py:54
+#: aleksis/apps/kort/tables.py:48
 msgid "Printer name"
 msgstr "Druckername"
 
-#: aleksis/apps/kort/tables.py:55
+#: aleksis/apps/kort/tables.py:49
 msgid "Printer location"
 msgstr "Druckerort"
 
-#: aleksis/apps/kort/tables.py:59
+#: aleksis/apps/kort/tables.py:53
 msgid "Running jobs"
 msgstr "Laufende Aufträge"
 
-#: aleksis/apps/kort/tables.py:81
+#: aleksis/apps/kort/tables.py:77
 msgid "Layout name"
 msgstr "Layoutname"
 
 #: aleksis/apps/kort/templates/kort/card/actions.html:8
-#: aleksis/apps/kort/templates/kort/card/detail.html:9
+#: aleksis/apps/kort/templates/kort/card/detail.html:13
 #, python-format
 msgid "Card of %(person)s"
 msgstr "Karte von %(person)s"
@@ -342,6 +350,7 @@ msgstr "Deaktivieren"
 #: aleksis/apps/kort/templates/kort/printer/actions.html:33
 #: aleksis/apps/kort/templates/kort/printer/delete.html:29
 #: aleksis/apps/kort/templates/kort/printer/detail.html:31
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:22
 msgid "Delete"
 msgstr "Löschen"
 
@@ -370,9 +379,14 @@ msgstr ""
 #: aleksis/apps/kort/templates/kort/card/delete.html:26
 #: aleksis/apps/kort/templates/kort/card_layout/delete.html:25
 #: aleksis/apps/kort/templates/kort/printer/delete.html:25
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:18
 msgid "Go back"
 msgstr "Zurück"
 
+#: aleksis/apps/kort/templates/kort/card/detail.html:11
+msgid "Back"
+msgstr "Zurück"
+
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:6
 msgid "Card details"
 msgstr "Kartendetails"
@@ -389,6 +403,10 @@ msgstr "Karte als PDF anzeigen"
 msgid "Generate card as PDF"
 msgstr "Karte als PDF generieren"
 
+#: aleksis/apps/kort/templates/kort/card/detail_content.html:68
+msgid "Preview card layout"
+msgstr "Kartenlayout anschauen"
+
 #: aleksis/apps/kort/templates/kort/card/edit.html:12
 #: aleksis/apps/kort/templates/kort/card/edit.html:13
 msgid "Edit card"
@@ -647,7 +665,7 @@ msgstr "3. Client einrichten"
 msgid "Print jobs"
 msgstr "Druckaufträge"
 
-#: aleksis/apps/kort/templates/kort/printer/detail_content.html:87
+#: aleksis/apps/kort/templates/kort/printer/detail_content.html:88
 msgid "Created at"
 msgstr "Erstellt am"
 
@@ -660,6 +678,14 @@ msgstr "Kartendrucker bearbeiten"
 msgid "Register new card printer"
 msgstr "Neuen Kartendrucker registrieren"
 
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:8
+msgid "Delete Card Print Job"
+msgstr "Kartendruckauftrag löschen"
+
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:12
+msgid "Do you really want to delete the following card print job?"
+msgstr "Möchten Sie wirklich den folgenden Kartendruckauftrag löschen?"
+
 #: aleksis/apps/kort/views.py:69
 msgid "The cards have been created successfully."
 msgstr "Die Karten wurden erfolgreich erstellt."
@@ -680,54 +706,57 @@ msgstr "Die Karte wurde erfolgreich gelöscht."
 msgid "The card has been deactivated successfully."
 msgstr "Die Karte wurde erfolgreich deaktiviert."
 
-#: aleksis/apps/kort/views.py:220
-msgid "The chip number is missing."
-msgstr "Die Chip-Nummer fehlt."
-
-#: aleksis/apps/kort/views.py:232
+#: aleksis/apps/kort/views.py:238
 msgid "Progress: Generate card layout as PDF file"
 msgstr "Fortschritt: Kartenlayout als PDF-Datei generieren"
 
-#: aleksis/apps/kort/views.py:233
+#: aleksis/apps/kort/views.py:239
 msgid "Generating PDF file …"
 msgstr "PDF-Datei wird generiert …"
 
-#: aleksis/apps/kort/views.py:234
+#: aleksis/apps/kort/views.py:240
 msgid "The PDF file with the card layout has been generated successfully."
 msgstr "Die PDF-Datei mit dem Kartenlayout wurde erfolgreich erstellt."
 
-#: aleksis/apps/kort/views.py:235
+#: aleksis/apps/kort/views.py:241
 msgid "There was a problem while generating the PDF file."
 msgstr "Es ist ein Fehler beim Generieren der PDF-Datei aufgetreten."
 
-#: aleksis/apps/kort/views.py:237
+#: aleksis/apps/kort/views.py:243
 msgid "Show card"
 msgstr "Karte anzeigen"
 
-#: aleksis/apps/kort/views.py:275
+#: aleksis/apps/kort/views.py:281
 msgid "The card printer has been created successfully."
 msgstr "Der Kartendrucker wurde erfolgreich erstellt."
 
-#: aleksis/apps/kort/views.py:288
+#: aleksis/apps/kort/views.py:294
 msgid "The card printer has been changed successfully."
 msgstr "Der Kartendrucker wurde erfolgreich geändert."
 
-#: aleksis/apps/kort/views.py:301
+#: aleksis/apps/kort/views.py:307
 msgid "The card printer has been deleted successfully."
 msgstr "Der Kartendrucker wurde erfolgreich gelöscht."
 
-#: aleksis/apps/kort/views.py:364
+#: aleksis/apps/kort/views.py:317
+msgid "The card print job has been deleted successfully."
+msgstr "Der Kartendruckauftrag wurde erfolgreich gelöscht."
+
+#: aleksis/apps/kort/views.py:380
 msgid "The card layout has been created successfully."
 msgstr "Das Kartenlayout wurde erfolgreich erstellt."
 
-#: aleksis/apps/kort/views.py:382
+#: aleksis/apps/kort/views.py:398
 msgid "The card layout has been changed successfully."
 msgstr "Das Kartenlayout wurde erfolgreich geändert."
 
-#: aleksis/apps/kort/views.py:395
+#: aleksis/apps/kort/views.py:411
 msgid "The card layout has been deleted successfully."
 msgstr "Das Kartenlayout wurde erfolgreich gelöscht."
 
+#~ msgid "The chip number is missing."
+#~ msgstr "Die Chip-Nummer fehlt."
+
 #~ msgid "Student ID Cards"
 #~ msgstr "Schülerausweise"
 
diff --git a/aleksis/apps/kort/locale/fr/LC_MESSAGES/django.po b/aleksis/apps/kort/locale/fr/LC_MESSAGES/django.po
index c9d5aa80caed318e89b7c676ae9ed125d0e7942c..8caf4f69b2f8e9045554203fb208bca0215e1c51 100644
--- a/aleksis/apps/kort/locale/fr/LC_MESSAGES/django.po
+++ b/aleksis/apps/kort/locale/fr/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-03-19 15:48+0100\n"
+"POT-Creation-Date: 2023-09-16 17:04+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -55,12 +55,12 @@ msgstr ""
 msgid "Groups"
 msgstr ""
 
-#: aleksis/apps/kort/forms.py:51 aleksis/apps/kort/models.py:191
+#: aleksis/apps/kort/forms.py:51 aleksis/apps/kort/models.py:209
 msgid "Card layout"
 msgstr ""
 
-#: aleksis/apps/kort/forms.py:53 aleksis/apps/kort/models.py:263
-#: aleksis/apps/kort/tables.py:30
+#: aleksis/apps/kort/forms.py:53 aleksis/apps/kort/models.py:281
+#: aleksis/apps/kort/tables.py:23
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:24
 #: aleksis/apps/kort/templates/kort/card/short.html:12
 msgid "Valid until"
@@ -82,43 +82,43 @@ msgstr ""
 msgid "Printer settings"
 msgstr ""
 
-#: aleksis/apps/kort/forms.py:138 aleksis/apps/kort/models.py:228
+#: aleksis/apps/kort/forms.py:138 aleksis/apps/kort/models.py:246
 msgid "Required data fields"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:24
+#: aleksis/apps/kort/models.py:25
 msgid "Online"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:25
+#: aleksis/apps/kort/models.py:26
 msgid "Offline"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:26
+#: aleksis/apps/kort/models.py:27
 msgid "With errors"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:27
+#: aleksis/apps/kort/models.py:28
 msgid "Not registered"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:56
+#: aleksis/apps/kort/models.py:57
 msgid "Registered"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:57
+#: aleksis/apps/kort/models.py:58
 msgid "In progress"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:58
+#: aleksis/apps/kort/models.py:59
 msgid "Finished"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:59
+#: aleksis/apps/kort/models.py:60
 msgid "Failed"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:64 aleksis/apps/kort/models.py:223
+#: aleksis/apps/kort/models.py:65 aleksis/apps/kort/models.py:241
 #: aleksis/apps/kort/templates/kort/card_layout/detail_content.html:11
 #: aleksis/apps/kort/templates/kort/card_layout/short.html:4
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:11
@@ -126,188 +126,196 @@ msgstr ""
 msgid "Name"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:65
+#: aleksis/apps/kort/models.py:66
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:24
 msgid "Description"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:66
+#: aleksis/apps/kort/models.py:67
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:17
 #: aleksis/apps/kort/templates/kort/printer/short.html:8
 msgid "Location"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:70 aleksis/apps/kort/models.py:336
-#: aleksis/apps/kort/tables.py:95
+#: aleksis/apps/kort/models.py:71 aleksis/apps/kort/models.py:354
+#: aleksis/apps/kort/tables.py:94
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:38
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:38
-#: aleksis/apps/kort/templates/kort/printer/detail_content.html:90
+#: aleksis/apps/kort/templates/kort/printer/detail_content.html:91
 #: aleksis/apps/kort/templates/kort/printer/short.html:12
 msgid "Status"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:74 aleksis/apps/kort/models.py:340
+#: aleksis/apps/kort/models.py:75 aleksis/apps/kort/models.py:358
 msgid "Status text"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:75 aleksis/apps/kort/tables.py:58
+#: aleksis/apps/kort/models.py:76 aleksis/apps/kort/tables.py:52
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:31
 msgid "Last seen at"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:80
+#: aleksis/apps/kort/models.py:81
 msgid "OAuth2 application"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:87
+#: aleksis/apps/kort/models.py:89
+msgid "OAuth2 client secret"
+msgstr ""
+
+#: aleksis/apps/kort/models.py:95
 msgid "CUPS printer"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:89
+#: aleksis/apps/kort/models.py:97
+msgid "Leave blank to deactivate CUPS printing"
+msgstr ""
+
+#: aleksis/apps/kort/models.py:100
 msgid "Generate card number on server"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:91
+#: aleksis/apps/kort/models.py:102
 msgid "Card detector"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:181
+#: aleksis/apps/kort/models.py:199
 msgid "Card printer"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:182
+#: aleksis/apps/kort/models.py:200
 #: aleksis/apps/kort/templates/kort/printer/list.html:8
 #: aleksis/apps/kort/templates/kort/printer/list.html:9
 msgid "Card printers"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:186
+#: aleksis/apps/kort/models.py:204
 msgid "Media file"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:198
+#: aleksis/apps/kort/models.py:216
 msgid "Media file for a card layout"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:199
+#: aleksis/apps/kort/models.py:217
 msgid "Media files for card layouts"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:224
+#: aleksis/apps/kort/models.py:242
 #: aleksis/apps/kort/templates/kort/card_layout/detail_content.html:43
 msgid "Template"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:225
+#: aleksis/apps/kort/models.py:243
 #: aleksis/apps/kort/templates/kort/card_layout/detail_content.html:49
 msgid "Custom CSS"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:226
+#: aleksis/apps/kort/models.py:244
 msgid "Width"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:226 aleksis/apps/kort/models.py:227
+#: aleksis/apps/kort/models.py:244 aleksis/apps/kort/models.py:245
 msgid "in mm"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:227
+#: aleksis/apps/kort/models.py:245
 msgid "Height"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:248
+#: aleksis/apps/kort/models.py:266
 msgid "Template is invalid: {}"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:254 aleksis/apps/kort/models.py:267
+#: aleksis/apps/kort/models.py:272 aleksis/apps/kort/models.py:285
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:31
 #: aleksis/apps/kort/templates/kort/card_layout/detail.html:8
 msgid "Card Layout"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:255
+#: aleksis/apps/kort/models.py:273
 msgid "Card Layouts"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:260
+#: aleksis/apps/kort/models.py:278 aleksis/apps/kort/tables.py:20
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:11
 #: aleksis/apps/kort/templates/kort/card/short.html:4
 msgid "Person"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:262
+#: aleksis/apps/kort/models.py:280
 msgid "Chip Number"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:264 aleksis/apps/kort/tables.py:31
+#: aleksis/apps/kort/models.py:282 aleksis/apps/kort/tables.py:24
 msgid "Deactivated"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:270
+#: aleksis/apps/kort/models.py:288
 msgid "PDF file"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:303
+#: aleksis/apps/kort/models.py:321
 msgid "There is no layout provided for the card."
 msgstr ""
 
-#: aleksis/apps/kort/models.py:322 aleksis/apps/kort/models.py:331
+#: aleksis/apps/kort/models.py:340 aleksis/apps/kort/models.py:349
 #: aleksis/apps/kort/templates/kort/card/detail.html:8
-#: aleksis/apps/kort/templates/kort/printer/detail_content.html:84
+#: aleksis/apps/kort/templates/kort/printer/detail_content.html:85
 msgid "Card"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:323
+#: aleksis/apps/kort/models.py:341
 #: aleksis/apps/kort/templates/kort/card/list.html:8
 #: aleksis/apps/kort/templates/kort/card/list.html:9
 msgid "Cards"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:328
+#: aleksis/apps/kort/models.py:346
 msgid "Printer"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:343
+#: aleksis/apps/kort/models.py:361
 msgid "Card print job"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:344
+#: aleksis/apps/kort/models.py:362
 msgid "Card print jobs"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:28
+#: aleksis/apps/kort/tables.py:21
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:17
 #: aleksis/apps/kort/templates/kort/card/short.html:8
 msgid "Chip number"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:29 aleksis/apps/kort/tables.py:57
+#: aleksis/apps/kort/tables.py:22 aleksis/apps/kort/tables.py:51
 msgid "Current status"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:32 aleksis/apps/kort/tables.py:61
-#: aleksis/apps/kort/tables.py:85
+#: aleksis/apps/kort/tables.py:25 aleksis/apps/kort/tables.py:55
+#: aleksis/apps/kort/tables.py:81
 msgid "Actions"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:54
+#: aleksis/apps/kort/tables.py:48
 msgid "Printer name"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:55
+#: aleksis/apps/kort/tables.py:49
 msgid "Printer location"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:59
+#: aleksis/apps/kort/tables.py:53
 msgid "Running jobs"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:81
+#: aleksis/apps/kort/tables.py:77
 msgid "Layout name"
 msgstr ""
 
 #: aleksis/apps/kort/templates/kort/card/actions.html:8
-#: aleksis/apps/kort/templates/kort/card/detail.html:9
+#: aleksis/apps/kort/templates/kort/card/detail.html:13
 #, python-format
 msgid "Card of %(person)s"
 msgstr ""
@@ -342,6 +350,7 @@ msgstr ""
 #: aleksis/apps/kort/templates/kort/printer/actions.html:33
 #: aleksis/apps/kort/templates/kort/printer/delete.html:29
 #: aleksis/apps/kort/templates/kort/printer/detail.html:31
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:22
 msgid "Delete"
 msgstr ""
 
@@ -365,9 +374,14 @@ msgstr ""
 #: aleksis/apps/kort/templates/kort/card/delete.html:26
 #: aleksis/apps/kort/templates/kort/card_layout/delete.html:25
 #: aleksis/apps/kort/templates/kort/printer/delete.html:25
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:18
 msgid "Go back"
 msgstr ""
 
+#: aleksis/apps/kort/templates/kort/card/detail.html:11
+msgid "Back"
+msgstr ""
+
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:6
 msgid "Card details"
 msgstr ""
@@ -384,6 +398,10 @@ msgstr ""
 msgid "Generate card as PDF"
 msgstr ""
 
+#: aleksis/apps/kort/templates/kort/card/detail_content.html:68
+msgid "Preview card layout"
+msgstr ""
+
 #: aleksis/apps/kort/templates/kort/card/edit.html:12
 #: aleksis/apps/kort/templates/kort/card/edit.html:13
 msgid "Edit card"
@@ -617,7 +635,7 @@ msgstr ""
 msgid "Print jobs"
 msgstr ""
 
-#: aleksis/apps/kort/templates/kort/printer/detail_content.html:87
+#: aleksis/apps/kort/templates/kort/printer/detail_content.html:88
 msgid "Created at"
 msgstr ""
 
@@ -630,6 +648,14 @@ msgstr ""
 msgid "Register new card printer"
 msgstr ""
 
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:8
+msgid "Delete Card Print Job"
+msgstr ""
+
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:12
+msgid "Do you really want to delete the following card print job?"
+msgstr ""
+
 #: aleksis/apps/kort/views.py:69
 msgid "The cards have been created successfully."
 msgstr ""
@@ -650,50 +676,50 @@ msgstr ""
 msgid "The card has been deactivated successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:220
-msgid "The chip number is missing."
-msgstr ""
-
-#: aleksis/apps/kort/views.py:232
+#: aleksis/apps/kort/views.py:238
 msgid "Progress: Generate card layout as PDF file"
 msgstr ""
 
-#: aleksis/apps/kort/views.py:233
+#: aleksis/apps/kort/views.py:239
 msgid "Generating PDF file …"
 msgstr ""
 
-#: aleksis/apps/kort/views.py:234
+#: aleksis/apps/kort/views.py:240
 msgid "The PDF file with the card layout has been generated successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:235
+#: aleksis/apps/kort/views.py:241
 msgid "There was a problem while generating the PDF file."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:237
+#: aleksis/apps/kort/views.py:243
 msgid "Show card"
 msgstr ""
 
-#: aleksis/apps/kort/views.py:275
+#: aleksis/apps/kort/views.py:281
 msgid "The card printer has been created successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:288
+#: aleksis/apps/kort/views.py:294
 msgid "The card printer has been changed successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:301
+#: aleksis/apps/kort/views.py:307
 msgid "The card printer has been deleted successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:364
+#: aleksis/apps/kort/views.py:317
+msgid "The card print job has been deleted successfully."
+msgstr ""
+
+#: aleksis/apps/kort/views.py:380
 msgid "The card layout has been created successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:382
+#: aleksis/apps/kort/views.py:398
 msgid "The card layout has been changed successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:395
+#: aleksis/apps/kort/views.py:411
 msgid "The card layout has been deleted successfully."
 msgstr ""
diff --git a/aleksis/apps/kort/locale/la/LC_MESSAGES/django.po b/aleksis/apps/kort/locale/la/LC_MESSAGES/django.po
index b5cff3863512b848040abb8a51a1ce6415629548..0b716c83252bfa3aa7c9327efb9c781eb8d1ee6a 100644
--- a/aleksis/apps/kort/locale/la/LC_MESSAGES/django.po
+++ b/aleksis/apps/kort/locale/la/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-03-19 15:48+0100\n"
+"POT-Creation-Date: 2023-09-16 17:04+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -54,12 +54,12 @@ msgstr ""
 msgid "Groups"
 msgstr ""
 
-#: aleksis/apps/kort/forms.py:51 aleksis/apps/kort/models.py:191
+#: aleksis/apps/kort/forms.py:51 aleksis/apps/kort/models.py:209
 msgid "Card layout"
 msgstr ""
 
-#: aleksis/apps/kort/forms.py:53 aleksis/apps/kort/models.py:263
-#: aleksis/apps/kort/tables.py:30
+#: aleksis/apps/kort/forms.py:53 aleksis/apps/kort/models.py:281
+#: aleksis/apps/kort/tables.py:23
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:24
 #: aleksis/apps/kort/templates/kort/card/short.html:12
 msgid "Valid until"
@@ -81,43 +81,43 @@ msgstr ""
 msgid "Printer settings"
 msgstr ""
 
-#: aleksis/apps/kort/forms.py:138 aleksis/apps/kort/models.py:228
+#: aleksis/apps/kort/forms.py:138 aleksis/apps/kort/models.py:246
 msgid "Required data fields"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:24
+#: aleksis/apps/kort/models.py:25
 msgid "Online"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:25
+#: aleksis/apps/kort/models.py:26
 msgid "Offline"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:26
+#: aleksis/apps/kort/models.py:27
 msgid "With errors"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:27
+#: aleksis/apps/kort/models.py:28
 msgid "Not registered"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:56
+#: aleksis/apps/kort/models.py:57
 msgid "Registered"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:57
+#: aleksis/apps/kort/models.py:58
 msgid "In progress"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:58
+#: aleksis/apps/kort/models.py:59
 msgid "Finished"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:59
+#: aleksis/apps/kort/models.py:60
 msgid "Failed"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:64 aleksis/apps/kort/models.py:223
+#: aleksis/apps/kort/models.py:65 aleksis/apps/kort/models.py:241
 #: aleksis/apps/kort/templates/kort/card_layout/detail_content.html:11
 #: aleksis/apps/kort/templates/kort/card_layout/short.html:4
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:11
@@ -125,188 +125,196 @@ msgstr ""
 msgid "Name"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:65
+#: aleksis/apps/kort/models.py:66
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:24
 msgid "Description"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:66
+#: aleksis/apps/kort/models.py:67
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:17
 #: aleksis/apps/kort/templates/kort/printer/short.html:8
 msgid "Location"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:70 aleksis/apps/kort/models.py:336
-#: aleksis/apps/kort/tables.py:95
+#: aleksis/apps/kort/models.py:71 aleksis/apps/kort/models.py:354
+#: aleksis/apps/kort/tables.py:94
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:38
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:38
-#: aleksis/apps/kort/templates/kort/printer/detail_content.html:90
+#: aleksis/apps/kort/templates/kort/printer/detail_content.html:91
 #: aleksis/apps/kort/templates/kort/printer/short.html:12
 msgid "Status"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:74 aleksis/apps/kort/models.py:340
+#: aleksis/apps/kort/models.py:75 aleksis/apps/kort/models.py:358
 msgid "Status text"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:75 aleksis/apps/kort/tables.py:58
+#: aleksis/apps/kort/models.py:76 aleksis/apps/kort/tables.py:52
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:31
 msgid "Last seen at"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:80
+#: aleksis/apps/kort/models.py:81
 msgid "OAuth2 application"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:87
+#: aleksis/apps/kort/models.py:89
+msgid "OAuth2 client secret"
+msgstr ""
+
+#: aleksis/apps/kort/models.py:95
 msgid "CUPS printer"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:89
+#: aleksis/apps/kort/models.py:97
+msgid "Leave blank to deactivate CUPS printing"
+msgstr ""
+
+#: aleksis/apps/kort/models.py:100
 msgid "Generate card number on server"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:91
+#: aleksis/apps/kort/models.py:102
 msgid "Card detector"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:181
+#: aleksis/apps/kort/models.py:199
 msgid "Card printer"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:182
+#: aleksis/apps/kort/models.py:200
 #: aleksis/apps/kort/templates/kort/printer/list.html:8
 #: aleksis/apps/kort/templates/kort/printer/list.html:9
 msgid "Card printers"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:186
+#: aleksis/apps/kort/models.py:204
 msgid "Media file"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:198
+#: aleksis/apps/kort/models.py:216
 msgid "Media file for a card layout"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:199
+#: aleksis/apps/kort/models.py:217
 msgid "Media files for card layouts"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:224
+#: aleksis/apps/kort/models.py:242
 #: aleksis/apps/kort/templates/kort/card_layout/detail_content.html:43
 msgid "Template"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:225
+#: aleksis/apps/kort/models.py:243
 #: aleksis/apps/kort/templates/kort/card_layout/detail_content.html:49
 msgid "Custom CSS"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:226
+#: aleksis/apps/kort/models.py:244
 msgid "Width"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:226 aleksis/apps/kort/models.py:227
+#: aleksis/apps/kort/models.py:244 aleksis/apps/kort/models.py:245
 msgid "in mm"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:227
+#: aleksis/apps/kort/models.py:245
 msgid "Height"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:248
+#: aleksis/apps/kort/models.py:266
 msgid "Template is invalid: {}"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:254 aleksis/apps/kort/models.py:267
+#: aleksis/apps/kort/models.py:272 aleksis/apps/kort/models.py:285
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:31
 #: aleksis/apps/kort/templates/kort/card_layout/detail.html:8
 msgid "Card Layout"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:255
+#: aleksis/apps/kort/models.py:273
 msgid "Card Layouts"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:260
+#: aleksis/apps/kort/models.py:278 aleksis/apps/kort/tables.py:20
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:11
 #: aleksis/apps/kort/templates/kort/card/short.html:4
 msgid "Person"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:262
+#: aleksis/apps/kort/models.py:280
 msgid "Chip Number"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:264 aleksis/apps/kort/tables.py:31
+#: aleksis/apps/kort/models.py:282 aleksis/apps/kort/tables.py:24
 msgid "Deactivated"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:270
+#: aleksis/apps/kort/models.py:288
 msgid "PDF file"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:303
+#: aleksis/apps/kort/models.py:321
 msgid "There is no layout provided for the card."
 msgstr ""
 
-#: aleksis/apps/kort/models.py:322 aleksis/apps/kort/models.py:331
+#: aleksis/apps/kort/models.py:340 aleksis/apps/kort/models.py:349
 #: aleksis/apps/kort/templates/kort/card/detail.html:8
-#: aleksis/apps/kort/templates/kort/printer/detail_content.html:84
+#: aleksis/apps/kort/templates/kort/printer/detail_content.html:85
 msgid "Card"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:323
+#: aleksis/apps/kort/models.py:341
 #: aleksis/apps/kort/templates/kort/card/list.html:8
 #: aleksis/apps/kort/templates/kort/card/list.html:9
 msgid "Cards"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:328
+#: aleksis/apps/kort/models.py:346
 msgid "Printer"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:343
+#: aleksis/apps/kort/models.py:361
 msgid "Card print job"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:344
+#: aleksis/apps/kort/models.py:362
 msgid "Card print jobs"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:28
+#: aleksis/apps/kort/tables.py:21
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:17
 #: aleksis/apps/kort/templates/kort/card/short.html:8
 msgid "Chip number"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:29 aleksis/apps/kort/tables.py:57
+#: aleksis/apps/kort/tables.py:22 aleksis/apps/kort/tables.py:51
 msgid "Current status"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:32 aleksis/apps/kort/tables.py:61
-#: aleksis/apps/kort/tables.py:85
+#: aleksis/apps/kort/tables.py:25 aleksis/apps/kort/tables.py:55
+#: aleksis/apps/kort/tables.py:81
 msgid "Actions"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:54
+#: aleksis/apps/kort/tables.py:48
 msgid "Printer name"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:55
+#: aleksis/apps/kort/tables.py:49
 msgid "Printer location"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:59
+#: aleksis/apps/kort/tables.py:53
 msgid "Running jobs"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:81
+#: aleksis/apps/kort/tables.py:77
 msgid "Layout name"
 msgstr ""
 
 #: aleksis/apps/kort/templates/kort/card/actions.html:8
-#: aleksis/apps/kort/templates/kort/card/detail.html:9
+#: aleksis/apps/kort/templates/kort/card/detail.html:13
 #, python-format
 msgid "Card of %(person)s"
 msgstr ""
@@ -341,6 +349,7 @@ msgstr ""
 #: aleksis/apps/kort/templates/kort/printer/actions.html:33
 #: aleksis/apps/kort/templates/kort/printer/delete.html:29
 #: aleksis/apps/kort/templates/kort/printer/detail.html:31
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:22
 msgid "Delete"
 msgstr ""
 
@@ -364,9 +373,14 @@ msgstr ""
 #: aleksis/apps/kort/templates/kort/card/delete.html:26
 #: aleksis/apps/kort/templates/kort/card_layout/delete.html:25
 #: aleksis/apps/kort/templates/kort/printer/delete.html:25
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:18
 msgid "Go back"
 msgstr ""
 
+#: aleksis/apps/kort/templates/kort/card/detail.html:11
+msgid "Back"
+msgstr ""
+
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:6
 msgid "Card details"
 msgstr ""
@@ -383,6 +397,10 @@ msgstr ""
 msgid "Generate card as PDF"
 msgstr ""
 
+#: aleksis/apps/kort/templates/kort/card/detail_content.html:68
+msgid "Preview card layout"
+msgstr ""
+
 #: aleksis/apps/kort/templates/kort/card/edit.html:12
 #: aleksis/apps/kort/templates/kort/card/edit.html:13
 msgid "Edit card"
@@ -616,7 +634,7 @@ msgstr ""
 msgid "Print jobs"
 msgstr ""
 
-#: aleksis/apps/kort/templates/kort/printer/detail_content.html:87
+#: aleksis/apps/kort/templates/kort/printer/detail_content.html:88
 msgid "Created at"
 msgstr ""
 
@@ -629,6 +647,14 @@ msgstr ""
 msgid "Register new card printer"
 msgstr ""
 
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:8
+msgid "Delete Card Print Job"
+msgstr ""
+
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:12
+msgid "Do you really want to delete the following card print job?"
+msgstr ""
+
 #: aleksis/apps/kort/views.py:69
 msgid "The cards have been created successfully."
 msgstr ""
@@ -649,50 +675,50 @@ msgstr ""
 msgid "The card has been deactivated successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:220
-msgid "The chip number is missing."
-msgstr ""
-
-#: aleksis/apps/kort/views.py:232
+#: aleksis/apps/kort/views.py:238
 msgid "Progress: Generate card layout as PDF file"
 msgstr ""
 
-#: aleksis/apps/kort/views.py:233
+#: aleksis/apps/kort/views.py:239
 msgid "Generating PDF file …"
 msgstr ""
 
-#: aleksis/apps/kort/views.py:234
+#: aleksis/apps/kort/views.py:240
 msgid "The PDF file with the card layout has been generated successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:235
+#: aleksis/apps/kort/views.py:241
 msgid "There was a problem while generating the PDF file."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:237
+#: aleksis/apps/kort/views.py:243
 msgid "Show card"
 msgstr ""
 
-#: aleksis/apps/kort/views.py:275
+#: aleksis/apps/kort/views.py:281
 msgid "The card printer has been created successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:288
+#: aleksis/apps/kort/views.py:294
 msgid "The card printer has been changed successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:301
+#: aleksis/apps/kort/views.py:307
 msgid "The card printer has been deleted successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:364
+#: aleksis/apps/kort/views.py:317
+msgid "The card print job has been deleted successfully."
+msgstr ""
+
+#: aleksis/apps/kort/views.py:380
 msgid "The card layout has been created successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:382
+#: aleksis/apps/kort/views.py:398
 msgid "The card layout has been changed successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:395
+#: aleksis/apps/kort/views.py:411
 msgid "The card layout has been deleted successfully."
 msgstr ""
diff --git a/aleksis/apps/kort/locale/nb_NO/LC_MESSAGES/django.po b/aleksis/apps/kort/locale/nb_NO/LC_MESSAGES/django.po
index b5cff3863512b848040abb8a51a1ce6415629548..0b716c83252bfa3aa7c9327efb9c781eb8d1ee6a 100644
--- a/aleksis/apps/kort/locale/nb_NO/LC_MESSAGES/django.po
+++ b/aleksis/apps/kort/locale/nb_NO/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-03-19 15:48+0100\n"
+"POT-Creation-Date: 2023-09-16 17:04+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -54,12 +54,12 @@ msgstr ""
 msgid "Groups"
 msgstr ""
 
-#: aleksis/apps/kort/forms.py:51 aleksis/apps/kort/models.py:191
+#: aleksis/apps/kort/forms.py:51 aleksis/apps/kort/models.py:209
 msgid "Card layout"
 msgstr ""
 
-#: aleksis/apps/kort/forms.py:53 aleksis/apps/kort/models.py:263
-#: aleksis/apps/kort/tables.py:30
+#: aleksis/apps/kort/forms.py:53 aleksis/apps/kort/models.py:281
+#: aleksis/apps/kort/tables.py:23
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:24
 #: aleksis/apps/kort/templates/kort/card/short.html:12
 msgid "Valid until"
@@ -81,43 +81,43 @@ msgstr ""
 msgid "Printer settings"
 msgstr ""
 
-#: aleksis/apps/kort/forms.py:138 aleksis/apps/kort/models.py:228
+#: aleksis/apps/kort/forms.py:138 aleksis/apps/kort/models.py:246
 msgid "Required data fields"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:24
+#: aleksis/apps/kort/models.py:25
 msgid "Online"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:25
+#: aleksis/apps/kort/models.py:26
 msgid "Offline"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:26
+#: aleksis/apps/kort/models.py:27
 msgid "With errors"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:27
+#: aleksis/apps/kort/models.py:28
 msgid "Not registered"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:56
+#: aleksis/apps/kort/models.py:57
 msgid "Registered"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:57
+#: aleksis/apps/kort/models.py:58
 msgid "In progress"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:58
+#: aleksis/apps/kort/models.py:59
 msgid "Finished"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:59
+#: aleksis/apps/kort/models.py:60
 msgid "Failed"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:64 aleksis/apps/kort/models.py:223
+#: aleksis/apps/kort/models.py:65 aleksis/apps/kort/models.py:241
 #: aleksis/apps/kort/templates/kort/card_layout/detail_content.html:11
 #: aleksis/apps/kort/templates/kort/card_layout/short.html:4
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:11
@@ -125,188 +125,196 @@ msgstr ""
 msgid "Name"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:65
+#: aleksis/apps/kort/models.py:66
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:24
 msgid "Description"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:66
+#: aleksis/apps/kort/models.py:67
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:17
 #: aleksis/apps/kort/templates/kort/printer/short.html:8
 msgid "Location"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:70 aleksis/apps/kort/models.py:336
-#: aleksis/apps/kort/tables.py:95
+#: aleksis/apps/kort/models.py:71 aleksis/apps/kort/models.py:354
+#: aleksis/apps/kort/tables.py:94
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:38
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:38
-#: aleksis/apps/kort/templates/kort/printer/detail_content.html:90
+#: aleksis/apps/kort/templates/kort/printer/detail_content.html:91
 #: aleksis/apps/kort/templates/kort/printer/short.html:12
 msgid "Status"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:74 aleksis/apps/kort/models.py:340
+#: aleksis/apps/kort/models.py:75 aleksis/apps/kort/models.py:358
 msgid "Status text"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:75 aleksis/apps/kort/tables.py:58
+#: aleksis/apps/kort/models.py:76 aleksis/apps/kort/tables.py:52
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:31
 msgid "Last seen at"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:80
+#: aleksis/apps/kort/models.py:81
 msgid "OAuth2 application"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:87
+#: aleksis/apps/kort/models.py:89
+msgid "OAuth2 client secret"
+msgstr ""
+
+#: aleksis/apps/kort/models.py:95
 msgid "CUPS printer"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:89
+#: aleksis/apps/kort/models.py:97
+msgid "Leave blank to deactivate CUPS printing"
+msgstr ""
+
+#: aleksis/apps/kort/models.py:100
 msgid "Generate card number on server"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:91
+#: aleksis/apps/kort/models.py:102
 msgid "Card detector"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:181
+#: aleksis/apps/kort/models.py:199
 msgid "Card printer"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:182
+#: aleksis/apps/kort/models.py:200
 #: aleksis/apps/kort/templates/kort/printer/list.html:8
 #: aleksis/apps/kort/templates/kort/printer/list.html:9
 msgid "Card printers"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:186
+#: aleksis/apps/kort/models.py:204
 msgid "Media file"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:198
+#: aleksis/apps/kort/models.py:216
 msgid "Media file for a card layout"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:199
+#: aleksis/apps/kort/models.py:217
 msgid "Media files for card layouts"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:224
+#: aleksis/apps/kort/models.py:242
 #: aleksis/apps/kort/templates/kort/card_layout/detail_content.html:43
 msgid "Template"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:225
+#: aleksis/apps/kort/models.py:243
 #: aleksis/apps/kort/templates/kort/card_layout/detail_content.html:49
 msgid "Custom CSS"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:226
+#: aleksis/apps/kort/models.py:244
 msgid "Width"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:226 aleksis/apps/kort/models.py:227
+#: aleksis/apps/kort/models.py:244 aleksis/apps/kort/models.py:245
 msgid "in mm"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:227
+#: aleksis/apps/kort/models.py:245
 msgid "Height"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:248
+#: aleksis/apps/kort/models.py:266
 msgid "Template is invalid: {}"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:254 aleksis/apps/kort/models.py:267
+#: aleksis/apps/kort/models.py:272 aleksis/apps/kort/models.py:285
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:31
 #: aleksis/apps/kort/templates/kort/card_layout/detail.html:8
 msgid "Card Layout"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:255
+#: aleksis/apps/kort/models.py:273
 msgid "Card Layouts"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:260
+#: aleksis/apps/kort/models.py:278 aleksis/apps/kort/tables.py:20
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:11
 #: aleksis/apps/kort/templates/kort/card/short.html:4
 msgid "Person"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:262
+#: aleksis/apps/kort/models.py:280
 msgid "Chip Number"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:264 aleksis/apps/kort/tables.py:31
+#: aleksis/apps/kort/models.py:282 aleksis/apps/kort/tables.py:24
 msgid "Deactivated"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:270
+#: aleksis/apps/kort/models.py:288
 msgid "PDF file"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:303
+#: aleksis/apps/kort/models.py:321
 msgid "There is no layout provided for the card."
 msgstr ""
 
-#: aleksis/apps/kort/models.py:322 aleksis/apps/kort/models.py:331
+#: aleksis/apps/kort/models.py:340 aleksis/apps/kort/models.py:349
 #: aleksis/apps/kort/templates/kort/card/detail.html:8
-#: aleksis/apps/kort/templates/kort/printer/detail_content.html:84
+#: aleksis/apps/kort/templates/kort/printer/detail_content.html:85
 msgid "Card"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:323
+#: aleksis/apps/kort/models.py:341
 #: aleksis/apps/kort/templates/kort/card/list.html:8
 #: aleksis/apps/kort/templates/kort/card/list.html:9
 msgid "Cards"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:328
+#: aleksis/apps/kort/models.py:346
 msgid "Printer"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:343
+#: aleksis/apps/kort/models.py:361
 msgid "Card print job"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:344
+#: aleksis/apps/kort/models.py:362
 msgid "Card print jobs"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:28
+#: aleksis/apps/kort/tables.py:21
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:17
 #: aleksis/apps/kort/templates/kort/card/short.html:8
 msgid "Chip number"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:29 aleksis/apps/kort/tables.py:57
+#: aleksis/apps/kort/tables.py:22 aleksis/apps/kort/tables.py:51
 msgid "Current status"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:32 aleksis/apps/kort/tables.py:61
-#: aleksis/apps/kort/tables.py:85
+#: aleksis/apps/kort/tables.py:25 aleksis/apps/kort/tables.py:55
+#: aleksis/apps/kort/tables.py:81
 msgid "Actions"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:54
+#: aleksis/apps/kort/tables.py:48
 msgid "Printer name"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:55
+#: aleksis/apps/kort/tables.py:49
 msgid "Printer location"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:59
+#: aleksis/apps/kort/tables.py:53
 msgid "Running jobs"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:81
+#: aleksis/apps/kort/tables.py:77
 msgid "Layout name"
 msgstr ""
 
 #: aleksis/apps/kort/templates/kort/card/actions.html:8
-#: aleksis/apps/kort/templates/kort/card/detail.html:9
+#: aleksis/apps/kort/templates/kort/card/detail.html:13
 #, python-format
 msgid "Card of %(person)s"
 msgstr ""
@@ -341,6 +349,7 @@ msgstr ""
 #: aleksis/apps/kort/templates/kort/printer/actions.html:33
 #: aleksis/apps/kort/templates/kort/printer/delete.html:29
 #: aleksis/apps/kort/templates/kort/printer/detail.html:31
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:22
 msgid "Delete"
 msgstr ""
 
@@ -364,9 +373,14 @@ msgstr ""
 #: aleksis/apps/kort/templates/kort/card/delete.html:26
 #: aleksis/apps/kort/templates/kort/card_layout/delete.html:25
 #: aleksis/apps/kort/templates/kort/printer/delete.html:25
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:18
 msgid "Go back"
 msgstr ""
 
+#: aleksis/apps/kort/templates/kort/card/detail.html:11
+msgid "Back"
+msgstr ""
+
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:6
 msgid "Card details"
 msgstr ""
@@ -383,6 +397,10 @@ msgstr ""
 msgid "Generate card as PDF"
 msgstr ""
 
+#: aleksis/apps/kort/templates/kort/card/detail_content.html:68
+msgid "Preview card layout"
+msgstr ""
+
 #: aleksis/apps/kort/templates/kort/card/edit.html:12
 #: aleksis/apps/kort/templates/kort/card/edit.html:13
 msgid "Edit card"
@@ -616,7 +634,7 @@ msgstr ""
 msgid "Print jobs"
 msgstr ""
 
-#: aleksis/apps/kort/templates/kort/printer/detail_content.html:87
+#: aleksis/apps/kort/templates/kort/printer/detail_content.html:88
 msgid "Created at"
 msgstr ""
 
@@ -629,6 +647,14 @@ msgstr ""
 msgid "Register new card printer"
 msgstr ""
 
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:8
+msgid "Delete Card Print Job"
+msgstr ""
+
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:12
+msgid "Do you really want to delete the following card print job?"
+msgstr ""
+
 #: aleksis/apps/kort/views.py:69
 msgid "The cards have been created successfully."
 msgstr ""
@@ -649,50 +675,50 @@ msgstr ""
 msgid "The card has been deactivated successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:220
-msgid "The chip number is missing."
-msgstr ""
-
-#: aleksis/apps/kort/views.py:232
+#: aleksis/apps/kort/views.py:238
 msgid "Progress: Generate card layout as PDF file"
 msgstr ""
 
-#: aleksis/apps/kort/views.py:233
+#: aleksis/apps/kort/views.py:239
 msgid "Generating PDF file …"
 msgstr ""
 
-#: aleksis/apps/kort/views.py:234
+#: aleksis/apps/kort/views.py:240
 msgid "The PDF file with the card layout has been generated successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:235
+#: aleksis/apps/kort/views.py:241
 msgid "There was a problem while generating the PDF file."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:237
+#: aleksis/apps/kort/views.py:243
 msgid "Show card"
 msgstr ""
 
-#: aleksis/apps/kort/views.py:275
+#: aleksis/apps/kort/views.py:281
 msgid "The card printer has been created successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:288
+#: aleksis/apps/kort/views.py:294
 msgid "The card printer has been changed successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:301
+#: aleksis/apps/kort/views.py:307
 msgid "The card printer has been deleted successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:364
+#: aleksis/apps/kort/views.py:317
+msgid "The card print job has been deleted successfully."
+msgstr ""
+
+#: aleksis/apps/kort/views.py:380
 msgid "The card layout has been created successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:382
+#: aleksis/apps/kort/views.py:398
 msgid "The card layout has been changed successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:395
+#: aleksis/apps/kort/views.py:411
 msgid "The card layout has been deleted successfully."
 msgstr ""
diff --git a/aleksis/apps/kort/locale/ru/LC_MESSAGES/django.po b/aleksis/apps/kort/locale/ru/LC_MESSAGES/django.po
index 194ff336e1e86e21c8802f07896463d148f92cd6..b85bd6e55d9046bfaca3588d17459afd209ec662 100644
--- a/aleksis/apps/kort/locale/ru/LC_MESSAGES/django.po
+++ b/aleksis/apps/kort/locale/ru/LC_MESSAGES/django.po
@@ -7,45 +7,48 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-03-19 15:48+0100\n"
+"POT-Creation-Date: 2023-09-16 17:04+0200\n"
 "PO-Revision-Date: 2023-05-26 04:37+0000\n"
 "Last-Translator: Serhii Horichenko <m@sgg.im>\n"
-"Language-Team: Russian <https://translate.edugit.org/projects/aleksis/aleksis-app-kort/ru/>\n"
+"Language-Team: Russian <https://translate.edugit.org/projects/aleksis/"
+"aleksis-app-kort/ru/>\n"
 "Language: ru\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n"
+"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
+"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n"
+"%100>=11 && n%100<=14)? 2 : 3);\n"
 "X-Generator: Weblate 4.12.1\n"
 
 #: aleksis/apps/kort/apps.py:31
 msgid "Access and manage printer status and print jobs"
-msgstr ""
+msgstr "Управление доступом к принтеру, его состоянием и заданиями печати"
 
 #: aleksis/apps/kort/forms.py:15
 msgid "Select person(s) or group(s)"
-msgstr ""
+msgstr "Выберите людей и группы"
 
 #: aleksis/apps/kort/forms.py:16
 msgid "Select validity"
-msgstr ""
+msgstr "Выберите срок действия"
 
 #: aleksis/apps/kort/forms.py:17
 msgid "Select layout"
-msgstr ""
+msgstr "Выберите шаблон"
 
 #: aleksis/apps/kort/forms.py:18
 msgid "Select printer (optional)"
-msgstr ""
+msgstr "Выберите принтер (необязательно)"
 
 #: aleksis/apps/kort/forms.py:22 aleksis/apps/kort/forms.py:111
 #: aleksis/apps/kort/templates/kort/printer/detail.html:8
 msgid "Card Printer"
-msgstr ""
+msgstr "Карточный принтер"
 
 #: aleksis/apps/kort/forms.py:23
 msgid "Select a printer to directly print the newly issued card."
-msgstr ""
+msgstr "Выберите принтер для непосредственной печати свежесозданных карт."
 
 #: aleksis/apps/kort/forms.py:28
 msgid "Persons"
@@ -57,267 +60,284 @@ msgstr "Группы"
 
 #: aleksis/apps/kort/forms.py:51 aleksis/apps/kort/models.py:191
 msgid "Card layout"
-msgstr ""
+msgstr "Шаблон карты"
 
-#: aleksis/apps/kort/forms.py:53 aleksis/apps/kort/models.py:263
-#: aleksis/apps/kort/tables.py:30
+#: aleksis/apps/kort/forms.py:53 aleksis/apps/kort/models.py:281
+#: aleksis/apps/kort/tables.py:23
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:24
 #: aleksis/apps/kort/templates/kort/card/short.html:12
+#: aleksis/apps/kort/models.py:263 aleksis/apps/kort/tables.py:30
 msgid "Valid until"
 msgstr "Действует до"
 
 #: aleksis/apps/kort/forms.py:63
 msgid "You must select at least one person or group."
-msgstr ""
+msgstr "Вам необходимо выбрать хотя бы одного человека или группу."
 
 #: aleksis/apps/kort/forms.py:71
 msgid "The selected groups don't have any members."
-msgstr ""
+msgstr "Выбранные группы не содержат ни одного участника."
 
 #: aleksis/apps/kort/forms.py:91
 msgid "Generic attributes"
-msgstr ""
+msgstr "Основные атрибуты"
 
 #: aleksis/apps/kort/forms.py:93
 msgid "Printer settings"
-msgstr ""
+msgstr "Настройки принтера"
 
 #: aleksis/apps/kort/forms.py:138 aleksis/apps/kort/models.py:228
 msgid "Required data fields"
-msgstr ""
+msgstr "Необходимые поля данных"
 
 #: aleksis/apps/kort/models.py:24
 msgid "Online"
-msgstr ""
+msgstr "Онлайн"
 
 #: aleksis/apps/kort/models.py:25
 msgid "Offline"
-msgstr ""
+msgstr "Офлайн"
 
 #: aleksis/apps/kort/models.py:26
 msgid "With errors"
-msgstr ""
+msgstr "С ошибками"
 
 #: aleksis/apps/kort/models.py:27
 msgid "Not registered"
-msgstr ""
+msgstr "Не зарегистрировано"
 
 #: aleksis/apps/kort/models.py:56
 msgid "Registered"
-msgstr ""
+msgstr "Зарегистрировано"
 
 #: aleksis/apps/kort/models.py:57
 msgid "In progress"
-msgstr ""
+msgstr "В процессе"
 
 #: aleksis/apps/kort/models.py:58
 msgid "Finished"
-msgstr ""
+msgstr "Завершено"
 
 #: aleksis/apps/kort/models.py:59
 msgid "Failed"
-msgstr ""
+msgstr "Сбой"
 
-#: aleksis/apps/kort/models.py:64 aleksis/apps/kort/models.py:223
+#: aleksis/apps/kort/models.py:65 aleksis/apps/kort/models.py:241
 #: aleksis/apps/kort/templates/kort/card_layout/detail_content.html:11
 #: aleksis/apps/kort/templates/kort/card_layout/short.html:4
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:11
 #: aleksis/apps/kort/templates/kort/printer/short.html:4
+#: aleksis/apps/kort/models.py:64 aleksis/apps/kort/models.py:223
 msgid "Name"
 msgstr "Полное имя"
 
-#: aleksis/apps/kort/models.py:65
+#: aleksis/apps/kort/models.py:66
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:24
+#: aleksis/apps/kort/models.py:65
 msgid "Description"
 msgstr "Описание"
 
-#: aleksis/apps/kort/models.py:66
+#: aleksis/apps/kort/models.py:67
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:17
 #: aleksis/apps/kort/templates/kort/printer/short.html:8
+#: aleksis/apps/kort/models.py:66
 msgid "Location"
 msgstr "Нас.пункт"
 
-#: aleksis/apps/kort/models.py:70 aleksis/apps/kort/models.py:336
-#: aleksis/apps/kort/tables.py:95
+#: aleksis/apps/kort/models.py:71 aleksis/apps/kort/models.py:354
+#: aleksis/apps/kort/tables.py:94
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:38
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:38
-#: aleksis/apps/kort/templates/kort/printer/detail_content.html:90
+#: aleksis/apps/kort/templates/kort/printer/detail_content.html:91
 #: aleksis/apps/kort/templates/kort/printer/short.html:12
+#: aleksis/apps/kort/models.py:70 aleksis/apps/kort/models.py:336
+#: aleksis/apps/kort/tables.py:95
+#: aleksis/apps/kort/templates/kort/printer/detail_content.html:90
 msgid "Status"
 msgstr "Состояние"
 
 #: aleksis/apps/kort/models.py:74 aleksis/apps/kort/models.py:340
 msgid "Status text"
-msgstr ""
+msgstr "Описание состояния"
 
 #: aleksis/apps/kort/models.py:75 aleksis/apps/kort/tables.py:58
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:31
 msgid "Last seen at"
-msgstr ""
+msgstr "Последний раз на связи"
 
 #: aleksis/apps/kort/models.py:80
 msgid "OAuth2 application"
+msgstr "Программа для OAuth2"
+
+#: aleksis/apps/kort/models.py:89
+msgid "OAuth2 client secret"
 msgstr ""
 
 #: aleksis/apps/kort/models.py:87
 msgid "CUPS printer"
+msgstr "Принтер CUPS"
+
+#: aleksis/apps/kort/models.py:97
+msgid "Leave blank to deactivate CUPS printing"
 msgstr ""
 
 #: aleksis/apps/kort/models.py:89
 msgid "Generate card number on server"
-msgstr ""
+msgstr "Генерировать номер карты на сервере"
 
 #: aleksis/apps/kort/models.py:91
 msgid "Card detector"
-msgstr ""
+msgstr "Детектор карт"
 
 #: aleksis/apps/kort/models.py:181
 msgid "Card printer"
-msgstr ""
+msgstr "Карточный принтер"
 
 #: aleksis/apps/kort/models.py:182
 #: aleksis/apps/kort/templates/kort/printer/list.html:8
 #: aleksis/apps/kort/templates/kort/printer/list.html:9
 msgid "Card printers"
-msgstr ""
+msgstr "Карточные принтеры"
 
 #: aleksis/apps/kort/models.py:186
 msgid "Media file"
-msgstr ""
+msgstr "Медиафайл"
 
 #: aleksis/apps/kort/models.py:198
 msgid "Media file for a card layout"
-msgstr ""
+msgstr "Медиафайл для шаблона карт"
 
 #: aleksis/apps/kort/models.py:199
 msgid "Media files for card layouts"
-msgstr ""
+msgstr "Медифайлы для шаблонов карт"
 
 #: aleksis/apps/kort/models.py:224
 #: aleksis/apps/kort/templates/kort/card_layout/detail_content.html:43
 msgid "Template"
-msgstr ""
+msgstr "Шаблон"
 
 #: aleksis/apps/kort/models.py:225
 #: aleksis/apps/kort/templates/kort/card_layout/detail_content.html:49
 msgid "Custom CSS"
-msgstr ""
+msgstr "Настраиваемый CSS"
 
 #: aleksis/apps/kort/models.py:226
 msgid "Width"
-msgstr ""
+msgstr "Ширина"
 
 #: aleksis/apps/kort/models.py:226 aleksis/apps/kort/models.py:227
 msgid "in mm"
-msgstr ""
+msgstr "в мм"
 
 #: aleksis/apps/kort/models.py:227
 msgid "Height"
-msgstr ""
+msgstr "Высота"
 
 #: aleksis/apps/kort/models.py:248
 msgid "Template is invalid: {}"
-msgstr ""
+msgstr "Шаблон неправильный: {}"
 
 #: aleksis/apps/kort/models.py:254 aleksis/apps/kort/models.py:267
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:31
 #: aleksis/apps/kort/templates/kort/card_layout/detail.html:8
 msgid "Card Layout"
-msgstr ""
+msgstr "Шаблон карты"
 
 #: aleksis/apps/kort/models.py:255
 msgid "Card Layouts"
-msgstr ""
+msgstr "Шаблоны карт"
 
-#: aleksis/apps/kort/models.py:260
+#: aleksis/apps/kort/models.py:278 aleksis/apps/kort/tables.py:20
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:11
 #: aleksis/apps/kort/templates/kort/card/short.html:4
+#: aleksis/apps/kort/models.py:260
 msgid "Person"
 msgstr "Физлицо"
 
 #: aleksis/apps/kort/models.py:262
 msgid "Chip Number"
-msgstr ""
+msgstr "Номер чипа"
 
 #: aleksis/apps/kort/models.py:264 aleksis/apps/kort/tables.py:31
 msgid "Deactivated"
-msgstr ""
+msgstr "Деактивировано"
 
-#: aleksis/apps/kort/models.py:270
+#: aleksis/apps/kort/models.py:288 aleksis/apps/kort/models.py:270
 msgid "PDF file"
 msgstr "Файл PDF"
 
 #: aleksis/apps/kort/models.py:303
 msgid "There is no layout provided for the card."
-msgstr ""
+msgstr "Для карты не задан шаблон."
 
 #: aleksis/apps/kort/models.py:322 aleksis/apps/kort/models.py:331
 #: aleksis/apps/kort/templates/kort/card/detail.html:8
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:84
 msgid "Card"
-msgstr ""
+msgstr "Карта"
 
 #: aleksis/apps/kort/models.py:323
 #: aleksis/apps/kort/templates/kort/card/list.html:8
 #: aleksis/apps/kort/templates/kort/card/list.html:9
 msgid "Cards"
-msgstr ""
+msgstr "Карты"
 
 #: aleksis/apps/kort/models.py:328
 msgid "Printer"
-msgstr ""
+msgstr "Принтер"
 
 #: aleksis/apps/kort/models.py:343
 msgid "Card print job"
-msgstr ""
+msgstr "Задание на печать карты"
 
 #: aleksis/apps/kort/models.py:344
 msgid "Card print jobs"
-msgstr ""
+msgstr "Задания на печать карт"
 
 #: aleksis/apps/kort/tables.py:28
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:17
 #: aleksis/apps/kort/templates/kort/card/short.html:8
 msgid "Chip number"
-msgstr ""
+msgstr "Номер чипа"
 
 #: aleksis/apps/kort/tables.py:29 aleksis/apps/kort/tables.py:57
 msgid "Current status"
-msgstr ""
+msgstr "Текущее состояние"
 
-#: aleksis/apps/kort/tables.py:32 aleksis/apps/kort/tables.py:61
-#: aleksis/apps/kort/tables.py:85
+#: aleksis/apps/kort/tables.py:25 aleksis/apps/kort/tables.py:55
+#: aleksis/apps/kort/tables.py:81 aleksis/apps/kort/tables.py:32
+#: aleksis/apps/kort/tables.py:61 aleksis/apps/kort/tables.py:85
 msgid "Actions"
 msgstr "Действия"
 
 #: aleksis/apps/kort/tables.py:54
 msgid "Printer name"
-msgstr ""
+msgstr "Название принтера"
 
 #: aleksis/apps/kort/tables.py:55
 msgid "Printer location"
-msgstr ""
+msgstr "Размещение принтера"
 
 #: aleksis/apps/kort/tables.py:59
 msgid "Running jobs"
-msgstr ""
+msgstr "Текущие задания"
 
 #: aleksis/apps/kort/tables.py:81
 msgid "Layout name"
-msgstr ""
+msgstr "Название шаблона"
 
 #: aleksis/apps/kort/templates/kort/card/actions.html:8
 #: aleksis/apps/kort/templates/kort/card/detail.html:9
 #, python-format
 msgid "Card of %(person)s"
-msgstr ""
+msgstr "Карта для %(person)s"
 
 #: aleksis/apps/kort/templates/kort/card/actions.html:14
 #: aleksis/apps/kort/templates/kort/card/actions.html:31
 #: aleksis/apps/kort/templates/kort/card_layout/actions.html:11
 #: aleksis/apps/kort/templates/kort/printer/actions.html:11
 msgid "Close"
-msgstr ""
+msgstr "Закрыть"
 
 #: aleksis/apps/kort/templates/kort/card/actions.html:20
 #: aleksis/apps/kort/templates/kort/card_layout/actions.html:17
@@ -327,12 +347,12 @@ msgstr "Показать"
 
 #: aleksis/apps/kort/templates/kort/card/actions.html:25
 msgid "Do you really want to deactivate the following card?"
-msgstr ""
+msgstr "Вы действительно хотите деактивировать эту карту?"
 
 #: aleksis/apps/kort/templates/kort/card/actions.html:35
 #: aleksis/apps/kort/templates/kort/card/actions.html:41
 msgid "Deactivate"
-msgstr ""
+msgstr "Деактивировать"
 
 #: aleksis/apps/kort/templates/kort/card/actions.html:47
 #: aleksis/apps/kort/templates/kort/card/delete.html:30
@@ -342,86 +362,120 @@ msgstr ""
 #: aleksis/apps/kort/templates/kort/printer/actions.html:33
 #: aleksis/apps/kort/templates/kort/printer/delete.html:29
 #: aleksis/apps/kort/templates/kort/printer/detail.html:31
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:22
 msgid "Delete"
 msgstr "Удалить"
 
 #: aleksis/apps/kort/templates/kort/card/delete.html:8
 msgid "Delete Card"
-msgstr ""
+msgstr "Удалить карту"
 
 #: aleksis/apps/kort/templates/kort/card/delete.html:12
 msgid "Do you really want to delete the following card?"
-msgstr ""
+msgstr "Вы действительно хотите удалить эту карту?"
 
 #: aleksis/apps/kort/templates/kort/card/delete.html:16
 msgid ""
 "\n"
-"      Please pay attention that a deletion of a card is irreversible and should be only used to clean up misprints.\n"
-"      If you just want to make a card unusable because a student has lost his card or left the school,\n"
+"      Please pay attention that a deletion of a card is irreversible and "
+"should be only used to clean up misprints.\n"
+"      If you just want to make a card unusable because a student has lost "
+"his card or left the school,\n"
 "      please deactivate the card instead.\n"
 "    "
 msgstr ""
+"\n"
+"      Обратите, пожалуйста, своё внимание, что удаление карты необратимо и "
+"должно использоваться только удаления ошибок.\n"
+"      Если Вы хотите просто заблокировать карту для использования из-за "
+"того, что учащийся потерял свою карту или покинул школу,\n"
+"      лучше, пожалуйста, деактивируйте карту.\n"
+"    "
 
 #: aleksis/apps/kort/templates/kort/card/delete.html:26
 #: aleksis/apps/kort/templates/kort/card_layout/delete.html:25
 #: aleksis/apps/kort/templates/kort/printer/delete.html:25
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:18
 msgid "Go back"
 msgstr "Назад"
 
+#: aleksis/apps/kort/templates/kort/card/detail.html:11
+msgid "Back"
+msgstr ""
+
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:6
 msgid "Card details"
-msgstr ""
+msgstr "Данные карты"
 
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:19
 msgid "not set yet"
-msgstr ""
+msgstr "ещё не установлено"
 
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:53
 msgid "Show card as PDF"
-msgstr ""
+msgstr "Показать карту как PDF"
 
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:61
 msgid "Generate card as PDF"
+msgstr "Сгенерировать карту как PDF"
+
+#: aleksis/apps/kort/templates/kort/card/detail_content.html:68
+msgid "Preview card layout"
 msgstr ""
 
 #: aleksis/apps/kort/templates/kort/card/edit.html:12
 #: aleksis/apps/kort/templates/kort/card/edit.html:13
 msgid "Edit card"
-msgstr ""
+msgstr "Редактировать карту"
 
 #: aleksis/apps/kort/templates/kort/card/issue.html:12
 #: aleksis/apps/kort/templates/kort/card/issue.html:13
 msgid "Issue card(s)"
-msgstr ""
+msgstr "Создать карту(ы)"
 
 #: aleksis/apps/kort/templates/kort/card/issue.html:23
 msgid ""
 "\n"
-"          Please select the persons and/or the groups to whom you want to issue new cards.\n"
-"          After clicking on 'Next', you will be able to check whether the data of the persons\n"
+"          Please select the persons and/or the groups to whom you want to "
+"issue new cards.\n"
+"          After clicking on 'Next', you will be able to check whether the "
+"data of the persons\n"
 "          are complete and include everything needed for the cards.\n"
 "        "
 msgstr ""
+"\n"
+"          Выберите, пожалуйста, людей и/или группы, для которых хотите "
+"создать новые карточки.\n"
+"          После нажатия на кнопку \"Далее\" Вы сможете проверить полноту и "
+"правильность\n"
+"          данных, необходимых для карточек.\n"
+"        "
 
 #: aleksis/apps/kort/templates/kort/card/issue.html:32
 msgid ""
 "\n"
-"          In the following table you can see all selected persons and the related data needed for the cards.\n"
+"          In the following table you can see all selected persons and the "
+"related data needed for the cards.\n"
 "          Please select the persons to whom you want to issue new cards.\n"
 "        "
 msgstr ""
+"\n"
+"          В следующей таблице Вы можете увидеть всех отобранных людей и "
+"данные, необходимые для карт.\n"
+"          Выберите, пожалуйста, для кого Вы хотите выпустить карты.\n"
+"        "
 
 #: aleksis/apps/kort/templates/kort/card/issue.html:65
 msgid "Previous step"
-msgstr ""
+msgstr "Предыдущий шаг"
 
 #: aleksis/apps/kort/templates/kort/card/issue.html:71
 msgid "Issue cards for selected persons"
-msgstr ""
+msgstr "Выпустить карты для отобранных лиц"
 
 #: aleksis/apps/kort/templates/kort/card/issue.html:77
 msgid "Next step"
-msgstr ""
+msgstr "Следующий шаг"
 
 #: aleksis/apps/kort/templates/kort/card/issue.html:83
 msgid "Cancel"
@@ -429,20 +483,20 @@ msgstr "Отменить"
 
 #: aleksis/apps/kort/templates/kort/card/list.html:17
 msgid "Issue new card(s)"
-msgstr ""
+msgstr "Выпустить новую карту (новые карты)"
 
 #: aleksis/apps/kort/templates/kort/card/print_form.html:8
 #: aleksis/apps/kort/templates/kort/card/print_form.html:16
 msgid "Print card"
-msgstr ""
+msgstr "Печать карты"
 
 #: aleksis/apps/kort/templates/kort/card/status.html:3
 msgid "Valid"
-msgstr ""
+msgstr "Действует"
 
 #: aleksis/apps/kort/templates/kort/card/status.html:5
 msgid "Not valid"
-msgstr ""
+msgstr "Не действует"
 
 #: aleksis/apps/kort/templates/kort/card_layout/actions.html:26
 #: aleksis/apps/kort/templates/kort/card_layout/detail.html:24
@@ -454,246 +508,292 @@ msgstr "Редактировать"
 #: aleksis/apps/kort/templates/kort/card_layout/create.html:12
 #: aleksis/apps/kort/templates/kort/card_layout/create.html:13
 msgid "Create card layout"
-msgstr ""
+msgstr "Создать шаблон карты"
 
 #: aleksis/apps/kort/templates/kort/card_layout/create.html:23
 #: aleksis/apps/kort/templates/kort/card_layout/edit.html:23
 msgid "Media Files"
-msgstr ""
+msgstr "Медиафайлы"
 
 #: aleksis/apps/kort/templates/kort/card_layout/delete.html:8
 msgid "Delete Card Layout"
-msgstr ""
+msgstr "Удалить шаблон карты"
 
 #: aleksis/apps/kort/templates/kort/card_layout/delete.html:12
 msgid "Do you really want to delete the following card layout?"
-msgstr ""
+msgstr "Вы действительно хотите удалить этот шаблон?"
 
 #: aleksis/apps/kort/templates/kort/card_layout/delete.html:16
 msgid ""
 "\n"
-"      Please pay attention that this also will prevent the successful finishing of all active print jobs\n"
+"      Please pay attention that this also will prevent the successful "
+"finishing of all active print jobs\n"
 "      which use these template.\n"
 "    "
 msgstr ""
+"\n"
+"      Обратите, пожалуйста, внимание, что это также помешает успешному "
+"выполнению всех активных заданий печати,\n"
+"      которые используют этот шаблон.\n"
+"    "
 
 #: aleksis/apps/kort/templates/kort/card_layout/detail.html:15
 msgid "Back to all layouts"
-msgstr ""
+msgstr "Назад ко всем шаблонам"
 
 #: aleksis/apps/kort/templates/kort/card_layout/detail_content.html:6
 msgid "Layout details"
-msgstr ""
+msgstr "Данные шаблона"
 
 #: aleksis/apps/kort/templates/kort/card_layout/detail_content.html:17
 msgid "Size (w × h)"
-msgstr ""
+msgstr "Размер (Ш х В)"
 
 #: aleksis/apps/kort/templates/kort/card_layout/detail_content.html:24
 msgid "Media files"
-msgstr ""
+msgstr "Медиафайлы"
 
 #: aleksis/apps/kort/templates/kort/card_layout/detail_content.html:31
 msgid "No media files uploaded."
-msgstr ""
+msgstr "Медиафайлы не загружены."
 
 #: aleksis/apps/kort/templates/kort/card_layout/edit.html:12
 #: aleksis/apps/kort/templates/kort/card_layout/edit.html:13
 msgid "Edit card layout"
-msgstr ""
+msgstr "Редактировать шаблон карты"
 
 #: aleksis/apps/kort/templates/kort/card_layout/instructions.html:4
 msgid "Instructions on templating the card"
-msgstr ""
+msgstr "Инструкции по созданию карты"
 
 #: aleksis/apps/kort/templates/kort/card_layout/instructions.html:5
 msgid ""
 "\n"
-"      You will be able to use the following data in your individual template. The template has to been written in the\n"
+"      You will be able to use the following data in your individual "
+"template. The template has to been written in the\n"
 "      Django template language.\n"
 "    "
 msgstr ""
+"\n"
+"      Вы сможете использовать следующие данные в своём собственном шаблоне. "
+"Шаблон должен быть написан\n"
+"      на языке шаблонов Django.\n"
+"    "
 
 #: aleksis/apps/kort/templates/kort/card_layout/instructions.html:11
 msgid "The chip number as string"
-msgstr ""
+msgstr "Номер чипа — строка"
 
 #: aleksis/apps/kort/templates/kort/card_layout/instructions.html:15
-msgid "This will give you access to any attributes of the person object like name, personal data or contact data."
+msgid ""
+"This will give you access to any attributes of the person object like name, "
+"personal data or contact data."
 msgstr ""
+"Это предоставит Вам доступ ко всем данным физлица, таким как имя, личные "
+"данные или контактные данные."
 
 #: aleksis/apps/kort/templates/kort/card_layout/instructions.html:19
 msgid "The date until when the card is valid"
-msgstr ""
+msgstr "Дата, до которой действует карта"
 
 #: aleksis/apps/kort/templates/kort/card_layout/instructions.html:24
-msgid "This will give you access to the uploaded media files. Replace 0 by the number of your media file (starting with 0)."
+msgid ""
+"This will give you access to the uploaded media files. Replace 0 by the "
+"number of your media file (starting with 0)."
 msgstr ""
+"Это предоставит Вам доступ к загруженным медиафайлам. Замените 0 на номер "
+"своего файла (начиная с 0)."
 
 #: aleksis/apps/kort/templates/kort/card_layout/list.html:8
 #: aleksis/apps/kort/templates/kort/card_layout/list.html:9
 msgid "Card layouts"
-msgstr ""
+msgstr "Шаблоны карт"
 
 #: aleksis/apps/kort/templates/kort/card_layout/list.html:17
 msgid "Create new card layout"
-msgstr ""
+msgstr "Создать новый шаблон для карт"
 
 #: aleksis/apps/kort/templates/kort/person_status.html:5
 #, python-format
 msgid "%(count)s missing data fields"
-msgstr ""
+msgstr "Отсутствуют поля данных: %(count)s"
 
 #: aleksis/apps/kort/templates/kort/person_status.html:10
 msgid "Data complete"
-msgstr ""
+msgstr "Данные заполнены"
 
 #: aleksis/apps/kort/templates/kort/picture.html:4
 msgid "Person picture"
-msgstr ""
+msgstr "Личное фото"
 
 #: aleksis/apps/kort/templates/kort/printer/create.html:12
 #: aleksis/apps/kort/templates/kort/printer/create.html:13
 msgid "Create card"
-msgstr ""
+msgstr "Создать карту"
 
 #: aleksis/apps/kort/templates/kort/printer/delete.html:8
 msgid "Delete Card Printer"
-msgstr ""
+msgstr "Удалить принтер для карт"
 
 #: aleksis/apps/kort/templates/kort/printer/delete.html:12
 msgid "Do you really want to delete the following card printer?"
-msgstr ""
+msgstr "Вы действительно хотите удалить этот принтер для карт?"
 
 #: aleksis/apps/kort/templates/kort/printer/delete.html:16
 msgid ""
 "\n"
-"      Please pay attention that this also will deactivate the access for the print client and you would have to\n"
+"      Please pay attention that this also will deactivate the access for the "
+"print client and you would have to\n"
 "      reconfigure the client if you want to use it further.\n"
 "    "
 msgstr ""
+"\n"
+"      Обратите, пожалуйста, внимание на то, что это также отключит доступ "
+"клиентов печати и если позже\n"
+"      захотите их использовать, их будет необходимо перенастроить заново.\n"
+"    "
 
 #: aleksis/apps/kort/templates/kort/printer/detail.html:15
 msgid "Back to all printers"
-msgstr ""
+msgstr "Назад ко всем принтерам"
 
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:6
 msgid "Printer details"
-msgstr ""
+msgstr "Подробные сведения о принтере"
 
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:33
 msgid "never seen yet"
-msgstr ""
+msgstr "ранее не встречалось"
 
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:60
 msgid "Setup printer client"
-msgstr ""
+msgstr "Настроить клиент печати"
 
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:62
 msgid ""
 "\n"
-"              To enable printing, you have to register the print client on the device\n"
+"              To enable printing, you have to register the print client on "
+"the device\n"
 "              which the printer is connected to.\n"
 "            "
 msgstr ""
+"\n"
+"              Для активации печати, Вам необходимо зарегистрировать клиент "
+"печати\n"
+"              на устройстве, к которому подключен принтер.\n"
+"            "
 
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:67
 msgid "1. Download print client"
-msgstr ""
+msgstr "1. Скачать клиента печати"
 
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:68
 msgid "2. Download configuration file"
-msgstr ""
+msgstr "2. Скачать конфигурационный файл"
 
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:71
 msgid "Download configuration"
-msgstr ""
+msgstr "Скачать конфигурацию"
 
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:73
 msgid "3. Setup client"
-msgstr ""
+msgstr "3. Настроить клиента"
 
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:80
 msgid "Print jobs"
-msgstr ""
+msgstr "Задания печати"
 
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:87
 msgid "Created at"
-msgstr ""
+msgstr "Создано в"
 
 #: aleksis/apps/kort/templates/kort/printer/edit.html:12
 #: aleksis/apps/kort/templates/kort/printer/edit.html:13
 msgid "Edit card printer"
-msgstr ""
+msgstr "Редактировать принтер карт"
 
 #: aleksis/apps/kort/templates/kort/printer/list.html:17
 msgid "Register new card printer"
+msgstr "Зарегистрировать новый принтер для карт"
+
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:8
+msgid "Delete Card Print Job"
+msgstr ""
+
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:12
+msgid "Do you really want to delete the following card print job?"
 msgstr ""
 
 #: aleksis/apps/kort/views.py:69
 msgid "The cards have been created successfully."
-msgstr ""
+msgstr "Карты были успешно созданы."
 
 #: aleksis/apps/kort/views.py:137 aleksis/apps/kort/views.py:193
-msgid "The print job #{} for the card {} on the printer {} has been created successfully."
-msgstr ""
+msgid ""
+"The print job #{} for the card {} on the printer {} has been created "
+"successfully."
+msgstr "Задание печати #{} для карты {} на принтере {} успешно создано."
 
 #: aleksis/apps/kort/views.py:145 aleksis/apps/kort/views.py:200
 msgid "The print job couldn't be started because of the following error: {}"
-msgstr ""
+msgstr "Задание печати не запущено из-за ошибки: {}"
 
 #: aleksis/apps/kort/views.py:158
 msgid "The card has been deleted successfully."
-msgstr ""
+msgstr "Карта успешно удалена."
 
 #: aleksis/apps/kort/views.py:171
 msgid "The card has been deactivated successfully."
-msgstr ""
-
-#: aleksis/apps/kort/views.py:220
-msgid "The chip number is missing."
-msgstr ""
+msgstr "Карта успешно деактивирована."
 
 #: aleksis/apps/kort/views.py:232
 msgid "Progress: Generate card layout as PDF file"
-msgstr ""
+msgstr "Прогресс: Сохранение шаблона карты в файл PDF"
 
-#: aleksis/apps/kort/views.py:233
+#: aleksis/apps/kort/views.py:239 aleksis/apps/kort/views.py:233
 msgid "Generating PDF file …"
 msgstr "Создание файла PDF …"
 
 #: aleksis/apps/kort/views.py:234
 msgid "The PDF file with the card layout has been generated successfully."
-msgstr ""
+msgstr "Файл PDF c шаблоном карты успешно сохранен."
 
-#: aleksis/apps/kort/views.py:235
+#: aleksis/apps/kort/views.py:241 aleksis/apps/kort/views.py:235
 msgid "There was a problem while generating the PDF file."
 msgstr "Во время создания файла PDF возникла проблема."
 
 #: aleksis/apps/kort/views.py:237
 msgid "Show card"
-msgstr ""
+msgstr "Показать карту"
 
 #: aleksis/apps/kort/views.py:275
 msgid "The card printer has been created successfully."
-msgstr ""
+msgstr "Принтер для карт успешно создан."
 
 #: aleksis/apps/kort/views.py:288
 msgid "The card printer has been changed successfully."
-msgstr ""
+msgstr "Принтер для карт успешно изменён."
 
 #: aleksis/apps/kort/views.py:301
 msgid "The card printer has been deleted successfully."
+msgstr "Принтер для карт успешно удалён."
+
+#: aleksis/apps/kort/views.py:317
+msgid "The card print job has been deleted successfully."
 msgstr ""
 
 #: aleksis/apps/kort/views.py:364
 msgid "The card layout has been created successfully."
-msgstr ""
+msgstr "Шаблон карты успешно создан."
 
 #: aleksis/apps/kort/views.py:382
 msgid "The card layout has been changed successfully."
-msgstr ""
+msgstr "Шаблон карт успешно изменён."
 
 #: aleksis/apps/kort/views.py:395
 msgid "The card layout has been deleted successfully."
-msgstr ""
+msgstr "Шаблон карт успешно удалён."
+
+#: aleksis/apps/kort/views.py:220
+msgid "The chip number is missing."
+msgstr "Номер чипа отсутствует."
diff --git a/aleksis/apps/kort/locale/tr_TR/LC_MESSAGES/django.po b/aleksis/apps/kort/locale/tr_TR/LC_MESSAGES/django.po
index b5cff3863512b848040abb8a51a1ce6415629548..0b716c83252bfa3aa7c9327efb9c781eb8d1ee6a 100644
--- a/aleksis/apps/kort/locale/tr_TR/LC_MESSAGES/django.po
+++ b/aleksis/apps/kort/locale/tr_TR/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-03-19 15:48+0100\n"
+"POT-Creation-Date: 2023-09-16 17:04+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -54,12 +54,12 @@ msgstr ""
 msgid "Groups"
 msgstr ""
 
-#: aleksis/apps/kort/forms.py:51 aleksis/apps/kort/models.py:191
+#: aleksis/apps/kort/forms.py:51 aleksis/apps/kort/models.py:209
 msgid "Card layout"
 msgstr ""
 
-#: aleksis/apps/kort/forms.py:53 aleksis/apps/kort/models.py:263
-#: aleksis/apps/kort/tables.py:30
+#: aleksis/apps/kort/forms.py:53 aleksis/apps/kort/models.py:281
+#: aleksis/apps/kort/tables.py:23
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:24
 #: aleksis/apps/kort/templates/kort/card/short.html:12
 msgid "Valid until"
@@ -81,43 +81,43 @@ msgstr ""
 msgid "Printer settings"
 msgstr ""
 
-#: aleksis/apps/kort/forms.py:138 aleksis/apps/kort/models.py:228
+#: aleksis/apps/kort/forms.py:138 aleksis/apps/kort/models.py:246
 msgid "Required data fields"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:24
+#: aleksis/apps/kort/models.py:25
 msgid "Online"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:25
+#: aleksis/apps/kort/models.py:26
 msgid "Offline"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:26
+#: aleksis/apps/kort/models.py:27
 msgid "With errors"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:27
+#: aleksis/apps/kort/models.py:28
 msgid "Not registered"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:56
+#: aleksis/apps/kort/models.py:57
 msgid "Registered"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:57
+#: aleksis/apps/kort/models.py:58
 msgid "In progress"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:58
+#: aleksis/apps/kort/models.py:59
 msgid "Finished"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:59
+#: aleksis/apps/kort/models.py:60
 msgid "Failed"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:64 aleksis/apps/kort/models.py:223
+#: aleksis/apps/kort/models.py:65 aleksis/apps/kort/models.py:241
 #: aleksis/apps/kort/templates/kort/card_layout/detail_content.html:11
 #: aleksis/apps/kort/templates/kort/card_layout/short.html:4
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:11
@@ -125,188 +125,196 @@ msgstr ""
 msgid "Name"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:65
+#: aleksis/apps/kort/models.py:66
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:24
 msgid "Description"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:66
+#: aleksis/apps/kort/models.py:67
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:17
 #: aleksis/apps/kort/templates/kort/printer/short.html:8
 msgid "Location"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:70 aleksis/apps/kort/models.py:336
-#: aleksis/apps/kort/tables.py:95
+#: aleksis/apps/kort/models.py:71 aleksis/apps/kort/models.py:354
+#: aleksis/apps/kort/tables.py:94
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:38
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:38
-#: aleksis/apps/kort/templates/kort/printer/detail_content.html:90
+#: aleksis/apps/kort/templates/kort/printer/detail_content.html:91
 #: aleksis/apps/kort/templates/kort/printer/short.html:12
 msgid "Status"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:74 aleksis/apps/kort/models.py:340
+#: aleksis/apps/kort/models.py:75 aleksis/apps/kort/models.py:358
 msgid "Status text"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:75 aleksis/apps/kort/tables.py:58
+#: aleksis/apps/kort/models.py:76 aleksis/apps/kort/tables.py:52
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:31
 msgid "Last seen at"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:80
+#: aleksis/apps/kort/models.py:81
 msgid "OAuth2 application"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:87
+#: aleksis/apps/kort/models.py:89
+msgid "OAuth2 client secret"
+msgstr ""
+
+#: aleksis/apps/kort/models.py:95
 msgid "CUPS printer"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:89
+#: aleksis/apps/kort/models.py:97
+msgid "Leave blank to deactivate CUPS printing"
+msgstr ""
+
+#: aleksis/apps/kort/models.py:100
 msgid "Generate card number on server"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:91
+#: aleksis/apps/kort/models.py:102
 msgid "Card detector"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:181
+#: aleksis/apps/kort/models.py:199
 msgid "Card printer"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:182
+#: aleksis/apps/kort/models.py:200
 #: aleksis/apps/kort/templates/kort/printer/list.html:8
 #: aleksis/apps/kort/templates/kort/printer/list.html:9
 msgid "Card printers"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:186
+#: aleksis/apps/kort/models.py:204
 msgid "Media file"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:198
+#: aleksis/apps/kort/models.py:216
 msgid "Media file for a card layout"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:199
+#: aleksis/apps/kort/models.py:217
 msgid "Media files for card layouts"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:224
+#: aleksis/apps/kort/models.py:242
 #: aleksis/apps/kort/templates/kort/card_layout/detail_content.html:43
 msgid "Template"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:225
+#: aleksis/apps/kort/models.py:243
 #: aleksis/apps/kort/templates/kort/card_layout/detail_content.html:49
 msgid "Custom CSS"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:226
+#: aleksis/apps/kort/models.py:244
 msgid "Width"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:226 aleksis/apps/kort/models.py:227
+#: aleksis/apps/kort/models.py:244 aleksis/apps/kort/models.py:245
 msgid "in mm"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:227
+#: aleksis/apps/kort/models.py:245
 msgid "Height"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:248
+#: aleksis/apps/kort/models.py:266
 msgid "Template is invalid: {}"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:254 aleksis/apps/kort/models.py:267
+#: aleksis/apps/kort/models.py:272 aleksis/apps/kort/models.py:285
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:31
 #: aleksis/apps/kort/templates/kort/card_layout/detail.html:8
 msgid "Card Layout"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:255
+#: aleksis/apps/kort/models.py:273
 msgid "Card Layouts"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:260
+#: aleksis/apps/kort/models.py:278 aleksis/apps/kort/tables.py:20
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:11
 #: aleksis/apps/kort/templates/kort/card/short.html:4
 msgid "Person"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:262
+#: aleksis/apps/kort/models.py:280
 msgid "Chip Number"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:264 aleksis/apps/kort/tables.py:31
+#: aleksis/apps/kort/models.py:282 aleksis/apps/kort/tables.py:24
 msgid "Deactivated"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:270
+#: aleksis/apps/kort/models.py:288
 msgid "PDF file"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:303
+#: aleksis/apps/kort/models.py:321
 msgid "There is no layout provided for the card."
 msgstr ""
 
-#: aleksis/apps/kort/models.py:322 aleksis/apps/kort/models.py:331
+#: aleksis/apps/kort/models.py:340 aleksis/apps/kort/models.py:349
 #: aleksis/apps/kort/templates/kort/card/detail.html:8
-#: aleksis/apps/kort/templates/kort/printer/detail_content.html:84
+#: aleksis/apps/kort/templates/kort/printer/detail_content.html:85
 msgid "Card"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:323
+#: aleksis/apps/kort/models.py:341
 #: aleksis/apps/kort/templates/kort/card/list.html:8
 #: aleksis/apps/kort/templates/kort/card/list.html:9
 msgid "Cards"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:328
+#: aleksis/apps/kort/models.py:346
 msgid "Printer"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:343
+#: aleksis/apps/kort/models.py:361
 msgid "Card print job"
 msgstr ""
 
-#: aleksis/apps/kort/models.py:344
+#: aleksis/apps/kort/models.py:362
 msgid "Card print jobs"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:28
+#: aleksis/apps/kort/tables.py:21
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:17
 #: aleksis/apps/kort/templates/kort/card/short.html:8
 msgid "Chip number"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:29 aleksis/apps/kort/tables.py:57
+#: aleksis/apps/kort/tables.py:22 aleksis/apps/kort/tables.py:51
 msgid "Current status"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:32 aleksis/apps/kort/tables.py:61
-#: aleksis/apps/kort/tables.py:85
+#: aleksis/apps/kort/tables.py:25 aleksis/apps/kort/tables.py:55
+#: aleksis/apps/kort/tables.py:81
 msgid "Actions"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:54
+#: aleksis/apps/kort/tables.py:48
 msgid "Printer name"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:55
+#: aleksis/apps/kort/tables.py:49
 msgid "Printer location"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:59
+#: aleksis/apps/kort/tables.py:53
 msgid "Running jobs"
 msgstr ""
 
-#: aleksis/apps/kort/tables.py:81
+#: aleksis/apps/kort/tables.py:77
 msgid "Layout name"
 msgstr ""
 
 #: aleksis/apps/kort/templates/kort/card/actions.html:8
-#: aleksis/apps/kort/templates/kort/card/detail.html:9
+#: aleksis/apps/kort/templates/kort/card/detail.html:13
 #, python-format
 msgid "Card of %(person)s"
 msgstr ""
@@ -341,6 +349,7 @@ msgstr ""
 #: aleksis/apps/kort/templates/kort/printer/actions.html:33
 #: aleksis/apps/kort/templates/kort/printer/delete.html:29
 #: aleksis/apps/kort/templates/kort/printer/detail.html:31
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:22
 msgid "Delete"
 msgstr ""
 
@@ -364,9 +373,14 @@ msgstr ""
 #: aleksis/apps/kort/templates/kort/card/delete.html:26
 #: aleksis/apps/kort/templates/kort/card_layout/delete.html:25
 #: aleksis/apps/kort/templates/kort/printer/delete.html:25
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:18
 msgid "Go back"
 msgstr ""
 
+#: aleksis/apps/kort/templates/kort/card/detail.html:11
+msgid "Back"
+msgstr ""
+
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:6
 msgid "Card details"
 msgstr ""
@@ -383,6 +397,10 @@ msgstr ""
 msgid "Generate card as PDF"
 msgstr ""
 
+#: aleksis/apps/kort/templates/kort/card/detail_content.html:68
+msgid "Preview card layout"
+msgstr ""
+
 #: aleksis/apps/kort/templates/kort/card/edit.html:12
 #: aleksis/apps/kort/templates/kort/card/edit.html:13
 msgid "Edit card"
@@ -616,7 +634,7 @@ msgstr ""
 msgid "Print jobs"
 msgstr ""
 
-#: aleksis/apps/kort/templates/kort/printer/detail_content.html:87
+#: aleksis/apps/kort/templates/kort/printer/detail_content.html:88
 msgid "Created at"
 msgstr ""
 
@@ -629,6 +647,14 @@ msgstr ""
 msgid "Register new card printer"
 msgstr ""
 
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:8
+msgid "Delete Card Print Job"
+msgstr ""
+
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:12
+msgid "Do you really want to delete the following card print job?"
+msgstr ""
+
 #: aleksis/apps/kort/views.py:69
 msgid "The cards have been created successfully."
 msgstr ""
@@ -649,50 +675,50 @@ msgstr ""
 msgid "The card has been deactivated successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:220
-msgid "The chip number is missing."
-msgstr ""
-
-#: aleksis/apps/kort/views.py:232
+#: aleksis/apps/kort/views.py:238
 msgid "Progress: Generate card layout as PDF file"
 msgstr ""
 
-#: aleksis/apps/kort/views.py:233
+#: aleksis/apps/kort/views.py:239
 msgid "Generating PDF file …"
 msgstr ""
 
-#: aleksis/apps/kort/views.py:234
+#: aleksis/apps/kort/views.py:240
 msgid "The PDF file with the card layout has been generated successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:235
+#: aleksis/apps/kort/views.py:241
 msgid "There was a problem while generating the PDF file."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:237
+#: aleksis/apps/kort/views.py:243
 msgid "Show card"
 msgstr ""
 
-#: aleksis/apps/kort/views.py:275
+#: aleksis/apps/kort/views.py:281
 msgid "The card printer has been created successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:288
+#: aleksis/apps/kort/views.py:294
 msgid "The card printer has been changed successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:301
+#: aleksis/apps/kort/views.py:307
 msgid "The card printer has been deleted successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:364
+#: aleksis/apps/kort/views.py:317
+msgid "The card print job has been deleted successfully."
+msgstr ""
+
+#: aleksis/apps/kort/views.py:380
 msgid "The card layout has been created successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:382
+#: aleksis/apps/kort/views.py:398
 msgid "The card layout has been changed successfully."
 msgstr ""
 
-#: aleksis/apps/kort/views.py:395
+#: aleksis/apps/kort/views.py:411
 msgid "The card layout has been deleted successfully."
 msgstr ""
diff --git a/aleksis/apps/kort/locale/uk/LC_MESSAGES/django.po b/aleksis/apps/kort/locale/uk/LC_MESSAGES/django.po
index b4b39246f634ca5f9b333bc4b2fe7570af4f359d..c0646a347f6ffa9c818fb5817611b0438b222c64 100644
--- a/aleksis/apps/kort/locale/uk/LC_MESSAGES/django.po
+++ b/aleksis/apps/kort/locale/uk/LC_MESSAGES/django.po
@@ -7,20 +7,24 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-03-19 15:48+0100\n"
+"POT-Creation-Date: 2023-09-16 17:04+0200\n"
 "PO-Revision-Date: 2023-04-13 23:05+0000\n"
 "Last-Translator: Serhii Horichenko <m@sgg.im>\n"
-"Language-Team: Ukrainian <https://translate.edugit.org/projects/aleksis/aleksis-app-kort/uk/>\n"
+"Language-Team: Ukrainian <https://translate.edugit.org/projects/aleksis/"
+"aleksis-app-kort/uk/>\n"
 "Language: uk\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3);\n"
+"Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != "
+"11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % "
+"100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || "
+"(n % 100 >=11 && n % 100 <=14 )) ? 2: 3);\n"
 "X-Generator: Weblate 4.12.1\n"
 
 #: aleksis/apps/kort/apps.py:31
 msgid "Access and manage printer status and print jobs"
-msgstr "Керування станом та доступом до принтера та завданнями друку"
+msgstr "Керування станом принтера, доступом та завданнями друку"
 
 #: aleksis/apps/kort/forms.py:15
 msgid "Select person(s) or group(s)"
@@ -55,14 +59,16 @@ msgstr "Особи"
 msgid "Groups"
 msgstr "Групи"
 
-#: aleksis/apps/kort/forms.py:51 aleksis/apps/kort/models.py:191
+#: aleksis/apps/kort/forms.py:51 aleksis/apps/kort/models.py:209
+#: aleksis/apps/kort/models.py:191
 msgid "Card layout"
 msgstr "Шаблон картки"
 
-#: aleksis/apps/kort/forms.py:53 aleksis/apps/kort/models.py:263
-#: aleksis/apps/kort/tables.py:30
+#: aleksis/apps/kort/forms.py:53 aleksis/apps/kort/models.py:281
+#: aleksis/apps/kort/tables.py:23
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:24
 #: aleksis/apps/kort/templates/kort/card/short.html:12
+#: aleksis/apps/kort/models.py:263 aleksis/apps/kort/tables.py:30
 msgid "Valid until"
 msgstr "Діє до"
 
@@ -82,231 +88,262 @@ msgstr "Основні атрибути"
 msgid "Printer settings"
 msgstr "Налаштування принтера"
 
-#: aleksis/apps/kort/forms.py:138 aleksis/apps/kort/models.py:228
+#: aleksis/apps/kort/forms.py:138 aleksis/apps/kort/models.py:246
+#: aleksis/apps/kort/models.py:228
 msgid "Required data fields"
 msgstr "Необхідні поля даних"
 
-#: aleksis/apps/kort/models.py:24
+#: aleksis/apps/kort/models.py:25 aleksis/apps/kort/models.py:24
 msgid "Online"
 msgstr "Онлайн"
 
-#: aleksis/apps/kort/models.py:25
+#: aleksis/apps/kort/models.py:26 aleksis/apps/kort/models.py:25
 msgid "Offline"
 msgstr "Офлайн"
 
-#: aleksis/apps/kort/models.py:26
+#: aleksis/apps/kort/models.py:27 aleksis/apps/kort/models.py:26
 msgid "With errors"
 msgstr "З помилками"
 
-#: aleksis/apps/kort/models.py:27
+#: aleksis/apps/kort/models.py:28 aleksis/apps/kort/models.py:27
 msgid "Not registered"
 msgstr "Не зареєстровано"
 
-#: aleksis/apps/kort/models.py:56
+#: aleksis/apps/kort/models.py:57 aleksis/apps/kort/models.py:56
 msgid "Registered"
 msgstr "Зареєстровано"
 
-#: aleksis/apps/kort/models.py:57
+#: aleksis/apps/kort/models.py:58 aleksis/apps/kort/models.py:57
 msgid "In progress"
 msgstr "Обробляється"
 
-#: aleksis/apps/kort/models.py:58
+#: aleksis/apps/kort/models.py:59 aleksis/apps/kort/models.py:58
 msgid "Finished"
 msgstr "Завершено"
 
-#: aleksis/apps/kort/models.py:59
+#: aleksis/apps/kort/models.py:60 aleksis/apps/kort/models.py:59
 msgid "Failed"
 msgstr "Збій"
 
-#: aleksis/apps/kort/models.py:64 aleksis/apps/kort/models.py:223
+#: aleksis/apps/kort/models.py:65 aleksis/apps/kort/models.py:241
 #: aleksis/apps/kort/templates/kort/card_layout/detail_content.html:11
 #: aleksis/apps/kort/templates/kort/card_layout/short.html:4
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:11
 #: aleksis/apps/kort/templates/kort/printer/short.html:4
+#: aleksis/apps/kort/models.py:64 aleksis/apps/kort/models.py:223
 msgid "Name"
 msgstr "Повне ім'я"
 
-#: aleksis/apps/kort/models.py:65
+#: aleksis/apps/kort/models.py:66
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:24
+#: aleksis/apps/kort/models.py:65
 msgid "Description"
 msgstr "Опис"
 
-#: aleksis/apps/kort/models.py:66
+#: aleksis/apps/kort/models.py:67
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:17
 #: aleksis/apps/kort/templates/kort/printer/short.html:8
+#: aleksis/apps/kort/models.py:66
 msgid "Location"
 msgstr "Нас.пункт"
 
-#: aleksis/apps/kort/models.py:70 aleksis/apps/kort/models.py:336
-#: aleksis/apps/kort/tables.py:95
+#: aleksis/apps/kort/models.py:71 aleksis/apps/kort/models.py:354
+#: aleksis/apps/kort/tables.py:94
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:38
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:38
-#: aleksis/apps/kort/templates/kort/printer/detail_content.html:90
+#: aleksis/apps/kort/templates/kort/printer/detail_content.html:91
 #: aleksis/apps/kort/templates/kort/printer/short.html:12
+#: aleksis/apps/kort/models.py:70 aleksis/apps/kort/models.py:336
+#: aleksis/apps/kort/tables.py:95
+#: aleksis/apps/kort/templates/kort/printer/detail_content.html:90
 msgid "Status"
 msgstr "Стан"
 
+#: aleksis/apps/kort/models.py:75 aleksis/apps/kort/models.py:358
 #: aleksis/apps/kort/models.py:74 aleksis/apps/kort/models.py:340
 msgid "Status text"
 msgstr "Опис стану"
 
-#: aleksis/apps/kort/models.py:75 aleksis/apps/kort/tables.py:58
+#: aleksis/apps/kort/models.py:76 aleksis/apps/kort/tables.py:52
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:31
+#: aleksis/apps/kort/models.py:75 aleksis/apps/kort/tables.py:58
 msgid "Last seen at"
 msgstr "Востаннє на зв'язку о"
 
-#: aleksis/apps/kort/models.py:80
+#: aleksis/apps/kort/models.py:81 aleksis/apps/kort/models.py:80
 msgid "OAuth2 application"
 msgstr "Програма для OAuth2"
 
-#: aleksis/apps/kort/models.py:87
+#: aleksis/apps/kort/models.py:89
+msgid "OAuth2 client secret"
+msgstr ""
+
+#: aleksis/apps/kort/models.py:95 aleksis/apps/kort/models.py:87
 msgid "CUPS printer"
 msgstr "Принтер CUPS"
 
-#: aleksis/apps/kort/models.py:89
+#: aleksis/apps/kort/models.py:97
+msgid "Leave blank to deactivate CUPS printing"
+msgstr ""
+
+#: aleksis/apps/kort/models.py:100 aleksis/apps/kort/models.py:89
 msgid "Generate card number on server"
 msgstr "Генерувати номер картки на сервері"
 
-#: aleksis/apps/kort/models.py:91
+#: aleksis/apps/kort/models.py:102 aleksis/apps/kort/models.py:91
 msgid "Card detector"
 msgstr "Детектор карток"
 
-#: aleksis/apps/kort/models.py:181
+#: aleksis/apps/kort/models.py:199 aleksis/apps/kort/models.py:181
 msgid "Card printer"
 msgstr "Принтер для карток"
 
-#: aleksis/apps/kort/models.py:182
+#: aleksis/apps/kort/models.py:200
 #: aleksis/apps/kort/templates/kort/printer/list.html:8
 #: aleksis/apps/kort/templates/kort/printer/list.html:9
+#: aleksis/apps/kort/models.py:182
 msgid "Card printers"
 msgstr "Принтери для карток"
 
-#: aleksis/apps/kort/models.py:186
+#: aleksis/apps/kort/models.py:204 aleksis/apps/kort/models.py:186
 msgid "Media file"
 msgstr "Медіафайл"
 
-#: aleksis/apps/kort/models.py:198
+#: aleksis/apps/kort/models.py:216 aleksis/apps/kort/models.py:198
 msgid "Media file for a card layout"
 msgstr "Медіафайл для шаблона карток"
 
-#: aleksis/apps/kort/models.py:199
+#: aleksis/apps/kort/models.py:217 aleksis/apps/kort/models.py:199
 msgid "Media files for card layouts"
 msgstr "Медіафайли для шаблонів карток"
 
-#: aleksis/apps/kort/models.py:224
+#: aleksis/apps/kort/models.py:242
 #: aleksis/apps/kort/templates/kort/card_layout/detail_content.html:43
+#: aleksis/apps/kort/models.py:224
 msgid "Template"
 msgstr "Шаблон"
 
-#: aleksis/apps/kort/models.py:225
+#: aleksis/apps/kort/models.py:243
 #: aleksis/apps/kort/templates/kort/card_layout/detail_content.html:49
+#: aleksis/apps/kort/models.py:225
 msgid "Custom CSS"
 msgstr "Власний CSS"
 
-#: aleksis/apps/kort/models.py:226
+#: aleksis/apps/kort/models.py:244 aleksis/apps/kort/models.py:226
 msgid "Width"
 msgstr "Ширина"
 
+#: aleksis/apps/kort/models.py:244 aleksis/apps/kort/models.py:245
 #: aleksis/apps/kort/models.py:226 aleksis/apps/kort/models.py:227
 msgid "in mm"
 msgstr "в мм"
 
-#: aleksis/apps/kort/models.py:227
+#: aleksis/apps/kort/models.py:245 aleksis/apps/kort/models.py:227
 msgid "Height"
 msgstr "Висота"
 
-#: aleksis/apps/kort/models.py:248
+#: aleksis/apps/kort/models.py:266 aleksis/apps/kort/models.py:248
 msgid "Template is invalid: {}"
 msgstr "Шаблон неправильний: {}"
 
-#: aleksis/apps/kort/models.py:254 aleksis/apps/kort/models.py:267
+#: aleksis/apps/kort/models.py:272 aleksis/apps/kort/models.py:285
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:31
 #: aleksis/apps/kort/templates/kort/card_layout/detail.html:8
+#: aleksis/apps/kort/models.py:254 aleksis/apps/kort/models.py:267
 msgid "Card Layout"
 msgstr "Шаблон картки"
 
-#: aleksis/apps/kort/models.py:255
+#: aleksis/apps/kort/models.py:273 aleksis/apps/kort/models.py:255
 msgid "Card Layouts"
 msgstr "Шаблони карток"
 
-#: aleksis/apps/kort/models.py:260
+#: aleksis/apps/kort/models.py:278 aleksis/apps/kort/tables.py:20
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:11
 #: aleksis/apps/kort/templates/kort/card/short.html:4
+#: aleksis/apps/kort/models.py:260
 msgid "Person"
 msgstr "Особа"
 
-#: aleksis/apps/kort/models.py:262
+#: aleksis/apps/kort/models.py:280 aleksis/apps/kort/models.py:262
 msgid "Chip Number"
 msgstr "Номер чипа"
 
+#: aleksis/apps/kort/models.py:282 aleksis/apps/kort/tables.py:24
 #: aleksis/apps/kort/models.py:264 aleksis/apps/kort/tables.py:31
 msgid "Deactivated"
 msgstr "Деактивовано"
 
-#: aleksis/apps/kort/models.py:270
+#: aleksis/apps/kort/models.py:288 aleksis/apps/kort/models.py:270
 msgid "PDF file"
 msgstr "Файл PDF"
 
-#: aleksis/apps/kort/models.py:303
+#: aleksis/apps/kort/models.py:321 aleksis/apps/kort/models.py:303
 msgid "There is no layout provided for the card."
 msgstr "Для картки не задано шаблон."
 
-#: aleksis/apps/kort/models.py:322 aleksis/apps/kort/models.py:331
+#: aleksis/apps/kort/models.py:340 aleksis/apps/kort/models.py:349
 #: aleksis/apps/kort/templates/kort/card/detail.html:8
+#: aleksis/apps/kort/templates/kort/printer/detail_content.html:85
+#: aleksis/apps/kort/models.py:322 aleksis/apps/kort/models.py:331
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:84
 msgid "Card"
 msgstr "Картка"
 
-#: aleksis/apps/kort/models.py:323
+#: aleksis/apps/kort/models.py:341
 #: aleksis/apps/kort/templates/kort/card/list.html:8
 #: aleksis/apps/kort/templates/kort/card/list.html:9
+#: aleksis/apps/kort/models.py:323
 msgid "Cards"
 msgstr "Картки"
 
-#: aleksis/apps/kort/models.py:328
+#: aleksis/apps/kort/models.py:346 aleksis/apps/kort/models.py:328
 msgid "Printer"
 msgstr "Принтер"
 
-#: aleksis/apps/kort/models.py:343
+#: aleksis/apps/kort/models.py:361 aleksis/apps/kort/models.py:343
 msgid "Card print job"
-msgstr "Завдання друку карток"
+msgstr "Завдання на друк картки"
 
-#: aleksis/apps/kort/models.py:344
+#: aleksis/apps/kort/models.py:362 aleksis/apps/kort/models.py:344
 msgid "Card print jobs"
-msgstr "Завдання друку карток"
+msgstr "Завдання на друк карток"
 
-#: aleksis/apps/kort/tables.py:28
+#: aleksis/apps/kort/tables.py:21
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:17
 #: aleksis/apps/kort/templates/kort/card/short.html:8
+#: aleksis/apps/kort/tables.py:28
 msgid "Chip number"
 msgstr "Номер чипа"
 
+#: aleksis/apps/kort/tables.py:22 aleksis/apps/kort/tables.py:51
 #: aleksis/apps/kort/tables.py:29 aleksis/apps/kort/tables.py:57
 msgid "Current status"
 msgstr "Поточний стан"
 
-#: aleksis/apps/kort/tables.py:32 aleksis/apps/kort/tables.py:61
-#: aleksis/apps/kort/tables.py:85
+#: aleksis/apps/kort/tables.py:25 aleksis/apps/kort/tables.py:55
+#: aleksis/apps/kort/tables.py:81 aleksis/apps/kort/tables.py:32
+#: aleksis/apps/kort/tables.py:61 aleksis/apps/kort/tables.py:85
 msgid "Actions"
 msgstr "Дії"
 
-#: aleksis/apps/kort/tables.py:54
+#: aleksis/apps/kort/tables.py:48 aleksis/apps/kort/tables.py:54
 msgid "Printer name"
 msgstr "Назва принтера"
 
-#: aleksis/apps/kort/tables.py:55
+#: aleksis/apps/kort/tables.py:49 aleksis/apps/kort/tables.py:55
 msgid "Printer location"
 msgstr "Розташування принтера"
 
-#: aleksis/apps/kort/tables.py:59
+#: aleksis/apps/kort/tables.py:53 aleksis/apps/kort/tables.py:59
 msgid "Running jobs"
 msgstr "Поточні завдання"
 
-#: aleksis/apps/kort/tables.py:81
+#: aleksis/apps/kort/tables.py:77 aleksis/apps/kort/tables.py:81
 msgid "Layout name"
 msgstr "Назва шаблону"
 
 #: aleksis/apps/kort/templates/kort/card/actions.html:8
+#: aleksis/apps/kort/templates/kort/card/detail.html:13
 #: aleksis/apps/kort/templates/kort/card/detail.html:9
 #, python-format
 msgid "Card of %(person)s"
@@ -342,6 +379,7 @@ msgstr "Деактивувати"
 #: aleksis/apps/kort/templates/kort/printer/actions.html:33
 #: aleksis/apps/kort/templates/kort/printer/delete.html:29
 #: aleksis/apps/kort/templates/kort/printer/detail.html:31
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:22
 msgid "Delete"
 msgstr "Видалити"
 
@@ -356,23 +394,32 @@ msgstr "Ви дійсно хочете видалити цю картку?"
 #: aleksis/apps/kort/templates/kort/card/delete.html:16
 msgid ""
 "\n"
-"      Please pay attention that a deletion of a card is irreversible and should be only used to clean up misprints.\n"
-"      If you just want to make a card unusable because a student has lost his card or left the school,\n"
+"      Please pay attention that a deletion of a card is irreversible and "
+"should be only used to clean up misprints.\n"
+"      If you just want to make a card unusable because a student has lost "
+"his card or left the school,\n"
 "      please deactivate the card instead.\n"
 "    "
 msgstr ""
 "\n"
-"      Будь ласка, зверніть увагу, що скасувати видалення картки неможливо і повинно використовуватися лише для виправлення помилок.\n"
-"      Якщо Ви просто хочете зробити картку непридатною для використання через те, що учень загубив свою картку або покинув школу,\n"
+"      Будь ласка, зверніть увагу, що скасувати видалення картки неможливо і "
+"повинно використовуватися лише для виправлення помилок.\n"
+"      Якщо Ви просто хочете зробити картку непридатною для використання "
+"через те, що учень загубив свою картку або покинув школу,\n"
 "      то, будь ласка, краще деактивуйте картку.\n"
 "    "
 
 #: aleksis/apps/kort/templates/kort/card/delete.html:26
 #: aleksis/apps/kort/templates/kort/card_layout/delete.html:25
 #: aleksis/apps/kort/templates/kort/printer/delete.html:25
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:18
 msgid "Go back"
 msgstr "Назад"
 
+#: aleksis/apps/kort/templates/kort/card/detail.html:11
+msgid "Back"
+msgstr ""
+
 #: aleksis/apps/kort/templates/kort/card/detail_content.html:6
 msgid "Card details"
 msgstr "Дані картки"
@@ -389,6 +436,11 @@ msgstr "Показати картку як PDF"
 msgid "Generate card as PDF"
 msgstr "Створити картку як PDF"
 
+#: aleksis/apps/kort/templates/kort/card/detail_content.html:68
+#, fuzzy
+msgid "Preview card layout"
+msgstr "Створити шаблон картки"
+
 #: aleksis/apps/kort/templates/kort/card/edit.html:12
 #: aleksis/apps/kort/templates/kort/card/edit.html:13
 msgid "Edit card"
@@ -402,26 +454,32 @@ msgstr "Створити картку(и)"
 #: aleksis/apps/kort/templates/kort/card/issue.html:23
 msgid ""
 "\n"
-"          Please select the persons and/or the groups to whom you want to issue new cards.\n"
-"          After clicking on 'Next', you will be able to check whether the data of the persons\n"
+"          Please select the persons and/or the groups to whom you want to "
+"issue new cards.\n"
+"          After clicking on 'Next', you will be able to check whether the "
+"data of the persons\n"
 "          are complete and include everything needed for the cards.\n"
 "        "
 msgstr ""
 "\n"
-"          Будь ласка, оберіть осіб та/або групи, для яких Ви хочете створити нові картки.\n"
-"          Після натискання кнопки \"Далі\" Ви зможете перевірити, чи дані осіб\n"
+"          Будь ласка, оберіть осіб та/або групи, для яких Ви хочете створити "
+"нові картки.\n"
+"          Після натискання кнопки \"Далі\" Ви зможете перевірити, чи дані "
+"осіб\n"
 "          є повними і включають все необхідне для карток.\n"
 "        "
 
 #: aleksis/apps/kort/templates/kort/card/issue.html:32
 msgid ""
 "\n"
-"          In the following table you can see all selected persons and the related data needed for the cards.\n"
+"          In the following table you can see all selected persons and the "
+"related data needed for the cards.\n"
 "          Please select the persons to whom you want to issue new cards.\n"
 "        "
 msgstr ""
 "\n"
-"          У наступній таблиці Ви можете побачити усіх обраних осіб та пов'язані дані, необхідні для карток.\n"
+"          У наступній таблиці Ви можете побачити усіх обраних осіб та "
+"пов'язані дані, необхідні для карток.\n"
 "          Будь ласка, оберіть осіб, для яких Ви хочете зробити нові картки.\n"
 "        "
 
@@ -443,12 +501,12 @@ msgstr "Скасувати"
 
 #: aleksis/apps/kort/templates/kort/card/list.html:17
 msgid "Issue new card(s)"
-msgstr "Створити нову(і) картку(и)"
+msgstr "Створити нову картку (нові картки)"
 
 #: aleksis/apps/kort/templates/kort/card/print_form.html:8
 #: aleksis/apps/kort/templates/kort/card/print_form.html:16
 msgid "Print card"
-msgstr "Друкувати картку"
+msgstr "Друк картки"
 
 #: aleksis/apps/kort/templates/kort/card/status.html:3
 msgid "Valid"
@@ -486,12 +544,14 @@ msgstr "Ви дійсно хочете видалити цей шаблон?"
 #: aleksis/apps/kort/templates/kort/card_layout/delete.html:16
 msgid ""
 "\n"
-"      Please pay attention that this also will prevent the successful finishing of all active print jobs\n"
+"      Please pay attention that this also will prevent the successful "
+"finishing of all active print jobs\n"
 "      which use these template.\n"
 "    "
 msgstr ""
 "\n"
-"      Зверніть увагу, що це також перешкоджатиме успішному завершенню всіх активних завдань друку,\n"
+"      Зверніть увагу, що це також перешкоджатиме успішному завершенню всіх "
+"активних завдань друку,\n"
 "      які використовують цей шаблон.\n"
 "    "
 
@@ -527,12 +587,14 @@ msgstr "Настанови щодо створення шаблонів карт
 #: aleksis/apps/kort/templates/kort/card_layout/instructions.html:5
 msgid ""
 "\n"
-"      You will be able to use the following data in your individual template. The template has to been written in the\n"
+"      You will be able to use the following data in your individual "
+"template. The template has to been written in the\n"
 "      Django template language.\n"
 "    "
 msgstr ""
 "\n"
-"      Ви зможете використовувати наведені нижче дані у своєму власному шаблоні. Шаблон повинен бути написаний\n"
+"      Ви зможете використовувати наведені нижче дані у своєму власному "
+"шаблоні. Шаблон повинен бути написаний\n"
 "      мовою шаблонів Django.\n"
 "    "
 
@@ -541,16 +603,24 @@ msgid "The chip number as string"
 msgstr "Номер чипа — рядок"
 
 #: aleksis/apps/kort/templates/kort/card_layout/instructions.html:15
-msgid "This will give you access to any attributes of the person object like name, personal data or contact data."
-msgstr "Це надасть Вам доступ до особистих атрибутів на кшталт імені, особистих або контактних даних."
+msgid ""
+"This will give you access to any attributes of the person object like name, "
+"personal data or contact data."
+msgstr ""
+"Це надасть Вам доступ до усіх особистих атрибутів на кшталт імені, особистих "
+"або контактних даних."
 
 #: aleksis/apps/kort/templates/kort/card_layout/instructions.html:19
 msgid "The date until when the card is valid"
 msgstr "Дата, до якої діє картка"
 
 #: aleksis/apps/kort/templates/kort/card_layout/instructions.html:24
-msgid "This will give you access to the uploaded media files. Replace 0 by the number of your media file (starting with 0)."
-msgstr "Це надасть Вам доступ до завантажених медіафайлів. Замініть 0 на номер Вашого файлу (починаючи з 0)."
+msgid ""
+"This will give you access to the uploaded media files. Replace 0 by the "
+"number of your media file (starting with 0)."
+msgstr ""
+"Це надасть Вам доступ до завантажених медіафайлів. Замініть 0 на номер "
+"Вашого файлу (починаючи з 0)."
 
 #: aleksis/apps/kort/templates/kort/card_layout/list.html:8
 #: aleksis/apps/kort/templates/kort/card_layout/list.html:9
@@ -559,12 +629,12 @@ msgstr "Шаблони карток"
 
 #: aleksis/apps/kort/templates/kort/card_layout/list.html:17
 msgid "Create new card layout"
-msgstr "Створіть новий шаблон для карток"
+msgstr "Створити новий шаблон для карток"
 
 #: aleksis/apps/kort/templates/kort/person_status.html:5
 #, python-format
 msgid "%(count)s missing data fields"
-msgstr "Відсутні %(count)s поля даних"
+msgstr "Відсутні поля даних: %(count)s"
 
 #: aleksis/apps/kort/templates/kort/person_status.html:10
 msgid "Data complete"
@@ -590,13 +660,16 @@ msgstr "Ви дійсно хочете видалити цей принтер д
 #: aleksis/apps/kort/templates/kort/printer/delete.html:16
 msgid ""
 "\n"
-"      Please pay attention that this also will deactivate the access for the print client and you would have to\n"
+"      Please pay attention that this also will deactivate the access for the "
+"print client and you would have to\n"
 "      reconfigure the client if you want to use it further.\n"
 "    "
 msgstr ""
 "\n"
-"      Зверніть увагу на те, що це також деактивує доступ клієнтів до друку, і Вам доведеться\n"
-"      переналаштовувати клієнтське ПЗ, якщо Ви пізніше захочете його використовувати.\n"
+"      Зверніть увагу на те, що це також деактивує доступ клієнтів до друку, "
+"і Вам доведеться\n"
+"      переналаштовувати клієнтське ПЗ, якщо Ви пізніше захочете його "
+"використовувати.\n"
 "    "
 
 #: aleksis/apps/kort/templates/kort/printer/detail.html:15
@@ -618,12 +691,14 @@ msgstr "Налаштувати клієнт друку"
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:62
 msgid ""
 "\n"
-"              To enable printing, you have to register the print client on the device\n"
+"              To enable printing, you have to register the print client on "
+"the device\n"
 "              which the printer is connected to.\n"
 "            "
 msgstr ""
 "\n"
-"              Для увімкнення друку, потрібно зареєструвати клієнт друку на пристрої,\n"
+"              Для увімкнення друку, потрібно зареєструвати клієнт друку на "
+"пристрої,\n"
 "              до якого під'єднаний принтер.\n"
 "            "
 
@@ -647,6 +722,7 @@ msgstr "3. Налаштувати клієнт"
 msgid "Print jobs"
 msgstr "Завдання друку"
 
+#: aleksis/apps/kort/templates/kort/printer/detail_content.html:88
 #: aleksis/apps/kort/templates/kort/printer/detail_content.html:87
 msgid "Created at"
 msgstr "Створено о"
@@ -660,17 +736,29 @@ msgstr "Редагувати принтер для карток"
 msgid "Register new card printer"
 msgstr "Зареєструвати новий принтер для карток"
 
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:8
+#, fuzzy
+msgid "Delete Card Print Job"
+msgstr "Видалити принтер для карток"
+
+#: aleksis/apps/kort/templates/kort/printer/print_job_delete.html:12
+#, fuzzy
+msgid "Do you really want to delete the following card print job?"
+msgstr "Ви дійсно хочете видалити цей принтер для карток?"
+
 #: aleksis/apps/kort/views.py:69
 msgid "The cards have been created successfully."
 msgstr "Картки були успішно створені."
 
 #: aleksis/apps/kort/views.py:137 aleksis/apps/kort/views.py:193
-msgid "The print job #{} for the card {} on the printer {} has been created successfully."
+msgid ""
+"The print job #{} for the card {} on the printer {} has been created "
+"successfully."
 msgstr "Завдання друку #{} для картки {} на принтер {} було успішно створене."
 
 #: aleksis/apps/kort/views.py:145 aleksis/apps/kort/views.py:200
 msgid "The print job couldn't be started because of the following error: {}"
-msgstr "Завдання друку не розпочало виконання через помилку: {}"
+msgstr "Завдання друку не розпочалося через помилку: {}"
 
 #: aleksis/apps/kort/views.py:158
 msgid "The card has been deleted successfully."
@@ -680,50 +768,55 @@ msgstr "Картка успішно видалена."
 msgid "The card has been deactivated successfully."
 msgstr "Картка була успішно деактивована."
 
-#: aleksis/apps/kort/views.py:220
-msgid "The chip number is missing."
-msgstr "Номер чипа відсутній."
-
-#: aleksis/apps/kort/views.py:232
+#: aleksis/apps/kort/views.py:238 aleksis/apps/kort/views.py:232
 msgid "Progress: Generate card layout as PDF file"
 msgstr "Прогрес: Збереження шаблону картки у файл PDF"
 
-#: aleksis/apps/kort/views.py:233
+#: aleksis/apps/kort/views.py:239 aleksis/apps/kort/views.py:233
 msgid "Generating PDF file …"
 msgstr "Створення файлу PDF …"
 
-#: aleksis/apps/kort/views.py:234
+#: aleksis/apps/kort/views.py:240 aleksis/apps/kort/views.py:234
 msgid "The PDF file with the card layout has been generated successfully."
 msgstr "Файл PDF з шаблоном картки успішно збережений."
 
-#: aleksis/apps/kort/views.py:235
+#: aleksis/apps/kort/views.py:241 aleksis/apps/kort/views.py:235
 msgid "There was a problem while generating the PDF file."
 msgstr "Під час створення файлу PDF виникла проблема."
 
-#: aleksis/apps/kort/views.py:237
+#: aleksis/apps/kort/views.py:243 aleksis/apps/kort/views.py:237
 msgid "Show card"
 msgstr "Показати картку"
 
-#: aleksis/apps/kort/views.py:275
+#: aleksis/apps/kort/views.py:281 aleksis/apps/kort/views.py:275
 msgid "The card printer has been created successfully."
 msgstr "Принтер для карток успішно створений."
 
-#: aleksis/apps/kort/views.py:288
+#: aleksis/apps/kort/views.py:294 aleksis/apps/kort/views.py:288
 msgid "The card printer has been changed successfully."
 msgstr "Принтер для карток успішно змінений."
 
-#: aleksis/apps/kort/views.py:301
+#: aleksis/apps/kort/views.py:307 aleksis/apps/kort/views.py:301
 msgid "The card printer has been deleted successfully."
 msgstr "Принтер для карток успішно видалений."
 
-#: aleksis/apps/kort/views.py:364
+#: aleksis/apps/kort/views.py:317
+#, fuzzy
+msgid "The card print job has been deleted successfully."
+msgstr "Принтер для карток успішно видалений."
+
+#: aleksis/apps/kort/views.py:380 aleksis/apps/kort/views.py:364
 msgid "The card layout has been created successfully."
 msgstr "Шаблон картки успішно створений."
 
-#: aleksis/apps/kort/views.py:382
+#: aleksis/apps/kort/views.py:398 aleksis/apps/kort/views.py:382
 msgid "The card layout has been changed successfully."
 msgstr "Шаблон картки успішно змінений."
 
-#: aleksis/apps/kort/views.py:395
+#: aleksis/apps/kort/views.py:411 aleksis/apps/kort/views.py:395
 msgid "The card layout has been deleted successfully."
 msgstr "Шаблон картки успішно видалений."
+
+#: aleksis/apps/kort/views.py:220
+msgid "The chip number is missing."
+msgstr "Номер чипа відсутній."
diff --git a/aleksis/apps/kort/migrations/0001_initial.py b/aleksis/apps/kort/migrations/0001_initial.py
index 61168bed713598ac6debe768536d5bd1cf36d1dc..0021b7f4a9ade9e391b8c7199a419af74cfa06c8 100644
--- a/aleksis/apps/kort/migrations/0001_initial.py
+++ b/aleksis/apps/kort/migrations/0001_initial.py
@@ -11,7 +11,6 @@ class Migration(migrations.Migration):
 
     dependencies = [
         ('core', '0022_public_favicon'),
-        ('sites', '0002_alter_domain_unique'),
     ]
 
     operations = [
@@ -24,7 +23,6 @@ class Migration(migrations.Migration):
                 ('valid_until', models.DateField(verbose_name='Valid until')),
                 ('deactivated', models.BooleanField(default=False, verbose_name='Deactivated')),
                 ('person', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='cards', to='core.person', verbose_name='Person')),
-                ('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.site')),
             ],
             options={
                 'verbose_name': 'Card',
diff --git a/aleksis/apps/kort/migrations/0002_card_printer.py b/aleksis/apps/kort/migrations/0002_card_printer.py
index 903420eb98b4d03408527b0f3716a5ee819f3dce..1e5ab729612f8b322d1d6b39fdc587e9d2900489 100644
--- a/aleksis/apps/kort/migrations/0002_card_printer.py
+++ b/aleksis/apps/kort/migrations/0002_card_printer.py
@@ -8,7 +8,6 @@ import django.db.models.deletion
 class Migration(migrations.Migration):
 
     dependencies = [
-        ('sites', '0002_alter_domain_unique'),
         ('kort', '0001_initial'),
     ]
 
@@ -34,7 +33,6 @@ class Migration(migrations.Migration):
                 ('status', models.CharField(choices=[('online', 'Online'), ('offline', 'Offline'), ('with_errors', 'With errors')], max_length=255, verbose_name='Status')),
                 ('status_text', models.TextField(blank=True, verbose_name='Status text')),
                 ('last_seen_at', models.DateTimeField(blank=True, null=True, verbose_name='Last seen at')),
-                ('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.site')),
             ],
             options={
                 'verbose_name': 'Card printer',
diff --git a/aleksis/apps/kort/migrations/0003_auto_20220308_2023.py b/aleksis/apps/kort/migrations/0003_auto_20220308_2023.py
index 74c09ebd70a900d8ecb19c2ec0087ed43a4fbb9c..20766975529df5794b04ac54250ca8875e735b18 100644
--- a/aleksis/apps/kort/migrations/0003_auto_20220308_2023.py
+++ b/aleksis/apps/kort/migrations/0003_auto_20220308_2023.py
@@ -8,7 +8,6 @@ import django.db.models.deletion
 class Migration(migrations.Migration):
 
     dependencies = [
-        ('sites', '0002_alter_domain_unique'),
         ('kort', '0002_card_printer'),
     ]
 
@@ -33,7 +32,6 @@ class Migration(migrations.Migration):
                 ('name', models.CharField(max_length=255, verbose_name='Name')),
                 ('template', models.TextField(verbose_name='Template')),
                 ('css', models.TextField(blank=True, verbose_name='Custom CSS')),
-                ('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.site')),
             ],
             options={
                 'abstract': False,
diff --git a/aleksis/apps/kort/migrations/0007_auto_20220315_1957.py b/aleksis/apps/kort/migrations/0007_auto_20220315_1957.py
index 254017326103b8661d57dca4ee55aac86ebb0ed2..7e939d01155d7dffb078407d847e1c10b87b2776 100644
--- a/aleksis/apps/kort/migrations/0007_auto_20220315_1957.py
+++ b/aleksis/apps/kort/migrations/0007_auto_20220315_1957.py
@@ -11,7 +11,6 @@ class Migration(migrations.Migration):
 
     dependencies = [
         migrations.swappable_dependency(settings.OAUTH2_PROVIDER_APPLICATION_MODEL),
-        ('sites', '0002_alter_domain_unique'),
         ('kort', '0006_auto_20220310_2003'),
     ]
 
@@ -36,7 +35,6 @@ class Migration(migrations.Migration):
                 ('status_text', models.TextField(blank=True, verbose_name='Status text')),
                 ('card', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='kort.card', verbose_name='Card')),
                 ('printer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='kort.cardprinter', verbose_name='Printer')),
-                ('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.site')),
             ],
             options={
                 'verbose_name': 'Card print job',
diff --git a/aleksis/apps/kort/migrations/0012_auto_20220529_1435.py b/aleksis/apps/kort/migrations/0012_auto_20220529_1435.py
index 8c9c377094dbcdba56d13f5d4a91e863acf33027..3bb036aa9aa6d8db5e81e7cf3d7e6f7bf3943f4d 100644
--- a/aleksis/apps/kort/migrations/0012_auto_20220529_1435.py
+++ b/aleksis/apps/kort/migrations/0012_auto_20220529_1435.py
@@ -8,7 +8,6 @@ import django.db.models.deletion
 class Migration(migrations.Migration):
 
     dependencies = [
-        ('sites', '0002_alter_domain_unique'),
         ('kort', '0011_cardprinter_card_detector'),
     ]
 
@@ -37,7 +36,6 @@ class Migration(migrations.Migration):
                 ('extended_data', models.JSONField(default=dict, editable=False)),
                 ('media_file', models.FileField(upload_to='card_layouts/media/', verbose_name='Media file')),
                 ('card_layout', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='media_files', to='kort.cardlayout', verbose_name='Card layout')),
-                ('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.site')),
             ],
             options={
                 'verbose_name': 'Media file for a card layout',
diff --git a/aleksis/apps/kort/migrations/0017_cardprinter_oauth2_client_secret.py b/aleksis/apps/kort/migrations/0016_cardprinter_oauth2_client_secret.py
similarity index 73%
rename from aleksis/apps/kort/migrations/0017_cardprinter_oauth2_client_secret.py
rename to aleksis/apps/kort/migrations/0016_cardprinter_oauth2_client_secret.py
index ca460fe86703a49b14765a609f3500eded91c36a..50e23bf5d56af71c5abfe6c6101013577756d8be 100644
--- a/aleksis/apps/kort/migrations/0017_cardprinter_oauth2_client_secret.py
+++ b/aleksis/apps/kort/migrations/0016_cardprinter_oauth2_client_secret.py
@@ -1,4 +1,4 @@
-# Generated by Django 4.1.9 on 2023-06-17 18:42
+# Generated by Django 4.2.4 on 2023-08-30 14:25
 
 from django.db import migrations, models
 import django.db.models.deletion
@@ -7,8 +7,7 @@ import django.db.models.deletion
 class Migration(migrations.Migration):
 
     dependencies = [
-        ("sites", "0002_alter_domain_unique"),
-        ("kort", "0016_card_last_read_counter"),
+        ("kort", "0015_migrate_scopes"),
     ]
 
     operations = [
diff --git a/aleksis/apps/kort/migrations/0017_managed_by_drop_sites.py b/aleksis/apps/kort/migrations/0017_managed_by_drop_sites.py
new file mode 100644
index 0000000000000000000000000000000000000000..258ef0a7960fae1efb2980d5fb79236cdfeecaef
--- /dev/null
+++ b/aleksis/apps/kort/migrations/0017_managed_by_drop_sites.py
@@ -0,0 +1,55 @@
+# Generated by Django 4.2.10 on 2024-02-24 11:58
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('kort', '0016_cardprinter_oauth2_client_secret'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='card',
+            name='managed_by_app_label',
+            field=models.CharField(blank=True, editable=False, max_length=255, verbose_name='App label of app responsible for managing this instance'),
+        ),
+        migrations.AddField(
+            model_name='cardlayout',
+            name='managed_by_app_label',
+            field=models.CharField(blank=True, editable=False, max_length=255, verbose_name='App label of app responsible for managing this instance'),
+        ),
+        migrations.AddField(
+            model_name='cardlayoutmediafile',
+            name='managed_by_app_label',
+            field=models.CharField(blank=True, editable=False, max_length=255, verbose_name='App label of app responsible for managing this instance'),
+        ),
+        migrations.AddField(
+            model_name='cardprinter',
+            name='managed_by_app_label',
+            field=models.CharField(blank=True, editable=False, max_length=255, verbose_name='App label of app responsible for managing this instance'),
+        ),
+        migrations.AddField(
+            model_name='cardprintjob',
+            name='managed_by_app_label',
+            field=models.CharField(blank=True, editable=False, max_length=255, verbose_name='App label of app responsible for managing this instance'),
+        ),
+        migrations.AlterField(
+            model_name='cardprinter',
+            name='cups_printer',
+            field=models.CharField(blank=True, help_text='Leave blank to deactivate CUPS printing', max_length=255, verbose_name='CUPS printer'),
+        ),
+    ] + [
+        migrations.RunSQL(
+            f"ALTER TABLE kort_{model_name} drop column if exists site_id;"
+        ) for model_name  in
+        [
+            "cardprinter",
+            "cardlayoutmediafile",
+            "cardlayout",
+            "card",
+            "cardprintjob",
+        ]
+    ]
+
diff --git a/aleksis/apps/kort/models/cards.py b/aleksis/apps/kort/models/cards.py
index b19fd31c801394a3b0a65fd5413c3a2011bfc196..a85dbd1af47e693f38474cecdcd9858a9b38fd12 100644
--- a/aleksis/apps/kort/models/cards.py
+++ b/aleksis/apps/kort/models/cards.py
@@ -156,10 +156,9 @@ class CardPrinter(ExtensibleModel):
             self.status
             not in (CardPrinterStatus.NOT_REGISTERED.value, CardPrinterStatus.OFFLINE.value)
             and self.last_seen_at
-        ):
-            if self.last_seen_at < timezone.now() - timedelta(minutes=1):
-                self.status = CardPrinterStatus.OFFLINE.value
-                self.save()
+        ) and self.last_seen_at < timezone.now() - timedelta(minutes=1):
+            self.status = CardPrinterStatus.OFFLINE.value
+            self.save()
 
     @classmethod
     def check_online_status_for_all(cls, qs=None):
@@ -192,6 +191,9 @@ class CardPrinter(ExtensibleModel):
         """Return OAuth2 scope name to access PDF file via API."""
         return f"{self.SCOPE_PREFIX}_{self.id}"
 
+    def get_jobs(self):
+        return self.jobs.all().order_by("-created")
+
     class Meta:
         verbose_name = _("Card printer")
         verbose_name_plural = _("Card printers")
@@ -260,7 +262,7 @@ class CardLayout(ExtensibleModel):
             t = Template(self.template)
             t.render(Context())
         except Exception as e:
-            raise ValidationError(_("Template is invalid: {}").format(e))
+            raise ValidationError(_("Template is invalid: {}").format(e)) from e
 
     def __str__(self):
         return self.name
diff --git a/aleksis/apps/kort/rules.py b/aleksis/apps/kort/rules.py
index c05ab9a5e65f4fb336dde0ad46c9c8f53e36631b..506258b45b816a2c348c53228c9dc8a1d546a813 100644
--- a/aleksis/apps/kort/rules.py
+++ b/aleksis/apps/kort/rules.py
@@ -34,6 +34,12 @@ delete_card_printer_predicate = view_card_printer_predicate & (
 )
 add_perm("kort.delete_cardprinter_rule", delete_card_printer_predicate)
 
+delete_card_print_job_predicate = has_person & (
+    has_global_perm("kort.delete_cardprintjob") | has_object_perm("kort.delete_cardprintjob")
+)
+add_perm("kort.delete_cardprintjob_rule", delete_card_print_job_predicate)
+
+
 view_card_layouts_predicate = has_person & (
     has_global_perm("kort.view_cardlayout") | has_any_object("kort.view_cardlayout", CardLayout)
 )
diff --git a/aleksis/apps/kort/tables.py b/aleksis/apps/kort/tables.py
index 0db9abd593b89ef8a88c92d75e213085ee856b98..85fb2541ac623816794f255623967a493220fe20 100644
--- a/aleksis/apps/kort/tables.py
+++ b/aleksis/apps/kort/tables.py
@@ -3,14 +3,7 @@ from django.template.loader import render_to_string
 from django.utils.safestring import SafeString, mark_safe
 from django.utils.translation import gettext as _
 
-from django_tables2 import (
-    BooleanColumn,
-    Column,
-    DateTimeColumn,
-    LinkColumn,
-    RelatedLinkColumn,
-    Table,
-)
+from django_tables2 import BooleanColumn, Column, DateTimeColumn, LinkColumn, Table
 from django_tables2.utils import A, AttributeDict, computed_values
 
 from aleksis.apps.kort.forms import PrinterSelectForm
@@ -24,7 +17,7 @@ class CardTable(Table):
     class Meta:
         attrs = {"class": "highlight"}
 
-    person = LinkColumn("card", verbose_name=_("Chip number"), args=[A("pk")])
+    person = LinkColumn("card", verbose_name=_("Person"), args=[A("pk")])
     chip_number = LinkColumn("card", verbose_name=_("Chip number"), args=[A("pk")])
     current_status = Column(verbose_name=_("Current status"), accessor=A("pk"))
     valid_until = Column(verbose_name=_("Valid until"))
@@ -41,7 +34,8 @@ class CardTable(Table):
 
     def render_actions(self, value, record):
         return render_to_string(
-            "kort/card/actions.html", dict(pk=value, card=record, printer_form=PrinterSelectForm())
+            "kort/card/actions.html",
+            dict(pk=value, card=record, printer_form=PrinterSelectForm(), user=self.request.user),
         )
 
 
@@ -69,7 +63,9 @@ class CardPrinterTable(Table):
         )
 
     def render_actions(self, value, record):
-        return render_to_string("kort/printer/actions.html", dict(pk=value, printer=record))
+        return render_to_string(
+            "kort/printer/actions.html", dict(pk=value, printer=record, user=self.request.user)
+        )
 
 
 class CardLayoutTable(Table):
@@ -85,7 +81,10 @@ class CardLayoutTable(Table):
     actions = Column(verbose_name=_("Actions"), accessor=A("pk"))
 
     def render_actions(self, value, record):
-        return render_to_string("kort/card_layout/actions.html", dict(pk=value, card_layout=record))
+        return render_to_string(
+            "kort/card_layout/actions.html",
+            dict(pk=value, card_layout=record, user=self.request.user),
+        )
 
 
 class IssueCardPersonsTable(Table):
diff --git a/aleksis/apps/kort/templates/kort/card/detail.html b/aleksis/apps/kort/templates/kort/card/detail.html
index e63f8bf07df448d14988382f3683521531eb7813..440657997a70a88b479c3109ed2caf68e493bf25 100644
--- a/aleksis/apps/kort/templates/kort/card/detail.html
+++ b/aleksis/apps/kort/templates/kort/card/detail.html
@@ -6,7 +6,12 @@
 
 
 {% block browser_title %}{% blocktrans %}Card{% endblocktrans %}{% endblock %}
-{% block page_title %}{% blocktrans with person=object.person %}Card of {{ person }}{% endblocktrans %}{% endblock %}
+{% block page_title %}
+  <a href="{% url "cards" %}" class="btn-flat primary-color-text waves-light waves-effect">
+    <i class="material-icons iconify left" data-icon="mdi:chevron-left"></i> {% trans "Back" %}
+  </a>
+  {% blocktrans with person=object.person %}Card of {{ person }}{% endblocktrans %}
+{% endblock %}
 
 
 {% block content %}
diff --git a/aleksis/apps/kort/templates/kort/card/detail_content.html b/aleksis/apps/kort/templates/kort/card/detail_content.html
index 07e102e5b030da2974930fbabd85d97de3df6ca3..dc1830e8a0ddf6c753806e36ff463583229fa5c8 100644
--- a/aleksis/apps/kort/templates/kort/card/detail_content.html
+++ b/aleksis/apps/kort/templates/kort/card/detail_content.html
@@ -63,5 +63,9 @@
         </div>
       {% endif %}
     {% endif %}
+    <a href="{% url 'preview_card' card.pk %}" class="btn waves-effect waves-light">
+      <i class="material-icons left iconify" data-icon="mdi:file-pdf-box"></i>
+      {% trans "Preview card layout" %}
+    </a>
   </div>
 </div>
\ No newline at end of file
diff --git a/aleksis/apps/kort/templates/kort/printer/detail_content.html b/aleksis/apps/kort/templates/kort/printer/detail_content.html
index 9618a4bf1c16faa0de82b58ae6cae020f6df4200..e186014426c4e4e086ca705ee1e104cd11dd623f 100644
--- a/aleksis/apps/kort/templates/kort/printer/detail_content.html
+++ b/aleksis/apps/kort/templates/kort/printer/detail_content.html
@@ -80,6 +80,7 @@
           <div class="card-title">{% trans "Print jobs" %}</div>
           <table>
             <tr>
+              <th></th>
               <th>
                 {% trans "Card" %}
               </th>
@@ -89,9 +90,19 @@
               <th>
                 {% trans "Status" %}
               </th>
+              <th></th>
             </tr>
-            {% for job in printer.jobs.all %}
+            {% for job in printer.get_jobs %}
               <tr>
+                <td>
+                  {% if job.status == "finished" %}
+                  <i class="material-icons iconify green-text" data-icon="mdi:check-circle-outline"></i>
+                  {% elif job.status == "failed" %}
+                  <i class="material-icons iconify red-text" data-icon="mdi:alert-circle-outline"></i>
+                  {% else %}
+                  <i class="material-icons iconify orange-text" data-icon="mdi:dots-horizontal"></i>
+                  {% endif %}
+                </td>
                 <td>
                   <a href="{% url "card" job.card.pk %}">
                     {{ job.card }}
@@ -103,6 +114,13 @@
                 <td>
                   {{ job.status }} {% if job.status_text %}({{ job.status_text }}){% endif %}
                 </td>
+                <td>
+                  {% if job.status == "registered" %}
+                  <a class="btn-flat waves-effect waves-light center" href="{% url 'delete_print_job' job.pk %}">
+                    <i class="material-icons iconify red-text" data-icon="mdi:delete-outline"></i>
+                  </a>
+                  {% endif %}
+                </td>
               </tr>
             {% endfor %}
           </table>
diff --git a/aleksis/apps/kort/templates/kort/printer/print_job_delete.html b/aleksis/apps/kort/templates/kort/printer/print_job_delete.html
new file mode 100644
index 0000000000000000000000000000000000000000..05fd4e65127d8f16830a0d25cbdff294734d4899
--- /dev/null
+++ b/aleksis/apps/kort/templates/kort/printer/print_job_delete.html
@@ -0,0 +1,25 @@
+{# -*- engine:django -*- #}
+
+{% extends "core/base.html" %}
+
+{% load i18n rules material_form %}
+{% load render_table from django_tables2 %}
+
+{% block browser_title %}{% blocktrans %}Delete Card Print Job{% endblocktrans %}{% endblock %}
+{% block no_page_title %}{% endblock %}
+
+{% block content %}
+  <p class="flow-text">{% trans "Do you really want to delete the following card print job?" %}</p>
+  {{ object }}
+  <form method="post" action="">
+    {% csrf_token %}
+    <a href="{% url "card_printers" %}" class="modal-close waves-effect waves-green btn">
+      <i class="material-icons left iconify" data-icon="mdi:arrow-left"></i>
+      {% trans "Go back" %}
+    </a>
+    <button type="submit" name="delete" class="modal-close waves-effect waves-light red btn">
+      <i class="material-icons left iconify" data-icon="mdi:delete-outline"></i>
+      {% trans "Delete" %}
+    </button>
+  </form>
+{% endblock %}
\ No newline at end of file
diff --git a/aleksis/apps/kort/urls.py b/aleksis/apps/kort/urls.py
index 424fd51ca8b788cc738c9ff755377173a7e4fb54..564ea85d8f9dfaacd4817c2a4241133fb711aa91 100644
--- a/aleksis/apps/kort/urls.py
+++ b/aleksis/apps/kort/urls.py
@@ -12,6 +12,7 @@ urlpatterns = [
         name="generate_card_pdf",
     ),
     path("cards/<int:pk>/deactivate/", views.CardDeactivateView.as_view(), name="deactivate_card"),
+    path("cards/<int:pk>/preview/", views.CardPreviewView.as_view(), name="preview_card"),
     path("cards/<int:pk>/print/", views.CardPrintView.as_view(), name="print_card"),
     path("cards/<int:pk>/delete/", views.CardDeleteView.as_view(), name="delete_card"),
     path("printers/", views.CardPrinterListView.as_view(), name="card_printers"),
@@ -28,6 +29,11 @@ urlpatterns = [
         views.CardPrinterConfigView.as_view(),
         name="card_printer_config",
     ),
+    path(
+        "jobs/<int:pk>/delete/",
+        views.CardPrintJobDeleteView.as_view(),
+        name="delete_print_job",
+    ),
     path("layouts/", views.CardLayoutListView.as_view(), name="card_layouts"),
     path("layouts/create/", views.CardLayoutCreateView.as_view(), name="create_card_layout"),
     path("layouts/<int:pk>/", views.CardLayoutDetailView.as_view(), name="card_layout"),
diff --git a/aleksis/apps/kort/views.py b/aleksis/apps/kort/views.py
index a7bad34bc5328b266de9a70524ec06d5a111fde4..47cc42efbb6773480f1e82e41c10b7c1164849ee 100644
--- a/aleksis/apps/kort/views.py
+++ b/aleksis/apps/kort/views.py
@@ -24,7 +24,7 @@ from aleksis.apps.kort.forms import (
     CardPrinterForm,
     PrinterSelectForm,
 )
-from aleksis.apps.kort.models import Card, CardLayout, CardPrinter, PrintStatus
+from aleksis.apps.kort.models import Card, CardLayout, CardPrinter, CardPrintJob, PrintStatus
 from aleksis.apps.kort.tables import (
     CardLayoutTable,
     CardPrinterTable,
@@ -209,6 +209,16 @@ class CardDetailView(PermissionRequiredMixin, RevisionMixin, PrinterSelectMixin,
     template_name = "kort/card/detail.html"
 
 
+class CardPreviewView(PermissionRequiredMixin, DetailView):
+    permission_required = "kort.view_card_rule"
+    model = Card
+
+    def get(self, *args, **kwargs):
+        self.object = self.get_object()
+        html = self.object.layout.render(self.object)
+        return HttpResponse(html)
+
+
 class CardGeneratePDFView(PermissionRequiredMixin, RevisionMixin, SingleObjectMixin, View):
     permission_required = "views.edit_card_rule"
     model = Card
@@ -216,10 +226,6 @@ class CardGeneratePDFView(PermissionRequiredMixin, RevisionMixin, SingleObjectMi
     def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
         self.object = self.get_object()
 
-        if not self.object.chip_number:
-            messages.error(request, _("The chip number is missing."))
-            return redirect("cards")
-
         redirect_url = f"/app/kort/cards/{self.object.pk}/"
         result = self.object.generate_pdf()
 
@@ -301,6 +307,16 @@ class CardPrinterDeleteView(PermissionRequiredMixin, RevisionMixin, AdvancedDele
     success_message = _("The card printer has been deleted successfully.")
 
 
+class CardPrintJobDeleteView(PermissionRequiredMixin, RevisionMixin, AdvancedDeleteView):
+    """View used to delete a card print job."""
+
+    permission_required = "kort.delete_cardprintjob_rule"
+    success_url = reverse_lazy("card_printers")
+    template_name = "kort/printer/print_job_delete.html"
+    model = CardPrintJob
+    success_message = _("The card print job has been deleted successfully.")
+
+
 class CardPrinterDetailView(PermissionRequiredMixin, RevisionMixin, DetailView):
     permission_required = "kort.view_cardprinter_rule"
     model = CardPrinter
@@ -323,7 +339,7 @@ class CardLayoutFormMixin:
 
     def post(self, request, *args, **kwargs):
         self.object = self.get_object()
-        context = self.get_context_data(**kwargs)
+        self.get_context_data(**kwargs)
         form = self.get_form()
         if form.is_valid() and self.formset.is_valid():
             return self.form_valid(form)
diff --git a/pyproject.toml b/pyproject.toml
index 363537fd92a231debca33c9806065e776d2a4b00..59abf435471681bfbec36ecc31bbc3e0075cf1f8 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -34,8 +34,8 @@ url = "https://edugit.org/api/v4/projects/461/packages/pypi/simple"
 priority = "supplemental"
 
 [tool.poetry.dependencies]
-python = "^3.9"
-aleksis-core = "^4.0.0.dev0"
+python = "^3.10"
+aleksis-core = "^4.0.0.dev3"
 python-barcode = "^0.15.0"
 django-formtools = "2.2"
 django-ace = "^1.0.12"
@@ -47,23 +47,9 @@ kort = "aleksis.apps.kort.apps:DefaultConfig"
 
 [tool.poetry.group.dev.dependencies]
 django-stubs = "^4.2"
-
 safety = "^2.3.5"
 
-flake8 = "^6.0.0"
-flake8-django = "^1.0.0"
-flake8-fixme = "^1.1.1"
-flake8-mypy = "^17.8.0"
-flake8-bandit = "^4.1.1"
-flake8-builtins = "^2.0.0"
-flake8-docstrings = "^1.5.0"
-flake8-rst-docstrings = "^0.3.0"
-
-black = ">=21.0"
-flake8-black = "^0.3.0"
-
-isort = "^5.0.0"
-flake8-isort = "^6.0.0"
+ruff = "^0.1.5"
 
 curlylint = "^0.13.0"
 
@@ -86,10 +72,6 @@ sphinxcontrib-svg2pdfconverter = "^1.1.1"
 sphinx-autodoc-typehints = "^1.7"
 sphinx_material = "^0.0.35"
 
-[tool.black]
-line-length = 100
-exclude = "/migrations/"
-
 [tool.curlylint]
 include = '\.html'
 
@@ -102,6 +84,21 @@ meta_viewport = true
 no_autofocus = true
 tabindex_no_positive = true
 
+[tool.ruff]
+exclude = ["migrations", "tests"]
+line-length = 100
+
+[tool.ruff.lint]
+select = ["E", "F", "UP", "B", "SIM", "I", "DJ", "A", "S"]
+ignore = ["UP034", "UP015", "B028"]
+
+[tool.ruff.isort]
+known-first-party = ["aleksis"]
+section-order = ["future", "standard-library", "django", "third-party", "first-party", "local-folder"]
+
+[tool.ruff.isort.sections]
+django = ["django"]
+
 [build-system]
 requires = ["poetry-core>=1.0.0"]
 build-backend = "poetry.core.masonry.api"
diff --git a/tox.ini b/tox.ini
index 6e4b77ab1ded935257117696975c2150772cd85c..294e65bc96d4e06262b67e3e6b8a987307b226e4 100644
--- a/tox.ini
+++ b/tox.ini
@@ -4,11 +4,12 @@ skip_missing_interpreters = true
 envlist = py39,py310,py311
 
 [testenv]
-whitelist_externals = poetry
+allowlist_externals =
+    poetry
+    yarnpkg
 skip_install = true
-envdir = {toxworkdir}/globalenv
 commands_pre =
-     poetry install
+     poetry install --all-extras
      poetry run aleksis-admin vite build
      poetry run aleksis-admin collectstatic --no-input
 commands =
@@ -22,14 +23,17 @@ setenv =
     TEST_HOST = {env:TEST_HOST:172.17.0.1}
 
 [testenv:lint]
+commands_pre =
+    poetry install --only=dev
+    yarnpkg --cwd=.dev-js
 commands =
-    poetry run black --check --diff aleksis/
-    poetry run isort -c --diff --stdout aleksis/
-    poetry run flake8 {posargs} aleksis/
-    poetry run sh -c "aleksis-admin yarn run prettier --check --ignore-path={toxinidir}/.prettierignore {toxinidir}"
-    poetry run sh -c "aleksis-admin yarn run eslint {toxinidir}/aleksis/**/*/frontend/**/*.{js,vue} --config={toxinidir}/.eslintrc.js --resolve-plugins-relative-to=."
+    poetry run ruff check {posargs} aleksis/
+    yarnpkg --cwd=.dev-js run prettier --ignore-path={toxinidir}/.prettierignore {posargs} --check ..
+    yarnpkg --cwd=.dev-js run eslint ../aleksis/**/*/frontend/**/*.{js,vue} --config={toxinidir}/.eslintrc.js --resolve-plugins-relative-to=.
 
 [testenv:security]
+commands_pre =
+    poetry install --all-extras
 commands =
     poetry show --no-dev
     poetry run safety check --full-report
@@ -41,45 +45,25 @@ commands_pre =
 commands = poetry build
 
 [testenv:docs]
+commands_pre =
+    poetry install --with docs
 commands = poetry run make -C docs/ html {posargs}
 
 [testenv:reformat]
+commands_pre =
+    poetry install --only=dev
+    yarnpkg --cwd=.dev-js
 commands =
-    poetry run isort aleksis/
-    poetry run black aleksis/
-    poetry run sh -c "aleksis-admin yarn run prettier --write --ignore-path={toxinidir}/.prettierignore {toxinidir}"
+    poetry run ruff format aleksis/
+    yarnpkg --cwd=.dev-js run prettier --ignore-path={toxinidir}/.prettierignore --write ..
 
 [testenv:makemessages]
+commands_pre =
+    poetry install
 commands =
     poetry run aleksis-admin makemessages --no-wrap -e html,txt,py,email -i static -l ar -l de_DE -l fr -l nb_NO -l tr_TR -l la -l uk -l ru
     poetry run aleksis-admin makemessages --no-wrap -d djangojs -i **/node_modules -l ar -l de_DE -l fr -l nb_NO -l tr_TR -l la -l uk -l ru
 
-[flake8]
-max_line_length = 100
-exclude = migrations,tests
-ignore = BLK100,E203,E231,W503,D100,D101,D102,D103,D104,D105,D106,D107,RST215,RST214,F821,F841,S106,T100,T101,DJ05
-
-[isort]
-profile = black
-line_length = 100
-default_section = THIRDPARTY
-known_first_party = aleksis
-known_django = django
-skip = migrations
-sections = FUTURE,STDLIB,DJANGO,THIRDPARTY,FIRSTPARTY,LOCALFOLDER
-
-[mypy]
-plugins = mypy_django_plugin.main
-python_version = 3.8
-platform = linux
-show_column_numbers = True
-follow_imports = skip
-ignore_missing_imports = True
-cache_dir = /dev/null
-
-[mypy.plugins.django-stubs]
-django_settings_module = aleksis.core.settings
-
 [pytest]
 DJANGO_SETTINGS_MODULE = aleksis.core.settings
 junit_family = legacy