iil-doc-templates 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- iil_doc_templates-0.1.0/.gitignore +50 -0
- iil_doc_templates-0.1.0/PKG-INFO +111 -0
- iil_doc_templates-0.1.0/README.md +86 -0
- iil_doc_templates-0.1.0/doc_templates/__init__.py +11 -0
- iil_doc_templates-0.1.0/doc_templates/admin.py +22 -0
- iil_doc_templates-0.1.0/doc_templates/apps.py +9 -0
- iil_doc_templates-0.1.0/doc_templates/models.py +156 -0
- iil_doc_templates-0.1.0/doc_templates/templates/doc_templates/create.html +48 -0
- iil_doc_templates-0.1.0/doc_templates/templates/doc_templates/edit.html +379 -0
- iil_doc_templates-0.1.0/doc_templates/templates/doc_templates/instance_create.html +42 -0
- iil_doc_templates-0.1.0/doc_templates/templates/doc_templates/instance_edit.html +237 -0
- iil_doc_templates-0.1.0/doc_templates/templates/doc_templates/list.html +145 -0
- iil_doc_templates-0.1.0/doc_templates/templates/doc_templates/upload.html +57 -0
- iil_doc_templates-0.1.0/doc_templates/urls.py +26 -0
- iil_doc_templates-0.1.0/doc_templates/views.py +674 -0
- iil_doc_templates-0.1.0/pyproject.toml +37 -0
- iil_doc_templates-0.1.0/tests/__init__.py +0 -0
- iil_doc_templates-0.1.0/tests/settings.py +18 -0
- iil_doc_templates-0.1.0/tests/test_models.py +132 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*\.class
|
|
5
|
+
.venv/
|
|
6
|
+
venv/
|
|
7
|
+
*.egg-info/
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
# Django
|
|
11
|
+
*.log
|
|
12
|
+
db.sqlite3
|
|
13
|
+
media/
|
|
14
|
+
staticfiles/
|
|
15
|
+
# Environment
|
|
16
|
+
.env
|
|
17
|
+
.env.local
|
|
18
|
+
.env.prod
|
|
19
|
+
|
|
20
|
+
# Secrets (ADR-045) — NEVER commit plaintext
|
|
21
|
+
secrets.env
|
|
22
|
+
!secrets.enc.env
|
|
23
|
+
# IDE
|
|
24
|
+
.idea/
|
|
25
|
+
.vscode/
|
|
26
|
+
*.swp
|
|
27
|
+
# OS
|
|
28
|
+
.DS_Store
|
|
29
|
+
Thumbs.db
|
|
30
|
+
# Large files
|
|
31
|
+
*.sqlite3
|
|
32
|
+
*.log
|
|
33
|
+
output_batch/
|
|
34
|
+
app_backup/
|
|
35
|
+
docs_legacy/
|
|
36
|
+
# Sphinx build output
|
|
37
|
+
docs/_build/
|
|
38
|
+
*:Zone.Identifier
|
|
39
|
+
# Local Windsurf/MCP config — machine-specific, never commit
|
|
40
|
+
.windsurf/mcp_config.json
|
|
41
|
+
# Local infra plaintext secrets — NEVER commit
|
|
42
|
+
infra/*.env
|
|
43
|
+
infra/*.key
|
|
44
|
+
# Validate-ports CI draft (not yet integrated)
|
|
45
|
+
.github/workflows/validate-ports.yml
|
|
46
|
+
# Markdownlint local config override
|
|
47
|
+
.markdownlint.json
|
|
48
|
+
# Concept review drafts (local working copies, not for VCS)
|
|
49
|
+
docs/concepts/REVIEW-*
|
|
50
|
+
env_loader.py
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: iil-doc-templates
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Reusable Django document template system — create, edit, fill templates with PDF extraction and LLM prefill
|
|
5
|
+
Author-email: Achim Dehnert <achim.dehnert@iil.gmbh>
|
|
6
|
+
License-Expression: LicenseRef-Proprietary
|
|
7
|
+
Requires-Python: >=3.10
|
|
8
|
+
Requires-Dist: django>=4.2
|
|
9
|
+
Requires-Dist: iil-concept-templates>=0.4.0
|
|
10
|
+
Provides-Extra: all
|
|
11
|
+
Requires-Dist: iil-aifw>=0.5.0; extra == 'all'
|
|
12
|
+
Requires-Dist: iil-django-tenancy>=0.3.0; extra == 'all'
|
|
13
|
+
Requires-Dist: pdfplumber>=0.10; extra == 'all'
|
|
14
|
+
Provides-Extra: dev
|
|
15
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
16
|
+
Requires-Dist: pytest-django; extra == 'dev'
|
|
17
|
+
Requires-Dist: ruff; extra == 'dev'
|
|
18
|
+
Provides-Extra: llm
|
|
19
|
+
Requires-Dist: iil-aifw>=0.5.0; extra == 'llm'
|
|
20
|
+
Provides-Extra: pdf
|
|
21
|
+
Requires-Dist: pdfplumber>=0.10; extra == 'pdf'
|
|
22
|
+
Provides-Extra: tenancy
|
|
23
|
+
Requires-Dist: iil-django-tenancy>=0.3.0; extra == 'tenancy'
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# iil-doc-templates
|
|
27
|
+
|
|
28
|
+
Reusable Django document template system — create, edit, fill templates with PDF extraction and LLM prefill.
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install iil-doc-templates
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
With optional dependencies:
|
|
37
|
+
```bash
|
|
38
|
+
pip install iil-doc-templates[pdf] # pdfplumber for PDF extraction
|
|
39
|
+
pip install iil-doc-templates[llm] # iil-aifw for LLM prefill
|
|
40
|
+
pip install iil-doc-templates[all] # everything
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Quick Start
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
# settings.py
|
|
47
|
+
INSTALLED_APPS = [
|
|
48
|
+
...
|
|
49
|
+
"doc_templates",
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
# urls.py
|
|
53
|
+
path("doc-templates/", include("doc_templates.urls")),
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Then run migrations:
|
|
57
|
+
```bash
|
|
58
|
+
python manage.py migrate doc_templates
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Features
|
|
62
|
+
|
|
63
|
+
- **DocumentTemplate** — Reusable document templates with JSON structure (sections + fields)
|
|
64
|
+
- **DocumentInstance** — Filled-out documents based on templates
|
|
65
|
+
- **PDF Upload** — Extract structure from PDF using `iil-concept-templates`
|
|
66
|
+
- **Interactive Editor** — Drag & drop sections, CRUD fields, table columns
|
|
67
|
+
- **LLM Prefill** — AI-powered field completion via `iil-aifw`
|
|
68
|
+
- **PDF Export** — Generate PDF from filled documents via `concept_templates.document_renderer`
|
|
69
|
+
- **Multi-Tenant** — All queries filter by `tenant_id`
|
|
70
|
+
|
|
71
|
+
## Architecture
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
iil-concept-templates (Pure Python) iil-doc-templates (Django)
|
|
75
|
+
├── Pydantic Schemas ├── Django Models
|
|
76
|
+
├── PDF Structure Extraction ──► ├── CRUD Views + URLs
|
|
77
|
+
├── Analysis, Prefill, Export ├── HTML Templates (6)
|
|
78
|
+
└── No Django dependency ├── Admin Integration
|
|
79
|
+
└── Uses concept_templates internally
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Field Types
|
|
83
|
+
|
|
84
|
+
| Type | Description |
|
|
85
|
+
|------|-------------|
|
|
86
|
+
| `textarea` | Multi-line text (default) |
|
|
87
|
+
| `text` | Single-line text |
|
|
88
|
+
| `number` | Numeric input |
|
|
89
|
+
| `date` | Date picker |
|
|
90
|
+
| `boolean` | Yes/No toggle |
|
|
91
|
+
| `table` | Table with configurable columns |
|
|
92
|
+
|
|
93
|
+
## URL Patterns
|
|
94
|
+
|
|
95
|
+
| URL | View | Description |
|
|
96
|
+
|-----|------|-------------|
|
|
97
|
+
| `/` | `template-list` | List all templates + instances |
|
|
98
|
+
| `/create/` | `template-create` | Create empty template |
|
|
99
|
+
| `/upload/` | `template-upload` | Create template from PDF |
|
|
100
|
+
| `/<pk>/edit/` | `template-edit` | Interactive template editor |
|
|
101
|
+
| `/<pk>/delete/` | `template-delete` | Delete template |
|
|
102
|
+
| `/<pk>/instance/create/` | `instance-create` | Create document from template |
|
|
103
|
+
| `/instance/<pk>/edit/` | `instance-edit` | Edit document fields |
|
|
104
|
+
| `/instance/<pk>/delete/` | `instance-delete` | Delete document |
|
|
105
|
+
| `/instance/<pk>/prefill/` | `instance-prefill` | LLM prefill endpoint |
|
|
106
|
+
| `/instance/<pk>/pdf/` | `instance-pdf` | PDF export |
|
|
107
|
+
|
|
108
|
+
## Dependencies
|
|
109
|
+
|
|
110
|
+
- **Required**: Django ≥ 4.2, iil-concept-templates ≥ 0.4.0
|
|
111
|
+
- **Optional**: pdfplumber (PDF extraction), iil-aifw (LLM prefill)
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# iil-doc-templates
|
|
2
|
+
|
|
3
|
+
Reusable Django document template system — create, edit, fill templates with PDF extraction and LLM prefill.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install iil-doc-templates
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
With optional dependencies:
|
|
12
|
+
```bash
|
|
13
|
+
pip install iil-doc-templates[pdf] # pdfplumber for PDF extraction
|
|
14
|
+
pip install iil-doc-templates[llm] # iil-aifw for LLM prefill
|
|
15
|
+
pip install iil-doc-templates[all] # everything
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
```python
|
|
21
|
+
# settings.py
|
|
22
|
+
INSTALLED_APPS = [
|
|
23
|
+
...
|
|
24
|
+
"doc_templates",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
# urls.py
|
|
28
|
+
path("doc-templates/", include("doc_templates.urls")),
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Then run migrations:
|
|
32
|
+
```bash
|
|
33
|
+
python manage.py migrate doc_templates
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Features
|
|
37
|
+
|
|
38
|
+
- **DocumentTemplate** — Reusable document templates with JSON structure (sections + fields)
|
|
39
|
+
- **DocumentInstance** — Filled-out documents based on templates
|
|
40
|
+
- **PDF Upload** — Extract structure from PDF using `iil-concept-templates`
|
|
41
|
+
- **Interactive Editor** — Drag & drop sections, CRUD fields, table columns
|
|
42
|
+
- **LLM Prefill** — AI-powered field completion via `iil-aifw`
|
|
43
|
+
- **PDF Export** — Generate PDF from filled documents via `concept_templates.document_renderer`
|
|
44
|
+
- **Multi-Tenant** — All queries filter by `tenant_id`
|
|
45
|
+
|
|
46
|
+
## Architecture
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
iil-concept-templates (Pure Python) iil-doc-templates (Django)
|
|
50
|
+
├── Pydantic Schemas ├── Django Models
|
|
51
|
+
├── PDF Structure Extraction ──► ├── CRUD Views + URLs
|
|
52
|
+
├── Analysis, Prefill, Export ├── HTML Templates (6)
|
|
53
|
+
└── No Django dependency ├── Admin Integration
|
|
54
|
+
└── Uses concept_templates internally
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Field Types
|
|
58
|
+
|
|
59
|
+
| Type | Description |
|
|
60
|
+
|------|-------------|
|
|
61
|
+
| `textarea` | Multi-line text (default) |
|
|
62
|
+
| `text` | Single-line text |
|
|
63
|
+
| `number` | Numeric input |
|
|
64
|
+
| `date` | Date picker |
|
|
65
|
+
| `boolean` | Yes/No toggle |
|
|
66
|
+
| `table` | Table with configurable columns |
|
|
67
|
+
|
|
68
|
+
## URL Patterns
|
|
69
|
+
|
|
70
|
+
| URL | View | Description |
|
|
71
|
+
|-----|------|-------------|
|
|
72
|
+
| `/` | `template-list` | List all templates + instances |
|
|
73
|
+
| `/create/` | `template-create` | Create empty template |
|
|
74
|
+
| `/upload/` | `template-upload` | Create template from PDF |
|
|
75
|
+
| `/<pk>/edit/` | `template-edit` | Interactive template editor |
|
|
76
|
+
| `/<pk>/delete/` | `template-delete` | Delete template |
|
|
77
|
+
| `/<pk>/instance/create/` | `instance-create` | Create document from template |
|
|
78
|
+
| `/instance/<pk>/edit/` | `instance-edit` | Edit document fields |
|
|
79
|
+
| `/instance/<pk>/delete/` | `instance-delete` | Delete document |
|
|
80
|
+
| `/instance/<pk>/prefill/` | `instance-prefill` | LLM prefill endpoint |
|
|
81
|
+
| `/instance/<pk>/pdf/` | `instance-pdf` | PDF export |
|
|
82
|
+
|
|
83
|
+
## Dependencies
|
|
84
|
+
|
|
85
|
+
- **Required**: Django ≥ 4.2, iil-concept-templates ≥ 0.4.0
|
|
86
|
+
- **Optional**: pdfplumber (PDF extraction), iil-aifw (LLM prefill)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""iil-doc-templates — Reusable Django document template system.
|
|
2
|
+
|
|
3
|
+
Provides DocumentTemplate + DocumentInstance models, CRUD views,
|
|
4
|
+
interactive template editor, PDF extraction, and LLM prefill.
|
|
5
|
+
|
|
6
|
+
Uses iil-concept-templates for schemas and PDF structure extraction.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__version__ = "0.1.0"
|
|
10
|
+
|
|
11
|
+
default_app_config = "doc_templates.apps.DocTemplatesConfig"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Admin registration for doc_templates."""
|
|
2
|
+
|
|
3
|
+
from django.contrib import admin
|
|
4
|
+
|
|
5
|
+
from .models import DocumentInstance, DocumentTemplate
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@admin.register(DocumentTemplate)
|
|
9
|
+
class DocumentTemplateAdmin(admin.ModelAdmin):
|
|
10
|
+
list_display = ["name", "scope", "status", "section_count", "field_count", "updated_at"]
|
|
11
|
+
list_filter = ["status", "scope"]
|
|
12
|
+
search_fields = ["name", "description"]
|
|
13
|
+
readonly_fields = ["uuid", "created_at", "updated_at"]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@admin.register(DocumentInstance)
|
|
17
|
+
class DocumentInstanceAdmin(admin.ModelAdmin):
|
|
18
|
+
list_display = ["name", "template", "status", "updated_at"]
|
|
19
|
+
list_filter = ["status"]
|
|
20
|
+
search_fields = ["name"]
|
|
21
|
+
readonly_fields = ["uuid", "created_at", "updated_at"]
|
|
22
|
+
raw_id_fields = ["template"]
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"""Document template models (generalized from ExDocTemplate/ExDocInstance)."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import uuid
|
|
5
|
+
|
|
6
|
+
from django.db import models
|
|
7
|
+
|
|
8
|
+
# Graceful import for TenantManager
|
|
9
|
+
try:
|
|
10
|
+
from django_tenancy.managers import TenantManager
|
|
11
|
+
except ImportError:
|
|
12
|
+
TenantManager = models.Manager
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class DocumentTemplate(models.Model):
|
|
16
|
+
"""Wiederverwendbare Dokumentvorlage (modulübergreifend).
|
|
17
|
+
|
|
18
|
+
Struktur als JSON:
|
|
19
|
+
{
|
|
20
|
+
"sections": [
|
|
21
|
+
{
|
|
22
|
+
"key": "section_1",
|
|
23
|
+
"label": "1. Allgemeines",
|
|
24
|
+
"fields": [
|
|
25
|
+
{"key": "inhalt", "label": "Inhalt", "type": "textarea"}
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
class Status(models.TextChoices):
|
|
33
|
+
DRAFT = "draft", "Entwurf"
|
|
34
|
+
ACCEPTED = "accepted", "Akzeptiert"
|
|
35
|
+
ARCHIVED = "archived", "Archiviert"
|
|
36
|
+
|
|
37
|
+
uuid = models.UUIDField(default=uuid.uuid4, unique=True, editable=False)
|
|
38
|
+
tenant_id = models.UUIDField(db_index=True)
|
|
39
|
+
name = models.CharField(max_length=255)
|
|
40
|
+
description = models.TextField(blank=True, default="")
|
|
41
|
+
scope = models.CharField(
|
|
42
|
+
max_length=50, blank=True, default="",
|
|
43
|
+
help_text="Fachbereich, z.B. explosionsschutz, brandschutz, gbu, risk",
|
|
44
|
+
)
|
|
45
|
+
structure_json = models.TextField(
|
|
46
|
+
default='{"sections": []}',
|
|
47
|
+
help_text="Template-Struktur als JSON",
|
|
48
|
+
)
|
|
49
|
+
status = models.CharField(
|
|
50
|
+
max_length=20, choices=Status.choices, default=Status.DRAFT,
|
|
51
|
+
)
|
|
52
|
+
source_filename = models.CharField(max_length=255, blank=True, default="")
|
|
53
|
+
source_text = models.TextField(blank=True, default="")
|
|
54
|
+
|
|
55
|
+
created_at = models.DateTimeField(auto_now_add=True)
|
|
56
|
+
updated_at = models.DateTimeField(auto_now=True)
|
|
57
|
+
|
|
58
|
+
objects = TenantManager()
|
|
59
|
+
|
|
60
|
+
class Meta:
|
|
61
|
+
db_table = "doc_template"
|
|
62
|
+
verbose_name = "Dokumentvorlage"
|
|
63
|
+
verbose_name_plural = "Dokumentvorlagen"
|
|
64
|
+
ordering = ["-updated_at"]
|
|
65
|
+
indexes = [
|
|
66
|
+
models.Index(fields=["tenant_id", "status"], name="ix_doctmpl_tenant_st"),
|
|
67
|
+
models.Index(fields=["tenant_id", "scope"], name="ix_doctmpl_tenant_scope"),
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
def __str__(self) -> str:
|
|
71
|
+
return f"{self.name} ({self.get_status_display()})"
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def section_count(self) -> int:
|
|
75
|
+
try:
|
|
76
|
+
data = json.loads(self.structure_json)
|
|
77
|
+
return len(data.get("sections", []))
|
|
78
|
+
except (json.JSONDecodeError, TypeError):
|
|
79
|
+
return 0
|
|
80
|
+
|
|
81
|
+
@property
|
|
82
|
+
def field_count(self) -> int:
|
|
83
|
+
try:
|
|
84
|
+
data = json.loads(self.structure_json)
|
|
85
|
+
return sum(len(s.get("fields", [])) for s in data.get("sections", []))
|
|
86
|
+
except (json.JSONDecodeError, TypeError):
|
|
87
|
+
return 0
|
|
88
|
+
|
|
89
|
+
def get_structure(self) -> dict:
|
|
90
|
+
"""Parse and return structure from JSON."""
|
|
91
|
+
try:
|
|
92
|
+
return json.loads(self.structure_json)
|
|
93
|
+
except (json.JSONDecodeError, TypeError):
|
|
94
|
+
return {"sections": []}
|
|
95
|
+
|
|
96
|
+
def get_sections(self) -> list[dict]:
|
|
97
|
+
"""Return sections list from structure."""
|
|
98
|
+
return self.get_structure().get("sections", [])
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class DocumentInstance(models.Model):
|
|
102
|
+
"""Ausgefülltes Dokument basierend auf einem Template.
|
|
103
|
+
|
|
104
|
+
Werte als JSON:
|
|
105
|
+
{
|
|
106
|
+
"section_1": {
|
|
107
|
+
"inhalt": "Dieses Dokument..."
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
"""
|
|
111
|
+
|
|
112
|
+
class Status(models.TextChoices):
|
|
113
|
+
DRAFT = "draft", "Entwurf"
|
|
114
|
+
REVIEW = "review", "In Prüfung"
|
|
115
|
+
APPROVED = "approved", "Freigegeben"
|
|
116
|
+
|
|
117
|
+
uuid = models.UUIDField(default=uuid.uuid4, unique=True, editable=False)
|
|
118
|
+
tenant_id = models.UUIDField(db_index=True)
|
|
119
|
+
template = models.ForeignKey(
|
|
120
|
+
DocumentTemplate, on_delete=models.PROTECT, related_name="instances",
|
|
121
|
+
)
|
|
122
|
+
name = models.CharField(max_length=255)
|
|
123
|
+
values_json = models.TextField(
|
|
124
|
+
default="{}", help_text="Ausgefüllte Werte als JSON",
|
|
125
|
+
)
|
|
126
|
+
status = models.CharField(
|
|
127
|
+
max_length=20, choices=Status.choices, default=Status.DRAFT,
|
|
128
|
+
)
|
|
129
|
+
source_filename = models.CharField(
|
|
130
|
+
max_length=255, blank=True, default="",
|
|
131
|
+
help_text="Dateiname des importierten Dokuments",
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
created_at = models.DateTimeField(auto_now_add=True)
|
|
135
|
+
updated_at = models.DateTimeField(auto_now=True)
|
|
136
|
+
|
|
137
|
+
objects = TenantManager()
|
|
138
|
+
|
|
139
|
+
class Meta:
|
|
140
|
+
db_table = "doc_instance"
|
|
141
|
+
verbose_name = "Dokument"
|
|
142
|
+
verbose_name_plural = "Dokumente"
|
|
143
|
+
ordering = ["-updated_at"]
|
|
144
|
+
indexes = [
|
|
145
|
+
models.Index(fields=["tenant_id", "status"], name="ix_docinst_tenant_st"),
|
|
146
|
+
]
|
|
147
|
+
|
|
148
|
+
def __str__(self) -> str:
|
|
149
|
+
return f"{self.name} ({self.get_status_display()})"
|
|
150
|
+
|
|
151
|
+
def get_values(self) -> dict:
|
|
152
|
+
"""Parse and return values from JSON."""
|
|
153
|
+
try:
|
|
154
|
+
return json.loads(self.values_json)
|
|
155
|
+
except (json.JSONDecodeError, TypeError):
|
|
156
|
+
return {}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{% extends "base.html" %}
|
|
2
|
+
{% block title %}Leere Vorlage erstellen{% endblock %}
|
|
3
|
+
|
|
4
|
+
{% block content %}
|
|
5
|
+
<div class="max-w-2xl mx-auto px-4 py-8">
|
|
6
|
+
|
|
7
|
+
<div class="flex items-center space-x-4 mb-6">
|
|
8
|
+
<a href="{% url 'doc_templates:template-list' %}" class="text-gray-400 hover:text-gray-600">←</a>
|
|
9
|
+
<h1 class="text-2xl font-bold text-gray-900">Leere Vorlage erstellen</h1>
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
<div class="bg-white rounded-xl border border-gray-200 p-6">
|
|
13
|
+
<form method="post" class="space-y-4">
|
|
14
|
+
{% csrf_token %}
|
|
15
|
+
<div>
|
|
16
|
+
<label class="block text-sm font-medium text-gray-700 mb-1">Name der Vorlage *</label>
|
|
17
|
+
<input type="text" name="name" required placeholder="z.B. Explosionsschutzdokument nach TRBS 2152"
|
|
18
|
+
class="w-full rounded-lg border-gray-300 text-sm focus:border-blue-500 focus:ring-blue-500">
|
|
19
|
+
</div>
|
|
20
|
+
<div>
|
|
21
|
+
<label class="block text-sm font-medium text-gray-700 mb-1">Fachbereich</label>
|
|
22
|
+
<input type="text" name="scope" list="scope-options" placeholder="z.B. explosionsschutz, brandschutz, gbu"
|
|
23
|
+
class="w-full rounded-lg border-gray-300 text-sm focus:border-blue-500 focus:ring-blue-500">
|
|
24
|
+
<datalist id="scope-options">
|
|
25
|
+
<option value="explosionsschutz">
|
|
26
|
+
<option value="brandschutz">
|
|
27
|
+
<option value="gbu">
|
|
28
|
+
<option value="betriebsanweisung">
|
|
29
|
+
<option value="risk">
|
|
30
|
+
</datalist>
|
|
31
|
+
</div>
|
|
32
|
+
<div>
|
|
33
|
+
<label class="block text-sm font-medium text-gray-700 mb-1">Beschreibung (optional)</label>
|
|
34
|
+
<textarea name="description" rows="2"
|
|
35
|
+
class="w-full rounded-lg border-gray-300 text-sm focus:border-blue-500 focus:ring-blue-500"
|
|
36
|
+
placeholder="Kurze Beschreibung..."></textarea>
|
|
37
|
+
</div>
|
|
38
|
+
<div class="flex justify-end gap-3 pt-2">
|
|
39
|
+
<a href="{% url 'doc_templates:template-list' %}" class="px-4 py-2 text-sm text-gray-500 hover:text-gray-700">Abbrechen</a>
|
|
40
|
+
<button type="submit" class="px-5 py-2.5 bg-blue-600 text-white rounded-lg hover:bg-blue-700 text-sm font-medium">
|
|
41
|
+
Vorlage erstellen
|
|
42
|
+
</button>
|
|
43
|
+
</div>
|
|
44
|
+
</form>
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
</div>
|
|
48
|
+
{% endblock %}
|