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
coati_payroll/forms.py
ADDED
|
@@ -0,0 +1,1769 @@
|
|
|
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
|
+
|
|
15
|
+
"""Forms module.
|
|
16
|
+
|
|
17
|
+
Contiene los formularios WTForms usados por la aplicación.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
# <-------------------------------------------------------------------------> #
|
|
23
|
+
# Standard library
|
|
24
|
+
# <-------------------------------------------------------------------------> #
|
|
25
|
+
from decimal import Decimal
|
|
26
|
+
|
|
27
|
+
# <-------------------------------------------------------------------------> #
|
|
28
|
+
# Third party libraries
|
|
29
|
+
# <-------------------------------------------------------------------------> #
|
|
30
|
+
from flask_wtf import FlaskForm
|
|
31
|
+
from wtforms import (
|
|
32
|
+
BooleanField,
|
|
33
|
+
DateField,
|
|
34
|
+
DecimalField,
|
|
35
|
+
IntegerField,
|
|
36
|
+
PasswordField,
|
|
37
|
+
SelectField,
|
|
38
|
+
StringField,
|
|
39
|
+
SubmitField,
|
|
40
|
+
)
|
|
41
|
+
from wtforms.validators import (
|
|
42
|
+
DataRequired,
|
|
43
|
+
Email,
|
|
44
|
+
Length,
|
|
45
|
+
NumberRange,
|
|
46
|
+
Optional,
|
|
47
|
+
Regexp,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
# <-------------------------------------------------------------------------> #
|
|
51
|
+
# Third party libraries
|
|
52
|
+
# <-------------------------------------------------------------------------> #
|
|
53
|
+
from coati_payroll.enums import TipoUsuario
|
|
54
|
+
from coati_payroll.i18n import _
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class LoginForm(FlaskForm):
|
|
58
|
+
"""Formulario de inicio de sesión.
|
|
59
|
+
|
|
60
|
+
Campos:
|
|
61
|
+
- email: correo o nombre de usuario identificador del usuario
|
|
62
|
+
- password: contraseña
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
# Permitimos que el usuario use su nombre de usuario o su correo electrónico
|
|
66
|
+
# para iniciar sesión, por eso no forzamos el validador Email.
|
|
67
|
+
email = StringField(_("Usuario o correo electrónico"), validators=[DataRequired(), Length(max=150)])
|
|
68
|
+
password = PasswordField(_("Contraseña"), validators=[DataRequired(), Length(min=6)])
|
|
69
|
+
submit = SubmitField(_("Entrar"))
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# --------------------------------------------------------------------------------------
|
|
73
|
+
# CRUD Forms
|
|
74
|
+
# --------------------------------------------------------------------------------------
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class UserForm(FlaskForm):
|
|
78
|
+
"""Form for creating and editing users."""
|
|
79
|
+
|
|
80
|
+
usuario = StringField(_("Usuario"), validators=[DataRequired(), Length(max=150)])
|
|
81
|
+
password = PasswordField(_("Contraseña"), validators=[Length(min=6)])
|
|
82
|
+
nombre = StringField(_("Nombre"), validators=[Optional(), Length(max=100)])
|
|
83
|
+
apellido = StringField(_("Apellido"), validators=[Optional(), Length(max=100)])
|
|
84
|
+
correo_electronico = StringField(
|
|
85
|
+
_("Correo electrónico"),
|
|
86
|
+
validators=[Optional(), Email(), Length(max=150)],
|
|
87
|
+
)
|
|
88
|
+
tipo = SelectField(
|
|
89
|
+
_("Tipo de usuario"),
|
|
90
|
+
choices=[
|
|
91
|
+
(TipoUsuario.ADMIN, _("Administrador")),
|
|
92
|
+
(TipoUsuario.HHRR, _("Recursos Humanos")),
|
|
93
|
+
(TipoUsuario.AUDIT, _("Auditoría")),
|
|
94
|
+
],
|
|
95
|
+
validators=[DataRequired()],
|
|
96
|
+
)
|
|
97
|
+
activo = BooleanField(_("Activo"), default=True)
|
|
98
|
+
submit = SubmitField(_("Guardar"))
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class ConfiguracionCalculosForm(FlaskForm):
|
|
102
|
+
"""Form for editing global calculation configuration parameters."""
|
|
103
|
+
|
|
104
|
+
liquidacion_modo_dias = SelectField(
|
|
105
|
+
_("Modo de Días (Liquidación)"),
|
|
106
|
+
choices=[
|
|
107
|
+
("calendario", _("Calendario")),
|
|
108
|
+
("laboral", _("Laboral")),
|
|
109
|
+
],
|
|
110
|
+
validators=[DataRequired()],
|
|
111
|
+
description=_(
|
|
112
|
+
"Define qué factor se usará como base de días para prorrateos en liquidaciones. "
|
|
113
|
+
"Calendario usa el factor calendario; Laboral usa el factor laboral."
|
|
114
|
+
),
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
liquidacion_factor_calendario = IntegerField(
|
|
118
|
+
_("Factor Días Calendario (Liquidación)"),
|
|
119
|
+
validators=[DataRequired(), NumberRange(min=1, max=366)],
|
|
120
|
+
default=30,
|
|
121
|
+
description=_("Factor base cuando el modo es Calendario (por defecto 30)."),
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
liquidacion_factor_laboral = IntegerField(
|
|
125
|
+
_("Factor Días Laborales (Liquidación)"),
|
|
126
|
+
validators=[DataRequired(), NumberRange(min=1, max=366)],
|
|
127
|
+
default=28,
|
|
128
|
+
description=_("Factor base cuando el modo es Laboral (por defecto 28)."),
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
submit = SubmitField(_("Guardar"))
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class ProfileForm(FlaskForm):
|
|
135
|
+
"""Form for editing user profile and password."""
|
|
136
|
+
|
|
137
|
+
nombre = StringField(_("Nombre"), validators=[Optional(), Length(max=100)])
|
|
138
|
+
apellido = StringField(_("Apellido"), validators=[Optional(), Length(max=100)])
|
|
139
|
+
correo_electronico = StringField(
|
|
140
|
+
_("Correo electrónico"),
|
|
141
|
+
validators=[Optional(), Email(), Length(max=150)],
|
|
142
|
+
)
|
|
143
|
+
current_password = PasswordField(_("Contraseña actual"), validators=[Optional(), Length(min=6)])
|
|
144
|
+
new_password = PasswordField(_("Nueva contraseña"), validators=[Optional(), Length(min=6)])
|
|
145
|
+
confirm_password = PasswordField(_("Confirmar nueva contraseña"), validators=[Optional(), Length(min=6)])
|
|
146
|
+
submit = SubmitField(_("Actualizar Perfil"))
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
class CurrencyForm(FlaskForm):
|
|
150
|
+
"""Form for creating and editing currencies."""
|
|
151
|
+
|
|
152
|
+
codigo = StringField(_("Código"), validators=[DataRequired(), Length(max=10)])
|
|
153
|
+
nombre = StringField(_("Nombre"), validators=[DataRequired(), Length(max=100)])
|
|
154
|
+
simbolo = StringField(_("Símbolo"), validators=[Optional(), Length(max=10)])
|
|
155
|
+
activo = BooleanField(_("Activo"), default=True)
|
|
156
|
+
submit = SubmitField(_("Guardar"))
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class ExchangeRateForm(FlaskForm):
|
|
160
|
+
"""Form for creating and editing exchange rates."""
|
|
161
|
+
|
|
162
|
+
fecha = DateField(_("Fecha"), validators=[DataRequired()])
|
|
163
|
+
moneda_origen_id = SelectField(_("Moneda origen"), validators=[DataRequired()], coerce=str)
|
|
164
|
+
moneda_destino_id = SelectField(_("Moneda destino"), validators=[DataRequired()], coerce=str)
|
|
165
|
+
tasa = DecimalField(_("Tasa de cambio"), validators=[DataRequired()], places=10)
|
|
166
|
+
submit = SubmitField(_("Guardar"))
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
class EmployeeForm(FlaskForm):
|
|
170
|
+
"""Form for creating and editing employees."""
|
|
171
|
+
|
|
172
|
+
codigo_empleado = StringField(
|
|
173
|
+
_("Código de empleado"),
|
|
174
|
+
validators=[
|
|
175
|
+
Optional(),
|
|
176
|
+
Length(max=20),
|
|
177
|
+
Regexp(
|
|
178
|
+
r"^[A-Za-z0-9\-]+$",
|
|
179
|
+
message=_("El código solo puede contener letras, números y guiones."),
|
|
180
|
+
),
|
|
181
|
+
],
|
|
182
|
+
description=_("Código único del empleado. Si no se proporciona, se genera automáticamente."),
|
|
183
|
+
)
|
|
184
|
+
primer_nombre = StringField(_("Primer nombre"), validators=[DataRequired(), Length(max=100)])
|
|
185
|
+
segundo_nombre = StringField(_("Segundo nombre"), validators=[Optional(), Length(max=100)])
|
|
186
|
+
primer_apellido = StringField(_("Primer apellido"), validators=[DataRequired(), Length(max=100)])
|
|
187
|
+
segundo_apellido = StringField(_("Segundo apellido"), validators=[Optional(), Length(max=100)])
|
|
188
|
+
genero = SelectField(
|
|
189
|
+
_("Género"),
|
|
190
|
+
choices=[
|
|
191
|
+
("", _("Seleccionar...")),
|
|
192
|
+
("masculino", _("Masculino")),
|
|
193
|
+
("femenino", _("Femenino")),
|
|
194
|
+
("otro", _("Otro")),
|
|
195
|
+
],
|
|
196
|
+
validators=[Optional()],
|
|
197
|
+
)
|
|
198
|
+
nacionalidad = StringField(_("Nacionalidad"), validators=[Optional(), Length(max=100)])
|
|
199
|
+
tipo_identificacion = SelectField(
|
|
200
|
+
_("Tipo de identificación"),
|
|
201
|
+
choices=[
|
|
202
|
+
("", _("Seleccionar...")),
|
|
203
|
+
("cedula", _("Cédula")),
|
|
204
|
+
("pasaporte", _("Pasaporte")),
|
|
205
|
+
("carnet_residente", _("Carnet de residente")),
|
|
206
|
+
("otro", _("Otro")),
|
|
207
|
+
],
|
|
208
|
+
validators=[Optional()],
|
|
209
|
+
)
|
|
210
|
+
identificacion_personal = StringField(_("Identificación personal"), validators=[DataRequired(), Length(max=50)])
|
|
211
|
+
id_seguridad_social = StringField(_("ID Seguridad Social"), validators=[Optional(), Length(max=50)])
|
|
212
|
+
id_fiscal = StringField(_("ID Fiscal"), validators=[Optional(), Length(max=50)])
|
|
213
|
+
tipo_sangre = SelectField(
|
|
214
|
+
_("Tipo de sangre"),
|
|
215
|
+
choices=[
|
|
216
|
+
("", _("Seleccionar...")),
|
|
217
|
+
("A+", "A+"),
|
|
218
|
+
("A-", "A-"),
|
|
219
|
+
("B+", "B+"),
|
|
220
|
+
("B-", "B-"),
|
|
221
|
+
("AB+", "AB+"),
|
|
222
|
+
("AB-", "AB-"),
|
|
223
|
+
("O+", "O+"),
|
|
224
|
+
("O-", "O-"),
|
|
225
|
+
],
|
|
226
|
+
validators=[Optional()],
|
|
227
|
+
)
|
|
228
|
+
fecha_nacimiento = DateField(_("Fecha de nacimiento"), validators=[Optional()])
|
|
229
|
+
fecha_alta = DateField(_("Fecha de alta"), validators=[DataRequired()])
|
|
230
|
+
fecha_baja = DateField(_("Fecha de baja"), validators=[Optional()])
|
|
231
|
+
activo = BooleanField(_("Activo"), default=True)
|
|
232
|
+
cargo = StringField(_("Cargo"), validators=[Optional(), Length(max=150)])
|
|
233
|
+
area = StringField(_("Área"), validators=[Optional(), Length(max=150)])
|
|
234
|
+
centro_costos = StringField(_("Centro de costos"), validators=[Optional(), Length(max=150)])
|
|
235
|
+
salario_base = DecimalField(_("Salario base"), validators=[DataRequired()], places=2)
|
|
236
|
+
moneda_id = SelectField(_("Moneda"), validators=[Optional()], coerce=str)
|
|
237
|
+
empresa_id = SelectField(_("Empresa"), validators=[Optional()], coerce=str)
|
|
238
|
+
correo = StringField(_("Correo electrónico"), validators=[Optional(), Email(), Length(max=150)])
|
|
239
|
+
telefono = StringField(_("Teléfono"), validators=[Optional(), Length(max=50)])
|
|
240
|
+
direccion = StringField(_("Dirección"), validators=[Optional(), Length(max=255)])
|
|
241
|
+
estado_civil = SelectField(
|
|
242
|
+
_("Estado civil"),
|
|
243
|
+
choices=[
|
|
244
|
+
("", _("Seleccionar...")),
|
|
245
|
+
("soltero", _("Soltero/a")),
|
|
246
|
+
("casado", _("Casado/a")),
|
|
247
|
+
("divorciado", _("Divorciado/a")),
|
|
248
|
+
("viudo", _("Viudo/a")),
|
|
249
|
+
("union_libre", _("Unión libre")),
|
|
250
|
+
],
|
|
251
|
+
validators=[Optional()],
|
|
252
|
+
)
|
|
253
|
+
banco = StringField(_("Banco"), validators=[Optional(), Length(max=100)])
|
|
254
|
+
numero_cuenta_bancaria = StringField(_("Número de cuenta bancaria"), validators=[Optional(), Length(max=100)])
|
|
255
|
+
tipo_contrato = SelectField(
|
|
256
|
+
_("Tipo de contrato"),
|
|
257
|
+
choices=[
|
|
258
|
+
("", _("Seleccionar...")),
|
|
259
|
+
("indefinido", _("Indefinido")),
|
|
260
|
+
("temporal", _("Temporal")),
|
|
261
|
+
("por_obra", _("Por obra")),
|
|
262
|
+
("practicas", _("Prácticas")),
|
|
263
|
+
],
|
|
264
|
+
validators=[Optional()],
|
|
265
|
+
)
|
|
266
|
+
# Datos iniciales de implementación
|
|
267
|
+
anio_implementacion_inicial = IntegerField(
|
|
268
|
+
_("Año de implementación inicial"),
|
|
269
|
+
validators=[Optional(), NumberRange(min=1900, max=2100)],
|
|
270
|
+
description=_("Año fiscal cuando se implementó el sistema por primera vez"),
|
|
271
|
+
)
|
|
272
|
+
mes_ultimo_cierre = SelectField(
|
|
273
|
+
_("Último mes cerrado"),
|
|
274
|
+
choices=[
|
|
275
|
+
("", _("Seleccionar...")),
|
|
276
|
+
("1", _("Enero")),
|
|
277
|
+
("2", _("Febrero")),
|
|
278
|
+
("3", _("Marzo")),
|
|
279
|
+
("4", _("Abril")),
|
|
280
|
+
("5", _("Mayo")),
|
|
281
|
+
("6", _("Junio")),
|
|
282
|
+
("7", _("Julio")),
|
|
283
|
+
("8", _("Agosto")),
|
|
284
|
+
("9", _("Septiembre")),
|
|
285
|
+
("10", _("Octubre")),
|
|
286
|
+
("11", _("Noviembre")),
|
|
287
|
+
("12", _("Diciembre")),
|
|
288
|
+
],
|
|
289
|
+
validators=[Optional()],
|
|
290
|
+
coerce=lambda x: int(x) if x else None,
|
|
291
|
+
description=_("Último mes cerrado antes de pasar al nuevo sistema"),
|
|
292
|
+
)
|
|
293
|
+
salario_acumulado = DecimalField(
|
|
294
|
+
_("Salario acumulado"),
|
|
295
|
+
validators=[Optional()],
|
|
296
|
+
places=2,
|
|
297
|
+
description=_("Suma de salarios del año fiscal antes del sistema"),
|
|
298
|
+
)
|
|
299
|
+
impuesto_acumulado = DecimalField(
|
|
300
|
+
_("Impuesto acumulado"),
|
|
301
|
+
validators=[Optional()],
|
|
302
|
+
places=2,
|
|
303
|
+
description=_("Suma de impuestos pagados en el año fiscal antes del sistema"),
|
|
304
|
+
)
|
|
305
|
+
ultimo_salario_1 = DecimalField(
|
|
306
|
+
_("Penúltimo salario mensual"),
|
|
307
|
+
validators=[Optional()],
|
|
308
|
+
places=2,
|
|
309
|
+
description=_("Salario del mes anterior al último"),
|
|
310
|
+
)
|
|
311
|
+
ultimo_salario_2 = DecimalField(
|
|
312
|
+
_("Antepenúltimo salario mensual"),
|
|
313
|
+
validators=[Optional()],
|
|
314
|
+
places=2,
|
|
315
|
+
description=_("Salario de 2 meses antes del último"),
|
|
316
|
+
)
|
|
317
|
+
ultimo_salario_3 = DecimalField(
|
|
318
|
+
_("Tercer salario anterior"),
|
|
319
|
+
validators=[Optional()],
|
|
320
|
+
places=2,
|
|
321
|
+
description=_("Salario de 3 meses antes del último"),
|
|
322
|
+
)
|
|
323
|
+
submit = SubmitField(_("Guardar"))
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
class CustomFieldForm(FlaskForm):
|
|
327
|
+
"""Form for creating and editing custom employee fields."""
|
|
328
|
+
|
|
329
|
+
nombre_campo = StringField(
|
|
330
|
+
_("Nombre del campo"),
|
|
331
|
+
validators=[DataRequired(), Length(max=100)],
|
|
332
|
+
description=_("Nombre interno único del campo (sin espacios ni caracteres especiales)"),
|
|
333
|
+
)
|
|
334
|
+
etiqueta = StringField(
|
|
335
|
+
_("Etiqueta"),
|
|
336
|
+
validators=[DataRequired(), Length(max=150)],
|
|
337
|
+
description=_("Nombre visible del campo en el formulario"),
|
|
338
|
+
)
|
|
339
|
+
tipo_dato = SelectField(
|
|
340
|
+
_("Tipo de dato"),
|
|
341
|
+
choices=[
|
|
342
|
+
("texto", _("Texto")),
|
|
343
|
+
("entero", _("Número entero")),
|
|
344
|
+
("decimal", _("Número decimal")),
|
|
345
|
+
("booleano", _("Verdadero/Falso")),
|
|
346
|
+
],
|
|
347
|
+
validators=[DataRequired()],
|
|
348
|
+
)
|
|
349
|
+
descripcion = StringField(_("Descripción"), validators=[Optional(), Length(max=255)])
|
|
350
|
+
orden = DecimalField(
|
|
351
|
+
_("Orden de visualización"),
|
|
352
|
+
validators=[Optional()],
|
|
353
|
+
places=0,
|
|
354
|
+
default=0,
|
|
355
|
+
)
|
|
356
|
+
activo = BooleanField(_("Activo"), default=True)
|
|
357
|
+
submit = SubmitField(_("Guardar"))
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
class ReglaCalculoForm(FlaskForm):
|
|
361
|
+
"""Form for creating and editing calculation rules."""
|
|
362
|
+
|
|
363
|
+
codigo = StringField(
|
|
364
|
+
_("Código"),
|
|
365
|
+
validators=[DataRequired(), Length(max=50)],
|
|
366
|
+
description=_("Código único de la regla (ej: INCOME_TAX_001)"),
|
|
367
|
+
)
|
|
368
|
+
nombre = StringField(
|
|
369
|
+
_("Nombre"),
|
|
370
|
+
validators=[DataRequired(), Length(max=150)],
|
|
371
|
+
description=_("Nombre descriptivo de la regla"),
|
|
372
|
+
)
|
|
373
|
+
descripcion = StringField(
|
|
374
|
+
_("Descripción"),
|
|
375
|
+
validators=[Optional(), Length(max=500)],
|
|
376
|
+
)
|
|
377
|
+
jurisdiccion = StringField(
|
|
378
|
+
_("Jurisdicción"),
|
|
379
|
+
validators=[Optional(), Length(max=100)],
|
|
380
|
+
description=_("País o región donde aplica (ej: Country A)"),
|
|
381
|
+
)
|
|
382
|
+
moneda_referencia = StringField(
|
|
383
|
+
_("Moneda de Referencia"),
|
|
384
|
+
validators=[Optional(), Length(max=10)],
|
|
385
|
+
description=_(
|
|
386
|
+
"Moneda base para cálculos de la regla (ej: NIO). "
|
|
387
|
+
"La moneda de la planilla se define en el Tipo de Planilla."
|
|
388
|
+
),
|
|
389
|
+
)
|
|
390
|
+
version = StringField(
|
|
391
|
+
_("Versión"),
|
|
392
|
+
validators=[DataRequired(), Length(max=20)],
|
|
393
|
+
default="1.0.0",
|
|
394
|
+
description=_("Versión semántica (ej: 1.0.0)"),
|
|
395
|
+
)
|
|
396
|
+
tipo_regla = SelectField(
|
|
397
|
+
_("Tipo de regla"),
|
|
398
|
+
choices=[
|
|
399
|
+
("impuesto", _("Impuesto")),
|
|
400
|
+
("deduccion", _("Deducción")),
|
|
401
|
+
("percepcion", _("Percepción")),
|
|
402
|
+
("prestacion", _("Prestación")),
|
|
403
|
+
],
|
|
404
|
+
validators=[DataRequired()],
|
|
405
|
+
)
|
|
406
|
+
vigente_desde = DateField(
|
|
407
|
+
_("Vigente desde"),
|
|
408
|
+
validators=[DataRequired()],
|
|
409
|
+
description=_("Fecha desde la cual la regla es válida"),
|
|
410
|
+
)
|
|
411
|
+
vigente_hasta = DateField(
|
|
412
|
+
_("Vigente hasta"),
|
|
413
|
+
validators=[Optional()],
|
|
414
|
+
description=_("Fecha hasta la cual la regla es válida (vacío = indefinido)"),
|
|
415
|
+
)
|
|
416
|
+
activo = BooleanField(_("Activo"), default=True)
|
|
417
|
+
submit = SubmitField(_("Guardar"))
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
# ============================================================================
|
|
421
|
+
# PAYROLL CONCEPTS FORMS (Percepciones, Deducciones, Prestaciones)
|
|
422
|
+
# ============================================================================
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
class PercepcionForm(FlaskForm):
|
|
426
|
+
"""Form for creating and editing perceptions (income items).
|
|
427
|
+
|
|
428
|
+
Percepciones are income items that ADD to employee's pay.
|
|
429
|
+
Only Percepciones and Deducciones affect the employee's net salary.
|
|
430
|
+
"""
|
|
431
|
+
|
|
432
|
+
codigo = StringField(
|
|
433
|
+
_("Código"),
|
|
434
|
+
validators=[DataRequired(), Length(max=50)],
|
|
435
|
+
description=_("Código único de la percepción (ej: SALARIO_BASE)"),
|
|
436
|
+
)
|
|
437
|
+
nombre = StringField(
|
|
438
|
+
_("Nombre"),
|
|
439
|
+
validators=[DataRequired(), Length(max=150)],
|
|
440
|
+
description=_("Nombre descriptivo de la percepción"),
|
|
441
|
+
)
|
|
442
|
+
descripcion = StringField(
|
|
443
|
+
_("Descripción"),
|
|
444
|
+
validators=[Optional(), Length(max=255)],
|
|
445
|
+
)
|
|
446
|
+
formula_tipo = SelectField(
|
|
447
|
+
_("Tipo de Cálculo"),
|
|
448
|
+
choices=[
|
|
449
|
+
("fijo", _("Monto Fijo")),
|
|
450
|
+
("porcentaje_salario", _("Porcentaje del Salario Base")),
|
|
451
|
+
("porcentaje_bruto", _("Porcentaje del Salario Bruto")),
|
|
452
|
+
("formula", _("Fórmula Personalizada")),
|
|
453
|
+
("horas", _("Por Horas")),
|
|
454
|
+
("dias", _("Por Días")),
|
|
455
|
+
],
|
|
456
|
+
validators=[DataRequired()],
|
|
457
|
+
)
|
|
458
|
+
monto_default = DecimalField(
|
|
459
|
+
_("Monto Predeterminado"),
|
|
460
|
+
validators=[Optional()],
|
|
461
|
+
description=_("Monto fijo cuando aplica"),
|
|
462
|
+
)
|
|
463
|
+
porcentaje = DecimalField(
|
|
464
|
+
_("Porcentaje"),
|
|
465
|
+
validators=[Optional(), NumberRange(min=0, max=100)],
|
|
466
|
+
description=_("Porcentaje para cálculos (0-100)"),
|
|
467
|
+
)
|
|
468
|
+
base_calculo = SelectField(
|
|
469
|
+
_("Base de Cálculo"),
|
|
470
|
+
choices=[
|
|
471
|
+
("", _("-- Seleccionar --")),
|
|
472
|
+
("salario_base", _("Salario Base")),
|
|
473
|
+
("salario_bruto", _("Salario Bruto")),
|
|
474
|
+
("salario_gravable", _("Salario Gravable")),
|
|
475
|
+
("salario_neto", _("Salario Neto")),
|
|
476
|
+
],
|
|
477
|
+
validators=[Optional()],
|
|
478
|
+
)
|
|
479
|
+
unidad_calculo = SelectField(
|
|
480
|
+
_("Unidad de Cálculo"),
|
|
481
|
+
choices=[
|
|
482
|
+
("", _("-- Ninguna --")),
|
|
483
|
+
("hora", _("Por Hora")),
|
|
484
|
+
("dia", _("Por Día")),
|
|
485
|
+
("mes", _("Por Mes")),
|
|
486
|
+
],
|
|
487
|
+
validators=[Optional()],
|
|
488
|
+
)
|
|
489
|
+
gravable = BooleanField(
|
|
490
|
+
_("Gravable"),
|
|
491
|
+
default=True,
|
|
492
|
+
description=_("¿Esta percepción está sujeta a impuestos?"),
|
|
493
|
+
)
|
|
494
|
+
recurrente = BooleanField(
|
|
495
|
+
_("Recurrente"),
|
|
496
|
+
default=False,
|
|
497
|
+
description=_("¿Se aplica automáticamente en cada nómina?"),
|
|
498
|
+
)
|
|
499
|
+
# Vigencia
|
|
500
|
+
vigente_desde = DateField(
|
|
501
|
+
_("Vigente Desde"),
|
|
502
|
+
validators=[Optional()],
|
|
503
|
+
description=_("Fecha desde la cual esta percepción es válida"),
|
|
504
|
+
)
|
|
505
|
+
valido_hasta = DateField(
|
|
506
|
+
_("Válido Hasta"),
|
|
507
|
+
validators=[Optional()],
|
|
508
|
+
description=_("Fecha hasta la cual esta percepción es válida (vacío = indefinido)"),
|
|
509
|
+
)
|
|
510
|
+
# Contabilidad
|
|
511
|
+
contabilizable = BooleanField(
|
|
512
|
+
_("Contabilizable"),
|
|
513
|
+
default=True,
|
|
514
|
+
)
|
|
515
|
+
codigo_cuenta_debe = StringField(
|
|
516
|
+
_("Cuenta Contable (Debe)"),
|
|
517
|
+
validators=[Optional(), Length(max=64)],
|
|
518
|
+
)
|
|
519
|
+
descripcion_cuenta_debe = StringField(
|
|
520
|
+
_("Descripción Cuenta (Debe)"),
|
|
521
|
+
validators=[Optional(), Length(max=255)],
|
|
522
|
+
)
|
|
523
|
+
codigo_cuenta_haber = StringField(
|
|
524
|
+
_("Cuenta Contable (Haber)"),
|
|
525
|
+
validators=[Optional(), Length(max=64)],
|
|
526
|
+
)
|
|
527
|
+
descripcion_cuenta_haber = StringField(
|
|
528
|
+
_("Descripción Cuenta (Haber)"),
|
|
529
|
+
validators=[Optional(), Length(max=255)],
|
|
530
|
+
)
|
|
531
|
+
editable_en_nomina = BooleanField(
|
|
532
|
+
_("Editable en Nómina"),
|
|
533
|
+
default=False,
|
|
534
|
+
description=_("¿Permitir modificar el monto durante la nómina?"),
|
|
535
|
+
)
|
|
536
|
+
activo = BooleanField(_("Activo"), default=True)
|
|
537
|
+
submit = SubmitField(_("Guardar"))
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
class DeduccionForm(FlaskForm):
|
|
541
|
+
"""Form for creating and editing deductions."""
|
|
542
|
+
|
|
543
|
+
codigo = StringField(
|
|
544
|
+
_("Código"),
|
|
545
|
+
validators=[DataRequired(), Length(max=50)],
|
|
546
|
+
description=_("Código único de la deducción (ej: SOCIAL_SEC_001)"),
|
|
547
|
+
)
|
|
548
|
+
nombre = StringField(
|
|
549
|
+
_("Nombre"),
|
|
550
|
+
validators=[DataRequired(), Length(max=150)],
|
|
551
|
+
description=_("Nombre descriptivo de la deducción"),
|
|
552
|
+
)
|
|
553
|
+
descripcion = StringField(
|
|
554
|
+
_("Descripción"),
|
|
555
|
+
validators=[Optional(), Length(max=255)],
|
|
556
|
+
)
|
|
557
|
+
tipo = SelectField(
|
|
558
|
+
_("Tipo de Deducción"),
|
|
559
|
+
choices=[
|
|
560
|
+
("general", _("General")),
|
|
561
|
+
("impuesto", _("Impuesto")),
|
|
562
|
+
("seguro_social", _("Seguro Social")),
|
|
563
|
+
("prestamo", _("Préstamo")),
|
|
564
|
+
("adelanto", _("Adelanto")),
|
|
565
|
+
("pension_alimenticia", _("Pensión Alimenticia")),
|
|
566
|
+
("ahorro", _("Ahorro Voluntario")),
|
|
567
|
+
("sindical", _("Cuota Sindical")),
|
|
568
|
+
("otro", _("Otro")),
|
|
569
|
+
],
|
|
570
|
+
validators=[DataRequired()],
|
|
571
|
+
)
|
|
572
|
+
es_impuesto = BooleanField(
|
|
573
|
+
_("Es Impuesto"),
|
|
574
|
+
default=False,
|
|
575
|
+
description=_("¿Esta deducción es un impuesto (IR, ISR)?"),
|
|
576
|
+
)
|
|
577
|
+
formula_tipo = SelectField(
|
|
578
|
+
_("Tipo de Cálculo"),
|
|
579
|
+
choices=[
|
|
580
|
+
("fijo", _("Monto Fijo")),
|
|
581
|
+
("porcentaje_salario", _("Porcentaje del Salario Base")),
|
|
582
|
+
("porcentaje_bruto", _("Porcentaje del Salario Bruto")),
|
|
583
|
+
("porcentaje_gravable", _("Porcentaje del Salario Gravable")),
|
|
584
|
+
("formula", _("Fórmula Personalizada")),
|
|
585
|
+
("tabla", _("Tabla de Impuestos")),
|
|
586
|
+
],
|
|
587
|
+
validators=[DataRequired()],
|
|
588
|
+
)
|
|
589
|
+
monto_default = DecimalField(
|
|
590
|
+
_("Monto Predeterminado"),
|
|
591
|
+
validators=[Optional()],
|
|
592
|
+
description=_("Monto fijo cuando aplica"),
|
|
593
|
+
)
|
|
594
|
+
porcentaje = DecimalField(
|
|
595
|
+
_("Porcentaje"),
|
|
596
|
+
validators=[Optional(), NumberRange(min=0, max=100)],
|
|
597
|
+
description=_("Porcentaje para cálculos (0-100)"),
|
|
598
|
+
)
|
|
599
|
+
base_calculo = SelectField(
|
|
600
|
+
_("Base de Cálculo"),
|
|
601
|
+
choices=[
|
|
602
|
+
("", _("-- Seleccionar --")),
|
|
603
|
+
("salario_base", _("Salario Base")),
|
|
604
|
+
("salario_bruto", _("Salario Bruto")),
|
|
605
|
+
("salario_gravable", _("Salario Gravable")),
|
|
606
|
+
("salario_neto", _("Salario Neto")),
|
|
607
|
+
],
|
|
608
|
+
validators=[Optional()],
|
|
609
|
+
)
|
|
610
|
+
unidad_calculo = SelectField(
|
|
611
|
+
_("Unidad de Cálculo"),
|
|
612
|
+
choices=[
|
|
613
|
+
("", _("-- Ninguna --")),
|
|
614
|
+
("hora", _("Por Hora")),
|
|
615
|
+
("dia", _("Por Día")),
|
|
616
|
+
("mes", _("Por Mes")),
|
|
617
|
+
],
|
|
618
|
+
validators=[Optional()],
|
|
619
|
+
)
|
|
620
|
+
antes_impuesto = BooleanField(
|
|
621
|
+
_("Antes de Impuesto"),
|
|
622
|
+
default=True,
|
|
623
|
+
description=_("¿Se deduce antes de calcular impuestos?"),
|
|
624
|
+
)
|
|
625
|
+
recurrente = BooleanField(
|
|
626
|
+
_("Recurrente"),
|
|
627
|
+
default=False,
|
|
628
|
+
description=_("¿Se aplica automáticamente en cada nómina?"),
|
|
629
|
+
)
|
|
630
|
+
# Vigencia
|
|
631
|
+
vigente_desde = DateField(
|
|
632
|
+
_("Vigente Desde"),
|
|
633
|
+
validators=[Optional()],
|
|
634
|
+
description=_("Fecha desde la cual esta deducción es válida"),
|
|
635
|
+
)
|
|
636
|
+
valido_hasta = DateField(
|
|
637
|
+
_("Válido Hasta"),
|
|
638
|
+
validators=[Optional()],
|
|
639
|
+
description=_("Fecha hasta la cual esta deducción es válida (vacío = indefinido)"),
|
|
640
|
+
)
|
|
641
|
+
# Contabilidad
|
|
642
|
+
contabilizable = BooleanField(
|
|
643
|
+
_("Contabilizable"),
|
|
644
|
+
default=True,
|
|
645
|
+
)
|
|
646
|
+
codigo_cuenta_debe = StringField(
|
|
647
|
+
_("Cuenta Contable (Debe)"),
|
|
648
|
+
validators=[Optional(), Length(max=64)],
|
|
649
|
+
)
|
|
650
|
+
descripcion_cuenta_debe = StringField(
|
|
651
|
+
_("Descripción Cuenta (Debe)"),
|
|
652
|
+
validators=[Optional(), Length(max=255)],
|
|
653
|
+
)
|
|
654
|
+
codigo_cuenta_haber = StringField(
|
|
655
|
+
_("Cuenta Contable (Haber)"),
|
|
656
|
+
validators=[Optional(), Length(max=64)],
|
|
657
|
+
)
|
|
658
|
+
descripcion_cuenta_haber = StringField(
|
|
659
|
+
_("Descripción Cuenta (Haber)"),
|
|
660
|
+
validators=[Optional(), Length(max=255)],
|
|
661
|
+
)
|
|
662
|
+
editable_en_nomina = BooleanField(
|
|
663
|
+
_("Editable en Nómina"),
|
|
664
|
+
default=False,
|
|
665
|
+
description=_("¿Permitir modificar el monto durante la nómina?"),
|
|
666
|
+
)
|
|
667
|
+
activo = BooleanField(_("Activo"), default=True)
|
|
668
|
+
submit = SubmitField(_("Guardar"))
|
|
669
|
+
|
|
670
|
+
|
|
671
|
+
class PlanillaForm(FlaskForm):
|
|
672
|
+
"""Form for creating and editing payroll master records (Planilla).
|
|
673
|
+
|
|
674
|
+
A Planilla is the central hub that connects employees, perceptions,
|
|
675
|
+
deductions, benefits, and calculation rules.
|
|
676
|
+
"""
|
|
677
|
+
|
|
678
|
+
nombre = StringField(
|
|
679
|
+
_("Nombre"),
|
|
680
|
+
validators=[DataRequired(), Length(max=150)],
|
|
681
|
+
description=_("Nombre único de la planilla (ej: Planilla Quincenal Córdobas)"),
|
|
682
|
+
)
|
|
683
|
+
descripcion = StringField(
|
|
684
|
+
_("Descripción"),
|
|
685
|
+
validators=[Optional(), Length(max=255)],
|
|
686
|
+
)
|
|
687
|
+
tipo_planilla_id = SelectField(
|
|
688
|
+
_("Tipo de Planilla"),
|
|
689
|
+
validators=[DataRequired()],
|
|
690
|
+
coerce=str,
|
|
691
|
+
description=_("Define periodicidad, período fiscal y configuración de cálculo"),
|
|
692
|
+
)
|
|
693
|
+
moneda_id = SelectField(
|
|
694
|
+
_("Moneda"),
|
|
695
|
+
validators=[DataRequired()],
|
|
696
|
+
coerce=str,
|
|
697
|
+
description=_("Moneda en la que se pagarán los salarios"),
|
|
698
|
+
)
|
|
699
|
+
empresa_id = SelectField(
|
|
700
|
+
_("Empresa"),
|
|
701
|
+
validators=[DataRequired(message=_("La empresa es obligatoria para crear una planilla"))],
|
|
702
|
+
coerce=str,
|
|
703
|
+
description=_("Empresa a la que pertenece esta planilla. Solo empleados de esta empresa podrán ser asignados."),
|
|
704
|
+
)
|
|
705
|
+
periodo_fiscal_inicio = DateField(
|
|
706
|
+
_("Inicio Período Fiscal"),
|
|
707
|
+
validators=[Optional()],
|
|
708
|
+
description=_("Fecha de inicio del período fiscal actual"),
|
|
709
|
+
)
|
|
710
|
+
periodo_fiscal_fin = DateField(
|
|
711
|
+
_("Fin Período Fiscal"),
|
|
712
|
+
validators=[Optional()],
|
|
713
|
+
description=_("Fecha de fin del período fiscal actual"),
|
|
714
|
+
)
|
|
715
|
+
# Automatic deduction priorities
|
|
716
|
+
prioridad_prestamos = IntegerField(
|
|
717
|
+
_("Prioridad Préstamos"),
|
|
718
|
+
validators=[Optional(), NumberRange(min=1, max=999)],
|
|
719
|
+
default=250,
|
|
720
|
+
description=_("Prioridad para deducir cuotas de préstamos (menor = primero)"),
|
|
721
|
+
)
|
|
722
|
+
prioridad_adelantos = IntegerField(
|
|
723
|
+
_("Prioridad Adelantos"),
|
|
724
|
+
validators=[Optional(), NumberRange(min=1, max=999)],
|
|
725
|
+
default=251,
|
|
726
|
+
description=_("Prioridad para deducir adelantos salariales (menor = primero)"),
|
|
727
|
+
)
|
|
728
|
+
aplicar_prestamos_automatico = BooleanField(
|
|
729
|
+
_("Aplicar Préstamos Automáticamente"),
|
|
730
|
+
default=True,
|
|
731
|
+
description=_("¿Deducir automáticamente las cuotas de préstamos?"),
|
|
732
|
+
)
|
|
733
|
+
aplicar_adelantos_automatico = BooleanField(
|
|
734
|
+
_("Aplicar Adelantos Automáticamente"),
|
|
735
|
+
default=True,
|
|
736
|
+
description=_("¿Deducir automáticamente los adelantos salariales?"),
|
|
737
|
+
)
|
|
738
|
+
# Accounting fields for base salary
|
|
739
|
+
codigo_cuenta_debe_salario = StringField(
|
|
740
|
+
_("Cuenta Débito (Salario Base)"),
|
|
741
|
+
validators=[Optional(), Length(max=64)],
|
|
742
|
+
description=_("Cuenta de débito para contabilizar el salario base (gasto)"),
|
|
743
|
+
)
|
|
744
|
+
descripcion_cuenta_debe_salario = StringField(
|
|
745
|
+
_("Descripción Cuenta Débito (Salario)"),
|
|
746
|
+
validators=[Optional(), Length(max=255)],
|
|
747
|
+
)
|
|
748
|
+
codigo_cuenta_haber_salario = StringField(
|
|
749
|
+
_("Cuenta Crédito (Salario Base)"),
|
|
750
|
+
validators=[Optional(), Length(max=64)],
|
|
751
|
+
description=_("Cuenta de crédito para contabilizar el salario base (pasivo)"),
|
|
752
|
+
)
|
|
753
|
+
descripcion_cuenta_haber_salario = StringField(
|
|
754
|
+
_("Descripción Cuenta Crédito (Salario)"),
|
|
755
|
+
validators=[Optional(), Length(max=255)],
|
|
756
|
+
)
|
|
757
|
+
activo = BooleanField(_("Activo"), default=True)
|
|
758
|
+
submit = SubmitField(_("Guardar"))
|
|
759
|
+
|
|
760
|
+
|
|
761
|
+
class TipoPlanillaForm(FlaskForm):
|
|
762
|
+
"""Form for creating and editing payroll types (TipoPlanilla).
|
|
763
|
+
|
|
764
|
+
Defines the type of payroll (monthly, biweekly, weekly, etc.) and its
|
|
765
|
+
fiscal period parameters.
|
|
766
|
+
"""
|
|
767
|
+
|
|
768
|
+
codigo = StringField(
|
|
769
|
+
_("Código"),
|
|
770
|
+
validators=[DataRequired(), Length(max=20)],
|
|
771
|
+
description=_("Código único del tipo de planilla (ej: MENSUAL)"),
|
|
772
|
+
)
|
|
773
|
+
descripcion = StringField(
|
|
774
|
+
_("Descripción"),
|
|
775
|
+
validators=[Optional(), Length(max=150)],
|
|
776
|
+
description=_("Descripción del tipo de planilla"),
|
|
777
|
+
)
|
|
778
|
+
periodicidad = SelectField(
|
|
779
|
+
_("Periodicidad"),
|
|
780
|
+
choices=[
|
|
781
|
+
("mensual", _("Mensual")),
|
|
782
|
+
("quincenal", _("Quincenal")),
|
|
783
|
+
("semanal", _("Semanal")),
|
|
784
|
+
],
|
|
785
|
+
validators=[DataRequired()],
|
|
786
|
+
description=_("Frecuencia de pago de la planilla"),
|
|
787
|
+
)
|
|
788
|
+
dias = IntegerField(
|
|
789
|
+
_("Días"),
|
|
790
|
+
validators=[DataRequired(), NumberRange(min=1, max=365)],
|
|
791
|
+
default=30,
|
|
792
|
+
description=_("Número de días usados para prorrateos"),
|
|
793
|
+
)
|
|
794
|
+
mes_inicio_fiscal = SelectField(
|
|
795
|
+
_("Mes Inicio Fiscal"),
|
|
796
|
+
choices=[
|
|
797
|
+
("1", _("Enero")),
|
|
798
|
+
("2", _("Febrero")),
|
|
799
|
+
("3", _("Marzo")),
|
|
800
|
+
("4", _("Abril")),
|
|
801
|
+
("5", _("Mayo")),
|
|
802
|
+
("6", _("Junio")),
|
|
803
|
+
("7", _("Julio")),
|
|
804
|
+
("8", _("Agosto")),
|
|
805
|
+
("9", _("Septiembre")),
|
|
806
|
+
("10", _("Octubre")),
|
|
807
|
+
("11", _("Noviembre")),
|
|
808
|
+
("12", _("Diciembre")),
|
|
809
|
+
],
|
|
810
|
+
validators=[DataRequired()],
|
|
811
|
+
coerce=int,
|
|
812
|
+
default=1,
|
|
813
|
+
description=_("Mes en que inicia el año fiscal"),
|
|
814
|
+
)
|
|
815
|
+
dia_inicio_fiscal = IntegerField(
|
|
816
|
+
_("Día Inicio Fiscal"),
|
|
817
|
+
validators=[DataRequired(), NumberRange(min=1, max=31)],
|
|
818
|
+
default=1,
|
|
819
|
+
description=_("Día del mes en que inicia el año fiscal"),
|
|
820
|
+
)
|
|
821
|
+
acumula_anual = BooleanField(
|
|
822
|
+
_("Acumula Anual"),
|
|
823
|
+
default=True,
|
|
824
|
+
description=_("¿Los valores se acumulan anualmente?"),
|
|
825
|
+
)
|
|
826
|
+
periodos_por_anio = IntegerField(
|
|
827
|
+
_("Períodos por Año"),
|
|
828
|
+
validators=[DataRequired(), NumberRange(min=1, max=365)],
|
|
829
|
+
default=12,
|
|
830
|
+
description=_("Número de períodos de nómina por año fiscal"),
|
|
831
|
+
)
|
|
832
|
+
activo = BooleanField(_("Activo"), default=True)
|
|
833
|
+
submit = SubmitField(_("Guardar"))
|
|
834
|
+
|
|
835
|
+
|
|
836
|
+
class PrestacionForm(FlaskForm):
|
|
837
|
+
"""Form for creating and editing benefits (employer contributions).
|
|
838
|
+
|
|
839
|
+
Prestaciones are employer costs that do NOT affect the employee's net pay.
|
|
840
|
+
Examples: INSS patronal, vacation provisions, aguinaldo provisions.
|
|
841
|
+
"""
|
|
842
|
+
|
|
843
|
+
codigo = StringField(
|
|
844
|
+
_("Código"),
|
|
845
|
+
validators=[DataRequired(), Length(max=50)],
|
|
846
|
+
description=_("Código único de la prestación (ej: INSS_PATRONAL)"),
|
|
847
|
+
)
|
|
848
|
+
nombre = StringField(
|
|
849
|
+
_("Nombre"),
|
|
850
|
+
validators=[DataRequired(), Length(max=150)],
|
|
851
|
+
description=_("Nombre descriptivo de la prestación"),
|
|
852
|
+
)
|
|
853
|
+
descripcion = StringField(
|
|
854
|
+
_("Descripción"),
|
|
855
|
+
validators=[Optional(), Length(max=255)],
|
|
856
|
+
)
|
|
857
|
+
tipo = SelectField(
|
|
858
|
+
_("Tipo de Prestación"),
|
|
859
|
+
choices=[
|
|
860
|
+
("patronal", _("Aporte Patronal")),
|
|
861
|
+
("seguro_social", _("Seguro Social Patronal")),
|
|
862
|
+
("vacaciones", _("Vacaciones")),
|
|
863
|
+
("aguinaldo", _("Aguinaldo / Treceavo Mes")),
|
|
864
|
+
("indemnizacion", _("Indemnización")),
|
|
865
|
+
("capacitacion", _("Capacitación")),
|
|
866
|
+
("otro", _("Otro")),
|
|
867
|
+
],
|
|
868
|
+
validators=[DataRequired()],
|
|
869
|
+
)
|
|
870
|
+
formula_tipo = SelectField(
|
|
871
|
+
_("Tipo de Cálculo"),
|
|
872
|
+
choices=[
|
|
873
|
+
("fijo", _("Monto Fijo")),
|
|
874
|
+
("porcentaje_salario", _("Porcentaje del Salario Base")),
|
|
875
|
+
("porcentaje_bruto", _("Porcentaje del Salario Bruto")),
|
|
876
|
+
("formula", _("Fórmula Personalizada")),
|
|
877
|
+
("provision", _("Provisión Mensual")),
|
|
878
|
+
],
|
|
879
|
+
validators=[DataRequired()],
|
|
880
|
+
)
|
|
881
|
+
monto_default = DecimalField(
|
|
882
|
+
_("Monto Predeterminado"),
|
|
883
|
+
validators=[Optional()],
|
|
884
|
+
description=_("Monto fijo cuando aplica"),
|
|
885
|
+
)
|
|
886
|
+
porcentaje = DecimalField(
|
|
887
|
+
_("Porcentaje"),
|
|
888
|
+
validators=[Optional(), NumberRange(min=0, max=100)],
|
|
889
|
+
description=_("Porcentaje para cálculos (0-100)"),
|
|
890
|
+
)
|
|
891
|
+
base_calculo = SelectField(
|
|
892
|
+
_("Base de Cálculo"),
|
|
893
|
+
choices=[
|
|
894
|
+
("", _("-- Seleccionar --")),
|
|
895
|
+
("salario_base", _("Salario Base")),
|
|
896
|
+
("salario_bruto", _("Salario Bruto")),
|
|
897
|
+
("salario_gravable", _("Salario Gravable")),
|
|
898
|
+
],
|
|
899
|
+
validators=[Optional()],
|
|
900
|
+
)
|
|
901
|
+
unidad_calculo = SelectField(
|
|
902
|
+
_("Unidad de Cálculo"),
|
|
903
|
+
choices=[
|
|
904
|
+
("", _("-- Ninguna --")),
|
|
905
|
+
("hora", _("Por Hora")),
|
|
906
|
+
("dia", _("Por Día")),
|
|
907
|
+
("mes", _("Por Mes")),
|
|
908
|
+
],
|
|
909
|
+
validators=[Optional()],
|
|
910
|
+
)
|
|
911
|
+
tope_aplicacion = DecimalField(
|
|
912
|
+
_("Tope de Aplicación"),
|
|
913
|
+
validators=[Optional()],
|
|
914
|
+
description=_("Monto máximo sobre el cual se aplica el cálculo (ej: techo salarial INSS)"),
|
|
915
|
+
)
|
|
916
|
+
recurrente = BooleanField(
|
|
917
|
+
_("Recurrente"),
|
|
918
|
+
default=True,
|
|
919
|
+
description=_("¿Se provisiona automáticamente en cada nómina?"),
|
|
920
|
+
)
|
|
921
|
+
# Vigencia
|
|
922
|
+
vigente_desde = DateField(
|
|
923
|
+
_("Vigente Desde"),
|
|
924
|
+
validators=[Optional()],
|
|
925
|
+
description=_("Fecha desde la cual esta prestación es válida"),
|
|
926
|
+
)
|
|
927
|
+
valido_hasta = DateField(
|
|
928
|
+
_("Válido Hasta"),
|
|
929
|
+
validators=[Optional()],
|
|
930
|
+
description=_("Fecha hasta la cual esta prestación es válida (vacío = indefinido)"),
|
|
931
|
+
)
|
|
932
|
+
# Contabilidad
|
|
933
|
+
contabilizable = BooleanField(
|
|
934
|
+
_("Contabilizable"),
|
|
935
|
+
default=True,
|
|
936
|
+
)
|
|
937
|
+
codigo_cuenta_debe = StringField(
|
|
938
|
+
_("Cuenta Contable (Debe)"),
|
|
939
|
+
validators=[Optional(), Length(max=64)],
|
|
940
|
+
)
|
|
941
|
+
descripcion_cuenta_debe = StringField(
|
|
942
|
+
_("Descripción Cuenta (Debe)"),
|
|
943
|
+
validators=[Optional(), Length(max=255)],
|
|
944
|
+
)
|
|
945
|
+
codigo_cuenta_haber = StringField(
|
|
946
|
+
_("Cuenta Contable (Haber)"),
|
|
947
|
+
validators=[Optional(), Length(max=64)],
|
|
948
|
+
)
|
|
949
|
+
descripcion_cuenta_haber = StringField(
|
|
950
|
+
_("Descripción Cuenta (Haber)"),
|
|
951
|
+
validators=[Optional(), Length(max=255)],
|
|
952
|
+
)
|
|
953
|
+
editable_en_nomina = BooleanField(
|
|
954
|
+
_("Editable en Nómina"),
|
|
955
|
+
default=False,
|
|
956
|
+
description=_("¿Permitir modificar el monto durante la nómina?"),
|
|
957
|
+
)
|
|
958
|
+
tipo_acumulacion = SelectField(
|
|
959
|
+
_("Tipo de Acumulación"),
|
|
960
|
+
choices=[
|
|
961
|
+
("mensual", _("Mensual - Liquida cada mes")),
|
|
962
|
+
("anual", _("Anual - Acumula durante el año")),
|
|
963
|
+
("vida_laboral", _("Vida Laboral - Acumula durante toda la relación laboral")),
|
|
964
|
+
],
|
|
965
|
+
validators=[DataRequired()],
|
|
966
|
+
default="mensual",
|
|
967
|
+
description=_("Define cómo se acumula esta prestación"),
|
|
968
|
+
)
|
|
969
|
+
activo = BooleanField(_("Activo"), default=True)
|
|
970
|
+
submit = SubmitField(_("Guardar"))
|
|
971
|
+
|
|
972
|
+
|
|
973
|
+
class NominaNovedadForm(FlaskForm):
|
|
974
|
+
"""Form for adding novelties (novedades) to a nomina.
|
|
975
|
+
|
|
976
|
+
Novedades are adjustments or events that affect an employee's payroll
|
|
977
|
+
for a specific period. They can be associated with:
|
|
978
|
+
- Percepciones (income items like bonuses, overtime)
|
|
979
|
+
- Deducciones (deductions like absences, loans)
|
|
980
|
+
|
|
981
|
+
The novedad is linked to a specific employee and a concept (percepcion or deduccion).
|
|
982
|
+
"""
|
|
983
|
+
|
|
984
|
+
empleado_id = SelectField(
|
|
985
|
+
_("Empleado"),
|
|
986
|
+
validators=[DataRequired()],
|
|
987
|
+
coerce=str,
|
|
988
|
+
description=_("Empleado al que se aplicará la novedad"),
|
|
989
|
+
)
|
|
990
|
+
tipo_concepto = SelectField(
|
|
991
|
+
_("Tipo de Concepto"),
|
|
992
|
+
choices=[
|
|
993
|
+
("percepcion", _("Percepción (Ingreso)")),
|
|
994
|
+
("deduccion", _("Deducción (Egreso)")),
|
|
995
|
+
],
|
|
996
|
+
validators=[DataRequired()],
|
|
997
|
+
description=_("Tipo de concepto al que se asocia la novedad"),
|
|
998
|
+
)
|
|
999
|
+
percepcion_id = SelectField(
|
|
1000
|
+
_("Percepción"),
|
|
1001
|
+
validators=[Optional()],
|
|
1002
|
+
coerce=str,
|
|
1003
|
+
description=_("Percepción a la que se asocia la novedad (si aplica)"),
|
|
1004
|
+
)
|
|
1005
|
+
deduccion_id = SelectField(
|
|
1006
|
+
_("Deducción"),
|
|
1007
|
+
validators=[Optional()],
|
|
1008
|
+
coerce=str,
|
|
1009
|
+
description=_("Deducción a la que se asocia la novedad (si aplica)"),
|
|
1010
|
+
)
|
|
1011
|
+
codigo_concepto = StringField(
|
|
1012
|
+
_("Código del Concepto"),
|
|
1013
|
+
validators=[DataRequired(), Length(max=50)],
|
|
1014
|
+
description=_("Código del concepto que se modifica o aplica"),
|
|
1015
|
+
)
|
|
1016
|
+
tipo_valor = SelectField(
|
|
1017
|
+
_("Tipo de Valor"),
|
|
1018
|
+
choices=[
|
|
1019
|
+
("monto", _("Monto Fijo")),
|
|
1020
|
+
("horas", _("Horas")),
|
|
1021
|
+
("dias", _("Días")),
|
|
1022
|
+
("cantidad", _("Cantidad")),
|
|
1023
|
+
("porcentaje", _("Porcentaje")),
|
|
1024
|
+
],
|
|
1025
|
+
validators=[DataRequired()],
|
|
1026
|
+
description=_("Tipo de valor de la novedad"),
|
|
1027
|
+
)
|
|
1028
|
+
valor_cantidad = DecimalField(
|
|
1029
|
+
_("Valor / Cantidad"),
|
|
1030
|
+
validators=[DataRequired()],
|
|
1031
|
+
places=2,
|
|
1032
|
+
description=_("Valor numérico de la novedad (ej: 5 horas, 1500 de bono)"),
|
|
1033
|
+
)
|
|
1034
|
+
fecha_novedad = DateField(
|
|
1035
|
+
_("Fecha de la Novedad"),
|
|
1036
|
+
validators=[Optional()],
|
|
1037
|
+
description=_("Fecha en que ocurrió el evento (opcional, para auditoría)"),
|
|
1038
|
+
)
|
|
1039
|
+
|
|
1040
|
+
# ---- Vacation Module Integration Fields ----
|
|
1041
|
+
es_descanso_vacaciones = BooleanField(
|
|
1042
|
+
_("Es Descanso de Vacaciones"),
|
|
1043
|
+
default=False,
|
|
1044
|
+
description=_("Marcar si esta novedad representa vacaciones/descanso del empleado"),
|
|
1045
|
+
)
|
|
1046
|
+
fecha_inicio_descanso = DateField(
|
|
1047
|
+
_("Fecha Inicio Descanso"),
|
|
1048
|
+
validators=[Optional()],
|
|
1049
|
+
description=_("Fecha de inicio del período de vacaciones (si aplica)"),
|
|
1050
|
+
)
|
|
1051
|
+
fecha_fin_descanso = DateField(
|
|
1052
|
+
_("Fecha Fin Descanso"),
|
|
1053
|
+
validators=[Optional()],
|
|
1054
|
+
description=_("Fecha de fin del período de vacaciones (si aplica)"),
|
|
1055
|
+
)
|
|
1056
|
+
|
|
1057
|
+
submit = SubmitField(_("Guardar"))
|
|
1058
|
+
|
|
1059
|
+
|
|
1060
|
+
class PrestamoForm(FlaskForm):
|
|
1061
|
+
"""Form for creating and managing loans and salary advances."""
|
|
1062
|
+
|
|
1063
|
+
empleado_id = SelectField(
|
|
1064
|
+
_("Empleado"),
|
|
1065
|
+
validators=[DataRequired()],
|
|
1066
|
+
coerce=str,
|
|
1067
|
+
description=_("Seleccione el empleado que solicita el préstamo o adelanto"),
|
|
1068
|
+
)
|
|
1069
|
+
tipo = SelectField(
|
|
1070
|
+
_("Tipo"),
|
|
1071
|
+
choices=[
|
|
1072
|
+
("adelanto", _("Adelanto de Salario")),
|
|
1073
|
+
("prestamo", _("Préstamo")),
|
|
1074
|
+
],
|
|
1075
|
+
validators=[DataRequired()],
|
|
1076
|
+
description=_("Adelanto: se descuenta rápidamente; Préstamo: cuotas a largo plazo"),
|
|
1077
|
+
)
|
|
1078
|
+
fecha_solicitud = DateField(
|
|
1079
|
+
_("Fecha de Solicitud"),
|
|
1080
|
+
validators=[DataRequired()],
|
|
1081
|
+
description=_("Fecha en que se realiza la solicitud"),
|
|
1082
|
+
)
|
|
1083
|
+
monto_solicitado = DecimalField(
|
|
1084
|
+
_("Monto Solicitado"),
|
|
1085
|
+
validators=[DataRequired(), NumberRange(min=0.01)],
|
|
1086
|
+
places=2,
|
|
1087
|
+
description=_("Monto que solicita el empleado"),
|
|
1088
|
+
)
|
|
1089
|
+
moneda_id = SelectField(
|
|
1090
|
+
_("Moneda"),
|
|
1091
|
+
validators=[DataRequired()],
|
|
1092
|
+
coerce=str,
|
|
1093
|
+
description=_("Moneda del préstamo (puede ser diferente a la de la planilla)"),
|
|
1094
|
+
)
|
|
1095
|
+
cuotas_pactadas = IntegerField(
|
|
1096
|
+
_("Número de Cuotas"),
|
|
1097
|
+
validators=[DataRequired(), NumberRange(min=1)],
|
|
1098
|
+
description=_("Número de cuotas (nóminas) para pagar el préstamo"),
|
|
1099
|
+
)
|
|
1100
|
+
tasa_interes = DecimalField(
|
|
1101
|
+
_("Tasa de Interés (%)"),
|
|
1102
|
+
validators=[Optional(), NumberRange(min=0, max=100)],
|
|
1103
|
+
places=4,
|
|
1104
|
+
default=0,
|
|
1105
|
+
description=_("Tasa de interés anual (ej: 5.0000 para 5%)"),
|
|
1106
|
+
)
|
|
1107
|
+
tipo_interes = SelectField(
|
|
1108
|
+
_("Tipo de Interés"),
|
|
1109
|
+
choices=[
|
|
1110
|
+
("ninguno", _("Sin Interés")),
|
|
1111
|
+
("simple", _("Interés Simple")),
|
|
1112
|
+
("compuesto", _("Interés Compuesto")),
|
|
1113
|
+
],
|
|
1114
|
+
validators=[Optional()],
|
|
1115
|
+
default="ninguno",
|
|
1116
|
+
description=_("Tipo de cálculo de interés"),
|
|
1117
|
+
)
|
|
1118
|
+
metodo_amortizacion = SelectField(
|
|
1119
|
+
_("Método de Amortización"),
|
|
1120
|
+
choices=[
|
|
1121
|
+
("frances", _("Francés - Cuota Constante")),
|
|
1122
|
+
("aleman", _("Alemán - Amortización Constante")),
|
|
1123
|
+
],
|
|
1124
|
+
validators=[Optional()],
|
|
1125
|
+
default="frances",
|
|
1126
|
+
description=_("Método para calcular las cuotas (solo aplica si hay interés)"),
|
|
1127
|
+
)
|
|
1128
|
+
cuenta_debe = StringField(
|
|
1129
|
+
_("Cuenta Contable Débito"),
|
|
1130
|
+
validators=[Optional(), Length(max=64)],
|
|
1131
|
+
description=_("Cuenta contable para el débito del desembolso"),
|
|
1132
|
+
)
|
|
1133
|
+
cuenta_haber = StringField(
|
|
1134
|
+
_("Cuenta Contable Crédito"),
|
|
1135
|
+
validators=[Optional(), Length(max=64)],
|
|
1136
|
+
description=_("Cuenta contable para el crédito del desembolso"),
|
|
1137
|
+
)
|
|
1138
|
+
deduccion_id = SelectField(
|
|
1139
|
+
_("Deducción Asociada"),
|
|
1140
|
+
validators=[Optional()],
|
|
1141
|
+
coerce=str,
|
|
1142
|
+
description=_("Deducción para aplicar en nómina (opcional para adelantos)"),
|
|
1143
|
+
)
|
|
1144
|
+
motivo = StringField(
|
|
1145
|
+
_("Motivo"),
|
|
1146
|
+
validators=[Optional(), Length(max=500)],
|
|
1147
|
+
description=_("Motivo o razón del préstamo"),
|
|
1148
|
+
)
|
|
1149
|
+
submit = SubmitField(_("Guardar"))
|
|
1150
|
+
|
|
1151
|
+
|
|
1152
|
+
class PrestamoApprovalForm(FlaskForm):
|
|
1153
|
+
"""Form for approving or rejecting a loan."""
|
|
1154
|
+
|
|
1155
|
+
monto_aprobado = DecimalField(
|
|
1156
|
+
_("Monto Aprobado"),
|
|
1157
|
+
validators=[DataRequired(), NumberRange(min=0.01)],
|
|
1158
|
+
places=2,
|
|
1159
|
+
description=_("Monto aprobado (puede ser diferente al solicitado)"),
|
|
1160
|
+
)
|
|
1161
|
+
fecha_aprobacion = DateField(
|
|
1162
|
+
_("Fecha de Aprobación"),
|
|
1163
|
+
validators=[DataRequired()],
|
|
1164
|
+
description=_("Fecha de aprobación del préstamo"),
|
|
1165
|
+
)
|
|
1166
|
+
fecha_desembolso = DateField(
|
|
1167
|
+
_("Fecha de Desembolso"),
|
|
1168
|
+
validators=[Optional()],
|
|
1169
|
+
description=_("Fecha en que se realizó el pago al empleado"),
|
|
1170
|
+
)
|
|
1171
|
+
monto_por_cuota = DecimalField(
|
|
1172
|
+
_("Monto por Cuota"),
|
|
1173
|
+
validators=[Optional(), NumberRange(min=0)],
|
|
1174
|
+
places=2,
|
|
1175
|
+
description=_("Monto a deducir por cada cuota (se calcula automáticamente)"),
|
|
1176
|
+
)
|
|
1177
|
+
aprobar = SubmitField(_("Aprobar"))
|
|
1178
|
+
rechazar = SubmitField(_("Rechazar"))
|
|
1179
|
+
motivo_rechazo = StringField(
|
|
1180
|
+
_("Motivo de Rechazo"),
|
|
1181
|
+
validators=[Optional(), Length(max=500)],
|
|
1182
|
+
description=_("Razón del rechazo (requerido si se rechaza)"),
|
|
1183
|
+
)
|
|
1184
|
+
|
|
1185
|
+
|
|
1186
|
+
class CondonacionForm(FlaskForm):
|
|
1187
|
+
"""Form for loan forgiveness/write-off (condonación de deuda)."""
|
|
1188
|
+
|
|
1189
|
+
fecha_condonacion = DateField(
|
|
1190
|
+
_("Fecha de Condonación"),
|
|
1191
|
+
validators=[DataRequired()],
|
|
1192
|
+
description=_("Fecha en que se autoriza la condonación"),
|
|
1193
|
+
)
|
|
1194
|
+
monto_condonado = DecimalField(
|
|
1195
|
+
_("Monto a Condonar"),
|
|
1196
|
+
validators=[DataRequired(), NumberRange(min=0.01)],
|
|
1197
|
+
places=2,
|
|
1198
|
+
description=_("Monto del saldo que se perdona al empleado"),
|
|
1199
|
+
)
|
|
1200
|
+
porcentaje_condonado = DecimalField(
|
|
1201
|
+
_("Porcentaje a Condonar (%)"),
|
|
1202
|
+
validators=[Optional(), NumberRange(min=0, max=100)],
|
|
1203
|
+
places=2,
|
|
1204
|
+
description=_("Porcentaje del saldo a condonar (opcional, para referencia)"),
|
|
1205
|
+
)
|
|
1206
|
+
autorizado_por = StringField(
|
|
1207
|
+
_("Autorizado Por"),
|
|
1208
|
+
validators=[DataRequired(), Length(max=150)],
|
|
1209
|
+
description=_("Nombre/cargo de quien autoriza la condonación"),
|
|
1210
|
+
)
|
|
1211
|
+
documento_soporte = SelectField(
|
|
1212
|
+
_("Tipo de Documento Soporte"),
|
|
1213
|
+
choices=[
|
|
1214
|
+
("correo", _("Correo Electrónico")),
|
|
1215
|
+
("memorandum", _("Memorándum")),
|
|
1216
|
+
("acta", _("Acta de Junta")),
|
|
1217
|
+
("resolucion", _("Resolución Administrativa")),
|
|
1218
|
+
("carta", _("Carta Formal")),
|
|
1219
|
+
("otro", _("Otro")),
|
|
1220
|
+
],
|
|
1221
|
+
validators=[DataRequired()],
|
|
1222
|
+
description=_("Tipo de documento que autoriza la condonación"),
|
|
1223
|
+
)
|
|
1224
|
+
referencia_documento = StringField(
|
|
1225
|
+
_("Referencia del Documento"),
|
|
1226
|
+
validators=[DataRequired(), Length(max=200)],
|
|
1227
|
+
description=_("Número, fecha u otra referencia del documento de autorización"),
|
|
1228
|
+
)
|
|
1229
|
+
justificacion = StringField(
|
|
1230
|
+
_("Justificación Completa"),
|
|
1231
|
+
validators=[DataRequired(), Length(min=20, max=1000)],
|
|
1232
|
+
description=_("Descripción detallada de la razón y autorización de la condonación"),
|
|
1233
|
+
)
|
|
1234
|
+
# Optional accounting fields
|
|
1235
|
+
cuenta_debe = StringField(
|
|
1236
|
+
_("Cuenta Contable Débito"),
|
|
1237
|
+
validators=[Optional(), Length(max=64)],
|
|
1238
|
+
description=_("Cuenta contable para el débito (opcional)"),
|
|
1239
|
+
)
|
|
1240
|
+
cuenta_haber = StringField(
|
|
1241
|
+
_("Cuenta Contable Crédito"),
|
|
1242
|
+
validators=[Optional(), Length(max=64)],
|
|
1243
|
+
description=_("Cuenta contable para el crédito (opcional)"),
|
|
1244
|
+
)
|
|
1245
|
+
submit = SubmitField(_("Condonar Deuda"))
|
|
1246
|
+
|
|
1247
|
+
|
|
1248
|
+
class PagoExtraordinarioForm(FlaskForm):
|
|
1249
|
+
"""Form for recording extraordinary/manual loan payments."""
|
|
1250
|
+
|
|
1251
|
+
fecha_abono = DateField(
|
|
1252
|
+
_("Fecha de Pago"),
|
|
1253
|
+
validators=[DataRequired()],
|
|
1254
|
+
description=_("Fecha en que se realiza el pago extraordinario"),
|
|
1255
|
+
)
|
|
1256
|
+
monto_abonado = DecimalField(
|
|
1257
|
+
_("Monto del Pago"),
|
|
1258
|
+
validators=[DataRequired(), NumberRange(min=0.01)],
|
|
1259
|
+
places=2,
|
|
1260
|
+
description=_("Monto del pago extraordinario"),
|
|
1261
|
+
)
|
|
1262
|
+
tipo_aplicacion = SelectField(
|
|
1263
|
+
_("Aplicación del Pago"),
|
|
1264
|
+
choices=[
|
|
1265
|
+
(
|
|
1266
|
+
"reducir_cuotas",
|
|
1267
|
+
_("Reducir número de cuotas (mantener monto por cuota)"),
|
|
1268
|
+
),
|
|
1269
|
+
("reducir_monto", _("Reducir monto de cuotas (mantener número de cuotas)")),
|
|
1270
|
+
],
|
|
1271
|
+
validators=[DataRequired()],
|
|
1272
|
+
description=_("Cómo aplicar el pago extraordinario según la ley"),
|
|
1273
|
+
)
|
|
1274
|
+
# Audit trail fields
|
|
1275
|
+
tipo_comprobante = SelectField(
|
|
1276
|
+
_("Tipo de Comprobante"),
|
|
1277
|
+
choices=[
|
|
1278
|
+
("recibo_caja", _("Recibo Oficial de Caja")),
|
|
1279
|
+
("minuta_deposito", _("Minuta Bancaria de Depósito")),
|
|
1280
|
+
("transferencia", _("Transferencia Bancaria")),
|
|
1281
|
+
("cheque", _("Cheque")),
|
|
1282
|
+
("otro", _("Otro")),
|
|
1283
|
+
],
|
|
1284
|
+
validators=[DataRequired()],
|
|
1285
|
+
description=_("Tipo de documento que respalda el pago"),
|
|
1286
|
+
)
|
|
1287
|
+
numero_comprobante = StringField(
|
|
1288
|
+
_("Número de Comprobante"),
|
|
1289
|
+
validators=[DataRequired(), Length(max=100)],
|
|
1290
|
+
description=_("Número de recibo, minuta, transferencia o cheque"),
|
|
1291
|
+
)
|
|
1292
|
+
referencia_bancaria = StringField(
|
|
1293
|
+
_("Referencia Bancaria"),
|
|
1294
|
+
validators=[Optional(), Length(max=100)],
|
|
1295
|
+
description=_("Número de referencia bancaria o autorización (opcional)"),
|
|
1296
|
+
)
|
|
1297
|
+
observaciones = StringField(
|
|
1298
|
+
_("Observaciones"),
|
|
1299
|
+
validators=[Optional(), Length(max=500)],
|
|
1300
|
+
description=_("Notas adicionales sobre este pago"),
|
|
1301
|
+
)
|
|
1302
|
+
# Optional accounting fields
|
|
1303
|
+
cuenta_debe = StringField(
|
|
1304
|
+
_("Cuenta Contable Débito"),
|
|
1305
|
+
validators=[Optional(), Length(max=64)],
|
|
1306
|
+
description=_("Cuenta contable para el débito (opcional)"),
|
|
1307
|
+
)
|
|
1308
|
+
cuenta_haber = StringField(
|
|
1309
|
+
_("Cuenta Contable Crédito"),
|
|
1310
|
+
validators=[Optional(), Length(max=64)],
|
|
1311
|
+
description=_("Cuenta contable para el crédito (opcional)"),
|
|
1312
|
+
)
|
|
1313
|
+
submit = SubmitField(_("Registrar Pago"))
|
|
1314
|
+
|
|
1315
|
+
|
|
1316
|
+
class EmpresaForm(FlaskForm):
|
|
1317
|
+
"""Form for creating and editing companies/entities."""
|
|
1318
|
+
|
|
1319
|
+
codigo = StringField(
|
|
1320
|
+
_("Código"),
|
|
1321
|
+
validators=[DataRequired(), Length(max=50)],
|
|
1322
|
+
description=_("Código único de la empresa"),
|
|
1323
|
+
)
|
|
1324
|
+
razon_social = StringField(
|
|
1325
|
+
_("Razón Social"),
|
|
1326
|
+
validators=[DataRequired(), Length(max=200)],
|
|
1327
|
+
description=_("Nombre legal de la empresa"),
|
|
1328
|
+
)
|
|
1329
|
+
nombre_comercial = StringField(
|
|
1330
|
+
_("Nombre Comercial"),
|
|
1331
|
+
validators=[Optional(), Length(max=200)],
|
|
1332
|
+
description=_("Nombre comercial (opcional)"),
|
|
1333
|
+
)
|
|
1334
|
+
ruc = StringField(
|
|
1335
|
+
_("RUC"),
|
|
1336
|
+
validators=[DataRequired(), Length(max=50)],
|
|
1337
|
+
description=_("Número de identificación fiscal"),
|
|
1338
|
+
)
|
|
1339
|
+
direccion = StringField(
|
|
1340
|
+
_("Dirección"),
|
|
1341
|
+
validators=[Optional(), Length(max=255)],
|
|
1342
|
+
)
|
|
1343
|
+
telefono = StringField(
|
|
1344
|
+
_("Teléfono"),
|
|
1345
|
+
validators=[Optional(), Length(max=50)],
|
|
1346
|
+
)
|
|
1347
|
+
correo = StringField(
|
|
1348
|
+
_("Correo Electrónico"),
|
|
1349
|
+
validators=[Optional(), Email(), Length(max=150)],
|
|
1350
|
+
)
|
|
1351
|
+
sitio_web = StringField(
|
|
1352
|
+
_("Sitio Web"),
|
|
1353
|
+
validators=[Optional(), Length(max=200)],
|
|
1354
|
+
)
|
|
1355
|
+
representante_legal = StringField(
|
|
1356
|
+
_("Representante Legal"),
|
|
1357
|
+
validators=[Optional(), Length(max=150)],
|
|
1358
|
+
)
|
|
1359
|
+
activo = BooleanField(_("Activo"), default=True)
|
|
1360
|
+
submit = SubmitField(_("Guardar"))
|
|
1361
|
+
|
|
1362
|
+
|
|
1363
|
+
class CargaInicialPrestacionForm(FlaskForm):
|
|
1364
|
+
"""Form for initial benefit balance loading.
|
|
1365
|
+
|
|
1366
|
+
Used when implementing the system to load existing accumulated balances
|
|
1367
|
+
for employees. Supports draft and applied states.
|
|
1368
|
+
"""
|
|
1369
|
+
|
|
1370
|
+
empleado_id = SelectField(
|
|
1371
|
+
_("Empleado"),
|
|
1372
|
+
validators=[DataRequired()],
|
|
1373
|
+
coerce=str,
|
|
1374
|
+
description=_("Seleccione el empleado"),
|
|
1375
|
+
)
|
|
1376
|
+
prestacion_id = SelectField(
|
|
1377
|
+
_("Prestación"),
|
|
1378
|
+
validators=[DataRequired()],
|
|
1379
|
+
coerce=str,
|
|
1380
|
+
description=_("Seleccione la prestación laboral"),
|
|
1381
|
+
)
|
|
1382
|
+
anio_corte = IntegerField(
|
|
1383
|
+
_("Año de Corte"),
|
|
1384
|
+
validators=[DataRequired(), NumberRange(min=1900, max=2100)],
|
|
1385
|
+
description=_("Año del corte del saldo"),
|
|
1386
|
+
)
|
|
1387
|
+
mes_corte = SelectField(
|
|
1388
|
+
_("Mes de Corte"),
|
|
1389
|
+
validators=[DataRequired()],
|
|
1390
|
+
coerce=int,
|
|
1391
|
+
choices=[
|
|
1392
|
+
(1, _("Enero")),
|
|
1393
|
+
(2, _("Febrero")),
|
|
1394
|
+
(3, _("Marzo")),
|
|
1395
|
+
(4, _("Abril")),
|
|
1396
|
+
(5, _("Mayo")),
|
|
1397
|
+
(6, _("Junio")),
|
|
1398
|
+
(7, _("Julio")),
|
|
1399
|
+
(8, _("Agosto")),
|
|
1400
|
+
(9, _("Septiembre")),
|
|
1401
|
+
(10, _("Octubre")),
|
|
1402
|
+
(11, _("Noviembre")),
|
|
1403
|
+
(12, _("Diciembre")),
|
|
1404
|
+
],
|
|
1405
|
+
description=_("Mes del corte del saldo"),
|
|
1406
|
+
)
|
|
1407
|
+
moneda_id = SelectField(
|
|
1408
|
+
_("Moneda"),
|
|
1409
|
+
validators=[DataRequired()],
|
|
1410
|
+
coerce=str,
|
|
1411
|
+
description=_("Moneda del saldo"),
|
|
1412
|
+
)
|
|
1413
|
+
saldo_acumulado = DecimalField(
|
|
1414
|
+
_("Saldo Acumulado"),
|
|
1415
|
+
validators=[DataRequired(), NumberRange(min=0)],
|
|
1416
|
+
description=_("Saldo acumulado a la fecha de corte"),
|
|
1417
|
+
)
|
|
1418
|
+
tipo_cambio = DecimalField(
|
|
1419
|
+
_("Tipo de Cambio"),
|
|
1420
|
+
validators=[Optional(), NumberRange(min=0)],
|
|
1421
|
+
default=Decimal("1.0"),
|
|
1422
|
+
description=_("Tipo de cambio para conversión (opcional)"),
|
|
1423
|
+
)
|
|
1424
|
+
saldo_convertido = DecimalField(
|
|
1425
|
+
_("Saldo Convertido"),
|
|
1426
|
+
validators=[Optional(), NumberRange(min=0)],
|
|
1427
|
+
description=_("Saldo convertido con el tipo de cambio propuesto"),
|
|
1428
|
+
)
|
|
1429
|
+
observaciones = StringField(
|
|
1430
|
+
_("Observaciones"),
|
|
1431
|
+
validators=[Optional(), Length(max=500)],
|
|
1432
|
+
description=_("Notas adicionales sobre esta carga inicial"),
|
|
1433
|
+
)
|
|
1434
|
+
submit = SubmitField(_("Guardar"))
|
|
1435
|
+
|
|
1436
|
+
|
|
1437
|
+
# ============================================================================
|
|
1438
|
+
# Vacation Module Forms
|
|
1439
|
+
# ============================================================================
|
|
1440
|
+
|
|
1441
|
+
|
|
1442
|
+
class VacationPolicyForm(FlaskForm):
|
|
1443
|
+
"""Form for creating and editing vacation policies."""
|
|
1444
|
+
|
|
1445
|
+
codigo = StringField(
|
|
1446
|
+
_("Código"),
|
|
1447
|
+
validators=[DataRequired(), Length(max=50)],
|
|
1448
|
+
description=_("Código único de la política"),
|
|
1449
|
+
)
|
|
1450
|
+
nombre = StringField(
|
|
1451
|
+
_("Nombre"),
|
|
1452
|
+
validators=[DataRequired(), Length(max=200)],
|
|
1453
|
+
description=_("Nombre descriptivo de la política"),
|
|
1454
|
+
)
|
|
1455
|
+
descripcion = StringField(
|
|
1456
|
+
_("Descripción"),
|
|
1457
|
+
validators=[Optional(), Length(max=500)],
|
|
1458
|
+
description=_("Descripción detallada de la política"),
|
|
1459
|
+
)
|
|
1460
|
+
planilla_id = SelectField(
|
|
1461
|
+
_("Planilla (Nómina)"),
|
|
1462
|
+
validators=[Optional()],
|
|
1463
|
+
coerce=str,
|
|
1464
|
+
description=_("Planilla a la que aplica esta política (recomendado para políticas específicas por país)"),
|
|
1465
|
+
)
|
|
1466
|
+
empresa_id = SelectField(
|
|
1467
|
+
_("Empresa"),
|
|
1468
|
+
validators=[Optional()],
|
|
1469
|
+
coerce=str,
|
|
1470
|
+
description=_("Empresa a la que aplica esta política (opcional, para políticas globales)"),
|
|
1471
|
+
)
|
|
1472
|
+
activo = BooleanField(_("Activo"), default=True)
|
|
1473
|
+
|
|
1474
|
+
# Accrual configuration
|
|
1475
|
+
accrual_method = SelectField(
|
|
1476
|
+
_("Método de Acumulación"),
|
|
1477
|
+
choices=[
|
|
1478
|
+
("periodic", _("Periódico")),
|
|
1479
|
+
("proportional", _("Proporcional")),
|
|
1480
|
+
("seniority", _("Por Antigüedad")),
|
|
1481
|
+
],
|
|
1482
|
+
validators=[DataRequired()],
|
|
1483
|
+
description=_("Cómo se acumulan las vacaciones"),
|
|
1484
|
+
)
|
|
1485
|
+
accrual_rate = DecimalField(
|
|
1486
|
+
_("Tasa de Acumulación"),
|
|
1487
|
+
validators=[DataRequired(), NumberRange(min=0)],
|
|
1488
|
+
default=Decimal("0.0"),
|
|
1489
|
+
description=_("Cantidad acumulada por período"),
|
|
1490
|
+
)
|
|
1491
|
+
accrual_frequency = SelectField(
|
|
1492
|
+
_("Frecuencia de Acumulación"),
|
|
1493
|
+
choices=[
|
|
1494
|
+
("monthly", _("Mensual")),
|
|
1495
|
+
("biweekly", _("Quincenal")),
|
|
1496
|
+
("annual", _("Anual")),
|
|
1497
|
+
],
|
|
1498
|
+
validators=[DataRequired()],
|
|
1499
|
+
description=_("Con qué frecuencia se acumula"),
|
|
1500
|
+
)
|
|
1501
|
+
accrual_basis = SelectField(
|
|
1502
|
+
_("Base de Acumulación"),
|
|
1503
|
+
choices=[
|
|
1504
|
+
("", _("N/A")),
|
|
1505
|
+
("days_worked", _("Días Trabajados")),
|
|
1506
|
+
("hours_worked", _("Horas Trabajadas")),
|
|
1507
|
+
],
|
|
1508
|
+
validators=[Optional()],
|
|
1509
|
+
description=_("Base para cálculo proporcional (opcional)"),
|
|
1510
|
+
)
|
|
1511
|
+
min_service_days = IntegerField(
|
|
1512
|
+
_("Días Mínimos de Servicio"),
|
|
1513
|
+
validators=[DataRequired(), NumberRange(min=0)],
|
|
1514
|
+
default=0,
|
|
1515
|
+
description=_("Días de servicio antes de comenzar a acumular"),
|
|
1516
|
+
)
|
|
1517
|
+
|
|
1518
|
+
# Balance limits
|
|
1519
|
+
max_balance = DecimalField(
|
|
1520
|
+
_("Balance Máximo"),
|
|
1521
|
+
validators=[Optional(), NumberRange(min=0)],
|
|
1522
|
+
description=_("Balance máximo permitido (opcional)"),
|
|
1523
|
+
)
|
|
1524
|
+
carryover_limit = DecimalField(
|
|
1525
|
+
_("Límite de Traspaso"),
|
|
1526
|
+
validators=[Optional(), NumberRange(min=0)],
|
|
1527
|
+
description=_("Máximo que puede traspasar al siguiente período (opcional)"),
|
|
1528
|
+
)
|
|
1529
|
+
allow_negative = BooleanField(
|
|
1530
|
+
_("Permitir Balance Negativo"),
|
|
1531
|
+
default=False,
|
|
1532
|
+
description=_("Permitir adelanto de vacaciones"),
|
|
1533
|
+
)
|
|
1534
|
+
|
|
1535
|
+
# Expiration rules
|
|
1536
|
+
expiration_rule = SelectField(
|
|
1537
|
+
_("Regla de Vencimiento"),
|
|
1538
|
+
choices=[
|
|
1539
|
+
("never", _("Nunca")),
|
|
1540
|
+
("fiscal_year_end", _("Fin de Año Fiscal")),
|
|
1541
|
+
("anniversary", _("Aniversario")),
|
|
1542
|
+
("custom_date", _("Fecha Personalizada")),
|
|
1543
|
+
],
|
|
1544
|
+
validators=[DataRequired()],
|
|
1545
|
+
description=_("Cuándo vencen las vacaciones no usadas"),
|
|
1546
|
+
)
|
|
1547
|
+
expiration_months = IntegerField(
|
|
1548
|
+
_("Meses para Vencimiento"),
|
|
1549
|
+
validators=[Optional(), NumberRange(min=0)],
|
|
1550
|
+
description=_("Meses después del acumulación antes de vencer (opcional)"),
|
|
1551
|
+
)
|
|
1552
|
+
expiration_date = DateField(
|
|
1553
|
+
_("Fecha de Vencimiento"),
|
|
1554
|
+
validators=[Optional()],
|
|
1555
|
+
description=_("Fecha personalizada de vencimiento (opcional)"),
|
|
1556
|
+
)
|
|
1557
|
+
|
|
1558
|
+
# Termination rules
|
|
1559
|
+
payout_on_termination = BooleanField(
|
|
1560
|
+
_("Pagar al Terminar"),
|
|
1561
|
+
default=True,
|
|
1562
|
+
description=_("Pagar vacaciones no usadas al terminar relación laboral"),
|
|
1563
|
+
)
|
|
1564
|
+
|
|
1565
|
+
# Usage configuration
|
|
1566
|
+
unit_type = SelectField(
|
|
1567
|
+
_("Tipo de Unidad"),
|
|
1568
|
+
choices=[
|
|
1569
|
+
("days", _("Días")),
|
|
1570
|
+
("hours", _("Horas")),
|
|
1571
|
+
],
|
|
1572
|
+
validators=[DataRequired()],
|
|
1573
|
+
description=_("Unidad para medir vacaciones"),
|
|
1574
|
+
)
|
|
1575
|
+
count_weekends = BooleanField(
|
|
1576
|
+
_("Contar Fines de Semana"),
|
|
1577
|
+
default=True,
|
|
1578
|
+
description=_("Incluir fines de semana al calcular días de vacaciones"),
|
|
1579
|
+
)
|
|
1580
|
+
count_holidays = BooleanField(
|
|
1581
|
+
_("Contar Feriados"),
|
|
1582
|
+
default=True,
|
|
1583
|
+
description=_("Incluir feriados al calcular días de vacaciones"),
|
|
1584
|
+
)
|
|
1585
|
+
partial_units_allowed = BooleanField(
|
|
1586
|
+
_("Permitir Unidades Parciales"),
|
|
1587
|
+
default=False,
|
|
1588
|
+
description=_("Permitir fracciones de días/horas"),
|
|
1589
|
+
)
|
|
1590
|
+
rounding_rule = SelectField(
|
|
1591
|
+
_("Regla de Redondeo"),
|
|
1592
|
+
choices=[
|
|
1593
|
+
("nearest", _("Más Cercano")),
|
|
1594
|
+
("up", _("Hacia Arriba")),
|
|
1595
|
+
("down", _("Hacia Abajo")),
|
|
1596
|
+
],
|
|
1597
|
+
validators=[Optional()],
|
|
1598
|
+
description=_("Cómo redondear unidades parciales"),
|
|
1599
|
+
)
|
|
1600
|
+
accrue_during_leave = BooleanField(
|
|
1601
|
+
_("Acumular Durante Vacaciones"),
|
|
1602
|
+
default=True,
|
|
1603
|
+
description=_("Continuar acumulando durante período de vacaciones"),
|
|
1604
|
+
)
|
|
1605
|
+
|
|
1606
|
+
submit = SubmitField(_("Guardar"))
|
|
1607
|
+
|
|
1608
|
+
|
|
1609
|
+
class VacationAccountForm(FlaskForm):
|
|
1610
|
+
"""Form for creating vacation accounts."""
|
|
1611
|
+
|
|
1612
|
+
empleado_id = SelectField(
|
|
1613
|
+
_("Empleado"),
|
|
1614
|
+
validators=[DataRequired()],
|
|
1615
|
+
coerce=str,
|
|
1616
|
+
description=_("Empleado al que pertenece esta cuenta"),
|
|
1617
|
+
)
|
|
1618
|
+
policy_id = SelectField(
|
|
1619
|
+
_("Política de Vacaciones"),
|
|
1620
|
+
validators=[DataRequired()],
|
|
1621
|
+
coerce=str,
|
|
1622
|
+
description=_("Política que rige esta cuenta"),
|
|
1623
|
+
)
|
|
1624
|
+
current_balance = DecimalField(
|
|
1625
|
+
_("Balance Inicial"),
|
|
1626
|
+
validators=[DataRequired(), NumberRange(min=0)],
|
|
1627
|
+
default=Decimal("0.0"),
|
|
1628
|
+
description=_("Balance inicial de vacaciones"),
|
|
1629
|
+
)
|
|
1630
|
+
activo = BooleanField(_("Activo"), default=True)
|
|
1631
|
+
|
|
1632
|
+
submit = SubmitField(_("Guardar"))
|
|
1633
|
+
|
|
1634
|
+
|
|
1635
|
+
class VacationLeaveRequestForm(FlaskForm):
|
|
1636
|
+
"""Form for creating vacation leave requests."""
|
|
1637
|
+
|
|
1638
|
+
empleado_id = SelectField(
|
|
1639
|
+
_("Empleado"),
|
|
1640
|
+
validators=[DataRequired()],
|
|
1641
|
+
coerce=str,
|
|
1642
|
+
description=_("Empleado que solicita las vacaciones"),
|
|
1643
|
+
)
|
|
1644
|
+
start_date = DateField(
|
|
1645
|
+
_("Fecha de Inicio"),
|
|
1646
|
+
validators=[DataRequired()],
|
|
1647
|
+
description=_("Primer día de vacaciones (inicio del período de descanso)"),
|
|
1648
|
+
)
|
|
1649
|
+
end_date = DateField(
|
|
1650
|
+
_("Fecha de Fin"),
|
|
1651
|
+
validators=[DataRequired()],
|
|
1652
|
+
description=_("Último día de vacaciones (fin del período de descanso)"),
|
|
1653
|
+
)
|
|
1654
|
+
units = DecimalField(
|
|
1655
|
+
_("Días/Horas de Vacaciones a Descontar"),
|
|
1656
|
+
validators=[DataRequired(), NumberRange(min=0)],
|
|
1657
|
+
description=_("IMPORTANTE: Días u horas reales a descontar del saldo acumulado de vacaciones."),
|
|
1658
|
+
)
|
|
1659
|
+
observaciones = StringField(
|
|
1660
|
+
_("Observaciones"),
|
|
1661
|
+
validators=[Optional(), Length(max=500)],
|
|
1662
|
+
description=_("Notas adicionales sobre la solicitud"),
|
|
1663
|
+
)
|
|
1664
|
+
|
|
1665
|
+
submit = SubmitField(_("Solicitar"))
|
|
1666
|
+
|
|
1667
|
+
|
|
1668
|
+
class VacationTakenForm(FlaskForm):
|
|
1669
|
+
"""Form for registering vacation days actually taken (with automatic novelty creation).
|
|
1670
|
+
|
|
1671
|
+
This form is used to register vacation time that has been taken by an employee,
|
|
1672
|
+
automatically creating the vacation record and the associated novelty (NominaNovedad).
|
|
1673
|
+
|
|
1674
|
+
IMPORTANT:
|
|
1675
|
+
- The 'dias_descontados' field represents the actual vacation days to deduct
|
|
1676
|
+
from the employee's balance, which may differ from the calendar days in the date range
|
|
1677
|
+
based on company policy (e.g., taking Friday+Monday = 4 calendar days but only 2 vacation days).
|
|
1678
|
+
- The novelty MUST be associated with a Percepcion or Deduccion for payroll calculations.
|
|
1679
|
+
"""
|
|
1680
|
+
|
|
1681
|
+
empleado_id = SelectField(
|
|
1682
|
+
_("Empleado"),
|
|
1683
|
+
validators=[DataRequired()],
|
|
1684
|
+
coerce=str,
|
|
1685
|
+
description=_("Empleado que tomó las vacaciones"),
|
|
1686
|
+
)
|
|
1687
|
+
fecha_inicio = DateField(
|
|
1688
|
+
_("Fecha Inicio del Descanso"),
|
|
1689
|
+
validators=[DataRequired()],
|
|
1690
|
+
description=_("Primer día del período de descanso (calendario)"),
|
|
1691
|
+
)
|
|
1692
|
+
fecha_fin = DateField(
|
|
1693
|
+
_("Fecha Fin del Descanso"),
|
|
1694
|
+
validators=[DataRequired()],
|
|
1695
|
+
description=_("Último día del período de descanso (calendario)"),
|
|
1696
|
+
)
|
|
1697
|
+
dias_descontados = DecimalField(
|
|
1698
|
+
_("Días/Horas a Descontar del Saldo"),
|
|
1699
|
+
validators=[DataRequired(), NumberRange(min=0.01)],
|
|
1700
|
+
places=2,
|
|
1701
|
+
description=_("CRÍTICO: Días u horas reales a descontar según política (ej: viernes+lunes = 2 días, no 4)"),
|
|
1702
|
+
)
|
|
1703
|
+
|
|
1704
|
+
# Asociación con Percepción o Deducción (REQUERIDO)
|
|
1705
|
+
tipo_concepto = SelectField(
|
|
1706
|
+
_("Tipo de Concepto"),
|
|
1707
|
+
choices=[
|
|
1708
|
+
("deduccion", _("Deducción (Descuento)")),
|
|
1709
|
+
("percepcion", _("Percepción (Pago de Vacaciones)")),
|
|
1710
|
+
],
|
|
1711
|
+
validators=[DataRequired()],
|
|
1712
|
+
description=_("Tipo de concepto al que se asocia la novedad"),
|
|
1713
|
+
)
|
|
1714
|
+
percepcion_id = SelectField(
|
|
1715
|
+
_("Percepción"),
|
|
1716
|
+
validators=[Optional()],
|
|
1717
|
+
coerce=str,
|
|
1718
|
+
description=_("Percepción asociada (si tipo_concepto es percepcion)"),
|
|
1719
|
+
)
|
|
1720
|
+
deduccion_id = SelectField(
|
|
1721
|
+
_("Deducción"),
|
|
1722
|
+
validators=[Optional()],
|
|
1723
|
+
coerce=str,
|
|
1724
|
+
description=_("Deducción asociada (si tipo_concepto es deduccion)"),
|
|
1725
|
+
)
|
|
1726
|
+
|
|
1727
|
+
observaciones = StringField(
|
|
1728
|
+
_("Observaciones"),
|
|
1729
|
+
validators=[Optional(), Length(max=500)],
|
|
1730
|
+
description=_("Notas adicionales"),
|
|
1731
|
+
)
|
|
1732
|
+
|
|
1733
|
+
submit = SubmitField(_("Registrar Vacaciones"))
|
|
1734
|
+
|
|
1735
|
+
|
|
1736
|
+
class VacationInitialBalanceForm(FlaskForm):
|
|
1737
|
+
"""Form for loading initial vacation balance for an employee.
|
|
1738
|
+
|
|
1739
|
+
Used during system implementation to set the initial accumulated vacation
|
|
1740
|
+
balance for employees who already have vacation time earned before the
|
|
1741
|
+
system goes live.
|
|
1742
|
+
|
|
1743
|
+
Creates an ADJUSTMENT ledger entry with the initial balance.
|
|
1744
|
+
"""
|
|
1745
|
+
|
|
1746
|
+
empleado_id = SelectField(
|
|
1747
|
+
_("Empleado"),
|
|
1748
|
+
validators=[DataRequired()],
|
|
1749
|
+
coerce=str,
|
|
1750
|
+
description=_("Empleado para cargar saldo inicial"),
|
|
1751
|
+
)
|
|
1752
|
+
saldo_inicial = DecimalField(
|
|
1753
|
+
_("Saldo Inicial de Vacaciones"),
|
|
1754
|
+
validators=[DataRequired(), NumberRange(min=0)],
|
|
1755
|
+
places=2,
|
|
1756
|
+
description=_("Días u horas de vacaciones acumuladas al momento de implementación"),
|
|
1757
|
+
)
|
|
1758
|
+
fecha_corte = DateField(
|
|
1759
|
+
_("Fecha de Corte"),
|
|
1760
|
+
validators=[DataRequired()],
|
|
1761
|
+
description=_("Fecha a la que corresponde el saldo inicial (típicamente fecha de implementación del sistema)"),
|
|
1762
|
+
)
|
|
1763
|
+
observaciones = StringField(
|
|
1764
|
+
_("Observaciones"),
|
|
1765
|
+
validators=[Optional(), Length(max=500)],
|
|
1766
|
+
description=_("Notas sobre el origen del saldo inicial"),
|
|
1767
|
+
)
|
|
1768
|
+
|
|
1769
|
+
submit = SubmitField(_("Cargar Saldo Inicial"))
|