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.
This commit is contained in:
google-labs-jules[bot]
2025-05-30 06:45:54 +00:00
parent 2c43538db3
commit a394c25245
12 changed files with 695 additions and 629 deletions

176
api/node_modules/.package-lock.json generated vendored
View File

@@ -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"
},

556
api/package-lock.json generated
View File

@@ -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-cron": "^4.0.5",
"pg": "^8.8.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"
"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"
},

View File

@@ -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"
}
}

View File

View File

@@ -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;

View File

View File

@@ -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;

View File

View File

@@ -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;

View File

156
api/routes/tareas/tareas.js Normal file
View File

@@ -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;

View File

@@ -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) => {