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,613 @@
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
+ """Initial data for currencies, income concepts, deduction concepts, and payroll types.
15
+
16
+ This module provides default data to be loaded during system initialization.
17
+ All data is jurisdiction-agnostic and uses Flask-Babel for translation support.
18
+ Strings are marked for translation using _() and will be translated based on
19
+ the configured language in the database.
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ # <-------------------------------------------------------------------------> #
25
+ # Standard library
26
+ # <-------------------------------------------------------------------------> #
27
+
28
+ # <-------------------------------------------------------------------------> #
29
+ # Third party libraries
30
+ # <-------------------------------------------------------------------------> #
31
+
32
+ # <-------------------------------------------------------------------------> #
33
+ # Local modules
34
+ # <-------------------------------------------------------------------------> #
35
+ from coati_payroll.i18n import _l as _
36
+
37
+
38
+ # American currencies (North, Central, South America, and Caribbean)
39
+ # Currency names are marked for translation
40
+ CURRENCIES = [
41
+ # North America
42
+ {"codigo": "USD", "nombre": _("US Dollar"), "simbolo": "$"},
43
+ {"codigo": "CAD", "nombre": _("Canadian Dollar"), "simbolo": "C$"},
44
+ {"codigo": "MXN", "nombre": _("Mexican Peso"), "simbolo": "$"},
45
+ # Central America
46
+ {"codigo": "BZD", "nombre": _("Belize Dollar"), "simbolo": "BZ$"},
47
+ {"codigo": "CRC", "nombre": _("Costa Rican Colón"), "simbolo": "₡"},
48
+ {"codigo": "GTQ", "nombre": _("Guatemalan Quetzal"), "simbolo": "Q"},
49
+ {"codigo": "HNL", "nombre": _("Honduran Lempira"), "simbolo": "L"},
50
+ {"codigo": "NIO", "nombre": _("Nicaraguan Córdoba"), "simbolo": "C$"},
51
+ {"codigo": "PAB", "nombre": _("Panamanian Balboa"), "simbolo": "B/."},
52
+ {"codigo": "SVC", "nombre": _("Salvadoran Colón"), "simbolo": "₡"},
53
+ # South America
54
+ {"codigo": "ARS", "nombre": _("Argentine Peso"), "simbolo": "$"},
55
+ {"codigo": "BOB", "nombre": _("Bolivian Boliviano"), "simbolo": "Bs."},
56
+ {"codigo": "BRL", "nombre": _("Brazilian Real"), "simbolo": "R$"},
57
+ {"codigo": "CLP", "nombre": _("Chilean Peso"), "simbolo": "$"},
58
+ {"codigo": "COP", "nombre": _("Colombian Peso"), "simbolo": "$"},
59
+ {"codigo": "GYD", "nombre": _("Guyanese Dollar"), "simbolo": "G$"},
60
+ {"codigo": "PEN", "nombre": _("Peruvian Sol"), "simbolo": "S/"},
61
+ {"codigo": "PYG", "nombre": _("Paraguayan Guaraní"), "simbolo": "₲"},
62
+ {"codigo": "SRD", "nombre": _("Surinamese Dollar"), "simbolo": "$"},
63
+ {"codigo": "UYU", "nombre": _("Uruguayan Peso"), "simbolo": "$"},
64
+ {"codigo": "VES", "nombre": _("Venezuelan Bolívar"), "simbolo": "Bs."},
65
+ # Caribbean
66
+ {"codigo": "ANG", "nombre": _("Netherlands Antillean Guilder"), "simbolo": "ƒ"},
67
+ {"codigo": "AWG", "nombre": _("Aruban Florin"), "simbolo": "ƒ"},
68
+ {"codigo": "BBD", "nombre": _("Barbadian Dollar"), "simbolo": "$"},
69
+ {"codigo": "BSD", "nombre": _("Bahamian Dollar"), "simbolo": "$"},
70
+ {"codigo": "CUP", "nombre": _("Cuban Peso"), "simbolo": "$"},
71
+ {"codigo": "DOP", "nombre": _("Dominican Peso"), "simbolo": "$"},
72
+ {"codigo": "HTG", "nombre": _("Haitian Gourde"), "simbolo": "G"},
73
+ {"codigo": "JMD", "nombre": _("Jamaican Dollar"), "simbolo": "J$"},
74
+ {"codigo": "TTD", "nombre": _("Trinidad and Tobago Dollar"), "simbolo": "TT$"},
75
+ {"codigo": "XCD", "nombre": _("East Caribbean Dollar"), "simbolo": "EC$"},
76
+ ]
77
+
78
+
79
+ # Liquidation concepts (LiquidacionConcepto)
80
+ LIQUIDATION_CONCEPTS = [
81
+ {
82
+ "codigo": "DESPIDO",
83
+ "nombre": _("Dismissal"),
84
+ "descripcion": _("Termination initiated by employer"),
85
+ },
86
+ {
87
+ "codigo": "RENUNCIA",
88
+ "nombre": _("Resignation"),
89
+ "descripcion": _("Termination initiated by employee"),
90
+ },
91
+ ]
92
+
93
+
94
+ # Income concepts (Percepciones / Ingresos)
95
+ # These add to employee salary
96
+ # All names and descriptions are marked for translation
97
+ INCOME_CONCEPTS = [
98
+ {
99
+ "codigo": "OVERTIME",
100
+ "nombre": _("Overtime"),
101
+ "descripcion": _("Additional hours worked beyond regular schedule"),
102
+ },
103
+ {
104
+ "codigo": "COMMISSIONS",
105
+ "nombre": _("Commissions"),
106
+ "descripcion": _("Sales commissions and performance-based income"),
107
+ },
108
+ {
109
+ "codigo": "BONUSES",
110
+ "nombre": _("Bonuses"),
111
+ "descripcion": _("Performance or achievement bonuses"),
112
+ },
113
+ {
114
+ "codigo": "GOAL_INCENTIVES",
115
+ "nombre": _("Goal Incentives"),
116
+ "descripcion": _("Incentives for meeting specific targets or goals"),
117
+ },
118
+ {
119
+ "codigo": "REPORTED_TIPS",
120
+ "nombre": _("Reported Tips"),
121
+ "descripcion": _("Tips and gratuities reported by employee"),
122
+ },
123
+ {
124
+ "codigo": "TRANSPORT_ALLOWANCE",
125
+ "nombre": _("Transportation Allowance"),
126
+ "descripcion": _("Fixed transportation allowance"),
127
+ },
128
+ {
129
+ "codigo": "FOOD_ALLOWANCE",
130
+ "nombre": _("Food Allowance"),
131
+ "descripcion": _("Fixed food or meal allowance"),
132
+ },
133
+ {
134
+ "codigo": "HOUSING_ALLOWANCE",
135
+ "nombre": _("Housing Allowance"),
136
+ "descripcion": _("Fixed housing or rent allowance"),
137
+ },
138
+ {
139
+ "codigo": "SENIORITY_BONUS",
140
+ "nombre": _("Seniority Bonus"),
141
+ "descripcion": _("Additional payment based on years of service"),
142
+ },
143
+ {
144
+ "codigo": "PAID_VACATION",
145
+ "nombre": _("Paid Vacation"),
146
+ "descripcion": _("Payment for vacation time taken"),
147
+ },
148
+ {
149
+ "codigo": "HOLIDAY_WORK",
150
+ "nombre": _("Holiday Work"),
151
+ "descripcion": _("Additional payment for working on holidays"),
152
+ },
153
+ {
154
+ "codigo": "PAID_LEAVE",
155
+ "nombre": _("Paid Leave"),
156
+ "descripcion": _("Payment for authorized paid leave"),
157
+ },
158
+ {
159
+ "codigo": "PAID_LICENSE",
160
+ "nombre": _("Paid License"),
161
+ "descripcion": _("Payment for extended paid license periods"),
162
+ },
163
+ {
164
+ "codigo": "RETROACTIVE_PAYMENTS",
165
+ "nombre": _("Retroactive Payments"),
166
+ "descripcion": _("Back payments for salary adjustments"),
167
+ },
168
+ {
169
+ "codigo": "THIRTEENTH_SALARY",
170
+ "nombre": _("13th Month Salary"),
171
+ "descripcion": _("Annual bonus (13th month salary)"),
172
+ },
173
+ {
174
+ "codigo": "GRATUITIES",
175
+ "nombre": _("Gratuities"),
176
+ "descripcion": _("Discretionary bonuses or gratuities"),
177
+ },
178
+ {
179
+ "codigo": "SEVERANCE_PAY",
180
+ "nombre": _("Severance Pay"),
181
+ "descripcion": _("Severance or termination compensation"),
182
+ },
183
+ ]
184
+
185
+
186
+ # Deduction concepts (Deducciones)
187
+ # These subtract from employee salary
188
+ # All names and descriptions are marked for translation
189
+ DEDUCTION_CONCEPTS = [
190
+ {
191
+ "codigo": "SALARY_ADVANCE",
192
+ "nombre": _("Salary Advance"),
193
+ "descripcion": _("Deduction for salary advance repayment (automatic from Loans/Advances module)"),
194
+ },
195
+ {
196
+ "codigo": "VOLUNTARY_RETIREMENT",
197
+ "nombre": _("Voluntary Retirement Plan"),
198
+ "descripcion": _("Voluntary retirement savings contribution"),
199
+ },
200
+ {
201
+ "codigo": "MEMBERSHIPS_SUBSCRIPTIONS",
202
+ "nombre": _("Memberships/Subscriptions"),
203
+ "descripcion": _("Deduction for memberships or subscription services"),
204
+ },
205
+ {
206
+ "codigo": "CAFETERIA",
207
+ "nombre": _("Cafeteria"),
208
+ "descripcion": _("Company cafeteria charges"),
209
+ },
210
+ {
211
+ "codigo": "INTERNAL_LOANS",
212
+ "nombre": _("Internal Loans"),
213
+ "descripcion": _("Internal loan repayment installments"),
214
+ },
215
+ {
216
+ "codigo": "CREDIT_UNION_LOANS",
217
+ "nombre": _("Credit Union Loans"),
218
+ "descripcion": _("Credit union or cooperative loan payments"),
219
+ },
220
+ {
221
+ "codigo": "LOAN_INTEREST",
222
+ "nombre": _("Loan Interest"),
223
+ "descripcion": _("Interest charges on loans"),
224
+ },
225
+ {
226
+ "codigo": "ALIMONY",
227
+ "nombre": _("Alimony"),
228
+ "descripcion": _("Court-ordered alimony or child support payments"),
229
+ },
230
+ {
231
+ "codigo": "COURT_GARNISHMENTS",
232
+ "nombre": _("Court Garnishments"),
233
+ "descripcion": _("Court-ordered wage garnishments"),
234
+ },
235
+ {
236
+ "codigo": "UNPAID_ABSENCES",
237
+ "nombre": _("Unpaid Absences"),
238
+ "descripcion": _("Deductions for unpaid absences"),
239
+ },
240
+ {
241
+ "codigo": "TARDINESS",
242
+ "nombre": _("Tardiness"),
243
+ "descripcion": _("Deductions for late arrivals"),
244
+ },
245
+ {
246
+ "codigo": "NONCOMPLIANCE_PENALTIES",
247
+ "nombre": _("Non-compliance Penalties"),
248
+ "descripcion": _("Penalties for policy or contract violations"),
249
+ },
250
+ {
251
+ "codigo": "LOSSES_DAMAGES",
252
+ "nombre": _("Losses or Damages"),
253
+ "descripcion": _("Deductions for lost or damaged property"),
254
+ },
255
+ {
256
+ "codigo": "UNIFORM_PENALTIES",
257
+ "nombre": _("Uniform Penalties"),
258
+ "descripcion": _("Penalties for unreturned uniforms or equipment"),
259
+ },
260
+ {
261
+ "codigo": "STORE_CANTEEN_PURCHASES",
262
+ "nombre": _("Store/Canteen Purchases"),
263
+ "descripcion": _("Purchases at company store or canteen"),
264
+ },
265
+ {
266
+ "codigo": "VOLUNTARY_DONATIONS",
267
+ "nombre": _("Voluntary Donations"),
268
+ "descripcion": _("Voluntary charitable donations"),
269
+ },
270
+ {
271
+ "codigo": "ASSOCIATION_CONTRIBUTIONS",
272
+ "nombre": _("Association Contributions"),
273
+ "descripcion": _("Voluntary contributions to associations"),
274
+ },
275
+ {
276
+ "codigo": "UNION_DUES",
277
+ "nombre": _("Union Dues"),
278
+ "descripcion": _("Voluntary union membership dues"),
279
+ },
280
+ {
281
+ "codigo": "OVERPAYMENT_CORRECTION",
282
+ "nombre": _("Overpayment Correction"),
283
+ "descripcion": _("Correction for previous overpayments"),
284
+ },
285
+ ]
286
+
287
+
288
+ # Employer benefit concepts (Prestaciones / Aportes Patronales)
289
+ # These are employer costs and provisions that do NOT affect employee's net pay
290
+ # All names and descriptions are marked for translation
291
+ BENEFIT_CONCEPTS = [
292
+ {
293
+ "codigo": "PAID_VACATION_PROVISION",
294
+ "nombre": _("Paid Vacation Provision"),
295
+ "descripcion": _("Employer provision for paid vacation days " "(universal labor right in the Americas)"),
296
+ },
297
+ {
298
+ "codigo": "THIRTEENTH_SALARY_PROVISION",
299
+ "nombre": _("13th Month Salary Provision"),
300
+ "descripcion": _(
301
+ "Employer provision for 13th month salary/Christmas bonus "
302
+ "(aguinaldo - widespread right in Latin America)"
303
+ ),
304
+ },
305
+ {
306
+ "codigo": "SEVERANCE_PROVISION",
307
+ "nombre": _("Severance Pay Provision"),
308
+ "descripcion": _(
309
+ "Employer provision for severance pay in case of unjust dismissal "
310
+ "(common legal principle in the Americas)"
311
+ ),
312
+ },
313
+ ]
314
+
315
+
316
+ # Payroll Types (Tipos de Planilla)
317
+ # Common payroll types with different periodicities
318
+ # All names and descriptions are marked for translation
319
+ PAYROLL_TYPES = [
320
+ {
321
+ "codigo": "MONTHLY",
322
+ "descripcion": _("Monthly Payroll - 30 days"),
323
+ "dias": 30,
324
+ "periodicidad": "mensual",
325
+ "periodos_por_anio": 12,
326
+ },
327
+ {
328
+ "codigo": "BIWEEKLY",
329
+ "descripcion": _("Biweekly Payroll - 15 days"),
330
+ "dias": 15,
331
+ "periodicidad": "quincenal",
332
+ "periodos_por_anio": 24,
333
+ },
334
+ {
335
+ "codigo": "FORTNIGHTLY",
336
+ "descripcion": _("Fortnightly Payroll - 14 days"),
337
+ "dias": 14,
338
+ "periodicidad": "catorcenal",
339
+ "periodos_por_anio": 26,
340
+ },
341
+ {
342
+ "codigo": "WEEKLY",
343
+ "descripcion": _("Weekly Payroll - 7 days"),
344
+ "dias": 7,
345
+ "periodicidad": "semanal",
346
+ "periodos_por_anio": 52,
347
+ },
348
+ ]
349
+
350
+
351
+ def load_currencies() -> None:
352
+ """Load American currencies into the database.
353
+
354
+ Currency names are translated based on the configured language in the database.
355
+ This function is idempotent - it will not create duplicates on repeated calls.
356
+ """
357
+ from coati_payroll.model import Moneda, db
358
+ from coati_payroll.log import log
359
+
360
+ currencies_loaded = 0
361
+ for currency_data in CURRENCIES:
362
+ # Check if currency already exists
363
+ existing = db.session.execute(db.select(Moneda).filter_by(codigo=currency_data["codigo"])).scalar_one_or_none()
364
+
365
+ if existing is None:
366
+ # Create new currency - nombre will be translated by _()
367
+ # Convert lazy string to regular string for database storage
368
+ currency = Moneda()
369
+ currency.codigo = currency_data["codigo"]
370
+ currency.nombre = str(currency_data["nombre"])
371
+ currency.simbolo = currency_data["simbolo"]
372
+ currency.activo = True
373
+
374
+ db.session.add(currency)
375
+ currencies_loaded += 1
376
+
377
+ if currencies_loaded > 0:
378
+ db.session.commit()
379
+ log.trace(f"Loaded {currencies_loaded} currencies")
380
+ else:
381
+ log.trace("No new currencies to load")
382
+
383
+
384
+ def load_income_concepts() -> None:
385
+ """Load income concepts (percepciones) into the database.
386
+
387
+ Concept names and descriptions are translated based on the configured
388
+ language in the database. This function is idempotent.
389
+ Default concepts are created with approved status.
390
+ """
391
+ from coati_payroll.model import Percepcion, db, utc_now
392
+ from coati_payroll.enums import EstadoAprobacion
393
+ from coati_payroll.log import log
394
+
395
+ concepts_loaded = 0
396
+ for concept_data in INCOME_CONCEPTS:
397
+ # Check if concept already exists
398
+ existing = db.session.execute(
399
+ db.select(Percepcion).filter_by(codigo=concept_data["codigo"])
400
+ ).scalar_one_or_none()
401
+
402
+ if existing is None:
403
+ # Create new income concept - strings will be translated by _()
404
+ # Convert lazy strings to regular strings for database storage
405
+ concept = Percepcion()
406
+ concept.codigo = concept_data["codigo"]
407
+ concept.nombre = str(concept_data["nombre"])
408
+ concept.descripcion = str(concept_data["descripcion"])
409
+ concept.formula_tipo = "fijo"
410
+ concept.gravable = True
411
+ concept.recurrente = False
412
+ concept.activo = True
413
+ concept.editable_en_nomina = True
414
+ # Default concepts are pre-approved
415
+ concept.estado_aprobacion = EstadoAprobacion.APROBADO
416
+ concept.aprobado_por = "system"
417
+ concept.aprobado_en = utc_now()
418
+ concept.creado_por = "system"
419
+
420
+ db.session.add(concept)
421
+ concepts_loaded += 1
422
+
423
+ if concepts_loaded > 0:
424
+ db.session.commit()
425
+ log.trace(f"Loaded {concepts_loaded} income concepts")
426
+ else:
427
+ log.trace("No new income concepts to load")
428
+
429
+
430
+ def load_deduction_concepts() -> None:
431
+ """Load deduction concepts (deducciones) into the database.
432
+
433
+ Concept names and descriptions are translated based on the configured
434
+ language in the database. This function is idempotent.
435
+ Default concepts are created with approved status.
436
+ """
437
+ from coati_payroll.model import Deduccion, db, utc_now
438
+ from coati_payroll.enums import EstadoAprobacion
439
+ from coati_payroll.log import log
440
+
441
+ concepts_loaded = 0
442
+ for concept_data in DEDUCTION_CONCEPTS:
443
+ # Check if concept already exists
444
+ existing = db.session.execute(
445
+ db.select(Deduccion).filter_by(codigo=concept_data["codigo"])
446
+ ).scalar_one_or_none()
447
+
448
+ if existing is None:
449
+ # Create new deduction concept - strings will be translated by _()
450
+ # Convert lazy strings to regular strings for database storage
451
+ concept = Deduccion()
452
+ concept.codigo = concept_data["codigo"]
453
+ concept.nombre = str(concept_data["nombre"])
454
+ concept.descripcion = str(concept_data["descripcion"])
455
+ concept.tipo = "general"
456
+ concept.es_impuesto = False
457
+ concept.formula_tipo = "fijo"
458
+ concept.antes_impuesto = False
459
+ concept.recurrente = False
460
+ concept.activo = True
461
+ concept.editable_en_nomina = True
462
+ # Default concepts are pre-approved
463
+ concept.estado_aprobacion = EstadoAprobacion.APROBADO
464
+ concept.aprobado_por = "system"
465
+ concept.aprobado_en = utc_now()
466
+ concept.creado_por = "system"
467
+
468
+ db.session.add(concept)
469
+ concepts_loaded += 1
470
+
471
+ if concepts_loaded > 0:
472
+ db.session.commit()
473
+ log.trace(f"Loaded {concepts_loaded} deduction concepts")
474
+ else:
475
+ log.trace("No new deduction concepts to load")
476
+
477
+
478
+ def load_benefit_concepts() -> None:
479
+ """Load employer benefit concepts (prestaciones) into the database.
480
+
481
+ Concept names and descriptions are translated based on the configured
482
+ language in the database. This function is idempotent.
483
+ Default concepts are created with approved status.
484
+ """
485
+ from coati_payroll.model import Prestacion, db, utc_now
486
+ from coati_payroll.enums import EstadoAprobacion
487
+ from coati_payroll.log import log
488
+
489
+ concepts_loaded = 0
490
+ for concept_data in BENEFIT_CONCEPTS:
491
+ # Check if concept already exists
492
+ existing = db.session.execute(
493
+ db.select(Prestacion).filter_by(codigo=concept_data["codigo"])
494
+ ).scalar_one_or_none()
495
+
496
+ if existing is None:
497
+ # Create new benefit concept - strings will be translated by _()
498
+ # Convert lazy strings to regular strings for database storage
499
+ concept = Prestacion()
500
+ concept.codigo = concept_data["codigo"]
501
+ concept.nombre = str(concept_data["nombre"])
502
+ concept.descripcion = str(concept_data["descripcion"])
503
+ concept.tipo = "patronal"
504
+ concept.formula_tipo = "fijo"
505
+ concept.recurrente = False
506
+ concept.activo = True
507
+ concept.editable_en_nomina = True
508
+ # Default concepts are pre-approved
509
+ concept.estado_aprobacion = EstadoAprobacion.APROBADO
510
+ concept.aprobado_por = "system"
511
+ concept.aprobado_en = utc_now()
512
+ concept.creado_por = "system"
513
+
514
+ db.session.add(concept)
515
+ concepts_loaded += 1
516
+
517
+ if concepts_loaded > 0:
518
+ db.session.commit()
519
+ log.trace(f"Loaded {concepts_loaded} benefit concepts")
520
+ else:
521
+ log.trace("No new benefit concepts to load")
522
+
523
+
524
+ def load_payroll_types() -> None:
525
+ """Load common payroll types into the database.
526
+
527
+ Payroll type descriptions are translated based on the configured
528
+ language in the database. This function is idempotent.
529
+ """
530
+ from coati_payroll.model import TipoPlanilla, db
531
+ from coati_payroll.log import log
532
+
533
+ types_loaded = 0
534
+ for type_data in PAYROLL_TYPES:
535
+ # Check if payroll type already exists
536
+ existing = db.session.execute(
537
+ db.select(TipoPlanilla).filter_by(codigo=type_data["codigo"])
538
+ ).scalar_one_or_none()
539
+
540
+ if existing is None:
541
+ # Create new payroll type - strings will be translated by _()
542
+ # Convert lazy strings to regular strings for database storage
543
+ payroll_type = TipoPlanilla()
544
+ payroll_type.codigo = type_data["codigo"]
545
+ payroll_type.descripcion = str(type_data["descripcion"])
546
+ payroll_type.dias = type_data["dias"]
547
+ payroll_type.periodicidad = type_data["periodicidad"]
548
+ payroll_type.periodos_por_anio = type_data["periodos_por_anio"]
549
+ payroll_type.mes_inicio_fiscal = 1 # January
550
+ payroll_type.dia_inicio_fiscal = 1 # 1st day
551
+ payroll_type.acumula_anual = True
552
+ payroll_type.activo = True
553
+
554
+ db.session.add(payroll_type)
555
+ types_loaded += 1
556
+
557
+ if types_loaded > 0:
558
+ db.session.commit()
559
+ log.trace(f"Loaded {types_loaded} payroll types")
560
+ else:
561
+ log.trace("No new payroll types to load")
562
+
563
+
564
+ def load_liquidation_concepts() -> None:
565
+ """Load liquidation concepts into the database.
566
+
567
+ This function is idempotent.
568
+ """
569
+ from coati_payroll.model import LiquidacionConcepto, db
570
+ from coati_payroll.log import log
571
+
572
+ concepts_loaded = 0
573
+ for concept_data in LIQUIDATION_CONCEPTS:
574
+ existing = db.session.execute(
575
+ db.select(LiquidacionConcepto).filter_by(codigo=concept_data["codigo"])
576
+ ).scalar_one_or_none()
577
+
578
+ if existing is None:
579
+ concept = LiquidacionConcepto()
580
+ concept.codigo = concept_data["codigo"]
581
+ concept.nombre = str(concept_data["nombre"])
582
+ concept.descripcion = str(concept_data["descripcion"])
583
+ concept.activo = True
584
+ db.session.add(concept)
585
+ concepts_loaded += 1
586
+
587
+ if concepts_loaded > 0:
588
+ db.session.commit()
589
+ log.trace(f"Loaded {concepts_loaded} liquidation concepts")
590
+ else:
591
+ log.trace("No new liquidation concepts to load")
592
+
593
+
594
+ def load_initial_data() -> None:
595
+ """Load all initial data into the database.
596
+
597
+ This function loads currencies, income concepts, deduction concepts,
598
+ employer benefit concepts, and payroll types. All strings are translated
599
+ based on the configured language in the database.
600
+ This function is idempotent - safe to call multiple times.
601
+ """
602
+ from coati_payroll.log import log
603
+
604
+ log.trace("Loading initial data")
605
+
606
+ load_currencies()
607
+ load_income_concepts()
608
+ load_deduction_concepts()
609
+ load_benefit_concepts()
610
+ load_payroll_types()
611
+ load_liquidation_concepts()
612
+
613
+ log.trace("Initial data loading completed")