assemblerpdf 1.0.0__tar.gz → 1.0.2__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.
Files changed (100) hide show
  1. {assemblerpdf-1.0.0/src/assemblerpdf.egg-info → assemblerpdf-1.0.2}/PKG-INFO +1 -1
  2. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/pyproject.toml +2 -1
  3. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/__init__.py +6 -0
  4. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/assemblers/base.py +45 -8
  5. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/core.py +20 -1
  6. assemblerpdf-1.0.2/src/assemblerpdf/templates/assemblerpdf/fields/checkbox.html +16 -0
  7. assemblerpdf-1.0.2/src/assemblerpdf/templates/assemblerpdf/fields/input.html +12 -0
  8. assemblerpdf-1.0.2/src/assemblerpdf/templates/assemblerpdf/fields/radio.html +14 -0
  9. assemblerpdf-1.0.2/src/assemblerpdf/templates/assemblerpdf/fields/textarea.html +12 -0
  10. {assemblerpdf-1.0.0/src/assemblerpdf/templates/assemblerpdf → assemblerpdf-1.0.2/src/assemblerpdf/templates/assemblerpdf/layout}/footer.html +1 -1
  11. assemblerpdf-1.0.2/src/assemblerpdf/templates/assemblerpdf/layout/footer_fixed.html +16 -0
  12. assemblerpdf-1.0.2/src/assemblerpdf/templates/assemblerpdf/layout/grid_row.html +7 -0
  13. assemblerpdf-1.0.2/src/assemblerpdf/templates/assemblerpdf/layout/header.html +19 -0
  14. assemblerpdf-1.0.2/src/assemblerpdf/templates/assemblerpdf/layout/section.html +6 -0
  15. {assemblerpdf-1.0.0/src/assemblerpdf/templates/assemblerpdf → assemblerpdf-1.0.2/src/assemblerpdf/templates/assemblerpdf/layout}/style.html +48 -3
  16. assemblerpdf-1.0.2/src/assemblerpdf/templates/assemblerpdf/misc/signature.html +14 -0
  17. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/utils/template_loader.py +25 -5
  18. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2/src/assemblerpdf.egg-info}/PKG-INFO +1 -1
  19. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf.egg-info/SOURCES.txt +11 -10
  20. assemblerpdf-1.0.0/src/assemblerpdf/templates/assemblerpdf/checkbox.html +0 -16
  21. assemblerpdf-1.0.0/src/assemblerpdf/templates/assemblerpdf/grid_row.html +0 -7
  22. assemblerpdf-1.0.0/src/assemblerpdf/templates/assemblerpdf/header.html +0 -19
  23. assemblerpdf-1.0.0/src/assemblerpdf/templates/assemblerpdf/input.html +0 -12
  24. assemblerpdf-1.0.0/src/assemblerpdf/templates/assemblerpdf/radio.html +0 -14
  25. assemblerpdf-1.0.0/src/assemblerpdf/templates/assemblerpdf/section.html +0 -6
  26. assemblerpdf-1.0.0/src/assemblerpdf/templates/assemblerpdf/signature.html +0 -14
  27. assemblerpdf-1.0.0/src/assemblerpdf/templates/assemblerpdf/textarea.html +0 -12
  28. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/MANIFEST.in +0 -0
  29. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/README.md +0 -0
  30. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/setup.cfg +0 -0
  31. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/assemblers/__init__.py +0 -0
  32. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/assemblers/form.py +0 -0
  33. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/assemblers/report.py +0 -0
  34. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/fonts/Inter-Bold.ttf +0 -0
  35. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/fonts/Inter-Medium.ttf +0 -0
  36. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/fonts/Inter-Regular.ttf +0 -0
  37. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/img/Logo-unp-rojo.png +0 -0
  38. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/img/logo-mininterior-rojo.jpg +0 -0
  39. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/anexos.html +0 -0
  40. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/anexos_limpio.html +0 -0
  41. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/archivese.html +0 -0
  42. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/autoriza_envio.html +0 -0
  43. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/checkbox.html +0 -0
  44. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/control_cambios.html +0 -0
  45. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/datos_basicosinf.html +0 -0
  46. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/datos_ot.html +0 -0
  47. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/encaso_de.html +0 -0
  48. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/fiila_dos_check.html +0 -0
  49. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/fila_cinco_zona.html +0 -0
  50. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/fila_cuatro.html +0 -0
  51. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/fila_cuatro_si_no.html +0 -0
  52. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/fila_cuatro_zona.html +0 -0
  53. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/fila_dos.html +0 -0
  54. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/fila_dos_zona.html +0 -0
  55. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/fila_instructivo.html +0 -0
  56. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/fila_tres.html +0 -0
  57. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/fila_tres_checkbox.html +0 -0
  58. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/fila_tres_zona.html +0 -0
  59. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/fila_uno.html +0 -0
  60. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/firma.html +0 -0
  61. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/firma_doble.html +0 -0
  62. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/firmaop2.html +0 -0
  63. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/firmas_oficializacion.html +0 -0
  64. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/hechos_sobrevinientes.html +0 -0
  65. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/hechos_sobrevinientes_vacio.html +0 -0
  66. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/iformfilacuatro.html +0 -0
  67. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/informacion_doble.html +0 -0
  68. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/input_2checks.html +0 -0
  69. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/input_check.html +0 -0
  70. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/input_checkbox.html +0 -0
  71. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/input_solitario.html +0 -0
  72. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/label_input_dos.html +0 -0
  73. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/leyenda_autoriza_correo.html +0 -0
  74. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/leyenda_superiol.html +0 -0
  75. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/logos.html +0 -0
  76. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/manifiesto.html +0 -0
  77. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/notificacion_correo.html +0 -0
  78. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/oficializacion.html +0 -0
  79. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/pregunta_si_no.html +0 -0
  80. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/pregunta_tresopciones.html +0 -0
  81. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/qr_oficializacion.html +0 -0
  82. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/situacion_amenaza.html +0 -0
  83. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/style.html +0 -0
  84. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/subtitulo_icono.html +0 -0
  85. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/subtitulo_icono_largo.html +0 -0
  86. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/tabla_doble.html +0 -0
  87. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/tabla_instructivo.html +0 -0
  88. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/tabla_matriz_riesgo.html +0 -0
  89. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/tabla_proyeccion.html +0 -0
  90. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/tabla_simple.html +0 -0
  91. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/texarea.html +0 -0
  92. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/tipo_identificacion.html +0 -0
  93. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/tipos_checkbox.html +0 -0
  94. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/titulo.html +0 -0
  95. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/titulo_logo.html +0 -0
  96. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/templates/sistema/titulo_principal.html +0 -0
  97. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf/utils/__init__.py +0 -0
  98. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf.egg-info/dependency_links.txt +0 -0
  99. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf.egg-info/requires.txt +0 -0
  100. {assemblerpdf-1.0.0 → assemblerpdf-1.0.2}/src/assemblerpdf.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: assemblerpdf
3
- Version: 1.0.0
3
+ Version: 1.0.2
4
4
  Summary: Generador de PDFs usando WeasyPrint, diseñado para formularios y reportes con componentes genéricos.
5
5
  Author-email: EcosistemaUNP <ecosistema@unp.gov.co>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "assemblerpdf"
7
- version = "1.0.0"
7
+ version = "1.0.2"
8
8
  description = "Generador de PDFs usando WeasyPrint, diseñado para formularios y reportes con componentes genéricos."
9
9
  readme = "README.md"
10
10
  authors = [
@@ -40,6 +40,7 @@ where = ["src"]
40
40
  [tool.setuptools.package-data]
41
41
  assemblerpdf = [
42
42
  "templates/assemblerpdf/*.html",
43
+ "templates/assemblerpdf/*/*.html",
43
44
  "templates/sistema/*.html",
44
45
  "fonts/*.ttf",
45
46
  "img/*.png",
@@ -5,6 +5,9 @@ from .core import (
5
5
  download_inter_font,
6
6
  check_weasyprint_installed
7
7
  )
8
+ from .assemblers.base import BaseFormAssembler
9
+ from .assemblers.form import FormularioReposicionAssembler
10
+ from .assemblers.report import TwoColumnReportAssembler
8
11
 
9
12
  __version__ = "1.0.0"
10
13
  __all__ = [
@@ -13,4 +16,7 @@ __all__ = [
13
16
  "install_dependencies",
14
17
  "download_inter_font",
15
18
  "check_weasyprint_installed",
19
+ "BaseFormAssembler",
20
+ "FormularioReposicionAssembler",
21
+ "TwoColumnReportAssembler",
16
22
  ]
@@ -2,9 +2,15 @@ import os
2
2
  from assemblerpdf.core import generate_pdf_from_string
3
3
 
4
4
  class BaseFormAssembler:
5
- def __init__(self, context=None):
5
+ def __init__(self, context=None, codigo=None, fecha=None, version=None, auto_decorations=True, custom_css_path=None, custom_css_content=None):
6
6
  self.context = context or {}
7
7
  self.components = []
8
+ self.codigo = codigo
9
+ self.fecha = fecha
10
+ self.version = version
11
+ self.auto_decorations = auto_decorations
12
+ self.custom_css_path = custom_css_path
13
+ self.custom_css_content = custom_css_content
8
14
 
9
15
  def _get_img_base(self):
10
16
  import assemblerpdf
@@ -18,6 +24,12 @@ class BaseFormAssembler:
18
24
  # Unificar contexto
19
25
  full_context = {
20
26
  'img_base': self._get_img_base(),
27
+ 'auto_decorations': self.auto_decorations,
28
+ 'codigo': self.codigo,
29
+ 'fecha': self.fecha,
30
+ 'version': self.version,
31
+ 'custom_css_path': self.custom_css_path,
32
+ 'custom_css_content': self.custom_css_content,
21
33
  **self.context,
22
34
  **(extra_context or {})
23
35
  }
@@ -25,12 +37,30 @@ class BaseFormAssembler:
25
37
  # Intentar usar Django primero si está configurado
26
38
  try:
27
39
  from django.template.loader import render_to_string
28
- # Asegurar prefijo de carpeta
29
- if not template_name.startswith("assemblerpdf/"):
30
- django_path = f"assemblerpdf/{template_name}"
40
+ from django.template import TemplateDoesNotExist
41
+
42
+ # Generar candidatos para buscar el template
43
+ posibles_rutas = []
44
+ if "/" not in template_name:
45
+ subcarpetas = ["layout", "fields", "misc"]
46
+ for sub in subcarpetas:
47
+ posibles_rutas.append(f"assemblerpdf/{sub}/{template_name}")
48
+ posibles_rutas.append(f"assemblerpdf/{template_name}")
49
+ posibles_rutas.append(f"sistema/{template_name}")
50
+ posibles_rutas.append(template_name)
31
51
  else:
32
- django_path = template_name
33
- return render_to_string(django_path, full_context)
52
+ posibles_rutas.append(template_name)
53
+ if not template_name.startswith("assemblerpdf/") and not template_name.startswith("sistema/"):
54
+ posibles_rutas.append(f"assemblerpdf/{template_name}")
55
+
56
+ last_error = None
57
+ for ruta in posibles_rutas:
58
+ try:
59
+ return render_to_string(ruta, full_context)
60
+ except TemplateDoesNotExist as e:
61
+ last_error = e
62
+ if last_error:
63
+ raise last_error
34
64
  except Exception:
35
65
  # Fallback a Jinja2
36
66
  from assemblerpdf.utils.template_loader import render_template
@@ -100,9 +130,16 @@ class BaseFormAssembler:
100
130
  head = self._render("style.html")
101
131
 
102
132
  # 2. Combinar componentes
103
- html_completo = "\n".join(self.components)
133
+ componentes_html = list(self.components)
134
+
135
+ # 3. Si está activado auto_decorations, inyectar el pie de página fijo de oficialización
136
+ if self.auto_decorations:
137
+ footer_fixed = self._render("footer_fixed.html")
138
+ componentes_html.append(footer_fixed)
139
+
140
+ html_completo = "\n".join(componentes_html)
104
141
 
105
- # 3. Construir estructura HTML final
142
+ # 4. Construir estructura HTML final
106
143
  html_final = f"""
107
144
  <!DOCTYPE html>
108
145
  <html lang="es">
@@ -148,7 +148,26 @@ def generate_pdf(template_name, context=None, output_path=None):
148
148
  # Intentar usar Django primero si está configurado en el proyecto
149
149
  try:
150
150
  from django.template.loader import render_to_string
151
- html = render_to_string(f'assemblerpdf/{template_name}', context)
151
+ from django.template import TemplateDoesNotExist
152
+
153
+ posibles_rutas = []
154
+ if "/" not in template_name:
155
+ posibles_rutas.append(f"assemblerpdf/{template_name}")
156
+ posibles_rutas.append(f"sistema/{template_name}")
157
+ posibles_rutas.append(template_name)
158
+ else:
159
+ posibles_rutas.append(template_name)
160
+
161
+ html = None
162
+ last_error = None
163
+ for ruta in posibles_rutas:
164
+ try:
165
+ html = render_to_string(ruta, context)
166
+ break
167
+ except TemplateDoesNotExist as e:
168
+ last_error = e
169
+ if html is None:
170
+ raise last_error
152
171
  except Exception:
153
172
  # Fallback a Jinja2 local
154
173
  from assemblerpdf.utils.template_loader import render_template
@@ -0,0 +1,16 @@
1
+ <div class="choice-container {{ class_group|default('') }}" style="margin-bottom: {{ margin_bottom|default('8px') }}; {{ style_group|default('') }}">
2
+ {% if label %}
3
+ <label class="form-label {{ class_label|default('') }}" style="{{ style_label|default('') }}">{{ label }}</label>
4
+ {% endif %}
5
+ <div class="choice-group {{ class_choices|default('') }}" style="{{ style_choices|default('') }}">
6
+ {% for opt in opciones %}
7
+ {% set is_checked = opt.checked or (seleccionado and opt.valor == seleccionado) or (seleccionados and opt.valor in seleccionados) %}
8
+ <div class="choice-item {{ class_item|default('') }}" style="{{ style_item|default('') }}">
9
+ <span class="choice-box {% if is_checked %}checked{% endif %} {{ class_box|default('') }}" style="{{ style_box|default('') }}">
10
+ {% if is_checked %}✓{% endif %}
11
+ </span>
12
+ <span class="{{ class_text|default('') }}" style="{{ style_text|default('') }}">{{ opt.label }}</span>
13
+ </div>
14
+ {% endfor %}
15
+ </div>
16
+ </div>
@@ -0,0 +1,12 @@
1
+ <div class="form-group {{ class_group|default('') }}" style="margin-bottom: {{ margin_bottom|default('8px') }}; {{ style_group|default('') }}">
2
+ {% if label %}
3
+ <label class="form-label {{ class_label|default('') }}" style="{{ style_label|default('') }}">{{ label }}</label>
4
+ {% endif %}
5
+ {% if interactive %}
6
+ <input type="text" class="form-control {{ class_control|default('') }}" name="{{ name }}" value="{{ valor|default('') }}" placeholder="{{ placeholder|default('') }}" {% if disabled %}disabled{% endif %} style="{{ style_control|default('') }}">
7
+ {% else %}
8
+ <div class="form-control-static {{ class_control|default('') }}" style="{{ style_control|default('') }}">
9
+ {{ valor|default('') }}
10
+ </div>
11
+ {% endif %}
12
+ </div>
@@ -0,0 +1,14 @@
1
+ <div class="choice-container {{ class_group|default('') }}" style="margin-bottom: {{ margin_bottom|default('8px') }}; {{ style_group|default('') }}">
2
+ {% if label %}
3
+ <label class="form-label {{ class_label|default('') }}" style="{{ style_label|default('') }}">{{ label }}</label>
4
+ {% endif %}
5
+ <div class="choice-group {{ class_choices|default('') }}" style="{{ style_choices|default('') }}">
6
+ {% for opt in opciones %}
7
+ {% set is_checked = opt.checked or (seleccionado and opt.valor == seleccionado) or (seleccionados and opt.valor in seleccionados) %}
8
+ <div class="choice-item {{ class_item|default('') }}" style="{{ style_item|default('') }}">
9
+ <span class="choice-circle {% if is_checked %}checked{% endif %} {{ class_circle|default('') }}" style="{{ style_circle|default('') }}"></span>
10
+ <span class="{{ class_text|default('') }}" style="{{ style_text|default('') }}">{{ opt.label }}</span>
11
+ </div>
12
+ {% endfor %}
13
+ </div>
14
+ </div>
@@ -0,0 +1,12 @@
1
+ <div class="form-group {{ class_group|default('') }}" style="margin-bottom: {{ margin_bottom|default('8px') }}; {{ style_group|default('') }}">
2
+ {% if label %}
3
+ <label class="form-label {{ class_label|default('') }}" style="{{ style_label|default('') }}">{{ label }}</label>
4
+ {% endif %}
5
+ {% if interactive %}
6
+ <textarea class="form-control {{ class_control|default('') }}" name="{{ name }}" style="min-height: {{ alto|default('80px') }}; {{ style_control|default('') }}" placeholder="{{ placeholder|default('') }}" {% if disabled %}disabled{% endif %}>{{ valor|default('') }}</textarea>
7
+ {% else %}
8
+ <div class="form-control-static {{ class_control|default('') }}" style="min-height: {{ alto|default('80px') }}; display: block; white-space: pre-wrap; page-break-inside: auto; {{ style_control|default('') }}">
9
+ {{ valor|default('') }}
10
+ </div>
11
+ {% endif %}
12
+ </div>
@@ -1,4 +1,4 @@
1
- <div class="footer-container" style="margin-top: {{ margin_top|default('20px') }};">
1
+ <div class="footer-container {{ class_group|default('') }}" style="margin-top: {{ margin_top|default('20px') }}; {{ style_group|default('') }}">
2
2
  <table class="footer-table">
3
3
  <tr>
4
4
  <td class="footer-cell footer-cell-bold" style="width: 15%;">Código:</td>
@@ -0,0 +1,16 @@
1
+ <div class="oficializacion-fija">
2
+ <table class="footer-table">
3
+ <tr>
4
+ <td class="footer-cell footer-cell-bold" style="width: 15%;">Código:</td>
5
+ <td class="footer-cell" style="width: 35%;">{{ codigo|default('N/A') }}</td>
6
+ <td class="footer-cell footer-cell-bold" style="width: 15%;">Versión:</td>
7
+ <td class="footer-cell" style="width: 35%;">{{ version|default('01') }}</td>
8
+ </tr>
9
+ <tr>
10
+ <td class="footer-cell footer-cell-bold">Fecha:</td>
11
+ <td class="footer-cell">{{ fecha|default('N/A') }}</td>
12
+ <td class="footer-cell footer-cell-bold">Página:</td>
13
+ <td class="footer-cell">Pág. <span class="page-num"></span> de <span class="page-total"></span></td>
14
+ </tr>
15
+ </table>
16
+ </div>
@@ -0,0 +1,7 @@
1
+ <div class="grid-row {{ class_row|default('') }}" style="{{ style_row|default('') }}">
2
+ {% for col in columns %}
3
+ <div class="{{ col.class_col|default('') }}" style="width: {{ col.ancho|default('100%') }}; flex: {{ col.flex|default('none') }}; {{ col.style_col|default('') }}">
4
+ {{ col.content }}
5
+ </div>
6
+ {% endfor %}
7
+ </div>
@@ -0,0 +1,19 @@
1
+ <div class="header-container {{ class_group|default('') }}" style="{{ style_group|default('') }}">
2
+ <div class="header-logos">
3
+ <img src="{{ logo_izq|default('img/logo-mininterior-rojo.jpg') }}" class="header-logo-left {{ class_logo_left|default('') }}" style="{{ style_logo_left|default('') }}" alt="Logo Izquierda">
4
+ </div>
5
+
6
+ <div class="header-text">
7
+ <h1 class="header-title-primary {{ class_title1|default('') }}" style="{{ style_title1|default('') }}">{{ titulo1 }}</h1>
8
+ {% if titulo2 %}
9
+ <h2 class="header-title-secondary {{ class_title2|default('') }}" style="{{ style_title2|default('') }}">{{ titulo2 }}</h2>
10
+ {% endif %}
11
+ {% if titulo3 %}
12
+ <h3 class="header-title-tertiary {{ class_title3|default('') }}" style="{{ style_title3|default('') }}">{{ titulo3 }}</h3>
13
+ {% endif %}
14
+ </div>
15
+
16
+ <div>
17
+ <img src="{{ logo_der|default('img/Logo-unp-rojo.png') }}" class="header-logo-right {{ class_logo_right|default('') }}" style="{{ style_logo_right|default('') }}" alt="Logo Derecha">
18
+ </div>
19
+ </div>
@@ -0,0 +1,6 @@
1
+ <div class="section-container {{ class_group|default('') }}" style="margin-top: {{ margin_top|default('15px') }}; margin-bottom: {{ margin_bottom|default('10px') }}; {{ style_group|default('') }}">
2
+ {% if icono %}
3
+ <i class="{{ icono }} section-icon {{ class_icon|default('') }}" style="{{ style_icon|default('') }}"></i>
4
+ {% endif %}
5
+ <span class="section-title {{ class_title|default('') }}" style="{{ style_title|default('') }}">{{ titulo }}</span>
6
+ </div>
@@ -32,6 +32,40 @@
32
32
  }
33
33
 
34
34
  /* 📄 Definición de Página Letter con Márgenes */
35
+ {% if auto_decorations %}
36
+ @page {
37
+ size: letter;
38
+ margin-top: 1.5cm;
39
+ margin-bottom: 2.2cm; /* Espacio reservado para el footer fijo */
40
+ margin-left: 1.2cm;
41
+ margin-right: 1.2cm;
42
+ border: 1px solid #303d50;
43
+ border-radius: 5px;
44
+ padding: 15px 15px 5px 15px; /* Espacio interno del borde */
45
+ }
46
+
47
+ /* Pie de página fijo de oficialización */
48
+ .oficializacion-fija {
49
+ position: fixed;
50
+ bottom: -1.7cm; /* Posicionado dentro del margen inferior */
51
+ left: 0;
52
+ width: 100%;
53
+ z-index: 9999;
54
+ }
55
+
56
+ /* Contadores de página dinámicos usando CSS nativo para WeasyPrint */
57
+ .page-num::after {
58
+ content: counter(page);
59
+ }
60
+ .page-total::after {
61
+ content: counter(pages);
62
+ }
63
+
64
+ /* Evitar saltos de página huérfanos dentro de grupos compactos */
65
+ .signature-container, .form-group, .choice-container {
66
+ page-break-inside: avoid;
67
+ }
68
+ {% else %}
35
69
  @page {
36
70
  size: letter;
37
71
  margin-top: 1.5cm;
@@ -39,6 +73,7 @@
39
73
  margin-left: 1cm;
40
74
  margin-right: 1cm;
41
75
  }
76
+ {% endif %}
42
77
 
43
78
  * {
44
79
  box-sizing: border-box;
@@ -288,18 +323,19 @@
288
323
  .footer-table {
289
324
  width: 100%;
290
325
  border-collapse: collapse;
326
+ background-color: #fff;
291
327
  }
292
328
 
293
329
  .footer-cell {
294
330
  border: 1px solid #cbd5e1;
295
- padding: 6px 10px;
331
+ padding: 4px 8px;
296
332
  vertical-align: middle;
297
333
  }
298
334
 
299
335
  .footer-cell-bold {
300
336
  font-weight: 600;
301
337
  background-color: #f8fafc;
302
- width: 25%;
338
+ width: 20%;
303
339
  }
304
340
 
305
341
  /* Saltos de Página */
@@ -313,6 +349,15 @@
313
349
  border-radius: 6px;
314
350
  padding: 15px;
315
351
  margin-bottom: 15px;
316
- min-height: 920px; /* Asegura un layout uniforme por página */
352
+ min-height: 920px;
317
353
  }
354
+
355
+ /* 🛡️ Inyección de CSS de Usuario */
356
+ {% if custom_css_path %}
357
+ @import url('{{ custom_css_path }}');
358
+ {% endif %}
359
+
360
+ {% if custom_css_content %}
361
+ {{ custom_css_content|safe }}
362
+ {% endif %}
318
363
  </style>
@@ -0,0 +1,14 @@
1
+ <div class="signature-container {{ class_group|default('') }}" style="justify-content: {{ justify|default('space-around') }}; margin-top: {{ margin_top|default('40px') }}; {{ style_group|default('') }}">
2
+ {% for sig in firmas %}
3
+ <div class="signature-box {{ class_box|default('') }}" style="width: {{ sig.ancho|default('45%') }}; {{ style_box|default('') }}">
4
+ <div class="signature-line {{ class_line|default('') }}" style="margin-top: {{ sig.alto_firma|default('50px') }}; {{ style_line|default('') }}"></div>
5
+ <span class="signature-name {{ class_name|default('') }}" style="{{ style_name|default('') }}">{{ sig.nombre }}</span>
6
+ {% if sig.cargo or sig.subtitulo %}
7
+ <span class="signature-sub {{ class_sub|default('') }}" style="{{ style_sub|default('') }}">{{ sig.cargo|default(sig.subtitulo) }}</span>
8
+ {% endif %}
9
+ {% if sig.documento %}
10
+ <span class="signature-sub {{ class_sub|default('') }}" style="{{ style_sub|default('') }}">C.C. {{ sig.documento }}</span>
11
+ {% endif %}
12
+ </div>
13
+ {% endfor %}
14
+ </div>
@@ -40,9 +40,29 @@ def get_template_env():
40
40
 
41
41
  def render_template(template_name, context):
42
42
  """Renderiza un template sin depender de Django (usando Jinja2)."""
43
+ from jinja2 import TemplateNotFound
43
44
  env = get_template_env()
44
- # Si no especifica una subcarpeta (ej: "input.html"), asumimos "assemblerpdf/"
45
- if "/" not in template_name and not template_name.startswith("assemblerpdf/"):
46
- template_name = f"assemblerpdf/{template_name}"
47
- template = env.get_template(template_name)
48
- return template.render(**context)
45
+
46
+ # Intentar las posibles rutas del template
47
+ posibles_rutas = []
48
+ if "/" not in template_name:
49
+ subcarpetas = ["layout", "fields", "misc"]
50
+ for sub in subcarpetas:
51
+ posibles_rutas.append(f"assemblerpdf/{sub}/{template_name}")
52
+ posibles_rutas.append(f"assemblerpdf/{template_name}")
53
+ posibles_rutas.append(f"sistema/{template_name}")
54
+ posibles_rutas.append(template_name)
55
+ else:
56
+ posibles_rutas.append(template_name)
57
+ if not template_name.startswith("assemblerpdf/") and not template_name.startswith("sistema/"):
58
+ posibles_rutas.append(f"assemblerpdf/{template_name}")
59
+
60
+ last_error = None
61
+ for ruta in posibles_rutas:
62
+ try:
63
+ template = env.get_template(ruta)
64
+ return template.render(**context)
65
+ except TemplateNotFound as e:
66
+ last_error = e
67
+
68
+ raise last_error
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: assemblerpdf
3
- Version: 1.0.0
3
+ Version: 1.0.2
4
4
  Summary: Generador de PDFs usando WeasyPrint, diseñado para formularios y reportes con componentes genéricos.
5
5
  Author-email: EcosistemaUNP <ecosistema@unp.gov.co>
6
6
  License: MIT
@@ -17,16 +17,17 @@ src/assemblerpdf/fonts/Inter-Medium.ttf
17
17
  src/assemblerpdf/fonts/Inter-Regular.ttf
18
18
  src/assemblerpdf/img/Logo-unp-rojo.png
19
19
  src/assemblerpdf/img/logo-mininterior-rojo.jpg
20
- src/assemblerpdf/templates/assemblerpdf/checkbox.html
21
- src/assemblerpdf/templates/assemblerpdf/footer.html
22
- src/assemblerpdf/templates/assemblerpdf/grid_row.html
23
- src/assemblerpdf/templates/assemblerpdf/header.html
24
- src/assemblerpdf/templates/assemblerpdf/input.html
25
- src/assemblerpdf/templates/assemblerpdf/radio.html
26
- src/assemblerpdf/templates/assemblerpdf/section.html
27
- src/assemblerpdf/templates/assemblerpdf/signature.html
28
- src/assemblerpdf/templates/assemblerpdf/style.html
29
- src/assemblerpdf/templates/assemblerpdf/textarea.html
20
+ src/assemblerpdf/templates/assemblerpdf/fields/checkbox.html
21
+ src/assemblerpdf/templates/assemblerpdf/fields/input.html
22
+ src/assemblerpdf/templates/assemblerpdf/fields/radio.html
23
+ src/assemblerpdf/templates/assemblerpdf/fields/textarea.html
24
+ src/assemblerpdf/templates/assemblerpdf/layout/footer.html
25
+ src/assemblerpdf/templates/assemblerpdf/layout/footer_fixed.html
26
+ src/assemblerpdf/templates/assemblerpdf/layout/grid_row.html
27
+ src/assemblerpdf/templates/assemblerpdf/layout/header.html
28
+ src/assemblerpdf/templates/assemblerpdf/layout/section.html
29
+ src/assemblerpdf/templates/assemblerpdf/layout/style.html
30
+ src/assemblerpdf/templates/assemblerpdf/misc/signature.html
30
31
  src/assemblerpdf/templates/sistema/anexos.html
31
32
  src/assemblerpdf/templates/sistema/anexos_limpio.html
32
33
  src/assemblerpdf/templates/sistema/archivese.html
@@ -1,16 +0,0 @@
1
- <div class="choice-container" style="margin-bottom: {{ margin_bottom|default('8px') }};">
2
- {% if label %}
3
- <label class="form-label">{{ label }}</label>
4
- {% endif %}
5
- <div class="choice-group">
6
- {% for opt in opciones %}
7
- {% set is_checked = opt.checked or (seleccionado and opt.valor == seleccionado) or (seleccionados and opt.valor in seleccionados) %}
8
- <div class="choice-item">
9
- <span class="choice-box {% if is_checked %}checked{% endif %}">
10
- {% if is_checked %}✓{% endif %}
11
- </span>
12
- <span>{{ opt.label }}</span>
13
- </div>
14
- {% endfor %}
15
- </div>
16
- </div>
@@ -1,7 +0,0 @@
1
- <div class="grid-row">
2
- {% for col in columns %}
3
- <div style="width: {{ col.ancho|default('100%') }}; flex: {{ col.flex|default('none') }};">
4
- {{ col.content }}
5
- </div>
6
- {% endfor %}
7
- </div>
@@ -1,19 +0,0 @@
1
- <div class="header-container">
2
- <div class="header-logos">
3
- <img src="{{ logo_izq|default('img/logo-mininterior-rojo.jpg') }}" class="header-logo-left" alt="Logo Izquierda">
4
- </div>
5
-
6
- <div class="header-text">
7
- <h1 class="header-title-primary">{{ titulo1 }}</h1>
8
- {% if titulo2 %}
9
- <h2 class="header-title-secondary">{{ titulo2 }}</h2>
10
- {% endif %}
11
- {% if titulo3 %}
12
- <h3 class="header-title-tertiary">{{ titulo3 }}</h3>
13
- {% endif %}
14
- </div>
15
-
16
- <div>
17
- <img src="{{ logo_der|default('img/Logo-unp-rojo.png') }}" class="header-logo-right" alt="Logo Derecha">
18
- </div>
19
- </div>
@@ -1,12 +0,0 @@
1
- <div class="form-group" style="margin-bottom: {{ margin_bottom|default('8px') }};">
2
- {% if label %}
3
- <label class="form-label">{{ label }}</label>
4
- {% endif %}
5
- {% if interactive %}
6
- <input type="text" class="form-control" name="{{ name }}" value="{{ valor|default('') }}" placeholder="{{ placeholder|default('') }}" {% if disabled %}disabled{% endif %}>
7
- {% else %}
8
- <div class="form-control-static">
9
- {{ valor|default('') }}
10
- </div>
11
- {% endif %}
12
- </div>
@@ -1,14 +0,0 @@
1
- <div class="choice-container" style="margin-bottom: {{ margin_bottom|default('8px') }};">
2
- {% if label %}
3
- <label class="form-label">{{ label }}</label>
4
- {% endif %}
5
- <div class="choice-group">
6
- {% for opt in opciones %}
7
- {% set is_checked = opt.checked or (seleccionado and opt.valor == seleccionado) or (seleccionados and opt.valor in seleccionados) %}
8
- <div class="choice-item">
9
- <span class="choice-circle {% if is_checked %}checked{% endif %}"></span>
10
- <span>{{ opt.label }}</span>
11
- </div>
12
- {% endfor %}
13
- </div>
14
- </div>
@@ -1,6 +0,0 @@
1
- <div class="section-container" style="margin-top: {{ margin_top|default('15px') }}; margin-bottom: {{ margin_bottom|default('10px') }};">
2
- {% if icono %}
3
- <i class="{{ icono }} section-icon"></i>
4
- {% endif %}
5
- <span class="section-title">{{ titulo }}</span>
6
- </div>
@@ -1,14 +0,0 @@
1
- <div class="signature-container" style="justify-content: {{ justify|default('space-around') }}; margin-top: {{ margin_top|default('40px') }};">
2
- {% for sig in firmas %}
3
- <div class="signature-box" style="width: {{ sig.ancho|default('45%') }};">
4
- <div class="signature-line" style="margin-top: {{ sig.alto_firma|default('50px') }};"></div>
5
- <span class="signature-name">{{ sig.nombre }}</span>
6
- {% if sig.cargo or sig.subtitulo %}
7
- <span class="signature-sub">{{ sig.cargo|default(sig.subtitulo) }}</span>
8
- {% endif %}
9
- {% if sig.documento %}
10
- <span class="signature-sub">C.C. {{ sig.documento }}</span>
11
- {% endif %}
12
- </div>
13
- {% endfor %}
14
- </div>
@@ -1,12 +0,0 @@
1
- <div class="form-group" style="margin-bottom: {{ margin_bottom|default('8px') }};">
2
- {% if label %}
3
- <label class="form-label">{{ label }}</label>
4
- {% endif %}
5
- {% if interactive %}
6
- <textarea class="form-control" name="{{ name }}" style="height: {{ alto|default('80px') }};" placeholder="{{ placeholder|default('') }}" {% if disabled %}disabled{% endif %}>{{ valor|default('') }}</textarea>
7
- {% else %}
8
- <div class="form-control-static" style="height: {{ alto|default('80px') }}; display: block; overflow: hidden; white-space: pre-wrap;">
9
- {{ valor|default('') }}
10
- </div>
11
- {% endif %}
12
- </div>
File without changes
File without changes
File without changes