coati-payroll 0.0.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of coati-payroll might be problematic. Click here for more details.

Files changed (243) hide show
  1. coati_payroll/__init__.py +415 -0
  2. coati_payroll/app.py +95 -0
  3. coati_payroll/audit_helpers.py +904 -0
  4. coati_payroll/auth.py +123 -0
  5. coati_payroll/cli.py +1318 -0
  6. coati_payroll/config.py +219 -0
  7. coati_payroll/demo_data.py +813 -0
  8. coati_payroll/enums.py +278 -0
  9. coati_payroll/forms.py +1769 -0
  10. coati_payroll/formula_engine/__init__.py +81 -0
  11. coati_payroll/formula_engine/ast/__init__.py +110 -0
  12. coati_payroll/formula_engine/ast/ast_visitor.py +259 -0
  13. coati_payroll/formula_engine/ast/expression_evaluator.py +228 -0
  14. coati_payroll/formula_engine/ast/safe_operators.py +131 -0
  15. coati_payroll/formula_engine/ast/type_converter.py +172 -0
  16. coati_payroll/formula_engine/data_sources.py +752 -0
  17. coati_payroll/formula_engine/engine.py +247 -0
  18. coati_payroll/formula_engine/exceptions.py +52 -0
  19. coati_payroll/formula_engine/execution/__init__.py +24 -0
  20. coati_payroll/formula_engine/execution/execution_context.py +52 -0
  21. coati_payroll/formula_engine/execution/step_executor.py +62 -0
  22. coati_payroll/formula_engine/execution/variable_store.py +59 -0
  23. coati_payroll/formula_engine/novelty_codes.py +206 -0
  24. coati_payroll/formula_engine/results/__init__.py +20 -0
  25. coati_payroll/formula_engine/results/execution_result.py +59 -0
  26. coati_payroll/formula_engine/steps/__init__.py +30 -0
  27. coati_payroll/formula_engine/steps/assignment_step.py +71 -0
  28. coati_payroll/formula_engine/steps/base_step.py +48 -0
  29. coati_payroll/formula_engine/steps/calculation_step.py +42 -0
  30. coati_payroll/formula_engine/steps/conditional_step.py +122 -0
  31. coati_payroll/formula_engine/steps/step_factory.py +58 -0
  32. coati_payroll/formula_engine/steps/tax_lookup_step.py +45 -0
  33. coati_payroll/formula_engine/tables/__init__.py +24 -0
  34. coati_payroll/formula_engine/tables/bracket_calculator.py +51 -0
  35. coati_payroll/formula_engine/tables/table_lookup.py +161 -0
  36. coati_payroll/formula_engine/tables/tax_table.py +32 -0
  37. coati_payroll/formula_engine/validation/__init__.py +24 -0
  38. coati_payroll/formula_engine/validation/schema_validator.py +37 -0
  39. coati_payroll/formula_engine/validation/security_validator.py +52 -0
  40. coati_payroll/formula_engine/validation/tax_table_validator.py +205 -0
  41. coati_payroll/formula_engine_examples.py +153 -0
  42. coati_payroll/i18n.py +54 -0
  43. coati_payroll/initial_data.py +613 -0
  44. coati_payroll/interes_engine.py +450 -0
  45. coati_payroll/liquidacion_engine/__init__.py +25 -0
  46. coati_payroll/liquidacion_engine/engine.py +267 -0
  47. coati_payroll/locale_config.py +165 -0
  48. coati_payroll/log.py +138 -0
  49. coati_payroll/model.py +2410 -0
  50. coati_payroll/nomina_engine/__init__.py +87 -0
  51. coati_payroll/nomina_engine/calculators/__init__.py +30 -0
  52. coati_payroll/nomina_engine/calculators/benefit_calculator.py +79 -0
  53. coati_payroll/nomina_engine/calculators/concept_calculator.py +254 -0
  54. coati_payroll/nomina_engine/calculators/deduction_calculator.py +105 -0
  55. coati_payroll/nomina_engine/calculators/exchange_rate_calculator.py +51 -0
  56. coati_payroll/nomina_engine/calculators/perception_calculator.py +75 -0
  57. coati_payroll/nomina_engine/calculators/salary_calculator.py +86 -0
  58. coati_payroll/nomina_engine/domain/__init__.py +27 -0
  59. coati_payroll/nomina_engine/domain/calculation_items.py +52 -0
  60. coati_payroll/nomina_engine/domain/employee_calculation.py +53 -0
  61. coati_payroll/nomina_engine/domain/payroll_context.py +44 -0
  62. coati_payroll/nomina_engine/engine.py +188 -0
  63. coati_payroll/nomina_engine/processors/__init__.py +28 -0
  64. coati_payroll/nomina_engine/processors/accounting_processor.py +171 -0
  65. coati_payroll/nomina_engine/processors/accumulation_processor.py +90 -0
  66. coati_payroll/nomina_engine/processors/loan_processor.py +227 -0
  67. coati_payroll/nomina_engine/processors/novelty_processor.py +42 -0
  68. coati_payroll/nomina_engine/processors/vacation_processor.py +67 -0
  69. coati_payroll/nomina_engine/repositories/__init__.py +32 -0
  70. coati_payroll/nomina_engine/repositories/acumulado_repository.py +83 -0
  71. coati_payroll/nomina_engine/repositories/base_repository.py +40 -0
  72. coati_payroll/nomina_engine/repositories/config_repository.py +102 -0
  73. coati_payroll/nomina_engine/repositories/employee_repository.py +34 -0
  74. coati_payroll/nomina_engine/repositories/exchange_rate_repository.py +58 -0
  75. coati_payroll/nomina_engine/repositories/novelty_repository.py +54 -0
  76. coati_payroll/nomina_engine/repositories/planilla_repository.py +52 -0
  77. coati_payroll/nomina_engine/results/__init__.py +24 -0
  78. coati_payroll/nomina_engine/results/error_result.py +28 -0
  79. coati_payroll/nomina_engine/results/payroll_result.py +53 -0
  80. coati_payroll/nomina_engine/results/validation_result.py +39 -0
  81. coati_payroll/nomina_engine/services/__init__.py +22 -0
  82. coati_payroll/nomina_engine/services/accounting_voucher_service.py +708 -0
  83. coati_payroll/nomina_engine/services/employee_processing_service.py +173 -0
  84. coati_payroll/nomina_engine/services/payroll_execution_service.py +374 -0
  85. coati_payroll/nomina_engine/services/snapshot_service.py +295 -0
  86. coati_payroll/nomina_engine/validators/__init__.py +31 -0
  87. coati_payroll/nomina_engine/validators/base_validator.py +48 -0
  88. coati_payroll/nomina_engine/validators/currency_validator.py +50 -0
  89. coati_payroll/nomina_engine/validators/employee_validator.py +87 -0
  90. coati_payroll/nomina_engine/validators/period_validator.py +44 -0
  91. coati_payroll/nomina_engine/validators/planilla_validator.py +136 -0
  92. coati_payroll/plugin_manager.py +176 -0
  93. coati_payroll/queue/__init__.py +33 -0
  94. coati_payroll/queue/driver.py +127 -0
  95. coati_payroll/queue/drivers/__init__.py +22 -0
  96. coati_payroll/queue/drivers/dramatiq_driver.py +268 -0
  97. coati_payroll/queue/drivers/huey_driver.py +390 -0
  98. coati_payroll/queue/drivers/noop_driver.py +54 -0
  99. coati_payroll/queue/selector.py +121 -0
  100. coati_payroll/queue/tasks.py +764 -0
  101. coati_payroll/rate_limiting.py +83 -0
  102. coati_payroll/rbac.py +183 -0
  103. coati_payroll/report_engine.py +512 -0
  104. coati_payroll/report_export.py +208 -0
  105. coati_payroll/schema_validator.py +167 -0
  106. coati_payroll/security.py +77 -0
  107. coati_payroll/static/styles.css +1044 -0
  108. coati_payroll/system_reports.py +573 -0
  109. coati_payroll/templates/auth/login.html +189 -0
  110. coati_payroll/templates/base.html +283 -0
  111. coati_payroll/templates/index.html +227 -0
  112. coati_payroll/templates/macros.html +146 -0
  113. coati_payroll/templates/modules/calculation_rule/form.html +78 -0
  114. coati_payroll/templates/modules/calculation_rule/index.html +102 -0
  115. coati_payroll/templates/modules/calculation_rule/schema_editor.html +1159 -0
  116. coati_payroll/templates/modules/carga_inicial_prestacion/form.html +170 -0
  117. coati_payroll/templates/modules/carga_inicial_prestacion/index.html +170 -0
  118. coati_payroll/templates/modules/carga_inicial_prestacion/reporte.html +193 -0
  119. coati_payroll/templates/modules/config_calculos/index.html +44 -0
  120. coati_payroll/templates/modules/configuracion/index.html +90 -0
  121. coati_payroll/templates/modules/currency/form.html +47 -0
  122. coati_payroll/templates/modules/currency/index.html +64 -0
  123. coati_payroll/templates/modules/custom_field/form.html +62 -0
  124. coati_payroll/templates/modules/custom_field/index.html +78 -0
  125. coati_payroll/templates/modules/deduccion/form.html +1 -0
  126. coati_payroll/templates/modules/deduccion/index.html +1 -0
  127. coati_payroll/templates/modules/employee/form.html +254 -0
  128. coati_payroll/templates/modules/employee/index.html +76 -0
  129. coati_payroll/templates/modules/empresa/form.html +74 -0
  130. coati_payroll/templates/modules/empresa/index.html +71 -0
  131. coati_payroll/templates/modules/exchange_rate/form.html +47 -0
  132. coati_payroll/templates/modules/exchange_rate/import.html +93 -0
  133. coati_payroll/templates/modules/exchange_rate/index.html +114 -0
  134. coati_payroll/templates/modules/liquidacion/index.html +58 -0
  135. coati_payroll/templates/modules/liquidacion/nueva.html +51 -0
  136. coati_payroll/templates/modules/liquidacion/ver.html +91 -0
  137. coati_payroll/templates/modules/payroll_concepts/audit_log.html +146 -0
  138. coati_payroll/templates/modules/percepcion/form.html +1 -0
  139. coati_payroll/templates/modules/percepcion/index.html +1 -0
  140. coati_payroll/templates/modules/planilla/config.html +190 -0
  141. coati_payroll/templates/modules/planilla/config_deducciones.html +129 -0
  142. coati_payroll/templates/modules/planilla/config_empleados.html +116 -0
  143. coati_payroll/templates/modules/planilla/config_percepciones.html +113 -0
  144. coati_payroll/templates/modules/planilla/config_prestaciones.html +118 -0
  145. coati_payroll/templates/modules/planilla/config_reglas.html +120 -0
  146. coati_payroll/templates/modules/planilla/ejecutar_nomina.html +106 -0
  147. coati_payroll/templates/modules/planilla/form.html +197 -0
  148. coati_payroll/templates/modules/planilla/index.html +144 -0
  149. coati_payroll/templates/modules/planilla/listar_nominas.html +91 -0
  150. coati_payroll/templates/modules/planilla/log_nomina.html +135 -0
  151. coati_payroll/templates/modules/planilla/novedades/form.html +177 -0
  152. coati_payroll/templates/modules/planilla/novedades/index.html +170 -0
  153. coati_payroll/templates/modules/planilla/ver_nomina.html +477 -0
  154. coati_payroll/templates/modules/planilla/ver_nomina_empleado.html +231 -0
  155. coati_payroll/templates/modules/plugins/index.html +71 -0
  156. coati_payroll/templates/modules/prestacion/form.html +1 -0
  157. coati_payroll/templates/modules/prestacion/index.html +1 -0
  158. coati_payroll/templates/modules/prestacion_management/dashboard.html +150 -0
  159. coati_payroll/templates/modules/prestacion_management/initial_balance_bulk.html +195 -0
  160. coati_payroll/templates/modules/prestamo/approve.html +156 -0
  161. coati_payroll/templates/modules/prestamo/condonacion.html +249 -0
  162. coati_payroll/templates/modules/prestamo/detail.html +443 -0
  163. coati_payroll/templates/modules/prestamo/form.html +203 -0
  164. coati_payroll/templates/modules/prestamo/index.html +150 -0
  165. coati_payroll/templates/modules/prestamo/pago_extraordinario.html +211 -0
  166. coati_payroll/templates/modules/prestamo/tabla_pago_pdf.html +181 -0
  167. coati_payroll/templates/modules/report/admin_index.html +125 -0
  168. coati_payroll/templates/modules/report/detail.html +129 -0
  169. coati_payroll/templates/modules/report/execute.html +266 -0
  170. coati_payroll/templates/modules/report/index.html +95 -0
  171. coati_payroll/templates/modules/report/permissions.html +64 -0
  172. coati_payroll/templates/modules/settings/index.html +274 -0
  173. coati_payroll/templates/modules/shared/concept_form.html +201 -0
  174. coati_payroll/templates/modules/shared/concept_index.html +145 -0
  175. coati_payroll/templates/modules/tipo_planilla/form.html +70 -0
  176. coati_payroll/templates/modules/tipo_planilla/index.html +68 -0
  177. coati_payroll/templates/modules/user/form.html +65 -0
  178. coati_payroll/templates/modules/user/index.html +76 -0
  179. coati_payroll/templates/modules/user/profile.html +81 -0
  180. coati_payroll/templates/modules/vacation/account_detail.html +149 -0
  181. coati_payroll/templates/modules/vacation/account_form.html +52 -0
  182. coati_payroll/templates/modules/vacation/account_index.html +68 -0
  183. coati_payroll/templates/modules/vacation/dashboard.html +156 -0
  184. coati_payroll/templates/modules/vacation/initial_balance_bulk.html +149 -0
  185. coati_payroll/templates/modules/vacation/initial_balance_form.html +93 -0
  186. coati_payroll/templates/modules/vacation/leave_request_detail.html +158 -0
  187. coati_payroll/templates/modules/vacation/leave_request_form.html +61 -0
  188. coati_payroll/templates/modules/vacation/leave_request_index.html +98 -0
  189. coati_payroll/templates/modules/vacation/policy_detail.html +176 -0
  190. coati_payroll/templates/modules/vacation/policy_form.html +152 -0
  191. coati_payroll/templates/modules/vacation/policy_index.html +79 -0
  192. coati_payroll/templates/modules/vacation/register_taken_form.html +178 -0
  193. coati_payroll/translations/en/LC_MESSAGES/messages.mo +0 -0
  194. coati_payroll/translations/en/LC_MESSAGES/messages.po +7283 -0
  195. coati_payroll/translations/es/LC_MESSAGES/messages.mo +0 -0
  196. coati_payroll/translations/es/LC_MESSAGES/messages.po +7374 -0
  197. coati_payroll/vacation_service.py +451 -0
  198. coati_payroll/version.py +18 -0
  199. coati_payroll/vistas/__init__.py +64 -0
  200. coati_payroll/vistas/calculation_rule.py +307 -0
  201. coati_payroll/vistas/carga_inicial_prestacion.py +423 -0
  202. coati_payroll/vistas/config_calculos.py +72 -0
  203. coati_payroll/vistas/configuracion.py +87 -0
  204. coati_payroll/vistas/constants.py +17 -0
  205. coati_payroll/vistas/currency.py +112 -0
  206. coati_payroll/vistas/custom_field.py +120 -0
  207. coati_payroll/vistas/employee.py +305 -0
  208. coati_payroll/vistas/empresa.py +153 -0
  209. coati_payroll/vistas/exchange_rate.py +341 -0
  210. coati_payroll/vistas/liquidacion.py +205 -0
  211. coati_payroll/vistas/payroll_concepts.py +580 -0
  212. coati_payroll/vistas/planilla/__init__.py +38 -0
  213. coati_payroll/vistas/planilla/association_routes.py +238 -0
  214. coati_payroll/vistas/planilla/config_routes.py +158 -0
  215. coati_payroll/vistas/planilla/export_routes.py +175 -0
  216. coati_payroll/vistas/planilla/helpers/__init__.py +34 -0
  217. coati_payroll/vistas/planilla/helpers/association_helpers.py +161 -0
  218. coati_payroll/vistas/planilla/helpers/excel_helpers.py +29 -0
  219. coati_payroll/vistas/planilla/helpers/form_helpers.py +97 -0
  220. coati_payroll/vistas/planilla/nomina_routes.py +488 -0
  221. coati_payroll/vistas/planilla/novedad_routes.py +227 -0
  222. coati_payroll/vistas/planilla/routes.py +145 -0
  223. coati_payroll/vistas/planilla/services/__init__.py +26 -0
  224. coati_payroll/vistas/planilla/services/export_service.py +687 -0
  225. coati_payroll/vistas/planilla/services/nomina_service.py +233 -0
  226. coati_payroll/vistas/planilla/services/novedad_service.py +126 -0
  227. coati_payroll/vistas/planilla/services/planilla_service.py +34 -0
  228. coati_payroll/vistas/planilla/validators/__init__.py +18 -0
  229. coati_payroll/vistas/planilla/validators/planilla_validators.py +40 -0
  230. coati_payroll/vistas/plugins.py +45 -0
  231. coati_payroll/vistas/prestacion.py +272 -0
  232. coati_payroll/vistas/prestamo.py +808 -0
  233. coati_payroll/vistas/report.py +432 -0
  234. coati_payroll/vistas/settings.py +29 -0
  235. coati_payroll/vistas/tipo_planilla.py +134 -0
  236. coati_payroll/vistas/user.py +172 -0
  237. coati_payroll/vistas/vacation.py +1045 -0
  238. coati_payroll-0.0.2.dist-info/LICENSE +201 -0
  239. coati_payroll-0.0.2.dist-info/METADATA +581 -0
  240. coati_payroll-0.0.2.dist-info/RECORD +243 -0
  241. coati_payroll-0.0.2.dist-info/WHEEL +5 -0
  242. coati_payroll-0.0.2.dist-info/entry_points.txt +2 -0
  243. coati_payroll-0.0.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,219 @@
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
+ """Base configuration for the payroll module."""
15
+
16
+ from __future__ import annotations
17
+
18
+ # <-------------------------------------------------------------------------> #
19
+ # Standard library
20
+ # <-------------------------------------------------------------------------> #
21
+ from os import environ, getcwd, path, sys
22
+ from pathlib import Path
23
+ from urllib.parse import parse_qs, urlencode, urlparse, urlunparse
24
+
25
+ # <-------------------------------------------------------------------------> #
26
+ # Third party libraries
27
+ # <-------------------------------------------------------------------------> #
28
+
29
+
30
+ # <-------------------------------------------------------------------------> #
31
+ # Local modules
32
+ # <-------------------------------------------------------------------------> #
33
+ from coati_payroll.log import log
34
+
35
+
36
+ # ---------------------------------------------------------------------------------------
37
+ # Configuration file loading functionality
38
+ # ---------------------------------------------------------------------------------------
39
+ def load_config_from_file() -> dict:
40
+ """
41
+ Busca y carga configuración desde archivo con ConfigObj.
42
+
43
+ Busca en las siguientes ubicaciones en orden:
44
+ 1. /etc/coati-payroll/coati-payroll.conf
45
+ 2. /etc/coati-payroll.conf
46
+ 3. ~/.config/coati-payroll/coati-payroll.conf
47
+ 3. ./coati-payroll.conf
48
+
49
+ Returns:
50
+ dict: Diccionario de configuración, vacío si no se encuentra archivo
51
+ """
52
+ try:
53
+ from configobj import ConfigObj
54
+ except ImportError:
55
+ log.debug("ConfigObj not available, skipping file-based configuration.")
56
+ return {}
57
+
58
+ search_paths = [
59
+ "/etc/coati-payroll/coati-payroll.conf",
60
+ "/etc/coati-payroll.conf",
61
+ path.expanduser("~/.config/coati-payroll/coati-payroll.conf"),
62
+ path.join(getcwd(), "coati-payroll.conf"),
63
+ ]
64
+
65
+ for config_path in search_paths:
66
+ if config_path and path.isfile(config_path):
67
+ try:
68
+ log.info(f"Loading configuration from file: {config_path}")
69
+ config_obj = ConfigObj(config_path, encoding="utf-8")
70
+
71
+ config_dict = dict(config_obj)
72
+
73
+ if "DATABASE_URL" in config_dict:
74
+ config_dict["SQLALCHEMY_DATABASE_URI"] = config_dict["DATABASE_URL"]
75
+
76
+ if "REDIS_URL" in config_dict:
77
+ config_dict["CACHE_REDIS_URL"] = config_dict["REDIS_URL"]
78
+
79
+ return config_dict
80
+
81
+ except Exception as e:
82
+ log.warning(f"Error loading configuration from {config_path}: {e}")
83
+ continue
84
+
85
+ log.trace("No configuration file found in search paths.")
86
+ return {}
87
+
88
+
89
+ # < --------------------------------------------------------------------------------------------- >
90
+ # Configuración central de la aplicación.
91
+ VALORES_TRUE = {*["1", "true", "yes", "on"], *["development", "dev"]}
92
+ DEBUG_VARS = ["DEBUG", "CI", "DEV", "DEVELOPMENT"]
93
+ FRAMEWORK_VARS = ["FLASK_ENV", "DJANGO_DEBUG", "NODE_ENV"]
94
+ GENERIC_VARS = ["ENV", "APP_ENV"]
95
+
96
+ # < --------------------------------------------------------------------------------------------- >
97
+ # Gestión de variables de entorno.
98
+ DESARROLLO = any(
99
+ str(environ.get(var, "")).strip().lower() in VALORES_TRUE for var in [*DEBUG_VARS, *FRAMEWORK_VARS, *GENERIC_VARS]
100
+ )
101
+
102
+ # < --------------------------------------------------------------------------------------------- >
103
+ # Directorios base de la aplicacion
104
+ DIRECTORIO_ACTUAL: Path = Path(path.abspath(path.dirname(__file__)))
105
+ DIRECTORIO_APP: Path = DIRECTORIO_ACTUAL.parent.absolute()
106
+ DIRECTORIO_DESARROLLO: Path = DIRECTORIO_APP
107
+ DIRECTORIO_PLANTILLAS_BASE: str = path.join(DIRECTORIO_ACTUAL, "templates")
108
+ DIRECTORIO_ARCHIVOS_BASE: str = path.join(DIRECTORIO_ACTUAL, "static")
109
+
110
+ # < --------------------------------------------------------------------------------------------- >
111
+ # Directorios personalizados para la aplicación.
112
+ DIRECTORIO_ARCHIVOS = DIRECTORIO_ARCHIVOS_BASE
113
+ DIRECTORIO_PLANTILLAS = DIRECTORIO_PLANTILLAS_BASE
114
+
115
+
116
+ # < --------------------------------------------------------------------------------------------- >
117
+ TESTING = (
118
+ "PYTEST_CURRENT_TEST" in environ
119
+ or "PYTEST_VERSION" in environ
120
+ or "TESTING" in environ
121
+ or hasattr(sys, "_called_from_test")
122
+ or environ.get("CI")
123
+ or "pytest" in sys.modules
124
+ or path.basename(sys.argv[0]) in ["pytest", "py.test"]
125
+ )
126
+
127
+ if TESTING:
128
+ # Use DB in memory for tests to avoid filesystem side-effects
129
+ SQLITE: str = "sqlite:///:memory:"
130
+ else:
131
+ # File-based sqlite in project root
132
+ sqlite_file = DIRECTORIO_DESARROLLO.joinpath("coati_payroll.db")
133
+ SQLITE = f"sqlite:///{sqlite_file.as_posix()}"
134
+
135
+ # < --------------------------------------------------------------------------------------------- >
136
+ # Configuración de la aplicación:
137
+ # Se siguen las recomendaciones de "Twelve Factors App" y las opciones se leen del entorno.
138
+ CONFIGURACION: dict[str, str | bool | Path] = {}
139
+ CONFIGURACION["SECRET_KEY"] = environ.get("SECRET_KEY") or "dev" # nosec
140
+ CONFIGURACION["SQLALCHEMY_DATABASE_URI"] = environ.get("DATABASE_URL") or SQLITE # nosec
141
+ # Opciones comunes de configuración.
142
+ CONFIGURACION["PRESERVE_CONTEXT_ON_EXCEPTION"] = False
143
+
144
+ if DESARROLLO:
145
+ log.warning("Using default configuration.")
146
+ log.info("Default configuration is not recommended for use in production environments.")
147
+ CONFIGURACION["SQLALCHEMY_TRACK_MODIFICATIONS"] = "False"
148
+ CONFIGURACION["TEMPLATES_AUTO_RELOAD"] = True
149
+
150
+ # < --------------------------------------------------------------------------------------------- >
151
+ # Corrige la URI de conexión a la base de datos si el usuario omite el driver apropiado.
152
+
153
+ if DATABASE_URL_BASE := CONFIGURACION.get("SQLALCHEMY_DATABASE_URI"):
154
+
155
+ DATABASE_URL_CORREGIDA = DATABASE_URL_BASE
156
+
157
+ prefix = DATABASE_URL_BASE.split(":", 1)[0] # Extraer prefijo: "postgres", "mysql", etc.
158
+
159
+ # Caso especial: Heroku + PostgreSQL
160
+ if environ.get("DYNO") and prefix in (
161
+ "postgres",
162
+ "postgresql",
163
+ ): # type: ignore[operator]
164
+ parsed = urlparse(DATABASE_URL_BASE) # type: ignore[arg-type]
165
+ query = parse_qs(parsed.query)
166
+ query["sslmode"] = ["require"]
167
+ DATABASE_URL_CORREGIDA = urlunparse(parsed._replace(scheme="postgresql", query=urlencode(query, doseq=True)))
168
+
169
+ else:
170
+ # Corrige el esquema según el prefijo detectado
171
+ match prefix:
172
+ case "postgresql":
173
+ parsed = urlparse(DATABASE_URL_BASE)
174
+ query = parse_qs(parsed.query)
175
+ query.pop("sslmode", None)
176
+ new_query = urlencode(query, doseq=True) if query else ""
177
+ cleaned = urlunparse(parsed._replace(query=new_query))
178
+ DATABASE_URL_CORREGIDA = "postgresql+pg8000" + cleaned[10:]
179
+ case "postgres":
180
+ parsed = urlparse(DATABASE_URL_BASE)
181
+ query = parse_qs(parsed.query)
182
+ query.pop("sslmode", None)
183
+ new_query = urlencode(query, doseq=True) if query else ""
184
+ cleaned = urlunparse(parsed._replace(query=new_query))
185
+ DATABASE_URL_CORREGIDA = "postgresql+pg8000" + cleaned[8:]
186
+ case "mysql":
187
+ DATABASE_URL_CORREGIDA = "mysql+pymysql" + DATABASE_URL_BASE[5:]
188
+ case "mariadb":
189
+ DATABASE_URL_CORREGIDA = "mariadb+mariadbconnector" + DATABASE_URL_BASE[7:]
190
+ case _:
191
+ pass
192
+
193
+ # Actualizar configuración si hubo cambio
194
+ if DATABASE_URL_BASE != DATABASE_URL_CORREGIDA:
195
+ log.info(f"Database URI corrected: {DATABASE_URL_BASE} → {DATABASE_URL_CORREGIDA}")
196
+ CONFIGURACION["SQLALCHEMY_DATABASE_URI"] = DATABASE_URL_CORREGIDA
197
+
198
+ # < --------------------------------------------------------------------------------------------- >
199
+ # Queue configuration for background job processing
200
+ # The system will automatically select between Dramatiq (Redis) and Huey (filesystem)
201
+ # based on REDIS_URL availability
202
+ CONFIGURACION["QUEUE_ENABLED"] = environ.get("QUEUE_ENABLED", "1") in [
203
+ "1",
204
+ "true",
205
+ "True",
206
+ "yes",
207
+ ]
208
+ CONFIGURACION["QUEUE_STORAGE_PATH"] = environ.get("COATI_QUEUE_PATH") # For Huey filesystem
209
+
210
+ # Background payroll processing configuration
211
+ # Threshold for automatic background processing (number of employees)
212
+ # Payrolls with more employees than this threshold will be processed in background
213
+ # Default: 100 employees. Can be adjusted based on system performance:
214
+ # - For systems with complex formulas or slow performance: lower to 50 or 25
215
+ # - For high-performance systems: increase to 200 or 500
216
+ CONFIGURACION["BACKGROUND_PAYROLL_THRESHOLD"] = int(environ.get("BACKGROUND_PAYROLL_THRESHOLD", "100"))
217
+
218
+ # < --------------------------------------------------------------------------------------------- >
219
+ configuration = CONFIGURACION