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,91 @@
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><i class="bi bi-file-earmark-text me-2"></i>{{ _('Liquidación') }}</h2>
10
+ <div class="d-flex gap-2">
11
+ <a class="btn btn-outline-primary" href="{{ url_for('liquidacion.exportar_excel', liquidacion_id=liquidacion.id) }}">
12
+ {{ _('Exportar Excel') }}
13
+ </a>
14
+ {% if liquidacion.estado == 'borrador' %}
15
+ <form method="POST" action="{{ url_for('liquidacion.recalcular', liquidacion_id=liquidacion.id) }}">
16
+ <button type="submit" class="btn btn-outline-primary">{{ _('Recalcular') }}</button>
17
+ </form>
18
+ <form method="POST" action="{{ url_for('liquidacion.aplicar', liquidacion_id=liquidacion.id) }}">
19
+ <button type="submit" class="btn btn-success">{{ _('Aplicar') }}</button>
20
+ </form>
21
+ {% elif liquidacion.estado == 'aplicada' %}
22
+ <form method="POST" action="{{ url_for('liquidacion.pagar', liquidacion_id=liquidacion.id) }}">
23
+ <button type="submit" class="btn btn-success">{{ _('Marcar Pagada') }}</button>
24
+ </form>
25
+ {% endif %}
26
+ <a href="{{ url_for('liquidacion.index') }}" class="btn btn-outline-secondary">
27
+ <i class="bi bi-arrow-left me-1"></i>{{ _('Volver') }}
28
+ </a>
29
+ </div>
30
+ </div>
31
+
32
+ <div class="card mb-3">
33
+ <div class="card-body">
34
+ <div class="row">
35
+ <div class="col-md-6">
36
+ <div><strong>{{ _('Empleado') }}:</strong>
37
+ {% if liquidacion.empleado %}
38
+ {{ liquidacion.empleado.primer_nombre }} {{ liquidacion.empleado.primer_apellido }}
39
+ {% else %}
40
+ {{ liquidacion.empleado_id }}
41
+ {% endif %}
42
+ </div>
43
+ <div><strong>{{ _('Fecha Cálculo') }}:</strong> {{ liquidacion.fecha_calculo }}</div>
44
+ <div><strong>{{ _('Último Día Pagado') }}:</strong> {{ liquidacion.ultimo_dia_pagado }}</div>
45
+ </div>
46
+ <div class="col-md-6">
47
+ <div><strong>{{ _('Días por Pagar') }}:</strong> {{ liquidacion.dias_por_pagar }}</div>
48
+ <div><strong>{{ _('Total Bruto') }}:</strong> {{ liquidacion.total_bruto }}</div>
49
+ <div><strong>{{ _('Total Deducciones') }}:</strong> {{ liquidacion.total_deducciones }}</div>
50
+ <div><strong>{{ _('Total Neto') }}:</strong> {{ liquidacion.total_neto }}</div>
51
+ <div><strong>{{ _('Estado') }}:</strong> {{ liquidacion.estado }}</div>
52
+ </div>
53
+ </div>
54
+ </div>
55
+ </div>
56
+
57
+ <div class="card">
58
+ <div class="card-header">
59
+ <h5 class="mb-0">{{ _('Detalle') }}</h5>
60
+ </div>
61
+ <div class="card-body">
62
+ {% if liquidacion.detalles %}
63
+ <div class="table-responsive">
64
+ <table class="table table-striped">
65
+ <thead>
66
+ <tr>
67
+ <th>{{ _('Tipo') }}</th>
68
+ <th>{{ _('Código') }}</th>
69
+ <th>{{ _('Descripción') }}</th>
70
+ <th class="text-end">{{ _('Monto') }}</th>
71
+ </tr>
72
+ </thead>
73
+ <tbody>
74
+ {% for d in liquidacion.detalles|sort(attribute='orden') %}
75
+ <tr>
76
+ <td>{{ d.tipo }}</td>
77
+ <td>{{ d.codigo }}</td>
78
+ <td>{{ d.descripcion }}</td>
79
+ <td class="text-end">{{ d.monto }}</td>
80
+ </tr>
81
+ {% endfor %}
82
+ </tbody>
83
+ </table>
84
+ </div>
85
+ {% else %}
86
+ <p class="text-muted mb-0">{{ _('No hay detalles.') }}</p>
87
+ {% endif %}
88
+ </div>
89
+ </div>
90
+ </div>
91
+ {% endblock %}
@@ -0,0 +1,146 @@
1
+ {% extends "base.html" %}
2
+ {% block title %}{{ _('Historial de Auditoría') }} - {{ concept.nombre }}{% endblock %}
3
+
4
+ {% block content %}
5
+ <div class="container-fluid">
6
+ <div class="row mb-4">
7
+ <div class="col-md-12">
8
+ <nav aria-label="breadcrumb">
9
+ <ol class="breadcrumb">
10
+ <li class="breadcrumb-item"><a href="{{ url_for('main.index') }}">{{ _('Inicio') }}</a></li>
11
+ <li class="breadcrumb-item"><a href="{{ url_for(config['blueprint'] + '.' + config['route_prefix'] + 'index') }}">{{ config['plural'] }}</a></li>
12
+ <li class="breadcrumb-item active" aria-current="page">{{ _('Historial de Auditoría') }}</li>
13
+ </ol>
14
+ </nav>
15
+ </div>
16
+ </div>
17
+
18
+ <div class="row mb-4">
19
+ <div class="col-md-12">
20
+ <div class="card">
21
+ <div class="card-header bg-primary text-white">
22
+ <h4 class="mb-0">
23
+ <i class="bi bi-clock-history"></i>
24
+ {{ _('Historial de Auditoría') }}: {{ concept.nombre }}
25
+ </h4>
26
+ </div>
27
+ <div class="card-body">
28
+ <div class="row mb-3">
29
+ <div class="col-md-6">
30
+ <p><strong>{{ _('Código') }}:</strong> {{ concept.codigo }}</p>
31
+ <p><strong>{{ _('Tipo') }}:</strong> {{ config['singular'] }}</p>
32
+ </div>
33
+ <div class="col-md-6">
34
+ <p>
35
+ <strong>{{ _('Estado Actual') }}:</strong>
36
+ {% if concept.estado_aprobacion == 'aprobado' %}
37
+ <span class="badge bg-success">{{ _('Aprobado') }}</span>
38
+ {% else %}
39
+ <span class="badge bg-warning text-dark">{{ _('Borrador') }}</span>
40
+ {% endif %}
41
+ </p>
42
+ {% if concept.aprobado_por %}
43
+ <p><strong>{{ _('Aprobado por') }}:</strong> {{ concept.aprobado_por }}</p>
44
+ <p><strong>{{ _('Fecha de aprobación') }}:</strong> {{ concept.aprobado_en.strftime('%Y-%m-%d %H:%M:%S') if concept.aprobado_en else '-' }}</p>
45
+ {% endif %}
46
+ </div>
47
+ </div>
48
+
49
+ <hr>
50
+
51
+ <h5 class="mb-3">{{ _('Registro de Cambios') }}</h5>
52
+
53
+ {% if audit_logs %}
54
+ <div class="table-responsive">
55
+ <table class="table table-striped table-hover">
56
+ <thead class="table-light">
57
+ <tr>
58
+ <th style="width: 15%;">{{ _('Fecha/Hora') }}</th>
59
+ <th style="width: 12%;">{{ _('Usuario') }}</th>
60
+ <th style="width: 12%;">{{ _('Acción') }}</th>
61
+ <th style="width: 15%;">{{ _('Estado') }}</th>
62
+ <th style="width: 46%;">{{ _('Descripción') }}</th>
63
+ </tr>
64
+ </thead>
65
+ <tbody>
66
+ {% for log in audit_logs %}
67
+ <tr>
68
+ <td>{{ log.timestamp.strftime('%Y-%m-%d %H:%M:%S') }}</td>
69
+ <td>{{ log.usuario }}</td>
70
+ <td>
71
+ {% if log.accion == 'created' %}
72
+ <span class="badge bg-info">{{ _('Creado') }}</span>
73
+ {% elif log.accion == 'updated' %}
74
+ <span class="badge bg-primary">{{ _('Actualizado') }}</span>
75
+ {% elif log.accion == 'approved' %}
76
+ <span class="badge bg-success">{{ _('Aprobado') }}</span>
77
+ {% elif log.accion == 'rejected' %}
78
+ <span class="badge bg-danger">{{ _('Rechazado') }}</span>
79
+ {% elif log.accion == 'migrated' %}
80
+ <span class="badge bg-secondary">{{ _('Migrado') }}</span>
81
+ {% else %}
82
+ <span class="badge bg-secondary">{{ log.accion }}</span>
83
+ {% endif %}
84
+ </td>
85
+ <td>
86
+ {% if log.estado_anterior and log.estado_nuevo %}
87
+ <span class="badge bg-secondary">{{ log.estado_anterior }}</span>
88
+ <i class="bi bi-arrow-right"></i>
89
+ {% if log.estado_nuevo == 'aprobado' %}
90
+ <span class="badge bg-success">{{ log.estado_nuevo }}</span>
91
+ {% else %}
92
+ <span class="badge bg-warning text-dark">{{ log.estado_nuevo }}</span>
93
+ {% endif %}
94
+ {% elif log.estado_nuevo %}
95
+ {% if log.estado_nuevo == 'aprobado' %}
96
+ <span class="badge bg-success">{{ log.estado_nuevo }}</span>
97
+ {% else %}
98
+ <span class="badge bg-warning text-dark">{{ log.estado_nuevo }}</span>
99
+ {% endif %}
100
+ {% else %}
101
+ -
102
+ {% endif %}
103
+ </td>
104
+ <td>
105
+ {{ log.descripcion or '-' }}
106
+ {% if log.cambios %}
107
+ <button class="btn btn-sm btn-outline-secondary" type="button"
108
+ data-bs-toggle="collapse"
109
+ data-bs-target="#cambios-{{ log.id }}"
110
+ aria-expanded="false">
111
+ <i class="bi bi-chevron-down"></i> {{ _('Ver detalles') }}
112
+ </button>
113
+ <div class="collapse mt-2" id="cambios-{{ log.id }}">
114
+ <div class="card card-body bg-light">
115
+ <small>
116
+ <strong>{{ _('Cambios detallados') }}:</strong>
117
+ <pre class="mb-0">{{ log.cambios | tojson(indent=2) }}</pre>
118
+ </small>
119
+ </div>
120
+ </div>
121
+ {% endif %}
122
+ </td>
123
+ </tr>
124
+ {% endfor %}
125
+ </tbody>
126
+ </table>
127
+ </div>
128
+ {% else %}
129
+ <div class="alert alert-info">
130
+ <i class="bi bi-info-circle"></i>
131
+ {{ _('No hay registros de auditoría para este concepto.') }}
132
+ </div>
133
+ {% endif %}
134
+
135
+ <div class="mt-4">
136
+ <a href="{{ url_for(config['blueprint'] + '.' + config['route_prefix'] + 'index') }}"
137
+ class="btn btn-secondary">
138
+ <i class="bi bi-arrow-left"></i> {{ _('Volver') }}
139
+ </a>
140
+ </div>
141
+ </div>
142
+ </div>
143
+ </div>
144
+ </div>
145
+ </div>
146
+ {% endblock %}
@@ -0,0 +1 @@
1
+ {% extends "modules/shared/concept_form.html" %}
@@ -0,0 +1 @@
1
+ {% extends "modules/shared/concept_index.html" %}
@@ -0,0 +1,190 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% block content %}
4
+ <div class="container-fluid">
5
+ <div class="d-flex justify-content-between align-items-center mb-4">
6
+ <h2>
7
+ <i class="bi bi-calculator me-2"></i>
8
+ {{ _('Configuración de Planilla') }}: {{ planilla.nombre }}
9
+ </h2>
10
+ <div>
11
+ <a href="{{ url_for('planilla.ejecutar_nomina', planilla_id=planilla.id) }}" class="btn btn-success me-2">
12
+ <i class="bi bi-play-fill me-1"></i>{{ _('Ejecutar Nómina') }}
13
+ </a>
14
+ <a href="{{ url_for('planilla.index') }}" class="btn btn-outline-secondary">
15
+ <i class="bi bi-arrow-left me-1"></i>{{ _('Volver a Planillas') }}
16
+ </a>
17
+ </div>
18
+ </div>
19
+
20
+ {% with messages = get_flashed_messages(with_categories=true) %}
21
+ {% if messages %}
22
+ {% for category, message in messages %}
23
+ <div class="alert alert-{{ 'danger' if category == 'error' else category }} alert-dismissible fade show" role="alert">
24
+ {{ message }}
25
+ <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
26
+ </div>
27
+ {% endfor %}
28
+ {% endif %}
29
+ {% endwith %}
30
+
31
+ <!-- Planilla summary card -->
32
+ <div class="card shadow-sm mb-4">
33
+ <div class="card-header bg-coaty-light">
34
+ <h5 class="mb-0"><i class="bi bi-info-circle me-2"></i>{{ _('Resumen de la Planilla') }}</h5>
35
+ </div>
36
+ <div class="card-body">
37
+ <div class="row">
38
+ <div class="col-md-6">
39
+ <p><strong>{{ _('Nombre') }}:</strong> {{ planilla.nombre }}</p>
40
+ <p><strong>{{ _('Descripción') }}:</strong> {{ planilla.descripcion or '-' }}</p>
41
+ <p><strong>{{ _('Tipo de Planilla') }}:</strong>
42
+ {% if planilla.tipo_planilla %}
43
+ {{ planilla.tipo_planilla.codigo }} - {{ planilla.tipo_planilla.descripcion or '' }}
44
+ {% else %}
45
+ -
46
+ {% endif %}
47
+ </p>
48
+ </div>
49
+ <div class="col-md-6">
50
+ <p><strong>{{ _('Moneda') }}:</strong>
51
+ {% if planilla.moneda %}
52
+ {{ planilla.moneda.codigo }} - {{ planilla.moneda.nombre }}
53
+ {% else %}
54
+ -
55
+ {% endif %}
56
+ </p>
57
+ <p><strong>{{ _('Estado') }}:</strong>
58
+ {% if planilla.activo %}
59
+ <span class="badge bg-success">{{ _('Activo') }}</span>
60
+ {% else %}
61
+ <span class="badge bg-secondary">{{ _('Inactivo') }}</span>
62
+ {% endif %}
63
+ </p>
64
+ </div>
65
+ </div>
66
+ <div class="text-end mt-3">
67
+ <a href="{{ url_for('planilla.edit', planilla_id=planilla.id) }}" class="btn btn-outline-primary">
68
+ <i class="bi bi-pencil me-1"></i>{{ _('Editar Configuración General') }}
69
+ </a>
70
+ </div>
71
+ </div>
72
+ </div>
73
+
74
+ <!-- Configuration sections -->
75
+ <div class="row">
76
+ <!-- Empleados -->
77
+ <div class="col-md-6 col-lg-4 mb-4">
78
+ <div class="card shadow-sm h-100">
79
+ <div class="card-body text-center">
80
+ <div class="mb-3">
81
+ <i class="bi bi-people display-4 text-primary"></i>
82
+ </div>
83
+ <h5 class="card-title">{{ _('Empleados') }}</h5>
84
+ <p class="card-text">
85
+ <span class="badge bg-primary fs-5">{{ empleados_count }}</span>
86
+ <br><small class="text-muted">{{ _('empleados asignados') }}</small>
87
+ </p>
88
+ <a href="{{ url_for('planilla.config_empleados', planilla_id=planilla.id) }}" class="btn btn-outline-primary">
89
+ <i class="bi bi-gear me-1"></i>{{ _('Gestionar') }}
90
+ </a>
91
+ </div>
92
+ </div>
93
+ </div>
94
+
95
+ <!-- Percepciones -->
96
+ <div class="col-md-6 col-lg-4 mb-4">
97
+ <div class="card shadow-sm h-100">
98
+ <div class="card-body text-center">
99
+ <div class="mb-3">
100
+ <i class="bi bi-plus-circle display-4 text-success"></i>
101
+ </div>
102
+ <h5 class="card-title">{{ _('Percepciones') }}</h5>
103
+ <p class="card-text">
104
+ <span class="badge bg-success fs-5">{{ percepciones_count }}</span>
105
+ <br><small class="text-muted">{{ _('percepciones asignadas') }}</small>
106
+ </p>
107
+ <a href="{{ url_for('planilla.config_percepciones', planilla_id=planilla.id) }}" class="btn btn-outline-success">
108
+ <i class="bi bi-gear me-1"></i>{{ _('Gestionar') }}
109
+ </a>
110
+ </div>
111
+ </div>
112
+ </div>
113
+
114
+ <!-- Deducciones -->
115
+ <div class="col-md-6 col-lg-4 mb-4">
116
+ <div class="card shadow-sm h-100">
117
+ <div class="card-body text-center">
118
+ <div class="mb-3">
119
+ <i class="bi bi-dash-circle display-4 text-danger"></i>
120
+ </div>
121
+ <h5 class="card-title">{{ _('Deducciones') }}</h5>
122
+ <p class="card-text">
123
+ <span class="badge bg-danger fs-5">{{ deducciones_count }}</span>
124
+ <br><small class="text-muted">{{ _('deducciones asignadas') }}</small>
125
+ </p>
126
+ <a href="{{ url_for('planilla.config_deducciones', planilla_id=planilla.id) }}" class="btn btn-outline-danger">
127
+ <i class="bi bi-gear me-1"></i>{{ _('Gestionar') }}
128
+ </a>
129
+ </div>
130
+ </div>
131
+ </div>
132
+
133
+ <!-- Prestaciones -->
134
+ <div class="col-md-6 col-lg-4 mb-4">
135
+ <div class="card shadow-sm h-100">
136
+ <div class="card-body text-center">
137
+ <div class="mb-3">
138
+ <i class="bi bi-gift display-4 text-info"></i>
139
+ </div>
140
+ <h5 class="card-title">{{ _('Prestaciones') }}</h5>
141
+ <p class="card-text">
142
+ <span class="badge bg-info fs-5">{{ prestaciones_count }}</span>
143
+ <br><small class="text-muted">{{ _('prestaciones asignadas') }}</small>
144
+ </p>
145
+ <a href="{{ url_for('planilla.config_prestaciones', planilla_id=planilla.id) }}" class="btn btn-outline-info">
146
+ <i class="bi bi-gear me-1"></i>{{ _('Gestionar') }}
147
+ </a>
148
+ </div>
149
+ </div>
150
+ </div>
151
+
152
+ <!-- Reglas de Cálculo -->
153
+ <div class="col-md-6 col-lg-4 mb-4">
154
+ <div class="card shadow-sm h-100">
155
+ <div class="card-body text-center">
156
+ <div class="mb-3">
157
+ <i class="bi bi-code-square display-4 text-warning"></i>
158
+ </div>
159
+ <h5 class="card-title">{{ _('Reglas de Cálculo') }}</h5>
160
+ <p class="card-text">
161
+ <span class="badge bg-warning text-dark fs-5">{{ reglas_count }}</span>
162
+ <br><small class="text-muted">{{ _('reglas asignadas') }}</small>
163
+ </p>
164
+ <a href="{{ url_for('planilla.config_reglas', planilla_id=planilla.id) }}" class="btn btn-outline-warning">
165
+ <i class="bi bi-gear me-1"></i>{{ _('Gestionar') }}
166
+ </a>
167
+ </div>
168
+ </div>
169
+ </div>
170
+
171
+ <!-- Nóminas -->
172
+ <div class="col-md-6 col-lg-4 mb-4">
173
+ <div class="card shadow-sm h-100">
174
+ <div class="card-body text-center">
175
+ <div class="mb-3">
176
+ <i class="bi bi-list-ul display-4 text-secondary"></i>
177
+ </div>
178
+ <h5 class="card-title">{{ _('Historial de Nóminas') }}</h5>
179
+ <p class="card-text">
180
+ <small class="text-muted">{{ _('Ver nóminas generadas') }}</small>
181
+ </p>
182
+ <a href="{{ url_for('planilla.listar_nominas', planilla_id=planilla.id) }}" class="btn btn-outline-secondary">
183
+ <i class="bi bi-list-ul me-1"></i>{{ _('Ver Historial') }}
184
+ </a>
185
+ </div>
186
+ </div>
187
+ </div>
188
+ </div>
189
+ </div>
190
+ {% endblock %}
@@ -0,0 +1,129 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% block content %}
4
+ <div class="container-fluid">
5
+ <div class="d-flex justify-content-between align-items-center mb-4">
6
+ <h2>
7
+ <i class="bi bi-dash-circle me-2"></i>
8
+ {{ _('Deducciones') }} - {{ planilla.nombre }}
9
+ </h2>
10
+ <a href="{{ url_for('planilla.config', planilla_id=planilla.id) }}" class="btn btn-outline-secondary">
11
+ <i class="bi bi-arrow-left me-1"></i>{{ _('Volver a Configuración') }}
12
+ </a>
13
+ </div>
14
+
15
+ {% with messages = get_flashed_messages(with_categories=true) %}
16
+ {% if messages %}
17
+ {% for category, message in messages %}
18
+ <div class="alert alert-{{ 'danger' if category == 'error' else category }} alert-dismissible fade show" role="alert">
19
+ {{ message }}
20
+ <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
21
+ </div>
22
+ {% endfor %}
23
+ {% endif %}
24
+ {% endwith %}
25
+
26
+ <div class="row">
27
+ <!-- Add Deduction Form -->
28
+ <div class="col-lg-4 mb-4">
29
+ <div class="card shadow-sm">
30
+ <div class="card-header bg-coaty-light">
31
+ <h5 class="mb-0"><i class="bi bi-plus-circle me-2"></i>{{ _('Agregar Deducción') }}</h5>
32
+ </div>
33
+ <div class="card-body">
34
+ <form action="{{ url_for('planilla.add_deduccion', planilla_id=planilla.id) }}" method="POST">
35
+ <div class="mb-3">
36
+ <label class="form-label">{{ _('Deducción') }}</label>
37
+ <select name="deduccion_id" class="form-select" required>
38
+ <option value="">{{ _('-- Seleccionar Deducción --') }}</option>
39
+ {% for ded in deducciones_disponibles %}
40
+ {% set is_assigned = ded.id in (deducciones_asignadas | map(attribute='deduccion_id') | list) %}
41
+ {% if not is_assigned %}
42
+ <option value="{{ ded.id }}">{{ ded.codigo }} - {{ ded.nombre }}</option>
43
+ {% endif %}
44
+ {% endfor %}
45
+ </select>
46
+ </div>
47
+ <div class="mb-3">
48
+ <label class="form-label">{{ _('Prioridad') }}</label>
49
+ <input type="number" name="prioridad" class="form-control" value="100" min="1" max="999">
50
+ <div class="form-text">{{ _('Menor número = se aplica primero (1-100 impuestos, 101-200 embargos, 201-300 préstamos)') }}</div>
51
+ </div>
52
+ <div class="mb-3 form-check">
53
+ <input type="checkbox" name="es_obligatoria" class="form-check-input" id="esObligatoria">
54
+ <label class="form-check-label" for="esObligatoria">{{ _('Es obligatoria') }}</label>
55
+ </div>
56
+ <button type="submit" class="btn btn-coaty w-100">
57
+ <i class="bi bi-plus me-1"></i>{{ _('Agregar Deducción') }}
58
+ </button>
59
+ </form>
60
+ </div>
61
+ </div>
62
+ </div>
63
+
64
+ <!-- Deductions List -->
65
+ <div class="col-lg-8">
66
+ <div class="card shadow-sm">
67
+ <div class="card-header bg-coaty-light d-flex justify-content-between align-items-center">
68
+ <h5 class="mb-0">
69
+ <i class="bi bi-list-ul me-2"></i>{{ _('Deducciones Asignadas') }}
70
+ <span class="badge bg-danger ms-2">{{ deducciones_asignadas | length }}</span>
71
+ </h5>
72
+ </div>
73
+ <div class="card-body">
74
+ {% if deducciones_asignadas %}
75
+ <div class="table-responsive">
76
+ <table class="table table-hover align-middle">
77
+ <thead class="table-light">
78
+ <tr>
79
+ <th>{{ _('Prioridad') }}</th>
80
+ <th>{{ _('Código') }}</th>
81
+ <th>{{ _('Nombre') }}</th>
82
+ <th>{{ _('Tipo') }}</th>
83
+ <th class="text-center">{{ _('Obligatoria') }}</th>
84
+ <th class="text-end">{{ _('Acciones') }}</th>
85
+ </tr>
86
+ </thead>
87
+ <tbody>
88
+ {% for assoc in deducciones_asignadas %}
89
+ <tr>
90
+ <td>
91
+ <form action="{{ url_for('planilla.update_deduccion_priority', planilla_id=planilla.id, association_id=assoc.id) }}" method="POST" class="d-inline">
92
+ <input type="number" name="prioridad" value="{{ assoc.prioridad }}" class="form-control form-control-sm" style="width: 70px;" min="1" max="999" onchange="this.form.submit()">
93
+ </form>
94
+ </td>
95
+ <td><code>{{ assoc.deduccion.codigo }}</code></td>
96
+ <td>{{ assoc.deduccion.nombre }}</td>
97
+ <td><small class="text-muted">{{ assoc.deduccion.tipo }}</small></td>
98
+ <td class="text-center">
99
+ {% if assoc.es_obligatoria %}
100
+ <span class="badge bg-danger">{{ _('Sí') }}</span>
101
+ {% else %}
102
+ <span class="badge bg-secondary">{{ _('No') }}</span>
103
+ {% endif %}
104
+ </td>
105
+ <td class="text-end">
106
+ <form action="{{ url_for('planilla.remove_deduccion', planilla_id=planilla.id, association_id=assoc.id) }}" method="POST" class="d-inline">
107
+ <button type="submit" class="btn btn-sm btn-outline-danger" title="{{ _('Remover') }}" onclick="return confirm('{{ _('¿Remover esta deducción de la planilla?') }}')">
108
+ <i class="bi bi-x-lg"></i>
109
+ </button>
110
+ </form>
111
+ </td>
112
+ </tr>
113
+ {% endfor %}
114
+ </tbody>
115
+ </table>
116
+ </div>
117
+ {% else %}
118
+ <div class="text-center py-5">
119
+ <i class="bi bi-dash-circle display-4 text-muted"></i>
120
+ <p class="lead mt-3">{{ _('No hay deducciones asignadas a esta planilla') }}</p>
121
+ <p class="text-muted">{{ _('Seleccione deducciones del formulario para agregarlas.') }}</p>
122
+ </div>
123
+ {% endif %}
124
+ </div>
125
+ </div>
126
+ </div>
127
+ </div>
128
+ </div>
129
+ {% endblock %}