From 3c5b3b4c1e5416df8ed4df26f8df8a86e9cd3cb6 Mon Sep 17 00:00:00 2001 From: natxocc Date: Fri, 17 Apr 2026 19:26:02 +0200 Subject: [PATCH] Firts Upload --- .vscode/settings.json | 39 +++ bun.lock | 336 ++++++++++++++++++++++ client/index.html | 14 + client/package.json | 20 ++ client/public/App.js | 247 ++++++++++++++++ client/public/app.css | 38 +++ client/public/geist.woff2 | Bin 0 -> 12544 bytes client/public/jakarta.woff2 | Bin 0 -> 11816 bytes client/public/main.js | 4 + client/vite.config.js | 16 ++ package.json | 12 + server/actions/db.actions.js | 52 ++++ server/actions/soap.actions.js | 138 +++++++++ server/api/auth.js | 74 +++++ server/api/db.js | 132 +++++++++ server/api/mail.js | 33 +++ server/api/soap.js | 61 ++++ server/index.js | 41 +++ server/lib/schema.json | 458 ++++++++++++++++++++++++++++++ server/package.json | 18 ++ server/scripts/generate-schema.js | 74 +++++ server/services/db.service.js | 135 +++++++++ server/services/mail.service.js | 47 +++ server/services/soap.service.js | 112 ++++++++ server/services/soap2.service.js | 151 ++++++++++ 25 files changed, 2252 insertions(+) create mode 100644 .vscode/settings.json create mode 100644 bun.lock create mode 100644 client/index.html create mode 100644 client/package.json create mode 100644 client/public/App.js create mode 100644 client/public/app.css create mode 100644 client/public/geist.woff2 create mode 100644 client/public/jakarta.woff2 create mode 100644 client/public/main.js create mode 100644 client/vite.config.js create mode 100644 package.json create mode 100644 server/actions/db.actions.js create mode 100644 server/actions/soap.actions.js create mode 100644 server/api/auth.js create mode 100644 server/api/db.js create mode 100644 server/api/mail.js create mode 100644 server/api/soap.js create mode 100644 server/index.js create mode 100644 server/lib/schema.json create mode 100644 server/package.json create mode 100644 server/scripts/generate-schema.js create mode 100644 server/services/db.service.js create mode 100644 server/services/mail.service.js create mode 100644 server/services/soap.service.js create mode 100644 server/services/soap2.service.js diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..958a96f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,39 @@ +{ + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.wordWrapColumn": 150, + "editor.formatOnSave": true, + + /* --- FORZAR PRETTIER PARA JAVASCRIPT --- */ + "[javascript]": { + "editor.defaultFormatter": "vscode.typescript-language-features", + "editor.suggest.insertMode": "replace" + }, + + /* --- CONFIGURACIÓN DE PRETTIER --- */ + "prettier.printWidth": 150, + "prettier.semi": true, + "prettier.singleQuote": false, + "prettier.bracketSameLine": true, + + /* ESTO ES CLAVE: Evita que Prettier colapse o rompa espacios raros en tus html`` */ + "prettier.htmlWhitespaceSensitivity": "ignore", + + /* --- LO QUE YA TENÍAS (MANTENER) --- */ + "files.associations": { + "*.js": "javascript" + }, + "emmet.includeLanguages": { + "javascript": "html" + }, + "emmet.triggerExpansionOnTab": true, + + "tailwindCSS.experimental.classRegex": [ + ["html`([^`]*?)`", "class=\"([^\"]*)\""], + ["html`([^`]*?)`", "class='([^']*)'"], + ["html`([^`]*?)`", "class=([^\\s\\/>]+)"] + ], + + "editor.quickSuggestions": { + "strings": true + } +} diff --git a/bun.lock b/bun.lock new file mode 100644 index 0000000..dfe7f02 --- /dev/null +++ b/bun.lock @@ -0,0 +1,336 @@ +{ + "lockfileVersion": 1, + "configVersion": 1, + "workspaces": { + "": { + "name": "dare", + }, + "client": { + "name": "dare-client", + "version": "2.0.0", + "dependencies": { + "@tailwindcss/vite": "^4.2.1", + }, + "devDependencies": { + "@iconify/json": "^2.2.443", + "@iconify/tailwind4": "^1.2.1", + "vite": "^8.0.0", + }, + }, + "server": { + "name": "dare-server", + "version": "2.0.0", + "dependencies": { + "hono": "^4.12.7", + "mariadb": "^3.5.2", + "nodemailer": "^8.0.2", + "sharp": "^0.34.5", + }, + }, + }, + "packages": { + "@antfu/install-pkg": ["@antfu/install-pkg@1.1.0", "", { "dependencies": { "package-manager-detector": "^1.3.0", "tinyexec": "^1.0.1" } }, "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ=="], + + "@cyberalien/svg-utils": ["@cyberalien/svg-utils@1.2.9", "", { "dependencies": { "@iconify/types": "^2.0.0" } }, "sha512-bd5I3TQ2k/xqcNB6P6GpFKeid3OgqgGSRz704+XHoGNBAsI7wwYKS6nuxAn26ciUtRjGKovfEy66ryEY9UGUwQ=="], + + "@emnapi/core": ["@emnapi/core@1.9.2", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA=="], + + "@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="], + + "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="], + + "@iconify/json": ["@iconify/json@2.2.463", "", { "dependencies": { "@iconify/types": "*", "pathe": "^2.0.3" } }, "sha512-VZ0n+99OWe9677b04KPF0NajDbFEyWNxMalXZA/4j8HrqyVvY+N1XN/EIER4ceQlKQJ501w9UxLJZjZ5mga0xA=="], + + "@iconify/tailwind4": ["@iconify/tailwind4@1.2.3", "", { "dependencies": { "@iconify/tools": "^5.0.5", "@iconify/types": "^2.0.0", "@iconify/utils": "^3.1.0" }, "peerDependencies": { "tailwindcss": ">= 4.0.0" } }, "sha512-z8SKiMHRASJKF/IY//87MF88lcB7ulxh8vlhQXXLWsBkNtOh6ese9R41MyGpQeqXdRvQVt+/fX2glQtHFjQ+MA=="], + + "@iconify/tools": ["@iconify/tools@5.0.11", "", { "dependencies": { "@cyberalien/svg-utils": "^1.2.8", "@iconify/types": "^2.0.0", "@iconify/utils": "^3.1.0", "fflate": "^0.8.2", "modern-tar": "^0.7.6", "pathe": "^2.0.3", "svgo": "^4.0.1" } }, "sha512-zur/06/zTSflUSoPARK5FfHNZQ9UYsoloPDQHLAZHbQqWhs0/tXS+KB70uOAt94dUB1F94JOkSqIOT2R4Deixg=="], + + "@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="], + + "@iconify/utils": ["@iconify/utils@3.1.0", "", { "dependencies": { "@antfu/install-pkg": "^1.1.0", "@iconify/types": "^2.0.0", "mlly": "^1.8.0" } }, "sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw=="], + + "@img/colour": ["@img/colour@1.1.0", "", {}, "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ=="], + + "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.2.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w=="], + + "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.2.4" }, "os": "darwin", "cpu": "x64" }, "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw=="], + + "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.2.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g=="], + + "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.2.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg=="], + + "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.2.4", "", { "os": "linux", "cpu": "arm" }, "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A=="], + + "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw=="], + + "@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.2.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA=="], + + "@img/sharp-libvips-linux-riscv64": ["@img/sharp-libvips-linux-riscv64@1.2.4", "", { "os": "linux", "cpu": "none" }, "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA=="], + + "@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.2.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ=="], + + "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw=="], + + "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw=="], + + "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg=="], + + "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.2.4" }, "os": "linux", "cpu": "arm" }, "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw=="], + + "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg=="], + + "@img/sharp-linux-ppc64": ["@img/sharp-linux-ppc64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-ppc64": "1.2.4" }, "os": "linux", "cpu": "ppc64" }, "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA=="], + + "@img/sharp-linux-riscv64": ["@img/sharp-linux-riscv64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-riscv64": "1.2.4" }, "os": "linux", "cpu": "none" }, "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw=="], + + "@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.2.4" }, "os": "linux", "cpu": "s390x" }, "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg=="], + + "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ=="], + + "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg=="], + + "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q=="], + + "@img/sharp-wasm32": ["@img/sharp-wasm32@0.34.5", "", { "dependencies": { "@emnapi/runtime": "^1.7.0" }, "cpu": "none" }, "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw=="], + + "@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g=="], + + "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg=="], + + "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.5", "", { "os": "win32", "cpu": "x64" }, "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw=="], + + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], + + "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], + + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], + + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], + + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + + "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.4", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow=="], + + "@oxc-project/types": ["@oxc-project/types@0.124.0", "", {}, "sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg=="], + + "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0-rc.15", "", { "os": "android", "cpu": "arm64" }, "sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA=="], + + "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.0-rc.15", "", { "os": "darwin", "cpu": "arm64" }, "sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg=="], + + "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.0-rc.15", "", { "os": "darwin", "cpu": "x64" }, "sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw=="], + + "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.0-rc.15", "", { "os": "freebsd", "cpu": "x64" }, "sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw=="], + + "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.15", "", { "os": "linux", "cpu": "arm" }, "sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA=="], + + "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.0-rc.15", "", { "os": "linux", "cpu": "arm64" }, "sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w=="], + + "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.0-rc.15", "", { "os": "linux", "cpu": "arm64" }, "sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ=="], + + "@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.15", "", { "os": "linux", "cpu": "ppc64" }, "sha512-VDpgGBzgfg5hLg+uBpCLoFG5kVvEyafmfxGUV0UHLcL5irxAK7PKNeC2MwClgk6ZAiNhmo9FLhRYgvMmedLtnQ=="], + + "@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.0.0-rc.15", "", { "os": "linux", "cpu": "s390x" }, "sha512-y1uXY3qQWCzcPgRJATPSOUP4tCemh4uBdY7e3EZbVwCJTY3gLJWnQABgeUetvED+bt1FQ01OeZwvhLS2bpNrAQ=="], + + "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.0-rc.15", "", { "os": "linux", "cpu": "x64" }, "sha512-023bTPBod7J3Y/4fzAN6QtpkSABR0rigtrwaP+qSEabUh5zf6ELr9Nc7GujaROuPY3uwdSIXWrvhn1KxOvurWA=="], + + "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.0-rc.15", "", { "os": "linux", "cpu": "x64" }, "sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw=="], + + "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.0.0-rc.15", "", { "os": "none", "cpu": "arm64" }, "sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg=="], + + "@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.0-rc.15", "", { "dependencies": { "@emnapi/core": "1.9.2", "@emnapi/runtime": "1.9.2", "@napi-rs/wasm-runtime": "^1.1.3" }, "cpu": "none" }, "sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q=="], + + "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.0-rc.15", "", { "os": "win32", "cpu": "arm64" }, "sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA=="], + + "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.0-rc.15", "", { "os": "win32", "cpu": "x64" }, "sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g=="], + + "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.15", "", {}, "sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g=="], + + "@tailwindcss/node": ["@tailwindcss/node@4.2.2", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.19.0", "jiti": "^2.6.1", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.2.2" } }, "sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA=="], + + "@tailwindcss/oxide": ["@tailwindcss/oxide@4.2.2", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.2.2", "@tailwindcss/oxide-darwin-arm64": "4.2.2", "@tailwindcss/oxide-darwin-x64": "4.2.2", "@tailwindcss/oxide-freebsd-x64": "4.2.2", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.2", "@tailwindcss/oxide-linux-arm64-gnu": "4.2.2", "@tailwindcss/oxide-linux-arm64-musl": "4.2.2", "@tailwindcss/oxide-linux-x64-gnu": "4.2.2", "@tailwindcss/oxide-linux-x64-musl": "4.2.2", "@tailwindcss/oxide-wasm32-wasi": "4.2.2", "@tailwindcss/oxide-win32-arm64-msvc": "4.2.2", "@tailwindcss/oxide-win32-x64-msvc": "4.2.2" } }, "sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg=="], + + "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.2.2", "", { "os": "android", "cpu": "arm64" }, "sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg=="], + + "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.2.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg=="], + + "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.2.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw=="], + + "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.2.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ=="], + + "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2", "", { "os": "linux", "cpu": "arm" }, "sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ=="], + + "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.2.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw=="], + + "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.2.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag=="], + + "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.2.2", "", { "os": "linux", "cpu": "x64" }, "sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg=="], + + "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.2.2", "", { "os": "linux", "cpu": "x64" }, "sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ=="], + + "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.2.2", "", { "dependencies": { "@emnapi/core": "^1.8.1", "@emnapi/runtime": "^1.8.1", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.1.1", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.8.1" }, "cpu": "none" }, "sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q=="], + + "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.2.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ=="], + + "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.2.2", "", { "os": "win32", "cpu": "x64" }, "sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA=="], + + "@tailwindcss/vite": ["@tailwindcss/vite@4.2.2", "", { "dependencies": { "@tailwindcss/node": "4.2.2", "@tailwindcss/oxide": "4.2.2", "tailwindcss": "4.2.2" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7 || ^8" } }, "sha512-mEiF5HO1QqCLXoNEfXVA1Tzo+cYsrqV7w9Juj2wdUFyW07JRenqMG225MvPwr3ZD9N1bFQj46X7r33iHxLUW0w=="], + + "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], + + "@types/geojson": ["@types/geojson@7946.0.16", "", {}, "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg=="], + + "@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="], + + "acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="], + + "boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="], + + "commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="], + + "confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], + + "css-select": ["css-select@5.2.2", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", "domhandler": "^5.0.2", "domutils": "^3.0.1", "nth-check": "^2.0.1" } }, "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw=="], + + "css-tree": ["css-tree@3.2.1", "", { "dependencies": { "mdn-data": "2.27.1", "source-map-js": "^1.2.1" } }, "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA=="], + + "css-what": ["css-what@6.2.2", "", {}, "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="], + + "csso": ["csso@5.0.5", "", { "dependencies": { "css-tree": "~2.2.0" } }, "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ=="], + + "dare-client": ["dare-client@workspace:client"], + + "dare-server": ["dare-server@workspace:server"], + + "denque": ["denque@2.1.0", "", {}, "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw=="], + + "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], + + "dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="], + + "domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="], + + "domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="], + + "domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="], + + "enhanced-resolve": ["enhanced-resolve@5.20.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.0" } }, "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA=="], + + "entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], + + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + + "fflate": ["fflate@0.8.2", "", {}, "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="], + + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + + "hono": ["hono@4.12.14", "", {}, "sha512-am5zfg3yu6sqn5yjKBNqhnTX7Cv+m00ox+7jbaKkrLMRJ4rAdldd1xPd/JzbBWspqaQv6RSTrgFN95EsfhC+7w=="], + + "iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="], + + "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], + + "lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="], + + "lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="], + + "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.32.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ=="], + + "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.32.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w=="], + + "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.32.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig=="], + + "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.32.0", "", { "os": "linux", "cpu": "arm" }, "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw=="], + + "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ=="], + + "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg=="], + + "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA=="], + + "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg=="], + + "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.32.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw=="], + + "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="], + + "lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + + "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], + + "mariadb": ["mariadb@3.5.2", "", { "dependencies": { "@types/geojson": "^7946.0.16", "@types/node": ">=18", "denque": "^2.1.0", "iconv-lite": "^0.7.2", "lru-cache": "^10.4.3" } }, "sha512-9rztrI4nouxAY/82a+RlzzZ5ie2vxu2eYclkBvTy1ATXH1B9cnvZ0O71Pzsy/mlfDb5P3HhOg0JzQKkDRhctyA=="], + + "mdn-data": ["mdn-data@2.27.1", "", {}, "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ=="], + + "mlly": ["mlly@1.8.2", "", { "dependencies": { "acorn": "^8.16.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "ufo": "^1.6.3" } }, "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA=="], + + "modern-tar": ["modern-tar@0.7.6", "", {}, "sha512-sweCIVXzx1aIGTCdzcMlSZt1h8k5Tmk08VNAuRk3IU28XamGiOH5ypi11g6De2CH7PhYqSSnGy2A/EFhbWnVKg=="], + + "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + + "nodemailer": ["nodemailer@8.0.5", "", {}, "sha512-0PF8Yb1yZuQfQbq+5/pZJrtF6WQcjTd5/S4JOHs9PGFxuTqoB/icwuB44pOdURHJbRKX1PPoJZtY7R4VUoCC8w=="], + + "nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="], + + "package-manager-detector": ["package-manager-detector@1.6.0", "", {}, "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA=="], + + "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], + + "pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], + + "postcss": ["postcss@8.5.10", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ=="], + + "rolldown": ["rolldown@1.0.0-rc.15", "", { "dependencies": { "@oxc-project/types": "=0.124.0", "@rolldown/pluginutils": "1.0.0-rc.15" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.0-rc.15", "@rolldown/binding-darwin-arm64": "1.0.0-rc.15", "@rolldown/binding-darwin-x64": "1.0.0-rc.15", "@rolldown/binding-freebsd-x64": "1.0.0-rc.15", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.15", "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.15", "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.15", "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.15", "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.15", "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.15", "@rolldown/binding-linux-x64-musl": "1.0.0-rc.15", "@rolldown/binding-openharmony-arm64": "1.0.0-rc.15", "@rolldown/binding-wasm32-wasi": "1.0.0-rc.15", "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.15", "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.15" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g=="], + + "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + + "sax": ["sax@1.6.0", "", {}, "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="], + + "semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], + + "sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="], + + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + + "svgo": ["svgo@4.0.1", "", { "dependencies": { "commander": "^11.1.0", "css-select": "^5.1.0", "css-tree": "^3.0.1", "css-what": "^6.1.0", "csso": "^5.0.5", "picocolors": "^1.1.1", "sax": "^1.5.0" }, "bin": "./bin/svgo.js" }, "sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w=="], + + "tailwindcss": ["tailwindcss@4.2.2", "", {}, "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q=="], + + "tapable": ["tapable@2.3.2", "", {}, "sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA=="], + + "tinyexec": ["tinyexec@1.1.1", "", {}, "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg=="], + + "tinyglobby": ["tinyglobby@0.2.16", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg=="], + + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "ufo": ["ufo@1.6.3", "", {}, "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="], + + "undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="], + + "vite": ["vite@8.0.8", "", { "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", "postcss": "^8.5.8", "rolldown": "1.0.0-rc.15", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.1.0", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw=="], + + "@rolldown/binding-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.9.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw=="], + + "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.9.2", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" }, "bundled": true }, "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA=="], + + "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="], + + "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="], + + "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.4", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" }, "bundled": true }, "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow=="], + + "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], + + "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "csso/css-tree": ["css-tree@2.2.1", "", { "dependencies": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" } }, "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA=="], + + "csso/css-tree/mdn-data": ["mdn-data@2.0.28", "", {}, "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g=="], + } +} diff --git a/client/index.html b/client/index.html new file mode 100644 index 0000000..1bfbb28 --- /dev/null +++ b/client/index.html @@ -0,0 +1,14 @@ + + + + + + + + SigPro + + +
+ + + diff --git a/client/package.json b/client/package.json new file mode 100644 index 0000000..2836511 --- /dev/null +++ b/client/package.json @@ -0,0 +1,20 @@ +{ + "name": "dare-client", + "version": "2.0.0", + "type": "module", + "scripts": { + "kill": "pkill -9 bun && pkill -9 node || true", + "del": "rm node_modules/.vite/deps -r", + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "@tailwindcss/vite": "^4.2.1" + }, + "devDependencies": { + "@iconify/json": "^2.2.443", + "@iconify/tailwind4": "^1.2.1", + "vite": "^8.0.0" + } +} \ No newline at end of file diff --git a/client/public/App.js b/client/public/App.js new file mode 100644 index 0000000..b1ea722 --- /dev/null +++ b/client/public/App.js @@ -0,0 +1,247 @@ +// App.js + +/** + * Vistas de la aplicación (pueden ir en archivos separados luego) + */ + +import { Navbar, Swap, Menu, Checkbox, Input, Button, Autocomplete, Datepicker, Colorpicker, Fileinput, Toast } from "sigpro-ui"; + +const toggle = $(false); +// const consoleToggle = $(()=>console.log(toggle())) +const Home = () => { + const valor = $("jjj"); + const miCheck = $(false); // Creamos la señal + return Div({ class: "gap-3 flex flex-col" }, [ + H1("Dashboard Principal"), + Button({ tooltip: "tooltip", badge: "22" }, "Hola"), + Input({ + label: "Correo Electrónico", + type: "email", + placeholder: "ejemplo@correo.com", + value: valor, // Binding automático + }), + Span({ class: "gap-4 text-4xl" }, () => valor()), + P("Bienvenido a la interfaz reactiva de SigPro. Aquí puedes ver el estado global."), + Checkbox({ tooltip: "Tooltip", toggle: toggle, value: miCheck, label: "Checkbox" }), + miCheck, + toggle, + Button( + { + class: "btn-primary", + onclick: () => { + Toast("Cambio de toggle"); + toggle(!toggle()); + }, + }, + "Lanzar Toast", + ), + ]); +}; + +const Profile = (params) => { + const miFecha = $(); + const miRango = $(); + const selectedFruit = $("Apple"); + const fruits = ["Apple", "Banana", "Cherry", "Dragonfruit", "Elderberry"]; + const colorFondo = $("#ef4444"); + const misArchivos = $([]); + + const textoInput = $(() => { + const f = miFecha; + if (!f.start) return ""; + return f.end ? `${f.start} - ${f.end}` : `${f.start}...`; + }); + + return Div({ class: "p-4 space-y-4" }, [ + H2({ class: "text-xl font-bold" }, `Perfil: ${params.id}`), + Autocomplete({ + label: "Selecciona una fruta", + value: selectedFruit, + options: fruits, + onSelect: (val) => console.log("Seleccionado:", val), + }), + Datepicker({ value: miFecha, label: "Fecha", placeholder: textoInput, hour: true }), + Datepicker({ value: miRango, label: "Fecha", placeholder: textoInput, range: true, hour: true }), + Colorpicker({ show: true, label: "Color del tema", value: colorFondo }), + Input({ type: "number", label: "Number" }), + Input({ type: "email", label: "Email" }), + Input({ label: "Text" }), + Input({ type: "date", label: "Date" }), + Input({ type: "password", label: "Password" }), + $html("p", {}, () => `Has elegido: ${selectedFruit()}`), + Fileinput({ + tooltip: "Formatos: PDF, JPG", + max: 5, + // Cada vez que la lista cambia, se dispara esto + onSelect: async (files) => { + if (files.length === 0) return; + + console.log("Subiendo archivos automáticamente...", files); + + const formData = new FormData(); + files.forEach((file) => formData.append("files[]", file)); + + // await fetch('/api/upload', { method: 'POST', body: formData }); + }, + }), + Div({ class: "pt-4" }, [ + Button( + { + class: "btn-sm btn-outline", + onclick: () => $router.to("/"), + }, + "Volver", + ), + ]), + ]); +}; +/** + * Componente Principal + */ +export const App = () => { + // Estado local de la App (ejemplo: tema o usuario) + const isDark = $(false, "sigpro-theme"); + + // Efecto para cambiar el tema en el HTML + $watch(() => { + document.documentElement.setAttribute("data-theme", isDark() ? "dark" : "light"); + }); + + const menuItems = [ + { label: "Inicio", onclick: () => $router.to("/") }, + { label: "Mi Perfil", onclick: () => $router.to("/profile/42") }, + { label: "Tareas TODO", onclick: () => $router.to("/todo") }, // <-- Nueva opción + { label: "Ajustes", onclick: () => Toast("Ajustes no disponibles", "alert-error") }, + ]; + + return Div({ class: "min-h-screen flex flex-col" }, [ + Navbar({ class: "sticky top-0 z-50 bg-base-100/80 backdrop-blur border-b border-base-300" }, [ + Div({ class: "flex-1" }, [ + A( + { + class: "btn btn-ghost text-xl font-black tracking-tighter", + onclick: () => $router.to("/"), + }, + "SIGPRO", + ), + ]), + Button({ disabled: true }, "Disabled"), + + Div({ class: "flex items-center gap-2" }, [ + Swap({ + class: "swap-rotate", + value: isDark, + on: "🌙", + off: "☀️", + }), + Button({ class: "btn-circle btn-ghost", icon: "👤" }), + ]), + ]), + + // --- LAYOUT PRINCIPAL --- + Div({ class: "flex flex-1" }, [ + // Sidebar Lateral + Aside({ class: "w-64 bg-base-200 p-4 hidden md:block" }, [Menu({ items: menuItems, class: "bg-transparent" })]), + + // Contenido Dinámico (Router) + Main({ class: "flex-1 p-6 bg-base-100" }, [ + $router([ + { path: "/", component: Home }, + { path: "/profile/:id", component: Profile }, + { path: "/todo", component: TodoPage }, + { + path: "*", + component: () => + Div({ class: "text-center py-20" }, [H1({ class: "text-9xl font-bold opacity-20" }, "404"), P("La página que buscas no existe.")]), + }, + ]), + ]), + ]), + + // --- FOOTER --- + Footer({ class: "footer footer-center p-4 bg-base-300 text-base-content text-xs" }, [P("© 2026 - Built with SigPro Engine")]), + ]); +}; + +const TodoPage = () => { + const newTask = $(""); + // Persistencia automática en localStorage gracias a tu Core + const tasks = $([], "sigpro-todo-list"); + + const addTask = () => { + const val = newTask().trim(); + if (!val) return Toast("Escribe algo...", "alert-warning"); + + tasks([...tasks(), { id: crypto.randomUUID(), text: val, done: false }]); + newTask(""); // Limpia el input + }; + + const removeTask = (id) => { + tasks(tasks().filter((t) => t.id !== id)); + }; + + const toggleTask = (id) => { + tasks(tasks().map((t) => (t.id === id ? { ...t, done: !t.done } : t))); + }; + + // Señal computada para el contador + const pendingCount = $(() => tasks().filter((t) => !t.done).length); + const misDatos = $([{ id: 1 }]); + return Div({ class: "max-w-md mx-auto space-y-6" }, [ + H1({ class: "text-3xl font-black italic" }, "TODO LIST"), + + // Input Group + Div({ class: "join w-full" }, [ + Input({ + class: "join-item w-full", + placeholder: "Nueva tarea...", + value: newTask, + onkeydown: (e) => e.key === "Enter" && addTask(), + }), + Button({ class: "btn-primary join-item", onclick: addTask }, "Añadir"), + ]), + + // Stats + Div({ class: "flex justify-between items-center opacity-70 text-sm" }, [ + Span(() => `Total: ${tasks().length}`), + Span({ class: "badge badge-secondary" }, () => `${pendingCount()} pendientes`), + ]), + + // Lista Reactiva (Aquí evaluamos tu append con sweep) + Ul({ class: "menu bg-base-200 rounded-box w-full p-2" }, () => + tasks().length === 0 + ? Li({ class: "p-4 text-center opacity-50" }, "No hay tareas pendientes") + : tasks().map((task) => + Li({ class: "flex flex-row items-center gap-2 p-2 border-b border-base-300 last:border-0" }, [ + Checkbox({ + class: "checkbox-sm", + value: () => task.done, + onclick: () => toggleTask(task.id), + }), + Span( + { + class: `flex-1 ${task.done ? "line-through opacity-40" : ""}`, + onclick: () => toggleTask(task.id), + }, + task.text, + ), + Button( + { + class: "btn-ghost btn-xs text-error", + onclick: () => removeTask(task.id), + }, + "✕", + ), + ]), + ), + ), + + Button( + { + class: "btn-link btn-xs text-error p-0", + onclick: () => tasks([]), + }, + "Limpiar todo", + ), + ]); +}; diff --git a/client/public/app.css b/client/public/app.css new file mode 100644 index 0000000..ad9598d --- /dev/null +++ b/client/public/app.css @@ -0,0 +1,38 @@ +@import "tailwindcss"; +@plugin "@iconify/tailwind4"; +@plugin "daisyui" { + themes: + light --default, + dark --prefersdark; + include: + alert, avatar, badge, button, card, checkbox, collapse, drawer, dropdown, fab, fieldset, loading, indicator, input, kbd, label, list, menu, modal, + navbar, radio, range, select, skeleton, tab, textarea, toast, toggle, tooltip, validator, rating, mask, swap; +} + +@font-face { + font-family: "Plus Jakarta Sans"; + src: url("/jakarta.woff2") format("woff2"); + font-weight: normal; + font-style: normal; + font-display: swap; +} + +:root { + font-size: 14px; + /* font-family: "Plus Jakarta Sans", ui-sans-serif, system-ui, sans-serif; */ +} + +.btn-ghost { + border-color: transparent !important; +} + +.floating-label > span { + font-size: 1.2rem; +} + +@utility input { + @apply transition-all duration-300 ease-in-out outline-none shrink appearance-none items-center; + &:hover { + background-color: var(--color-base-300); + } +} diff --git a/client/public/geist.woff2 b/client/public/geist.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..b189a1bc716c16fbecbd13709421b2eab4ff9ef6 GIT binary patch literal 12544 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 W1JXMkR+{v6;?0MgVJ-sL0RR9*@9)h3 literal 0 HcmV?d00001 diff --git a/client/public/jakarta.woff2 b/client/public/jakarta.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..954c272b5018e4e561e029e334bcb6373d812ad2 GIT binary patch literal 11816 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 { + // Si el id viene vacío o es 0, lo eliminamos para que MariaDB genere uno nuevo (AUTO_INCREMENT) + if (!data.id) delete data.id; + + const result = await db.upsert(table, data); + + // Normalizamos la respuesta del driver de MariaDB + const res = Array.isArray(result) ? result[0] : result; + + // Obtenemos el ID: o bien el que ya venía en data, o el nuevo generado por el insert + const idToFetch = data.id || res?.insertId; + + if (!idToFetch) throw new Error("No se pudo determinar el ID del registro"); + + // Devolvemos el registro fresco (útil si usamos una 'view' con campos calculados) + return db.one(view || table, { id: idToFetch }); + }, + + /** + * Elimina un registro por ID + */ + _del: async (db, { table, id }) => { + if (!id) throw new Error("ID requerido para eliminar"); + return db.delete(table, { id }); + }, + + /** + * Obtiene todos los clientes (compatibilidad con ClientesOld) + */ + Clientes: async (db) => { + return db.select('ClientesOld'); + }, + Recibos: async (db) => { + return db.select('Recibos'); + }, + + /** + * Búsqueda avanzada usando parámetros nombrados (raw query) + */ + Search: async (db, { text }) => { + const query = 'SELECT * FROM ClientesOld WHERE Cliente LIKE :term OR NIF LIKE :term'; + const params = { term: `%${text}%` }; + return db.raw(query, params); + } +}; \ No newline at end of file diff --git a/server/actions/soap.actions.js b/server/actions/soap.actions.js new file mode 100644 index 0000000..edc68a5 --- /dev/null +++ b/server/actions/soap.actions.js @@ -0,0 +1,138 @@ +import schemaDataRaw from '../lib/schema.json' assert { type: 'json' }; + +// El schema se usa para validar qué columnas existen realmente en la DB +const schemaData = schemaDataRaw; + +/** + * Formatea fechas a estándar ISO (YYYY-MM-DD) para MariaDB + */ +const fmt = (d) => + (d instanceof Date && !isNaN(d.getTime()) ? d.toISOString().split('T')[0] : null); + +/** + * Filtra y limpia las columnas según el schema.json + */ +const filterColumns = (tableName, rowData) => { + const schema = schemaData[tableName]; + if (!schema) return rowData; + + return Object.keys(rowData).reduce((cleanRow, col) => { + const colDef = schema[col]; + if (!colDef) return cleanRow; // Si la columna no existe en el JSON, se ignora + + let val = rowData[col]; + const type = colDef.type || ''; // Usamos el campo 'type' generado por tu script anterior + + if (val != null) { + // Lógica de fechas + if (type.includes('date')) { + try { + const s = val.toString().trim(); + const isISO = val instanceof Date || s.includes('T'); + + val = isISO ? fmt(new Date(val)) : + /^\d{8}$/.test(s) ? `${s.slice(4, 8)}-${s.slice(2, 4)}-${s.slice(0, 2)}` : + s.includes('.') ? s.split('.').reverse().join('-') : s.slice(0, 10); + } catch { + val = null; + } + } + // Lógica de texto: trim y recorte por seguridad según definición + else if (type === 'text' && typeof val === 'string') { + val = val.trim().slice(0, 255); + } + } + cleanRow[col] = val; + return cleanRow; + }, {}); +}; + +/** + * Orquestador para guardar datos transformados de SOAP a DB + */ +const saveSoap = async (db, raw, config) => { + if (!raw || !raw.length) return 0; + + const rawArray = Array.isArray(raw) ? raw : [raw]; + + for (const [table, transform] of Object.entries(config)) { + const data = rawArray.flatMap(item => { + const res = transform ? transform(item) : item; + if (!res) return []; + + return Array.isArray(res) + ? res.map(sub => filterColumns(table, sub)) + : [filterColumns(table, res)]; + }); + + if (data.length) { + await db.upsert(table, data, true); // true para INSERT IGNORE + } + } + return rawArray.length; +}; + +/** + * Acciones exportables para el motor TRX + * Estas funciones son llamadas dinámicamente según el nombre del servicio SOAP + */ +export const actions = { + DescargaCompletaRecibos: async (db, { data }) => { + const raw = data.ListaRecibos?.ReciboAmpliado || data || []; + const total = await saveSoap(db, raw, { 'Recibos': null, 'RecibosEstados': null }); + return { totalProcesado: total }; + }, + + DescargaCartera: async (db, { data }) => { + const raw = data.DatosCartera?.Cartera || data || []; + const total = await saveSoap(db, raw, { 'Cartera': null }); + return { totalProcesado: total }; + }, + + DescargaSiniestros: async (db, { data }) => { + const raw = data.ListaSiniestros?.SiniestroAmpliado || data || []; + const total = await saveSoap(db, raw, { 'Siniestros': null, 'SiniestrosEstados': null }); + return { totalProcesado: total }; + }, + + ConsultaAgendaTramitacion: async (db, { data }) => { + const raw = data.Datos?.DatosTramitacionResponse || data || []; + const total = await saveSoap(db, raw, { 'SiniestrosTramites': null }); + return { totalProcesado: total }; + }, + + DescargaPolizas: async (db, { data }) => { + const raw = data.ListaPolizas?.Poliza || data || []; + const total = await saveSoap(db, raw, { + 'Polizas': i => ({ + ...i.DatosGenerales, + Riesgo: [ + i.DatosAccidentes?.NombreAsegurado, + i.DatosAutos?.CodigoModelo && `${i.DatosAutos.CodigoModelo} ${i.DatosAutos.Matricula || ''}`.trim(), + i.DatosMultirriesgos?.SituacionRiesgo + ].filter(Boolean).join(' | ') + }), + 'PolizasDetalle': i => i.DatosGenerales + ? { ...i.DatosGenerales.DatosTomador, ...i.DatosGenerales, CodigoPoliza: i.DatosGenerales.CodigoPoliza, CodigoSuplemento: i.DatosGenerales.CodigoSuplemento } + : null, + 'PolizasAutos': i => i.DatosAutos?.CodigoModelo + ? { ...i.DatosAutos, CodigoPoliza: i.DatosGenerales.CodigoPoliza, CodigoSuplemento: i.DatosGenerales.CodigoSuplemento } + : null, + 'PolizasAutosConductor': i => { + const { CodigoPoliza, CodigoSuplemento } = i.DatosGenerales || {}; + const { DatosConductor: hab, DatosConductorOcasional: oca } = i.DatosAutos || {}; + return [ + hab?.Nombre ? { ...hab, CodigoPoliza, CodigoSuplemento, TipoConductor: 'Habitual' } : null, + oca?.Nombre ? { ...oca, CodigoPoliza, CodigoSuplemento, TipoConductor: 'Ocasional' } : null + ].filter(Boolean); + }, + 'PolizasMultirriesgos': i => i.DatosMultirriesgos + ? { ...i.DatosMultirriesgos, CodigoPoliza: i.DatosGenerales.CodigoPoliza, CodigoSuplemento: i.DatosGenerales.CodigoSuplemento } + : null, + 'PolizasAccidentes': i => i.DatosAccidentes + ? { ...i.DatosAccidentes, CodigoPoliza: i.DatosGenerales.CodigoPoliza, CodigoSuplemento: i.DatosGenerales.CodigoSuplemento } + : null + }); + return { totalProcesado: total }; + } +}; \ No newline at end of file diff --git a/server/api/auth.js b/server/api/auth.js new file mode 100644 index 0000000..7b88dc5 --- /dev/null +++ b/server/api/auth.js @@ -0,0 +1,74 @@ +import { Hono } from 'hono' +import { sign } from 'hono/jwt' +import { pool } from '../services/db.service.js' + +const auth = new Hono() + +// Configuración externa +const SYNO_BASE = 'http://192.168.1.100:5000/webapi/auth.cgi' +const JWT_SECRET = process.env.JWT_SECRET || 'cambia_esto_en_el_env' + +auth.post('/login', async (c) => { + const { username, password } = await c.req.json().catch(() => ({})) + + if (!username || !password) { + return c.json({ success: false, message: 'Faltan credenciales' }, 400) + } + + try { + // 1. Preparar parámetros para el NAS Synology + const params = new URLSearchParams({ + api: 'SYNO.API.Auth', + version: '6', + method: 'login', + account: username, + passwd: password, + format: 'sid' + }) + + // 2. Petición al NAS usando el fetch nativo + const response = await fetch(`${SYNO_BASE}?${params.toString()}`) + const data = await response.json() + + if (data.success && data.data) { + // 3. Generar JWT (expiración en 8 horas) + const payload = { + username, + sid: data.data.sid, + exp: Math.floor(Date.now() / 1000) + (60 * 60 * 8) + } + + const token = await sign(payload, JWT_SECRET) + + // 4. Asegurar el usuario en la base de datos (MariaDB) + try { + await pool.query('INSERT IGNORE INTO Usuarios (Usuario) VALUES (?)', [username]) + } catch (dbError) { + console.error('Error al registrar usuario en DB:', dbError) + } + + return c.json({ + success: true, + token, + data: { + user: { username } + } + }) + } + + // Error de autenticación del NAS + return c.json({ + success: false, + message: `Error de autenticación (Código: ${data.error?.code || 'unknown'})` + }, 401) + + } catch (error) { + console.error('Error crítico en Auth:', error) + return c.json({ + success: false, + message: 'NAS Unreachable / Internal Error' + }, 500) + } +}) + +export default auth \ No newline at end of file diff --git a/server/api/db.js b/server/api/db.js new file mode 100644 index 0000000..8f104b9 --- /dev/null +++ b/server/api/db.js @@ -0,0 +1,132 @@ +import { Hono } from 'hono' +import { jwt } from 'hono/jwt' +import { db, trx } from '../services/db.service.js' +import { actions } from '../actions/db.actions.js' +import sharp from 'sharp' +import path from 'path' +import mime from 'mime-types' + +const api = new Hono() + +const JWT_SECRET = process.env.JWT_SECRET || 'tu_clave_secreta' + +// --- MIDDLEWARE AUTH CON BYPASS --- +// api.use('/*', async (c, next) => { +// if (process.env.DISABLE_AUTH === 'true') { +// c.set('jwtPayload', { username: 'TEST_USER', role: 'admin' }) +// return await next() +// } +// const jwtMiddleware = jwt({ secret: JWT_SECRET, alg: 'HS256' }) +// return jwtMiddleware(c, next) +// }) + +// --- RUTA PARA TRANSACCIONES (TRX) --- +api.on(['GET', 'POST'], '/', async (c) => { + const body = c.req.method === 'POST' ? await c.req.json().catch(() => ({})) : {} + const query = c.req.query() + const postData = { ...query, ...body } + + if (Object.keys(postData).length === 0) { + return c.json({ success: false, error: 'No data provided' }, 400) + } + + try { + const data = await trx(postData, actions) + // Manejo de BigInt para evitar errores en JSON.stringify + const cleanData = JSON.parse(JSON.stringify(data, (_, v) => typeof v === 'bigint' ? v.toString() : v)) + return c.json({ success: true, data: cleanData }) + } catch (error) { + return c.json({ success: false, error: error.message }, 500) + } +}) + +// --- RUTA FICHAR --- +api.on(['GET', 'POST'], '/fichar/:query', async (c) => { + const payload = c.get('jwtPayload') + const user = payload?.username || 'ANONYMOUS' + const queryType = c.req.param('query') + + try { + const ret = queryType === 'nuevo' + ? await db.raw('CALL RegistrarFichaje(:user)', { user }) + : await db.raw('SELECT Fecha, Tipo, Duracion FROM UsuariosFichajes WHERE Usuario = :user ORDER BY id DESC LIMIT 1', { user }) + + return c.json({ success: true, data: ret }) + } catch (error) { + return c.json({ success: false, error: error.message }, 500) + } +}) + +// --- RUTA DE SUBIDA (UPLOAD) --- +api.post('/upload', async (c) => { + try { + const body = await c.req.parseBody() + const file = body.file + if (!file) throw new Error('No se ha enviado ningún archivo') + + const arrayBuffer = await file.arrayBuffer() + let finalBuffer = Buffer.from(arrayBuffer) + const isImg = file.type.startsWith('image/') + + if (isImg) { + finalBuffer = await sharp(finalBuffer) + .resize(1024, null, { withoutEnlargement: true }) + .jpeg({ quality: 75 }) + .toBuffer() + } + + const res = await db.insert('Documentos', { + CodigoPoliza: body.CodigoPoliza || null, + CodigoRecibo: body.CodigoRecibo ? BigInt(body.CodigoRecibo) : null, + CodigoSiniestro: body.CodigoSiniestro ? BigInt(body.CodigoSiniestro) : null, + NIF: body.NIF || null, + Nombre: file.name, + Extension: isImg ? '.jpg' : path.extname(file.name).toLowerCase(), + Archivo: finalBuffer + }) + + const insertId = Array.isArray(res) ? res[0].insertId : res?.insertId + return c.json({ success: true, id: insertId?.toString() }) + } catch (err) { + return c.json({ success: false, error: err.message }, 500) + } +}) + +// --- RUTA DE DESCARGA --- +api.get('/download', async (c) => { + try { + const { id, CodigoPoliza, CodigoRecibo, CodigoSiniestro, NIF, download } = c.req.query() + const filtros = Object.fromEntries( + Object.entries({ id, CodigoPoliza, CodigoRecibo, CodigoSiniestro, NIF }) + .filter(([_, v]) => v) + ) + + if (Object.keys(filtros).length === 0) return c.json({ success: false, error: 'Faltan parámetros' }, 400) + + const docs = await db.select('Documentos', filtros) + if (!docs.length) return c.json({ success: false, error: 'Sin resultados' }, 404) + + if (id) { + const doc = docs[0] + const contentType = mime.lookup(doc.Extension) || 'application/octet-stream' + c.header('Content-Type', contentType) + c.header('Content-Disposition', `${download === 'true' ? 'attachment' : 'inline'}; filename="${doc.Nombre}"`) + + return c.body(doc.Archivo) + } + + return c.json(docs.map((doc) => { + const { Archivo, ...info } = doc + return { + ...info, + id: info.id.toString(), + url: `/api/db/download?id=${info.id}`, + urlDownload: `/api/db/download?id=${info.id}&download=true` + } + })) + } catch (err) { + return c.json({ success: false, error: err.message }, 500) + } +}) + +export default api \ No newline at end of file diff --git a/server/api/mail.js b/server/api/mail.js new file mode 100644 index 0000000..f230e50 --- /dev/null +++ b/server/api/mail.js @@ -0,0 +1,33 @@ +import { Hono } from 'hono' +import { send } from '../services/mail.service.js' + +const mail = new Hono() + +/** + * Endpoint para envío de correo + * Soporta GET (para pruebas rápidas) y POST (para producción) + */ +mail.on(['GET', 'POST'], '/', async (c) => { + try { + // Llamamos al servicio de correo + // Nota: Aquí podrías extraer to, subject y html de c.req.json() o c.req.query() + await send( + 'natxocc@natxocc.com', + 'Prueba desde Hono', + '

Este es un correo de prueba

' + ) + + return c.json({ + success: true, + message: 'Email enviado correctamente' + }) + } catch (error) { + console.error('Error en ruta mail:', error) + return c.json({ + success: false, + error: error.message + }, 500) + } +}) + +export default mail \ No newline at end of file diff --git a/server/api/soap.js b/server/api/soap.js new file mode 100644 index 0000000..45b8fee --- /dev/null +++ b/server/api/soap.js @@ -0,0 +1,61 @@ +import { Hono } from 'hono' +import { soapCall } from '../services/soap2.service.js' + +const api = new Hono() + +/** + * Endpoint simplificado: /api/soap/12345/Polizas + * El servicio soapCall se encarga de traducir "Polizas" a "DescargaPolizas" + */ +api.get('/:CodigoMediador/:alias', async (c) => { + const params = c.req.param() // Contiene CodigoMediador y alias + const query = c.req.query() + + try { + // Pasamos params directamente porque soapCall ya sabe buscar el 'alias' + const result = await soapCall(params, query) + + return c.json({ + success: true, + data: result + }) + } catch (error) { + console.error(`[Router Error] ${params.alias}:`, error.message) + return c.json({ + success: false, + message: error.message || 'Error en el servicio externo SOAP' + }, 500) + } +}) + +export default api +/* +import { Hono } from 'hono' +import { soapCall } from '../services/soap2.service.js' + +const api = new Hono() + +api.get('/:CodigoMediador/:service/:method', async (c) => { + const params = c.req.param() + const query = c.req.query() + + try { + const result = await soapCall(params, query) + + return c.json({ + success: true, + message: false, + data: result + }) + } catch (error) { + console.error(`Error en llamada SOAP ${params.service}/${params.method}:`, error) + + return c.json({ + success: false, + message: error.message || 'Error en el servicio externo SOAP' + }, 500) + } +}) + +export default api +*/ \ No newline at end of file diff --git a/server/index.js b/server/index.js new file mode 100644 index 0000000..a9d6a5b --- /dev/null +++ b/server/index.js @@ -0,0 +1,41 @@ +import { Hono } from 'hono' +import { logger } from 'hono/logger' +import { cors } from 'hono/cors' +import { jwt } from 'hono/jwt' + +// Importación de APIs (Rutas) +import auth from './api/auth' +import db from './api/db' +import mail from './api/mail' +import soap from './api/soap' + +const app = new Hono() + +// --- Middlewares Globales --- +app.use('*', logger()) +app.use('*', cors()) + +// --- Gestión de Errores Global --- +app.onError((err, c) => { + console.error(`[Global Error]: ${err.message}`) + const status = err.name === 'JwtTokenInvalid' ? 401 : 500 + return c.json({ + success: false, + message: err.message || 'Internal Server Error' + }, status) +}) + +// --- Registro de Rutas --- +// Nota: La protección JWT ya la pusimos dentro de api/db.ts y api/soap.ts +// para permitir que auth y mail (quizás) sean públicos. +app.route('/api/auth', auth) +app.route('/api/db', db) +app.route('/api/mail', mail) +app.route('/api/soap', soap) + +// --- Servidor Bun --- +export default { + port: 3000, + fetch: app.fetch, + idleTimeout: 120, +} \ No newline at end of file diff --git a/server/lib/schema.json b/server/lib/schema.json new file mode 100644 index 0000000..9e265c7 --- /dev/null +++ b/server/lib/schema.json @@ -0,0 +1,458 @@ +{ + "Cartera": { + "CodigoPoliza": { "field": "CodigoPoliza", "header": "CODIGOPOLIZA", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "CodigoRecibo": { "field": "CodigoRecibo", "header": "CODIGORECIBO", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "CodigoGestor": { "field": "CodigoGestor", "header": "CODIGOGESTOR", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Contenido": { "field": "Contenido", "header": "CONTENIDO", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "Continente": { "field": "Continente", "header": "CONTINENTE", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaEfecto": { "field": "FechaEfecto", "header": "FECHAEFECTO", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaVencimiento": { "field": "FechaVencimiento", "header": "FECHAVENCIMIENTO", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "FormaPago": { "field": "FormaPago", "header": "FORMAPAGO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteBonificacion": { "field": "ImporteBonificacion", "header": "IMPORTEBONIFICACION", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteComision": { "field": "ImporteComision", "header": "IMPORTECOMISION", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteImpuestos": { "field": "ImporteImpuestos", "header": "IMPORTEIMPUESTOS", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteLiquido": { "field": "ImporteLiquido", "header": "IMPORTELIQUIDO", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteNeto": { "field": "ImporteNeto", "header": "IMPORTENETO", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteTotalRecibo": { "field": "ImporteTotalRecibo", "header": "IMPORTETOTALRECIBO", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "NombreTomador": { "field": "NombreTomador", "header": "NOMBRETOMADOR", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "RCGeneral": { "field": "RCGeneral", "header": "RCGENERAL", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "SubcodigoMediador": { "field": "SubcodigoMediador", "header": "SUBCODIGOMEDIADOR", "type": "text", "hide": false, "virt": false, "key": false, "editable": true } + }, + "Chat": { + "id": { "field": "id", "header": "ID", "type": "numeric", "hide": true, "virt": false, "key": "PK", "editable": false }, + "De": { "field": "De", "header": "DE", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Para": { "field": "Para", "header": "PARA", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Mensaje": { "field": "Mensaje", "header": "MENSAJE", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaMensaje": { "field": "FechaMensaje", "header": "FECHAMENSAJE", "type": "datetime", "hide": false, "virt": false, "key": false, "editable": true }, + "Leido": { "field": "Leido", "header": "LEIDO", "type": "boolean", "hide": false, "virt": false, "key": false, "editable": true }, + "Editado": { "field": "Editado", "header": "EDITADO", "type": "boolean", "hide": false, "virt": false, "key": false, "editable": true }, + "Eliminado": { "field": "Eliminado", "header": "ELIMINADO", "type": "boolean", "hide": false, "virt": false, "key": false, "editable": true } + }, + "Clientes": { + "id": { "field": "id", "header": "ID", "type": "numeric", "hide": true, "virt": false, "key": "PK", "editable": false }, + "Documento": { "field": "Documento", "header": "DOCUMENTO", "type": "text", "hide": false, "virt": false, "key": "UK", "editable": true }, + "Nombre": { "field": "Nombre", "header": "NOMBRE", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Apellidos": { "field": "Apellidos", "header": "APELLIDOS", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Cliente": { "field": "Cliente", "header": "CLIENTE", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Grupo": { "field": "Grupo", "header": "GRUPO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaNacimiento": { "field": "FechaNacimiento", "header": "FECHANACIMIENTO", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaCarnet": { "field": "FechaCarnet", "header": "FECHACARNET", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "EstadoCivil": { "field": "EstadoCivil", "header": "ESTADOCIVIL", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Profesion": { "field": "Profesion", "header": "PROFESION", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Hijos": { "field": "Hijos", "header": "HIJOS", "type": "text", "hide": false, "virt": false, "key": false, "editable": true } + }, + "ClientesCorreos": { + "Documento": { "field": "Documento", "header": "DOCUMENTO", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "Correo": { "field": "Correo", "header": "CORREO", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "Tipo": { "field": "Tipo", "header": "TIPO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true } + }, + "ClientesDirecciones": { + "Documento": { "field": "Documento", "header": "DOCUMENTO", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "Domicilio": { "field": "Domicilio", "header": "DOMICILIO", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "CodigoPostal": { "field": "CodigoPostal", "header": "CODIGOPOSTAL", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "Localidad": { "field": "Localidad", "header": "LOCALIDAD", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Provincia": { "field": "Provincia", "header": "PROVINCIA", "type": "text", "hide": false, "virt": false, "key": false, "editable": true } + }, + "ClientesOld": { + "id": { "field": "id", "header": "ID", "type": "numeric", "hide": true, "virt": false, "key": "PK", "editable": false }, + "Mediador": { "field": "Mediador", "header": "MEDIADOR", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "NIF": { "field": "NIF", "header": "NIF", "type": "text", "hide": false, "virt": false, "key": "FK", "editable": true }, + "Cliente": { "field": "Cliente", "header": "CLIENTE", "type": "text", "hide": false, "virt": false, "key": "FK", "editable": true }, + "Grupo": { "field": "Grupo", "header": "GRUPO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Correo": { "field": "Correo", "header": "CORREO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Correo2": { "field": "Correo2", "header": "CORREO2", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Fijo": { "field": "Fijo", "header": "FIJO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Movil": { "field": "Movil", "header": "MOVIL", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Movil2": { "field": "Movil2", "header": "MOVIL2", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "CP": { "field": "CP", "header": "CP", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Direccion": { "field": "Direccion", "header": "DIRECCION", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Poblacion": { "field": "Poblacion", "header": "POBLACION", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Provincia": { "field": "Provincia", "header": "PROVINCIA", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Banco": { "field": "Banco", "header": "BANCO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaNacimiento": { "field": "FechaNacimiento", "header": "FECHANACIMIENTO", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaCarnet": { "field": "FechaCarnet", "header": "FECHACARNET", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "EstadoCivil": { "field": "EstadoCivil", "header": "ESTADOCIVIL", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Profesion": { "field": "Profesion", "header": "PROFESION", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Hijos": { "field": "Hijos", "header": "HIJOS", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Promo": { "field": "Promo", "header": "PROMO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaPromo": { "field": "FechaPromo", "header": "FECHAPROMO", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaBienvenida": { "field": "FechaBienvenida", "header": "FECHABIENVENIDA", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "NoMolestar": { "field": "NoMolestar", "header": "NOMOLESTAR", "type": "boolean", "hide": false, "virt": false, "key": false, "editable": true }, + "Notas": { "field": "Notas", "header": "NOTAS", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaRegistro": { "field": "FechaRegistro", "header": "FECHAREGISTRO", "type": "datetime", "hide": false, "virt": false, "key": false, "editable": true }, + "SM": { "field": "SM", "header": "SM", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "upd": { "field": "upd", "header": "UPD", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Activo": { "field": "Activo", "header": "ACTIVO", "type": "boolean", "hide": false, "virt": false, "key": false, "editable": true }, + "MP": { "field": "MP", "header": "MP", "type": "text", "hide": false, "virt": false, "key": false, "editable": true } + }, + "ClientesTelefonos": { + "Documento": { "field": "Documento", "header": "DOCUMENTO", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "Telefono": { "field": "Telefono", "header": "TELEFONO", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "Tipo": { "field": "Tipo", "header": "TIPO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true } + }, + "Colaboradores": { + "SM": { "field": "SM", "header": "SM", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "CodigoMediador": { "field": "CodigoMediador", "header": "CODIGOMEDIADOR", "type": "numeric", "hide": false, "virt": false, "key": "PK", "editable": false }, + "CIF": { "field": "CIF", "header": "CIF", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Nombre": { "field": "Nombre", "header": "NOMBRE", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "ResponsableRecibos": { "field": "ResponsableRecibos", "header": "RESPONSABLERECIBOS", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "ResponsableSiniestros": { "field": "ResponsableSiniestros", "header": "RESPONSABLESINIESTROS", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "ResponsablePolizas": { "field": "ResponsablePolizas", "header": "RESPONSABLEPOLIZAS", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Cartera": { "field": "Cartera", "header": "CARTERA", "type": "boolean", "hide": false, "virt": false, "key": false, "editable": true }, + "Recibos": { "field": "Recibos", "header": "RECIBOS", "type": "boolean", "hide": false, "virt": false, "key": false, "editable": true }, + "Pro": { "field": "Pro", "header": "PRO", "type": "boolean", "hide": false, "virt": false, "key": false, "editable": true }, + "Activo": { "field": "Activo", "header": "ACTIVO", "type": "boolean", "hide": false, "virt": false, "key": false, "editable": true }, + "Porc": { "field": "Porc", "header": "PORC", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Fact": { "field": "Fact", "header": "FACT", "type": "boolean", "hide": false, "virt": false, "key": false, "editable": true }, + "IRPF": { "field": "IRPF", "header": "IRPF", "type": "boolean", "hide": false, "virt": false, "key": false, "editable": true }, + "Banco": { "field": "Banco", "header": "BANCO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Correo": { "field": "Correo", "header": "CORREO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Movil": { "field": "Movil", "header": "MOVIL", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Fijo": { "field": "Fijo", "header": "FIJO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Direccion": { "field": "Direccion", "header": "DIRECCION", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "CP": { "field": "CP", "header": "CP", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Notas": { "field": "Notas", "header": "NOTAS", "type": "text", "hide": false, "virt": false, "key": false, "editable": true } + }, + "Contactos": { + "Empresa": { "field": "Empresa", "header": "EMPRESA", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Seccion": { "field": "Seccion", "header": "SECCION", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Departamento": { "field": "Departamento", "header": "DEPARTAMENTO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Nombre": { "field": "Nombre", "header": "NOMBRE", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Fijo": { "field": "Fijo", "header": "FIJO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Movil": { "field": "Movil", "header": "MOVIL", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Fax": { "field": "Fax", "header": "FAX", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Correo": { "field": "Correo", "header": "CORREO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Correo2": { "field": "Correo2", "header": "CORREO2", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "CodigoMediador": { "field": "CodigoMediador", "header": "CODIGOMEDIADOR", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "Notas": { "field": "Notas", "header": "NOTAS", "type": "text", "hide": false, "virt": false, "key": false, "editable": true } + }, + "Correos": { + "id": { "field": "id", "header": "ID", "type": "numeric", "hide": true, "virt": false, "key": "PK", "editable": false }, + "id_config": { "field": "id_config", "header": "ID CONFIG", "type": "numeric", "hide": true, "virt": false, "key": "FK", "editable": false }, + "Asunto": { "field": "Asunto", "header": "ASUNTO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Cuerpo": { "field": "Cuerpo", "header": "CUERPO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaProgramada": { "field": "FechaProgramada", "header": "FECHAPROGRAMADA", "type": "datetime", "hide": false, "virt": false, "key": false, "editable": true }, + "Estado": { "field": "Estado", "header": "ESTADO", "type": "select", "hide": false, "virt": false, "key": false, "editable": true } + }, + "CorreosConfig": { + "id": { "field": "id", "header": "ID", "type": "numeric", "hide": true, "virt": false, "key": "PK", "editable": false }, + "Nombre": { "field": "Nombre", "header": "NOMBRE", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Frecuencia": { "field": "Frecuencia", "header": "FRECUENCIA", "type": "select", "hide": false, "virt": false, "key": false, "editable": true }, + "DiaSemana": { "field": "DiaSemana", "header": "DIASEMANA", "type": "boolean", "hide": false, "virt": false, "key": false, "editable": true }, + "DiaMes": { "field": "DiaMes", "header": "DIAMES", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "HoraEnvio": { "field": "HoraEnvio", "header": "HORAENVIO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Cron": { "field": "Cron", "header": "CRON", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "id_plantilla": { "field": "id_plantilla", "header": "ID PLANTILLA", "type": "numeric", "hide": true, "virt": false, "key": "FK", "editable": false }, + "Activo": { "field": "Activo", "header": "ACTIVO", "type": "boolean", "hide": false, "virt": false, "key": false, "editable": true } + }, + "CorreosDestinatarios": { + "id": { "field": "id", "header": "ID", "type": "numeric", "hide": true, "virt": false, "key": "PK", "editable": false }, + "id_correo": { "field": "id_correo", "header": "ID CORREO", "type": "numeric", "hide": true, "virt": false, "key": "FK", "editable": false }, + "id_cliente": { "field": "id_cliente", "header": "ID CLIENTE", "type": "numeric", "hide": true, "virt": false, "key": false, "editable": false }, + "EmailDestino": { "field": "EmailDestino", "header": "EMAILDESTINO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaEnviado": { "field": "FechaEnviado", "header": "FECHAENVIADO", "type": "datetime", "hide": false, "virt": false, "key": false, "editable": true }, + "ErrorLog": { "field": "ErrorLog", "header": "ERRORLOG", "type": "text", "hide": false, "virt": false, "key": false, "editable": true } + }, + "CorreosPlantillas": { + "id": { "field": "id", "header": "ID", "type": "numeric", "hide": true, "virt": false, "key": "PK", "editable": false }, + "Nombre": { "field": "Nombre", "header": "NOMBRE", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "AsuntoBase": { "field": "AsuntoBase", "header": "ASUNTOBASE", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "ContenidoHtml": { "field": "ContenidoHtml", "header": "CONTENIDOHTML", "type": "text", "hide": false, "virt": false, "key": false, "editable": true } + }, + "Documentos": { + "id": { "field": "id", "header": "ID", "type": "numeric", "hide": true, "virt": false, "key": "PK", "editable": false }, + "CodigoPoliza": { "field": "CodigoPoliza", "header": "CODIGOPOLIZA", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "CodigoRecibo": { "field": "CodigoRecibo", "header": "CODIGORECIBO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "CodigoSiniestro": { "field": "CodigoSiniestro", "header": "CODIGOSINIESTRO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "NIF": { "field": "NIF", "header": "NIF", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaRegistro": { "field": "FechaRegistro", "header": "FECHAREGISTRO", "type": "datetime", "hide": false, "virt": false, "key": false, "editable": true }, + "Nombre": { "field": "Nombre", "header": "NOMBRE", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Extension": { "field": "Extension", "header": "EXTENSION", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Archivo": { "field": "Archivo", "header": "ARCHIVO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true } + }, + "Empresas": { + "Empresa": { "field": "Empresa", "header": "EMPRESA", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "CIF": { "field": "CIF", "header": "CIF", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Direccion": { "field": "Direccion", "header": "DIRECCION", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Notas": { "field": "Notas", "header": "NOTAS", "type": "text", "hide": false, "virt": false, "key": false, "editable": true } + }, + "Etiquetas": { + "id": { "field": "id", "header": "ID", "type": "numeric", "hide": true, "virt": false, "key": "PK", "editable": false }, + "Etiqueta": { "field": "Etiqueta", "header": "ETIQUETA", "type": "text", "hide": false, "virt": false, "key": "FK", "editable": true }, + "Tabla": { "field": "Tabla", "header": "TABLA", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Nombre": { "field": "Nombre", "header": "NOMBRE", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Color": { "field": "Color", "header": "COLOR", "type": "text", "hide": false, "virt": false, "key": false, "editable": true } + }, + "Grupos": { + "Grupo": { "field": "Grupo", "header": "GRUPO", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "CodigoMediador": { "field": "CodigoMediador", "header": "CODIGOMEDIADOR", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "Detalle": { "field": "Detalle", "header": "DETALLE", "type": "text", "hide": false, "virt": false, "key": false, "editable": true } + }, + "Liquidaciones": { + "id": { "field": "id", "header": "ID", "type": "numeric", "hide": true, "virt": false, "key": "PK", "editable": false }, + "CodigoMediador": { "field": "CodigoMediador", "header": "CODIGOMEDIADOR", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "CodigoPoliza": { "field": "CodigoPoliza", "header": "CODIGOPOLIZA", "type": "text", "hide": false, "virt": false, "key": "FK", "editable": true }, + "CodigoRecibo": { "field": "CodigoRecibo", "header": "CODIGORECIBO", "type": "text", "hide": false, "virt": false, "key": "FK", "editable": true }, + "FechaRegistro": { "field": "FechaRegistro", "header": "FECHAREGISTRO", "type": "date", "hide": false, "virt": false, "key": "FK", "editable": true }, + "FechaEfecto": { "field": "FechaEfecto", "header": "FECHAEFECTO", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "Detalle": { "field": "Detalle", "header": "DETALLE", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "NumLiq": { "field": "NumLiq", "header": "NUMLIQ", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "id_cuenta_Origen": { "field": "id_cuenta_Origen", "header": "ID CUENTA ORIGEN", "type": "numeric", "hide": true, "virt": false, "key": "FK", "editable": false }, + "id_cuenta_Destino": { "field": "id_cuenta_Destino", "header": "ID CUENTA DESTINO", "type": "numeric", "hide": true, "virt": false, "key": "FK", "editable": false }, + "Importe": { "field": "Importe", "header": "IMPORTE", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "Usuario": { "field": "Usuario", "header": "USUARIO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Validado": { "field": "Validado", "header": "VALIDADO", "type": "boolean", "hide": false, "virt": false, "key": false, "editable": true }, + "Liquidado": { "field": "Liquidado", "header": "LIQUIDADO", "type": "boolean", "hide": false, "virt": false, "key": false, "editable": true } + }, + "LiquidacionesCuentas": { + "id": { "field": "id", "header": "ID", "type": "numeric", "hide": true, "virt": false, "key": "PK", "editable": false }, + "CodigoMediador": { "field": "CodigoMediador", "header": "CODIGOMEDIADOR", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "Cuenta": { "field": "Cuenta", "header": "CUENTA", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Activo": { "field": "Activo", "header": "ACTIVO", "type": "boolean", "hide": false, "virt": false, "key": false, "editable": true }, + "Tipo": { "field": "Tipo", "header": "TIPO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true } + }, + "LiquidacionesMovimientos": { + "id": { "field": "id", "header": "ID", "type": "numeric", "hide": true, "virt": false, "key": "PK", "editable": false }, + "id_liquidacion": { "field": "id_liquidacion", "header": "ID LIQUIDACION", "type": "numeric", "hide": true, "virt": false, "key": "FK", "editable": false }, + "id_cuenta": { "field": "id_cuenta", "header": "ID CUENTA", "type": "numeric", "hide": true, "virt": false, "key": "FK", "editable": false }, + "Importe": { "field": "Importe", "header": "IMPORTE", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "Accion": { "field": "Accion", "header": "ACCION", "type": "select", "hide": false, "virt": false, "key": false, "editable": true }, + "CodigoPoliza": { "field": "CodigoPoliza", "header": "CODIGOPOLIZA", "type": "text", "hide": false, "virt": false, "key": "FK", "editable": true }, + "CodigoRecibo": { "field": "CodigoRecibo", "header": "CODIGORECIBO", "type": "text", "hide": false, "virt": false, "key": "FK", "editable": true }, + "Detalle": { "field": "Detalle", "header": "DETALLE", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaRegistro": { "field": "FechaRegistro", "header": "FECHAREGISTRO", "type": "datetime", "hide": false, "virt": false, "key": "FK", "editable": true } + }, + "Mediadores": { + "CodigoMediador": { "field": "CodigoMediador", "header": "CODIGOMEDIADOR", "type": "numeric", "hide": false, "virt": false, "key": "PK", "editable": false }, + "Descripcion": { "field": "Descripcion", "header": "DESCRIPCION", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Domicilio": { "field": "Domicilio", "header": "DOMICILIO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "CodigoPostal": { "field": "CodigoPostal", "header": "CODIGOPOSTAL", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "Localidad": { "field": "Localidad", "header": "LOCALIDAD", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Provincia": { "field": "Provincia", "header": "PROVINCIA", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Correo": { "field": "Correo", "header": "CORREO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Telefono": { "field": "Telefono", "header": "TELEFONO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Whatsapp": { "field": "Whatsapp", "header": "WHATSAPP", "type": "text", "hide": false, "virt": false, "key": false, "editable": true } + }, + "Oportunidades": { + "id": { "field": "id", "header": "ID", "type": "numeric", "hide": true, "virt": false, "key": "PK", "editable": false }, + "id_cliente": { "field": "id_cliente", "header": "ID CLIENTE", "type": "numeric", "hide": true, "virt": false, "key": "FK", "editable": false }, + "id_estado": { "field": "id_estado", "header": "ID ESTADO", "type": "numeric", "hide": true, "virt": false, "key": "FK", "editable": false }, + "id_usuario": { "field": "id_usuario", "header": "ID USUARIO", "type": "numeric", "hide": true, "virt": false, "key": "FK", "editable": false }, + "Empresa": { "field": "Empresa", "header": "EMPRESA", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaVencimiento": { "field": "FechaVencimiento", "header": "FECHAVENCIMIENTO", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "Riesgo": { "field": "Riesgo", "header": "RIESGO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Importe": { "field": "Importe", "header": "IMPORTE", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "Pago": { "field": "Pago", "header": "PAGO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaCreacion": { "field": "FechaCreacion", "header": "FECHACREACION", "type": "datetime", "hide": false, "virt": false, "key": false, "editable": true }, + "UltimaActualizacion": { "field": "UltimaActualizacion", "header": "ULTIMAACTUALIZACION", "type": "datetime", "hide": false, "virt": false, "key": false, "editable": true } + }, + "OportunidadesSeguimiento": { + "id": { "field": "id", "header": "ID", "type": "numeric", "hide": true, "virt": false, "key": "PK", "editable": false }, + "id_oportunidad": { "field": "id_oportunidad", "header": "ID OPORTUNIDAD", "type": "numeric", "hide": true, "virt": false, "key": "FK", "editable": false }, + "id_usuario": { "field": "id_usuario", "header": "ID USUARIO", "type": "numeric", "hide": true, "virt": false, "key": "FK", "editable": false }, + "id_responsable": { "field": "id_responsable", "header": "ID RESPONSABLE", "type": "numeric", "hide": true, "virt": false, "key": false, "editable": false }, + "id_estado_ant": { "field": "id_estado_ant", "header": "ID ESTADO ANT", "type": "numeric", "hide": true, "virt": false, "key": "FK", "editable": false }, + "id_estado_act": { "field": "id_estado_act", "header": "ID ESTADO ACT", "type": "numeric", "hide": true, "virt": false, "key": "FK", "editable": false }, + "Fecha": { "field": "Fecha", "header": "FECHA", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "Accion": { "field": "Accion", "header": "ACCION", "type": "text", "hide": false, "virt": false, "key": false, "editable": true } + }, + "Polizas": { + "CodigoPoliza": { "field": "CodigoPoliza", "header": "CODIGOPOLIZA", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "CodigoMediador": { "field": "CodigoMediador", "header": "CODIGOMEDIADOR", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaAlta": { "field": "FechaAlta", "header": "FECHAALTA", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaBaja": { "field": "FechaBaja", "header": "FECHABAJA", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "Riesgo": { "field": "Riesgo", "header": "RIESGO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Ramo": { "field": "Ramo", "header": "RAMO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Modalidad": { "field": "Modalidad", "header": "MODALIDAD", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "GestorCobroInicial": { "field": "GestorCobroInicial", "header": "GESTORCOBROINICIAL", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "VigorSucursal": { "field": "VigorSucursal", "header": "VIGORSUCURSAL", "type": "boolean", "hide": false, "virt": false, "key": false, "editable": true } + }, + "PolizasAccidentes": { + "CodigoPoliza": { "field": "CodigoPoliza", "header": "CODIGOPOLIZA", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "CodigoSuplemento": { "field": "CodigoSuplemento", "header": "CODIGOSUPLEMENTO", "type": "numeric", "hide": false, "virt": false, "key": "PK", "editable": false }, + "DocumentoAsegurado": { "field": "DocumentoAsegurado", "header": "DOCUMENTOASEGURADO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaNacimientoAsegurado": { "field": "FechaNacimientoAsegurado", "header": "FECHANACIMIENTOASEGURADO", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteIncapacidadTemporal": { "field": "ImporteIncapacidadTemporal", "header": "IMPORTEINCAPACIDADTEMPORAL", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteInvalidezPorAccidente": { "field": "ImporteInvalidezPorAccidente", "header": "IMPORTEINVALIDEZPORACCIDENTE", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteInvalidezPorInfarto": { "field": "ImporteInvalidezPorInfarto", "header": "IMPORTEINVALIDEZPORINFARTO", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteMuertePorInfarto": { "field": "ImporteMuertePorInfarto", "header": "IMPORTEMUERTEPORINFARTO", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "Invalidez": { "field": "Invalidez", "header": "INVALIDEZ", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Muerte": { "field": "Muerte", "header": "MUERTE", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "NombreAsegurado": { "field": "NombreAsegurado", "header": "NOMBREASEGURADO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "NumeroAsegurados": { "field": "NumeroAsegurados", "header": "NUMEROASEGURADOS", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "TipoInvalidez": { "field": "TipoInvalidez", "header": "TIPOINVALIDEZ", "type": "text", "hide": false, "virt": false, "key": false, "editable": true } + }, + "PolizasAutos": { + "CodigoPoliza": { "field": "CodigoPoliza", "header": "CODIGOPOLIZA", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "CodigoSuplemento": { "field": "CodigoSuplemento", "header": "CODIGOSUPLEMENTO", "type": "numeric", "hide": false, "virt": false, "key": "PK", "editable": false }, + "BonusDP": { "field": "BonusDP", "header": "BONUSDP", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "BonusRC": { "field": "BonusRC", "header": "BONUSRC", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "CodigoModelo": { "field": "CodigoModelo", "header": "CODIGOMODELO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "CodigoModeloBase7": { "field": "CodigoModeloBase7", "header": "CODIGOMODELOBASE7", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Matricula": { "field": "Matricula", "header": "MATRICULA", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Remolque": { "field": "Remolque", "header": "REMOLQUE", "type": "boolean", "hide": false, "virt": false, "key": false, "editable": true } + }, + "PolizasAutosConductor": { + "CodigoPoliza": { "field": "CodigoPoliza", "header": "CODIGOPOLIZA", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "CodigoSuplemento": { "field": "CodigoSuplemento", "header": "CODIGOSUPLEMENTO", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "Documento": { "field": "Documento", "header": "DOCUMENTO", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "TipoConductor": { "field": "TipoConductor", "header": "TIPOCONDUCTOR", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "FechaCarnet": { "field": "FechaCarnet", "header": "FECHACARNET", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaNacimiento": { "field": "FechaNacimiento", "header": "FECHANACIMIENTO", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "Nombre": { "field": "Nombre", "header": "NOMBRE", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Sexo": { "field": "Sexo", "header": "SEXO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true } + }, + "PolizasDetalle": { + "CodigoPoliza": { "field": "CodigoPoliza", "header": "CODIGOPOLIZA", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "CodigoSuplemento": { "field": "CodigoSuplemento", "header": "CODIGOSUPLEMENTO", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "CodigoRecibo": { "field": "CodigoRecibo", "header": "CODIGORECIBO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "CodigoRiesgo": { "field": "CodigoRiesgo", "header": "CODIGORIESGO", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "DatosBancarios": { "field": "DatosBancarios", "header": "DATOSBANCARIOS", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Nombre": { "field": "Nombre", "header": "NOMBRE", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Apellidos": { "field": "Apellidos", "header": "APELLIDOS", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Documento": { "field": "Documento", "header": "DOCUMENTO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Domicilio": { "field": "Domicilio", "header": "DOMICILIO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Localidad": { "field": "Localidad", "header": "LOCALIDAD", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "CodigoPostal": { "field": "CodigoPostal", "header": "CODIGOPOSTAL", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "Provincia": { "field": "Provincia", "header": "PROVINCIA", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaEfectoSuplemento": { "field": "FechaEfectoSuplemento", "header": "FECHAEFECTOSUPLEMENTO", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaEquipo": { "field": "FechaEquipo", "header": "FECHAEQUIPO", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaVencimientoSuplemento": { "field": "FechaVencimientoSuplemento", "header": "FECHAVENCIMIENTOSUPLEMENTO", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "FormaPago": { "field": "FormaPago", "header": "FORMAPAGO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "GestorCobro": { "field": "GestorCobro", "header": "GESTORCOBRO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteBonificacionAnualSuplemento": { "field": "ImporteBonificacionAnualSuplemento", "header": "IMPORTEBONIFICACIONANUALSUPLEMENTO", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteBonificacionRecibo": { "field": "ImporteBonificacionRecibo", "header": "IMPORTEBONIFICACIONRECIBO", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteComisionAnualSuplemento": { "field": "ImporteComisionAnualSuplemento", "header": "IMPORTECOMISIONANUALSUPLEMENTO", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteComisionRecibo": { "field": "ImporteComisionRecibo", "header": "IMPORTECOMISIONRECIBO", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteImpuestosAnualSuplemento": { "field": "ImporteImpuestosAnualSuplemento", "header": "IMPORTEIMPUESTOSANUALSUPLEMENTO", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteImpuestosRecibo": { "field": "ImporteImpuestosRecibo", "header": "IMPORTEIMPUESTOSRECIBO", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteLiquidoAnualSuplemento": { "field": "ImporteLiquidoAnualSuplemento", "header": "IMPORTELIQUIDOANUALSUPLEMENTO", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteLiquidoRecibo": { "field": "ImporteLiquidoRecibo", "header": "IMPORTELIQUIDORECIBO", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteNetoAnualSuplemento": { "field": "ImporteNetoAnualSuplemento", "header": "IMPORTENETOANUALSUPLEMENTO", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteNetoRecibo": { "field": "ImporteNetoRecibo", "header": "IMPORTENETORECIBO", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteTotalAnualSuplemento": { "field": "ImporteTotalAnualSuplemento", "header": "IMPORTETOTALANUALSUPLEMENTO", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteTotalRecibo": { "field": "ImporteTotalRecibo", "header": "IMPORTETOTALRECIBO", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteNeto": { "field": "ImporteNeto", "header": "IMPORTENETO", "type": "numeric", "hide": false, "virt": true, "key": false, "editable": false }, + "TipoInformacion": { "field": "TipoInformacion", "header": "TIPOINFORMACION", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "SubCodigoMediador": { "field": "SubCodigoMediador", "header": "SUBCODIGOMEDIADOR", "type": "text", "hide": false, "virt": false, "key": false, "editable": true } + }, + "PolizasMultirriesgos": { + "CodigoPoliza": { "field": "CodigoPoliza", "header": "CODIGOPOLIZA", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "CodigoSuplemento": { "field": "CodigoSuplemento", "header": "CODIGOSUPLEMENTO", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "DocumentoAsegurado": { "field": "DocumentoAsegurado", "header": "DOCUMENTOASEGURADO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteContenido": { "field": "ImporteContenido", "header": "IMPORTECONTENIDO", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteContinente": { "field": "ImporteContinente", "header": "IMPORTECONTINENTE", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteRC": { "field": "ImporteRC", "header": "IMPORTERC", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "NombreAsegurado": { "field": "NombreAsegurado", "header": "NOMBREASEGURADO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "SituacionRiesgo": { "field": "SituacionRiesgo", "header": "SITUACIONRIESGO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true } + }, + "Recibos": { + "CodigoPoliza": { "field": "CodigoPoliza", "header": "CODIGOPOLIZA", "type": "text", "hide": false, "virt": false, "key": "FK", "editable": true }, + "CodigoRecibo": { "field": "CodigoRecibo", "header": "CODIGORECIBO", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "CodigoEmpresa": { "field": "CodigoEmpresa", "header": "CODIGOEMPRESA", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaEfecto": { "field": "FechaEfecto", "header": "FECHAEFECTO", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "Importe": { "field": "Importe", "header": "IMPORTE", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true } + }, + "RecibosEstados": { + "CodigoRecibo": { "field": "CodigoRecibo", "header": "CODIGORECIBO", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "Situacion": { "field": "Situacion", "header": "SITUACION", "type": "date", "hide": false, "virt": false, "key": "PK", "editable": false }, + "Estado": { "field": "Estado", "header": "ESTADO", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "NombreTomador": { "field": "NombreTomador", "header": "NOMBRETOMADOR", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "AutoLiquidacion": { "field": "AutoLiquidacion", "header": "AUTOLIQUIDACION", "type": "boolean", "hide": false, "virt": false, "key": false, "editable": true }, + "CodigoGestor": { "field": "CodigoGestor", "header": "CODIGOGESTOR", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "CodigoMediador": { "field": "CodigoMediador", "header": "CODIGOMEDIADOR", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "CodigoRiesgo": { "field": "CodigoRiesgo", "header": "CODIGORIESGO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "DescripcionGestor": { "field": "DescripcionGestor", "header": "DESCRIPCIONGESTOR", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Divisa": { "field": "Divisa", "header": "DIVISA", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaVencimiento": { "field": "FechaVencimiento", "header": "FECHAVENCIMIENTO", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "FormaPago": { "field": "FormaPago", "header": "FORMAPAGO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteBonificacion": { "field": "ImporteBonificacion", "header": "IMPORTEBONIFICACION", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteComision": { "field": "ImporteComision", "header": "IMPORTECOMISION", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteIRPF": { "field": "ImporteIRPF", "header": "IMPORTEIRPF", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteImpuestos": { "field": "ImporteImpuestos", "header": "IMPORTEIMPUESTOS", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "ImporteNeto": { "field": "ImporteNeto", "header": "IMPORTENETO", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "SubCodigoMediador": { "field": "SubCodigoMediador", "header": "SUBCODIGOMEDIADOR", "type": "text", "hide": false, "virt": false, "key": false, "editable": true } + }, + "Siniestros": { + "CodigoSiniestro": { "field": "CodigoSiniestro", "header": "CODIGOSINIESTRO", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "CodigoPoliza": { "field": "CodigoPoliza", "header": "CODIGOPOLIZA", "type": "text", "hide": false, "virt": false, "key": "FK", "editable": true }, + "CodigoMediador": { "field": "CodigoMediador", "header": "CODIGOMEDIADOR", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "CodigoEmpresa": { "field": "CodigoEmpresa", "header": "CODIGOEMPRESA", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "CodigoSuplemento": { "field": "CodigoSuplemento", "header": "CODIGOSUPLEMENTO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Descripcion": { "field": "Descripcion", "header": "DESCRIPCION", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaOcurrencia": { "field": "FechaOcurrencia", "header": "FECHAOCURRENCIA", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaDenuncia": { "field": "FechaDenuncia", "header": "FECHADENUNCIA", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaTerminacion": { "field": "FechaTerminacion", "header": "FECHATERMINACION", "type": "date", "hide": false, "virt": false, "key": false, "editable": true } + }, + "SiniestrosEstados": { + "CodigoSiniestro": { "field": "CodigoSiniestro", "header": "CODIGOSINIESTRO", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "Estado": { "field": "Estado", "header": "ESTADO", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "TipoMovimiento": { "field": "TipoMovimiento", "header": "TIPOMOVIMIENTO", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "ClaveConsecuencia": { "field": "ClaveConsecuencia", "header": "CLAVECONSECUENCIA", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "CodigoActividad": { "field": "CodigoActividad", "header": "CODIGOACTIVIDAD", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "CodigoPostal": { "field": "CodigoPostal", "header": "CODIGOPOSTAL", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "CodigoSucursalTramitadora": { "field": "CodigoSucursalTramitadora", "header": "CODIGOSUCURSALTRAMITADORA", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "DescripcionClaveConsecuencia": { "field": "DescripcionClaveConsecuencia", "header": "DESCRIPCIONCLAVECONSECUENCIA", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaInformacion": { "field": "FechaInformacion", "header": "FECHAINFORMACION", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaReapertura": { "field": "FechaReapertura", "header": "FECHAREAPERTURA", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaTerminacion": { "field": "FechaTerminacion", "header": "FECHATERMINACION", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "Hora": { "field": "Hora", "header": "HORA", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Localidad": { "field": "Localidad", "header": "LOCALIDAD", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Lugar": { "field": "Lugar", "header": "LUGAR", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "NombreTomador": { "field": "NombreTomador", "header": "NOMBRETOMADOR", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Observaciones": { "field": "Observaciones", "header": "OBSERVACIONES", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Situacion": { "field": "Situacion", "header": "SITUACION", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "SubCodigoMediador": { "field": "SubCodigoMediador", "header": "SUBCODIGOMEDIADOR", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Tramitador": { "field": "Tramitador", "header": "TRAMITADOR", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Usuario": { "field": "Usuario", "header": "USUARIO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true } + }, + "SiniestrosTramites": { + "CodigoSiniestro": { "field": "CodigoSiniestro", "header": "CODIGOSINIESTRO", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "FechaInicio": { "field": "FechaInicio", "header": "FECHAINICIO", "type": "datetime", "hide": false, "virt": false, "key": "PK", "editable": false }, + "Observaciones": { "field": "Observaciones", "header": "OBSERVACIONES", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "CodigoPoliza": { "field": "CodigoPoliza", "header": "CODIGOPOLIZA", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "CodigoExpediente": { "field": "CodigoExpediente", "header": "CODIGOEXPEDIENTE", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "TipoTramite": { "field": "TipoTramite", "header": "TIPOTRAMITE", "type": "text", "hide": false, "virt": false, "key": false, "editable": true } + }, + "Usuarios": { + "Usuario": { "field": "Usuario", "header": "USUARIO", "type": "text", "hide": false, "virt": false, "key": "PK", "editable": false }, + "Nombre": { "field": "Nombre", "header": "NOMBRE", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Correo": { "field": "Correo", "header": "CORREO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Activo": { "field": "Activo", "header": "ACTIVO", "type": "boolean", "hide": false, "virt": false, "key": false, "editable": true }, + "Suplente": { "field": "Suplente", "header": "SUPLENTE", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaInicio": { "field": "FechaInicio", "header": "FECHAINICIO", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaFinal": { "field": "FechaFinal", "header": "FECHAFINAL", "type": "date", "hide": false, "virt": false, "key": false, "editable": true } + }, + "UsuariosFichajes": { + "id": { "field": "id", "header": "ID", "type": "numeric", "hide": true, "virt": false, "key": "PK", "editable": false }, + "Usuario": { "field": "Usuario", "header": "USUARIO", "type": "text", "hide": false, "virt": false, "key": "FK", "editable": true }, + "Fecha": { "field": "Fecha", "header": "FECHA", "type": "datetime", "hide": false, "virt": false, "key": false, "editable": true }, + "Tipo": { "field": "Tipo", "header": "TIPO", "type": "select", "hide": false, "virt": false, "key": false, "editable": true }, + "Duracion": { "field": "Duracion", "header": "DURACION", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true } + }, + "vClientes": { + "Nombre": { "field": "Nombre", "header": "NOMBRE", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Apellidos": { "field": "Apellidos", "header": "APELLIDOS", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Documento": { "field": "Documento", "header": "DOCUMENTO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Domicilio": { "field": "Domicilio", "header": "DOMICILIO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Localidad": { "field": "Localidad", "header": "LOCALIDAD", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "CodigoPostal": { "field": "CodigoPostal", "header": "CODIGOPOSTAL", "type": "numeric", "hide": false, "virt": false, "key": false, "editable": true }, + "Provincia": { "field": "Provincia", "header": "PROVINCIA", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaCarnet": { "field": "FechaCarnet", "header": "FECHACARNET", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaNacimiento": { "field": "FechaNacimiento", "header": "FECHANACIMIENTO", "type": "date", "hide": false, "virt": false, "key": false, "editable": true } + }, + "vClientesCorreos": { + "Documento": { "field": "Documento", "header": "DOCUMENTO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "Correo2": { "field": "Correo2", "header": "CORREO2", "type": "text", "hide": false, "virt": false, "key": false, "editable": true } + }, + "vRecibos": { + "CodigoRecibo": { "field": "CodigoRecibo", "header": "CODIGORECIBO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "CodigoEmpresa": { "field": "CodigoEmpresa", "header": "CODIGOEMPRESA", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "CodigoPoliza": { "field": "CodigoPoliza", "header": "CODIGOPOLIZA", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaEfecto": { "field": "FechaEfecto", "header": "FECHAEFECTO", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "Situacion": { "field": "Situacion", "header": "SITUACION", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "Estado": { "field": "Estado", "header": "ESTADO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true }, + "FechaVencimiento": { "field": "FechaVencimiento", "header": "FECHAVENCIMIENTO", "type": "date", "hide": false, "virt": false, "key": false, "editable": true }, + "FormaPago": { "field": "FormaPago", "header": "FORMAPAGO", "type": "text", "hide": false, "virt": false, "key": false, "editable": true } + } +} \ No newline at end of file diff --git a/server/package.json b/server/package.json new file mode 100644 index 0000000..68c4d0f --- /dev/null +++ b/server/package.json @@ -0,0 +1,18 @@ +{ + "name": "dare-server", + "version": "2.0.0", + "type": "module", + "scripts": { + "kill": "pkill -9 bun && pkill -9 node || true", + "del": "rm node_modules/.vite/deps -r", + "gen:schema": "bun run scripts/generate-schema.js", + "dev": "bun gen:schema && bun --watch index.js", + "build": "bun build index.js --target bun --outdir ./dist" + }, + "dependencies": { + "hono": "^4.12.7", + "mariadb": "^3.5.2", + "nodemailer": "^8.0.2", + "sharp": "^0.34.5" + } +} \ No newline at end of file diff --git a/server/scripts/generate-schema.js b/server/scripts/generate-schema.js new file mode 100644 index 0000000..df8b12e --- /dev/null +++ b/server/scripts/generate-schema.js @@ -0,0 +1,74 @@ +import { pool } from '../services/db.service'; +import { resolve } from 'node:path'; + +/** + * Genera el esquema de la base de datos automáticamente + */ +async function generateSchema() { + try { + const rows = await pool.query(` + SELECT + TABLE_NAME as t, + COLUMN_NAME as f, + DATA_TYPE as T, + COLUMN_TYPE as fT, + EXTRA as e, + COLUMN_KEY as k + FROM information_schema.columns + WHERE table_schema = DATABASE() + ORDER BY TABLE_NAME, ORDINAL_POSITION + `); + + const data = rows.reduce((acc, { t, f, T, fT, e, k }) => { + if (!acc[t]) acc[t] = {}; + + // Mapeo de tipos + let type = 'text'; + + if (['int', 'decimal', 'float', 'double'].includes(T)) { + type = 'numeric'; + } else if (['date', 'datetime', 'timestamp'].includes(T)) { + type = T === 'date' ? 'date' : 'datetime'; + } else if (T === 'tinyint' && fT.includes('(1)')) { + type = 'boolean'; + } else if (T === 'enum') { + type = 'select'; + } + + const hide = f.startsWith('id') || f === 'password' || f === 'token'; + const virt = e.toLowerCase().includes('generated'); + const key = k === 'PRI' ? 'PK' : k === 'UNI' ? 'UK' : k === 'MUL' ? 'FK' : false; + + acc[t][f] = { + field: f, + header: f.replace(/_/g, ' ').toUpperCase(), + type, + hide, + virt, + key, + editable: !(hide || key === 'PK' || virt) + }; + + return acc; + }, {}); + + const outPath = resolve('./server/lib/schema.json'); + + // JSON compacto para ahorrar bytes pero manteniendo legibilidad por tabla + const json = JSON.stringify(data, null, 2) + .replace(/\{\n\s+"field":[\s\S]+?\n\s+\}/g, m => m.replace(/\s*\n\s*/g, ' ')); + + await Bun.write(outPath, json); + + console.log(`✅ Esquema generado: ${outPath}`); + console.log(`📊 Tablas: ${Object.keys(data).length}`); + + } catch (error) { + console.error('❌ Error:', error); + } finally { + await pool.end(); + process.exit(0); + } +} + +generateSchema(); \ No newline at end of file diff --git a/server/services/db.service.js b/server/services/db.service.js new file mode 100644 index 0000000..227cb09 --- /dev/null +++ b/server/services/db.service.js @@ -0,0 +1,135 @@ +// import mariadb from 'mariadb'; +import * as mariadb from 'mariadb'; + +// Fix para BigInt en la serialización JSON (necesario para IDs grandes en MariaDB) +BigInt.prototype.toJSON = function () { + return this.toString(); +}; + +// Configuración del Pool +export const pool = mariadb.createPool({ + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: 'Reale', + connectionLimit: 20, + timezone: 'Z', + insertIdAsNumber: true +}); + +// Helper para escapar identificadores (tablas/columnas) +const b = (id) => `\`${id.replace(/`/g, '``')}\``; + +export class Database { + constructor(connector) { + /** @type {mariadb.Pool | mariadb.PoolConnection} */ + this.connector = connector; + } + + async insert(table, data) { + const rows = Array.isArray(data) ? data : [data]; + if (!rows.length) return null; + const fields = Object.keys(rows[0]); + const query = `INSERT INTO ${b(table)} (${fields.map(b).join(',')}) VALUES (${fields.map(() => '?').join(',')})`; + return this.connector.batch(query, rows.map(r => fields.map(f => r[f]))); + } + + async update(table, data, where) { + const fields = Object.keys(data); + const wFields = Object.keys(where); + const query = `UPDATE ${b(table)} SET ${fields.map(f => `${b(f)}=?`).join(',')} WHERE ${wFields.map(f => `${b(f)}=?`).join(' AND ')}`; + return this.connector.query(query, [...fields.map(f => data[f]), ...wFields.map(f => where[f])]); + } + + async upsert(table, data, ignore = false) { + const rows = Array.isArray(data) ? data : [data]; + if (!rows.length) return null; + const fields = Object.keys(rows[0]); + const set = fields.filter(f => f !== 'id').map(f => `${b(f)}=VALUES(${b(f)})`).join(','); + const query = `INSERT ${ignore ? 'IGNORE' : ''} INTO ${b(table)} (${fields.map(b).join(',')}) VALUES (${fields.map(() => '?').join(',')}) ON DUPLICATE KEY UPDATE ${set}`; + return this.connector.batch(query, rows.map(r => fields.map(f => r[f]))); + } + + async delete(table, where) { + const keys = Object.keys(where); + if (!keys.length) throw new Error('Delete requiere condiciones'); + return this.connector.query(`DELETE FROM ${b(table)} WHERE ${keys.map(k => `${b(k)}=?`).join(' AND ')}`, keys.map(k => where[k])); + } + + async select(table, where = {}, opts = { limit: 5000, order: null }) { + const keys = Object.keys(where); + let sqlStr = `SELECT * FROM ${b(table)}`; + if (keys.length) sqlStr += ` WHERE ${keys.map(k => `${b(k)}=?`).join(' AND ')}`; + if (opts.order) sqlStr += ` ORDER BY ${b(opts.order)}`; + return this.connector.query(sqlStr + ` LIMIT ${opts.limit}`, keys.map(k => where[k])); + } + + async one(table, where) { + const res = await this.select(table, where, { limit: 1 }); + return res[0] || null; + } + + async count(table, where = {}) { + const keys = Object.keys(where); + let sqlStr = `SELECT COUNT(*) as total FROM ${b(table)}`; + if (keys.length) sqlStr += ` WHERE ${keys.map(k => `${b(k)}=?`).join(' AND ')}`; + const res = await this.connector.query(sqlStr, keys.map(k => where[k])); + return Number(res[0].total); + } + + async search(table, fields, term, limit = 1000) { + if (!fields.length || !term) return []; + const where = fields.map(f => `${b(f)} LIKE ?`).join(' OR '); + return this.connector.query(`SELECT * FROM ${b(table)} WHERE ${where} LIMIT ${limit}`, fields.map(() => `%${term}%`)); + } + + async unique(table, fields, where = {}) { + const f = Array.isArray(fields) ? fields.map(b).join(',') : b(fields); + const keys = Object.keys(where); + let sqlStr = `SELECT DISTINCT ${f} FROM ${b(table)}`; + if (keys.length) sqlStr += ` WHERE ${keys.map(k => `${b(k)}=?`).join(' AND ')}`; + const sort = Array.isArray(fields) ? b(fields[0]) : f; + return this.connector.query(sqlStr + ` ORDER BY ${sort} ASC`, keys.map(k => where[k])); + } + + async raw(query, data = {}) { + const params = []; + const sqlStr = query.replace(/:(\w+)/g, (_, key) => { + params.push(data[key]); + return '?'; + }); + return this.connector.query(sqlStr, params); + } +} + +/** + * Lógica de Transacciones + */ +export const trx = async (opts, actions) => { + const tasks = Array.isArray(opts) ? opts : [opts]; + const conn = await pool.getConnection(); + try { + await conn.beginTransaction(); + const transactionDb = new Database(conn); + const results = {}; + + for (const item of tasks) { + if (typeof actions[item.action] !== 'function') { + throw new Error(`Acción ${item.action} no existe`); + } + results[item.action] = await actions[item.action](transactionDb, item); + } + + await conn.commit(); + return results; + } catch (err) { + console.error('Error en la transacción:', err); + await conn.rollback(); + throw err; + } finally { + if (conn) conn.release(); + } +}; + +// Exportamos la instancia principal vinculada al Pool +export const db = new Database(pool); \ No newline at end of file diff --git a/server/services/mail.service.js b/server/services/mail.service.js new file mode 100644 index 0000000..de6eb8c --- /dev/null +++ b/server/services/mail.service.js @@ -0,0 +1,47 @@ +import nodemailer from 'nodemailer'; + +// Configuración del transportador +const transporter = nodemailer.createTransport({ + host: process.env.db, // Nota: Asegúrate de que esta variable sea el host SMTP (ej. smtp.tuproveedor.com) + port: 587, + secure: false, // true para 465, false para otros puertos + auth: { + user: "natxocc", + pass: "Ncc629406731.", + }, +}); + +/** + * Envía un correo electrónico + * @param {string} to - Destinatario + * @param {string} subject - Asunto + * @param {string} html - Cuerpo en HTML + * @param {Object|null} file - Opcional: { filename, content, contentType } + */ +export const send = async (to, subject, html, file = null) => { + + const mailOptions = { + from: '"Natxocc" ', + to, + subject, + html, + }; + + // Si pasas un archivo (ej: buffer de Sharp), lo añadimos como attachment + if (file) { + mailOptions.attachments = [ + { + filename: file.filename, + content: file.content, + contentType: file.contentType || 'image/jpeg' + } + ]; + } + + try { + await transporter.sendMail(mailOptions); + } catch (error) { + console.error('Error enviando email:', error); + throw error; // Re-lanzamos para que la ruta de Hono capture el error + } +}; \ No newline at end of file diff --git a/server/services/soap.service.js b/server/services/soap.service.js new file mode 100644 index 0000000..d148be6 --- /dev/null +++ b/server/services/soap.service.js @@ -0,0 +1,112 @@ +import * as soap from 'soap'; +import { HttpClient } from 'soap'; +import { trx } from './db.service.js'; +import { actions } from '../actions/soap.actions.js'; + +// --- Helpers de Fecha --- +const fmt = (d) => (!isNaN(d.getTime()) ? d.toLocaleDateString('sv-SE') : null); + +const getFirstMonth = (m = 0) => { + const now = new Date(); + return fmt(new Date(now.getFullYear(), now.getMonth() + m, 1)); +}; + +const getDate = (d = 0) => { + const t = new Date(); + t.setDate(t.getDate() + d); + return fmt(t); +}; + +const SOAP_SERVICES = { + DescargaPolizas: "https://lba.realeonline.net/Reale.B2b.Services.Multitarificadores.IisHost/DescargaPolizas.svc?wsdl", + LiquidacionMediador: "https://lba.realeonline.net/Reale.B2b.Services.Multitarificadores.IisHost/LiquidacionMediador.svc?wsdl", + DescargaSiniestros: "https://lba.realeonline.net/Reale.B2b.Services.Multitarificadores.IisHost/DescargaSiniestros.svc?wsdl", + DescargaCompletaRecibos: "https://lba.realeonline.net/Reale.B2b.Services.Multitarificadores.IisHost/DescargaCompletaRecibos.svc?wsdl", + DescargaCartera: "https://lba.realeonline.net/Reale.B2b.Services.Multitarificadores.IisHost/DescargaCartera.svc?wsdl", + ConsultaPolizas: "https://lba.realeonline.net/Reale.B2b.Services.Multitarificadores.IisHost/ConsultaPolizas.svc?wsdl", + ConsultaRecibos: "https://lba.realeonline.net/Reale.B2b.Services.Multitarificadores.IisHost/ConsultaRecibos.svc?wsdl", + ConsultaAgendaTramitacion: "https://lba.realeonline.net/Reale.B2b.Services.Multitarificadores.IisHost/ConsultaAgendaTramitacion.svc?wsdl", + TramitacionSiniestro: "https://lba.realeonline.net/Reale.B2b.Services.Multitarificadores.IisHost/TramitacionSiniestro.svc?wsdl", +}; + +export const soapCall = async (params, query, save = true) => { + const { CodigoMediador, service, method } = params; + const url = SOAP_SERVICES[service]; + + if (!url) throw new Error(`Servicio SOAP '${service}' no encontrado`); + + // --- Identificador desde ENV o Query --- + const Identificador = query.Identificador || process.env[`SOAP_${CodigoMediador}`]; + if (!Identificador) throw new Error(`Identificador no configurado para mediador ${CodigoMediador}`); + + // --- Normalización de Argumentos --- + const Mediador = query.Mediador || CodigoMediador; + const CodigoPoliza = query.CodigoPoliza || "0"; + const CodigoSiniestro = query.CodigoSiniestro || "0"; + const CodigoExpediente = query.CodigoExpediente || "0"; + const Observaciones = query.Observaciones || ""; + const CodigoRecibo = query.CodigoRecibo || "0"; + const CodigoSuplemento = query.CodigoSuplemento || "1000"; + const Clave = query.Clave || "10000"; + const Empresa = query.Empresa || "4"; + const CodigoEmpresa = query.CodigoEmpresa || Empresa; + const Plataforma = query.Plataforma || "10000"; + const CodigoRamo = query.CodigoRamo || "0"; + const FechaFinal = query.FechaFinal || getDate(); + const FechaRenovacion = query.FechaRenovacion || getFirstMonth(-1); + const FechaInicial = query.FechaInicial || getFirstMonth(-1); + const FechaLiquidacion = query.FechaLiquidacion || getDate(); + + const HEADER = `${Plataforma}${Identificador}`; + + // --- Diccionario de Configuración --- + const SOAP_CONFIG = { + DescargaPolizas: { Descargar: { args: { Clave, CodigoRamo, Empresa, FechaFinal, FechaInicial, Identificador, Plataforma, TipoSuplemento1: "NP", TipoSuplemento2: "AN", TipoSuplemento3: "RE", TipoSuplemento4: "SP" }, header: null } }, + LiquidacionMediador: { + Consulta: { args: { CodigoMediador, Empresa, FechaLiquidacion }, header: HEADER }, + ObtenerFechasLiquidacion: { args: { CodigoMediador, Empresa }, header: HEADER } + }, + DescargaSiniestros: { Descargar: { args: { AceptarCicos: true, AceptarSdm: true, Clave, CodigoRamo, Empresa, FechaFinal, FechaInicial, Identificador, IncluirAperturas: true, IncluirAperturasCicos: true, IncluirAperturasSdm: true, IncluirPagosImdemnizacion: true, IncluirTerminados: true, Plataforma }, header: HEADER } }, + DescargaCompletaRecibos: { DescargarNew: { args: { Clave, CodigoRamo, Empresa, FechaFinal, FechaInicial, Identificador, Plataforma, IncluirAnulados: true, IncluirCobrados: true, IncluirDevueltos: true, IncluirNuevos: true }, header: null } }, + DescargaCartera: { + DescargarCartera: { args: { CodigoMediador, Empresa, FechaRenovacion, Identificador, Plataforma }, header: null }, + ObtenerListaRamos: { args: { Empresa }, header: null }, + ObtenerListaRenovaciones: { args: { Empresa, Mediador }, header: null } + }, + ConsultaPolizas: { + ConsultarPoliza: { args: { CodigoPoliza, CodigoRamo, CodigoSuplemento, Empresa, Identificador, Plataforma }, header: null }, + ObtenerListaPolizasMediador: { args: { CodigoMediador, Empresa, Identificador }, header: null }, + ObtenerListaSuplementosPoliza: { args: { CodigoPoliza, CodigoRamo, Empresa, Identificador }, header: null } + }, + ConsultaRecibos: { + ConsultarRecibo: { args: { CodigoPoliza, CodigoRamo, CodigoRecibo, CodigoSuplemento, Empresa, Identificador, Plataforma }, header: null }, + ObtenerListaRecibosPoliza: { args: { CodigoPoliza, CodigoRamo, Empresa, Identificador }, header: null } + }, + ConsultaAgendaTramitacion: { ConsultaTramitacion: { args: { Datos: { CodigoExpediente, CodigoPoliza, CodigoSiniestro, Empresa } }, header: HEADER } }, + TramitacionSiniestro: { InsertarTramite: { args: { CodigoEmpresa, CodigoExpediente, CodigoSiniestro, Identificador, Observaciones, Plataforma }, header: null } } + }; + + const config = SOAP_CONFIG[service]?.[method]; + if (!config) throw new Error(`Método '${method}' no configurado para el servicio '${service}'`); + + try { + const client = await soap.createClientAsync(url, { + httpClient: new HttpClient(), + request: { timeout: 120000 } + }); + + if (config.header) client.addSoapHeader(config.header); + + const methodName = `${method}Async`; + const [result] = await client[methodName](config.args); + + if (save) { + await trx({ action: service, data: result }, actions); + } + + return result; + } catch (error) { + console.error(`[SOAP ERROR] ${service}/${method}:`, error.message); + throw error; + } +}; \ No newline at end of file diff --git a/server/services/soap2.service.js b/server/services/soap2.service.js new file mode 100644 index 0000000..6a1c160 --- /dev/null +++ b/server/services/soap2.service.js @@ -0,0 +1,151 @@ +import { XMLParser } from "fast-xml-parser"; +import { trx } from "./db.service.js"; +import { actions } from "../actions/soap.actions.js"; + +const parser = new XMLParser({ + removeNSPrefix: true, + ignoreAttributes: false, + parseTagValue: true, + trimValues: true, +}); + +const ALIAS_MAP = { + Polizas: { service: "DescargaPolizas", method: "Descargar" }, + Recibos: { service: "DescargaCompletaRecibos", method: "Descargar" }, + Siniestros: { service: "DescargaSiniestros", method: "Descargar" }, + Cartera: { service: "DescargaCartera", method: "DescargarCartera" }, + TramiteSiniestro: { service: "ConsultaAgendaTramitacion", method: "ConsultaTramitacion" }, + Poliza: { service: "ConsultaPolizas", method: "ConsultarPoliza" }, + Recibo: { service: "ConsultaRecibos", method: "ConsultarRecibo" }, + Siniestro: { service: "ConsultaSiniestros", method: "ConsultarSiniestro" }, +}; + +const cleanNil = (obj) => { + if (obj !== null && typeof obj === "object") { + if (obj["@_nil"] === "true" || obj["@_nil"] === true) return null; + if (Array.isArray(obj)) return obj.map(cleanNil); + const newObj = {}; + for (const [key, value] of Object.entries(obj)) { + newObj[key] = cleanNil(value); + } + return newObj; + } + return obj; +}; + +const fmt = (d) => (!isNaN(d.getTime()) ? d.toLocaleDateString("sv-SE") : null); +const getFirstMonth = (m = 0) => { + const now = new Date(); + return fmt(new Date(now.getFullYear(), now.getMonth() + m, 1)); +}; +const getDate = (d = 0) => { + const t = new Date(); + t.setDate(t.getDate() + d); + return fmt(t); +}; + +const getXmlBody = (service, method, q) => { + const templates = { + DescargaPolizas: `${q.Clave}${q.CodigoRamo}${q.Empresa}${q.FechaFinal}${q.FechaInicial}${q.Identificador}${q.Plataforma}NPANRESP`, + DescargaSiniestros: `truetrue${q.Clave}${q.CodigoRamo}${q.Empresa}${q.FechaFinal}${q.FechaInicial}${q.Identificador}true${q.Plataforma}`, + DescargaCompletaRecibos: `${q.Clave}${q.Empresa}${q.FechaFinal}${q.FechaInicial}${q.Identificador}truetruetruetrue`, + DescargaCartera: `${q.CodigoMediador}${q.Empresa}${q.FechaRenovacion}${q.Identificador}${q.Plataforma}`, + ConsultaAgendaTramitacion: `${q.CodigoExpediente}${q.CodigoPoliza}${q.CodigoSiniestro}${q.Empresa}`, + ConsultaPolizas: `${q.CodigoPoliza}${q.CodigoRamo}${q.CodigoSuplemento || 0}${q.Empresa}${q.Identificador}${q.Plataforma}`, + ConsultaRecibos: `${q.CodigoPoliza}${q.CodigoRamo}${q.CodigoRecibo || 0}${q.CodigoSuplemento || 0}${q.Empresa}${q.Identificador}${q.Plataforma}`, + ConsultaSiniestros: `${q.CodigoPoliza}${q.CodigoRamo}${q.CodigoSiniestro}${q.CodigoSuplemento || 0}${q.Empresa}${q.Identificador}${q.Plataforma}`, + }; + return templates[service] || `${q.Identificador}`; +}; + +export const soapCall = async (params, query, save = true) => { + const { CodigoMediador, alias } = params; + const target = ALIAS_MAP[alias] || { service: params.service, method: params.method }; + const { service, method } = target; + + if (!service) throw new Error(`Servicio o Alias '${alias || params.service}' no definido`); + + const url = `https://lba.realeonline.net/Reale.B2b.Services.Multitarificadores.IisHost/${service}.svc`; + const Identificador = query.Identificador || process.env[`SOAP_${CodigoMediador}`]; + if (!Identificador) throw new Error(`Identificador no configurado para ${CodigoMediador}`); + + const q = { + ...query, + Identificador, + CodigoMediador, + Clave: query.Clave || "10000", + Empresa: query.Empresa || "4", + Plataforma: query.Plataforma || "10000", + CodigoRamo: query.CodigoRamo || "0", + CodigoSuplemento: query.CodigoSuplemento || "0", + CodigoPoliza: query.CodigoPoliza || "0", + CodigoSiniestro: query.CodigoSiniestro || "0", + CodigoExpediente: query.CodigoExpediente || "0", + FechaFinal: query.FechaFinal || getDate(), + FechaInicial: query.FechaInicial || (alias === "Cartera" ? getFirstMonth(0) : getFirstMonth(-1)), + FechaRenovacion: query.FechaRenovacion || getFirstMonth(1), + }; + + let nsBase = "http://reale.net/B2b/Multitarificadores"; + let nsName = service; + let contract = `I${service}`; + let actMethod = method; + let soapHeader = ""; + + if (service === "DescargaCartera") { + nsName = "DescargaFicheros"; + contract = "IDescargaCartera"; + } + else if (service === "ConsultaPolizas") { + nsName = "ConsultaPolizas"; + contract = "IConsultaPolizas"; + } + else if (service === "DescargaCompletaRecibos" && method === "Descargar") { + actMethod = "DescargarNew"; + } + else if (service === "ConsultaAgendaTramitacion") { + nsBase = "http://reale.net/wcf/internalServices"; + nsName = ""; + contract = "IAgendaTramitacion"; + actMethod = "ConsultaTramitacion"; + soapHeader = `${q.Plataforma}${q.Identificador}`; + } + + const fullNs = nsName ? `${nsBase}/${nsName}` : nsBase; + const soapAction = `"${fullNs}/${contract}/${actMethod}"`.replace(/([^:])\/\//g, "$1/"); + + const soapEnvelope = ` + + ${soapHeader} + ${getXmlBody(service, method, q)} + `.trim(); + + try { + const response = await fetch(url, { + method: "POST", + headers: { "Content-Type": "text/xml;charset=UTF-8", "SOAPAction": soapAction }, + body: soapEnvelope, + }); + + const xmlData = await response.text(); + const rawJson = parser.parse(xmlData); + + if (!response.ok) { + const fault = rawJson.Envelope?.Body?.Fault?.faultstring; + throw new Error(typeof fault === "object" ? JSON.stringify(fault) : fault || `Error ${response.status}`); + } + + const resultBody = rawJson.Envelope?.Body; + const responseName = Object.keys(resultBody || {})[0]; + const result = cleanNil(resultBody?.[responseName] || {}); + + // CUIDADO DA ERROR CUANDO USAS /Poliza /Siniestro /Recibo porque no hay un action para ellos + if (save) await trx({ action: service, data: result }, actions); + return result; + } catch (error) { + console.error(`[SOAP ERROR] ${service}/${method}:`, error.message); + throw error; + } +}; \ No newline at end of file