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.
- coati_payroll/__init__.py +415 -0
- coati_payroll/app.py +95 -0
- coati_payroll/audit_helpers.py +904 -0
- coati_payroll/auth.py +123 -0
- coati_payroll/cli.py +1318 -0
- coati_payroll/config.py +219 -0
- coati_payroll/demo_data.py +813 -0
- coati_payroll/enums.py +278 -0
- coati_payroll/forms.py +1769 -0
- coati_payroll/formula_engine/__init__.py +81 -0
- coati_payroll/formula_engine/ast/__init__.py +110 -0
- coati_payroll/formula_engine/ast/ast_visitor.py +259 -0
- coati_payroll/formula_engine/ast/expression_evaluator.py +228 -0
- coati_payroll/formula_engine/ast/safe_operators.py +131 -0
- coati_payroll/formula_engine/ast/type_converter.py +172 -0
- coati_payroll/formula_engine/data_sources.py +752 -0
- coati_payroll/formula_engine/engine.py +247 -0
- coati_payroll/formula_engine/exceptions.py +52 -0
- coati_payroll/formula_engine/execution/__init__.py +24 -0
- coati_payroll/formula_engine/execution/execution_context.py +52 -0
- coati_payroll/formula_engine/execution/step_executor.py +62 -0
- coati_payroll/formula_engine/execution/variable_store.py +59 -0
- coati_payroll/formula_engine/novelty_codes.py +206 -0
- coati_payroll/formula_engine/results/__init__.py +20 -0
- coati_payroll/formula_engine/results/execution_result.py +59 -0
- coati_payroll/formula_engine/steps/__init__.py +30 -0
- coati_payroll/formula_engine/steps/assignment_step.py +71 -0
- coati_payroll/formula_engine/steps/base_step.py +48 -0
- coati_payroll/formula_engine/steps/calculation_step.py +42 -0
- coati_payroll/formula_engine/steps/conditional_step.py +122 -0
- coati_payroll/formula_engine/steps/step_factory.py +58 -0
- coati_payroll/formula_engine/steps/tax_lookup_step.py +45 -0
- coati_payroll/formula_engine/tables/__init__.py +24 -0
- coati_payroll/formula_engine/tables/bracket_calculator.py +51 -0
- coati_payroll/formula_engine/tables/table_lookup.py +161 -0
- coati_payroll/formula_engine/tables/tax_table.py +32 -0
- coati_payroll/formula_engine/validation/__init__.py +24 -0
- coati_payroll/formula_engine/validation/schema_validator.py +37 -0
- coati_payroll/formula_engine/validation/security_validator.py +52 -0
- coati_payroll/formula_engine/validation/tax_table_validator.py +205 -0
- coati_payroll/formula_engine_examples.py +153 -0
- coati_payroll/i18n.py +54 -0
- coati_payroll/initial_data.py +613 -0
- coati_payroll/interes_engine.py +450 -0
- coati_payroll/liquidacion_engine/__init__.py +25 -0
- coati_payroll/liquidacion_engine/engine.py +267 -0
- coati_payroll/locale_config.py +165 -0
- coati_payroll/log.py +138 -0
- coati_payroll/model.py +2410 -0
- coati_payroll/nomina_engine/__init__.py +87 -0
- coati_payroll/nomina_engine/calculators/__init__.py +30 -0
- coati_payroll/nomina_engine/calculators/benefit_calculator.py +79 -0
- coati_payroll/nomina_engine/calculators/concept_calculator.py +254 -0
- coati_payroll/nomina_engine/calculators/deduction_calculator.py +105 -0
- coati_payroll/nomina_engine/calculators/exchange_rate_calculator.py +51 -0
- coati_payroll/nomina_engine/calculators/perception_calculator.py +75 -0
- coati_payroll/nomina_engine/calculators/salary_calculator.py +86 -0
- coati_payroll/nomina_engine/domain/__init__.py +27 -0
- coati_payroll/nomina_engine/domain/calculation_items.py +52 -0
- coati_payroll/nomina_engine/domain/employee_calculation.py +53 -0
- coati_payroll/nomina_engine/domain/payroll_context.py +44 -0
- coati_payroll/nomina_engine/engine.py +188 -0
- coati_payroll/nomina_engine/processors/__init__.py +28 -0
- coati_payroll/nomina_engine/processors/accounting_processor.py +171 -0
- coati_payroll/nomina_engine/processors/accumulation_processor.py +90 -0
- coati_payroll/nomina_engine/processors/loan_processor.py +227 -0
- coati_payroll/nomina_engine/processors/novelty_processor.py +42 -0
- coati_payroll/nomina_engine/processors/vacation_processor.py +67 -0
- coati_payroll/nomina_engine/repositories/__init__.py +32 -0
- coati_payroll/nomina_engine/repositories/acumulado_repository.py +83 -0
- coati_payroll/nomina_engine/repositories/base_repository.py +40 -0
- coati_payroll/nomina_engine/repositories/config_repository.py +102 -0
- coati_payroll/nomina_engine/repositories/employee_repository.py +34 -0
- coati_payroll/nomina_engine/repositories/exchange_rate_repository.py +58 -0
- coati_payroll/nomina_engine/repositories/novelty_repository.py +54 -0
- coati_payroll/nomina_engine/repositories/planilla_repository.py +52 -0
- coati_payroll/nomina_engine/results/__init__.py +24 -0
- coati_payroll/nomina_engine/results/error_result.py +28 -0
- coati_payroll/nomina_engine/results/payroll_result.py +53 -0
- coati_payroll/nomina_engine/results/validation_result.py +39 -0
- coati_payroll/nomina_engine/services/__init__.py +22 -0
- coati_payroll/nomina_engine/services/accounting_voucher_service.py +708 -0
- coati_payroll/nomina_engine/services/employee_processing_service.py +173 -0
- coati_payroll/nomina_engine/services/payroll_execution_service.py +374 -0
- coati_payroll/nomina_engine/services/snapshot_service.py +295 -0
- coati_payroll/nomina_engine/validators/__init__.py +31 -0
- coati_payroll/nomina_engine/validators/base_validator.py +48 -0
- coati_payroll/nomina_engine/validators/currency_validator.py +50 -0
- coati_payroll/nomina_engine/validators/employee_validator.py +87 -0
- coati_payroll/nomina_engine/validators/period_validator.py +44 -0
- coati_payroll/nomina_engine/validators/planilla_validator.py +136 -0
- coati_payroll/plugin_manager.py +176 -0
- coati_payroll/queue/__init__.py +33 -0
- coati_payroll/queue/driver.py +127 -0
- coati_payroll/queue/drivers/__init__.py +22 -0
- coati_payroll/queue/drivers/dramatiq_driver.py +268 -0
- coati_payroll/queue/drivers/huey_driver.py +390 -0
- coati_payroll/queue/drivers/noop_driver.py +54 -0
- coati_payroll/queue/selector.py +121 -0
- coati_payroll/queue/tasks.py +764 -0
- coati_payroll/rate_limiting.py +83 -0
- coati_payroll/rbac.py +183 -0
- coati_payroll/report_engine.py +512 -0
- coati_payroll/report_export.py +208 -0
- coati_payroll/schema_validator.py +167 -0
- coati_payroll/security.py +77 -0
- coati_payroll/static/styles.css +1044 -0
- coati_payroll/system_reports.py +573 -0
- coati_payroll/templates/auth/login.html +189 -0
- coati_payroll/templates/base.html +283 -0
- coati_payroll/templates/index.html +227 -0
- coati_payroll/templates/macros.html +146 -0
- coati_payroll/templates/modules/calculation_rule/form.html +78 -0
- coati_payroll/templates/modules/calculation_rule/index.html +102 -0
- coati_payroll/templates/modules/calculation_rule/schema_editor.html +1159 -0
- coati_payroll/templates/modules/carga_inicial_prestacion/form.html +170 -0
- coati_payroll/templates/modules/carga_inicial_prestacion/index.html +170 -0
- coati_payroll/templates/modules/carga_inicial_prestacion/reporte.html +193 -0
- coati_payroll/templates/modules/config_calculos/index.html +44 -0
- coati_payroll/templates/modules/configuracion/index.html +90 -0
- coati_payroll/templates/modules/currency/form.html +47 -0
- coati_payroll/templates/modules/currency/index.html +64 -0
- coati_payroll/templates/modules/custom_field/form.html +62 -0
- coati_payroll/templates/modules/custom_field/index.html +78 -0
- coati_payroll/templates/modules/deduccion/form.html +1 -0
- coati_payroll/templates/modules/deduccion/index.html +1 -0
- coati_payroll/templates/modules/employee/form.html +254 -0
- coati_payroll/templates/modules/employee/index.html +76 -0
- coati_payroll/templates/modules/empresa/form.html +74 -0
- coati_payroll/templates/modules/empresa/index.html +71 -0
- coati_payroll/templates/modules/exchange_rate/form.html +47 -0
- coati_payroll/templates/modules/exchange_rate/import.html +93 -0
- coati_payroll/templates/modules/exchange_rate/index.html +114 -0
- coati_payroll/templates/modules/liquidacion/index.html +58 -0
- coati_payroll/templates/modules/liquidacion/nueva.html +51 -0
- coati_payroll/templates/modules/liquidacion/ver.html +91 -0
- coati_payroll/templates/modules/payroll_concepts/audit_log.html +146 -0
- coati_payroll/templates/modules/percepcion/form.html +1 -0
- coati_payroll/templates/modules/percepcion/index.html +1 -0
- coati_payroll/templates/modules/planilla/config.html +190 -0
- coati_payroll/templates/modules/planilla/config_deducciones.html +129 -0
- coati_payroll/templates/modules/planilla/config_empleados.html +116 -0
- coati_payroll/templates/modules/planilla/config_percepciones.html +113 -0
- coati_payroll/templates/modules/planilla/config_prestaciones.html +118 -0
- coati_payroll/templates/modules/planilla/config_reglas.html +120 -0
- coati_payroll/templates/modules/planilla/ejecutar_nomina.html +106 -0
- coati_payroll/templates/modules/planilla/form.html +197 -0
- coati_payroll/templates/modules/planilla/index.html +144 -0
- coati_payroll/templates/modules/planilla/listar_nominas.html +91 -0
- coati_payroll/templates/modules/planilla/log_nomina.html +135 -0
- coati_payroll/templates/modules/planilla/novedades/form.html +177 -0
- coati_payroll/templates/modules/planilla/novedades/index.html +170 -0
- coati_payroll/templates/modules/planilla/ver_nomina.html +477 -0
- coati_payroll/templates/modules/planilla/ver_nomina_empleado.html +231 -0
- coati_payroll/templates/modules/plugins/index.html +71 -0
- coati_payroll/templates/modules/prestacion/form.html +1 -0
- coati_payroll/templates/modules/prestacion/index.html +1 -0
- coati_payroll/templates/modules/prestacion_management/dashboard.html +150 -0
- coati_payroll/templates/modules/prestacion_management/initial_balance_bulk.html +195 -0
- coati_payroll/templates/modules/prestamo/approve.html +156 -0
- coati_payroll/templates/modules/prestamo/condonacion.html +249 -0
- coati_payroll/templates/modules/prestamo/detail.html +443 -0
- coati_payroll/templates/modules/prestamo/form.html +203 -0
- coati_payroll/templates/modules/prestamo/index.html +150 -0
- coati_payroll/templates/modules/prestamo/pago_extraordinario.html +211 -0
- coati_payroll/templates/modules/prestamo/tabla_pago_pdf.html +181 -0
- coati_payroll/templates/modules/report/admin_index.html +125 -0
- coati_payroll/templates/modules/report/detail.html +129 -0
- coati_payroll/templates/modules/report/execute.html +266 -0
- coati_payroll/templates/modules/report/index.html +95 -0
- coati_payroll/templates/modules/report/permissions.html +64 -0
- coati_payroll/templates/modules/settings/index.html +274 -0
- coati_payroll/templates/modules/shared/concept_form.html +201 -0
- coati_payroll/templates/modules/shared/concept_index.html +145 -0
- coati_payroll/templates/modules/tipo_planilla/form.html +70 -0
- coati_payroll/templates/modules/tipo_planilla/index.html +68 -0
- coati_payroll/templates/modules/user/form.html +65 -0
- coati_payroll/templates/modules/user/index.html +76 -0
- coati_payroll/templates/modules/user/profile.html +81 -0
- coati_payroll/templates/modules/vacation/account_detail.html +149 -0
- coati_payroll/templates/modules/vacation/account_form.html +52 -0
- coati_payroll/templates/modules/vacation/account_index.html +68 -0
- coati_payroll/templates/modules/vacation/dashboard.html +156 -0
- coati_payroll/templates/modules/vacation/initial_balance_bulk.html +149 -0
- coati_payroll/templates/modules/vacation/initial_balance_form.html +93 -0
- coati_payroll/templates/modules/vacation/leave_request_detail.html +158 -0
- coati_payroll/templates/modules/vacation/leave_request_form.html +61 -0
- coati_payroll/templates/modules/vacation/leave_request_index.html +98 -0
- coati_payroll/templates/modules/vacation/policy_detail.html +176 -0
- coati_payroll/templates/modules/vacation/policy_form.html +152 -0
- coati_payroll/templates/modules/vacation/policy_index.html +79 -0
- coati_payroll/templates/modules/vacation/register_taken_form.html +178 -0
- coati_payroll/translations/en/LC_MESSAGES/messages.mo +0 -0
- coati_payroll/translations/en/LC_MESSAGES/messages.po +7283 -0
- coati_payroll/translations/es/LC_MESSAGES/messages.mo +0 -0
- coati_payroll/translations/es/LC_MESSAGES/messages.po +7374 -0
- coati_payroll/vacation_service.py +451 -0
- coati_payroll/version.py +18 -0
- coati_payroll/vistas/__init__.py +64 -0
- coati_payroll/vistas/calculation_rule.py +307 -0
- coati_payroll/vistas/carga_inicial_prestacion.py +423 -0
- coati_payroll/vistas/config_calculos.py +72 -0
- coati_payroll/vistas/configuracion.py +87 -0
- coati_payroll/vistas/constants.py +17 -0
- coati_payroll/vistas/currency.py +112 -0
- coati_payroll/vistas/custom_field.py +120 -0
- coati_payroll/vistas/employee.py +305 -0
- coati_payroll/vistas/empresa.py +153 -0
- coati_payroll/vistas/exchange_rate.py +341 -0
- coati_payroll/vistas/liquidacion.py +205 -0
- coati_payroll/vistas/payroll_concepts.py +580 -0
- coati_payroll/vistas/planilla/__init__.py +38 -0
- coati_payroll/vistas/planilla/association_routes.py +238 -0
- coati_payroll/vistas/planilla/config_routes.py +158 -0
- coati_payroll/vistas/planilla/export_routes.py +175 -0
- coati_payroll/vistas/planilla/helpers/__init__.py +34 -0
- coati_payroll/vistas/planilla/helpers/association_helpers.py +161 -0
- coati_payroll/vistas/planilla/helpers/excel_helpers.py +29 -0
- coati_payroll/vistas/planilla/helpers/form_helpers.py +97 -0
- coati_payroll/vistas/planilla/nomina_routes.py +488 -0
- coati_payroll/vistas/planilla/novedad_routes.py +227 -0
- coati_payroll/vistas/planilla/routes.py +145 -0
- coati_payroll/vistas/planilla/services/__init__.py +26 -0
- coati_payroll/vistas/planilla/services/export_service.py +687 -0
- coati_payroll/vistas/planilla/services/nomina_service.py +233 -0
- coati_payroll/vistas/planilla/services/novedad_service.py +126 -0
- coati_payroll/vistas/planilla/services/planilla_service.py +34 -0
- coati_payroll/vistas/planilla/validators/__init__.py +18 -0
- coati_payroll/vistas/planilla/validators/planilla_validators.py +40 -0
- coati_payroll/vistas/plugins.py +45 -0
- coati_payroll/vistas/prestacion.py +272 -0
- coati_payroll/vistas/prestamo.py +808 -0
- coati_payroll/vistas/report.py +432 -0
- coati_payroll/vistas/settings.py +29 -0
- coati_payroll/vistas/tipo_planilla.py +134 -0
- coati_payroll/vistas/user.py +172 -0
- coati_payroll/vistas/vacation.py +1045 -0
- coati_payroll-0.0.2.dist-info/LICENSE +201 -0
- coati_payroll-0.0.2.dist-info/METADATA +581 -0
- coati_payroll-0.0.2.dist-info/RECORD +243 -0
- coati_payroll-0.0.2.dist-info/WHEEL +5 -0
- coati_payroll-0.0.2.dist-info/entry_points.txt +2 -0
- coati_payroll-0.0.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# Copyright 2025 BMO Soluciones, S.A.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
"""Helper functions for managing planilla associations."""
|
|
15
|
+
|
|
16
|
+
from sqlalchemy import func, select
|
|
17
|
+
from coati_payroll.model import (
|
|
18
|
+
db,
|
|
19
|
+
PlanillaEmpleado,
|
|
20
|
+
PlanillaIngreso,
|
|
21
|
+
PlanillaDeduccion,
|
|
22
|
+
PlanillaPrestacion,
|
|
23
|
+
PlanillaReglaCalculo,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def get_planilla_component_counts(planilla_id: str) -> dict:
|
|
28
|
+
"""Get counts of all components associated with a planilla.
|
|
29
|
+
|
|
30
|
+
Returns a dictionary with counts for empleados, percepciones, deducciones,
|
|
31
|
+
prestaciones, and reglas.
|
|
32
|
+
"""
|
|
33
|
+
return {
|
|
34
|
+
"empleados_count": db.session.execute(
|
|
35
|
+
select(func.count()).select_from(PlanillaEmpleado).filter_by(planilla_id=planilla_id)
|
|
36
|
+
).scalar(),
|
|
37
|
+
"percepciones_count": db.session.execute(
|
|
38
|
+
select(func.count()).select_from(PlanillaIngreso).filter_by(planilla_id=planilla_id)
|
|
39
|
+
).scalar(),
|
|
40
|
+
"deducciones_count": db.session.execute(
|
|
41
|
+
select(func.count()).select_from(PlanillaDeduccion).filter_by(planilla_id=planilla_id)
|
|
42
|
+
).scalar(),
|
|
43
|
+
"prestaciones_count": db.session.execute(
|
|
44
|
+
select(func.count()).select_from(PlanillaPrestacion).filter_by(planilla_id=planilla_id)
|
|
45
|
+
).scalar(),
|
|
46
|
+
"reglas_count": db.session.execute(
|
|
47
|
+
select(func.count()).select_from(PlanillaReglaCalculo).filter_by(planilla_id=planilla_id)
|
|
48
|
+
).scalar(),
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def agregar_asociacion(
|
|
53
|
+
planilla_id: str,
|
|
54
|
+
tipo_componente: str,
|
|
55
|
+
componente_id: str,
|
|
56
|
+
datos_extra: dict | None = None,
|
|
57
|
+
usuario: str | None = None,
|
|
58
|
+
) -> tuple[bool, str | None, str | None]:
|
|
59
|
+
"""Generic function to add any component association to a planilla.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
planilla_id: ID of the planilla
|
|
63
|
+
tipo_componente: Type of component ('percepcion', 'deduccion', 'prestacion', 'regla')
|
|
64
|
+
componente_id: ID of the component to associate
|
|
65
|
+
datos_extra: Additional data for the association (orden, prioridad, etc.)
|
|
66
|
+
usuario: Username of the user creating the association
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
Tuple of (success, error_message, association_id). If success is False, error_message is set.
|
|
70
|
+
"""
|
|
71
|
+
from coati_payroll.model import (
|
|
72
|
+
Planilla,
|
|
73
|
+
PlanillaIngreso,
|
|
74
|
+
PlanillaDeduccion,
|
|
75
|
+
PlanillaPrestacion,
|
|
76
|
+
PlanillaReglaCalculo,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
datos_extra = datos_extra or {}
|
|
80
|
+
usuario = usuario or "system"
|
|
81
|
+
|
|
82
|
+
# Verify planilla exists
|
|
83
|
+
planilla = db.session.get(Planilla, planilla_id)
|
|
84
|
+
if not planilla:
|
|
85
|
+
return False, "Planilla no encontrada", None
|
|
86
|
+
|
|
87
|
+
if not componente_id:
|
|
88
|
+
return False, f"Debe seleccionar una {tipo_componente}.", None
|
|
89
|
+
|
|
90
|
+
# Check for existing association based on type
|
|
91
|
+
existing = None
|
|
92
|
+
association_class = None
|
|
93
|
+
filter_params = {"planilla_id": planilla_id}
|
|
94
|
+
|
|
95
|
+
if tipo_componente == "percepcion":
|
|
96
|
+
association_class = PlanillaIngreso
|
|
97
|
+
filter_params["percepcion_id"] = componente_id
|
|
98
|
+
elif tipo_componente == "deduccion":
|
|
99
|
+
association_class = PlanillaDeduccion
|
|
100
|
+
filter_params["deduccion_id"] = componente_id
|
|
101
|
+
elif tipo_componente == "prestacion":
|
|
102
|
+
association_class = PlanillaPrestacion
|
|
103
|
+
filter_params["prestacion_id"] = componente_id
|
|
104
|
+
elif tipo_componente == "regla":
|
|
105
|
+
association_class = PlanillaReglaCalculo
|
|
106
|
+
filter_params["regla_calculo_id"] = componente_id
|
|
107
|
+
else:
|
|
108
|
+
return False, f"Tipo de componente desconocido: {tipo_componente}", None
|
|
109
|
+
|
|
110
|
+
existing = db.session.execute(db.select(association_class).filter_by(**filter_params)).scalar_one_or_none()
|
|
111
|
+
|
|
112
|
+
if existing:
|
|
113
|
+
return False, f"La {tipo_componente} ya está asignada a esta planilla.", None
|
|
114
|
+
|
|
115
|
+
# Create association based on type
|
|
116
|
+
if tipo_componente == "percepcion":
|
|
117
|
+
orden = datos_extra.get("orden", 0)
|
|
118
|
+
association = PlanillaIngreso(
|
|
119
|
+
planilla_id=planilla_id,
|
|
120
|
+
percepcion_id=componente_id,
|
|
121
|
+
orden=orden,
|
|
122
|
+
editable=True,
|
|
123
|
+
activo=True,
|
|
124
|
+
creado_por=usuario,
|
|
125
|
+
)
|
|
126
|
+
elif tipo_componente == "deduccion":
|
|
127
|
+
prioridad = datos_extra.get("prioridad", 100)
|
|
128
|
+
es_obligatoria = datos_extra.get("es_obligatoria", False)
|
|
129
|
+
association = PlanillaDeduccion(
|
|
130
|
+
planilla_id=planilla_id,
|
|
131
|
+
deduccion_id=componente_id,
|
|
132
|
+
prioridad=prioridad,
|
|
133
|
+
es_obligatoria=es_obligatoria,
|
|
134
|
+
editable=True,
|
|
135
|
+
activo=True,
|
|
136
|
+
creado_por=usuario,
|
|
137
|
+
)
|
|
138
|
+
elif tipo_componente == "prestacion":
|
|
139
|
+
orden = datos_extra.get("orden", 0)
|
|
140
|
+
association = PlanillaPrestacion(
|
|
141
|
+
planilla_id=planilla_id,
|
|
142
|
+
prestacion_id=componente_id,
|
|
143
|
+
orden=orden,
|
|
144
|
+
editable=True,
|
|
145
|
+
activo=True,
|
|
146
|
+
creado_por=usuario,
|
|
147
|
+
)
|
|
148
|
+
elif tipo_componente == "regla":
|
|
149
|
+
orden = datos_extra.get("orden", 0)
|
|
150
|
+
association = PlanillaReglaCalculo(
|
|
151
|
+
planilla_id=planilla_id,
|
|
152
|
+
regla_calculo_id=componente_id,
|
|
153
|
+
orden=orden,
|
|
154
|
+
activo=True,
|
|
155
|
+
creado_por=usuario,
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
db.session.add(association)
|
|
159
|
+
db.session.commit()
|
|
160
|
+
|
|
161
|
+
return True, None, association.id
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Copyright 2025 BMO Soluciones, S.A.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
"""Excel helper functions for planilla views."""
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def check_openpyxl_available():
|
|
18
|
+
"""Check if openpyxl is available and return necessary classes.
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
tuple: (Workbook, Font, Alignment, PatternFill, Border, Side) or None if not available
|
|
22
|
+
"""
|
|
23
|
+
try:
|
|
24
|
+
from openpyxl import Workbook
|
|
25
|
+
from openpyxl.styles import Font, Alignment, PatternFill, Border, Side
|
|
26
|
+
|
|
27
|
+
return Workbook, Font, Alignment, PatternFill, Border, Side
|
|
28
|
+
except ImportError:
|
|
29
|
+
return None
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Copyright 2025 BMO Soluciones, S.A.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
"""Form helper functions for planilla views."""
|
|
15
|
+
|
|
16
|
+
from coati_payroll.model import db, TipoPlanilla, Moneda, Empresa, NominaEmpleado, Percepcion, Deduccion
|
|
17
|
+
from coati_payroll.forms import PlanillaForm
|
|
18
|
+
from coati_payroll.i18n import _
|
|
19
|
+
from sqlalchemy.orm import joinedload
|
|
20
|
+
|
|
21
|
+
# Constants
|
|
22
|
+
SELECT_PLACEHOLDER = "-- Seleccionar --"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def populate_form_choices(form: PlanillaForm):
|
|
26
|
+
"""Populate form select choices from database."""
|
|
27
|
+
tipos = (
|
|
28
|
+
db.session.execute(db.select(TipoPlanilla).filter_by(activo=True).order_by(TipoPlanilla.codigo)).scalars().all()
|
|
29
|
+
)
|
|
30
|
+
form.tipo_planilla_id.choices = [("", _(SELECT_PLACEHOLDER))] + [
|
|
31
|
+
(t.id, f"{t.codigo} - {t.descripcion or t.codigo}") for t in tipos
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
monedas = db.session.execute(db.select(Moneda).filter_by(activo=True).order_by(Moneda.codigo)).scalars().all()
|
|
35
|
+
form.moneda_id.choices = [("", _(SELECT_PLACEHOLDER))] + [(m.id, f"{m.codigo} - {m.nombre}") for m in monedas]
|
|
36
|
+
|
|
37
|
+
empresas = (
|
|
38
|
+
db.session.execute(db.select(Empresa).filter_by(activo=True).order_by(Empresa.razon_social)).scalars().all()
|
|
39
|
+
)
|
|
40
|
+
form.empresa_id.choices = [("", _(SELECT_PLACEHOLDER))] + [
|
|
41
|
+
(e.id, f"{e.codigo} - {e.razon_social}") for e in empresas
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def populate_novedad_form_choices(form, nomina_id: str):
|
|
46
|
+
"""Populate form select choices for novedad form."""
|
|
47
|
+
# Get employees associated with this nomina with eager loading
|
|
48
|
+
nomina_empleados = (
|
|
49
|
+
db.session.execute(
|
|
50
|
+
db.select(NominaEmpleado).filter_by(nomina_id=nomina_id).options(joinedload(NominaEmpleado.empleado))
|
|
51
|
+
)
|
|
52
|
+
.scalars()
|
|
53
|
+
.all()
|
|
54
|
+
)
|
|
55
|
+
form.empleado_id.choices = [("", _("-- Seleccionar Empleado --"))] + [
|
|
56
|
+
(
|
|
57
|
+
ne.empleado.id,
|
|
58
|
+
f"{ne.empleado.primer_nombre} {ne.empleado.primer_apellido} ({ne.empleado.codigo_empleado})",
|
|
59
|
+
)
|
|
60
|
+
for ne in nomina_empleados
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
# Get active percepciones
|
|
64
|
+
percepciones = (
|
|
65
|
+
db.session.execute(db.select(Percepcion).filter_by(activo=True).order_by(Percepcion.nombre)).scalars().all()
|
|
66
|
+
)
|
|
67
|
+
form.percepcion_id.choices = [("", _("-- Seleccionar Percepción --"))] + [
|
|
68
|
+
(p.id, f"{p.codigo} - {p.nombre}") for p in percepciones
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
# Get active deducciones
|
|
72
|
+
deducciones = (
|
|
73
|
+
db.session.execute(db.select(Deduccion).filter_by(activo=True).order_by(Deduccion.nombre)).scalars().all()
|
|
74
|
+
)
|
|
75
|
+
form.deduccion_id.choices = [("", _("-- Seleccionar Deducción --"))] + [
|
|
76
|
+
(d.id, f"{d.codigo} - {d.nombre}") for d in deducciones
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def get_concepto_ids_from_form(form) -> tuple[str | None, str | None]:
|
|
81
|
+
"""Extract percepcion_id and deduccion_id from form based on tipo_concepto.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
form: The NominaNovedadForm with submitted data
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
Tuple of (percepcion_id, deduccion_id) - one will be set, other will be None
|
|
88
|
+
"""
|
|
89
|
+
percepcion_id = None
|
|
90
|
+
deduccion_id = None
|
|
91
|
+
|
|
92
|
+
if form.tipo_concepto.data == "percepcion":
|
|
93
|
+
percepcion_id = form.percepcion_id.data if form.percepcion_id.data else None
|
|
94
|
+
else:
|
|
95
|
+
deduccion_id = form.deduccion_id.data if form.deduccion_id.data else None
|
|
96
|
+
|
|
97
|
+
return percepcion_id, deduccion_id
|