coati-payroll 0.0.2__py3-none-any.whl

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.

Potentially problematic release.


This version of coati-payroll might be problematic. Click here for more details.

Files changed (243) hide show
  1. coati_payroll/__init__.py +415 -0
  2. coati_payroll/app.py +95 -0
  3. coati_payroll/audit_helpers.py +904 -0
  4. coati_payroll/auth.py +123 -0
  5. coati_payroll/cli.py +1318 -0
  6. coati_payroll/config.py +219 -0
  7. coati_payroll/demo_data.py +813 -0
  8. coati_payroll/enums.py +278 -0
  9. coati_payroll/forms.py +1769 -0
  10. coati_payroll/formula_engine/__init__.py +81 -0
  11. coati_payroll/formula_engine/ast/__init__.py +110 -0
  12. coati_payroll/formula_engine/ast/ast_visitor.py +259 -0
  13. coati_payroll/formula_engine/ast/expression_evaluator.py +228 -0
  14. coati_payroll/formula_engine/ast/safe_operators.py +131 -0
  15. coati_payroll/formula_engine/ast/type_converter.py +172 -0
  16. coati_payroll/formula_engine/data_sources.py +752 -0
  17. coati_payroll/formula_engine/engine.py +247 -0
  18. coati_payroll/formula_engine/exceptions.py +52 -0
  19. coati_payroll/formula_engine/execution/__init__.py +24 -0
  20. coati_payroll/formula_engine/execution/execution_context.py +52 -0
  21. coati_payroll/formula_engine/execution/step_executor.py +62 -0
  22. coati_payroll/formula_engine/execution/variable_store.py +59 -0
  23. coati_payroll/formula_engine/novelty_codes.py +206 -0
  24. coati_payroll/formula_engine/results/__init__.py +20 -0
  25. coati_payroll/formula_engine/results/execution_result.py +59 -0
  26. coati_payroll/formula_engine/steps/__init__.py +30 -0
  27. coati_payroll/formula_engine/steps/assignment_step.py +71 -0
  28. coati_payroll/formula_engine/steps/base_step.py +48 -0
  29. coati_payroll/formula_engine/steps/calculation_step.py +42 -0
  30. coati_payroll/formula_engine/steps/conditional_step.py +122 -0
  31. coati_payroll/formula_engine/steps/step_factory.py +58 -0
  32. coati_payroll/formula_engine/steps/tax_lookup_step.py +45 -0
  33. coati_payroll/formula_engine/tables/__init__.py +24 -0
  34. coati_payroll/formula_engine/tables/bracket_calculator.py +51 -0
  35. coati_payroll/formula_engine/tables/table_lookup.py +161 -0
  36. coati_payroll/formula_engine/tables/tax_table.py +32 -0
  37. coati_payroll/formula_engine/validation/__init__.py +24 -0
  38. coati_payroll/formula_engine/validation/schema_validator.py +37 -0
  39. coati_payroll/formula_engine/validation/security_validator.py +52 -0
  40. coati_payroll/formula_engine/validation/tax_table_validator.py +205 -0
  41. coati_payroll/formula_engine_examples.py +153 -0
  42. coati_payroll/i18n.py +54 -0
  43. coati_payroll/initial_data.py +613 -0
  44. coati_payroll/interes_engine.py +450 -0
  45. coati_payroll/liquidacion_engine/__init__.py +25 -0
  46. coati_payroll/liquidacion_engine/engine.py +267 -0
  47. coati_payroll/locale_config.py +165 -0
  48. coati_payroll/log.py +138 -0
  49. coati_payroll/model.py +2410 -0
  50. coati_payroll/nomina_engine/__init__.py +87 -0
  51. coati_payroll/nomina_engine/calculators/__init__.py +30 -0
  52. coati_payroll/nomina_engine/calculators/benefit_calculator.py +79 -0
  53. coati_payroll/nomina_engine/calculators/concept_calculator.py +254 -0
  54. coati_payroll/nomina_engine/calculators/deduction_calculator.py +105 -0
  55. coati_payroll/nomina_engine/calculators/exchange_rate_calculator.py +51 -0
  56. coati_payroll/nomina_engine/calculators/perception_calculator.py +75 -0
  57. coati_payroll/nomina_engine/calculators/salary_calculator.py +86 -0
  58. coati_payroll/nomina_engine/domain/__init__.py +27 -0
  59. coati_payroll/nomina_engine/domain/calculation_items.py +52 -0
  60. coati_payroll/nomina_engine/domain/employee_calculation.py +53 -0
  61. coati_payroll/nomina_engine/domain/payroll_context.py +44 -0
  62. coati_payroll/nomina_engine/engine.py +188 -0
  63. coati_payroll/nomina_engine/processors/__init__.py +28 -0
  64. coati_payroll/nomina_engine/processors/accounting_processor.py +171 -0
  65. coati_payroll/nomina_engine/processors/accumulation_processor.py +90 -0
  66. coati_payroll/nomina_engine/processors/loan_processor.py +227 -0
  67. coati_payroll/nomina_engine/processors/novelty_processor.py +42 -0
  68. coati_payroll/nomina_engine/processors/vacation_processor.py +67 -0
  69. coati_payroll/nomina_engine/repositories/__init__.py +32 -0
  70. coati_payroll/nomina_engine/repositories/acumulado_repository.py +83 -0
  71. coati_payroll/nomina_engine/repositories/base_repository.py +40 -0
  72. coati_payroll/nomina_engine/repositories/config_repository.py +102 -0
  73. coati_payroll/nomina_engine/repositories/employee_repository.py +34 -0
  74. coati_payroll/nomina_engine/repositories/exchange_rate_repository.py +58 -0
  75. coati_payroll/nomina_engine/repositories/novelty_repository.py +54 -0
  76. coati_payroll/nomina_engine/repositories/planilla_repository.py +52 -0
  77. coati_payroll/nomina_engine/results/__init__.py +24 -0
  78. coati_payroll/nomina_engine/results/error_result.py +28 -0
  79. coati_payroll/nomina_engine/results/payroll_result.py +53 -0
  80. coati_payroll/nomina_engine/results/validation_result.py +39 -0
  81. coati_payroll/nomina_engine/services/__init__.py +22 -0
  82. coati_payroll/nomina_engine/services/accounting_voucher_service.py +708 -0
  83. coati_payroll/nomina_engine/services/employee_processing_service.py +173 -0
  84. coati_payroll/nomina_engine/services/payroll_execution_service.py +374 -0
  85. coati_payroll/nomina_engine/services/snapshot_service.py +295 -0
  86. coati_payroll/nomina_engine/validators/__init__.py +31 -0
  87. coati_payroll/nomina_engine/validators/base_validator.py +48 -0
  88. coati_payroll/nomina_engine/validators/currency_validator.py +50 -0
  89. coati_payroll/nomina_engine/validators/employee_validator.py +87 -0
  90. coati_payroll/nomina_engine/validators/period_validator.py +44 -0
  91. coati_payroll/nomina_engine/validators/planilla_validator.py +136 -0
  92. coati_payroll/plugin_manager.py +176 -0
  93. coati_payroll/queue/__init__.py +33 -0
  94. coati_payroll/queue/driver.py +127 -0
  95. coati_payroll/queue/drivers/__init__.py +22 -0
  96. coati_payroll/queue/drivers/dramatiq_driver.py +268 -0
  97. coati_payroll/queue/drivers/huey_driver.py +390 -0
  98. coati_payroll/queue/drivers/noop_driver.py +54 -0
  99. coati_payroll/queue/selector.py +121 -0
  100. coati_payroll/queue/tasks.py +764 -0
  101. coati_payroll/rate_limiting.py +83 -0
  102. coati_payroll/rbac.py +183 -0
  103. coati_payroll/report_engine.py +512 -0
  104. coati_payroll/report_export.py +208 -0
  105. coati_payroll/schema_validator.py +167 -0
  106. coati_payroll/security.py +77 -0
  107. coati_payroll/static/styles.css +1044 -0
  108. coati_payroll/system_reports.py +573 -0
  109. coati_payroll/templates/auth/login.html +189 -0
  110. coati_payroll/templates/base.html +283 -0
  111. coati_payroll/templates/index.html +227 -0
  112. coati_payroll/templates/macros.html +146 -0
  113. coati_payroll/templates/modules/calculation_rule/form.html +78 -0
  114. coati_payroll/templates/modules/calculation_rule/index.html +102 -0
  115. coati_payroll/templates/modules/calculation_rule/schema_editor.html +1159 -0
  116. coati_payroll/templates/modules/carga_inicial_prestacion/form.html +170 -0
  117. coati_payroll/templates/modules/carga_inicial_prestacion/index.html +170 -0
  118. coati_payroll/templates/modules/carga_inicial_prestacion/reporte.html +193 -0
  119. coati_payroll/templates/modules/config_calculos/index.html +44 -0
  120. coati_payroll/templates/modules/configuracion/index.html +90 -0
  121. coati_payroll/templates/modules/currency/form.html +47 -0
  122. coati_payroll/templates/modules/currency/index.html +64 -0
  123. coati_payroll/templates/modules/custom_field/form.html +62 -0
  124. coati_payroll/templates/modules/custom_field/index.html +78 -0
  125. coati_payroll/templates/modules/deduccion/form.html +1 -0
  126. coati_payroll/templates/modules/deduccion/index.html +1 -0
  127. coati_payroll/templates/modules/employee/form.html +254 -0
  128. coati_payroll/templates/modules/employee/index.html +76 -0
  129. coati_payroll/templates/modules/empresa/form.html +74 -0
  130. coati_payroll/templates/modules/empresa/index.html +71 -0
  131. coati_payroll/templates/modules/exchange_rate/form.html +47 -0
  132. coati_payroll/templates/modules/exchange_rate/import.html +93 -0
  133. coati_payroll/templates/modules/exchange_rate/index.html +114 -0
  134. coati_payroll/templates/modules/liquidacion/index.html +58 -0
  135. coati_payroll/templates/modules/liquidacion/nueva.html +51 -0
  136. coati_payroll/templates/modules/liquidacion/ver.html +91 -0
  137. coati_payroll/templates/modules/payroll_concepts/audit_log.html +146 -0
  138. coati_payroll/templates/modules/percepcion/form.html +1 -0
  139. coati_payroll/templates/modules/percepcion/index.html +1 -0
  140. coati_payroll/templates/modules/planilla/config.html +190 -0
  141. coati_payroll/templates/modules/planilla/config_deducciones.html +129 -0
  142. coati_payroll/templates/modules/planilla/config_empleados.html +116 -0
  143. coati_payroll/templates/modules/planilla/config_percepciones.html +113 -0
  144. coati_payroll/templates/modules/planilla/config_prestaciones.html +118 -0
  145. coati_payroll/templates/modules/planilla/config_reglas.html +120 -0
  146. coati_payroll/templates/modules/planilla/ejecutar_nomina.html +106 -0
  147. coati_payroll/templates/modules/planilla/form.html +197 -0
  148. coati_payroll/templates/modules/planilla/index.html +144 -0
  149. coati_payroll/templates/modules/planilla/listar_nominas.html +91 -0
  150. coati_payroll/templates/modules/planilla/log_nomina.html +135 -0
  151. coati_payroll/templates/modules/planilla/novedades/form.html +177 -0
  152. coati_payroll/templates/modules/planilla/novedades/index.html +170 -0
  153. coati_payroll/templates/modules/planilla/ver_nomina.html +477 -0
  154. coati_payroll/templates/modules/planilla/ver_nomina_empleado.html +231 -0
  155. coati_payroll/templates/modules/plugins/index.html +71 -0
  156. coati_payroll/templates/modules/prestacion/form.html +1 -0
  157. coati_payroll/templates/modules/prestacion/index.html +1 -0
  158. coati_payroll/templates/modules/prestacion_management/dashboard.html +150 -0
  159. coati_payroll/templates/modules/prestacion_management/initial_balance_bulk.html +195 -0
  160. coati_payroll/templates/modules/prestamo/approve.html +156 -0
  161. coati_payroll/templates/modules/prestamo/condonacion.html +249 -0
  162. coati_payroll/templates/modules/prestamo/detail.html +443 -0
  163. coati_payroll/templates/modules/prestamo/form.html +203 -0
  164. coati_payroll/templates/modules/prestamo/index.html +150 -0
  165. coati_payroll/templates/modules/prestamo/pago_extraordinario.html +211 -0
  166. coati_payroll/templates/modules/prestamo/tabla_pago_pdf.html +181 -0
  167. coati_payroll/templates/modules/report/admin_index.html +125 -0
  168. coati_payroll/templates/modules/report/detail.html +129 -0
  169. coati_payroll/templates/modules/report/execute.html +266 -0
  170. coati_payroll/templates/modules/report/index.html +95 -0
  171. coati_payroll/templates/modules/report/permissions.html +64 -0
  172. coati_payroll/templates/modules/settings/index.html +274 -0
  173. coati_payroll/templates/modules/shared/concept_form.html +201 -0
  174. coati_payroll/templates/modules/shared/concept_index.html +145 -0
  175. coati_payroll/templates/modules/tipo_planilla/form.html +70 -0
  176. coati_payroll/templates/modules/tipo_planilla/index.html +68 -0
  177. coati_payroll/templates/modules/user/form.html +65 -0
  178. coati_payroll/templates/modules/user/index.html +76 -0
  179. coati_payroll/templates/modules/user/profile.html +81 -0
  180. coati_payroll/templates/modules/vacation/account_detail.html +149 -0
  181. coati_payroll/templates/modules/vacation/account_form.html +52 -0
  182. coati_payroll/templates/modules/vacation/account_index.html +68 -0
  183. coati_payroll/templates/modules/vacation/dashboard.html +156 -0
  184. coati_payroll/templates/modules/vacation/initial_balance_bulk.html +149 -0
  185. coati_payroll/templates/modules/vacation/initial_balance_form.html +93 -0
  186. coati_payroll/templates/modules/vacation/leave_request_detail.html +158 -0
  187. coati_payroll/templates/modules/vacation/leave_request_form.html +61 -0
  188. coati_payroll/templates/modules/vacation/leave_request_index.html +98 -0
  189. coati_payroll/templates/modules/vacation/policy_detail.html +176 -0
  190. coati_payroll/templates/modules/vacation/policy_form.html +152 -0
  191. coati_payroll/templates/modules/vacation/policy_index.html +79 -0
  192. coati_payroll/templates/modules/vacation/register_taken_form.html +178 -0
  193. coati_payroll/translations/en/LC_MESSAGES/messages.mo +0 -0
  194. coati_payroll/translations/en/LC_MESSAGES/messages.po +7283 -0
  195. coati_payroll/translations/es/LC_MESSAGES/messages.mo +0 -0
  196. coati_payroll/translations/es/LC_MESSAGES/messages.po +7374 -0
  197. coati_payroll/vacation_service.py +451 -0
  198. coati_payroll/version.py +18 -0
  199. coati_payroll/vistas/__init__.py +64 -0
  200. coati_payroll/vistas/calculation_rule.py +307 -0
  201. coati_payroll/vistas/carga_inicial_prestacion.py +423 -0
  202. coati_payroll/vistas/config_calculos.py +72 -0
  203. coati_payroll/vistas/configuracion.py +87 -0
  204. coati_payroll/vistas/constants.py +17 -0
  205. coati_payroll/vistas/currency.py +112 -0
  206. coati_payroll/vistas/custom_field.py +120 -0
  207. coati_payroll/vistas/employee.py +305 -0
  208. coati_payroll/vistas/empresa.py +153 -0
  209. coati_payroll/vistas/exchange_rate.py +341 -0
  210. coati_payroll/vistas/liquidacion.py +205 -0
  211. coati_payroll/vistas/payroll_concepts.py +580 -0
  212. coati_payroll/vistas/planilla/__init__.py +38 -0
  213. coati_payroll/vistas/planilla/association_routes.py +238 -0
  214. coati_payroll/vistas/planilla/config_routes.py +158 -0
  215. coati_payroll/vistas/planilla/export_routes.py +175 -0
  216. coati_payroll/vistas/planilla/helpers/__init__.py +34 -0
  217. coati_payroll/vistas/planilla/helpers/association_helpers.py +161 -0
  218. coati_payroll/vistas/planilla/helpers/excel_helpers.py +29 -0
  219. coati_payroll/vistas/planilla/helpers/form_helpers.py +97 -0
  220. coati_payroll/vistas/planilla/nomina_routes.py +488 -0
  221. coati_payroll/vistas/planilla/novedad_routes.py +227 -0
  222. coati_payroll/vistas/planilla/routes.py +145 -0
  223. coati_payroll/vistas/planilla/services/__init__.py +26 -0
  224. coati_payroll/vistas/planilla/services/export_service.py +687 -0
  225. coati_payroll/vistas/planilla/services/nomina_service.py +233 -0
  226. coati_payroll/vistas/planilla/services/novedad_service.py +126 -0
  227. coati_payroll/vistas/planilla/services/planilla_service.py +34 -0
  228. coati_payroll/vistas/planilla/validators/__init__.py +18 -0
  229. coati_payroll/vistas/planilla/validators/planilla_validators.py +40 -0
  230. coati_payroll/vistas/plugins.py +45 -0
  231. coati_payroll/vistas/prestacion.py +272 -0
  232. coati_payroll/vistas/prestamo.py +808 -0
  233. coati_payroll/vistas/report.py +432 -0
  234. coati_payroll/vistas/settings.py +29 -0
  235. coati_payroll/vistas/tipo_planilla.py +134 -0
  236. coati_payroll/vistas/user.py +172 -0
  237. coati_payroll/vistas/vacation.py +1045 -0
  238. coati_payroll-0.0.2.dist-info/LICENSE +201 -0
  239. coati_payroll-0.0.2.dist-info/METADATA +581 -0
  240. coati_payroll-0.0.2.dist-info/RECORD +243 -0
  241. coati_payroll-0.0.2.dist-info/WHEEL +5 -0
  242. coati_payroll-0.0.2.dist-info/entry_points.txt +2 -0
  243. coati_payroll-0.0.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,189 @@
1
+ <!doctype html>
2
+ <html lang="es">
3
+
4
+ <head>
5
+ <meta charset="utf-8" />
6
+ <meta name="viewport" content="width=device-width,initial-scale=1" />
7
+ <title>{{ _('Iniciar sesión') }} - Coati Payroll</title>
8
+
9
+ <!-- Google Fonts - Enterprise Typography -->
10
+ <link rel="preconnect" href="https://fonts.googleapis.com">
11
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
12
+ <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;600;700&display=swap" rel="stylesheet">
13
+
14
+ <!-- Bootstrap (mismo CDN que base) -->
15
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
16
+
17
+ <!-- Bootstrap Icons -->
18
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
19
+
20
+ <!-- App styles -->
21
+ <link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
22
+ </head>
23
+
24
+ <body class="login-page">
25
+ <div class="login-container">
26
+ <!-- Left side - Branding -->
27
+ <div class="login-branding">
28
+ <div class="branding-content">
29
+ <div class="logo-container">
30
+ <span class="logo-placeholder logo-large"><i class="bi bi-flower1"></i></span>
31
+ </div>
32
+ <div>
33
+ <h1 class="brand-name">Coati <span>Payroll</span></h1>
34
+ <p class="brand-tagline">
35
+ {{ _('Sistema de gestión de nóminas') }}<br>
36
+ {{ _('Agiliza y simplifica el pago de sueldos en su compañía.') }}
37
+ </p>
38
+ </div>
39
+ <div class="brand-features">
40
+ <div class="feature-item">
41
+ <i class="bi bi-building-fill-add"></i>
42
+ <span>{{ _('Multiempresa') }}</span>
43
+ </div>
44
+ <div class="feature-item">
45
+ <i class="bi bi-currency-exchange"></i>
46
+ <span>{{ _('Multimoneda') }}</span>
47
+ </div>
48
+ <div class="feature-item">
49
+ <i class="bi bi-shield-check"></i>
50
+ <span>{{ _('Seguro y confiable') }}</span>
51
+ </div>
52
+ <div class="feature-item">
53
+ <i class="bi bi-speedometer2"></i>
54
+ <span>{{ _('Rápido y eficiente') }}</span>
55
+ </div>
56
+ <div class="feature-item">
57
+ <i class="bi bi-gear-fill"></i>
58
+ <span>{{ _('Configurable') }}</span>
59
+ </div>
60
+ <div class="feature-item">
61
+ <i class="bi bi-shuffle"></i>
62
+ <span>{{ _('Flexible') }}</span>
63
+ </div>
64
+ </div>
65
+ </div>
66
+ </div>
67
+
68
+ <!-- Right side - Login Form -->
69
+ <div class="login-form-container">
70
+ <div class="login-form-wrapper">
71
+ <div class="login-header">
72
+ <h2 id="loginTitle">{{ _('Iniciar sesión') }}</h2>
73
+ <p class="login-subtitle">{{ _('Introduce tus credenciales para acceder a tu cuenta.') }}</p>
74
+ </div>
75
+
76
+ {%- set flashed = get_flashed_messages(with_categories=true) -%}
77
+ {% if flashed %}
78
+ <div id="errorMsg" class="alert alert-warning" role="alert" aria-live="polite">
79
+ <i class="bi bi-exclamation-triangle me-2"></i>
80
+ {{ flashed[0][1] }}
81
+ </div>
82
+ {% endif %}
83
+
84
+ <form id="loginForm" method="post" action="{{ url_for('auth.login') }}">
85
+ {{ form.hidden_tag() }}
86
+
87
+ <div class="mb-4">
88
+ <label for="{{ form.email.id }}" class="form-label">
89
+ <i class="bi bi-person me-1"></i>
90
+ {{ _('Usuario o correo electrónico') }}
91
+ </label>
92
+ {{ form.email(id='email', class_='form-control form-control-lg', autocomplete='username', placeholder=_('usuario o correo')) }}
93
+ {% if form.email.errors %}
94
+ <div class="form-text text-danger">{{ form.email.errors[0] }}</div>
95
+ {% else %}
96
+ <div class="form-text">
97
+ {{ _('Usa el correo o el nombre de usuario asociado a tu cuenta.') }}</div>
98
+ {% endif %}
99
+ </div>
100
+
101
+ <div class="mb-4">
102
+ <label for="{{ form.password.id }}" class="form-label">
103
+ <i class="bi bi-lock me-1"></i>
104
+ {{ _('Contraseña') }}
105
+ </label>
106
+ <div class="input-group">
107
+ {{ form.password(id='password', class_='form-control form-control-lg', autocomplete='current-password', placeholder='••••••••') }}
108
+ <button type="button" id="togglePwd" class="btn btn-outline-secondary"
109
+ aria-label="{{ _('Mostrar u ocultar contraseña') }}" aria-pressed="false">
110
+ <i class="bi bi-eye" id="toggleIcon" aria-hidden="true"></i>
111
+ </button>
112
+ </div>
113
+ {% if form.password.errors %}
114
+ <div class="form-text text-danger">{{ form.password.errors[0] }}</div>
115
+ {% endif %}
116
+ </div>
117
+
118
+ <div class="d-grid mb-3">
119
+ {{ form.submit(class_='btn btn-primary btn-lg') }}
120
+ </div>
121
+ </form>
122
+ </div>
123
+ </div>
124
+ </div>
125
+
126
+ <script>
127
+ // Textos de JS marcados para que Flask-Babel pueda extraerlos
128
+ const TXT_SHOW = "{{ _('Mostrar') }}";
129
+ const TXT_HIDE = "{{ _('Ocultar') }}";
130
+ const ERR_EMAIL = "{{ _('Por favor introduce tu correo.') }}";
131
+ const ERR_PASS = "{{ _('La contraseña debe tener al menos 6 caracteres.') }}";
132
+ const ERR_CONN = "{{ _('No se pudo conectar al servidor.') }}";
133
+ const ERR_LOGIN = "{{ _('Error al iniciar sesión') }}";
134
+
135
+ (function () {
136
+ const pwd = document.getElementById('password');
137
+ const toggle = document.getElementById('togglePwd');
138
+ const toggleIcon = document.getElementById('toggleIcon');
139
+ const form = document.getElementById('loginForm');
140
+ const errorMsg = document.getElementById('errorMsg');
141
+
142
+ toggle.addEventListener('click', () => {
143
+ if (pwd.type === 'password') {
144
+ pwd.type = 'text';
145
+ toggleIcon.classList.remove('bi-eye');
146
+ toggleIcon.classList.add('bi-eye-slash');
147
+ toggle.setAttribute('aria-pressed', 'true');
148
+ } else {
149
+ pwd.type = 'password';
150
+ toggleIcon.classList.remove('bi-eye-slash');
151
+ toggleIcon.classList.add('bi-eye');
152
+ toggle.setAttribute('aria-pressed', 'false');
153
+ }
154
+ });
155
+
156
+ form.addEventListener('submit', (e) => {
157
+ if (errorMsg) {
158
+ errorMsg.style.display = 'none';
159
+ errorMsg.textContent = '';
160
+ }
161
+
162
+ const email = document.getElementById('email').value.trim();
163
+ const password = pwd.value;
164
+
165
+ if (!email) {
166
+ e.preventDefault();
167
+ showError(ERR_EMAIL);
168
+ return;
169
+ }
170
+ if (password.length < 6) {
171
+ e.preventDefault();
172
+ showError(ERR_PASS);
173
+ return;
174
+ }
175
+ });
176
+
177
+ function showError(text) {
178
+ if (errorMsg) {
179
+ errorMsg.innerHTML = '<i class="bi bi-exclamation-triangle me-2"></i>' + text;
180
+ errorMsg.style.display = 'block';
181
+ }
182
+ }
183
+
184
+ document.getElementById('email').focus();
185
+ })();
186
+ </script>
187
+ </body>
188
+
189
+ </html>
@@ -0,0 +1,283 @@
1
+ <!doctype html>
2
+ <html lang="es">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>{{ _('Coaty - Sistema de Planillas') }}</title>
7
+
8
+ <!-- Google Fonts - Enterprise Typography -->
9
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
10
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
11
+ <link
12
+ href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;600;700&display=swap"
13
+ rel="stylesheet"
14
+ />
15
+
16
+ <!-- Bootstrap 5 -->
17
+ <link
18
+ href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
19
+ rel="stylesheet"
20
+ />
21
+
22
+ <!-- Bootstrap Icons -->
23
+ <link
24
+ rel="stylesheet"
25
+ href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css"
26
+ />
27
+
28
+ <!-- Custom styles -->
29
+ <link
30
+ rel="stylesheet"
31
+ href="{{ url_for('static', filename='styles.css') }}"
32
+ />
33
+ </head>
34
+
35
+ <body>
36
+ <!-- ======================= NAVBAR SUPERIOR ======================= -->
37
+ <nav class="navbar navbar-expand-lg navbar-dark bg-coaty-dark px-3">
38
+ <!-- Botón hamburguesa para abrir sidebar en pantallas pequeñas -->
39
+ <button
40
+ class="btn sidebar-toggle-btn d-lg-none me-2"
41
+ id="sidebarToggleMobile"
42
+ aria-label="Toggle sidebar"
43
+ >
44
+ <span class="navbar-toggler-icon"></span>
45
+ </button>
46
+
47
+ <a
48
+ class="navbar-brand fw-bold text-uppercase"
49
+ href="{{ url_for('app.index') }}"
50
+ >
51
+ <!-- Logo placeholder - reemplazar con logo real posteriormente -->
52
+ <span class="logo-placeholder"
53
+ ><i class="bi bi-flower1"></i
54
+ ></span>
55
+ <span
56
+ >{{ _('Coati') }}
57
+ <span class="fw-normal">Payroll</span></span
58
+ >
59
+ </a>
60
+
61
+ <!-- Navbar items - visible en pantallas grandes -->
62
+ <div
63
+ class="navbar-collapse justify-content-end d-none d-lg-flex"
64
+ id="topNav"
65
+ >
66
+ <ul class="navbar-nav flex-row gap-2 mb-0">
67
+ <li class="nav-item">
68
+ <a
69
+ class="nav-link"
70
+ href="{{ url_for('user.profile') }}"
71
+ >
72
+ <i class="bi bi-person-circle"></i>
73
+ {{ _('Mi Perfil') }}
74
+ </a>
75
+ </li>
76
+ <li class="nav-item">
77
+ <a class="nav-link" href="{{ url_for('auth.logout') }}">
78
+ <i class="bi bi-box-arrow-right"></i>
79
+ {{ _('Cerrar Sesión') }}
80
+ </a>
81
+ </li>
82
+ </ul>
83
+ </div>
84
+ </nav>
85
+
86
+ <!-- ======================= LAYOUT PRINCIPAL ======================= -->
87
+ <div class="d-flex">
88
+ <!-- ======================= SIDEBAR ======================= -->
89
+ <aside id="sidebar" class="sidebar bg-coaty-light">
90
+ <!-- Sidebar header with logo -->
91
+ <div class="sidebar-header">
92
+ <div class="brand-title">
93
+ <span class="logo-placeholder"
94
+ ><i class="bi bi-flower1"></i
95
+ ></span>
96
+ {{ _('Coati Payroll') }}
97
+ </div>
98
+ <div class="brand-subtitle">
99
+ {{ _('Sistema de Planillas') }}
100
+ </div>
101
+ </div>
102
+
103
+ <ul class="nav flex-column">
104
+ <!-- Inicio -->
105
+ <li class="nav-item">
106
+ <a
107
+ class="nav-link d-flex align-items-center"
108
+ href="{{ url_for('app.index') }}"
109
+ >
110
+ <i class="bi bi-house me-2"></i
111
+ ><span><span>{{ _('Inicio') }}</span></span>
112
+ </a>
113
+ </li>
114
+
115
+ <!-- Empresas -->
116
+ <li class="nav-item">
117
+ <a
118
+ class="nav-link d-flex align-items-center"
119
+ href="{{ url_for('empresa.index') }}"
120
+ >
121
+ <i class="bi bi-building-fill"></i
122
+ ><span><span>{{ _('Empresas') }}</span></span>
123
+ </a>
124
+ </li>
125
+
126
+ <!-- Planillas -->
127
+ <li class="nav-item">
128
+ <a
129
+ class="nav-link d-flex align-items-center"
130
+ href="{{ url_for('planilla.index') }}"
131
+ >
132
+ <i class="bi bi-calculator me-2"></i
133
+ ><span><span>{{ _('Planillas') }}</span></span>
134
+ </a>
135
+ </li>
136
+
137
+ <li class="nav-item">
138
+ <a class="nav-link d-flex align-items-center" href="{{ url_for('liquidacion.index') }}">
139
+ <i class="bi bi-file-earmark-text me-2"></i
140
+ ><span><span>{{ _('Liquidaciones') }}</span></span>
141
+ </a>
142
+ </li>
143
+
144
+ <!-- Empleados -->
145
+ <li class="nav-item">
146
+ <a
147
+ class="nav-link d-flex align-items-center"
148
+ href="{{ url_for('employee.index') }}"
149
+ >
150
+ <i class="bi bi-people me-2"></i
151
+ ><span><span>{{ _('Empleados') }}</span></span>
152
+ </a>
153
+ </li>
154
+
155
+ <!-- Vacaciones -->
156
+ <li class="nav-item">
157
+ <a
158
+ class="nav-link d-flex align-items-center"
159
+ href="{{ url_for('vacation.dashboard') }}"
160
+ >
161
+ <i class="bi bi-calendar-check me-2"></i
162
+ ><span><span>{{ _('Vacaciones') }}</span></span>
163
+ </a>
164
+ </li>
165
+
166
+ <!-- Prestaciones -->
167
+ <li class="nav-item">
168
+ <a
169
+ class="nav-link d-flex align-items-center"
170
+ href="{{ url_for('prestacion_management.dashboard') }}"
171
+ >
172
+ <i class="bi bi-gift me-2"></i
173
+ ><span><span>{{ _('Prestaciones') }}</span></span>
174
+ </a>
175
+ </li>
176
+
177
+ <!-- Préstamos -->
178
+ <li class="nav-item">
179
+ <a
180
+ class="nav-link d-flex align-items-center"
181
+ href="{{ url_for('prestamo.index') }}"
182
+ >
183
+ <i class="bi bi-cash-coin me-2"></i
184
+ ><span><span>{{ _('Préstamos') }}</span></span>
185
+ </a>
186
+ </li>
187
+
188
+ <!-- Usuarios -->
189
+ <li class="nav-item">
190
+ <a
191
+ class="nav-link d-flex align-items-center"
192
+ href="{{ url_for('user.index') }}"
193
+ >
194
+ <i class="bi bi-person-gear me-2"></i
195
+ ><span><span>{{ _('Usuarios') }}</span></span>
196
+ </a>
197
+ </li>
198
+
199
+ {% for active_plugin in plugin_actives %}
200
+ <li class="nav-item">
201
+ <a class="nav-link d-flex align-items-center" href="{{ active_plugin.url }}">
202
+ <i class="{{ active_plugin.icon or 'bi bi-puzzle' }} me-2"></i
203
+ ><span><span>{{ active_plugin.label }}</span></span>
204
+ </a>
205
+ </li>
206
+ {% endfor %}
207
+
208
+ <!-- Configuración -->
209
+ <li class="nav-item">
210
+ <a
211
+ class="nav-link d-flex align-items-center"
212
+ href="{{ url_for('settings.index') }}"
213
+ >
214
+ <i class="bi bi-gear me-2"></i
215
+ ><span><span>{{ _('Configuración') }}</span></span>
216
+ </a>
217
+ </li>
218
+ </ul>
219
+
220
+ <!-- Mobile-only links: Profile and Logout (shown only on small screens) -->
221
+ <div class="mobile-only-links">
222
+ <ul class="nav flex-column">
223
+ <li class="nav-item">
224
+ <a
225
+ class="nav-link d-flex align-items-center"
226
+ href="{{ url_for('user.profile') }}"
227
+ >
228
+ <i class="bi bi-person-circle me-2"></i>
229
+ <span>{{ _('Mi Perfil') }}</span>
230
+ </a>
231
+ </li>
232
+ <li class="nav-item">
233
+ <a
234
+ class="nav-link d-flex align-items-center"
235
+ href="{{ url_for('auth.logout') }}"
236
+ >
237
+ <i class="bi bi-box-arrow-right me-2"></i>
238
+ <span>{{ _('Cerrar Sesión') }}</span>
239
+ </a>
240
+ </li>
241
+ </ul>
242
+ </div>
243
+ </aside>
244
+
245
+ <!-- ======================= CONTENIDO DINÁMICO ======================= -->
246
+ <main class="flex-grow-1 p-4">
247
+ {% block content %}
248
+ <h2>{{ _('Bienvenido a Coaty') }}</h2>
249
+ <p>{{ _('Sistema de Planillas (Payroll)') }}</p>
250
+ {% endblock %}
251
+ </main>
252
+ </div>
253
+
254
+ <!-- Bootstrap JS -->
255
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
256
+
257
+ <!-- Sidebar Toggle Script -->
258
+ <script>
259
+ document
260
+ .getElementById("sidebarToggleMobile")
261
+ .addEventListener("click", function () {
262
+ document.getElementById("sidebar").classList.toggle("open");
263
+ });
264
+
265
+ // Close sidebar when clicking outside of it on mobile
266
+ document.addEventListener("click", function (event) {
267
+ const sidebar = document.getElementById("sidebar");
268
+ const toggleBtn = document.getElementById(
269
+ "sidebarToggleMobile",
270
+ );
271
+
272
+ if (
273
+ window.innerWidth < 992 &&
274
+ sidebar.classList.contains("open") &&
275
+ !sidebar.contains(event.target) &&
276
+ !toggleBtn.contains(event.target)
277
+ ) {
278
+ sidebar.classList.remove("open");
279
+ }
280
+ });
281
+ </script>
282
+ </body>
283
+ </html>