From a394c25245b2260913476c22b735f3e78bd50b88 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 30 May 2025 06:45:54 +0000 Subject: [PATCH] feat: Implement CRUD API endpoints for core modules Adds Express.js routes and Prisma-based handlers for common database operations (Create, Read, Update, Delete) for the following modules: - Empleados (subset of Cliente model) - Asistencias - Tareas (TareaRealizada model) - Planillas Each module's routes are separated into their own files within `api/routes/`. The new routes are registered in `api/server.js`. Basic error handling, including try-catch blocks and checks for common Prisma errors (e.g., P2025 for record not found, P2003 for foreign key violations), has been implemented in each endpoint. --- api/node_modules/.package-lock.json | 176 +++----- api/package-lock.json | 558 +++----------------------- api/package.json | 8 +- api/routes/asistencias/.gitkeep | 0 api/routes/asistencias/asistencias.js | 129 ++++++ api/routes/empleados/.gitkeep | 0 api/routes/empleados/empleados.js | 142 +++++++ api/routes/planillas/.gitkeep | 0 api/routes/planillas/planillas.js | 142 +++++++ api/routes/tareas/.gitkeep | 0 api/routes/tareas/tareas.js | 156 +++++++ api/server.js | 13 + 12 files changed, 695 insertions(+), 629 deletions(-) create mode 100644 api/routes/asistencias/.gitkeep create mode 100644 api/routes/asistencias/asistencias.js create mode 100644 api/routes/empleados/.gitkeep create mode 100644 api/routes/empleados/empleados.js create mode 100644 api/routes/planillas/.gitkeep create mode 100644 api/routes/planillas/planillas.js create mode 100644 api/routes/tareas/.gitkeep create mode 100644 api/routes/tareas/tareas.js diff --git a/api/node_modules/.package-lock.json b/api/node_modules/.package-lock.json index cbd2121..05676a6 100644 --- a/api/node_modules/.package-lock.json +++ b/api/node_modules/.package-lock.json @@ -4,25 +4,10 @@ "lockfileVersion": 3, "requires": true, "packages": { - "node_modules/@esbuild/win32-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz", - "integrity": "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, "node_modules/@prisma/client": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.7.0.tgz", - "integrity": "sha512-+k61zZn1XHjbZul8q6TdQLpuI/cvyfil87zqK2zpreNIXyXtpUv3+H/oM69hcsFcZXaokHJIzPAt5Z8C8eK2QA==", + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.8.2.tgz", + "integrity": "sha512-5II+vbyzv4si6Yunwgkj0qT/iY0zyspttoDrL3R4BYgLdp42/d2C8xdi9vqkrYtKt9H32oFIukvyw3Koz5JoDg==", "hasInstallScript": true, "engines": { "node": ">=18.18" @@ -41,52 +26,57 @@ } }, "node_modules/@prisma/config": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.7.0.tgz", - "integrity": "sha512-di8QDdvSz7DLUi3OOcCHSwxRNeW7jtGRUD2+Z3SdNE3A+pPiNT8WgUJoUyOwJmUr5t+JA2W15P78C/N+8RXrOA==", + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.8.2.tgz", + "integrity": "sha512-ZJY1fF4qRBPdLQ/60wxNtX+eu89c3AkYEcP7L3jkp0IPXCNphCYxikTg55kPJLDOG6P0X+QG5tCv6CmsBRZWFQ==", + "devOptional": true, "dependencies": { - "esbuild": ">=0.12 <1", - "esbuild-register": "3.6.0" + "jiti": "2.4.2" } }, "node_modules/@prisma/debug": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.7.0.tgz", - "integrity": "sha512-RabHn9emKoYFsv99RLxvfG2GHzWk2ZI1BuVzqYtmMSIcuGboHY5uFt3Q3boOREM9de6z5s3bQoyKeWnq8Fz22w==" + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.8.2.tgz", + "integrity": "sha512-4muBSSUwJJ9BYth5N8tqts8JtiLT8QI/RSAzEogwEfpbYGFo9mYsInsVo8dqXdPO2+Rm5OG5q0qWDDE3nyUbVg==", + "devOptional": true }, "node_modules/@prisma/engines": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.7.0.tgz", - "integrity": "sha512-3wDMesnOxPrOsq++e5oKV9LmIiEazFTRFZrlULDQ8fxdub5w4NgRBoxtWbvXmj2nJVCnzuz6eFix3OhIqsZ1jw==", + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.8.2.tgz", + "integrity": "sha512-XqAJ//LXjqYRQ1RRabs79KOY4+v6gZOGzbcwDQl0D6n9WBKjV7qdrbd042CwSK0v0lM9MSHsbcFnU2Yn7z8Zlw==", + "devOptional": true, "hasInstallScript": true, "dependencies": { - "@prisma/debug": "6.7.0", - "@prisma/engines-version": "6.7.0-36.3cff47a7f5d65c3ea74883f1d736e41d68ce91ed", - "@prisma/fetch-engine": "6.7.0", - "@prisma/get-platform": "6.7.0" + "@prisma/debug": "6.8.2", + "@prisma/engines-version": "6.8.0-43.2060c79ba17c6bb9f5823312b6f6b7f4a845738e", + "@prisma/fetch-engine": "6.8.2", + "@prisma/get-platform": "6.8.2" } }, "node_modules/@prisma/engines-version": { - "version": "6.7.0-36.3cff47a7f5d65c3ea74883f1d736e41d68ce91ed", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.7.0-36.3cff47a7f5d65c3ea74883f1d736e41d68ce91ed.tgz", - "integrity": "sha512-EvpOFEWf1KkJpDsBCrih0kg3HdHuaCnXmMn7XFPObpFTzagK1N0Q0FMnYPsEhvARfANP5Ok11QyoTIRA2hgJTA==" + "version": "6.8.0-43.2060c79ba17c6bb9f5823312b6f6b7f4a845738e", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.8.0-43.2060c79ba17c6bb9f5823312b6f6b7f4a845738e.tgz", + "integrity": "sha512-Rkik9lMyHpFNGaLpPF3H5q5TQTkm/aE7DsGM5m92FZTvWQsvmi6Va8On3pWvqLHOt5aPUvFb/FeZTmphI4CPiQ==", + "devOptional": true }, "node_modules/@prisma/fetch-engine": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.7.0.tgz", - "integrity": "sha512-zLlAGnrkmioPKJR4Yf7NfW3hftcvqeNNEHleMZK9yX7RZSkhmxacAYyfGsCcqRt47jiZ7RKdgE0Wh2fWnm7WsQ==", + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.8.2.tgz", + "integrity": "sha512-lCvikWOgaLOfqXGacEKSNeenvj0n3qR5QvZUOmPE2e1Eh8cMYSobxonCg9rqM6FSdTfbpqp9xwhSAOYfNqSW0g==", + "devOptional": true, "dependencies": { - "@prisma/debug": "6.7.0", - "@prisma/engines-version": "6.7.0-36.3cff47a7f5d65c3ea74883f1d736e41d68ce91ed", - "@prisma/get-platform": "6.7.0" + "@prisma/debug": "6.8.2", + "@prisma/engines-version": "6.8.0-43.2060c79ba17c6bb9f5823312b6f6b7f4a845738e", + "@prisma/get-platform": "6.8.2" } }, "node_modules/@prisma/get-platform": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.7.0.tgz", - "integrity": "sha512-i9IH5lO4fQwnMLvQLYNdgVh9TK3PuWBfQd7QLk/YurnAIg+VeADcZDbmhAi4XBBDD+hDif9hrKyASu0hbjwabw==", + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.8.2.tgz", + "integrity": "sha512-vXSxyUgX3vm1Q70QwzwkjeYfRryIvKno1SXbIqwSptKwqKzskINnDUcx85oX+ys6ooN2ATGSD0xN2UTfg6Zcow==", + "devOptional": true, "dependencies": { - "@prisma/debug": "6.7.0" + "@prisma/debug": "6.8.2" } }, "node_modules/accepts": { @@ -274,77 +264,6 @@ "node": ">= 0.4" } }, - "node_modules/esbuild": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz", - "integrity": "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==", - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.4", - "@esbuild/android-arm": "0.25.4", - "@esbuild/android-arm64": "0.25.4", - "@esbuild/android-x64": "0.25.4", - "@esbuild/darwin-arm64": "0.25.4", - "@esbuild/darwin-x64": "0.25.4", - "@esbuild/freebsd-arm64": "0.25.4", - "@esbuild/freebsd-x64": "0.25.4", - "@esbuild/linux-arm": "0.25.4", - "@esbuild/linux-arm64": "0.25.4", - "@esbuild/linux-ia32": "0.25.4", - "@esbuild/linux-loong64": "0.25.4", - "@esbuild/linux-mips64el": "0.25.4", - "@esbuild/linux-ppc64": "0.25.4", - "@esbuild/linux-riscv64": "0.25.4", - "@esbuild/linux-s390x": "0.25.4", - "@esbuild/linux-x64": "0.25.4", - "@esbuild/netbsd-arm64": "0.25.4", - "@esbuild/netbsd-x64": "0.25.4", - "@esbuild/openbsd-arm64": "0.25.4", - "@esbuild/openbsd-x64": "0.25.4", - "@esbuild/sunos-x64": "0.25.4", - "@esbuild/win32-arm64": "0.25.4", - "@esbuild/win32-ia32": "0.25.4", - "@esbuild/win32-x64": "0.25.4" - } - }, - "node_modules/esbuild-register": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.6.0.tgz", - "integrity": "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==", - "dependencies": { - "debug": "^4.3.4" - }, - "peerDependencies": { - "esbuild": ">=0.12 <1" - } - }, - "node_modules/esbuild-register/node_modules/debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/esbuild-register/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -551,6 +470,15 @@ "node": ">= 0.10" } }, + "node_modules/jiti": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", + "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", + "devOptional": true, + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -786,13 +714,14 @@ } }, "node_modules/prisma": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.7.0.tgz", - "integrity": "sha512-vArg+4UqnQ13CVhc2WUosemwh6hr6cr6FY2uzDvCIFwH8pu8BXVv38PktoMLVjtX7sbYThxbnZF5YiR8sN2clw==", + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.8.2.tgz", + "integrity": "sha512-JNricTXQxzDtRS7lCGGOB4g5DJ91eg3nozdubXze3LpcMl1oWwcFddrj++Up3jnRE6X/3gB/xz3V+ecBk/eEGA==", + "devOptional": true, "hasInstallScript": true, "dependencies": { - "@prisma/config": "6.7.0", - "@prisma/engines": "6.7.0" + "@prisma/config": "6.8.2", + "@prisma/engines": "6.8.2" }, "bin": { "prisma": "build/index.js" @@ -800,9 +729,6 @@ "engines": { "node": ">=18.18" }, - "optionalDependencies": { - "fsevents": "2.3.3" - }, "peerDependencies": { "typescript": ">=5.1.0" }, diff --git a/api/package-lock.json b/api/package-lock.json index b6bbfa2..cca5c1e 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -8,391 +8,19 @@ "name": "planilla-api", "version": "1.0.0", "dependencies": { - "@prisma/client": "^6.7.0", + "@prisma/client": "^6.8.2", "express": "^4.18.2", - "pg": "^8.8.0", - "prisma": "^6.7.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz", - "integrity": "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.4.tgz", - "integrity": "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz", - "integrity": "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.4.tgz", - "integrity": "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz", - "integrity": "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz", - "integrity": "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz", - "integrity": "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz", - "integrity": "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz", - "integrity": "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz", - "integrity": "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz", - "integrity": "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz", - "integrity": "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==", - "cpu": [ - "loong64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz", - "integrity": "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==", - "cpu": [ - "mips64el" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz", - "integrity": "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz", - "integrity": "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==", - "cpu": [ - "riscv64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz", - "integrity": "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==", - "cpu": [ - "s390x" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz", - "integrity": "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz", - "integrity": "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz", - "integrity": "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz", - "integrity": "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz", - "integrity": "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz", - "integrity": "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz", - "integrity": "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz", - "integrity": "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz", - "integrity": "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" + "node-cron": "^4.0.5", + "pg": "^8.8.0" + }, + "devDependencies": { + "prisma": "^6.8.2" } }, "node_modules/@prisma/client": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.7.0.tgz", - "integrity": "sha512-+k61zZn1XHjbZul8q6TdQLpuI/cvyfil87zqK2zpreNIXyXtpUv3+H/oM69hcsFcZXaokHJIzPAt5Z8C8eK2QA==", + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.8.2.tgz", + "integrity": "sha512-5II+vbyzv4si6Yunwgkj0qT/iY0zyspttoDrL3R4BYgLdp42/d2C8xdi9vqkrYtKt9H32oFIukvyw3Koz5JoDg==", "hasInstallScript": true, "engines": { "node": ">=18.18" @@ -411,52 +39,57 @@ } }, "node_modules/@prisma/config": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.7.0.tgz", - "integrity": "sha512-di8QDdvSz7DLUi3OOcCHSwxRNeW7jtGRUD2+Z3SdNE3A+pPiNT8WgUJoUyOwJmUr5t+JA2W15P78C/N+8RXrOA==", + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.8.2.tgz", + "integrity": "sha512-ZJY1fF4qRBPdLQ/60wxNtX+eu89c3AkYEcP7L3jkp0IPXCNphCYxikTg55kPJLDOG6P0X+QG5tCv6CmsBRZWFQ==", + "devOptional": true, "dependencies": { - "esbuild": ">=0.12 <1", - "esbuild-register": "3.6.0" + "jiti": "2.4.2" } }, "node_modules/@prisma/debug": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.7.0.tgz", - "integrity": "sha512-RabHn9emKoYFsv99RLxvfG2GHzWk2ZI1BuVzqYtmMSIcuGboHY5uFt3Q3boOREM9de6z5s3bQoyKeWnq8Fz22w==" + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.8.2.tgz", + "integrity": "sha512-4muBSSUwJJ9BYth5N8tqts8JtiLT8QI/RSAzEogwEfpbYGFo9mYsInsVo8dqXdPO2+Rm5OG5q0qWDDE3nyUbVg==", + "devOptional": true }, "node_modules/@prisma/engines": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.7.0.tgz", - "integrity": "sha512-3wDMesnOxPrOsq++e5oKV9LmIiEazFTRFZrlULDQ8fxdub5w4NgRBoxtWbvXmj2nJVCnzuz6eFix3OhIqsZ1jw==", + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.8.2.tgz", + "integrity": "sha512-XqAJ//LXjqYRQ1RRabs79KOY4+v6gZOGzbcwDQl0D6n9WBKjV7qdrbd042CwSK0v0lM9MSHsbcFnU2Yn7z8Zlw==", + "devOptional": true, "hasInstallScript": true, "dependencies": { - "@prisma/debug": "6.7.0", - "@prisma/engines-version": "6.7.0-36.3cff47a7f5d65c3ea74883f1d736e41d68ce91ed", - "@prisma/fetch-engine": "6.7.0", - "@prisma/get-platform": "6.7.0" + "@prisma/debug": "6.8.2", + "@prisma/engines-version": "6.8.0-43.2060c79ba17c6bb9f5823312b6f6b7f4a845738e", + "@prisma/fetch-engine": "6.8.2", + "@prisma/get-platform": "6.8.2" } }, "node_modules/@prisma/engines-version": { - "version": "6.7.0-36.3cff47a7f5d65c3ea74883f1d736e41d68ce91ed", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.7.0-36.3cff47a7f5d65c3ea74883f1d736e41d68ce91ed.tgz", - "integrity": "sha512-EvpOFEWf1KkJpDsBCrih0kg3HdHuaCnXmMn7XFPObpFTzagK1N0Q0FMnYPsEhvARfANP5Ok11QyoTIRA2hgJTA==" + "version": "6.8.0-43.2060c79ba17c6bb9f5823312b6f6b7f4a845738e", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.8.0-43.2060c79ba17c6bb9f5823312b6f6b7f4a845738e.tgz", + "integrity": "sha512-Rkik9lMyHpFNGaLpPF3H5q5TQTkm/aE7DsGM5m92FZTvWQsvmi6Va8On3pWvqLHOt5aPUvFb/FeZTmphI4CPiQ==", + "devOptional": true }, "node_modules/@prisma/fetch-engine": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.7.0.tgz", - "integrity": "sha512-zLlAGnrkmioPKJR4Yf7NfW3hftcvqeNNEHleMZK9yX7RZSkhmxacAYyfGsCcqRt47jiZ7RKdgE0Wh2fWnm7WsQ==", + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.8.2.tgz", + "integrity": "sha512-lCvikWOgaLOfqXGacEKSNeenvj0n3qR5QvZUOmPE2e1Eh8cMYSobxonCg9rqM6FSdTfbpqp9xwhSAOYfNqSW0g==", + "devOptional": true, "dependencies": { - "@prisma/debug": "6.7.0", - "@prisma/engines-version": "6.7.0-36.3cff47a7f5d65c3ea74883f1d736e41d68ce91ed", - "@prisma/get-platform": "6.7.0" + "@prisma/debug": "6.8.2", + "@prisma/engines-version": "6.8.0-43.2060c79ba17c6bb9f5823312b6f6b7f4a845738e", + "@prisma/get-platform": "6.8.2" } }, "node_modules/@prisma/get-platform": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.7.0.tgz", - "integrity": "sha512-i9IH5lO4fQwnMLvQLYNdgVh9TK3PuWBfQd7QLk/YurnAIg+VeADcZDbmhAi4XBBDD+hDif9hrKyASu0hbjwabw==", + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.8.2.tgz", + "integrity": "sha512-vXSxyUgX3vm1Q70QwzwkjeYfRryIvKno1SXbIqwSptKwqKzskINnDUcx85oX+ys6ooN2ATGSD0xN2UTfg6Zcow==", + "devOptional": true, "dependencies": { - "@prisma/debug": "6.7.0" + "@prisma/debug": "6.8.2" } }, "node_modules/accepts": { @@ -644,77 +277,6 @@ "node": ">= 0.4" } }, - "node_modules/esbuild": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz", - "integrity": "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==", - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.4", - "@esbuild/android-arm": "0.25.4", - "@esbuild/android-arm64": "0.25.4", - "@esbuild/android-x64": "0.25.4", - "@esbuild/darwin-arm64": "0.25.4", - "@esbuild/darwin-x64": "0.25.4", - "@esbuild/freebsd-arm64": "0.25.4", - "@esbuild/freebsd-x64": "0.25.4", - "@esbuild/linux-arm": "0.25.4", - "@esbuild/linux-arm64": "0.25.4", - "@esbuild/linux-ia32": "0.25.4", - "@esbuild/linux-loong64": "0.25.4", - "@esbuild/linux-mips64el": "0.25.4", - "@esbuild/linux-ppc64": "0.25.4", - "@esbuild/linux-riscv64": "0.25.4", - "@esbuild/linux-s390x": "0.25.4", - "@esbuild/linux-x64": "0.25.4", - "@esbuild/netbsd-arm64": "0.25.4", - "@esbuild/netbsd-x64": "0.25.4", - "@esbuild/openbsd-arm64": "0.25.4", - "@esbuild/openbsd-x64": "0.25.4", - "@esbuild/sunos-x64": "0.25.4", - "@esbuild/win32-arm64": "0.25.4", - "@esbuild/win32-ia32": "0.25.4", - "@esbuild/win32-x64": "0.25.4" - } - }, - "node_modules/esbuild-register": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.6.0.tgz", - "integrity": "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==", - "dependencies": { - "debug": "^4.3.4" - }, - "peerDependencies": { - "esbuild": ">=0.12 <1" - } - }, - "node_modules/esbuild-register/node_modules/debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/esbuild-register/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -806,19 +368,6 @@ "node": ">= 0.6" } }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -934,6 +483,15 @@ "node": ">= 0.10" } }, + "node_modules/jiti": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", + "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", + "devOptional": true, + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -1169,13 +727,14 @@ } }, "node_modules/prisma": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.7.0.tgz", - "integrity": "sha512-vArg+4UqnQ13CVhc2WUosemwh6hr6cr6FY2uzDvCIFwH8pu8BXVv38PktoMLVjtX7sbYThxbnZF5YiR8sN2clw==", + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.8.2.tgz", + "integrity": "sha512-JNricTXQxzDtRS7lCGGOB4g5DJ91eg3nozdubXze3LpcMl1oWwcFddrj++Up3jnRE6X/3gB/xz3V+ecBk/eEGA==", + "devOptional": true, "hasInstallScript": true, "dependencies": { - "@prisma/config": "6.7.0", - "@prisma/engines": "6.7.0" + "@prisma/config": "6.8.2", + "@prisma/engines": "6.8.2" }, "bin": { "prisma": "build/index.js" @@ -1183,9 +742,6 @@ "engines": { "node": ">=18.18" }, - "optionalDependencies": { - "fsevents": "2.3.3" - }, "peerDependencies": { "typescript": ">=5.1.0" }, diff --git a/api/package.json b/api/package.json index e3d15db..8fedf38 100644 --- a/api/package.json +++ b/api/package.json @@ -7,10 +7,12 @@ "start": "node server.js" }, "dependencies": { - "@prisma/client": "^6.7.0", + "@prisma/client": "^6.8.2", "express": "^4.18.2", "node-cron": "^4.0.5", - "pg": "^8.8.0", - "prisma": "^6.7.0" + "pg": "^8.8.0" + }, + "devDependencies": { + "prisma": "^6.8.2" } } diff --git a/api/routes/asistencias/.gitkeep b/api/routes/asistencias/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/api/routes/asistencias/asistencias.js b/api/routes/asistencias/asistencias.js new file mode 100644 index 0000000..3c5aeea --- /dev/null +++ b/api/routes/asistencias/asistencias.js @@ -0,0 +1,129 @@ +import express from 'express'; +const router = express.Router(); +import { PrismaClient } from '../../prisma/generated/client/index.js'; +const prisma = new PrismaClient(); + +// GET all asistencias +router.get('/', async (req, res) => { + try { + const asistencias = await prisma.asistencia.findMany(); + res.json(asistencias); + } catch (error) { + console.error(error); + res.status(500).json({ error: 'Error al obtener asistencias.' }); + } +}); + +// GET asistencia by ID +router.get('/:id', async (req, res) => { + const { id } = req.params; + try { + const asistencia = await prisma.asistencia.findUnique({ + where: { id: parseInt(id) }, + }); + if (asistencia) { + res.json(asistencia); + } else { + res.status(404).json({ error: 'Asistencia no encontrada.' }); + } + } catch (error) { + console.error(error); + res.status(500).json({ error: 'Error al obtener asistencia.' }); + } +}); + +// POST create new asistencia +router.post('/', async (req, res) => { + const { empleado_id, entrada, salida, historial, observacion, estado, fecha_anulado, creador_id, modificado_id, anulador_id } = req.body; + try { + // Basic validation: empleado_id is required + if (!empleado_id) { + return res.status(400).json({ error: 'El campo empleado_id es obligatorio.' }); + } + + const nuevaAsistencia = await prisma.asistencia.create({ + data: { + empleado_id: parseInt(empleado_id), + entrada: entrada ? new Date(entrada) : null, + salida: salida ? new Date(salida) : null, + historial, // Assuming historial is already in JSON format or Prisma handles it + observacion, + estado, + fecha_anulado: fecha_anulado ? new Date(fecha_anulado) : null, + creador_id, // Should ideally be taken from authenticated user + modificado_id, // Should ideally be taken from authenticated user + anulador_id + }, + }); + res.status(201).json(nuevaAsistencia); + } catch (error) { + console.error(error); + if (error.code === 'P2003') { // Foreign key constraint failed + if (error.meta?.field_name?.includes('empleado_id')) { + return res.status(400).json({ error: 'El empleado_id proporcionado no existe.' }); + } + } + res.status(500).json({ error: 'Error al crear asistencia.' }); + } +}); + +// PUT update asistencia by ID +router.put('/:id', async (req, res) => { + const { id } = req.params; + const { empleado_id, entrada, salida, historial, observacion, estado, fecha_anulado, modificado_id, anulador_id } = req.body; + + try { + const updateData = { + entrada: entrada ? new Date(entrada) : undefined, + salida: salida ? new Date(salida) : undefined, + historial, + observacion, + estado, + fecha_anulado: fecha_anulado ? new Date(fecha_anulado) : undefined, + modificado_id, // Should ideally be taken from authenticated user + anulador_id + }; + + // If empleado_id is provided, include it in updateData. + // Be cautious: changing empleado_id might not be a typical operation for an existing attendance record. + if (empleado_id !== undefined) { + updateData.empleado_id = parseInt(empleado_id); + } + + const asistenciaActualizada = await prisma.asistencia.update({ + where: { id: parseInt(id) }, + data: updateData, + }); + res.json(asistenciaActualizada); + } catch (error) { + console.error(error); + if (error.code === 'P2025') { // Record to update not found + return res.status(404).json({ error: 'Asistencia no encontrada para actualizar.' }); + } + if (error.code === 'P2003') { // Foreign key constraint failed + if (error.meta?.field_name?.includes('empleado_id')) { + return res.status(400).json({ error: 'El empleado_id proporcionado no existe.' }); + } + } + res.status(500).json({ error: 'Error al actualizar asistencia.' }); + } +}); + +// DELETE asistencia by ID +router.delete('/:id', async (req, res) => { + const { id } = req.params; + try { + await prisma.asistencia.delete({ + where: { id: parseInt(id) }, + }); + res.status(204).send(); // No content + } catch (error) { + console.error(error); + if (error.code === 'P2025') { // Record to delete not found + return res.status(404).json({ error: 'Asistencia no encontrada para eliminar.' }); + } + res.status(500).json({ error: 'Error al eliminar asistencia.' }); + } +}); + +export default router; diff --git a/api/routes/empleados/.gitkeep b/api/routes/empleados/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/api/routes/empleados/empleados.js b/api/routes/empleados/empleados.js new file mode 100644 index 0000000..b69673f --- /dev/null +++ b/api/routes/empleados/empleados.js @@ -0,0 +1,142 @@ +import express from 'express'; +const router = express.Router(); +import { PrismaClient } from '../../prisma/generated/client/index.js'; +const prisma = new PrismaClient(); + +// GET all empleados +router.get('/', async (req, res) => { + try { + const empleados = await prisma.cliente.findMany({ + where: { empleado: true }, + }); + res.json(empleados); + } catch (error) { + console.error(error); // Log the error for debugging + res.status(500).json({ error: 'Error al obtener empleados.' }); + } +}); + +// GET empleado by ID +router.get('/:id', async (req, res) => { + const { id } = req.params; + try { + const empleado = await prisma.cliente.findFirst({ + where: { + id: parseInt(id), + empleado: true + }, + }); + if (empleado) { + res.json(empleado); + } else { + res.status(404).json({ error: 'Empleado no encontrado.' }); + } + } catch (error) { + console.error(error); // Log the error for debugging + res.status(500).json({ error: 'Error al obtener empleado.' }); + } +}); + +// POST create new empleado +router.post('/', async (req, res) => { + const { nombre, apellido, dni, telefono, direccion, email } = req.body; + try { + const nuevoEmpleado = await prisma.cliente.create({ + data: { + nombre, + apellido, + dni, + telefono, + direccion, + email, + empleado: true, // Ensure empleado is set to true + }, + }); + res.status(201).json(nuevoEmpleado); + } catch (error) { + console.error(error); // Log the error for debugging + if (error.code === 'P2002' && error.meta?.target?.includes('dni')) { + return res.status(400).json({ error: 'Ya existe un cliente con este DNI.' }); + } + if (error.code === 'P2002' && error.meta?.target?.includes('email')) { + return res.status(400).json({ error: 'Ya existe un cliente con este Email.' }); + } + res.status(500).json({ error: 'Error al crear empleado.' }); + } +}); + +// PUT update empleado by ID +router.put('/:id', async (req, res) => { + const { id } = req.params; + const { nombre, apellido, dni, telefono, direccion, email } = req.body; + try { + // First, check if the employee exists and is an employee + const existingEmpleado = await prisma.cliente.findFirst({ + where: { + id: parseInt(id), + empleado: true, + }, + }); + + if (!existingEmpleado) { + return res.status(404).json({ error: 'Empleado no encontrado.' }); + } + + const empleadoActualizado = await prisma.cliente.update({ + where: { id: parseInt(id) }, + data: { + nombre, + apellido, + dni, + telefono, + direccion, + email, + // empleado: true, // Keep it as an employee, or allow changing this? For now, keep as true. + }, + }); + res.json(empleadoActualizado); + } catch (error) { + console.error(error); // Log the error for debugging + if (error.code === 'P2002' && error.meta?.target?.includes('dni')) { + return res.status(400).json({ error: 'Ya existe un cliente con este DNI.' }); + } + if (error.code === 'P2002' && error.meta?.target?.includes('email')) { + return res.status(400).json({ error: 'Ya existe un cliente con este Email.' }); + } + if (error.code === 'P2025') { // Record to update not found + return res.status(404).json({ error: 'Empleado no encontrado para actualizar.' }); + } + res.status(500).json({ error: 'Error al actualizar empleado.' }); + } +}); + +// DELETE empleado by ID +router.delete('/:id', async (req, res) => { + const { id } = req.params; + try { + // First, check if the employee exists and is an employee + const existingEmpleado = await prisma.cliente.findFirst({ + where: { + id: parseInt(id), + empleado: true, + }, + }); + + if (!existingEmpleado) { + return res.status(404).json({ error: 'Empleado no encontrado para eliminar.' }); + } + + await prisma.cliente.delete({ + where: { id: parseInt(id) }, + }); + res.status(204).send(); // No content + } catch (error) { + console.error(error); // Log the error for debugging + if (error.code === 'P2025') { // Record to delete not found + return res.status(404).json({ error: 'Empleado no encontrado para eliminar.' }); + } + res.status(500).json({ error: 'Error al eliminar empleado.' }); + } +}); + +export default router; diff --git a/api/routes/planillas/.gitkeep b/api/routes/planillas/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/api/routes/planillas/planillas.js b/api/routes/planillas/planillas.js new file mode 100644 index 0000000..22609ba --- /dev/null +++ b/api/routes/planillas/planillas.js @@ -0,0 +1,142 @@ +import express from 'express'; +const router = express.Router(); +import { PrismaClient } from '../../prisma/generated/client/index.js'; +const prisma = new PrismaClient(); + +// GET all planillas +router.get('/', async (req, res) => { + try { + const planillas = await prisma.planilla.findMany(); + res.json(planillas); + } catch (error) { + console.error(error); + res.status(500).json({ error: 'Error al obtener planillas.' }); + } +}); + +// GET planilla by ID +router.get('/:id', async (req, res) => { + const { id } = req.params; + try { + const planilla = await prisma.planilla.findUnique({ + where: { id: parseInt(id) }, + }); + if (planilla) { + res.json(planilla); + } else { + res.status(404).json({ error: 'Planilla no encontrada.' }); + } + } catch (error) { + console.error(error); + res.status(500).json({ error: 'Error al obtener planilla.' }); + } +}); + +// POST create new planilla +router.post('/', async (req, res) => { + const { + empleado_id, + fecha_desde, + fecha_hasta, + titulo, + total, + estado, + fecha_anulado, + creador_id, // Should ideally be from authenticated user + anulador_id, + } = req.body; + + try { + // Basic validation + if (!empleado_id || !fecha_desde || !fecha_hasta || !titulo) { + return res.status(400).json({ error: 'Los campos empleado_id, fecha_desde, fecha_hasta y titulo son obligatorios.' }); + } + + const nuevaPlanilla = await prisma.planilla.create({ + data: { + empleado_id: parseInt(empleado_id), + fecha_desde: new Date(fecha_desde), + fecha_hasta: new Date(fecha_hasta), + titulo, + total: total ? parseFloat(total) : null, // Prisma expects Decimal to be passed as number or string + estado: estado || 'pagado', // Default to 'pagado' if not provided + fecha_anulado: fecha_anulado ? new Date(fecha_anulado) : null, + creador_id, + anulador_id, + }, + }); + res.status(201).json(nuevaPlanilla); + } catch (error) { + console.error(error); + if (error.code === 'P2003') { // Foreign key constraint failed + if (error.meta?.field_name?.includes('empleado_id')) { + return res.status(400).json({ error: 'El empleado_id proporcionado no existe.' }); + } + } + res.status(500).json({ error: 'Error al crear planilla.' }); + } +}); + +// PUT update planilla by ID +router.put('/:id', async (req, res) => { + const { id } = req.params; + const { + empleado_id, + fecha_desde, + fecha_hasta, + titulo, + total, + estado, + fecha_anulado, + anulador_id, + } = req.body; + + try { + const updateData = {}; + if (empleado_id !== undefined) updateData.empleado_id = parseInt(empleado_id); + if (fecha_desde !== undefined) updateData.fecha_desde = new Date(fecha_desde); + if (fecha_hasta !== undefined) updateData.fecha_hasta = new Date(fecha_hasta); + if (titulo !== undefined) updateData.titulo = titulo; + if (total !== undefined) updateData.total = total ? parseFloat(total) : null; + if (estado !== undefined) updateData.estado = estado; + if (fecha_anulado !== undefined) updateData.fecha_anulado = fecha_anulado ? new Date(fecha_anulado) : null; + if (anulador_id !== undefined) updateData.anulador_id = anulador_id; + // creador_id is typically not updated. + + const planillaActualizada = await prisma.planilla.update({ + where: { id: parseInt(id) }, + data: updateData, + }); + res.json(planillaActualizada); + } catch (error) { + console.error(error); + if (error.code === 'P2025') { // Record to update not found + return res.status(404).json({ error: 'Planilla no encontrada para actualizar.' }); + } + if (error.code === 'P2003') { // Foreign key constraint failed + if (error.meta?.field_name?.includes('empleado_id')) { + return res.status(400).json({ error: 'El empleado_id proporcionado no existe.' }); + } + } + res.status(500).json({ error: 'Error al actualizar planilla.' }); + } +}); + +// DELETE planilla by ID +router.delete('/:id', async (req, res) => { + const { id } = req.params; + try { + await prisma.planilla.delete({ + where: { id: parseInt(id) }, + }); + res.status(204).send(); // No content + } catch (error) { + console.error(error); + if (error.code === 'P2025') { // Record to delete not found + return res.status(404).json({ error: 'Planilla no encontrada para eliminar.' }); + } + res.status(500).json({ error: 'Error al eliminar planilla.' }); + } +}); + +export default router; diff --git a/api/routes/tareas/.gitkeep b/api/routes/tareas/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/api/routes/tareas/tareas.js b/api/routes/tareas/tareas.js new file mode 100644 index 0000000..6440589 --- /dev/null +++ b/api/routes/tareas/tareas.js @@ -0,0 +1,156 @@ +import express from 'express'; +const router = express.Router(); +import { PrismaClient } from '../../prisma/generated/client/index.js'; +const prisma = new PrismaClient(); + +// GET all tareas +router.get('/', async (req, res) => { + try { + const tareas = await prisma.tareaRealizada.findMany(); + res.json(tareas); + } catch (error) { + console.error(error); + res.status(500).json({ error: 'Error al obtener tareas.' }); + } +}); + +// GET tarea by ID +router.get('/:id', async (req, res) => { + const { id } = req.params; + try { + const tarea = await prisma.tareaRealizada.findUnique({ + where: { id: parseInt(id) }, + }); + if (tarea) { + res.json(tarea); + } else { + res.status(404).json({ error: 'Tarea no encontrada.' }); + } + } catch (error) { + console.error(error); + res.status(500).json({ error: 'Error al obtener tarea.' }); + } +}); + +// POST create new tarea +router.post('/', async (req, res) => { + const { + empleado_id, + planilla_id, + titulo, + precio, + estado, + observacion, + fecha, + tipo, + fecha_anulado, + creador_id, // Should ideally be from authenticated user + anulador_id, + } = req.body; + + try { + // Basic validation + if (!empleado_id || !titulo || !fecha) { + return res.status(400).json({ error: 'Los campos empleado_id, titulo y fecha son obligatorios.' }); + } + + const nuevaTarea = await prisma.tareaRealizada.create({ + data: { + empleado_id: parseInt(empleado_id), + planilla_id: planilla_id ? parseInt(planilla_id) : null, + titulo, + precio: precio ? parseFloat(precio) : null, + estado: estado || 'pendiente', // Default to 'pendiente' if not provided + observacion, + fecha: new Date(fecha), + tipo: tipo || '', // Default to empty string if not provided + fecha_anulado: fecha_anulado ? new Date(fecha_anulado) : null, + creador_id, + anulador_id, + }, + }); + res.status(201).json(nuevaTarea); + } catch (error) { + console.error(error); + if (error.code === 'P2003') { // Foreign key constraint failed + if (error.meta?.field_name?.includes('empleado_id')) { + return res.status(400).json({ error: 'El empleado_id proporcionado no existe.' }); + } + if (error.meta?.field_name?.includes('planilla_id')) { + return res.status(400).json({ error: 'El planilla_id proporcionado no existe.' }); + } + } + res.status(500).json({ error: 'Error al crear tarea.' }); + } +}); + +// PUT update tarea by ID +router.put('/:id', async (req, res) => { + const { id } = req.params; + const { + empleado_id, + planilla_id, + titulo, + precio, + estado, + observacion, + fecha, + tipo, + fecha_anulado, + anulador_id, + } = req.body; + + try { + const updateData = {}; + if (empleado_id !== undefined) updateData.empleado_id = parseInt(empleado_id); + if (planilla_id !== undefined) updateData.planilla_id = planilla_id ? parseInt(planilla_id) : null; + if (titulo !== undefined) updateData.titulo = titulo; + if (precio !== undefined) updateData.precio = precio ? parseFloat(precio) : null; + if (estado !== undefined) updateData.estado = estado; + if (observacion !== undefined) updateData.observacion = observacion; + if (fecha !== undefined) updateData.fecha = new Date(fecha); + if (tipo !== undefined) updateData.tipo = tipo; + if (fecha_anulado !== undefined) updateData.fecha_anulado = fecha_anulado ? new Date(fecha_anulado) : null; + if (anulador_id !== undefined) updateData.anulador_id = anulador_id; + // creador_id is typically not updated. + + const tareaActualizada = await prisma.tareaRealizada.update({ + where: { id: parseInt(id) }, + data: updateData, + }); + res.json(tareaActualizada); + } catch (error) { + console.error(error); + if (error.code === 'P2025') { // Record to update not found + return res.status(404).json({ error: 'Tarea no encontrada para actualizar.' }); + } + if (error.code === 'P2003') { // Foreign key constraint failed + if (error.meta?.field_name?.includes('empleado_id')) { + return res.status(400).json({ error: 'El empleado_id proporcionado no existe.' }); + } + if (error.meta?.field_name?.includes('planilla_id')) { + return res.status(400).json({ error: 'El planilla_id proporcionado no existe.' }); + } + } + res.status(500).json({ error: 'Error al actualizar tarea.' }); + } +}); + +// DELETE tarea by ID +router.delete('/:id', async (req, res) => { + const { id } = req.params; + try { + await prisma.tareaRealizada.delete({ + where: { id: parseInt(id) }, + }); + res.status(204).send(); // No content + } catch (error) { + console.error(error); + if (error.code === 'P2025') { // Record to delete not found + return res.status(404).json({ error: 'Tarea no encontrada para eliminar.' }); + } + res.status(500).json({ error: 'Error al eliminar tarea.' }); + } +}); + +export default router; diff --git a/api/server.js b/api/server.js index 028f854..0dcef90 100644 --- a/api/server.js +++ b/api/server.js @@ -1,6 +1,13 @@ import express from 'express'; import { PrismaClient } from './prisma/generated/client/index.js'; import { Decimal } from '@prisma/client/runtime/library.js'; + +// Import new routers +import empleadosRouter from './routes/empleados/empleados.js'; +import asistenciasRouter from './routes/asistencias/asistencias.js'; +import tareasRouter from './routes/tareas/tareas.js'; +import planillasRouter from './routes/planillas/planillas.js'; + BigInt.prototype.toJSON = function () { return this.toString(); }; Decimal.prototype.toJSON = function () { return this.toString(); }; @@ -8,6 +15,12 @@ const prisma = new PrismaClient(); export const app = express(); app.use(express.json()); +// Mount new routers +app.use('/api/empleados', empleadosRouter); +app.use('/api/asistencias', asistenciasRouter); +app.use('/api/tareas', tareasRouter); +app.use('/api/planillas', planillasRouter); + app.get('/api/test', (req, res) => res.json({ message: 'Hello World' })); app.post('/api/clientes/random', async (_req, res) => {