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,145 @@
1
+ {% extends "base.html" %}
2
+ {% from "macros.html" import render_field %}
3
+
4
+ {% block content %}
5
+ <div class="container-fluid py-4">
6
+ <div class="row">
7
+ <div class="col-12">
8
+ <div class="d-flex justify-content-between align-items-center mb-4">
9
+ <h2 class="mb-0">
10
+ <i class="bi {{ config.icon }} me-2"></i>
11
+ {{ config.plural }}
12
+ </h2>
13
+ <a href="{{ url_for(config.blueprint + '.' + config.route_prefix + 'new') }}" class="btn btn-primary">
14
+ <i class="bi bi-plus-lg me-1"></i> {{ _('Nueva %(type)s', type=config.singular) }}
15
+ </a>
16
+ </div>
17
+ </div>
18
+ </div>
19
+
20
+ <div class="row">
21
+ <div class="col-12">
22
+ <div class="card shadow-sm">
23
+ <div class="card-body">
24
+ {% if items %}
25
+ <div class="table-responsive">
26
+ <table class="table table-hover align-middle">
27
+ <thead class="table-light">
28
+ <tr>
29
+ <th>{{ _('Código') }}</th>
30
+ <th>{{ _('Nombre') }}</th>
31
+ <th>{{ _('Tipo Cálculo') }}</th>
32
+ <th class="text-center">{{ _('Recurrente') }}</th>
33
+ <th class="text-center">{{ _('Estado') }}</th>
34
+ <th class="text-end">{{ _('Acciones') }}</th>
35
+ </tr>
36
+ </thead>
37
+ <tbody>
38
+ {% for item in items %}
39
+ <tr>
40
+ <td>
41
+ <code>{{ item.codigo }}</code>
42
+ </td>
43
+ <td>
44
+ <strong>{{ item.nombre }}</strong>
45
+ {% if item.descripcion %}
46
+ <br><small class="text-muted">{{ item.descripcion }}</small>
47
+ {% endif %}
48
+ </td>
49
+ <td>
50
+ <span class="badge bg-secondary">{{ item.formula_tipo }}</span>
51
+ {% if item.porcentaje %}
52
+ <span class="text-muted ms-1">{{ item.porcentaje }}%</span>
53
+ {% elif item.monto_default %}
54
+ <span class="text-muted ms-1">{{ item.monto_default }}</span>
55
+ {% endif %}
56
+ </td>
57
+ <td class="text-center">
58
+ {% if item.recurrente %}
59
+ <i class="bi bi-check-circle-fill text-success"></i>
60
+ {% else %}
61
+ <i class="bi bi-dash text-muted"></i>
62
+ {% endif %}
63
+ </td>
64
+ <td class="text-center">
65
+ {% if item.activo %}
66
+ <span class="badge bg-success">{{ _('Activo') }}</span>
67
+ {% else %}
68
+ <span class="badge bg-secondary">{{ _('Inactivo') }}</span>
69
+ {% endif %}
70
+ </td>
71
+ <td class="text-end">
72
+ <a href="{{ url_for(config.blueprint + '.' + config.route_prefix + 'edit', concept_id=item.id) }}"
73
+ class="btn btn-sm btn-outline-primary"
74
+ title="{{ _('Editar') }}">
75
+ <i class="bi bi-pencil"></i>
76
+ </a>
77
+ <form action="{{ url_for(config.blueprint + '.' + config.route_prefix + 'delete', concept_id=item.id) }}"
78
+ method="post" class="d-inline"
79
+ onsubmit="return confirm('{{ _('¿Está seguro de eliminar esta %(type)s?', type=config.singular) }}');">
80
+ <button type="submit" class="btn btn-sm btn-outline-danger" title="{{ _('Eliminar') }}">
81
+ <i class="bi bi-trash"></i>
82
+ </button>
83
+ </form>
84
+ </td>
85
+ </tr>
86
+ {% endfor %}
87
+ </tbody>
88
+ </table>
89
+ </div>
90
+
91
+ <!-- Pagination -->
92
+ {% if pagination.pages > 1 %}
93
+ <nav aria-label="Page navigation" class="mt-4">
94
+ <ul class="pagination justify-content-center mb-0">
95
+ {% if pagination.has_prev %}
96
+ <li class="page-item">
97
+ <a class="page-link" href="{{ url_for(config.blueprint + '.' + config.route_prefix + 'index', page=pagination.prev_num) }}">
98
+ <i class="bi bi-chevron-left"></i>
99
+ </a>
100
+ </li>
101
+ {% endif %}
102
+
103
+ {% for page_num in pagination.iter_pages(left_edge=1, right_edge=1, left_current=2, right_current=2) %}
104
+ {% if page_num %}
105
+ {% if page_num == pagination.page %}
106
+ <li class="page-item active">
107
+ <span class="page-link">{{ page_num }}</span>
108
+ </li>
109
+ {% else %}
110
+ <li class="page-item">
111
+ <a class="page-link" href="{{ url_for(config.blueprint + '.' + config.route_prefix + 'index', page=page_num) }}">{{ page_num }}</a>
112
+ </li>
113
+ {% endif %}
114
+ {% else %}
115
+ <li class="page-item disabled"><span class="page-link">...</span></li>
116
+ {% endif %}
117
+ {% endfor %}
118
+
119
+ {% if pagination.has_next %}
120
+ <li class="page-item">
121
+ <a class="page-link" href="{{ url_for(config.blueprint + '.' + config.route_prefix + 'index', page=pagination.next_num) }}">
122
+ <i class="bi bi-chevron-right"></i>
123
+ </a>
124
+ </li>
125
+ {% endif %}
126
+ </ul>
127
+ </nav>
128
+ {% endif %}
129
+
130
+ {% else %}
131
+ <div class="text-center py-5">
132
+ <i class="bi {{ config.icon }} display-1 text-muted"></i>
133
+ <h4 class="mt-3">{{ _('No hay %(type)s registradas', type=config.plural|lower) }}</h4>
134
+ <p class="text-muted">{{ _('Comience creando una nueva %(type)s', type=config.singular|lower) }}</p>
135
+ <a href="{{ url_for(config.blueprint + '.' + config.route_prefix + 'new') }}" class="btn btn-primary">
136
+ <i class="bi bi-plus-lg me-1"></i> {{ _('Nueva %(type)s', type=config.singular) }}
137
+ </a>
138
+ </div>
139
+ {% endif %}
140
+ </div>
141
+ </div>
142
+ </div>
143
+ </div>
144
+ </div>
145
+ {% endblock %}
@@ -0,0 +1,70 @@
1
+ {% extends 'base.html' %}
2
+ {% from 'macros.html' import render_field, render_messages, render_form_errors %}
3
+
4
+ {% block content %}
5
+ <div class="container">
6
+ {{ render_messages() }}
7
+ {{ render_form_errors(form) }}
8
+
9
+ <div class="d-flex justify-content-between align-items-center mb-4">
10
+ <h2>{{ title }}</h2>
11
+ <a href="{{ url_for('tipo_planilla.index') }}" class="btn btn-secondary">
12
+ <i class="bi bi-arrow-left me-1"></i>{{ _('Volver') }}
13
+ </a>
14
+ </div>
15
+
16
+ <div class="card">
17
+ <div class="card-body">
18
+ <form method="POST" action="">
19
+ {{ form.hidden_tag() }}
20
+
21
+ <div class="row">
22
+ <div class="col-md-4">
23
+ {{ render_field(form.codigo) }}
24
+ </div>
25
+ <div class="col-md-8">
26
+ {{ render_field(form.descripcion) }}
27
+ </div>
28
+ </div>
29
+
30
+ <div class="row">
31
+ <div class="col-md-4">
32
+ {{ render_field(form.periodicidad) }}
33
+ </div>
34
+ <div class="col-md-4">
35
+ {{ render_field(form.dias) }}
36
+ </div>
37
+ <div class="col-md-4">
38
+ {{ render_field(form.periodos_por_anio) }}
39
+ </div>
40
+ </div>
41
+
42
+ <h5 class="mt-4 mb-3">{{ _('Configuración Fiscal') }}</h5>
43
+
44
+ <div class="row">
45
+ <div class="col-md-4">
46
+ {{ render_field(form.mes_inicio_fiscal) }}
47
+ </div>
48
+ <div class="col-md-4">
49
+ {{ render_field(form.dia_inicio_fiscal) }}
50
+ </div>
51
+ <div class="col-md-4">
52
+ {{ render_field(form.acumula_anual) }}
53
+ </div>
54
+ </div>
55
+
56
+ <div class="row">
57
+ <div class="col-md-6">
58
+ {{ render_field(form.activo) }}
59
+ </div>
60
+ </div>
61
+
62
+ <div class="mt-4">
63
+ {{ form.submit(class="btn btn-primary") }}
64
+ <a href="{{ url_for('tipo_planilla.index') }}" class="btn btn-secondary">{{ _('Cancelar') }}</a>
65
+ </div>
66
+ </form>
67
+ </div>
68
+ </div>
69
+ </div>
70
+ {% endblock %}
@@ -0,0 +1,68 @@
1
+ {% extends 'base.html' %}
2
+ {% from 'macros.html' import render_messages, render_pagination %}
3
+
4
+ {% block content %}
5
+ <div class="container">
6
+ {{ render_messages() }}
7
+
8
+ <div class="d-flex justify-content-between align-items-center mb-4">
9
+ <h2>{{ _('Tipos de Planilla') }}</h2>
10
+ <a href="{{ url_for('tipo_planilla.new') }}" class="btn btn-primary">
11
+ <i class="bi bi-plus-lg me-1"></i>{{ _('Nuevo Tipo de Planilla') }}
12
+ </a>
13
+ </div>
14
+
15
+ <div class="card">
16
+ <div class="card-body">
17
+ <div class="table-responsive">
18
+ <table class="table table-hover">
19
+ <thead>
20
+ <tr>
21
+ <th>{{ _('Código') }}</th>
22
+ <th>{{ _('Descripción') }}</th>
23
+ <th>{{ _('Periodicidad') }}</th>
24
+ <th>{{ _('Días') }}</th>
25
+ <th>{{ _('Períodos/Año') }}</th>
26
+ <th>{{ _('Estado') }}</th>
27
+ <th>{{ _('Acciones') }}</th>
28
+ </tr>
29
+ </thead>
30
+ <tbody>
31
+ {% for tipo in tipos_planilla %}
32
+ <tr>
33
+ <td><strong>{{ tipo.codigo }}</strong></td>
34
+ <td>{{ tipo.descripcion or '-' }}</td>
35
+ <td>{{ tipo.periodicidad | capitalize }}</td>
36
+ <td>{{ tipo.dias }}</td>
37
+ <td>{{ tipo.periodos_por_anio }}</td>
38
+ <td>
39
+ {% if tipo.activo %}
40
+ <span class="badge bg-success">{{ _('Activo') }}</span>
41
+ {% else %}
42
+ <span class="badge bg-warning">{{ _('Inactivo') }}</span>
43
+ {% endif %}
44
+ </td>
45
+ <td>
46
+ <a href="{{ url_for('tipo_planilla.edit', id=tipo.id) }}" class="btn btn-sm btn-outline-primary" title="{{ _('Editar') }}">
47
+ <i class="bi bi-pencil"></i>
48
+ </a>
49
+ <form action="{{ url_for('tipo_planilla.delete', id=tipo.id) }}" method="POST" class="d-inline" onsubmit="return confirm('{{ _('¿Está seguro de eliminar este tipo de planilla?') }}');">
50
+ <button type="submit" class="btn btn-sm btn-outline-danger" title="{{ _('Eliminar') }}">
51
+ <i class="bi bi-trash"></i>
52
+ </button>
53
+ </form>
54
+ </td>
55
+ </tr>
56
+ {% else %}
57
+ <tr>
58
+ <td colspan="7" class="text-center text-muted">{{ _('No hay tipos de planilla registrados.') }}</td>
59
+ </tr>
60
+ {% endfor %}
61
+ </tbody>
62
+ </table>
63
+ </div>
64
+ {{ render_pagination(pagination, 'tipo_planilla.index') }}
65
+ </div>
66
+ </div>
67
+ </div>
68
+ {% endblock %}
@@ -0,0 +1,65 @@
1
+ {% extends 'base.html' %}
2
+ {% from 'macros.html' import render_field, render_messages, render_form_errors %}
3
+
4
+ {% block content %}
5
+ <div class="container">
6
+ {{ render_messages() }}
7
+ {{ render_form_errors(form) }}
8
+
9
+ <div class="d-flex justify-content-between align-items-center mb-4">
10
+ <h2>{{ title }}</h2>
11
+ <a href="{{ url_for('user.index') }}" class="btn btn-secondary">
12
+ <i class="bi bi-arrow-left me-1"></i>{{ _('Volver') }}
13
+ </a>
14
+ </div>
15
+
16
+ <div class="card">
17
+ <div class="card-body">
18
+ <form method="POST" action="">
19
+ {{ form.hidden_tag() }}
20
+
21
+ <div class="row">
22
+ <div class="col-md-6">
23
+ {{ render_field(form.usuario) }}
24
+ </div>
25
+ <div class="col-md-6">
26
+ {{ render_field(form.password) }}
27
+ {% if user %}
28
+ <small class="text-muted">{{ _('Dejar en blanco para mantener la contraseña actual.') }}</small>
29
+ {% endif %}
30
+ </div>
31
+ </div>
32
+
33
+ <div class="row">
34
+ <div class="col-md-6">
35
+ {{ render_field(form.nombre) }}
36
+ </div>
37
+ <div class="col-md-6">
38
+ {{ render_field(form.apellido) }}
39
+ </div>
40
+ </div>
41
+
42
+ <div class="row">
43
+ <div class="col-md-6">
44
+ {{ render_field(form.correo_electronico) }}
45
+ </div>
46
+ <div class="col-md-6">
47
+ {{ render_field(form.tipo) }}
48
+ </div>
49
+ </div>
50
+
51
+ <div class="row">
52
+ <div class="col-md-6">
53
+ {{ render_field(form.activo) }}
54
+ </div>
55
+ </div>
56
+
57
+ <div class="mt-4">
58
+ {{ form.submit(class="btn btn-primary") }}
59
+ <a href="{{ url_for('user.index') }}" class="btn btn-secondary">{{ _('Cancelar') }}</a>
60
+ </div>
61
+ </form>
62
+ </div>
63
+ </div>
64
+ </div>
65
+ {% endblock %}
@@ -0,0 +1,76 @@
1
+ {% extends 'base.html' %}
2
+ {% from 'macros.html' import render_messages, render_pagination %}
3
+
4
+ {% block content %}
5
+ <div class="container">
6
+ {{ render_messages() }}
7
+
8
+ <div class="d-flex justify-content-between align-items-center mb-4">
9
+ <h2>{{ _('Usuarios') }}</h2>
10
+ <a href="{{ url_for('user.new') }}" class="btn btn-primary">
11
+ <i class="bi bi-plus-lg me-1"></i>{{ _('Nuevo Usuario') }}
12
+ </a>
13
+ </div>
14
+
15
+ <div class="card">
16
+ <div class="card-body">
17
+ <div class="table-responsive">
18
+ <table class="table table-hover">
19
+ <thead>
20
+ <tr>
21
+ <th>{{ _('Usuario') }}</th>
22
+ <th>{{ _('Nombre') }}</th>
23
+ <th>{{ _('Correo') }}</th>
24
+ <th>{{ _('Tipo') }}</th>
25
+ <th>{{ _('Estado') }}</th>
26
+ <th>{{ _('Acciones') }}</th>
27
+ </tr>
28
+ </thead>
29
+ <tbody>
30
+ {% for user in users %}
31
+ <tr>
32
+ <td>{{ user.usuario }}</td>
33
+ <td>{{ user.nombre }} {{ user.apellido }}</td>
34
+ <td>{{ user.correo_electronico or '-' }}</td>
35
+ <td>
36
+ {% if user.tipo == 'admin' %}
37
+ <span class="badge bg-danger">{{ _('Administrador') }}</span>
38
+ {% elif user.tipo == 'hhrr' %}
39
+ <span class="badge bg-primary">{{ _('Recursos Humanos') }}</span>
40
+ {% elif user.tipo == 'audit' %}
41
+ <span class="badge bg-secondary">{{ _('Auditoría') }}</span>
42
+ {% else %}
43
+ <span class="badge bg-light text-dark">{{ user.tipo }}</span>
44
+ {% endif %}
45
+ </td>
46
+ <td>
47
+ {% if user.activo %}
48
+ <span class="badge bg-success">{{ _('Activo') }}</span>
49
+ {% else %}
50
+ <span class="badge bg-warning">{{ _('Inactivo') }}</span>
51
+ {% endif %}
52
+ </td>
53
+ <td>
54
+ <a href="{{ url_for('user.edit', id=user.id) }}" class="btn btn-sm btn-outline-primary" title="{{ _('Editar') }}">
55
+ <i class="bi bi-pencil"></i>
56
+ </a>
57
+ <form action="{{ url_for('user.delete', id=user.id) }}" method="POST" class="d-inline" onsubmit="return confirm('{{ _('¿Está seguro de eliminar este usuario?') }}');">
58
+ <button type="submit" class="btn btn-sm btn-outline-danger" title="{{ _('Eliminar') }}">
59
+ <i class="bi bi-trash"></i>
60
+ </button>
61
+ </form>
62
+ </td>
63
+ </tr>
64
+ {% else %}
65
+ <tr>
66
+ <td colspan="6" class="text-center text-muted">{{ _('No hay usuarios registrados.') }}</td>
67
+ </tr>
68
+ {% endfor %}
69
+ </tbody>
70
+ </table>
71
+ </div>
72
+ {{ render_pagination(pagination, 'user.index') }}
73
+ </div>
74
+ </div>
75
+ </div>
76
+ {% endblock %}
@@ -0,0 +1,81 @@
1
+ {% extends 'base.html' %}
2
+ {% from 'macros.html' import render_field, render_messages, render_form_errors %}
3
+
4
+ {% block content %}
5
+ <div class="container">
6
+ {{ render_messages() }}
7
+ {{ render_form_errors(form) }}
8
+
9
+ <div class="d-flex justify-content-between align-items-center mb-4">
10
+ <h2><i class="bi bi-person-circle me-2"></i>{{ _('Mi Perfil') }}</h2>
11
+ <a href="{{ url_for('app.index') }}" class="btn btn-secondary">
12
+ <i class="bi bi-arrow-left me-1"></i>{{ _('Volver') }}
13
+ </a>
14
+ </div>
15
+
16
+ <div class="card">
17
+ <div class="card-body">
18
+ <form method="POST" action="">
19
+ {{ form.hidden_tag() }}
20
+
21
+ <h5 class="mb-3">{{ _('Información Personal') }}</h5>
22
+
23
+ <div class="row">
24
+ <div class="col-md-6">
25
+ <div class="mb-3">
26
+ <label class="form-label"><strong>{{ _('Usuario') }}</strong></label>
27
+ <p class="form-control-plaintext">{{ current_user.usuario }}</p>
28
+ </div>
29
+ </div>
30
+ <div class="col-md-6">
31
+ <div class="mb-3">
32
+ <label class="form-label"><strong>{{ _('Tipo de usuario') }}</strong></label>
33
+ <p class="form-control-plaintext">{{ current_user.tipo|title }}</p>
34
+ </div>
35
+ </div>
36
+ </div>
37
+
38
+ <div class="row">
39
+ <div class="col-md-6">
40
+ {{ render_field(form.nombre) }}
41
+ </div>
42
+ <div class="col-md-6">
43
+ {{ render_field(form.apellido) }}
44
+ </div>
45
+ </div>
46
+
47
+ <div class="row">
48
+ <div class="col-md-6">
49
+ {{ render_field(form.correo_electronico) }}
50
+ </div>
51
+ </div>
52
+
53
+ <hr class="my-4">
54
+
55
+ <h5 class="mb-3">{{ _('Cambiar Contraseña') }}</h5>
56
+ <p class="text-muted small">{{ _('Deja estos campos en blanco si no deseas cambiar tu contraseña.') }}</p>
57
+
58
+ <div class="row">
59
+ <div class="col-md-6">
60
+ {{ render_field(form.current_password) }}
61
+ </div>
62
+ </div>
63
+
64
+ <div class="row">
65
+ <div class="col-md-6">
66
+ {{ render_field(form.new_password) }}
67
+ </div>
68
+ <div class="col-md-6">
69
+ {{ render_field(form.confirm_password) }}
70
+ </div>
71
+ </div>
72
+
73
+ <div class="mt-4">
74
+ {{ form.submit(class="btn btn-primary") }}
75
+ <a href="{{ url_for('app.index') }}" class="btn btn-secondary">{{ _('Cancelar') }}</a>
76
+ </div>
77
+ </form>
78
+ </div>
79
+ </div>
80
+ </div>
81
+ {% endblock %}
@@ -0,0 +1,149 @@
1
+ {% extends 'base.html' %}
2
+ {% from 'macros.html' import render_messages %}
3
+
4
+ {% block content %}
5
+ <div class="container">
6
+ {{ render_messages() }}
7
+
8
+ <div class="d-flex justify-content-between align-items-center mb-4">
9
+ <h2>{{ _('Cuenta de Vacaciones') }} - {{ account.empleado.primer_nombre }} {{ account.empleado.primer_apellido }}</h2>
10
+ <a href="{{ url_for('vacation.account_index') }}" class="btn btn-secondary">
11
+ <i class="bi bi-arrow-left me-1"></i>{{ _('Volver') }}
12
+ </a>
13
+ </div>
14
+
15
+ <div class="row">
16
+ <div class="col-md-4">
17
+ <div class="card mb-4">
18
+ <div class="card-header bg-primary text-white">
19
+ <h5 class="mb-0">{{ _('Balance Actual') }}</h5>
20
+ </div>
21
+ <div class="card-body text-center">
22
+ <h1 class="display-3">{{ account.current_balance }}</h1>
23
+ <p class="text-muted">{{ account.policy.unit_type }}</p>
24
+ </div>
25
+ </div>
26
+
27
+ <div class="card mb-4">
28
+ <div class="card-header">
29
+ <h5 class="mb-0">{{ _('Información de la Cuenta') }}</h5>
30
+ </div>
31
+ <div class="card-body">
32
+ <dl>
33
+ <dt>{{ _('Empleado') }}</dt>
34
+ <dd>{{ account.empleado.primer_nombre }} {{ account.empleado.primer_apellido }}</dd>
35
+
36
+ <dt>{{ _('Código') }}</dt>
37
+ <dd><strong>{{ account.empleado.codigo_empleado }}</strong></dd>
38
+
39
+ <dt>{{ _('Política') }}</dt>
40
+ <dd>
41
+ <a href="{{ url_for('vacation.policy_detail', policy_id=account.policy.id) }}">
42
+ {{ account.policy.nombre }}
43
+ </a>
44
+ </dd>
45
+
46
+ <dt>{{ _('Última Acumulación') }}</dt>
47
+ <dd>{{ account.last_accrual_date.strftime('%Y-%m-%d') if account.last_accrual_date else '-' }}</dd>
48
+
49
+ <dt>{{ _('Estado') }}</dt>
50
+ <dd>
51
+ {% if account.activo %}
52
+ <span class="badge bg-success">{{ _('Activa') }}</span>
53
+ {% else %}
54
+ <span class="badge bg-warning">{{ _('Inactiva') }}</span>
55
+ {% endif %}
56
+ </dd>
57
+ </dl>
58
+ </div>
59
+ </div>
60
+
61
+ {% if pending_requests %}
62
+ <div class="card mb-4">
63
+ <div class="card-header bg-warning text-dark">
64
+ <h5 class="mb-0">{{ _('Solicitudes Pendientes') }}</h5>
65
+ </div>
66
+ <div class="card-body">
67
+ <ul class="list-group">
68
+ {% for request in pending_requests %}
69
+ <li class="list-group-item">
70
+ <div class="d-flex justify-content-between align-items-center">
71
+ <div>
72
+ <strong>{{ request.start_date.strftime('%Y-%m-%d') }}</strong> al
73
+ <strong>{{ request.end_date.strftime('%Y-%m-%d') }}</strong>
74
+ <br>
75
+ <small>{{ request.units }} {{ account.policy.unit_type }}</small>
76
+ </div>
77
+ <a href="{{ url_for('vacation.leave_request_detail', request_id=request.id) }}"
78
+ class="btn btn-sm btn-outline-primary">
79
+ <i class="bi bi-eye"></i>
80
+ </a>
81
+ </div>
82
+ </li>
83
+ {% endfor %}
84
+ </ul>
85
+ </div>
86
+ </div>
87
+ {% endif %}
88
+ </div>
89
+
90
+ <div class="col-md-8">
91
+ <div class="card">
92
+ <div class="card-header">
93
+ <h5 class="mb-0">{{ _('Historial de Movimientos') }}</h5>
94
+ </div>
95
+ <div class="card-body">
96
+ <div class="table-responsive">
97
+ <table class="table table-sm">
98
+ <thead>
99
+ <tr>
100
+ <th>{{ _('Fecha') }}</th>
101
+ <th>{{ _('Tipo') }}</th>
102
+ <th>{{ _('Cantidad') }}</th>
103
+ <th>{{ _('Balance Después') }}</th>
104
+ <th>{{ _('Origen') }}</th>
105
+ <th>{{ _('Observaciones') }}</th>
106
+ </tr>
107
+ </thead>
108
+ <tbody>
109
+ {% for entry in ledger_entries %}
110
+ <tr>
111
+ <td>{{ entry.fecha.strftime('%Y-%m-%d') }}</td>
112
+ <td>
113
+ {% if entry.entry_type == 'accrual' %}
114
+ <span class="badge bg-success">{{ _('Acumulación') }}</span>
115
+ {% elif entry.entry_type == 'usage' %}
116
+ <span class="badge bg-info">{{ _('Uso') }}</span>
117
+ {% elif entry.entry_type == 'adjustment' %}
118
+ <span class="badge bg-warning">{{ _('Ajuste') }}</span>
119
+ {% elif entry.entry_type == 'expiration' %}
120
+ <span class="badge bg-danger">{{ _('Vencimiento') }}</span>
121
+ {% elif entry.entry_type == 'payout' %}
122
+ <span class="badge bg-secondary">{{ _('Pago') }}</span>
123
+ {% endif %}
124
+ </td>
125
+ <td>
126
+ {% if entry.quantity >= 0 %}
127
+ <span class="text-success">+{{ entry.quantity }}</span>
128
+ {% else %}
129
+ <span class="text-danger">{{ entry.quantity }}</span>
130
+ {% endif %}
131
+ </td>
132
+ <td>{{ entry.balance_after }}</td>
133
+ <td>{{ entry.source }}</td>
134
+ <td>{{ entry.observaciones or '-' }}</td>
135
+ </tr>
136
+ {% else %}
137
+ <tr>
138
+ <td colspan="6" class="text-center text-muted">{{ _('No hay movimientos registrados.') }}</td>
139
+ </tr>
140
+ {% endfor %}
141
+ </tbody>
142
+ </table>
143
+ </div>
144
+ </div>
145
+ </div>
146
+ </div>
147
+ </div>
148
+ </div>
149
+ {% endblock %}