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,116 @@
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-people me-2"></i>
8
+ {{ _('Empleados') }} - {{ 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 Employee 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 Empleado') }}</h5>
32
+ </div>
33
+ <div class="card-body">
34
+ <form action="{{ url_for('planilla.add_empleado', planilla_id=planilla.id) }}" method="POST">
35
+ <div class="mb-3">
36
+ <label class="form-label">{{ _('Empleado') }}</label>
37
+ <select name="empleado_id" class="form-select" required>
38
+ <option value="">{{ _('-- Seleccionar Empleado --') }}</option>
39
+ {% for emp in empleados_disponibles %}
40
+ {% set is_assigned = emp.id in (empleados_asignados | map(attribute='empleado_id') | list) %}
41
+ {% if not is_assigned %}
42
+ <option value="{{ emp.id }}">{{ emp.primer_apellido }} {{ emp.segundo_apellido or '' }}, {{ emp.primer_nombre }} - {{ emp.identificacion_personal }}</option>
43
+ {% endif %}
44
+ {% endfor %}
45
+ </select>
46
+ </div>
47
+ <button type="submit" class="btn btn-coaty w-100">
48
+ <i class="bi bi-plus me-1"></i>{{ _('Agregar Empleado') }}
49
+ </button>
50
+ </form>
51
+ </div>
52
+ </div>
53
+ </div>
54
+
55
+ <!-- Employee List -->
56
+ <div class="col-lg-8">
57
+ <div class="card shadow-sm">
58
+ <div class="card-header bg-coaty-light d-flex justify-content-between align-items-center">
59
+ <h5 class="mb-0">
60
+ <i class="bi bi-list-ul me-2"></i>{{ _('Empleados Asignados') }}
61
+ <span class="badge bg-primary ms-2">{{ empleados_asignados | length }}</span>
62
+ </h5>
63
+ </div>
64
+ <div class="card-body">
65
+ {% if empleados_asignados %}
66
+ <div class="table-responsive">
67
+ <table class="table table-hover align-middle">
68
+ <thead class="table-light">
69
+ <tr>
70
+ <th>{{ _('Empleado') }}</th>
71
+ <th>{{ _('Identificación') }}</th>
72
+ <th>{{ _('Desde') }}</th>
73
+ <th class="text-center">{{ _('Activo') }}</th>
74
+ <th class="text-end">{{ _('Acciones') }}</th>
75
+ </tr>
76
+ </thead>
77
+ <tbody>
78
+ {% for assoc in empleados_asignados %}
79
+ <tr>
80
+ <td>
81
+ <strong>{{ assoc.empleado.primer_apellido }} {{ assoc.empleado.segundo_apellido or '' }}</strong>, {{ assoc.empleado.primer_nombre }}
82
+ </td>
83
+ <td><code>{{ assoc.empleado.identificacion_personal }}</code></td>
84
+ <td>{{ assoc.fecha_inicio.strftime('%d/%m/%Y') if assoc.fecha_inicio else '-' }}</td>
85
+ <td class="text-center">
86
+ {% if assoc.activo %}
87
+ <span class="badge bg-success">{{ _('Sí') }}</span>
88
+ {% else %}
89
+ <span class="badge bg-secondary">{{ _('No') }}</span>
90
+ {% endif %}
91
+ </td>
92
+ <td class="text-end">
93
+ <form action="{{ url_for('planilla.remove_empleado', planilla_id=planilla.id, association_id=assoc.id) }}" method="POST" class="d-inline">
94
+ <button type="submit" class="btn btn-sm btn-outline-danger" title="{{ _('Remover') }}" onclick="return confirm('{{ _('¿Remover este empleado de la planilla?') }}')">
95
+ <i class="bi bi-x-lg"></i>
96
+ </button>
97
+ </form>
98
+ </td>
99
+ </tr>
100
+ {% endfor %}
101
+ </tbody>
102
+ </table>
103
+ </div>
104
+ {% else %}
105
+ <div class="text-center py-5">
106
+ <i class="bi bi-people display-4 text-muted"></i>
107
+ <p class="lead mt-3">{{ _('No hay empleados asignados a esta planilla') }}</p>
108
+ <p class="text-muted">{{ _('Seleccione empleados del formulario para agregarlos.') }}</p>
109
+ </div>
110
+ {% endif %}
111
+ </div>
112
+ </div>
113
+ </div>
114
+ </div>
115
+ </div>
116
+ {% endblock %}
@@ -0,0 +1,113 @@
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-plus-circle me-2"></i>
8
+ {{ _('Percepciones') }} - {{ 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 Perception 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 Percepción') }}</h5>
32
+ </div>
33
+ <div class="card-body">
34
+ <form action="{{ url_for('planilla.add_percepcion', planilla_id=planilla.id) }}" method="POST">
35
+ <div class="mb-3">
36
+ <label class="form-label">{{ _('Percepción') }}</label>
37
+ <select name="percepcion_id" class="form-select" required>
38
+ <option value="">{{ _('-- Seleccionar Percepción --') }}</option>
39
+ {% for perc in percepciones_disponibles %}
40
+ {% set is_assigned = perc.id in (percepciones_asignadas | map(attribute='percepcion_id') | list) %}
41
+ {% if not is_assigned %}
42
+ <option value="{{ perc.id }}">{{ perc.codigo }} - {{ perc.nombre }}</option>
43
+ {% endif %}
44
+ {% endfor %}
45
+ </select>
46
+ </div>
47
+ <div class="mb-3">
48
+ <label class="form-label">{{ _('Orden') }}</label>
49
+ <input type="number" name="orden" class="form-control" value="0" min="0">
50
+ <div class="form-text">{{ _('Orden de aplicación de la percepción') }}</div>
51
+ </div>
52
+ <button type="submit" class="btn btn-coaty w-100">
53
+ <i class="bi bi-plus me-1"></i>{{ _('Agregar Percepción') }}
54
+ </button>
55
+ </form>
56
+ </div>
57
+ </div>
58
+ </div>
59
+
60
+ <!-- Perceptions List -->
61
+ <div class="col-lg-8">
62
+ <div class="card shadow-sm">
63
+ <div class="card-header bg-coaty-light d-flex justify-content-between align-items-center">
64
+ <h5 class="mb-0">
65
+ <i class="bi bi-list-ul me-2"></i>{{ _('Percepciones Asignadas') }}
66
+ <span class="badge bg-success ms-2">{{ percepciones_asignadas | length }}</span>
67
+ </h5>
68
+ </div>
69
+ <div class="card-body">
70
+ {% if percepciones_asignadas %}
71
+ <div class="table-responsive">
72
+ <table class="table table-hover align-middle">
73
+ <thead class="table-light">
74
+ <tr>
75
+ <th>{{ _('Código') }}</th>
76
+ <th>{{ _('Nombre') }}</th>
77
+ <th>{{ _('Tipo') }}</th>
78
+ <th class="text-center">{{ _('Orden') }}</th>
79
+ <th class="text-end">{{ _('Acciones') }}</th>
80
+ </tr>
81
+ </thead>
82
+ <tbody>
83
+ {% for assoc in percepciones_asignadas %}
84
+ <tr>
85
+ <td><code>{{ assoc.percepcion.codigo }}</code></td>
86
+ <td>{{ assoc.percepcion.nombre }}</td>
87
+ <td><small class="text-muted">{{ assoc.percepcion.formula_tipo }}</small></td>
88
+ <td class="text-center">{{ assoc.orden }}</td>
89
+ <td class="text-end">
90
+ <form action="{{ url_for('planilla.remove_percepcion', planilla_id=planilla.id, association_id=assoc.id) }}" method="POST" class="d-inline">
91
+ <button type="submit" class="btn btn-sm btn-outline-danger" title="{{ _('Remover') }}" onclick="return confirm('{{ _('¿Remover esta percepción de la planilla?') }}')">
92
+ <i class="bi bi-x-lg"></i>
93
+ </button>
94
+ </form>
95
+ </td>
96
+ </tr>
97
+ {% endfor %}
98
+ </tbody>
99
+ </table>
100
+ </div>
101
+ {% else %}
102
+ <div class="text-center py-5">
103
+ <i class="bi bi-plus-circle display-4 text-muted"></i>
104
+ <p class="lead mt-3">{{ _('No hay percepciones asignadas a esta planilla') }}</p>
105
+ <p class="text-muted">{{ _('Seleccione percepciones del formulario para agregarlas.') }}</p>
106
+ </div>
107
+ {% endif %}
108
+ </div>
109
+ </div>
110
+ </div>
111
+ </div>
112
+ </div>
113
+ {% endblock %}
@@ -0,0 +1,118 @@
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-gift me-2"></i>
8
+ {{ _('Prestaciones') }} - {{ 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="alert alert-info">
27
+ <i class="bi bi-info-circle me-2"></i>
28
+ {{ _('Las prestaciones son costos patronales que NO afectan el salario neto del empleado.') }}
29
+ </div>
30
+
31
+ <div class="row">
32
+ <!-- Add Benefit Form -->
33
+ <div class="col-lg-4 mb-4">
34
+ <div class="card shadow-sm">
35
+ <div class="card-header bg-coaty-light">
36
+ <h5 class="mb-0"><i class="bi bi-plus-circle me-2"></i>{{ _('Agregar Prestación') }}</h5>
37
+ </div>
38
+ <div class="card-body">
39
+ <form action="{{ url_for('planilla.add_prestacion', planilla_id=planilla.id) }}" method="POST">
40
+ <div class="mb-3">
41
+ <label class="form-label">{{ _('Prestación') }}</label>
42
+ <select name="prestacion_id" class="form-select" required>
43
+ <option value="">{{ _('-- Seleccionar Prestación --') }}</option>
44
+ {% for prest in prestaciones_disponibles %}
45
+ {% set is_assigned = prest.id in (prestaciones_asignadas | map(attribute='prestacion_id') | list) %}
46
+ {% if not is_assigned %}
47
+ <option value="{{ prest.id }}">{{ prest.codigo }} - {{ prest.nombre }}</option>
48
+ {% endif %}
49
+ {% endfor %}
50
+ </select>
51
+ </div>
52
+ <div class="mb-3">
53
+ <label class="form-label">{{ _('Orden') }}</label>
54
+ <input type="number" name="orden" class="form-control" value="0" min="0">
55
+ <div class="form-text">{{ _('Orden de aplicación de la prestación') }}</div>
56
+ </div>
57
+ <button type="submit" class="btn btn-coaty w-100">
58
+ <i class="bi bi-plus me-1"></i>{{ _('Agregar Prestación') }}
59
+ </button>
60
+ </form>
61
+ </div>
62
+ </div>
63
+ </div>
64
+
65
+ <!-- Benefits List -->
66
+ <div class="col-lg-8">
67
+ <div class="card shadow-sm">
68
+ <div class="card-header bg-coaty-light d-flex justify-content-between align-items-center">
69
+ <h5 class="mb-0">
70
+ <i class="bi bi-list-ul me-2"></i>{{ _('Prestaciones Asignadas') }}
71
+ <span class="badge bg-info ms-2">{{ prestaciones_asignadas | length }}</span>
72
+ </h5>
73
+ </div>
74
+ <div class="card-body">
75
+ {% if prestaciones_asignadas %}
76
+ <div class="table-responsive">
77
+ <table class="table table-hover align-middle">
78
+ <thead class="table-light">
79
+ <tr>
80
+ <th>{{ _('Código') }}</th>
81
+ <th>{{ _('Nombre') }}</th>
82
+ <th>{{ _('Tipo') }}</th>
83
+ <th class="text-center">{{ _('Orden') }}</th>
84
+ <th class="text-end">{{ _('Acciones') }}</th>
85
+ </tr>
86
+ </thead>
87
+ <tbody>
88
+ {% for assoc in prestaciones_asignadas %}
89
+ <tr>
90
+ <td><code>{{ assoc.prestacion.codigo }}</code></td>
91
+ <td>{{ assoc.prestacion.nombre }}</td>
92
+ <td><small class="text-muted">{{ assoc.prestacion.tipo }}</small></td>
93
+ <td class="text-center">{{ assoc.orden }}</td>
94
+ <td class="text-end">
95
+ <form action="{{ url_for('planilla.remove_prestacion', planilla_id=planilla.id, association_id=assoc.id) }}" method="POST" class="d-inline">
96
+ <button type="submit" class="btn btn-sm btn-outline-danger" title="{{ _('Remover') }}" onclick="return confirm('{{ _('¿Remover esta prestación de la planilla?') }}')">
97
+ <i class="bi bi-x-lg"></i>
98
+ </button>
99
+ </form>
100
+ </td>
101
+ </tr>
102
+ {% endfor %}
103
+ </tbody>
104
+ </table>
105
+ </div>
106
+ {% else %}
107
+ <div class="text-center py-5">
108
+ <i class="bi bi-gift display-4 text-muted"></i>
109
+ <p class="lead mt-3">{{ _('No hay prestaciones asignadas a esta planilla') }}</p>
110
+ <p class="text-muted">{{ _('Seleccione prestaciones del formulario para agregarlas.') }}</p>
111
+ </div>
112
+ {% endif %}
113
+ </div>
114
+ </div>
115
+ </div>
116
+ </div>
117
+ </div>
118
+ {% endblock %}
@@ -0,0 +1,120 @@
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-code-square me-2"></i>
8
+ {{ _('Reglas de Cálculo') }} - {{ 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="alert alert-info">
27
+ <i class="bi bi-info-circle me-2"></i>
28
+ {{ _('Las reglas de cálculo definen fórmulas complejas como IR, INSS, etc.') }}
29
+ </div>
30
+
31
+ <div class="row">
32
+ <!-- Add Rule Form -->
33
+ <div class="col-lg-4 mb-4">
34
+ <div class="card shadow-sm">
35
+ <div class="card-header bg-coaty-light">
36
+ <h5 class="mb-0"><i class="bi bi-plus-circle me-2"></i>{{ _('Agregar Regla') }}</h5>
37
+ </div>
38
+ <div class="card-body">
39
+ <form action="{{ url_for('planilla.add_regla', planilla_id=planilla.id) }}" method="POST">
40
+ <div class="mb-3">
41
+ <label class="form-label">{{ _('Regla de Cálculo') }}</label>
42
+ <select name="regla_calculo_id" class="form-select" required>
43
+ <option value="">{{ _('-- Seleccionar Regla de Cálculo --') }}</option>
44
+ {% for regla in reglas_disponibles %}
45
+ {% set is_assigned = regla.id in (reglas_asignadas | map(attribute='regla_calculo_id') | list) %}
46
+ {% if not is_assigned %}
47
+ <option value="{{ regla.id }}">{{ regla.codigo }} v{{ regla.version }} - {{ regla.nombre }}</option>
48
+ {% endif %}
49
+ {% endfor %}
50
+ </select>
51
+ </div>
52
+ <div class="mb-3">
53
+ <label class="form-label">{{ _('Orden') }}</label>
54
+ <input type="number" name="orden" class="form-control" value="0" min="0">
55
+ <div class="form-text">{{ _('Orden de ejecución de la regla') }}</div>
56
+ </div>
57
+ <button type="submit" class="btn btn-coaty w-100">
58
+ <i class="bi bi-plus me-1"></i>{{ _('Agregar Regla') }}
59
+ </button>
60
+ </form>
61
+ </div>
62
+ </div>
63
+ </div>
64
+
65
+ <!-- Rules List -->
66
+ <div class="col-lg-8">
67
+ <div class="card shadow-sm">
68
+ <div class="card-header bg-coaty-light d-flex justify-content-between align-items-center">
69
+ <h5 class="mb-0">
70
+ <i class="bi bi-list-ul me-2"></i>{{ _('Reglas Asignadas') }}
71
+ <span class="badge bg-warning text-dark ms-2">{{ reglas_asignadas | length }}</span>
72
+ </h5>
73
+ </div>
74
+ <div class="card-body">
75
+ {% if reglas_asignadas %}
76
+ <div class="table-responsive">
77
+ <table class="table table-hover align-middle">
78
+ <thead class="table-light">
79
+ <tr>
80
+ <th>{{ _('Orden') }}</th>
81
+ <th>{{ _('Código') }}</th>
82
+ <th>{{ _('Nombre') }}</th>
83
+ <th>{{ _('Tipo') }}</th>
84
+ <th>{{ _('Versión') }}</th>
85
+ <th class="text-end">{{ _('Acciones') }}</th>
86
+ </tr>
87
+ </thead>
88
+ <tbody>
89
+ {% for assoc in reglas_asignadas %}
90
+ <tr>
91
+ <td>{{ assoc.orden }}</td>
92
+ <td><code>{{ assoc.regla_calculo.codigo }}</code></td>
93
+ <td>{{ assoc.regla_calculo.nombre }}</td>
94
+ <td><small class="text-muted">{{ assoc.regla_calculo.tipo_regla }}</small></td>
95
+ <td><span class="badge bg-secondary">v{{ assoc.regla_calculo.version }}</span></td>
96
+ <td class="text-end">
97
+ <form action="{{ url_for('planilla.remove_regla', planilla_id=planilla.id, association_id=assoc.id) }}" method="POST" class="d-inline">
98
+ <button type="submit" class="btn btn-sm btn-outline-danger" title="{{ _('Remover') }}" onclick="return confirm('{{ _('¿Remover esta regla de la planilla?') }}')">
99
+ <i class="bi bi-x-lg"></i>
100
+ </button>
101
+ </form>
102
+ </td>
103
+ </tr>
104
+ {% endfor %}
105
+ </tbody>
106
+ </table>
107
+ </div>
108
+ {% else %}
109
+ <div class="text-center py-5">
110
+ <i class="bi bi-code-square display-4 text-muted"></i>
111
+ <p class="lead mt-3">{{ _('No hay reglas de cálculo asignadas a esta planilla') }}</p>
112
+ <p class="text-muted">{{ _('Seleccione reglas del formulario para agregarlas.') }}</p>
113
+ </div>
114
+ {% endif %}
115
+ </div>
116
+ </div>
117
+ </div>
118
+ </div>
119
+ </div>
120
+ {% endblock %}
@@ -0,0 +1,106 @@
1
+ {% extends "base.html" %}
2
+ {% block content %}
3
+ <div class="content-header">
4
+ <h3>Ejecutar Nómina: {{ planilla.nombre }}</h3>
5
+ <a href="{{ url_for('planilla.edit', planilla_id=planilla.id) }}" class="btn btn-secondary">
6
+ <i class="fas fa-arrow-left"></i> Volver a Planilla
7
+ </a>
8
+ </div>
9
+
10
+ <div class="card">
11
+ <div class="card-header">
12
+ <h5>Configuración de Ejecución</h5>
13
+ </div>
14
+ <div class="card-body">
15
+ {% if ultima_nomina %}
16
+ <div class="alert alert-info mb-4">
17
+ <strong>Última nómina:</strong>
18
+ {{ ultima_nomina.periodo_inicio.strftime('%d/%m/%Y') }} -
19
+ {{ ultima_nomina.periodo_fin.strftime('%d/%m/%Y') }}
20
+ (Estado: {{ ultima_nomina.estado }})
21
+ </div>
22
+ {% endif %}
23
+
24
+ <form method="post" action="{{ url_for('planilla.ejecutar_nomina', planilla_id=planilla.id) }}">
25
+ <div class="row">
26
+ <div class="col-md-4">
27
+ <div class="form-group">
28
+ <label for="periodo_inicio">Período Inicio *</label>
29
+ <input type="date" class="form-control" id="periodo_inicio" name="periodo_inicio"
30
+ value="{{ periodo_inicio.isoformat() }}" required>
31
+ </div>
32
+ </div>
33
+ <div class="col-md-4">
34
+ <div class="form-group">
35
+ <label for="periodo_fin">Período Fin *</label>
36
+ <input type="date" class="form-control" id="periodo_fin" name="periodo_fin"
37
+ value="{{ periodo_fin.isoformat() }}" required>
38
+ </div>
39
+ </div>
40
+ <div class="col-md-4">
41
+ <div class="form-group">
42
+ <label for="fecha_calculo">Fecha de Cálculo</label>
43
+ <input type="date" class="form-control" id="fecha_calculo" name="fecha_calculo"
44
+ value="{{ fecha_calculo.isoformat() }}">
45
+ <small class="form-text text-muted">Si no se especifica, se usa la fecha actual.</small>
46
+ </div>
47
+ </div>
48
+ </div>
49
+
50
+ <div class="card mt-4">
51
+ <div class="card-header bg-light">
52
+ <h6 class="mb-0">Resumen de la Planilla</h6>
53
+ </div>
54
+ <div class="card-body">
55
+ <div class="row">
56
+ <div class="col-md-3">
57
+ <strong>Tipo de Planilla:</strong><br>
58
+ {{ planilla.tipo_planilla.descripcion if planilla.tipo_planilla else 'N/A' }}
59
+ </div>
60
+ <div class="col-md-3">
61
+ <strong>Moneda:</strong><br>
62
+ {{ planilla.moneda.codigo if planilla.moneda else 'N/A' }}
63
+ </div>
64
+ <div class="col-md-3">
65
+ <strong>Empleados:</strong><br>
66
+ {{ planilla.planilla_empleados|selectattr('activo')|list|length }}
67
+ </div>
68
+ <div class="col-md-3">
69
+ <strong>Periodicidad:</strong><br>
70
+ {{ planilla.tipo_planilla.periodicidad|capitalize if planilla.tipo_planilla else 'N/A' }}
71
+ </div>
72
+ </div>
73
+ <hr>
74
+ <div class="row">
75
+ <div class="col-md-3">
76
+ <strong>Percepciones:</strong><br>
77
+ {{ planilla.planilla_percepciones|length }}
78
+ </div>
79
+ <div class="col-md-3">
80
+ <strong>Deducciones:</strong><br>
81
+ {{ planilla.planilla_deducciones|length }}
82
+ </div>
83
+ <div class="col-md-3">
84
+ <strong>Prestaciones:</strong><br>
85
+ {{ planilla.planilla_prestaciones|length }}
86
+ </div>
87
+ <div class="col-md-3">
88
+ <strong>Reglas de Cálculo:</strong><br>
89
+ {{ planilla.planilla_reglas_calculo|length }}
90
+ </div>
91
+ </div>
92
+ </div>
93
+ </div>
94
+
95
+ <div class="mt-4">
96
+ <button type="submit" class="btn btn-primary btn-lg">
97
+ <i class="fas fa-play"></i> Ejecutar Nómina
98
+ </button>
99
+ <a href="{{ url_for('planilla.listar_nominas', planilla_id=planilla.id) }}" class="btn btn-outline-secondary">
100
+ <i class="fas fa-list"></i> Ver Historial de Nóminas
101
+ </a>
102
+ </div>
103
+ </form>
104
+ </div>
105
+ </div>
106
+ {% endblock %}